Elementary: Drag & Drop feature for items containers

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.
This commit is contained in:
Daniel Zaoui 2013-03-17 08:36:30 +02:00
parent 6d980a03e7
commit ac01929f37
12 changed files with 1929 additions and 39 deletions

View 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 \

View 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;
@ -741,6 +744,11 @@ add_tests:
ADD_TEST(NULL, "System", "Notification", test_sys_notify);
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);

View File

@ -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);
}

View 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

View 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");
@ -1450,6 +1509,25 @@ _x11_dnd_status(void *data __UNUSED__, int etype __UNUSED__, void *ev)
return EINA_TRUE;
}
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)
{
@ -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 */

View File

@ -114,6 +114,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.
*
@ -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
@ -144,9 +156,19 @@ 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.
*
@ -335,6 +358,147 @@ 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);
/**
* @}
*/

View 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
};

View 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)
/**
* @}

View 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);

View 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
};

View 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
};
@ -355,6 +356,21 @@
*/
#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)
/**
* @}
*/

View 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);