#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "common.h" #define CTRL_PT_LAYER 3 #define INFO_TEXT_LAYER (CTRL_PT_LAYER+1) #define ROUNDING(x, dig) (floor((x) * pow(10, dig) + 0.5) / pow(10, dig)) typedef enum { Ctrl_Pt_Rel1 = 0, Ctrl_Pt_Rel2, Ctrl_Pt_Rel3, Ctrl_Pt_Rel4, Ctrl_Pt_Top, Ctrl_Pt_Bottom, Ctrl_Pt_Left, Ctrl_Pt_Right, Ctrl_Pt_Cnt } Ctrl_Pt; typedef enum { Info_Text_Rel1 = 0, Info_Text_Rel2, Info_Text_Size, Info_Text_Cnt } Info_Text; typedef enum { Align_Line_Top = 0, Align_Line_Bottom, Align_Line_Left, Align_Line_Right, Align_Line_Cnt } Align_Line; typedef struct ctxpopup_it_data_s { const char *name; Edje_Part_Type type; } ctxpopup_it_data; typedef struct live_editor_s { Evas_Object *ctxpopup; Evas_Object *layout; Evas_Object *live_view; Evas_Object *enventor; Evas_Object *trigger; Evas_Object *ctrl_pt[Ctrl_Pt_Cnt]; Evas_Object *align_line[Align_Line_Cnt]; Evas_Object *info_text[Info_Text_Cnt]; double half_ctrl_size; struct { unsigned int type; float rel1_x, rel1_y; float rel2_x, rel2_y; } part_info; Ecore_Event_Handler *key_down_handler; Eina_Bool on : 1; } live_data; static void live_edit_update(live_data *ld); static const ctxpopup_it_data CTXPOPUP_ITEMS[] = { {"RECT", EDJE_PART_TYPE_RECTANGLE}, {"TEXT", EDJE_PART_TYPE_TEXT}, {"IMAGE", EDJE_PART_TYPE_IMAGE}, {"SWALLOW", EDJE_PART_TYPE_SWALLOW}, {"TEXTBLOCK", EDJE_PART_TYPE_TEXTBLOCK}, {"SPACER", EDJE_PART_TYPE_SPACER} }; static live_data *g_ld = NULL; static void info_text_update(live_data *ld) { //Update Text char buf[256]; Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); //Rel1 snprintf(buf, sizeof(buf), "%.2f %.2f (%d %d)", ld->part_info.rel1_x, ld->part_info.rel1_y, (int) round(ld->part_info.rel1_x * (double) lw), (int) round(ld->part_info.rel1_y * (double) lh)); evas_object_text_text_set(ld->info_text[Info_Text_Rel1], buf); //Rel2 snprintf(buf, sizeof(buf), "%.2f %.2f (%d %d)", ld->part_info.rel2_x, ld->part_info.rel2_y, (int) round(ld->part_info.rel2_x * (double) lw), (int) round(ld->part_info.rel2_y * (double) lh)); evas_object_text_text_set(ld->info_text[Info_Text_Rel2], buf); //Size Evas_Coord layout_x, layout_y, layout_w, layout_h; evas_object_geometry_get(ld->layout, &layout_x, &layout_y, &layout_w, &layout_h); snprintf(buf, sizeof(buf), "[%d x %d]", layout_w, layout_h); evas_object_text_text_set(ld->info_text[Info_Text_Size], buf); //Update Position Evas_Coord x, y, w, h; Evas_Coord rx, ry, rw, rh; //Rel1 evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rx, &ry, &rw, &rh); evas_object_geometry_get(ld->info_text[Info_Text_Rel1], NULL, NULL, &w, &h); x = rx - w; y = ry - h; if (x < lx) x = (rx + rw); if (y < ly) y = (ry + rh); evas_object_move(ld->info_text[Info_Text_Rel1], x, y); //Rel2 evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rx, &ry, &rw, &rh); evas_object_geometry_get(ld->info_text[Info_Text_Rel2], NULL, NULL, &w, &h); x = (rx + rw); y = (ry + rh); if ((x + w) > (lx + lw)) x = (rx - w); if ((y + h) > (ly + lh)) y = (ry - h); evas_object_move(ld->info_text[Info_Text_Rel2], x, y); //Size evas_object_geometry_get(ld->info_text[Info_Text_Size], NULL, NULL, &w, &h); x = (layout_x + (layout_w/2)) - (w/2); y = (layout_y + (layout_h/2)) - (h/2); if (x < lx) x = lx; if (y < lx) y = ly; if ((x + w) > (lx + lw)) x = ((lx + lw) - w); if ((y + h) > (ly + lh)) y = ((ly + lh) - h); evas_object_move(ld->info_text[Info_Text_Size], x, y); } static void live_edit_symbol_set(live_data *ld) { char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "%s_bg", CTXPOPUP_ITEMS[ld->part_info.type].name); Evas_Object *layout_symbol = elm_layout_add(ld->layout); elm_layout_file_set(layout_symbol, EDJE_PATH, buf); elm_object_part_content_set(ld->layout, "elm.swallow.symbol", layout_symbol); } static void live_edit_insert(live_data *ld) { int type = CTXPOPUP_ITEMS[ld->part_info.type].type; enventor_object_template_part_insert(ld->enventor, type, ENVENTOR_TEMPLATE_INSERT_LIVE_EDIT, ld->part_info.rel1_x, ld->part_info.rel1_y, ld->part_info.rel2_x, ld->part_info.rel2_y, NULL, 0); enventor_object_save(ld->enventor, config_edc_path_get()); } static Eina_Bool key_down_cb(void *data, int type EINA_UNUSED, void *ev) { Ecore_Event_Key *event = ev; live_data *ld = data; if (!strcmp(event->key, "Return")) live_edit_insert(ld); else if (strcmp(event->key, "Delete") && strcmp(event->key, "BackSpace")) return EINA_TRUE; live_edit_cancel(); return EINA_TRUE; } static void ctrl_pt_update(live_data *ld) { //Init Control Point Positions Evas_Coord dx, dy, dw, dh; evas_object_geometry_get(ld->layout, &dx, &dy, &dw, &dh); double x = dx; double y = dy; double w = dw; double h = dh; int half_ctrl_size = ld->half_ctrl_size; //Rel1 evas_object_move(ld->ctrl_pt[Ctrl_Pt_Rel1], round((x - half_ctrl_size)), round((y - half_ctrl_size))); //Rel2 evas_object_move(ld->ctrl_pt[Ctrl_Pt_Rel2], round((x + w) - half_ctrl_size), round((y + h) - half_ctrl_size)); //Rel3 evas_object_move(ld->ctrl_pt[Ctrl_Pt_Rel3], round((x + w) - half_ctrl_size), round(y - half_ctrl_size)); //Rel4 evas_object_move(ld->ctrl_pt[Ctrl_Pt_Rel4], round(x - half_ctrl_size), round((y + h) - half_ctrl_size)); //Top evas_object_move(ld->ctrl_pt[Ctrl_Pt_Top], round((x + (w/2)) - half_ctrl_size), round(y - half_ctrl_size)); //Bottom evas_object_move(ld->ctrl_pt[Ctrl_Pt_Bottom], round((x + (w/2)) - half_ctrl_size), round((y + h) - half_ctrl_size)); //Left evas_object_move(ld->ctrl_pt[Ctrl_Pt_Left], round(x - half_ctrl_size), round((y + (h/2)) - half_ctrl_size)); //Right evas_object_move(ld->ctrl_pt[Ctrl_Pt_Right], round((x + w) - half_ctrl_size), round((y + (h/2)) - half_ctrl_size)); } static void cp_top_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord y = ev->cur.canvas.y; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel2_y; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], NULL, &rel2_y, NULL, NULL); if (ly > y) y = ly; if ((y - ld->half_ctrl_size) > rel2_y) y = (rel2_y + ld->half_ctrl_size); ld->part_info.rel1_y = ROUNDING(((double) (y - ly) / (double) lh), 2); } static void cp_bottom_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord y = ev->cur.canvas.y; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel1_y; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], NULL, &rel1_y, NULL, NULL); if (y > (ly + lh)) y = (ly + lh); if (rel1_y > (y + ld->half_ctrl_size)) y = (rel1_y + ld->half_ctrl_size); ld->part_info.rel2_y = ROUNDING(((double) (y - ly) / (double) lh), 2); } static void align_line_update(live_data *ld) { Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); int x, y; //Top evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Top], NULL, &y, NULL, NULL); y = round(((double) y) + ld->half_ctrl_size); evas_object_move(ld->align_line[Align_Line_Top], (lx + 1), y); evas_object_resize(ld->align_line[Align_Line_Top], (lw - 2), (1 * elm_config_scale_get())); elm_object_signal_emit(ld->align_line[Align_Line_Top], "elm,state,show", ""); //Bottom evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Bottom], NULL, &y, NULL, NULL); y = round(((double) y) + ld->half_ctrl_size); evas_object_move(ld->align_line[Align_Line_Bottom], (lx + 1), (y - 1)); evas_object_resize(ld->align_line[Align_Line_Bottom], (lw - 2), (1 * elm_config_scale_get())); elm_object_signal_emit(ld->align_line[Align_Line_Bottom], "elm,state,show", ""); //Left evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Left], &x, NULL, NULL, NULL); x = round(((double) x) + ld->half_ctrl_size); evas_object_move(ld->align_line[Align_Line_Left], x, (ly + 1)); evas_object_resize(ld->align_line[Align_Line_Left], (1 * elm_config_scale_get()), (lh - 2)); elm_object_signal_emit(ld->align_line[Align_Line_Left], "elm,state,show", ""); //Right evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Right], &x, NULL, NULL, NULL); x = round(((double) x) + ld->half_ctrl_size); evas_object_move(ld->align_line[Align_Line_Right], (x - 1), (ly + 1)); evas_object_resize(ld->align_line[Align_Line_Right], (1 * elm_config_scale_get()), (lh - 2)); elm_object_signal_emit(ld->align_line[Align_Line_Right], "elm,state,show", ""); } static void cp_rel1_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord x = ev->cur.canvas.x; Evas_Coord y = ev->cur.canvas.y; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel2_x, rel2_y; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rel2_x, &rel2_y, NULL, NULL); if (lx > x) x = lx; if (ly > y) y = ly; if ((x - ld->half_ctrl_size) > rel2_x) x = (rel2_x + ld->half_ctrl_size); if ((y - ld->half_ctrl_size) > rel2_y) y = (rel2_y + ld->half_ctrl_size); ld->part_info.rel1_x = ROUNDING(((double) (x - lx) / (double) lw), 2); ld->part_info.rel1_y = ROUNDING(((double) (y - ly) / (double) lh), 2); } static void cp_rel2_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord x = ev->cur.canvas.x; Evas_Coord y = ev->cur.canvas.y; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel1_x, rel1_y; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rel1_x, &rel1_y, NULL, NULL); if (x > (lx + lw)) x = (lx + lw); if (y > (ly + lh)) y = (ly + lh); if (rel1_x > (x + ld->half_ctrl_size)) x = (rel1_x + ld->half_ctrl_size); if (rel1_y > (y + ld->half_ctrl_size)) y = (rel1_y + ld->half_ctrl_size); ld->part_info.rel2_x = ROUNDING(((double) (x - lx) / (double) lw), 2); ld->part_info.rel2_y = ROUNDING(((double) (y - ly) / (double) lh), 2); } static void cp_rel3_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord x = ev->cur.canvas.x; Evas_Coord y = ev->cur.canvas.y; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel1_x; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rel1_x, NULL, NULL, NULL); if (x > (lx + lw)) x = (lx + lw); if (rel1_x > (x + ld->half_ctrl_size)) x = (rel1_x - ld->half_ctrl_size); Evas_Coord rel2_y; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], NULL, &rel2_y, NULL, NULL); if (ly > y) y = ly; if ((y - ld->half_ctrl_size) > rel2_y) y = (rel2_y + ld->half_ctrl_size); ld->part_info.rel2_x = ROUNDING(((double) (x - lx) / (double) lw), 2); ld->part_info.rel1_y = ROUNDING(((double) (y - ly) / (double) lh), 2); } static void cp_rel4_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord x = ev->cur.canvas.x; Evas_Coord y = ev->cur.canvas.y; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel2_x; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rel2_x, NULL, NULL, NULL); if (lx > x) x = lx; if ((x - ld->half_ctrl_size) > rel2_x) x = (rel2_x + ld->half_ctrl_size); Evas_Coord rel1_y; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], NULL, &rel1_y, NULL, NULL); if (y > (ly + lh)) y = (ly + lh); if (rel1_y > (y + ld->half_ctrl_size)) y = (rel1_y + ld->half_ctrl_size); ld->part_info.rel1_x = ROUNDING(((double) (x - lx) / (double) lw), 2); ld->part_info.rel2_y = ROUNDING(((double) (y - ly) / (double) lh), 2); } static void cp_left_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord x = ev->cur.canvas.x; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel2_x; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rel2_x, NULL, NULL, NULL); if (lx > x) x = lx; if ((x - ld->half_ctrl_size) > rel2_x) x = (rel2_x + ld->half_ctrl_size); ld->part_info.rel1_x = ROUNDING(((double) (x - lx) / (double) lw), 2); } static void cp_right_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { live_data *ld = data; Evas_Event_Mouse_Move *ev = event_info; Evas_Coord x = ev->cur.canvas.x; //Limit to boundary Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord rel1_x; evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rel1_x, NULL, NULL, NULL); if (x > (lx + lw)) x = (lx + lw); if (rel1_x > (x + ld->half_ctrl_size)) x = (rel1_x + ld->half_ctrl_size); ld->part_info.rel2_x = ROUNDING(((double) (x - lx) / (double) lw), 2); } static void cp_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) { //Dispatch to actual mouse move call Ctrl_Pt cp = (Ctrl_Pt) evas_object_data_get(obj, "index"); //Show Control Point live_data *ld = data; elm_object_signal_emit(ld->ctrl_pt[cp], "elm,state,show", ""); switch (cp) { case Ctrl_Pt_Rel1: cp_rel1_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Rel2: cp_rel2_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Rel3: cp_rel3_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Rel4: cp_rel4_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Top: cp_top_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Bottom: cp_bottom_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Left: cp_left_mouse_move_cb(data, e, obj, event_info); break; case Ctrl_Pt_Right: cp_right_mouse_move_cb(data, e, obj, event_info); break; } live_edit_update(ld); } static void align_lines_hide(live_data *ld) { int i; for (i = 0; i < Align_Line_Cnt; i++) elm_object_signal_emit(ld->align_line[i], "elm,state,hide", ""); } static void cp_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE, cp_mouse_move_cb); live_data *ld = data; align_lines_hide(ld); //Show All Control Points int i; for (i = 0; i < Ctrl_Pt_Cnt; i++) elm_object_signal_emit(ld->ctrl_pt[i], "elm,state,show", ""); } static void cp_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, cp_mouse_move_cb, data); evas_object_layer_set(obj, CTRL_PT_LAYER); //Hide All Control Points live_data *ld = data; int i; for (i = 0; i < Ctrl_Pt_Cnt; i++) elm_object_signal_emit(ld->ctrl_pt[i], "elm,state,hide", ""); } static void ctrl_pt_init(live_data *ld) { //Ctrl Point Size Evas_Object *edje = elm_layout_edje_get(ld->layout); double ctrl_size = atof(edje_object_data_get(edje, "ctrl_size")); ctrl_size *= elm_config_scale_get(); ld->half_ctrl_size = ctrl_size * 0.5; //Create Control Points int i; for (i = 0; i < Ctrl_Pt_Cnt; i++) { Evas_Object *layout = elm_layout_add(ld->layout); elm_layout_file_set(layout, EDJE_PATH, "ctrl_pt"); evas_object_resize(layout, ctrl_size, ctrl_size); evas_object_show(layout); evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_DOWN, cp_mouse_down_cb, ld); evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_UP, cp_mouse_up_cb, ld); evas_object_data_set(layout, "index", (void *) i); ld->ctrl_pt[i] = layout; } //Set Mouse Cursors elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Rel1], ELM_CURSOR_TOP_LEFT_CORNER); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Rel2], ELM_CURSOR_BOTTOM_RIGHT_CORNER); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Rel3], ELM_CURSOR_TOP_RIGHT_CORNER); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Rel4], ELM_CURSOR_BOTTOM_LEFT_CORNER); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Top], ELM_CURSOR_TOP_SIDE); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Bottom], ELM_CURSOR_BOTTOM_SIDE); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Left], ELM_CURSOR_LEFT_SIDE); elm_object_cursor_set(ld->ctrl_pt[Ctrl_Pt_Right], ELM_CURSOR_RIGHT_SIDE); ctrl_pt_update(ld); } static void layout_update(live_data *ld) { Evas_Coord x, y, w, h; evas_object_geometry_get(ld->live_view, &x, &y, NULL, NULL); config_view_size_get(&w, &h); Evas_Coord x2 = round(((double) w) * ld->part_info.rel1_x); Evas_Coord y2 = round(((double) h) * ld->part_info.rel1_y); evas_object_move(ld->layout, (x + x2), (y + y2)); Evas_Coord w2 = round(((double) w * (ld->part_info.rel2_x - ld->part_info.rel1_x))); Evas_Coord h2 = round(((double) h * (ld->part_info.rel2_y - ld->part_info.rel1_y))); evas_object_resize(ld->layout, w2, h2); } static void live_edit_update(live_data *ld) { layout_update(ld); ctrl_pt_update(ld); align_line_update(ld); info_text_update(ld); } static void live_view_geom_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { live_data *ld = data; live_edit_update(ld); } static void layout_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Move *ev = event_info; live_data *ld = data; Evas_Coord lx, ly, lw, lh; evas_object_geometry_get(ld->live_view, &lx, &ly, NULL, NULL); config_view_size_get(&lw, &lh); Evas_Coord x, y, w, h; evas_object_geometry_get(obj, &x, &y, &w, &h); //only affect when cursor is inside of the part if (ev->cur.canvas.x > (x + w)) return; if (x > ev->cur.canvas.x) return; if (ev->cur.canvas.y > (y + h)) return; if (y > ev->cur.canvas.y) return; double tmp; tmp = ((double) (ev->cur.canvas.x - ev->prev.canvas.x) * 0.5); x = round(((double) x) + tmp); tmp = ((double) (ev->cur.canvas.y - ev->prev.canvas.y) * 0.5); y = round(((double) y) + tmp); //limit to live view boundary if (lx > x) x = lx; if ((x + w) > (lx + lw)) x -= ((x + w) - (lx + lw)); if (ly > y) y = ly; if ((y + h) > (ly + lh)) y -= ((y + h) - (ly + lh)); double orig_rel1_x = ld->part_info.rel1_x; double orig_rel1_y = ld->part_info.rel1_y; ld->part_info.rel1_x = ROUNDING(((double) (x - lx) / lw), 2); ld->part_info.rel1_y = ROUNDING(((double) (y - ly) / lh), 2); ld->part_info.rel2_x += ROUNDING((ld->part_info.rel1_x - orig_rel1_x), 2); ld->part_info.rel2_y += ROUNDING((ld->part_info.rel1_y - orig_rel1_y), 2); evas_object_move(obj, x, y); ctrl_pt_update(ld); info_text_update(ld); align_line_update(ld); } static void layout_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE, layout_mouse_move_cb); live_data *ld = data; align_lines_hide(ld); //Show hidden control points elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Top], "elm,state,show", ""); elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Bottom], "elm,state,show", ""); elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Left], "elm,state,show", ""); elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Right], "elm,state,show", ""); } static void layout_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; live_data *ld = data; //insert part on double click if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) { live_edit_insert(ld); live_edit_cancel(); return; } evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, layout_mouse_move_cb, data); //Hide unnecessary control points elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Top], "elm,state,hide", ""); elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Bottom], "elm,state,hide", ""); elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Left], "elm,state,hide", ""); elm_object_signal_emit(ld->ctrl_pt[Ctrl_Pt_Right], "elm,state,hide", ""); } static void align_line_init(live_data *ld) { //Create Align Lines int i; for (i = 0; i < Align_Line_Cnt; i++) { Evas_Object *layout = elm_layout_add(ld->layout); elm_layout_file_set(layout, EDJE_PATH, "ctrl_pt"); evas_object_show(layout); elm_object_signal_emit(layout, "elm,state,hide,instance", ""); ld->align_line[i] = layout; } } static void info_text_init(live_data *ld) { //Create Info Texts int i; Evas *e = evas_object_evas_get(ld->layout); double scale = elm_config_scale_get(); for (i = 0; i < Info_Text_Cnt; i++) { Evas_Object *text = evas_object_text_add(e); evas_object_pass_events_set(text, EINA_TRUE); evas_object_layer_set(text, INFO_TEXT_LAYER); evas_object_text_font_set(text, LIVE_EDIT_FONT, ( LIVE_EDIT_FONT_SIZE * scale)); evas_object_text_style_set(text, EVAS_TEXT_STYLE_OUTLINE); evas_object_text_outline_color_set(text, 0, 0, 0, 255); evas_object_show(text); ld->info_text[i] = text; } info_text_update(ld); } static void live_edit_layer_set(live_data *ld) { ld->key_down_handler = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, key_down_cb, ld); evas_object_event_callback_add(ld->live_view, EVAS_CALLBACK_RESIZE, live_view_geom_cb, ld); evas_object_event_callback_add(ld->live_view, EVAS_CALLBACK_MOVE, live_view_geom_cb, ld); //Create Live View Layout Evas_Object *layout = elm_layout_add(ld->live_view); elm_layout_file_set(layout, EDJE_PATH, "live_edit_layout"); evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_DOWN, layout_mouse_down_cb, ld); evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_UP, layout_mouse_up_cb, ld); elm_layout_part_cursor_set(layout, "cursor_body", ELM_CURSOR_FLEUR); evas_object_show(layout); ld->layout = layout; //Initial Layout Geometry ld->part_info.rel1_x = LIVE_EDIT_REL1; ld->part_info.rel1_y = LIVE_EDIT_REL1; ld->part_info.rel2_x = LIVE_EDIT_REL2; ld->part_info.rel2_y = LIVE_EDIT_REL2; live_edit_symbol_set(ld); ctrl_pt_init(ld); align_line_init(ld); live_edit_update(ld); info_text_init(ld); } static void ctxpopup_it_selected_cb(void *data, Evas_Object *obj, void *event_info) { live_data *ld = g_ld; const Elm_Object_Item *it = event_info; ld->part_info.type = (unsigned int) data; live_edit_layer_set(ld); elm_ctxpopup_dismiss(obj); stats_info_msg_update("Click and drag the mouse in the Live View."); } static void ctxpopup_dismissed_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { live_data *ld = data; if (!ld->layout) live_edit_cancel(); evas_object_del(obj); ld->ctxpopup = NULL; } static Evas_Object * ctxpopup_create(live_data *ld) { const int CTXPOPUP_ITEMS_NUM = 6; int i; Evas_Object *ctxpopup = elm_ctxpopup_add(ld->live_view); elm_ctxpopup_direction_priority_set(ctxpopup, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_LEFT, ELM_CTXPOPUP_DIRECTION_UP); for (i = 0; i < CTXPOPUP_ITEMS_NUM; i++) { Evas_Object *icon = elm_image_add(ctxpopup); elm_image_file_set(icon, EDJE_PATH, CTXPOPUP_ITEMS[i].name); elm_ctxpopup_item_append(ctxpopup, CTXPOPUP_ITEMS[i].name, icon, ctxpopup_it_selected_cb, (void *)i); } evas_object_smart_callback_add(ctxpopup, "dismissed", ctxpopup_dismissed_cb, ld); Evas_Coord x, y, w, h; evas_object_geometry_get(ld->trigger, &x, &y, &w, &h); evas_object_move(ctxpopup, (x + (w/2)), (y + h)); evas_object_show(ctxpopup); return ctxpopup; } void live_edit_toggle(void) { live_data *ld = g_ld; Eina_Bool on = !ld->on; if (on) { enventor_object_disabled_set(ld->enventor, EINA_TRUE); ld->live_view = enventor_object_live_view_get(ld->enventor); ld->ctxpopup = ctxpopup_create(ld); stats_info_msg_update("Select a part to add in Live View."); } else { live_edit_cancel(); stats_info_msg_update("Live View Edit Mode Disabled."); } ld->on = on; } Eina_Bool live_edit_get(void) { live_data *ld = g_ld; return ld->on; } void live_edit_cancel(void) { live_data *ld = g_ld; if (!ld->on) return; if (ld->ctxpopup) elm_ctxpopup_dismiss(ld->ctxpopup); enventor_object_disabled_set(ld->enventor, EINA_FALSE); ecore_event_handler_del(ld->key_down_handler); ld->key_down_handler = NULL; evas_object_event_callback_del(ld->live_view, EVAS_CALLBACK_RESIZE, live_view_geom_cb); evas_object_event_callback_del(ld->live_view, EVAS_CALLBACK_MOVE, live_view_geom_cb); ld->live_view = NULL; evas_object_del(ld->layout); ld->layout = NULL; //Delete Control Points int i; for (i = 0; i < Ctrl_Pt_Cnt; i++) { evas_object_del(ld->ctrl_pt[i]); ld->ctrl_pt[i] = NULL; } //Delete Align Lines for (i = 0; i < Align_Line_Cnt; i++) { evas_object_del(ld->align_line[i]); ld->align_line[i] = NULL; } //Delete Info Texts for (i = 0; i < Info_Text_Cnt; i++) { evas_object_del(ld->info_text[i]); ld->info_text[i] = NULL; } ld->on = EINA_FALSE; } void live_edit_init(Evas_Object *enventor, Evas_Object *trigger) { live_data *ld = calloc(1, sizeof(live_data)); if (!ld) { EINA_LOG_ERR("Faild to allocate Memory!"); return; } g_ld = ld; ld->enventor = enventor; ld->trigger = trigger; } void live_edit_term(void) { live_data *ld = g_ld; evas_object_del(ld->ctxpopup); ld->ctxpopup = NULL; live_edit_cancel(); free(ld); g_ld = NULL; }