--- /dev/null
+#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);
+}
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
{
Evas_Object *obj;
/* FIXME: Cache window */
Elm_Sel_Format types;
+ Elm_Drag_State entercb;
+ Elm_Drag_State leavecb;
+ Elm_Drag_Pos poscb;
Elm_Drop_Cb dropcb;
+ void *enterdata;
+ void *leavedata;
+ void *posdata;
void *cbdata;
+ struct {
+ Evas_Coord x, y;
+ Eina_Bool in : 1;
+ } 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 Saved_Type savedtypes = { NULL, NULL, 0, 0, 0, EINA_FALSE };
/* TODO BUG: should NEVER have these as globals! They should be per context (window). */
-static void (*dragdonecb) (void *data, Evas_Object *obj) = NULL;
+static Elm_Drag_Pos dragposcb = NULL;
+static Elm_Drag_Accept dragacceptcb = NULL;
+static Elm_Drag_State dragdonecb = NULL;
+static void *dragposdata = NULL;
+static void *dragacceptdata = NULL;
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;
static Ecore_Event_Handler *handler_enter = NULL;
static Ecore_Event_Handler *handler_status = NULL;
+static Ecore_Event_Handler *handler_leave = NULL;
+static Ecore_Event_Handler *handler_up = NULL;
static Tmp_Info *_tempfile_new (int size);
static int _tmpinfo_free (Tmp_Info *tmp);
static Eina_Bool _pasteimage_append (char *file, Evas_Object *entry);
static void _entry_insert_filter(Evas_Object *entry, char *str); // TIZEN ONLY
-//#define DEBUGON 1
+#define DEBUGON 1
#ifdef DEBUGON
# define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
#else
Elm_Sel_Format format;
Ecore_X_Selection ecore_sel;
Ecore_X_Window xwin;
+ Elm_Xdnd_Action action;
Eina_Bool active : 1;
};
static Eina_Bool _x11_dnd_drop (void *data __UNUSED__, int etype __UNUSED__, void *ev);
static Eina_Bool _x11_dnd_position (void *data __UNUSED__, int etype __UNUSED__, void *ev);
static Eina_Bool _x11_dnd_status (void *data __UNUSED__, int etype __UNUSED__, void *ev);
-static void _x11_drag_mouse_up (void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data);
+static Eina_Bool _x11_drag_mouse_up (void *data, int etype __UNUSED__, void *event);
static void _x11_drag_move (void *data __UNUSED__, Ecore_X_Xdnd_Position *pos);
static Ecore_X_Window _x11_elm_widget_xwin_get (const Evas_Object *obj);
static void _x11_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data);
static Eina_Bool _x11_elm_object_cnp_selection_clear (Evas_Object *obj, Elm_Sel_Type selection);
static Eina_Bool _x11_elm_cnp_selection_get (Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata);
-static Eina_Bool _x11_elm_drop_target_add (Evas_Object *obj, Elm_Sel_Type format, Elm_Drop_Cb dropcb, void *cbdata);
+static Eina_Bool _x11_elm_drop_target_add (Evas_Object *obj, Elm_Sel_Format format,
+ Elm_Drag_State entercb, void *enterdata,
+ Elm_Drag_State leavecb, void *leavedata,
+ Elm_Drag_Pos poscb, void *posdata,
+ Elm_Drop_Cb dropcb, void *cbdata);
static Eina_Bool _x11_elm_drop_target_del (Evas_Object *obj);
static Eina_Bool _x11_elm_selection_selection_has_owner (Evas_Object *obj __UNUSED__);
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
_x11_text_converter,
NULL,
- NULL,
+ _x11_notify_handler_text,
0
},
[CNP_ATOM_TEXT] = {
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
_x11_text_converter,
NULL,
- NULL,
+ _x11_notify_handler_text,
0
},
[CNP_ATOM_text_plain_utf8] = {
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
_x11_text_converter,
NULL,
- NULL,
+ _x11_notify_handler_text,
0
},
[CNP_ATOM_text_plain] = {
ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
_x11_text_converter,
NULL,
- NULL,
+ _x11_notify_handler_text,
0
},
};
{
X11_Cnp_Selection *sel = data;
if (sel->widget == obj) sel->widget = NULL;
+ if (dragwidget == obj) dragwidget = NULL;
}
static void
_x11_notify_handler_text(X11_Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
{
Ecore_X_Selection_Data *data;
+ Eina_List *l;
+ Dropable *dropable;
data = notify->data;
+ if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
+ {
+ Elm_Selection_Data ddata;
+
+ cnp_debug("drag & drop\n");
+ /* FIXME: this needs to be generic: Used for all receives */
+ EINA_LIST_FOREACH(drops, l, dropable)
+ {
+ if (dropable->obj == sel->requestwidget) break;
+ dropable = NULL;
+ }
+ if (dropable)
+ {
+ ddata.x = savedtypes.x;
+ ddata.y = savedtypes.y;
+ ddata.format = ELM_SEL_FORMAT_TEXT;
+ ddata.data = data->data;
+ ddata.len = data->length;
+ ddata.action = sel->action;
+ dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
+ goto end;
+ }
+ }
if (sel->datacb)
{
Elm_Selection_Data ddata;
ddata.format = ELM_SEL_FORMAT_TEXT;
ddata.data = data->data;
ddata.len = data->length;
+ ddata.action = sel->action;
sel->datacb(sel->udata, sel->widget, &ddata);
}
else
char *stripstr, *mkupstr;
stripstr = malloc(data->length + 1);
- if (!stripstr) return 0;
+ if (!stripstr) goto end;
strncpy(stripstr, (char *)data->data, data->length);
stripstr[data->length] = '\0';
cnp_debug("Notify handler text %d %d %p\n", data->format,
free(stripstr);
free(mkupstr);
}
+end:
+ if (sel == (_x11_selections + ELM_SEL_TYPE_XDND))
+ ecore_x_dnd_send_finished();
return 0;
}
{
Ecore_X_Selection_Data *data;
Ecore_X_Selection_Data_Files *files;
- char *p, *stripstr;
+ char *p, *s, *stripstr = NULL;
data = notify->data;
cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
if (data->content == ECORE_X_SELECTION_CONTENT_FILES)
{
+ int i, len = 0;
+
cnp_debug("got a files list\n");
files = notify->data;
+ /*
if (files->num_files > 1)
{
- /* Don't handle many items */
+ // Don't handle many items <- this makes mr bigglesworth sad :(
cnp_debug("more then one file: Bailing\n");
return 0;
}
stripstr = p = strdup(files->files[0]);
+ */
+ for (i = 0; i < files->num_files ; i++)
+ {
+ p = files->files[i];
+ if ((strncmp(p, "file://", 7)) && (p[0] != '/')) continue;
+ len += strlen(files->files[i]) + 1;
+ }
+ p = NULL;
+ if (len > 0)
+ {
+ s = stripstr = malloc(len + 1);
+ for (i = 0; i < files->num_files ; i++)
+ {
+ p = files->files[i];
+ if (!strncmp(p, "file://", 7)) p += 7;
+ else if (p[0] != '/') continue;
+ len = strlen(p);
+ strcpy(s, p);
+ if (i < (files->num_files - 1))
+ {
+ s[len] = '\n';
+ s[len + 1] = 0;
+ s += len + 1;
+ }
+ else
+ {
+ s[len] = 0;
+ s += len;
+ }
+ }
+ }
}
else
{
- stripstr = p = malloc(data->length + 1);
- if (!stripstr) return 0;
- memcpy(stripstr, data->data, data->length);
- stripstr[data->length] = 0;
+ p = (char *)data->data;
+ if ((!strncmp(p, "file://", 7)) || (p[0] == '/'))
+ {
+ int len = data->length;
+ if (!strncmp(p, "file://", 7))
+ {
+ p += 7;
+ len -= 7;
+ }
+ stripstr = malloc(len + 1);
+ if (!stripstr) return 0;
+ memcpy(stripstr, p, len);
+ stripstr[len] = 0;
+ }
}
- if (!p)
+ if (!stripstr)
{
cnp_debug("Couldn't find a file\n");
return 0;
}
- cnp_debug("Got %s\n", p);
-
- if (sel->datacb)
- {
- Elm_Selection_Data ddata;
-
- ddata.x = ddata.y = 0;
- ddata.format = ELM_SEL_FORMAT_IMAGE;
- ddata.data = p;
- ddata.len = data->length;
- sel->datacb(sel->udata, sel->widget, &ddata);
- free(p);
- return 0;
- }
-
- if (strncmp(p, "file://", 7))
- {
- /* Try and continue if it looks sane */
- if (*p != '/')
- {
- free(p);
- return 0;
- }
- }
- else p += strlen("file://");
if (savedtypes.imgfile) free(savedtypes.imgfile);
if (savedtypes.textreq)
{
savedtypes.textreq = 0;
- savedtypes.imgfile = strdup(p);
+ savedtypes.imgfile = stripstr;
+ }
+ else
+ {
+ savedtypes.imgfile = NULL;
+ _pasteimage_append(p, sel->requestwidget);
+ free(stripstr);
}
- else _pasteimage_append(p, sel->requestwidget);
- free(stripstr);
return 0;
}
ddata.format = ELM_SEL_FORMAT_VCARD;
ddata.data = data->data;
ddata.len = data->length;
+ ddata.action = sel->action;
dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
ecore_x_dnd_send_finished();
}
ddata.format = ELM_SEL_FORMAT_VCARD;
ddata.data = data->data;
ddata.len = data->length;
+ ddata.action = sel->action;
sel->datacb(sel->udata, sel->widget, &ddata);
}
else cnp_debug("Paste request\n");
ddata.format = ELM_SEL_FORMAT_IMAGE;
ddata.data = data->data;
ddata.len = data->length;
+ ddata.action = sel->action;
sel->datacb(sel->udata, sel->widget, &ddata);
return 0;
}
ddata.format = ELM_SEL_FORMAT_HTML;
ddata.data = stripstr;
ddata.len = data->length;
+ ddata.action = ELM_XDND_ACTION_UNKNOWN;
sel->datacb(sel->udata, sel->widget, &ddata);
free(stripstr);
return 0;
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;
}
+static Dropable *
+_x11_dropable_find(Ecore_X_Window win)
+{
+ Eina_List *l;
+ Dropable *dropable;
+
+ if (!drops) return NULL;
+ EINA_LIST_FOREACH(drops, l, dropable)
+ {
+ if (_x11_elm_widget_xwin_get(dropable->obj) == win) return dropable;
+ }
+ return NULL;
+}
+
+static Dropable *
+_x11_dropable_geom_find(Ecore_X_Window win, Evas_Coord px, Evas_Coord py)
+{
+ Eina_List *l;
+ Dropable *dropable;
+ Evas_Coord x, y, w, h;
+
+ if (!drops) return NULL;
+ EINA_LIST_FOREACH(drops, l, dropable)
+ {
+ if (_x11_elm_widget_xwin_get(dropable->obj) == win)
+ {
+ evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
+ if ((px >= x) && (py >= y) && (px < (x + w)) && (py < (y + h)))
+ return dropable;
+ }
+ }
+ return NULL;
+}
+
+static void
+_x11_dropable_coords_adjust(Dropable *dropable, Evas_Coord *x, Evas_Coord *y)
+{
+ Ecore_Evas *ee;
+ int ex = 0, ey = 0;
+
+ ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
+ ecore_evas_geometry_get(ee, &ex, &ey, NULL, NULL);
+ *x = *x - ex;
+ *y = *y - ey;
+}
+
+static void
+_x11_dropable_all_set(Ecore_X_Window win, Evas_Coord x, Evas_Coord y, Eina_Bool set)
+{
+ Eina_List *l;
+ Dropable *dropable;
+ EINA_LIST_FOREACH(drops, l, dropable)
+ {
+ if (_x11_elm_widget_xwin_get(dropable->obj) == win)
+ {
+ dropable->last.x = x;
+ dropable->last.y = y;
+ dropable->last.in = set;
+ }
+ }
+}
+
static Eina_Bool
_x11_dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
{
Ecore_X_Event_Xdnd_Enter *enter = ev;
int i;
+ Dropable *dropable;
+ dropable = _x11_dropable_find(enter->win);
+ if (dropable)
+ {
+ cnp_debug("Enter %x\n", enter->win);
+ _x11_dropable_all_set(enter->win, 0, 0, EINA_FALSE);
+ }
/* Skip it */
- cnp_debug("enter %p\n", enter);
cnp_debug("enter types=%p (%d)\n", enter->types, enter->num_types);
if ((!enter) || (!enter->num_types) || (!enter->types)) return EINA_TRUE;
return EINA_TRUE;
}
+static void
+_x11_dnd_dropable_handle(Dropable *dropable, Evas_Coord x, Evas_Coord y, Eina_Bool have_obj, Elm_Xdnd_Action action)
+{
+ Dropable *dropable_last = NULL;
+
+ if (dropable->last.in)
+ dropable_last = _x11_dropable_geom_find
+ (_x11_elm_widget_xwin_get(dropable->obj),
+ dropable->last.x, dropable->last.y);
+ if ((have_obj) && (dropable_last == dropable)) // same
+ {
+ cnp_debug("same obj dropable %p\n", dropable);
+ if (dropable->poscb)
+ dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
+ }
+ else if ((have_obj) && (!dropable_last)) // enter new obj
+ {
+ cnp_debug("enter %p\n", dropable->obj);
+ if (dropable->entercb)
+ dropable->entercb(dropable->enterdata, dropable->obj);
+ if (dropable->poscb)
+ dropable->poscb(dropable->posdata, dropable->obj, x, y, action);
+ }
+ else if ((!have_obj) && (dropable_last)) // leave last obj
+ {
+ cnp_debug("leave %p\n", dropable_last->obj);
+ if (dropable->leavecb)
+ dropable->leavecb(dropable->leavedata, dropable->obj);
+ }
+ else if (have_obj) // leave last obj and enter new one
+ {
+ cnp_debug("enter %p\n", dropable->obj);
+ if (dropable->entercb)
+ dropable->entercb(dropable->enterdata, dropable->obj);
+ if (dropable_last)
+ {
+ dropable = dropable_last;
+ if (dropable->leavecb)
+ dropable->leavecb(dropable->leavedata, dropable->obj);
+ cnp_debug("leave %p\n", dropable->obj);
+ }
+ }
+}
+
+static Elm_Xdnd_Action
+_x11_dnd_action_map(Ecore_X_Atom action)
+{
+ Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN;
+
+ if (action == ECORE_X_ATOM_XDND_ACTION_COPY)
+ act = ELM_XDND_ACTION_COPY;
+ else if (action == ECORE_X_ATOM_XDND_ACTION_MOVE)
+ act = ELM_XDND_ACTION_MOVE;
+ else if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE)
+ act = ELM_XDND_ACTION_PRIVATE;
+ else if (action == ECORE_X_ATOM_XDND_ACTION_ASK)
+ act = ELM_XDND_ACTION_ASK;
+ else if (action == ECORE_X_ATOM_XDND_ACTION_LIST)
+ act = ELM_XDND_ACTION_LIST;
+ else if (action == ECORE_X_ATOM_XDND_ACTION_LINK)
+ act = ELM_XDND_ACTION_LINK;
+ else if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION)
+ act = ELM_XDND_ACTION_DESCRIPTION;
+ return act;
+}
+
+static Ecore_X_Atom
+_x11_dnd_action_rev_map(Elm_Xdnd_Action action)
+{
+ Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE;
+
+ if (action == ELM_XDND_ACTION_COPY)
+ act = ECORE_X_ATOM_XDND_ACTION_COPY;
+ else if (action == ELM_XDND_ACTION_MOVE)
+ act = ECORE_X_ATOM_XDND_ACTION_MOVE;
+ else if (action == ELM_XDND_ACTION_PRIVATE)
+ act = ECORE_X_ATOM_XDND_ACTION_PRIVATE;
+ else if (action == ELM_XDND_ACTION_ASK)
+ act = ECORE_X_ATOM_XDND_ACTION_ASK;
+ else if (action == ELM_XDND_ACTION_LIST)
+ act = ECORE_X_ATOM_XDND_ACTION_LIST;
+ else if (action == ELM_XDND_ACTION_LINK)
+ act = ECORE_X_ATOM_XDND_ACTION_LINK;
+ else if (action == ELM_XDND_ACTION_DESCRIPTION)
+ act = ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
+ return act;
+}
+
+static Eina_Bool
+_x11_dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
+{
+ Ecore_X_Event_Xdnd_Position *pos = ev;
+ Ecore_X_Rectangle rect;
+ Dropable *dropable, *dropable_old;
+ Elm_Xdnd_Action act;
+
+ /* Need to send a status back */
+ /* FIXME: Should check I can drop here */
+ /* FIXME: Should highlight widget */
+ dropable_old = dropable = _x11_dropable_find(pos->win);
+ if (dropable)
+ {
+ Evas_Coord x, y, ox = 0, oy = 0, ow = 0, oh = 0;
+
+ x = pos->position.x;
+ y = pos->position.y;
+ _x11_dropable_coords_adjust(dropable, &x, &y);
+ dropable = _x11_dropable_geom_find(pos->win, x, y);
+ act = _x11_dnd_action_map(pos->action);
+ if (dropable)
+ {
+ evas_object_geometry_get(dropable->obj, &ox, &oy, &ow, &oh);
+ rect.x = pos->position.x - x + ox;
+ rect.y = pos->position.y - y + oy;
+ rect.width = ow;
+ rect.height = oh;
+ ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
+ cnp_debug("dnd position %i %i %p\n", x - ox, y - oy, dropable);
+ _x11_dnd_dropable_handle(dropable, x - ox, y - oy, EINA_TRUE,
+ act);
+ // CCCCCCC: call dnd exit on last obj if obj != last
+ // CCCCCCC: call drop position on obj
+ _x11_dropable_all_set(pos->win, x, y, EINA_TRUE);
+ }
+ else
+ {
+ ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action);
+ cnp_debug("dnd position not in obj\n");
+ _x11_dnd_dropable_handle(dropable_old, 0, 0, EINA_FALSE,
+ act);
+ // CCCCCCC: call dnd exit on last obj
+ _x11_dropable_all_set(pos->win, x, y, EINA_TRUE);
+ }
+ }
+ else
+ {
+ ecore_x_dnd_send_status(EINA_FALSE, EINA_FALSE, rect, pos->action);
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_x11_dnd_leave(void *data __UNUSED__, int etype __UNUSED__, void *ev)
+{
+ Ecore_X_Event_Xdnd_Leave *leave = ev;
+ Dropable *dropable;
+
+ dropable = _x11_dropable_find(leave->win);
+ if (dropable)
+ {
+ cnp_debug("Leave %x\n", leave->win);
+ _x11_dnd_dropable_handle(dropable, 0, 0, EINA_FALSE, ELM_XDND_ACTION_UNKNOWN);
+ _x11_dropable_all_set(leave->win, 0, 0, EINA_FALSE);
+ // CCCCCCC: call dnd exit on last obj if there was one
+ }
+ // leave->win leave->source
+ return EINA_TRUE;
+}
+
static Eina_Bool
_x11_dnd_drop(void *data __UNUSED__, int etype __UNUSED__, void *ev)
{
- struct _Ecore_X_Event_Xdnd_Drop *drop;
+ Ecore_X_Event_Xdnd_Drop *drop;
Dropable *dropable;
- Eina_List *l;
- Ecore_Evas *ee;
- Ecore_X_Window xwin;
Elm_Selection_Data ddata;
- int x, y, w, h;
+ Evas_Coord x = 0, y = 0;
+ Elm_Xdnd_Action act = ELM_XDND_ACTION_UNKNOWN;
int i, j;
drop = ev;
cnp_debug("drops %p (%d)\n", drops, eina_list_count(drops));
-
- // check we still have something to drop
- if (!drops) return EINA_TRUE;
-
- /* Find any widget in our window; then work out geometry rel to our window */
- for (l = drops; l; l = l->next)
- {
- dropable = l->data;
- xwin = _x11_elm_widget_xwin_get(dropable->obj);
- if (xwin == drop->win) break;
- }
- /* didn't find a window */
- if (!l) return EINA_TRUE;
+ if (!(dropable = _x11_dropable_find(drop->win))) return EINA_TRUE;
/* Calculate real (widget relative) position */
// - window position
// - widget position
- ee = ecore_evas_ecore_evas_get(evas_object_evas_get(dropable->obj));
- ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
- savedtypes.x = drop->position.x - x;
- savedtypes.y = drop->position.y - y;
+ savedtypes.x = drop->position.x;
+ savedtypes.y = drop->position.y;
+ _x11_dropable_coords_adjust(dropable, &savedtypes.x, &savedtypes.y);
cnp_debug("Drop position is %d,%d\n", savedtypes.x, savedtypes.y);
- for (; l; l = l->next)
- {
- dropable = l->data;
- evas_object_geometry_get(dropable->obj, &x, &y, &w, &h);
- if ((savedtypes.x >= x) && (savedtypes.y >= y) &&
- (savedtypes.x < x + w) && (savedtypes.y < y + h))
- break; /* found! */
- }
-
- if (!l) return EINA_TRUE; /* didn't find one */
+ dropable = _x11_dropable_geom_find(drop->win, savedtypes.x, savedtypes.y);
+ if (!dropable) return EINA_TRUE; /* didn't find one */
evas_object_geometry_get(dropable->obj, &x, &y, NULL, NULL);
savedtypes.x -= x;
found:
cnp_debug("Found a target we'd like: %s\n", _x11_atoms[i].name);
- cnp_debug("0x%x\n",xwin);
+ cnp_debug("0x%x\n", drop->win);
+ act = _x11_dnd_action_map(drop->action);
+
if (i == CNP_ATOM_text_urilist)
{
cnp_debug("We found a URI... (%scached) %s\n",
if (savedtypes.imgfile)
{
char *entrytag;
- static const char *tagstring = "<item absize=240x180 href="
- "file://%s></item>";
+ static const char *tagstring =
+ "<item absize=240x180 href=file://%s></item>";
ddata.x = savedtypes.x;
ddata.y = savedtypes.y;
+ ddata.action = act;
/* If it's markup that also supports images */
if ((dropable->types & ELM_SEL_FORMAT_MARKUP) &&
}
cnp_debug("doing a request then\n");
- _x11_selections[ELM_SEL_TYPE_XDND].xwin = xwin;
+ _x11_selections[ELM_SEL_TYPE_XDND].xwin = drop->win;
_x11_selections[ELM_SEL_TYPE_XDND].requestwidget = dropable->obj;
_x11_selections[ELM_SEL_TYPE_XDND].requestformat = ELM_SEL_FORMAT_MARKUP;
_x11_selections[ELM_SEL_TYPE_XDND].active = EINA_TRUE;
+ _x11_selections[ELM_SEL_TYPE_XDND].action = act;
- ecore_x_selection_xdnd_request(xwin, _x11_atoms[i].name);
+ ecore_x_selection_xdnd_request(drop->win, _x11_atoms[i].name);
return EINA_TRUE;
}
static Eina_Bool
-_x11_dnd_position(void *data __UNUSED__, int etype __UNUSED__, void *ev)
+_x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
{
- struct _Ecore_X_Event_Xdnd_Position *pos = ev;
- Ecore_X_Rectangle rect;
+ Ecore_X_Event_Xdnd_Status *status = ev;
+ doaccept = EINA_FALSE;
- /* Need to send a status back */
- /* FIXME: Should check I can drop here */
- /* FIXME: Should highlight widget */
- rect.x = pos->position.x - 5;
- rect.y = pos->position.y - 5;
- rect.width = 10;
- rect.height = 10;
- ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, rect, pos->action);
+ /* Only thing we care about: will accept */
+ if ((status) && (status->will_accept))
+ {
+ cnp_debug("Will accept\n");
+ doaccept = EINA_TRUE;
+ }
+ /* Won't accept */
+ else
+ {
+ cnp_debug("Won't accept accept\n");
+ }
+ if (dragacceptcb)
+ dragacceptcb(dragacceptdata, _x11_selections[ELM_SEL_TYPE_XDND].widget,
+ doaccept);
return EINA_TRUE;
}
-/**
- * When dragging this is callback response from the destination.
- * The important thing we care about: Can we drop; thus update cursor
- * appropriately.
- */
static Eina_Bool
-_x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
-{
- struct _Ecore_X_Event_Xdnd_Status *status = ev;
-
- if (!status) return EINA_TRUE;
+_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);
+ }
- /* Only thing we care about: will accept */
- if (status->will_accept) cnp_debug("Will accept\n");
- /* Won't accept */
- else cnp_debug("Won't accept accept\n");
- return EINA_TRUE;
+ return ECORE_CALLBACK_RENEW;
}
-static void
-_x11_drag_mouse_up(void *un __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *data)
+static Eina_Bool
+_x11_drag_mouse_up(void *data, int etype __UNUSED__, void *event)
{
- Ecore_X_Window xwin = *((Ecore_X_Window *)data);
- evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _x11_drag_mouse_up);
- ecore_x_dnd_drop();
-
- cnp_debug("mouse up, xwin=%#llx\n", (unsigned long long)xwin);
+ Ecore_X_Window xwin = (Ecore_X_Window)(long)data;
+ Ecore_Event_Mouse_Button *ev = event;
- /* TODO BUG: should not revert to FALSE if xwin is a drop target! */
- ecore_x_dnd_aware_set(xwin, EINA_FALSE);
- if (dragdonecb)
+ if ((ev->buttons == 1) &&
+ (ev->event_window == xwin))
{
- dragdonecb(dragdonedata, _x11_selections[ELM_SEL_TYPE_XDND].widget);
+ Eina_Bool have_drops = EINA_FALSE;
+ Eina_List *l;
+ Dropable *dropable;
+
+ ecore_x_pointer_ungrab();
+ if (handler_up)
+ {
+ ecore_event_handler_del(handler_up);
+ handler_up = NULL;
+ }
+ if (handler_status)
+ {
+ ecore_event_handler_del(handler_status);
+ 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))
+ {
+ have_drops = EINA_TRUE;
+ break;
+ }
+ }
+ 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;
+ }
+ */
}
- if (dragwin)
- {
- evas_object_del(dragwin);
- dragwin = NULL;
- }
+ return EINA_TRUE;
}
static void
_x11_drag_move(void *data __UNUSED__, Ecore_X_Xdnd_Position *pos)
{
- evas_object_move(dragwin, pos->position.x - _dragx, pos->position.y - _dragy);
+ evas_object_move(dragwin,
+ pos->position.x - _dragx, pos->position.y - _dragy);
+ 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,
+ dragaction);
}
static Ecore_X_Window
{
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);
{
int i;
static int _init_count = 0;
-
+
if (_init_count > 0) return EINA_TRUE;
_init_count++;
for (i = 0; i < CNP_N_ATOMS; i++)
ecore_x_selection_converter_atom_add
(_x11_atoms[i].atom, _x11_atoms[i].converter);
}
+ //XXX delete handlers?
ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _x11_selection_clear, NULL);
ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _x11_selection_notify, NULL);
return EINA_TRUE;
static Eina_Bool
_x11_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection,
- Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
+ Elm_Sel_Format format, Elm_Drop_Cb datacb,
+ void *udata)
{
Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
X11_Cnp_Selection *sel;
}
static Eina_Bool
-_x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
+_x11_elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
+ Elm_Drag_State entercb, void *enterdata,
+ Elm_Drag_State leavecb, void *leavedata,
+ Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *cbdata)
{
- Dropable *drop;
+ Dropable *drop, *dropable;
Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
- Eina_List *item;
+ Eina_List *item, *l;
int first;
-
- _x11_elm_cnp_init();
+ Eina_Bool have_drops = EINA_FALSE;
+ _x11_elm_cnp_init();
+
/* TODO: check if obj is already a drop target. Do not add twice! */
/* Is this the first? */
+ EINA_LIST_FOREACH(drops, l, dropable)
+ {
+ if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
+ {
+ have_drops = EINA_TRUE;
+ break;
+ }
+ }
first = (!drops) ? 1 : 0;
EINA_LIST_FOREACH(drops, item, drop)
free(drop);
return EINA_FALSE;
}
+ drop->entercb = entercb;
+ drop->enterdata = enterdata;
+ drop->leavecb = leavecb;
+ drop->leavedata = leavedata;
+ drop->poscb = poscb;
+ drop->posdata = posdata;
drop->dropcb = dropcb;
drop->cbdata = cbdata;
drop->types = format;
/* I love C and varargs */
(Evas_Object_Event_Cb)elm_drop_target_del,
obj);
+ if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_TRUE);
+
/* TODO BUG: should handle dnd-aware per window, not just the first
* window that requested it! */
/* If not the first: We're done */
if (!first) return EINA_TRUE;
- ecore_x_dnd_aware_set(xwin, EINA_TRUE);
cnp_debug("Adding drop target calls xwin=%#llx\n", (unsigned long long)xwin);
handler_enter = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
_x11_dnd_enter, NULL);
+ handler_leave = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
+ _x11_dnd_leave, NULL);
handler_pos = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
_x11_dnd_position, NULL);
handler_drop = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
static Eina_Bool
_x11_elm_drop_target_del(Evas_Object *obj)
{
- Dropable *drop,*del;
- Eina_List *item;
+ Dropable *drop, *del, *dropable;
+ Eina_List *item, *l;
Ecore_X_Window xwin;
+ Eina_Bool have_drops = EINA_FALSE;
_x11_elm_cnp_init();
evas_object_event_callback_del(obj, EVAS_CALLBACK_FREE,
(Evas_Object_Event_Cb)elm_drop_target_del);
- free(drop);
-
+ if (del) free(del);
+
/* TODO BUG: we should handle dnd-aware per window, not just the last that reelased it */
/* If still drops there: All fine.. continue */
cnp_debug("Disabling DND\n");
xwin = _x11_elm_widget_xwin_get(obj);
- ecore_x_dnd_aware_set(xwin, EINA_FALSE);
+ EINA_LIST_FOREACH(drops, l, dropable)
+ {
+ if (xwin == _x11_elm_widget_xwin_get(dropable->obj))
+ {
+ have_drops = EINA_TRUE;
+ break;
+ }
+ }
+ if (!have_drops) ecore_x_dnd_aware_set(xwin, EINA_FALSE);
- ecore_event_handler_del(handler_pos);
- ecore_event_handler_del(handler_drop);
- ecore_event_handler_del(handler_enter);
+ if (!drops)
+ {
+ if (handler_pos)
+ {
+ ecore_event_handler_del(handler_pos);
+ handler_pos = NULL;
+ }
+ if (handler_drop)
+ {
+ ecore_event_handler_del(handler_drop);
+ handler_drop = NULL;
+ }
+ if (handler_enter)
+ {
+ ecore_event_handler_del(handler_enter);
+ handler_enter = NULL;
+ }
+ if (handler_leave)
+ {
+ ecore_event_handler_del(handler_leave);
+ handler_leave = NULL;
+ }
+ }
if (savedtypes.imgfile) free(savedtypes.imgfile);
savedtypes.imgfile = NULL;
return EINA_TRUE;
}
+static void
+_x11_drag_target_del(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *info __UNUSED__)
+{
+ X11_Cnp_Selection *sel = _x11_selections + ELM_SEL_TYPE_XDND;
+
+ if (dragwidget == obj)
+ {
+ sel->widget = NULL;
+ dragwidget = NULL;
+ }
+}
+
static Eina_Bool
-_x11_elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data, void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
+_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,
+ Elm_Drag_Accept acceptcb, void *acceptdata,
+ Elm_Drag_State dragdone, void *donecbdata)
{
Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj);
X11_Cnp_Selection *sel;
Elm_Sel_Type xdnd = ELM_SEL_TYPE_XDND;
Ecore_Evas *ee;
- int x, y, x2, y2, x3, y3;
- Evas_Object *icon;
+ int x, y, x2 = 0, y2 = 0, x3, y3;
+ Evas_Object *icon = NULL;
int w, h;
+ Ecore_X_Atom actx;
_x11_elm_cnp_init();
-
- cnp_debug("starting drag...\n");
+
+ cnp_debug("starting drag... %p\n", obj);
if (dragwin)
{
sel->widget = obj;
sel->format = format;
sel->selbuf = data ? strdup(data) : NULL;
+ sel->action = action;
+ dragwidget = obj;
+ dragaction = action;
+ evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
+ _x11_drag_target_del, obj);
/* TODO BUG: should NEVER have these as globals! They should be per context (window). */
+ dragposcb = dragpos;
+ dragposdata = dragdata;
+ dragacceptcb = acceptcb;
+ dragacceptdata = acceptdata;
dragdonecb = dragdone;
dragdonedata = donecbdata;
/* TODO BUG: should increase dnd-awareness, in case it's drop target as well. See _x11_drag_mouse_up() */
ecore_x_dnd_aware_set(xwin, EINA_TRUE);
ecore_x_dnd_callback_pos_update_set(_x11_drag_move, NULL);
- ecore_x_dnd_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
- evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
- _x11_drag_mouse_up, (void *)(long)xwin);
+ ecore_x_dnd_self_begin(xwin, (unsigned char *)&xdnd, sizeof(Elm_Sel_Type));
+ actx = _x11_dnd_action_rev_map(dragaction);
+ ecore_x_dnd_source_action_set(actx);
+ ecore_x_pointer_grab(xwin);
+ handler_up = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
+ _x11_drag_mouse_up,
+ (void *)(long)xwin);
handler_status = ecore_event_handler_add(ECORE_X_EVENT_XDND_STATUS,
_x11_dnd_status, NULL);
- dragwin = elm_win_add(NULL, "Elm Drag Object", ELM_WIN_UTILITY);
+ dragwin = elm_win_add(NULL, "Elm-Drag", ELM_WIN_UTILITY);
+ elm_win_alpha_set(dragwin, EINA_TRUE);
elm_win_override_set(dragwin, EINA_TRUE);
- /* FIXME: Images only */
- icon = elm_icon_add(dragwin);
- elm_image_file_set(icon, data + 7, NULL); /* 7!? "file://" */
+ if (createicon)
+ {
+ Evas_Coord xoff = 0, yoff = 0;
+
+ icon = createicon(createdata, dragwin, &xoff, &yoff);
+ if (icon)
+ {
+ x2 = xoff;
+ y2 = yoff;
+ evas_object_geometry_get(icon, NULL, NULL, &w, &h);
+ }
+ }
+ else
+ {
+ icon = elm_icon_add(dragwin);
+ 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);
- 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);
/* Position subwindow appropriately */
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
ecore_evas_geometry_get(ee, &x, &y, NULL, NULL);
- evas_object_geometry_get(obj, &x2, &y2, &w, &h);
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);
}
static Eina_Bool
+_x11_elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
+{
+ Ecore_X_Atom actx;
+
+ _x11_elm_cnp_init();
+ if (!dragwin) return EINA_FALSE;
+
+ if (dragwidget != obj) return EINA_FALSE;
+ if (dragaction == action) return EINA_TRUE;
+ dragaction = action;
+ actx = _x11_dnd_action_rev_map(dragaction);
+ ecore_x_dnd_source_action_set(actx);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
_x11_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
{
_x11_elm_cnp_init();
static void _local_elm_cnp_selection_loss_callback_set(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection __UNUSED__, Elm_Selection_Loss_Cb func __UNUSED__, const void *data __UNUSED__);
static Eina_Bool _local_elm_object_cnp_selection_clear(Evas_Object *obj __UNUSED__, Elm_Sel_Type selection);
static Eina_Bool _local_elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format __UNUSED__, Elm_Drop_Cb datacb, void *udata);
-static Eina_Bool _local_elm_drop_target_add(Evas_Object *obj __UNUSED__, Elm_Sel_Type format __UNUSED__, Elm_Drop_Cb dropcb __UNUSED__, void *cbdata __UNUSED__);
+static Eina_Bool _local_elm_drop_target_add(Evas_Object *obj __UNUSED__, Elm_Sel_Format format __UNUSED__,
+ Elm_Drag_State entercb __UNUSED__, void *enterdata __UNUSED__,
+ Elm_Drag_State leavecb __UNUSED__, void *leavedata __UNUSED__,
+ Elm_Drag_Pos poscb __UNUSED__, void *posdata __UNUSED__,
+ Elm_Drop_Cb dropcb __UNUSED__, void *cbdata __UNUSED__);
static Eina_Bool _local_elm_drop_target_del(Evas_Object *obj __UNUSED__);
-static Eina_Bool _local_elm_drag_start(Evas_Object *obj __UNUSED__, Elm_Sel_Format format __UNUSED__, const char *data __UNUSED__, void (*dragdone) (void *data, Evas_Object *) __UNUSED__, void *donecbdata __UNUSED__);
+static Eina_Bool _local_elm_drag_start(Evas_Object *obj __UNUSED__,
+ Elm_Sel_Format format __UNUSED__,
+ const char *data __UNUSED__,
+ Elm_Xdnd_Action action __UNUSED__,
+ Elm_Drag_Icon_Create_Cb createicon __UNUSED__,
+ void *createdata __UNUSED__,
+ Elm_Drag_Pos dragpos __UNUSED__,
+ void *dragdata __UNUSED__,
+ Elm_Drag_Accept acceptcb __UNUSED__,
+ void *acceptdata __UNUSED__,
+ Elm_Drag_State dragdone __UNUSED__,
+ void *donecbdata __UNUSED__);
static Eina_Bool _local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__);
static void
ev.format = info->format;
ev.data = info->sel.buf;
ev.len = info->sel.size;
+ ev.action = ELM_XDND_ACTION_UNKNOWN;
if (info->get.func)
info->get.func(info->get.data, info->get.obj, &ev);
}
static Eina_Bool
_local_elm_drop_target_add(Evas_Object *obj __UNUSED__,
- Elm_Sel_Type format __UNUSED__,
+ Elm_Sel_Format format __UNUSED__,
+ Elm_Drag_State entercb __UNUSED__,
+ void *enterdata __UNUSED__,
+ Elm_Drag_State leavecb __UNUSED__,
+ void *leavedata __UNUSED__,
+ Elm_Drag_Pos poscb __UNUSED__,
+ void *posdata __UNUSED__,
Elm_Drop_Cb dropcb __UNUSED__,
void *cbdata __UNUSED__)
{
_local_elm_drag_start(Evas_Object *obj __UNUSED__,
Elm_Sel_Format format __UNUSED__,
const char *data __UNUSED__,
- void (*dragdone) (void *data, Evas_Object *) __UNUSED__,
+ Elm_Xdnd_Action action __UNUSED__,
+ Elm_Drag_Icon_Create_Cb createicon __UNUSED__,
+ void *createdata __UNUSED__,
+ Elm_Drag_Pos dragpos __UNUSED__,
+ void *dragdata __UNUSED__,
+ Elm_Drag_Accept acceptcb __UNUSED__,
+ void *acceptdata __UNUSED__,
+ Elm_Drag_State dragdone __UNUSED__,
void *donecbdata __UNUSED__)
{
// XXX: implement me
}
static Eina_Bool
+_local_elm_drag_action_set(Evas_Object *obj __UNUSED__,
+ Elm_Xdnd_Action action __UNUSED__)
+{
+ // XXX: implement me
+ _local_elm_cnp_init();
+ return EINA_FALSE;
+}
+
+static Eina_Bool
_local_elm_selection_selection_has_owner(Evas_Object *obj __UNUSED__)
{
_local_elm_cnp_init();
* Add a widget as drop target.
*/
EAPI Eina_Bool
-elm_drop_target_add(Evas_Object *obj, Elm_Sel_Type format,
+elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
+ Elm_Drag_State entercb, void *enterdata,
+ Elm_Drag_State leavecb, void *leavedata,
+ Elm_Drag_Pos poscb, void *posdata,
Elm_Drop_Cb dropcb, void *cbdata)
{
if (!_elm_cnp_init_count) _elm_cnp_init();
#ifdef HAVE_ELEMENTARY_X
if (_x11_elm_widget_xwin_get(obj))
- return _x11_elm_drop_target_add(obj, format, dropcb, cbdata);
+ return _x11_elm_drop_target_add(obj, format, entercb, enterdata,
+ leavecb, leavedata, poscb, posdata,
+ dropcb, cbdata);
#endif
- return _local_elm_drop_target_add(obj, format, dropcb, cbdata);
+ return _local_elm_drop_target_add(obj, format, entercb, enterdata,
+ leavecb, leavedata, poscb, posdata,
+ dropcb, cbdata);
}
EAPI Eina_Bool
}
EAPI Eina_Bool
-elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const char *data,
- void (*dragdone) (void *data, Evas_Object *), void *donecbdata)
+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)
{
if (!_elm_cnp_init_count) _elm_cnp_init();
#ifdef HAVE_ELEMENTARY_X
if (_x11_elm_widget_xwin_get(obj))
- return _x11_elm_drag_start(obj, format, data, dragdone, donecbdata);
+ return _x11_elm_drag_start(obj, format, data, action,
+ createicon, createdata,
+ dragpos, dragdata,
+ acceptcb, acceptdata,
+ dragdone, donecbdata);
#endif
- return _local_elm_drag_start(obj, format, data, dragdone, donecbdata);
+ return _local_elm_drag_start(obj, format, data, action,
+ createicon, createdata,
+ dragpos, dragdata,
+ acceptcb, acceptdata,
+ dragdone, donecbdata);
+}
+
+EAPI Eina_Bool
+elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
+{
+ if (!_elm_cnp_init_count) _elm_cnp_init();
+#ifdef HAVE_ELEMENTARY_X
+ if (_x11_elm_widget_xwin_get(obj))
+ return _x11_elm_drag_action_set(obj, action);
+#endif
+ return _local_elm_drag_action_set(obj, action);
}
EAPI Eina_Bool
return _local_elm_selection_selection_has_owner(obj);
}
+/* 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;
+ evas_object_geometry_get(obj, &xo, &yo, NULL, NULL);
+ 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;
+ evas_object_geometry_get(obj, &xo, &yo, NULL, NULL);
+ 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)
+ {
+ free(st);
+ cont_drop_tg = eina_list_remove(cont_drop_tg, 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 */
/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/
+#ifndef _ELM_CNP_H
+#define _ELM_CNP_H
/**
* @defgroup CopyPaste CopyPaste
* @ingroup Elementary
} Elm_Sel_Format;
/**
+ * Defines the kind of action associated with the drop data if for XDND
+ * @since 1.8
+ */
+typedef enum
+{
+ ELM_XDND_ACTION_UNKNOWN, /**< Action type is unknown */
+ ELM_XDND_ACTION_COPY, /**< Copy the data */
+ ELM_XDND_ACTION_MOVE, /**< Move the data */
+ ELM_XDND_ACTION_PRIVATE, /**< Pricate action type */
+ ELM_XDND_ACTION_ASK, /**< Ask the user what to do */
+ ELM_XDND_ACTION_LIST, /**< List the data */
+ ELM_XDND_ACTION_LINK, /**< Link the data */
+ ELM_XDND_ACTION_DESCRIPTION /**< Describe the data */
+} Elm_Xdnd_Action;
+
+/**
* Structure holding the info about selected data.
*/
struct _Elm_Selection_Data
{
- Evas_Coord x, y;
- Elm_Sel_Format format;
- void *data;
- size_t len;
+ Evas_Coord x, y;
+ Elm_Sel_Format format;
+ void *data;
+ size_t len;
+ Elm_Xdnd_Action action; /**< The action to perform with the data @since 1.8 */
};
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
*/
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
+ * @param yoff A return coordinate for the Y offset at which to place the drag icon object relative to the source drag object
+ * @return An object to fill the drag window with or NULL if not needed
+ * @since 1.8
+ */
+typedef Evas_Object *(*Elm_Drag_Icon_Create_Cb) (void *data, Evas_Object *win, Evas_Coord *xoff, Evas_Coord *yoff);
+
+/**
+ * Callback called when a drag is finished, enters, or leaves an object
+ *
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @since 1.8
+ */
+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
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Accept) (void *data, Evas_Object *obj, Eina_Bool doaccept);
+
+/**
+ * Callback called when a drag is over an object, and gives object-relative coordinates
+ *
+ * @param data Application specific data
+ * @param obj The object where the drag started
+ * @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
+ * @since 1.8
+ */
+typedef void (*Elm_Drag_Pos) (void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action);
/**
* @brief Set copy data for a widget.
EAPI void elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const void *data);
/**
+ * @brief Set the given object as a target for drops for drag-and-drop
+ *
+ * @param obj The target object
+ * @param format The formats supported for dropping
+ * @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_target_add(Evas_Object *obj, Elm_Sel_Format format,
+ Elm_Drag_State entercb, void *enterdata,
+ Elm_Drag_State leavecb, void *leavedata,
+ Elm_Drag_Pos poscb, void *posdata,
+ Elm_Drop_Cb dropcb, void *cbdata);
+
+/**
+ * @brief Deletes the drop target status of an object
+ *
+ * @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_drop_target_del(Evas_Object *obj);
+
+/**
+ * @brief Begins a drag given a source object
+ *
+ * @param obj The source object
+ * @param format The drag formats supported by the data
+ * @param data The drag data itself (a string)
+ * @param action The drag action to be done
+ * @param createicon Function to call to create a drag object, or NULL if not wanted
+ * @param createdata Application data passed to @p createicon
+ * @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
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @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,
+ 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 action The drag action to be done
+ * @return Returns EINA_TRUE, if successful, or EINA_FALSE if not.
+ *
+ * @ingroup CopyPaste
+ *
+ * @since 1.8
+ */
+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);
+
+/**
* @}
*/
+#endif