Elementary: Drag & Drop feature for items containers
authorDaniel Zaoui <daniel.zaoui@samsung.com>
Sun, 17 Mar 2013 06:36:30 +0000 (08:36 +0200)
committerDaniel Zaoui <daniel.zaoui@samsung.com>
Thu, 9 May 2013 10:57:31 +0000 (13:57 +0300)
New APIs have been added to facilitate DnD for genlist, gengrid and list
widgets.
Tests have been added in the new section DnD to play with that.

12 files changed:
src/bin/Makefile.am
src/bin/test.c
src/bin/test_dnd.c [new file with mode: 0644]
src/bin/test_genlist.c
src/lib/elm_cnp.c
src/lib/elm_cnp.h
src/lib/elm_gengrid.c
src/lib/elm_gengrid_eo.h
src/lib/elm_gengrid_legacy.h
src/lib/elm_list.c
src/lib/elm_list_eo.h
src/lib/elm_list_legacy.h

index c567002..0fd1e8f 100644 (file)
@@ -65,6 +65,7 @@ test_cursor.c \
 test_datetime.c \
 test_dayselector.c \
 test_diskselector.c \
+test_dnd.c \
 test_entry.c \
 test_entry_anchor.c \
 test_entry_anchor2.c \
index 0e30d84..77de0bd 100644 (file)
@@ -216,6 +216,9 @@ void test_eio(void *data, Evas_Object *obj, void *event_info);
 void test_web_normal(void *data, Evas_Object *obj, void *event_info);
 void test_web_mobile(void *data, Evas_Object *obj, void *event_info);
 #endif
+void test_dnd_genlist_default_anim(void *data, Evas_Object *obj, void *event_info);
+void test_dnd_genlist_user_anim(void *data, Evas_Object *obj, void *event_info);
+void test_dnd_genlist_gengrid(void *data, Evas_Object *obj, void *event_info);
 
 Evas_Object *win, *tbx; // TODO: refactoring
 void *tt;
@@ -742,6 +745,11 @@ add_tests:
    ADD_TEST(NULL, "System", "Systray Item", test_systray);
 
    //------------------------------//
+   ADD_TEST(NULL, "Drag & Drop", "Genlist DnD Dflt Anim", test_dnd_genlist_default_anim);
+   ADD_TEST(NULL, "Drag & Drop", "Genlist DnD User Anim", test_dnd_genlist_user_anim);
+   ADD_TEST(NULL, "Drag & Drop", "Genlist-Gengrid DnD", test_dnd_genlist_gengrid);
+
+   //------------------------------//
    ADD_TEST(NULL, "Miscellaneous", "Copy And Paste", test_cnp);
    ADD_TEST(NULL, "Miscellaneous", "Weather", test_weather);
    ADD_TEST(NULL, "Miscellaneous", "Icon Desktops", test_icon_desktops);
diff --git a/src/bin/test_dnd.c b/src/bin/test_dnd.c
new file mode 100644 (file)
index 0000000..e32385b
--- /dev/null
@@ -0,0 +1,894 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+#include <Elementary.h>
+
+static const char *img[9] =
+{
+   "panel_01.jpg",
+   "plant_01.jpg",
+   "rock_01.jpg",
+   "rock_02.jpg",
+   "sky_01.jpg",
+   "sky_02.jpg",
+   "sky_03.jpg",
+   "sky_04.jpg",
+   "wood_01.jpg",
+};
+
+struct _anim_icon_st
+{
+   int start_x;
+   int start_y;
+   Evas_Object *o;
+};
+typedef struct _anim_icon_st anim_icon_st;
+
+struct _drag_anim_st
+{
+   Evas_Object *icwin;
+   Evas *e;
+   Evas_Coord mdx;     /* Mouse-down x */
+   Evas_Coord mdy;     /* Mouse-down y */
+   Eina_List *icons;   /* List of icons to animate (anim_icon_st) */
+   Ecore_Timer *tm;
+   Ecore_Animator *ea;
+   Evas_Object *gl;
+};
+typedef struct _drag_anim_st drag_anim_st;
+
+#define DRAG_TIMEOUT 0.3
+#define ANIM_TIME 0.5
+
+static int
+_item_ptr_cmp(const void *d1, const void *d2)
+{
+   return (d1 - d2);
+}
+
+static Elm_Genlist_Item_Class *itc1;
+static Elm_Gengrid_Item_Class *gic;
+static char *
+gl_text_get(void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__)
+{
+   return strdup(data);
+}
+
+static Evas_Object *
+gl_content_get(void *data, Evas_Object *obj, const char *part)
+{
+   if (!strcmp(part, "elm.swallow.icon"))
+     {
+        Evas_Object *icon = elm_icon_add(obj);
+        elm_image_file_set(icon, data, NULL);
+        evas_object_size_hint_aspect_set(icon, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+        evas_object_show(icon);
+        return icon;
+     }
+   return NULL;
+}
+
+static void
+_win_del(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   printf("<%s> <%d> will del <%p>\n", __func__, __LINE__, data);
+   elm_drop_item_container_del(data);
+   elm_drag_item_container_del(data);
+
+   if (gic) elm_gengrid_item_class_free(gic);
+   gic = NULL;
+   if (itc1) elm_genlist_item_class_free(itc1);
+   itc1 = NULL;
+}
+
+static Elm_Object_Item *
+_gl_item_getcb(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret __UNUSED__, int *yposret)
+{  /* This function returns pointer to item under (x,y) coords */
+   printf("<%s> <%d> obj=<%p>\n", __func__, __LINE__, obj);
+   Elm_Object_Item *gli;
+   gli = elm_genlist_at_xy_item_get(obj, x, y, yposret);
+   if (gli)
+     printf("over <%s>, gli=<%p> yposret %i\n",
+           elm_object_item_part_text_get(gli, "elm.text"), gli, *yposret);
+   else
+     printf("over none, yposret %i\n", *yposret);
+   return gli;
+}
+
+static Elm_Object_Item *
+_grid_item_getcb(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret, int *yposret)
+{  /* This function returns pointer to item under (x,y) coords */
+   printf("<%s> <%d> obj=<%p>\n", __func__, __LINE__, obj);
+   Elm_Object_Item *item;
+   item = elm_gengrid_at_xy_item_get(obj, x, y, xposret, yposret);
+   if (item)
+     printf("over <%s>, item=<%p> xposret %i yposret %i\n",
+           elm_object_item_part_text_get(item, "elm.text"), item, *xposret, *yposret);
+   else
+     printf("over none, xposret %i yposret %i\n", *xposret, *yposret);
+   return item;
+}
+
+static Eina_Bool
+_gl_dropcb(void *data __UNUSED__, Evas_Object *obj, Elm_Object_Item *it, Elm_Selection_Data *ev, int xposret __UNUSED__, int yposret)
+{  /* This function is called when data is dropped on the genlist */
+   printf("<%s> <%d> str=<%s>\n", __func__, __LINE__, (char *) ev->data);
+   if (!ev->data)
+     return EINA_FALSE;
+
+   char *p = ev->data;
+   p = strchr(p, '#');
+   while(p)
+     {
+        p++;
+        char *p2 = strchr(p, '#');
+        if (p2)
+          {
+             *p2 = '\0';
+             printf("Item %s\n", p);
+             switch(yposret)
+               {
+                case -1:  /* Dropped on top-part of the it item */
+                     {
+                        elm_genlist_item_insert_before(obj,
+                              itc1, strdup(p), NULL, it,
+                              ELM_GENLIST_ITEM_NONE,
+                              NULL, NULL);
+                        break;
+                     }
+                case  0:  /* Dropped on center of the it item      */
+                case  1:  /* Dropped on botton-part of the it item */
+                     {
+                        if (!it) it = elm_genlist_last_item_get(obj);
+                        if (it) it = elm_genlist_item_insert_after(obj,
+                              itc1, strdup(p), NULL, it,
+                              ELM_GENLIST_ITEM_NONE,
+                              NULL, NULL);
+                        else
+                           it = elm_genlist_item_append(obj,
+                                 itc1, strdup(p), NULL,
+                                 ELM_GENLIST_ITEM_NONE,
+                                 NULL, NULL);
+                        break;
+                     }
+                default:
+                   return EINA_FALSE;
+               }
+             p = p2;
+          }
+        else p = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_grid_dropcb(void *data __UNUSED__, Evas_Object *obj, Elm_Object_Item *it, Elm_Selection_Data *ev, int xposret __UNUSED__, int yposret EINA_UNUSED)
+{  /* This function is called when data is dropped on the genlist */
+   printf("<%s> <%d> str=<%s>\n", __func__, __LINE__, (char *) ev->data);
+   if (!ev->data)
+     return EINA_FALSE;
+
+   char *p = ev->data;
+   p = strchr(p, '#');
+   while(p)
+     {
+        p++;
+        char *p2 = strchr(p, '#');
+        if (p2)
+          {
+             *p2 = '\0';
+             printf("Item %s\n", p);
+             if (!it) it = elm_gengrid_last_item_get(obj);
+             if (it) it = elm_gengrid_item_insert_after(obj, gic, strdup(p), it, NULL, NULL);
+             else it = elm_gengrid_item_append(obj, gic, strdup(p), NULL, NULL);
+             p = p2;
+          }
+        else p = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+static void _gl_obj_mouse_move( void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _gl_obj_mouse_up( void *data, Evas *e, Evas_Object *obj, void *event_info);
+
+static void
+anim_st_free(drag_anim_st *anim_st)
+{  /* Stops and free mem of ongoing animation */
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   if (anim_st)
+     {
+        evas_object_event_callback_del_full
+           (anim_st->gl, EVAS_CALLBACK_MOUSE_MOVE, _gl_obj_mouse_move, anim_st);
+        evas_object_event_callback_del_full
+           (anim_st->gl, EVAS_CALLBACK_MOUSE_UP, _gl_obj_mouse_up, anim_st);
+        if (anim_st->tm)
+          {
+             ecore_timer_del(anim_st->tm);
+             anim_st->tm = NULL;
+          }
+
+        if (anim_st->ea)
+          {
+             ecore_animator_del(anim_st->ea);
+             anim_st->ea = NULL;
+          }
+
+        anim_icon_st *st;
+
+        EINA_LIST_FREE(anim_st->icons, st)
+          {
+             evas_object_hide(st->o);
+             evas_object_del(st->o);
+             free(st);
+          }
+
+        free(anim_st);
+     }
+}
+
+static Eina_Bool
+_drag_anim_play(void *data, double pos)
+{  /* Impl of the animation of icons, called on frame time */
+   drag_anim_st *anim_st = data;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   Eina_List *l;
+   anim_icon_st *st;
+
+   if (anim_st)
+     {
+        if (pos > 0.99)
+          {
+             anim_st->ea = NULL;  /* Avoid deleting on mouse up */
+
+             EINA_LIST_FOREACH(anim_st->icons, l, st)
+                evas_object_hide(st->o);   /* Hide animated icons */
+             anim_st_free(anim_st);
+             return ECORE_CALLBACK_CANCEL;
+          }
+
+        EINA_LIST_FOREACH(anim_st->icons, l, st)
+          {
+             int x, y, w, h;
+             Evas_Coord xm, ym;
+             evas_object_geometry_get(st->o, NULL, NULL, &w, &h);
+             evas_pointer_canvas_xy_get(anim_st->e, &xm, &ym);
+             x = st->start_x + (pos * (xm - (st->start_x + (w/2))));
+             y = st->start_y + (pos * (ym - (st->start_y + (h/2))));
+             evas_object_move(st->o, x, y);
+          }
+
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_gl_anim_start(void *data)
+{  /* Start icons animation before actually drag-starts */
+   drag_anim_st *anim_st = data;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   int yposret = 0;
+
+   Eina_List *l;
+   Eina_List *items = eina_list_clone(elm_genlist_selected_items_get(anim_st->gl));
+   Elm_Object_Item *gli = elm_genlist_at_xy_item_get(anim_st->gl,
+         anim_st->mdx, anim_st->mdy, &yposret);
+   if (gli)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(items, _item_ptr_cmp, gli);
+        if (!p)
+          items = eina_list_append(items, gli);
+     }
+
+   EINA_LIST_FOREACH(items, l, gli)
+     {  /* Now add icons to animation window */
+        Evas_Object *o = elm_object_item_part_content_get(gli,
+              "elm.swallow.icon");
+
+        if (o)
+          {
+             int w, h;
+             const char *f;
+             const char *g;
+             anim_icon_st *st = calloc(1, sizeof(*st));
+             elm_image_file_get(o, &f, &g);
+             Evas_Object *ic = elm_icon_add(anim_st->gl);
+             elm_image_file_set(ic, f, g);
+             evas_object_geometry_get(o, &st->start_x, &st->start_y, &w, &h);
+             evas_object_size_hint_align_set(ic,
+                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+             evas_object_size_hint_weight_set(ic,
+                   EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+             evas_object_move(ic, st->start_x, st->start_y);
+             evas_object_resize(ic, w, h);
+             evas_object_show(ic);
+
+             st->o = ic;
+             anim_st->icons = eina_list_append(anim_st->icons, st);
+          }
+     }
+
+   eina_list_free(items);
+
+   anim_st->tm = NULL;
+   anim_st->ea = ecore_animator_timeline_add(DRAG_TIMEOUT,
+         _drag_anim_play, anim_st);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_gl_obj_mouse_up(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info __UNUSED__)
+{  /* Cancel any drag waiting to start on timeout */
+   drag_anim_st *anim_st = data;
+   anim_st_free(anim_st);
+}
+
+static void
+_gl_obj_mouse_move(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Cancel any drag waiting to start on timeout */
+
+   if (((Evas_Event_Mouse_Move *)event_info)->event_flags | EVAS_EVENT_FLAG_ON_HOLD)
+     {
+        drag_anim_st *anim_st = data;
+        anim_st_free(anim_st);
+     }
+}
+
+static void
+_gl_obj_mouse_down(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Launch a timer to start drag animation */
+   Evas_Event_Mouse_Down *ev = event_info;
+   drag_anim_st *anim_st = calloc(1, sizeof(*anim_st));
+   anim_st->e = e;
+   anim_st->mdx = ev->canvas.x;
+   anim_st->mdy = ev->canvas.y;
+   anim_st->gl = data;
+   anim_st->tm = ecore_timer_add(DRAG_TIMEOUT, _gl_anim_start, anim_st);
+   evas_object_event_callback_add(data, EVAS_CALLBACK_MOUSE_UP,
+         _gl_obj_mouse_up, anim_st);
+   evas_object_event_callback_add(data, EVAS_CALLBACK_MOUSE_MOVE,
+         _gl_obj_mouse_move, anim_st);
+}
+/* END   - Handling drag start animation */
+
+static void
+_gl_dragdone(void *data, Evas_Object *obj __UNUSED__, Eina_Bool doaccept)
+{
+   printf("<%s> <%d> data=<%p> doaccept=<%d>\n",
+         __func__, __LINE__, data, doaccept);
+
+   Elm_Object_Item *it;
+   Eina_List *l;
+
+   if (doaccept)
+     {  /* Remove items dragged out (accepted by target) */
+        EINA_LIST_FOREACH(data, l, it)
+           elm_object_item_del(it);
+     }
+
+   eina_list_free(data);
+   return;
+}
+
+static Evas_Object *
+_gl_createicon(void *data, Evas_Object *win, Evas_Coord *xoff, Evas_Coord *yoff)
+{
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   Evas_Object *icon = NULL;
+   Evas_Object *o = elm_object_item_part_content_get(data, "elm.swallow.icon");
+
+   if (o)
+     {
+        int xm, ym, w = 30, h = 30;
+        const char *f;
+        const char *g;
+        elm_image_file_get(o, &f, &g);
+        evas_pointer_canvas_xy_get(evas_object_evas_get(o), &xm, &ym);
+        if (xoff) *xoff = xm - (w/2);
+        if (yoff) *yoff = ym - (h/2);
+        icon = elm_icon_add(win);
+        elm_image_file_set(icon, f, g);
+        evas_object_size_hint_align_set(icon,
+              EVAS_HINT_FILL, EVAS_HINT_FILL);
+        evas_object_size_hint_weight_set(icon,
+              EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        if (xoff && yoff) evas_object_move(icon, *xoff, *yoff);
+        evas_object_resize(icon, w, h);
+     }
+
+   return icon;
+}
+
+static Eina_List *
+_gl_icons_get(void *data)
+{  /* Start icons animation before actually drag-starts */
+   printf("<%s> <%d>\n", __func__, __LINE__);
+   int yposret = 0;
+
+   Eina_List *l;
+
+   Eina_List *icons = NULL;
+
+   Evas_Coord xm, ym;
+   evas_pointer_canvas_xy_get(evas_object_evas_get(data), &xm, &ym);
+   Eina_List *items = eina_list_clone(elm_genlist_selected_items_get(data));
+   Elm_Object_Item *gli = elm_genlist_at_xy_item_get(data,
+         xm, ym, &yposret);
+   if (gli)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(items, _item_ptr_cmp, gli);
+        if (!p)
+          items = eina_list_append(items, gli);
+     }
+
+   EINA_LIST_FOREACH(items, l, gli)
+     {  /* Now add icons to animation window */
+        Evas_Object *o = elm_object_item_part_content_get(gli,
+              "elm.swallow.icon");
+
+        if (o)
+          {
+             int x, y, w, h;
+             const char *f, *g;
+             elm_image_file_get(o, &f, &g);
+             Evas_Object *ic = elm_icon_add(data);
+             elm_image_file_set(ic, f, g);
+             evas_object_geometry_get(o, &x, &y, &w, &h);
+             evas_object_size_hint_align_set(ic,
+                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+             evas_object_size_hint_weight_set(ic,
+                   EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+             evas_object_move(ic, x, y);
+             evas_object_resize(ic, w, h);
+             evas_object_show(ic);
+
+             icons =  eina_list_append(icons, ic);
+          }
+     }
+
+   eina_list_free(items);
+   return icons;
+}
+
+static const char *
+_gl_get_drag_data(Evas_Object *obj, Elm_Object_Item *it, Eina_List **items)
+{  /* Construct a string of dragged info, user frees returned string */
+   const char *drag_data = NULL;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+
+   *items = eina_list_clone(elm_genlist_selected_items_get(obj));
+   if (it)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(*items, _item_ptr_cmp, it);
+        if (!p)
+          *items = eina_list_append(*items, it);
+     }
+
+   if (*items)
+     {  /* Now we can actually compose string to send and start dragging */
+        Eina_List *l;
+        const char *t;
+        unsigned int len = 0;
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               len += strlen(t);
+          }
+
+        drag_data = malloc(len + eina_list_count(*items) * 2 + 8);
+        strcpy((char *) drag_data, "file://");
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               {
+                  strcat((char *) drag_data, "#");
+                  strcat((char *) drag_data, t);
+               }
+          }
+        strcat((char *) drag_data, "#");
+
+        printf("<%s> <%d> Sending <%s>\n", __func__, __LINE__, drag_data);
+     }
+
+   return drag_data;
+}
+
+static const char *
+_grid_get_drag_data(Evas_Object *obj, Elm_Object_Item *it, Eina_List **items)
+{  /* Construct a string of dragged info, user frees returned string */
+   const char *drag_data = NULL;
+   printf("<%s> <%d>\n", __func__, __LINE__);
+
+   *items = eina_list_clone(elm_gengrid_selected_items_get(obj));
+   if (it)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(*items, _item_ptr_cmp, it);
+        if (!p)
+          *items = eina_list_append(*items, it);
+     }
+
+   if (*items)
+     {  /* Now we can actually compose string to send and start dragging */
+        Eina_List *l;
+        const char *t;
+        unsigned int len = 0;
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               len += strlen(t);
+          }
+
+        drag_data = malloc(len + eina_list_count(*items) * 2 + 8);
+        strcpy((char *) drag_data, "file://");
+
+        EINA_LIST_FOREACH(*items, l, it)
+          {
+             t = elm_object_item_part_text_get(it, "elm.text");
+             if (t)
+               {
+                  strcat((char *) drag_data, "#");
+                  strcat((char *) drag_data, t);
+               }
+          }
+        strcat((char *) drag_data, "#");
+
+        printf("<%s> <%d> Sending <%s>\n", __func__, __LINE__, drag_data);
+     }
+
+   return drag_data;
+}
+
+static Eina_Bool
+_gl_dnd_default_anim_data_getcb(Evas_Object *obj,  /* The genlist object */
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info)
+{  /* This called before starting to drag, mouse-down was on it */
+   info->format = ELM_SEL_FORMAT_TARGETS;
+   info->createicon = _gl_createicon;
+   info->createdata = it;
+   info->icons = _gl_icons_get(obj);
+   info->dragdone = _gl_dragdone;
+
+   /* Now, collect data to send for drop from ALL selected items */
+   /* Save list pointer to remove items after drop and free list on done */
+   info->data = _gl_get_drag_data(obj, it, (Eina_List **) &info->donecbdata);
+   printf("%s - data = %s\n", __FUNCTION__, info->data);
+   info->acceptdata = info->donecbdata;
+
+   if (info->data)
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static Eina_Bool
+_gl_data_getcb(Evas_Object *obj,  /* The genlist object */
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info)
+{  /* This called before starting to drag, mouse-down was on it */
+   info->format = ELM_SEL_FORMAT_TARGETS;
+   info->createicon = _gl_createicon;
+   info->createdata = it;
+   info->dragdone = _gl_dragdone;
+
+   /* Now, collect data to send for drop from ALL selected items */
+   /* Save list pointer to remove items after drop and free list on done */
+   info->data = _gl_get_drag_data(obj, it, (Eina_List **) &info->donecbdata);
+   info->acceptdata = info->donecbdata;
+
+   if (info->data)
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+static Eina_List *
+_grid_icons_get(void *data)
+{  /* Start icons animation before actually drag-starts */
+   printf("<%s> <%d>\n", __func__, __LINE__);
+
+   Eina_List *l;
+
+   Eina_List *icons = NULL;
+
+   Evas_Coord xm, ym;
+   evas_pointer_canvas_xy_get(evas_object_evas_get(data), &xm, &ym);
+   Eina_List *items = eina_list_clone(elm_gengrid_selected_items_get(data));
+   Elm_Object_Item *gli = elm_gengrid_at_xy_item_get(data,
+         xm, ym, NULL, NULL);
+   if (gli)
+     {  /* Add the item mouse is over to the list if NOT seleced */
+        void *p = eina_list_search_unsorted(items, _item_ptr_cmp, gli);
+        if (!p)
+          items = eina_list_append(items, gli);
+     }
+
+   EINA_LIST_FOREACH(items, l, gli)
+     {  /* Now add icons to animation window */
+        Evas_Object *o = elm_object_item_part_content_get(gli,
+              "elm.swallow.icon");
+
+        if (o)
+          {
+             int x, y, w, h;
+             const char *f, *g;
+             elm_image_file_get(o, &f, &g);
+             Evas_Object *ic = elm_icon_add(data);
+             elm_image_file_set(ic, f, g);
+             evas_object_geometry_get(o, &x, &y, &w, &h);
+             evas_object_size_hint_align_set(ic,
+                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+             evas_object_size_hint_weight_set(ic,
+                   EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+             evas_object_move(ic, x, y);
+             evas_object_resize(ic, w, h);
+             evas_object_show(ic);
+
+             icons =  eina_list_append(icons, ic);
+          }
+     }
+
+   eina_list_free(items);
+   return icons;
+}
+
+static Eina_Bool
+_grid_data_getcb(Evas_Object *obj,  /* The genlist object */
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info)
+{  /* This called before starting to drag, mouse-down was on it */
+   info->format = ELM_SEL_FORMAT_TARGETS;
+   info->createicon = _gl_createicon;
+   info->createdata = it;
+   info->icons = _grid_icons_get(obj);
+   info->dragdone = _gl_dragdone;
+
+   /* Now, collect data to send for drop from ALL selected items */
+   /* Save list pointer to remove items after drop and free list on done */
+   info->data = _grid_get_drag_data(obj, it, (Eina_List **) &info->donecbdata);
+   printf("%s - data = %s\n", __FUNCTION__, info->data);
+   info->acceptdata = info->donecbdata;
+
+   if (info->data)
+     return EINA_TRUE;
+   else
+     return EINA_FALSE;
+}
+
+void
+test_dnd_genlist_default_anim(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   char buf[PATH_MAX];
+   Evas_Object *win, *gl, *bxx;
+   int i, j;
+
+   win = elm_win_util_standard_add("dnd-genlist-default-anim", "DnD-Genlist-Default-Anim");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bxx = elm_box_add(win);
+   elm_box_horizontal_set(bxx, EINA_TRUE);
+   evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bxx);
+   evas_object_show(bxx);
+
+   itc1 = elm_genlist_item_class_new();
+   itc1->item_style     = "default";
+   itc1->func.text_get = gl_text_get;
+   itc1->func.content_get  = gl_content_get;
+   itc1->func.del       = NULL;
+
+   for (j = 0; j < 2; j++)
+     {
+        gl = elm_genlist_add(win);
+
+        /* START Drag and Drop handling */
+        evas_object_smart_callback_add(win, "delete,request", _win_del, gl);
+        elm_genlist_multi_select_set(gl, EINA_TRUE); /* We allow multi drag */
+        elm_drop_item_container_add(gl,
+              ELM_SEL_FORMAT_TARGETS,
+              _gl_item_getcb,
+              NULL, NULL,
+              NULL, NULL,
+              NULL, NULL,
+              _gl_dropcb, NULL);
+
+        elm_drag_item_container_add(gl, ANIM_TIME, DRAG_TIMEOUT,
+              _gl_item_getcb, _gl_dnd_default_anim_data_getcb);
+
+        // FIXME: This causes genlist to resize the horiz axis very slowly :(
+        // Reenable this and resize the window horizontally, then try to resize it back
+        //elm_genlist_mode_set(gl, ELM_LIST_LIMIT);
+        evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        elm_box_pack_end(bxx, gl);
+        evas_object_show(gl);
+
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_genlist_item_append(gl, itc1, path, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+          }
+     }
+
+   evas_object_resize(win, 680, 800);
+   evas_object_show(win);
+}
+
+void
+test_dnd_genlist_user_anim(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   char buf[PATH_MAX];
+   Evas_Object *win, *gl, *bxx;
+   int i, j;
+
+   win = elm_win_util_standard_add("dnd-genlist-user-anim", "DnD-Genlist-User-Anim");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bxx = elm_box_add(win);
+   elm_box_horizontal_set(bxx, EINA_TRUE);
+   evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bxx);
+   evas_object_show(bxx);
+
+   itc1 = elm_genlist_item_class_new();
+   itc1->item_style     = "default";
+   itc1->func.text_get = gl_text_get;
+   itc1->func.content_get  = gl_content_get;
+   itc1->func.del       = NULL;
+
+   for (j = 0; j < 2; j++)
+     {
+        gl = elm_genlist_add(win);
+
+        /* START Drag and Drop handling */
+        evas_object_smart_callback_add(win, "delete,request", _win_del, gl);
+        elm_genlist_multi_select_set(gl, EINA_TRUE); /* We allow multi drag */
+        elm_drop_item_container_add(gl,
+              ELM_SEL_FORMAT_TARGETS,
+              _gl_item_getcb,
+              NULL, NULL,
+              NULL, NULL,
+              NULL, NULL,
+              _gl_dropcb, NULL);
+
+        elm_drag_item_container_add(gl, ANIM_TIME, DRAG_TIMEOUT,
+              _gl_item_getcb, _gl_data_getcb);
+
+        /* We add mouse-down, up callbacks to start/stop drag animation */
+        evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_DOWN,
+              _gl_obj_mouse_down, gl);
+        /* END Drag and Drop handling */
+
+        // FIXME: This causes genlist to resize the horiz axis very slowly :(
+        // Reenable this and resize the window horizontally, then try to resize it back
+        //elm_genlist_mode_set(gl, ELM_LIST_LIMIT);
+        evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        elm_box_pack_end(bxx, gl);
+        evas_object_show(gl);
+
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_genlist_item_append(gl, itc1, path, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+          }
+     }
+
+   evas_object_resize(win, 680, 800);
+   evas_object_show(win);
+}
+
+void
+test_dnd_genlist_gengrid(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   char buf[PATH_MAX];
+   Evas_Object *win, *bxx;
+   int i;
+
+   win = elm_win_util_standard_add("dnd-genlist-gengrid", "DnD-Genlist-Gengrid");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bxx = elm_box_add(win);
+   elm_box_horizontal_set(bxx, EINA_TRUE);
+   evas_object_size_hint_weight_set(bxx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bxx);
+   evas_object_show(bxx);
+
+     {
+        itc1 = elm_genlist_item_class_new();
+        itc1->item_style     = "default";
+        itc1->func.text_get = gl_text_get;
+        itc1->func.content_get  = gl_content_get;
+        itc1->func.del       = NULL;
+
+        Evas_Object *gl = elm_genlist_add(win);
+        evas_object_smart_callback_add(win, "delete,request", _win_del, gl);
+
+        /* START Drag and Drop handling */
+        elm_genlist_multi_select_set(gl, EINA_TRUE); /* We allow multi drag */
+        elm_drop_item_container_add(gl, ELM_SEL_FORMAT_TARGETS, _gl_item_getcb, NULL, NULL,
+              NULL, NULL, NULL, NULL, _gl_dropcb, NULL);
+
+        elm_drag_item_container_add(gl, ANIM_TIME, DRAG_TIMEOUT,
+              _gl_item_getcb, _gl_dnd_default_anim_data_getcb);
+        /* END Drag and Drop handling */
+
+        // FIXME: This causes genlist to resize the horiz axis very slowly :(
+        // Reenable this and resize the window horizontally, then try to resize it back
+        //elm_genlist_mode_set(gl, ELM_LIST_LIMIT);
+        evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        elm_box_pack_end(bxx, gl);
+        evas_object_show(gl);
+
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_genlist_item_append(gl, itc1, path, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+          }
+     }
+
+     {
+        Evas_Object *grid = elm_gengrid_add(win);
+        evas_object_smart_callback_add(win, "delete,request", _win_del, grid);
+        elm_gengrid_item_size_set(grid,
+              elm_config_scale_get() * 150,
+              elm_config_scale_get() * 150);
+        elm_gengrid_horizontal_set(grid, EINA_FALSE);
+        elm_gengrid_reorder_mode_set(grid, EINA_FALSE);
+        elm_gengrid_multi_select_set(grid, EINA_TRUE); /* We allow multi drag */
+        evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+        evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+        gic = elm_gengrid_item_class_new();
+        gic->item_style = "default";
+        gic->func.text_get = gl_text_get;
+        gic->func.content_get = gl_content_get;
+
+        elm_drop_item_container_add(grid, ELM_SEL_FORMAT_TARGETS, _grid_item_getcb, NULL, NULL,
+              NULL, NULL, NULL, NULL, _grid_dropcb, NULL);
+
+        elm_drag_item_container_add(grid, ANIM_TIME, DRAG_TIMEOUT,
+              _grid_item_getcb, _grid_data_getcb);
+        for (i = 0; i < 20; i++)
+          {
+             snprintf(buf, sizeof(buf), "%s/images/%s", elm_app_data_dir_get(), img[(i % 9)]);
+             const char *path = eina_stringshare_add(buf);
+             elm_gengrid_item_append(grid, gic, path, NULL, NULL);
+          }
+        elm_box_pack_end(bxx, grid);
+        evas_object_show(grid);
+     }
+
+   evas_object_resize(win, 1280, 800);
+   evas_object_show(win);
+}
+
index ec64d84..ab093eb 100644 (file)
@@ -216,9 +216,9 @@ _move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *even
    Elm_Object_Item *gli;
    gli = elm_genlist_at_xy_item_get(gl, ev->cur.canvas.x, ev->cur.canvas.y, &where);
    if (gli)
-     INF("over %p, where %i", elm_object_item_data_get(gli), where);
+     INF("<%s> over %p, where %i\n", __func__, elm_object_item_data_get(gli), where);
    else
-     INF("over none, where %i", where);
+     INF("<%s> over none, where %i\n", __func__,where);
 }
 
 static void
index 362cbc6..93454ad 100644 (file)
@@ -42,6 +42,7 @@ typedef struct _Tmp_Info      Tmp_Info;
 typedef struct _Saved_Type    Saved_Type;
 typedef struct _Cnp_Escape    Cnp_Escape;
 typedef struct _Dropable      Dropable;
+static Eina_Bool doaccept = EINA_FALSE;
 
 struct _Tmp_Info
 {
@@ -85,6 +86,48 @@ struct _Dropable
    } last;
 };
 
+struct _Item_Container_Drop_Info
+{  /* Info kept for containers to support drop */
+   Evas_Object *obj;
+   Elm_Xy_Item_Get_Cb itemgetcb;
+   Elm_Drop_Item_Container_Cb dropcb;
+   Elm_Drag_Item_Container_Pos poscb;
+};
+typedef struct _Item_Container_Drop_Info Item_Container_Drop_Info;
+
+struct _Anim_Icon
+{
+   int start_x;
+   int start_y;
+   int start_w;
+   int start_h;
+   Evas_Object *o;
+};
+typedef struct _Anim_Icon Anim_Icon;
+
+struct _Item_Container_Drag_Info
+{  /* Info kept for containers to support drag */
+   Evas_Object *obj;
+   Ecore_Timer *tm;    /* When this expires, start drag */
+   double anim_tm;  /* Time period to set tm         */
+   double tm_to_drag;  /* Time period to set tm         */
+   Elm_Xy_Item_Get_Cb itemgetcb;
+   Elm_Item_Container_Data_Get_Cb data_get;
+
+   Evas_Coord x_down;  /* Mouse down x cord when drag starts */
+   Evas_Coord y_down;  /* Mouse down y cord when drag starts */
+
+   /* Some extra information needed to impl default anim */
+   Evas *e;
+   Eina_List *icons;   /* List of icons to animate (Anim_Icon) */
+   int final_icon_w; /* We need the w and h of the final icon for the animation */
+   int final_icon_h;
+   Ecore_Animator *ea;
+
+   Elm_Drag_User_Info user_info;
+};
+typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info;
+
 static int _elm_cnp_init_count = 0;
 /* Stringshared, so I can just compare pointers later */
 static const char *text_uri;
@@ -101,10 +144,18 @@ static void *dragdonedata = NULL;
 static Evas_Object *dragwidget = NULL;
 static Elm_Xdnd_Action dragaction = ELM_XDND_ACTION_UNKNOWN;
 
+static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */
+static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */
+
+static void _cont_obj_mouse_up( void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _cont_obj_mouse_move( void *data, Evas *e, Evas_Object *obj, void *event_info);
+
 /* Drag & Drop functions */
 /* FIXME: Way too many globals */
 static Eina_List *drops = NULL;
 static Evas_Object *dragwin = NULL;
+static int dragwin_x_start, dragwin_y_start;
+static int dragwin_x_end, dragwin_y_end;
 static int _dragx = 0, _dragy = 0;
 static Ecore_Event_Handler *handler_pos = NULL;
 static Ecore_Event_Handler *handler_drop = NULL;
@@ -1036,8 +1087,16 @@ _x11_general_converter(char *target __UNUSED__, void *data, int size, void **dat
    else
      {
         X11_Cnp_Selection *sel = _x11_selections + *((int *)data);
-        if (data_ret) *data_ret = strdup(sel->selbuf);
-        if (size_ret) *size_ret = strlen(sel->selbuf);
+        if (sel->selbuf)
+          {
+             if (data_ret) *data_ret = strdup(sel->selbuf);
+             if (size_ret) *size_ret = strlen(sel->selbuf);
+          }
+        else
+          {
+             if (data_ret) *data_ret = NULL;
+             if (size_ret) *size_ret = 0;
+          }
      }
    return EINA_TRUE;
 }
@@ -1431,15 +1490,15 @@ static Eina_Bool
 _x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
 {
    Ecore_X_Event_Xdnd_Status *status = ev;
-   Eina_Bool doaccept = EINA_FALSE;
-   
+   doaccept = EINA_FALSE;
+
    /* Only thing we care about: will accept */
    if ((status) && (status->will_accept))
      {
         cnp_debug("Will accept\n");
         doaccept = EINA_TRUE;
      }
-   /* Won't accept */   
+   /* Won't accept */
    else
      {
         cnp_debug("Won't accept accept\n");
@@ -1451,6 +1510,25 @@ _x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
 }
 
 static Eina_Bool
+_drag_cancel_animate(void *data __UNUSED__, double pos)
+{  /* Animation to "move back" drag-window */
+   if (pos >= 0.99)
+     {
+        evas_object_del(data);
+        return ECORE_CALLBACK_CANCEL;
+     }
+   else
+     {
+        int x, y;
+        x = dragwin_x_end - (pos * (dragwin_x_end - dragwin_x_start));
+        y = dragwin_y_end - (pos * (dragwin_y_end - dragwin_y_start));
+        evas_object_move(data, x, y);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
 _x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
 {
    Ecore_X_Window xwin = (Ecore_X_Window)(long)data;
@@ -1462,9 +1540,9 @@ _x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
         Eina_Bool have_drops = EINA_FALSE;
         Eina_List *l;
         Dropable *dropable;
-        
+
         ecore_x_pointer_ungrab();
-        if (handler_up) 
+        if (handler_up)
           {
              ecore_event_handler_del(handler_up);
              handler_up = NULL;
@@ -1475,9 +1553,9 @@ _x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
              handler_status = NULL;
           }
         ecore_x_dnd_self_drop();
-        
+
         cnp_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
-        
+
         EINA_LIST_FOREACH(drops, l, dropable)
           {
              if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
@@ -1488,15 +1566,34 @@ _x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
           }
         if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
         if (dragdonecb) dragdonecb(dragdonedata, dragwidget);
+        if (dragwin)
+          {
+             if (!doaccept)
+               {  /* Commit animation when drag cancelled */
+                  /* Record final position of dragwin, then do animation */
+                  ecore_animator_timeline_add(0.3,
+                        _drag_cancel_animate, dragwin);
+               }
+             else
+               {  /* No animation drop was committed */
+                  evas_object_del(dragwin);
+               }
+
+             dragwin = NULL;  /* if not freed here, free in end of anim */
+          }
+
         dragdonecb = NULL;
         dragacceptcb = NULL;
         dragposcb = NULL;
         dragwidget = NULL;
+        doaccept = EINA_FALSE;
+        /*  moved to _drag_cancel_animate
         if (dragwin)
           {
              evas_object_del(dragwin);
              dragwin = NULL;
           }
+          */
      }
    return EINA_TRUE;
 }
@@ -1504,10 +1601,12 @@ _x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
 static void
 _x11_drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
 {
-   evas_object_move(dragwin, 
+   evas_object_move(dragwin,
                     pos->position.x - _dragx, pos->position.y - _dragy);
-   printf("dragevas: %p -> %p\n",
-          dragwidget, 
+   dragwin_x_end = pos->position.x - _dragx;
+   dragwin_y_end = pos->position.y - _dragy;
+   cnp_debug("dragevas: %p -> %p\n",
+          dragwidget,
           evas_object_evas_get(dragwidget));
    if (dragposcb)
      dragposcb(dragposdata, dragwidget, pos->position.x, pos->position.y,
@@ -1519,7 +1618,7 @@ _x11_elm_widget_xwin_get(const Evas_Object *obj)
 {
    Evas_Object *top;
    Ecore_X_Window xwin = 0;
-   
+
    top = elm_widget_top_get(obj);
    if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj));
    if (top) xwin = elm_win_xwindow_get(top);
@@ -1540,7 +1639,7 @@ _x11_elm_cnp_init(void)
 {
    int i;
    static int _init_count = 0;
-   
+
    if (_init_count > 0) return EINA_TRUE;
    _init_count++;
    for (i = 0; i < CNP_N_ATOMS; i++)
@@ -1853,7 +1952,7 @@ _x11_drag_target_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj
 }
 
 static  Eina_Bool
-_x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, 
+_x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
                     Elm_Xdnd_Action action,
                     Elm_Drag_Icon_Create_Cb createicon, void *createdata,
                     Elm_Drag_Pos dragpos, void *dragdata,
@@ -1870,7 +1969,7 @@ _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
    Ecore_X_Atom actx;
 
    _x11_elm_cnp_init();
-   
+
    cnp_debug("starting drag... %p\n", obj);
 
    if (dragwin)
@@ -1917,28 +2016,21 @@ _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
    if (createicon)
      {
         Evas_Coord xoff = 0, yoff = 0;
-        
+
         icon = createicon(createdata, dragwin, &xoff, &yoff);
         if (icon)
           {
-             evas_object_geometry_get(obj, &x2, &y2, NULL, NULL);
+             x2 = xoff;
+             y2 = yoff;
              evas_object_geometry_get(icon, NULL, NULL, &w, &h);
-             x2 += xoff;
-             y2 += yoff;
           }
      }
-   if (!icon)
+   else
      {
-        evas_object_geometry_get(obj, &x2, &y2, &w, &h);
-   
-        /* FIXME: Images only */
         icon = elm_icon_add(dragwin);
-        if (!strncmp(data, "file://", 7))
-          elm_image_file_set(icon, data + 7, NULL); /* 7!? "file://" */
-        else
-          elm_image_file_set(icon, data, NULL);
         evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
         evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        // need to resize
      }
    elm_win_resize_object_add(dragwin, icon);
 
@@ -1947,8 +2039,9 @@ _x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
    ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
    x += x2;
    y += y2;
+   dragwin_x_start = dragwin_x_end = x;
+   dragwin_y_start = dragwin_y_end = y;
    evas_object_move(dragwin, x, y);
-   evas_object_resize(icon, w, h);
    evas_object_resize(dragwin, w, h);
 
    evas_object_show(icon);
@@ -2604,4 +2697,470 @@ elm_selection_selection_has_owner(Evas_Object *obj)
    return _local_elm_selection_selection_has_owner(obj);
 }
 
-/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/
+/* START - Support elm containers for Drag and Drop */
+/* START - Support elm containers for Drop */
+static int
+_drop_item_container_cmp(const void *d1,
+               const void *d2)
+{
+   const Item_Container_Drop_Info *st = d1;
+   return (((uintptr_t) (st->obj)) - ((uintptr_t) d2));
+}
+
+static void
+_elm_item_container_pos_cb(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action)
+{  /* obj is the container pointer */
+   Elm_Object_Item *it = NULL;
+   int xposret = 0;
+   int yposret = 0;
+   Item_Container_Drop_Info *st =
+      eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+
+   if (st && st->poscb)
+     {  /* Call container drop func with specific item pointer */
+        int xo = 0;
+        int yo = 0;
+        eo_do(obj, evas_obj_position_get(&xo, &yo));
+        if (st->itemgetcb)
+          it = st->itemgetcb(obj, x+xo, y+yo, &xposret, &yposret);
+
+        st->poscb(data, obj, it, x, y, xposret, yposret, action);
+     }
+}
+
+static Eina_Bool
+_elm_item_container_drop_cb(void *data, Evas_Object *obj , Elm_Selection_Data *ev)
+{  /* obj is the container pointer */
+   Elm_Object_Item *it = NULL;
+   int xposret = 0;
+   int yposret = 0;
+   Item_Container_Drop_Info *st =
+      eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+
+   if (st && st->dropcb)
+     {  /* Call container drop func with specific item pointer */
+        int xo = 0;
+        int yo = 0;
+        eo_do(obj, evas_obj_position_get(&xo, &yo));
+        if (st->itemgetcb)
+          it = st->itemgetcb(obj, ev->x+xo, ev->y+yo, &xposret, &yposret);
+
+        return st->dropcb(data, obj, it, ev, xposret, yposret);
+     }
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+elm_drop_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
+{
+   Item_Container_Drop_Info *st =
+      eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+
+   if (st)
+     {
+        elm_drop_target_del(obj);
+        st->itemgetcb= NULL;
+        st->poscb = NULL;
+        st->dropcb = NULL;
+
+        if (full)
+          {
+             cont_drop_tg = eina_list_remove(cont_drop_tg, st);
+             free(st);
+          }
+
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+elm_drop_item_container_del(Evas_Object *obj)
+{
+   return elm_drop_item_container_del_internal(obj, EINA_TRUE);
+}
+
+EAPI Eina_Bool
+elm_drop_item_container_add(Evas_Object *obj,
+      Elm_Sel_Format format,
+      Elm_Xy_Item_Get_Cb itemgetcb,
+      Elm_Drag_State entercb, void *enterdata,
+      Elm_Drag_State leavecb, void *leavedata,
+      Elm_Drag_Item_Container_Pos poscb, void *posdata,
+      Elm_Drop_Item_Container_Cb dropcb, void *cbdata)
+{
+   Item_Container_Drop_Info *st;
+
+   if (elm_drop_item_container_del_internal(obj, EINA_FALSE))
+     {  /* Updating info of existing obj */
+        st = eina_list_search_unsorted(cont_drop_tg, _drop_item_container_cmp, obj);
+     }
+   else
+     {
+        st = calloc(1, sizeof(*st));
+        st->obj = obj;
+        cont_drop_tg = eina_list_append(cont_drop_tg, st);
+     }
+
+   st->itemgetcb = itemgetcb;
+   st->poscb = poscb;
+   st->dropcb = dropcb;
+   elm_drop_target_add(obj, format,
+                       entercb, enterdata,
+                       leavecb, leavedata,
+                       _elm_item_container_pos_cb, posdata,
+                       _elm_item_container_drop_cb, cbdata);
+
+   return EINA_TRUE;
+}
+/* END   - Support elm containers for Drop */
+
+
+/* START - Support elm containers for Drag */
+static int
+_drag_item_container_cmp(const void *d1,
+               const void *d2)
+{
+   const Item_Container_Drag_Info *st = d1;
+   return (((uintptr_t) (st->obj)) - ((uintptr_t) d2));
+}
+
+static void
+_cont_drag_done_cb(void *data, Evas_Object *obj __UNUSED__)
+{
+   Item_Container_Drag_Info *st = data;
+   elm_widget_scroll_freeze_pop(st->obj);
+   if (st->user_info.dragdone) st->user_info.dragdone(st->user_info.donecbdata, dragwidget, doaccept);
+}
+
+static Eina_Bool
+_cont_obj_drag_start(void *data)
+{  /* Start a drag-action when timer expires */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+   st->tm = NULL;
+   Elm_Drag_User_Info *info = &st->user_info;
+   elm_widget_scroll_freeze_push(st->obj);
+   evas_object_event_callback_del_full
+      (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
+   elm_drag_start(  /* Commit the start only if data_get successful */
+         st->obj, info->format,
+         info->data, info->action,
+         info->createicon, info->createdata,
+         info->dragpos, info->dragdata,
+         info->acceptcb, info->acceptdata,
+         _cont_drag_done_cb, st);
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+void
+_anim_st_free(Item_Container_Drag_Info *st)
+{  /* Stops and free mem of ongoing animation */
+   if (st)
+     {
+        if (st->ea)
+          {
+             ecore_animator_del(st->ea);
+             st->ea = NULL;
+          }
+
+        Anim_Icon *sti;
+
+        EINA_LIST_FREE(st->icons, sti)
+          {
+             evas_object_del(sti->o);
+             free(sti);
+          }
+
+        st->icons = NULL;
+     }
+}
+
+static inline Eina_List *
+_anim_icons_make(Eina_List *icons)
+{  /* Make local copies of all icons, add them to list */
+   Eina_List *list = NULL, *itr;
+   Evas_Object *o;
+
+   EINA_LIST_FOREACH(icons, itr, o)
+     {  /* Now add icons to animation window */
+        Anim_Icon *st = calloc(1, sizeof(*st));
+        evas_object_geometry_get(o, &st->start_x, &st->start_y, &st->start_w, &st->start_h);
+        evas_object_show(o);
+        st->o = o;
+        list = eina_list_append(list, st);
+     }
+
+   return list;
+}
+
+static Eina_Bool
+_drag_anim_play(void *data, double pos)
+{  /* Impl of the animation of icons, called on frame time */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+   Eina_List *l;
+   Anim_Icon *sti;
+
+   if (st->ea)
+     {
+        if (pos > 0.99)
+          {
+             st->ea = NULL;  /* Avoid deleting on mouse up */
+             EINA_LIST_FOREACH(st->icons, l, sti)
+                evas_object_hide(sti->o);
+
+             _cont_obj_drag_start(st);  /* Start dragging */
+             return ECORE_CALLBACK_CANCEL;
+          }
+
+        Evas_Coord xm, ym;
+        evas_pointer_canvas_xy_get(st->e, &xm, &ym);
+        EINA_LIST_FOREACH(st->icons, l, sti)
+          {
+             int x, y, h, w;
+             w = sti->start_w + ((st->final_icon_w - sti->start_w) * pos);
+             h = sti->start_h + ((st->final_icon_h - sti->start_h) * pos);
+             x = sti->start_x - (pos * ((sti->start_x + (w/2) - xm)));
+             y = sti->start_y - (pos * ((sti->start_y + (h/2) - ym)));
+             evas_object_move(sti->o, x, y);
+             evas_object_resize(sti->o, w, h);
+          }
+
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static inline Eina_Bool
+_drag_anim_start(void *data)
+{  /* Start default animation */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+
+   st->tm = NULL;
+   /* Now we need to build an (Anim_Icon *) list */
+   st->icons = _anim_icons_make(st->user_info.icons);
+   if (st->user_info.createicon)
+     {
+        Evas_Object *temp_win = elm_win_add(NULL, "Temp", ELM_WIN_UTILITY);
+        Evas_Object *final_icon = st->user_info.createicon(st->user_info.createdata, temp_win, NULL, NULL);
+        evas_object_geometry_get(final_icon, NULL, NULL, &st->final_icon_w, &st->final_icon_h);
+        evas_object_del(final_icon);
+        evas_object_del(temp_win);
+     }
+   st->ea = ecore_animator_timeline_add(st->anim_tm, _drag_anim_play, st);
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_cont_obj_anim_start(void *data)
+{  /* Start a drag-action when timer expires */
+   cnp_debug("%s In\n", __FUNCTION__);
+   Item_Container_Drag_Info *st = data;
+   int xposret, yposret;  /* Unused */
+   Elm_Object_Item *it = (st->itemgetcb) ?
+      (st->itemgetcb(st->obj, st->x_down, st->y_down, &xposret, &yposret))
+      : NULL;
+
+   st->tm = NULL;
+   st->user_info.format = ELM_SEL_FORMAT_TARGETS; /* Default */
+   st->icons = NULL;
+   st->user_info.data = NULL;
+   st->user_info.action = ELM_XDND_ACTION_COPY;  /* Default */
+
+   if (!it)   /* Failed to get mouse-down item, abort drag */
+     return ECORE_CALLBACK_CANCEL;
+
+   if (st->data_get)
+     {  /* collect info then start animation or start dragging */
+        if(st->data_get(    /* Collect drag info */
+                 st->obj,      /* The container object */
+                 it,           /* Drag started on this item */
+                 &st->user_info))
+          {
+             if (st->user_info.icons)
+               _drag_anim_start(st);
+             else
+               {
+                  if (st->anim_tm)
+                    {
+                       // even if we don't manage the icons animation, we have
+                       // to wait until it is finished before beginning drag.
+                       st->tm = ecore_timer_add(st->anim_tm, _cont_obj_drag_start, st);
+                    }
+                  else
+                    _cont_obj_drag_start(st);  /* Start dragging, no anim */
+               }
+          }
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_cont_obj_mouse_down(
+   void *data,
+   Evas *e,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Launch a timer to start dragging */
+   Evas_Event_Mouse_Down *ev = event_info;
+   cnp_debug("%s In - event %X\n", __FUNCTION__, ev->event_flags);
+   if (ev->button != 1)
+     return;  /* We only process left-click at the moment */
+
+   Item_Container_Drag_Info *st = data;
+   evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_MOVE,
+         _cont_obj_mouse_move, st);
+
+   evas_object_event_callback_add(st->obj, EVAS_CALLBACK_MOUSE_UP,
+         _cont_obj_mouse_up, st);
+
+   if (st->tm)
+     ecore_timer_del(st->tm);
+
+   st->e = e;
+   st->x_down = ev->canvas.x;
+   st->y_down = ev->canvas.y;
+   st->tm = ecore_timer_add(st->tm_to_drag, _cont_obj_anim_start, st);
+}
+
+static Eina_Bool elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full);
+
+static void
+_cont_obj_mouse_move(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Cancel any drag waiting to start on timeout */
+
+   cnp_debug("%s In\n", __FUNCTION__);
+   if (((Evas_Event_Mouse_Move *)event_info)->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
+     {
+        cnp_debug("%s event on hold - have to cancel DnD\n", __FUNCTION__);
+        Item_Container_Drag_Info *st = data;
+        evas_object_event_callback_del_full
+           (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
+        evas_object_event_callback_del_full
+           (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st);
+        elm_drag_item_container_del_internal(obj, EINA_FALSE);
+
+        if (st->tm)
+          {
+             ecore_timer_del(st->tm);
+             st->tm = NULL;
+          }
+
+        _anim_st_free(st);
+     }
+   cnp_debug("%s Out\n", __FUNCTION__);
+}
+
+static void
+_cont_obj_mouse_up(
+   void *data,
+   Evas *e __UNUSED__,
+   Evas_Object *obj __UNUSED__,
+   void *event_info)
+{  /* Cancel any drag waiting to start on timeout */
+   Item_Container_Drag_Info *st = data;
+
+   cnp_debug("%s In\n", __FUNCTION__);
+   if (((Evas_Event_Mouse_Up *)event_info)->button != 1)
+     return;  /* We only process left-click at the moment */
+
+   evas_object_event_callback_del_full
+      (st->obj, EVAS_CALLBACK_MOUSE_MOVE, _cont_obj_mouse_move, st);
+   evas_object_event_callback_del_full
+      (st->obj, EVAS_CALLBACK_MOUSE_UP, _cont_obj_mouse_up, st);
+
+   if (st->tm)
+     {
+        ecore_timer_del(st->tm);
+        st->tm = NULL;
+     }
+
+   _anim_st_free(st);
+}
+
+static Eina_Bool
+elm_drag_item_container_del_internal(Evas_Object *obj, Eina_Bool full)
+{
+   Item_Container_Drag_Info *st =
+      eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj);
+
+   if (st)
+     {
+        if (st->tm)
+          ecore_timer_del(st->tm);  /* Cancel drag-start timer */
+
+        if (st->ea)  /* Cancel ongoing default animation */
+          _anim_st_free(st);
+
+        st->tm = NULL;
+
+        if (full)
+          {
+             st->itemgetcb = NULL;;
+             st->data_get = NULL;
+             evas_object_event_callback_del_full
+                (obj, EVAS_CALLBACK_MOUSE_DOWN, _cont_obj_mouse_down, st);
+
+             free(st);
+             cont_drag_tg = eina_list_remove(cont_drag_tg, st);
+          }
+
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+elm_drag_item_container_del(Evas_Object *obj)
+{
+   return elm_drag_item_container_del_internal(obj, EINA_TRUE);
+}
+
+EAPI Eina_Bool
+elm_drag_item_container_add(
+   Evas_Object *obj,
+   double anim_tm,
+   double tm_to_drag,
+   Elm_Xy_Item_Get_Cb itemgetcb,
+   Elm_Item_Container_Data_Get_Cb data_get)
+{
+   Item_Container_Drag_Info *st;
+
+   if (elm_drag_item_container_del_internal(obj, EINA_FALSE))
+     {  /* Updating info of existing obj */
+        st = eina_list_search_unsorted(cont_drag_tg, _drag_item_container_cmp, obj);
+     }
+   else
+     {
+        st = calloc(1, sizeof(*st));
+        st->obj = obj;
+        cont_drag_tg = eina_list_append(cont_drag_tg, st);
+
+        /* Register for mouse callback for container to start/abort drag */
+        evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
+                                       _cont_obj_mouse_down, st);
+     }
+
+   st->tm = NULL;
+   st->anim_tm = anim_tm;
+   st->tm_to_drag = tm_to_drag;
+   st->itemgetcb = itemgetcb;
+   st->data_get = data_get;
+
+   return EINA_TRUE;
+}
+/* END   - Support elm containers for Drag */
+/* END   - Support elm containers for Drag and Drop */
index 598735e..5b0b2df 100644 (file)
@@ -115,6 +115,18 @@ typedef struct _Elm_Selection_Data Elm_Selection_Data;
 typedef Eina_Bool (*Elm_Drop_Cb)(void *data, Evas_Object *obj, Elm_Selection_Data *ev);
 
 /**
+ * Callback invoked to find out what object is under (x,y) coords
+ *
+ * @param obj The container object
+ * @param x cord to check
+ * @param y cord to check
+ * @param xposret Position relative to item (left (-1), middle (0), right (1)
+ * @param yposret Position relative to item (upper (-1), middle (0), bottom (1)
+ * @return object under x,y cords or NULL if not found.
+ */
+typedef Elm_Object_Item *(*Elm_Xy_Item_Get_Cb)(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret, int *yposret);
+
+/**
  * Callback invoked in when the selection ownership for a given selection is lost.
  *
  * @param data Application specific data
@@ -125,7 +137,7 @@ typedef void (*Elm_Selection_Loss_Cb)(void *data, Elm_Sel_Type selection);
 
 /**
  * Callback called to create a drag icon object
- * 
+ *
  * @param data Application specific data
  * @param win The window to create the objects relative to
  * @param xoff A return coordinate for the X offset at which to place the drag icon object relative to the source drag object
@@ -145,8 +157,18 @@ typedef Evas_Object *(*Elm_Drag_Icon_Create_Cb) (void *data, Evas_Object *win, E
 typedef void (*Elm_Drag_State) (void *data, Evas_Object *obj);
 
 /**
+ * Callback called when a drag is finished.
+ *
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @param accepted TRUE if the droppped-data is accepted on drop
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Done) (void *data, Evas_Object *obj, Eina_Bool accepted);
+
+/**
  * Callback called when a drag is responded to with an accept or deny
- * 
+ *
  * @param data Application specific data
  * @param obj The object where the drag started
  * @param doaccept A boolean as to if the target accepts the drag or not
@@ -306,7 +328,7 @@ EAPI Eina_Bool elm_drop_target_del(Evas_Object *obj);
  * @param dragpos Function called with each position of the drag, x, y being screen coordinates if possible, and action being the current action.
  * @param dragdata Application data passed to @p dragpos
  * @param acceptcb Function called indicating if drop target accepts (or does not) the drop data while dragging
- * 
+ *
  * @param acceptdata Application data passed to @p acceptcb
  * @param dragdone Function to call when drag is done
  * @param donecbdata Application data to pass to @p dragdone
@@ -316,16 +338,17 @@ EAPI Eina_Bool elm_drop_target_del(Evas_Object *obj);
  *
  * @since 1.8
  */
-EAPI Eina_Bool elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, 
-                              const char *data, Elm_Xdnd_Action action, 
-                              Elm_Drag_Icon_Create_Cb createicon, void *createdata, 
+EAPI Eina_Bool elm_drag_start(Evas_Object *obj, Elm_Sel_Format format,
+                              const char *data, Elm_Xdnd_Action action,
+                              Elm_Drag_Icon_Create_Cb createicon,
+                              void *createdata,
                               Elm_Drag_Pos dragpos, void *dragdata,
                               Elm_Drag_Accept acceptcb, void *acceptdata,
                               Elm_Drag_State dragdone, void *donecbdata);
 /**
  * @brief Changes the current drag action
  *
- * @param obj The source of a drag if a drag is underway 
+ * @param obj The source of a drag if a drag is underway
  * @param action The drag action to be done
  * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
  *
@@ -336,5 +359,146 @@ EAPI Eina_Bool elm_drag_start(Evas_Object *obj, Elm_Sel_Format format,
 EAPI Eina_Bool elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action);
 
 /**
+ * Callback called when a drag is over an object
+ *
+ * @param data Application specific data
+ * @param cont The container object where the drag started
+ * @param it The object item in container where mouse-over
+ * @param x The X coordinate relative to the top-left of the object
+ * @param y The Y coordinate relative to the top-left of the object
+ * @param xposret Position relative to item (left (-1), middle (0), right (1)
+ * @param yposret Position relative to item (upper (-1), middle (0), bottom (1)
+ * @param action The drag action to be done
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Item_Container_Pos) (void *data, Evas_Object *cont, Elm_Object_Item *it, Evas_Coord x, Evas_Coord y, int xposret, int yposret, Elm_Xdnd_Action action);
+
+/**
+ * Callback invoked in when the selected data is 'dropped' on container.
+ *
+ * @param data Application specific data
+ * @param obj The evas object where selected data is 'dropped'.
+ * @param it The item in container where drop-cords
+ * @param ev struct holding information about selected data
+ * @param xposret Position relative to item (left (-1), middle (0), right (1)
+ * @param yposret Position relative to item (upper (-1), middle (0), bottom (1)
+ */
+typedef Eina_Bool (*Elm_Drop_Item_Container_Cb)(void *data, Evas_Object *obj, Elm_Object_Item *it, Elm_Selection_Data *ev, int xposret, int yposret);
+
+/**
+ * Structure describing user information for the drag process.
+ *
+ * @param format The drag formats supported by the data (output)
+ * @param data The drag data itself (a string) (output)
+ * @param icons if value not NULL, play default anim (output)
+ * @param action The drag action to be done (output)
+ * @param createicon Function to call to create a drag object, or NULL if not wanted (output)
+ * @param createdata Application data passed to @p createicon (output)
+ * @param dragpos Function called with each position of the drag, x, y being screen coordinates if possible, and action being the current action. (output)
+ * @param dragdata Application data passed to @p dragpos (output)
+ * @param acceptcb Function called indicating if drop target accepts (or does not) the drop data while dragging (output)
+ * @param acceptdata Application data passed to @p acceptcb (output)
+ * @param dragdone Function to call when drag is done (output)
+ * @param donecbdata Application data to pass to @p dragdone (output)
+ */
+typedef struct _Elm_Drag_User_Info Elm_Drag_User_Info;
+
+struct _Elm_Drag_User_Info
+{
+   Elm_Sel_Format format;
+   const char *data;
+   Eina_List *icons;
+   Elm_Xdnd_Action action;
+   Elm_Drag_Icon_Create_Cb createicon;
+   void *createdata;
+   Elm_Drag_Pos dragpos;
+   void *dragdata;
+   Elm_Drag_Accept acceptcb;
+   void *acceptdata;
+   Elm_Drag_Done dragdone;
+   void *donecbdata;
+};
+
+/**
+ * Callback invoked when starting to drag for a container.
+ *
+ * @param obj The container object
+ * @param it The Elm_Object_Item pointer where drag-start
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ */
+typedef Eina_Bool (*Elm_Item_Container_Data_Get_Cb)(
+      Evas_Object *obj,
+      Elm_Object_Item *it,
+      Elm_Drag_User_Info *info);
+
+/**
+ * @brief Set a item container (list, genlist, grid) as source of drag
+ *
+ * @param obj The container object.
+ * @param tm_to_anim Time period to wait before start animation.
+ * @param tm_to_drag Time period to wait before start draggind.
+ * @param itemgetcb Callback to get Evas_Object pointer for item at (x,y)
+ * @param data_get  Callback to get drag info
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drag_item_container_add(Evas_Object *obj, double tm_to_anim, double tm_to_drag, Elm_Xy_Item_Get_Cb itemgetcb, Elm_Item_Container_Data_Get_Cb data_get);
+
+/**
+ * @brief Deletes a item container from drag-source list
+ *
+ * @param obj The target object
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drag_item_container_del(Evas_Object *obj);
+
+/**
+ * @brief Set a item container (list, genlist, grid) as target for drop.
+ *
+ * @param obj The container object.
+ * @param format The formats supported for dropping
+ * @param itemgetcb Callback to get Evas_Object pointer for item at (x,y)
+ * @param entercb The function to call when the object is entered with a drag
+ * @param enterdata The application data to pass to enterdata
+ * @param leavecb The function to call when the object is left with a drag
+ * @param leavedata The application data to pass to leavedata
+ * @param poscb The function to call when the object has a drag over it
+ * @param posdata The application data to pass to posdata
+ * @param dropcb The function to call when a drop has occurred
+ * @param cbdata The application data to pass to dropcb
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drop_item_container_add(Evas_Object *obj,
+      Elm_Sel_Format format,
+      Elm_Xy_Item_Get_Cb itemgetcb,
+      Elm_Drag_State entercb, void *enterdata,
+      Elm_Drag_State leavecb, void *leavedata,
+      Elm_Drag_Item_Container_Pos poscb, void *posdata,
+      Elm_Drop_Item_Container_Cb dropcb, void *cbdata);
+
+/**
+ * @brief Removes a container from list of drop tragets.
+ *
+ * @param obj The container object
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+EAPI Eina_Bool elm_drop_item_container_del(Evas_Object *obj);
+
+/**
  * @}
  */
index e831ff5..972971f 100644 (file)
@@ -3604,6 +3604,118 @@ _first_item_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
    *ret = (Elm_Object_Item *)it;
 }
 
+
+EAPI Elm_Object_Item *
+elm_gengrid_at_xy_item_get(const Evas_Object *obj,
+                           Evas_Coord x,
+                           Evas_Coord y,
+                           int *xposret,
+                           int *yposret)
+{
+   ELM_GENGRID_CHECK(obj) NULL;
+   Elm_Object_Item *ret = NULL;
+   eo_do((Eo *) obj, elm_obj_gengrid_at_xy_item_get(x, y,
+            xposret, yposret, &ret));
+
+   return ret;
+}
+
+static void
+_at_xy_item_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+   Evas_Coord x = va_arg(*list, Evas_Coord);
+   Evas_Coord y = va_arg(*list, Evas_Coord);
+   int *xposret = va_arg(*list, int *);
+   int *yposret = va_arg(*list, int *);
+   Elm_Object_Item **ret = va_arg(*list, Elm_Object_Item **);
+
+   Elm_Gengrid_Smart_Data *sd = _pd;
+   Elm_Gen_Item *it = ELM_GEN_ITEM_FROM_INLIST(sd->items);
+
+   Evas_Coord l, r, t, b; /* left, right, top, bottom */
+   Eina_Bool init = EINA_TRUE;
+
+   while ((it) && (it->generation < sd->generation))
+     it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
+
+   if (it)
+     do
+       {
+          Evas_Coord itx, ity;
+          Evas_Coord itw, ith;
+          evas_object_geometry_get(VIEW(it), &itx, &ity, &itw, &ith);
+
+          /* Record leftmost, rightmost, top, bottom cords to set posret */
+          if ((itw > 0) && (ith > 0) && (itx >= 0) && (ity >= 0))
+            {  /* A scroller, ignore items in negative cords,or not rendered */
+               if (init)
+                 {
+                    l = itx;
+                    r = itx + itw;
+                    t = ity;
+                    b = ity + ith;
+                    init = EINA_FALSE;
+                 }
+               else
+                 {
+                    if (itx < l)
+                      l = itx;
+                    if ((itx + itw) > r)
+                      r = itx + itw;
+                    if (ity < t)
+                      t = ity;
+                    if ((ity + ith) > b)
+                      b = ity + ith;
+                 }
+            }
+
+          if (ELM_RECTS_INTERSECT
+                (itx, ity, itw, ith, x, y, 1, 1))
+            {
+               if (yposret)
+                 {
+                    if (y <= (ity + (ith / 4))) *yposret = -1;
+                    else if (y >= (ity + ith - (ith / 4)))
+                      *yposret = 1;
+                    else *yposret = 0;
+                 }
+
+               if (xposret)
+                 {
+                    if (x <= (itx + (itw / 4))) *xposret = -1;
+                    else if (x >= (itx + itw - (itw / 4)))
+                      *xposret = 1;
+                    else *xposret = 0;
+                 }
+
+               *ret = (Elm_Object_Item *) it;
+               return;
+            }
+
+       } while ((it = ELM_GEN_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next)));
+
+   /* No item found, tell the user if hit left/right/top/bottom of items */
+   if (xposret)
+     {
+        *xposret = 0;
+        if (x < l)
+          *xposret = (-1);
+        else if (x > r)
+          *xposret = (1);
+     }
+
+   if (yposret)
+     {
+        *yposret = 0;
+        if (y < t)
+          *yposret = (-1);
+        else if (y > b)
+          *yposret = (1);
+     }
+
+   *ret = NULL;
+}
+
 EAPI Elm_Object_Item *
 elm_gengrid_last_item_get(const Evas_Object *obj)
 {
@@ -4008,6 +4120,7 @@ _class_constructor(Eo_Class *klass)
         EO_OP_FUNC(ELM_OBJ_GENGRID_ID(ELM_OBJ_GENGRID_SUB_ID_SELECT_MODE_GET), _select_mode_get),
         EO_OP_FUNC(ELM_OBJ_GENGRID_ID(ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_SET), _highlight_mode_set),
         EO_OP_FUNC(ELM_OBJ_GENGRID_ID(ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_GET), _highlight_mode_get),
+        EO_OP_FUNC(ELM_OBJ_GENGRID_ID(ELM_OBJ_GENGRID_SUB_ID_AT_XY_ITEM_GET), _at_xy_item_get),
         EO_OP_FUNC_SENTINEL
    };
    eo_class_funcs_set(klass, func_desc);
@@ -4052,6 +4165,7 @@ static const Eo_Op_Description op_desc[] = {
      EO_OP_DESCRIPTION(ELM_OBJ_GENGRID_SUB_ID_SELECT_MODE_GET, "Get the gengrid select mode."),
      EO_OP_DESCRIPTION(ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_SET, "Set whether the gengrid items should be highlighted when item selected."),
      EO_OP_DESCRIPTION(ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_GET, "Get whether the gengrid items should be highlighted when item selected."),
+     EO_OP_DESCRIPTION(ELM_OBJ_GENGRID_SUB_ID_AT_XY_ITEM_GET, "Get the item that is at the x, y canvas coords."),
      EO_OP_DESCRIPTION_SENTINEL
 };
 
index 19c6ea6..94f0dc6 100644 (file)
@@ -49,6 +49,7 @@ enum
    ELM_OBJ_GENGRID_SUB_ID_SELECT_MODE_GET,
    ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_SET,
    ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_GET,
+   ELM_OBJ_GENGRID_SUB_ID_AT_XY_ITEM_GET,
    ELM_OBJ_GENGRID_SUB_ID_LAST
 };
 
@@ -603,6 +604,22 @@ enum
  */
 #define elm_obj_gengrid_highlight_mode_get(ret) ELM_OBJ_GENGRID_ID(ELM_OBJ_GENGRID_SUB_ID_HIGHLIGHT_MODE_GET), EO_TYPECHECK(Eina_Bool *, ret)
 
+/**
+ * @def elm_obj_gengrid_at_xy_item_get
+ * @since 1.8
+ *
+ * Get the item that is at the x, y canvas coords.
+ *
+ * @param[in] x
+ * @param[in] y
+ * @param[out] xposret
+ * @param[out] yposret
+ * @param[out] ret
+ *
+ * @see elm_gengrid_at_xy_item_get
+ */
+#define elm_obj_gengrid_at_xy_item_get(x, y, xposret, yposret, ret) ELM_OBJ_GENGRID_ID(ELM_OBJ_GENGRID_SUB_ID_AT_XY_ITEM_GET), EO_TYPECHECK(Evas_Coord, x), EO_TYPECHECK(Evas_Coord, y), EO_TYPECHECK(int *, xposret), EO_TYPECHECK(int *, yposret), EO_TYPECHECK(Elm_Object_Item **, ret)
+
 
 /**
  * @}
index a48e00e..a87a7ae 100644 (file)
@@ -866,3 +866,32 @@ EAPI Eina_Bool                     elm_gengrid_highlight_mode_get(const Evas_Obj
  * @since 1.8
  */
 EAPI Elm_Object_Item *elm_gengrid_nth_item_get(const Evas_Object *obj, unsigned int nth);
+
+/**
+ * Get the item that is at the x, y canvas coords.
+ *
+ * @param obj The gengrid object.
+ * @param x The input x coordinate
+ * @param y The input y coordinate
+ * @param xposret The position relative to the item returned here
+ * @param yposret The position relative to the item returned here
+ * @return The item at the coordinates or NULL if none
+ *
+ * This returns the item at the given coordinates (which are canvas
+ * relative, not object-relative). If an item is at that coordinate,
+ * that item handle is returned, and if @p xposret is not NULL, the
+ * integer pointed to is set to a value of -1, 0 or 1, depending if
+ * the coordinate is on the left portion of that item (-1), on the
+ * middle section (0) or on the right part (1).
+ * if @p yposret is not NULL, the
+ * integer pointed to is set to a value of -1, 0 or 1, depending if
+ * the coordinate is on the upper portion of that item (-1), on the
+ * middle section (0) or on the lower part (1). If NULL is returned as
+ * an item (no item found there), then posret may indicate -1 or 1
+ * based if the coordinate is above or below all items respectively in
+ * the gengrid.
+ *
+ * @ingroup Gengrid
+ */
+EAPI Elm_Object_Item             *elm_gengrid_at_xy_item_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *xposret, int *yposret);
+
index 256689a..b9c9325 100644 (file)
@@ -2483,6 +2483,68 @@ _last_item_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
    else *ret = eina_list_data_get(eina_list_last(sd->items));
 }
 
+EAPI Elm_Object_Item *
+elm_list_at_xy_item_get(const Evas_Object *obj,
+                           Evas_Coord x,
+                           Evas_Coord y,
+                           int *posret)
+{
+   ELM_LIST_CHECK(obj) NULL;
+   Elm_Object_Item *ret = NULL;
+   eo_do((Eo *) obj, elm_obj_list_at_xy_item_get(x, y, posret, &ret));
+   return ret;
+}
+
+static void
+_at_xy_item_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
+{
+   Eina_List *l;
+   Elm_List_Item *it;
+
+   Evas_Coord x = va_arg(*list, Evas_Coord);
+   Evas_Coord y = va_arg(*list, Evas_Coord);
+   int *posret = va_arg(*list, int *);
+   Evas_Coord lasty;
+   Elm_Object_Item **ret = va_arg(*list, Elm_Object_Item **);
+   Elm_List_Smart_Data *sd = _pd;
+   evas_object_geometry_get(sd->hit_rect, &lasty, NULL, NULL, NULL);
+
+   EINA_LIST_FOREACH(sd->items, l, it)
+     {
+        Evas_Coord itx, ity;
+        Evas_Object *vit = VIEW(it);
+        Evas_Coord vx, vy, vw, vh;
+        evas_object_geometry_get(vit, &vx, &vy, &vw, &vh);
+
+        itx = vx;
+        ity = vy;
+        if (ELM_RECTS_INTERSECT
+              (itx, ity, vw, vh, x, y, 1, 1))
+          {
+             if (posret)
+               {
+                  if (y <= (ity + (vh / 4))) *posret = -1;
+                  else if (y >= (ity + vh - (vh / 4)))
+                    *posret = 1;
+                  else *posret = 0;
+               }
+
+             *ret = (Elm_Object_Item *) it;
+             return;
+          }
+
+        lasty = ity + vh;
+     }
+
+   if (posret)
+     {
+        if (y > lasty) *posret = 1;
+        else *posret = -1;
+     }
+
+   *ret = NULL;
+}
+
 static void
 _class_constructor(Eo_Class *klass)
 {
@@ -2530,6 +2592,7 @@ _class_constructor(Eo_Class *klass)
            EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_ITEM_SORTED_INSERT), _item_sorted_insert),
            EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_FIRST_ITEM_GET), _first_item_get),
            EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET), _last_item_get),
+           EO_OP_FUNC(ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET), _at_xy_item_get),
            EO_OP_FUNC_SENTINEL
       };
       eo_class_funcs_set(klass, func_desc);
@@ -2561,6 +2624,7 @@ static const Eo_Op_Description op_desc[] = {
      EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_ITEM_SORTED_INSERT, "Insert a new item into the sorted list object."),
      EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_FIRST_ITEM_GET, "Get the first item in the list."),
      EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET, "Get the last item in the list."),
+     EO_OP_DESCRIPTION(ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET, "Get the item that is at the x, y canvas coords."),
      EO_OP_DESCRIPTION_SENTINEL
 };
 
index 26217bb..e443ba1 100644 (file)
@@ -31,6 +31,7 @@
    ELM_OBJ_LIST_SUB_ID_ITEM_SORTED_INSERT,
    ELM_OBJ_LIST_SUB_ID_FIRST_ITEM_GET,
    ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET,
+   ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET,
    ELM_OBJ_LIST_SUB_ID_LAST
 };
 
 #define elm_obj_list_last_item_get(ret) ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_LAST_ITEM_GET), EO_TYPECHECK(Elm_Object_Item **, ret)
 
 /**
+ * @def elm_obj_list_at_xy_item_get
+ * @since 1.8
+ *
+ * Get the item that is at the x, y canvas coords.
+ *
+ * @param[in] x
+ * @param[in] y
+ * @param[out] posret
+ * @param[out] ret
+ *
+ * @see elm_list_at_xy_item_get
+ */
+#define elm_obj_list_at_xy_item_get(x, y, posret, ret) ELM_OBJ_LIST_ID(ELM_OBJ_LIST_SUB_ID_AT_XY_ITEM_GET), EO_TYPECHECK(Evas_Coord, x), EO_TYPECHECK(Evas_Coord, y), EO_TYPECHECK(int *, posret), EO_TYPECHECK(Elm_Object_Item **, ret)
+
+/**
  * @}
  */
index a9afa84..98aac27 100644 (file)
@@ -500,3 +500,27 @@ EAPI Elm_Object_Item             *elm_list_first_item_get(const Evas_Object *obj
  * @ingroup List
  */
 EAPI Elm_Object_Item             *elm_list_last_item_get(const Evas_Object *obj);
+
+/**
+ * Get the item that is at the x, y canvas coords.
+ *
+ * @param obj The list object.
+ * @param x The input x coordinate
+ * @param y The input y coordinate
+ * @param posret The position relative to the item returned here
+ * @return The item at the coordinates or NULL if none
+ *
+ * This returns the item at the given coordinates (which are canvas
+ * relative, not object-relative). If an item is at that coordinate,
+ * that item handle is returned, and if @p posret is not NULL, the
+ * integer pointed to is set to a value of -1, 0 or 1, depending if
+ * the coordinate is on the upper portion of that item (-1), on the
+ * middle section (0) or on the lower part (1). If NULL is returned as
+ * an item (no item found there), then posret may indicate -1 or 1
+ * based if the coordinate is above or below all items respectively in
+ * the list.
+ *
+ *
+ * @ingroup List
+ */
+EAPI Elm_Object_Item             *elm_list_at_xy_item_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *posret);