hermet pushed a commit to branch master.

http://git.enlightenment.org/tools/enventor.git/commit/?id=279eea73eb72808c50322f97ebee8f891010f7f8

commit 279eea73eb72808c50322f97ebee8f891010f7f8
Author: Taehyub Kim <taehyub....@samsung.com>
Date:   Tue May 3 16:53:07 2016 +0900

    live_edit: add new feature about auto align
    
    Summary:
    when we are layouting using live edit item,
    It is hart to align the inserting item among the exist parts.
    so add auto align feature to align easily.
    
    Test Plan:
    1. launch enventor
    2. add a live item using the toolbar
    3. move and resize the live item in live view
    4. check the auto align function when the item near another part
    
    Reviewers: Jaehyun_Cho, NikaWhite, Hermet
    
    Differential Revision: https://phab.enlightenment.org/D3884
---
 src/bin/live_edit.c     | 372 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/include/live_edit.h |   2 +
 2 files changed, 374 insertions(+)

diff --git a/src/bin/live_edit.c b/src/bin/live_edit.c
index b93d261..ec4356a 100644
--- a/src/bin/live_edit.c
+++ b/src/bin/live_edit.c
@@ -55,6 +55,7 @@ typedef struct live_editor_s
    Evas_Object *info_text[Info_Text_Cnt];
    Evas_Coord_Point move_delta;
    double half_ctrl_size;
+   unsigned int auto_align_dist;
 
    struct {
       unsigned int type;
@@ -63,10 +64,18 @@ typedef struct live_editor_s
    } part_info;
 
    Evas_Object *keygrabber;
+   Eina_Array *auto_align_array;
 
    Eina_Bool on : 1;
 } live_data;
 
+typedef struct auto_align_data_s
+{
+   Evas_Coord_Point pt1;
+   Evas_Coord_Point pt2;
+} auto_align_data;
+
+
 static void live_edit_update_internal(live_data *ld);
 
 #define LIVEEDIT_ITEMS_NUM 6
@@ -235,6 +244,69 @@ keygrabber_key_down_cb(void *data, Evas *e EINA_UNUSED,
    live_edit_cancel();
 }
 
+Evas_Coord_Point
+calc_ctrl_pt_auto_align_pos(live_data *ld, int cursor_x, int cursor_y)
+{
+   int res_x, res_y;
+   int nx, ny;
+   res_x = res_y = -1;
+   nx = ny = LIVE_EDIT_MAX_DIST;
+   int dist = ld->auto_align_dist;
+
+   // This loop finds the closest position of part to control point
+   // And then return the position
+   unsigned int i;
+   auto_align_data *al_pos;
+   Eina_Array_Iterator iter;
+   EINA_ARRAY_ITER_NEXT(ld->auto_align_array, i, al_pos, iter)
+   {
+      unsigned int dx, dy, i;
+
+      dx = abs(al_pos->pt1.x - cursor_x);
+      dy = abs(al_pos->pt1.y - cursor_y);
+
+      if ((dx < dist) && (dx < nx) && (cursor_y >= al_pos->pt1.y) && (cursor_y 
<= al_pos->pt2.y))
+        {
+           nx = dx;
+           res_x = al_pos->pt1.x;
+        }
+      if ((dy < dist) && (dy < ny) && (cursor_x >= al_pos->pt1.x) && (cursor_x 
<= al_pos->pt2.x))
+        {
+           ny = dy;
+           res_y = al_pos->pt1.y;
+        }
+
+      dx = abs(al_pos->pt2.x - cursor_x);
+      dy = abs(al_pos->pt2.y - cursor_y);
+
+      if ((dx < dist) && (dx < nx) && (cursor_y >= al_pos->pt1.y) && (cursor_y 
<= al_pos->pt2.y))
+        {
+           nx = dx;
+           res_x = al_pos->pt2.x;
+        }
+      if ((dy < dist) && (dy < ny) && (cursor_x >= al_pos->pt1.x) && (cursor_x 
<= al_pos->pt2.x))
+        {
+           ny = dy;
+           res_y = al_pos->pt2.y;
+        }
+   }
+
+   Evas_Coord_Point pt;
+
+   if (res_x != -1)
+     pt.x = res_x;
+   else
+     pt.x = cursor_x;
+
+   if (res_y != -1)
+     pt.y = res_y;
+   else
+     pt.y = cursor_y;
+
+   return pt;
+}
+
+
 static void
 ctrl_pt_update(live_data *ld)
 {
@@ -297,6 +369,8 @@ cp_top_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    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;
 
    Evas_Object *view = view_obj_get(ld);
@@ -306,6 +380,11 @@ cp_top_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel2_y;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], NULL, &rel2_y,
                             NULL, NULL);
+
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   y = pt.y;
+
    if (vy > y) y = vy;
    if ((y - ld->half_ctrl_size) > rel2_y) y = (rel2_y + ld->half_ctrl_size);
 
@@ -322,6 +401,8 @@ cp_bottom_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    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;
 
    Evas_Object *view = view_obj_get(ld);
@@ -331,6 +412,11 @@ cp_bottom_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel1_y;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], NULL, &rel1_y,
                             NULL, NULL);
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   y = pt.y;
+
+
    if (y > (vy + vh)) y = (vy + vh);
    if (rel1_y > (y + ld->half_ctrl_size)) y = (rel1_y + ld->half_ctrl_size);
 
@@ -451,6 +537,12 @@ cp_rel1_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel2_x, rel2_y;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rel2_x, &rel2_y,
                             NULL, NULL);
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   x = pt.x;
+   y = pt.y;
+
+
    if (vx > x) x = vx;
    if (vy > y) y = vy;
    if ((x - ld->half_ctrl_size) > rel2_x) x = (rel2_x + ld->half_ctrl_size);
@@ -482,6 +574,11 @@ cp_rel2_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel1_x, rel1_y;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rel1_x, &rel1_y,
                             NULL, NULL);
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   x = pt.x;
+   y = pt.y;
+
    if (x > (vx + vw)) x = (vx + vw);
    if (y > (vy + vh)) y = (vy + vh);
    if (rel1_x > (x + ld->half_ctrl_size)) x = (rel1_x + ld->half_ctrl_size);
@@ -514,6 +611,11 @@ cp_rel3_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel1_x;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rel1_x, NULL,
                             NULL, NULL);
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   x = pt.x;
+   y = pt.y;
+
    if (x > (vx + vw)) x = (vx + vw);
    if (rel1_x > (x + ld->half_ctrl_size)) x = (rel1_x - ld->half_ctrl_size);
 
@@ -549,6 +651,11 @@ cp_rel4_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel2_x;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rel2_x, NULL,
                             NULL, NULL);
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   x = pt.x;
+   y = pt.y;
+
    if (vx > x) x = vx;
    if ((x - ld->half_ctrl_size) > rel2_x) x = (rel2_x + ld->half_ctrl_size);
 
@@ -576,6 +683,7 @@ cp_left_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Event_Mouse_Move *ev = event_info;
 
    Evas_Coord x = ev->cur.canvas.x;
+   Evas_Coord y = ev->cur.canvas.y;
 
    Evas_Object *view = view_obj_get(ld);
    Evas_Coord vx, vy, vw, vh;
@@ -584,6 +692,11 @@ cp_left_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel2_x;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel2], &rel2_x, NULL,
                             NULL, NULL);
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   x = pt.x;
+
+
    if (vx > x) x = vx;
    if ((x - ld->half_ctrl_size) > rel2_x) x = (rel2_x + ld->half_ctrl_size);
 
@@ -602,6 +715,7 @@ cp_right_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Event_Mouse_Move *ev = event_info;
 
    Evas_Coord x = ev->cur.canvas.x;
+   Evas_Coord y = ev->cur.canvas.y;
 
    Evas_Object *view = view_obj_get(ld);
    Evas_Coord vx, vy, vw, vh;
@@ -610,6 +724,12 @@ cp_right_mouse_move_cb(void *data, Evas *e EINA_UNUSED,
    Evas_Coord rel1_x;
    evas_object_geometry_get(ld->ctrl_pt[Ctrl_Pt_Rel1], &rel1_x, NULL,
                             NULL, NULL);
+
+
+   Evas_Coord_Point pt = calc_ctrl_pt_auto_align_pos(ld, x, y);
+   x = pt.x;
+
+
    if (x > (vx + vw)) x = (vx + vw);
    if (rel1_x > (x + ld->half_ctrl_size)) x = (rel1_x + ld->half_ctrl_size);
 
@@ -753,6 +873,80 @@ ctrl_pt_init(live_data *ld)
    ctrl_pt_update(ld);
 }
 
+static free_auto_align_data(Eina_Array *arr)
+{
+   unsigned int i;
+   Eina_Array_Iterator iter;
+   auto_align_data *al_pos;
+
+   if (arr)
+     {
+        EINA_ARRAY_ITER_NEXT(arr, i, al_pos, iter)
+        {
+           free(al_pos);
+        }
+        eina_array_free(arr);
+        arr = NULL;
+     }
+}
+
+static void
+live_edit_auto_align_target_parts_init(live_data *ld, Eina_Bool is_update)
+{
+   Eina_List *l;
+
+   Evas_Object *view_obj = view_obj_get(ld);
+   Evas_Coord vx, vy;
+   evas_object_geometry_get(view_obj, &vx, &vy, NULL, NULL);
+
+   // set target parts for finding the boundary of exists parts
+   char *part_name;
+   Eina_List *parts = enventor_object_parts_list_get(base_enventor_get());
+
+   Evas_Object *part_obj;
+   Evas_Coord x,y,w,h;
+   //Case 1: create new auto_align_data for new live edit item
+   if (!is_update)
+     {
+        free_auto_align_data(ld->auto_align_array);
+        ld->auto_align_array = eina_array_new(eina_list_count(parts));
+        EINA_LIST_FOREACH(parts, l, part_name)
+        {
+           part_obj = (Evas_Object *) edje_object_part_object_get(view_obj, 
part_name);
+           edje_object_part_geometry_get(view_obj, part_name, &x, &y, &w, &h);
+           auto_align_data *al_pos = calloc(1, sizeof(auto_align_data));
+           al_pos->pt1.x = x + vx;
+           al_pos->pt1.y = y + vy;
+           al_pos->pt2.x = x + w + vx;
+           al_pos->pt2.y = y + h + vy;
+           eina_array_push(ld->auto_align_array, al_pos);
+        }
+     }
+   //Case 2: update the exsit auto_align_data when view is resized
+   else
+     {
+        int i = 0, item_cnt;
+        if (ld->auto_align_array)
+          {
+             item_cnt = eina_array_count_get(ld->auto_align_array);
+             EINA_LIST_FOREACH(parts, l, part_name)
+             {
+                part_obj = (Evas_Object *) 
edje_object_part_object_get(view_obj, part_name);
+                edje_object_part_geometry_get(view_obj, part_name, &x, &y, &w, 
&h);
+
+                if (i < item_cnt)
+                  {
+                     auto_align_data *al_pos = 
eina_array_data_get(ld->auto_align_array, i++);
+                     al_pos->pt1.x = x + vx;
+                     al_pos->pt1.y = y + vy;
+                     al_pos->pt2.x = x + w + vx;
+                     al_pos->pt2.y = y + h + vy;
+                  }
+              }
+         }
+     }
+}
+
 static void
 layout_update(live_data *ld)
 {
@@ -768,6 +962,8 @@ layout_update(live_data *ld)
    double h2 =
      round(((double) h * (ld->part_info.rel2_y - ld->part_info.rel1_y)));
    evas_object_resize(ld->layout, w2, h2);
+
+   live_edit_auto_align_target_parts_init(ld, EINA_TRUE);
 }
 
 static void
@@ -789,6 +985,164 @@ live_view_geom_cb(void *data, Evas *e EINA_UNUSED,
 }
 
 static void
+calc_layout_auto_align_pos(Evas_Object *layout, live_data *ld, int x, int y,
+                           int layout_dir_x, int layout_dir_y, int *ret_x, int 
*ret_y)
+{
+   // This function cacluates the position of layout to the closest part edge
+   static int pre_layout_dir_x, pre_layout_dir_y;
+
+   Eina_Bool is_up, is_down, is_left, is_right;
+   is_up = is_down = is_left = is_right = EINA_FALSE;
+
+   Evas_Coord w, h;
+   evas_object_geometry_get(layout, NULL, NULL, &w, &h);
+
+   // layout_dir_x and layout_dir_y are the current direction of layout,
+   // pre_layout_dir_x and pre_layout_dir_y are previous direction of layout.
+   // These conditions are used to align the layout in moving direction
+   if (layout_dir_x == 0)
+     {
+       if (pre_layout_dir_x < 0)
+         {
+            is_left = EINA_TRUE;
+            pre_layout_dir_x = -1;
+         }
+       else
+         {
+            is_right = EINA_TRUE;
+            pre_layout_dir_x = 1;
+         }
+     }
+   else
+     {
+        pre_layout_dir_x = layout_dir_x;
+        if (layout_dir_x < 0)
+          is_left = EINA_TRUE;
+        else if (layout_dir_x > 0)
+          is_right = EINA_TRUE;
+     }
+
+   if (layout_dir_y == 0)
+     {
+       if (pre_layout_dir_y < 0)
+         {
+            is_up = EINA_TRUE;
+            pre_layout_dir_y = -1;
+         }
+     else
+       {
+          is_down = EINA_TRUE;
+          pre_layout_dir_y = 1;
+       }
+     }
+   else
+     {
+        pre_layout_dir_y = layout_dir_y;
+        if (layout_dir_y < 0)
+          is_up = EINA_TRUE;
+        else if (layout_dir_y > 0)
+          is_down = EINA_TRUE;
+     }
+
+   unsigned int res_x1, res_y1, res_x2, res_y2;
+   unsigned int nx, ny, nx2, ny2;
+   res_x1 = res_y1 = res_x2 = res_y2 = -1;
+   nx = ny = nx2 = ny2 = LIVE_EDIT_MAX_DIST;
+   unsigned int dist = ld->auto_align_dist;
+
+   // This loop finds the closest part to the layout
+   Eina_Array *arr;
+   unsigned int i;
+   auto_align_data *al_pos;
+   Eina_Array_Iterator iter;
+   EINA_ARRAY_ITER_NEXT(ld->auto_align_array, i, al_pos, iter)
+   {
+      unsigned int dx1, dy1, dx2, dy2;
+      dx1 = dy1 = dx2 = dy2 = LIVE_EDIT_MAX_DIST;
+      if ((al_pos->pt1.y <= y) && (al_pos->pt2.y >= y) || (al_pos->pt1.y <= (y 
+ h)) &&
+          (al_pos->pt2.y >= (y + h)) || (al_pos->pt1.y >= y) && (al_pos->pt2.y 
<= (y + h)))
+        {
+           dx1 = abs(al_pos->pt1.x - x);
+           dx2 = abs(al_pos->pt1.x - (x + w));
+        }
+
+      if ((al_pos->pt1.x <= x) && (al_pos->pt2.x >= x) || (al_pos->pt1.x <= (x 
+ w)) &&
+          (al_pos->pt2.x >= (x + w)) || (al_pos->pt1.x >= x) && (al_pos->pt2.x 
<= (x + w)))
+        {
+           dy1 = abs(al_pos->pt1.y - y);
+           dy2 = abs(al_pos->pt1.y - (y + h));
+        }
+
+      if (is_left && (dx1 < dist) && (dx1 < nx))
+        {
+           nx = dx1;
+           res_x1 = al_pos->pt1.x;
+        }
+      if (is_right && (dx2 < dist) && (dx2 < nx2))
+        {
+           nx2 = dx2;
+           res_x2 = al_pos->pt1.x;
+        }
+      if (is_up && (dy1 < dist) && (dy1 < ny))
+        {
+           ny = dy1;
+           res_y1 = al_pos->pt1.y;
+        }
+      if (is_down && (dy2 < dist) && (dy2 < ny2))
+        {
+           ny2 = dy2;
+           res_y2 = al_pos->pt1.y;
+        }
+
+      if ((al_pos->pt1.y <= y) && (al_pos->pt2.y >= y) || (al_pos->pt1.y <= (y 
+ h)) &&
+          (al_pos->pt2.y >= (y + h)) || (al_pos->pt1.y >= y) && (al_pos->pt2.y 
<= (y + h)))
+        {
+           dx1 = abs(al_pos->pt2.x - x);
+           dx2 = abs(al_pos->pt2.x - (x + w));
+        }
+
+      if ((al_pos->pt1.x <= x) && (al_pos->pt2.x >= x) || (al_pos->pt1.x <= (x 
+ w)) &&
+          (al_pos->pt2.x >= (x + w)) || (al_pos->pt1.x >= x) && (al_pos->pt2.x 
<= (x + w)))
+        {
+           dy1 = abs(al_pos->pt2.y - y);
+           dy2 = abs(al_pos->pt2.y - (y + h));
+        }
+
+      if (is_left && (dx1 < dist) && (dx1 < nx))
+        {
+           nx = dx1;
+           res_x1 = al_pos->pt2.x;
+        }
+      if (is_right && (dx2 < dist) && (dx2 < nx2))
+        {
+           nx2 = dx2;
+           res_x2 = al_pos->pt2.x;
+        }
+      if (is_up && (dy1 < dist) && (dy1 < ny))
+        {
+           ny = dy1;
+           res_y1 = al_pos->pt2.y;
+        }
+      if (is_down && (dy2 < dist) && (dy2 < ny2))
+        {
+           ny2 = dy2;
+           res_y2 = al_pos->pt2.y;
+        }
+   }
+
+   // If we find the closest position and return it
+   if (is_left && (res_x1 != -1))
+     *ret_x = res_x1;
+   else if (is_right && (res_x2 != -1))
+     *ret_x = res_x2 - w;
+
+   if (is_up && (res_y1 != -1))
+     *ret_y = res_y1;
+   else if (is_down && (res_y2 != -1))
+     *ret_y = res_y2 - h;
+}
+
+static void
 layout_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj,
                      void *event_info)
 {
@@ -813,6 +1167,20 @@ layout_mouse_move_cb(void *data, Evas *e EINA_UNUSED, 
Evas_Object *obj,
    x = ev->cur.canvas.x - ld->move_delta.x;
    y = ev->cur.canvas.y - ld->move_delta.y;
 
+   Evas_Coord dir_x, dir_y;
+   dir_x =  ev->cur.canvas.x - ev->prev.canvas.x;
+   dir_y = ev->cur.canvas.y - ev->prev.canvas.y;
+
+   int ret_x, ret_y;
+   ret_x = x;
+   ret_y = y;
+
+   // This function set the position of layout to the closest part edge
+   calc_layout_auto_align_pos(obj, ld, x, y, dir_x, dir_y, &ret_x, &ret_y);
+
+   x = ret_x;
+   y = ret_y;
+
    //limit to live view boundary
    if (vx > x) x = vx;
    if ((x + w) > (vx + vw)) x = (vx + vw) - w;
@@ -991,6 +1359,7 @@ live_edit_layer_set(live_data *ld)
    align_line_init(ld);
    live_edit_update_internal(ld);
    info_text_init(ld);
+   live_edit_auto_align_target_parts_init(ld, EINA_FALSE);
 }
 
 static void
@@ -1143,6 +1512,7 @@ live_edit_init(Evas_Object *trigger)
      }
    g_ld = ld;
    ld->trigger = trigger;
+   ld->auto_align_dist = LIVE_EDIT_AUTO_ALIGN_DIST;
 }
 
 void
@@ -1151,6 +1521,8 @@ live_edit_term(void)
    live_data *ld = g_ld;
    evas_object_del(ld->toolbox);
    live_edit_cancel();
+
+   free_auto_align_data(ld->auto_align_array);
    free(ld);
    g_ld = NULL;
 }
diff --git a/src/include/live_edit.h b/src/include/live_edit.h
index 626146a..a886442 100644
--- a/src/include/live_edit.h
+++ b/src/include/live_edit.h
@@ -2,6 +2,8 @@
 #define LIVE_EDIT_REL2 0.75
 #define LIVE_EDIT_FONT "Sans"
 #define LIVE_EDIT_FONT_SIZE 10
+#define LIVE_EDIT_MAX_DIST 999999
+#define LIVE_EDIT_AUTO_ALIGN_DIST 10
 
 void live_edit_init(Evas_Object *trigger);
 void live_edit_term(void);

-- 


Reply via email to