efl/src/lib/elementary/elm_dnd.c

835 lines
25 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
int ELM_CNP_EVENT_SELECTION_CHANGED;
typedef struct {
void *enter_data, *leave_data, *pos_data, *drop_data;
Elm_Drag_State enter_cb;
Elm_Drag_State leave_cb;
Elm_Drag_Pos pos_cb;
Elm_Drop_Cb drop_cb;
Eina_Array *mime_types;
Elm_Sel_Format format;
Elm_Xdnd_Action action;
} Elm_Drop_Target;
static int
_default_seat(const Eo *obj)
{
return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EVAS_DEVICE_CLASS_SEAT));
}
static const char*
_action_to_string(Elm_Xdnd_Action action)
{
if (action == ELM_XDND_ACTION_COPY) return "copy";
if (action == ELM_XDND_ACTION_MOVE) return "move";
if (action == ELM_XDND_ACTION_PRIVATE) return "private";
if (action == ELM_XDND_ACTION_ASK) return "ask";
if (action == ELM_XDND_ACTION_LIST) return "list";
if (action == ELM_XDND_ACTION_LINK) return "link";
if (action == ELM_XDND_ACTION_DESCRIPTION) return "description";
return "unknown";
}
static Elm_Xdnd_Action
_string_to_action(const char* action)
{
if (eina_streq(action, "copy")) return ELM_XDND_ACTION_COPY;
else if (eina_streq(action, "move")) return ELM_XDND_ACTION_MOVE;
else if (eina_streq(action, "private")) return ELM_XDND_ACTION_PRIVATE;
else if (eina_streq(action, "ask")) return ELM_XDND_ACTION_ASK;
else if (eina_streq(action, "list")) return ELM_XDND_ACTION_LIST;
else if (eina_streq(action, "link")) return ELM_XDND_ACTION_LINK;
else if (eina_streq(action, "description")) return ELM_XDND_ACTION_DESCRIPTION;
return ELM_XDND_ACTION_UNKNOWN;
}
static void
_enter_cb(void *data, const Efl_Event *ev)
{
Elm_Drop_Target *target = data;
if (target->enter_cb)
target->enter_cb(target->enter_data, ev->object);
}
static void
_leave_cb(void *data, const Efl_Event *ev)
{
Elm_Drop_Target *target = data;
if (target->leave_cb)
target->leave_cb(target->leave_data, ev->object);
}
static void
_pos_cb(void *data, const Efl_Event *ev)
{
Elm_Drop_Target *target = data;
Efl_Ui_Drop_Event *event = ev->info;
if (target->pos_cb)
target->pos_cb(target->pos_data, ev->object, event->position.x, event->position.y, target->action); //FIXME action
}
static Eina_Value
_deliver_content(Eo *obj, void *data, const Eina_Value value)
{
Elm_Drop_Target *target = data;
Elm_Selection_Data sel_data;
Eina_Content *content = eina_value_to_content(&value);
sel_data.data = (void*)eina_content_data_get(content).mem;
sel_data.len = eina_content_data_get(content).len;
sel_data.action = target->action;
sel_data.format = target->format;
if (target->drop_cb)
target->drop_cb(target->drop_data, obj, &sel_data);
return EINA_VALUE_EMPTY;
}
static void
_drop_cb(void *data, const Efl_Event *ev)
{
Efl_Ui_Drop_Dropped_Event *event = ev->info;
Elm_Drop_Target *target = data;
target->action = _string_to_action(event->action);
efl_future_then(ev->object, efl_ui_dnd_drop_data_get(elm_widget_is(ev->object) ? ev->object : efl_ui_win_get(ev->object), _default_seat(ev->object), eina_array_iterator_new(target->mime_types)),
.success = _deliver_content,
.data = target
);
}
static void
_inv_cb(void *data, const Efl_Event *ev)
{
Elm_Drop_Target *target = data;
elm_drop_target_del(ev->object, target->format, target->enter_cb, target->enter_data, target->leave_cb,
target->leave_data, target->pos_cb, target->pos_data, target->drop_cb, target->drop_data);
}
EFL_CALLBACKS_ARRAY_DEFINE(drop_target_cb,
{EFL_UI_DND_EVENT_DROP_ENTERED, _enter_cb},
{EFL_UI_DND_EVENT_DROP_LEFT, _leave_cb},
{EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _pos_cb},
{EFL_UI_DND_EVENT_DROP_DROPPED, _drop_cb},
{EFL_EVENT_INVALIDATE, _inv_cb}
)
static Eina_Hash *target_register = NULL;
static Eina_Array*
_format_to_mime_array(Elm_Sel_Format format)
{
Eina_Array *ret = eina_array_new(10);
if (format & ELM_SEL_FORMAT_URILIST)
eina_array_push(ret, "text/uri-list");
if (format & ELM_SEL_FORMAT_TEXT)
{
eina_array_push(ret, "text/plain");
eina_array_push(ret, "text/plain;charset=utf-8");
if (!(format & ELM_SEL_FORMAT_URILIST))
eina_array_push(ret, "text/uri-list");
}
if (format & ELM_SEL_FORMAT_MARKUP)
eina_array_push(ret, "application/x-elementary-markup");
if (format & ELM_SEL_FORMAT_IMAGE)
{
eina_array_push(ret, "image/png");
eina_array_push(ret, "image/jpeg");
eina_array_push(ret, "image/x-ms-bmp");
eina_array_push(ret, "image/gif");
eina_array_push(ret, "image/tiff");
eina_array_push(ret, "image/svg+xml");
eina_array_push(ret, "image/x-xpixmap");
eina_array_push(ret, "image/x-tga");
eina_array_push(ret, "image/x-portable-pixmap");
}
if (format & ELM_SEL_FORMAT_VCARD)
eina_array_push(ret, "text/vcard");
if (format & ELM_SEL_FORMAT_HTML)
eina_array_push(ret, "text/html");
return ret;
}
EAPI Eina_Bool
elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_State enter_cb, void *enter_data,
Elm_Drag_State leave_cb, void *leave_data,
Elm_Drag_Pos pos_cb, void *pos_data,
Elm_Drop_Cb drop_cb, void *drop_data)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
Elm_Drop_Target *target = calloc(1, sizeof(Elm_Drop_Target));
target->enter_cb = enter_cb;
target->enter_data = enter_data;
target->leave_cb = leave_cb;
target->leave_data = leave_data;
target->pos_cb = pos_cb;
target->pos_data = pos_data;
target->drop_cb = drop_cb;
target->drop_data = drop_data;
target->mime_types = _format_to_mime_array(format);
target->format = format;
efl_event_callback_array_add(obj, drop_target_cb(), target);
if (!efl_isa(obj, EFL_UI_WIDGET_CLASS))
_drop_event_register(obj); //this is ensuring that we are also supporting none widgets
if (!target_register)
target_register = eina_hash_pointer_new(NULL);
eina_hash_list_append(target_register, &obj, target);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_drop_target_del(Evas_Object *obj, Elm_Sel_Format format,
Elm_Drag_State enter_cb, void *enter_data,
Elm_Drag_State leave_cb, void *leave_data,
Elm_Drag_Pos pos_cb, void *pos_data,
Elm_Drop_Cb drop_cb, void *drop_data)
{
Elm_Drop_Target *target;
Eina_List *n, *found = NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
if (!target_register)
return EINA_TRUE;
Eina_List *targets = eina_hash_find(target_register, &obj);
if (!targets)
return EINA_TRUE;
EINA_LIST_FOREACH(targets, n, target)
{
if (target->enter_cb == enter_cb && target->enter_data == enter_data &&
target->leave_cb == leave_cb && target->leave_data == leave_data &&
target->pos_cb == pos_cb && target->pos_data == pos_data &&
target->drop_cb == drop_cb && target->drop_data == drop_data &&
target->format == format)
{
found = n;
break;
}
}
if (found)
{
efl_event_callback_array_del(obj, drop_target_cb(), eina_list_data_get(found));
eina_hash_list_remove(target_register, &obj, target);
eina_array_free(target->mime_types);
_drop_event_unregister(obj); //this is ensuring that we are also supporting none widgets
free(target);
}
return EINA_TRUE;
}
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;
struct _Anim_Icon
{
int start_x;
int start_y;
int start_w;
int start_h;
Evas_Object *o;
};
typedef struct _Anim_Icon Anim_Icon;
static Eina_List *cont_drag_tg = NULL; /* List of Item_Container_Drag_Info */
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 EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info);
static void
_cont_drag_done_cb(void *data, Evas_Object *obj EINA_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, NULL, EINA_FALSE); /*FIXME*/
}
static Eina_Bool
_cont_obj_drag_start(void *data)
{ /* Start a drag-action when timer expires */
Item_Container_Drag_Info *st = data;
st->tm = NULL;
Elm_Drag_User_Info *info = &st->user_info;
if (info->dragstart) info->dragstart(info->startcbdata, st->obj);
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);
ELM_SAFE_FREE(info->data, free);
return ECORE_CALLBACK_CANCEL;
}
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));
if (!st)
{
ERR("Failed to allocate memory for icon!");
continue;
}
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 */
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 */
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_DND);
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 */
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 (EINA_DBL_NONZERO(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 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));
}
void
_anim_st_free(Item_Container_Drag_Info *st)
{ /* Stops and free mem of ongoing animation */
if (st)
{
ELM_SAFE_FREE(st->ea, ecore_animator_del);
Anim_Icon *sti;
EINA_LIST_FREE(st->icons, sti)
{
evas_object_del(sti->o);
free(sti);
}
st->icons = NULL;
}
}
static void
_cont_obj_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{ /* Cancel any drag waiting to start on timeout */
Item_Container_Drag_Info *st = data;
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);
ELM_SAFE_FREE(st->tm, ecore_timer_del);
_anim_st_free(st);
}
static void
_cont_obj_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_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)
{
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);
ELM_SAFE_FREE(st->tm, ecore_timer_del);
_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)
{
ELM_SAFE_FREE(st->tm, ecore_timer_del); /* Cancel drag-start timer */
if (st->ea) /* Cancel ongoing default animation */
_anim_st_free(st);
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);
cont_drag_tg = eina_list_remove(cont_drag_tg, st);
ELM_SAFE_FREE(st->user_info.data, free);
free(st);
}
return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_cont_obj_mouse_down(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info)
{ /* Launch a timer to start dragging */
Evas_Event_Mouse_Down *ev = event_info;
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);
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);
}
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);
if (!st) return EINA_FALSE;
}
else
{
st = calloc(1, sizeof(*st));
if (!st) return EINA_FALSE;
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;
}
static Eina_List *cont_drop_tg = NULL; /* List of Item_Container_Drop_Info */
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;
typedef struct
{
Evas_Object *obj;
/* FIXME: Cache window */
Eina_Inlist *cbs_list; /* List of Dropable_Cbs * */
struct {
Evas_Coord x, y;
Eina_Bool in : 1;
const char *type;
Elm_Sel_Format format;
} last;
} Dropable;
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)
{
// temp until st is stored inside data of obj.
//FIXME delete this drop container
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_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 *dropdata)
{
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);
if (!st) return EINA_FALSE;
}
else
{
st = calloc(1, sizeof(*st));
if (!st) return EINA_FALSE;
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, dropdata);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_drop_item_container_del(Evas_Object *obj)
{
return elm_drop_item_container_del_internal(obj, EINA_TRUE);
}
typedef struct {
void *dragdata, *acceptdata, *donecbdata;
Elm_Drag_Pos dragposcb;
Elm_Drag_Accept acceptcb;
Elm_Drag_State dragdonecb;
} Elm_Drag_Data;
static void
_drag_finished_cb(void *data, const Efl_Event *ev)
{
Elm_Drag_Data *dd = data;
Eina_Bool *accepted = ev->info;
if (dd->acceptcb)
dd->acceptcb(dd->acceptdata, ev->object, *accepted);
if (dd->dragdonecb)
dd->dragdonecb(dd->donecbdata, ev->object);
efl_event_callback_del(ev->object, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd);
free(dd);
}
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)
{
Eina_Array *mime_types;
Eina_Content *content;
Efl_Content *ui;
int x = 0, y = 0, w, h;
Efl_Ui_Widget *widget;
Elm_Drag_Data *dd;
const char *str_action;
Eina_Position2D pointer;
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
//it should return EINA_TRUE to keep backward compatibility
if (!data)
return EINA_TRUE;
str_action = _action_to_string(action);
dd = calloc(1, sizeof(Elm_Drag_Data));
dd->dragposcb = dragpos;
dd->dragdata = dragdata;
dd->acceptcb = acceptcb;
dd->acceptdata = acceptdata;
dd->dragdonecb = dragdone;
dd->donecbdata = donecbdata;
mime_types = _format_to_mime_array(format);
if (eina_array_count(mime_types) != 1)
{
WRN("You passed more than one format, this is not going to work well");
}
content = eina_content_new((Eina_Slice) EINA_SLICE_STR_FULL(data), eina_array_data_get(mime_types, 0));
ui = efl_ui_dnd_drag_start(obj, content, str_action, _default_seat(obj));
widget = createicon(createdata, ui, &x, &y);
evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &pointer.x, &pointer.y);
efl_ui_dnd_drag_offset_set(obj, _default_seat(obj), EINA_SIZE2D(x - pointer.x, y - pointer.y));
evas_object_geometry_get(widget, NULL, NULL, &w, &h);
evas_object_show(widget);
efl_content_set(ui, widget);
efl_gfx_entity_size_set(ui, EINA_SIZE2D(w, h));
eina_array_free(mime_types);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_FINISHED, _drag_finished_cb, dd);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_drag_cancel(Evas_Object *obj)
{
efl_ui_dnd_drag_cancel(obj, _default_seat(obj));
return EINA_TRUE;
}
EAPI Eina_Bool
elm_drag_action_set(Evas_Object *obj EINA_UNUSED, Elm_Xdnd_Action action EINA_UNUSED)
{
ERR("This operation is not supported anymore.");
return EINA_FALSE;
}