forked from enlightenment/efl
835 lines
25 KiB
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;
|
|
}
|