rewrite efl cnp and dnd handling

the previous commits introduced a abstraction for drag in drop which can
be now used for this here. With this commit all the direct protocol
handling in efl.ui is removed, and only the ecore evas API is used.

Additionally, this lead to a giant refactor of how APIs do work. All
Efl.Ui. interfaces have been removed except Efl.Ui.Selection and
Efl.Ui.Dnd, these two have been restructored.
A small list of what is new:
- In general no function pointers are used anymore. They feel very
  uncompftable in bindings and in C. For us its a lot easier to just
listen to a event when a drop enters or leaves, there is no need to
register custom functions for that.
- Asynchronous data transphere is handled via futures, which proved to
  be more error safe.
- Formats and actions are handled as mime types / strings.
- 0 is the default seat if you do not know what else to take.
- Content is in general passes as a content container from eina, this
  also allows applications to pass custom types

The legacy dnd and cnp API is implemented based on that.
All cnp related things are in elm_cnp.c the dnd parts are in elm_dnd.c

Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Differential Revision: https://phab.enlightenment.org/D11190
This commit is contained in:
Marcel Hollerbach 2020-01-19 13:58:26 +01:00
parent 5ac02ec9ac
commit 165f6f0ae2
24 changed files with 1782 additions and 7345 deletions

View File

@ -119,8 +119,6 @@ extern EAPI Eina_Error EFL_UI_THEME_APPLY_ERROR_NONE;
// EO types. Defined for legacy-only builds as legacy uses typedef of EO types.
#include "efl_ui.eot.h"
#include "efl_ui_selection_types.eot.h"
#include "efl_ui_dnd_types.eot.h"
//define focus manager earlier since focus object and manager is circular
typedef Eo Efl_Ui_Focus_Manager;
@ -322,7 +320,6 @@ typedef Eo Efl_Ui_Spotlight_Indicator;
# include <efl_ui_widget_focus_manager.eo.h>
# include <efl_ui_selection.eo.h>
# include <efl_ui_dnd.eo.h>
# include <efl_ui_dnd_container.eo.h>
# include <efl_ui_timepicker.eo.h>
# include <efl_ui_datepicker.eo.h>

View File

@ -12,838 +12,140 @@
#include <Elementary_Cursor.h>
#include "elm_priv.h"
typedef struct _Efl_Ui_Dnd_Container_Data Efl_Ui_Dnd_Container_Data;
struct _Efl_Ui_Dnd_Container_Data
{
unsigned int drag_delay_time;
};
typedef struct {
Ecore_Evas *ee;
Eina_Bool registered;
} Efl_Ui_Dnd_Data;
extern int _wl_default_seat_id_get(Evas_Object *obj);
#ifdef HAVE_ELEMENTARY_WL2
Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj);
#endif
Eo*
_efl_ui_selection_manager_get(Eo *obj)
{
if (!efl_isa(obj, EFL_UI_WIDGET_CLASS)) return NULL;
Eo *app = efl_app_main_get();
Eo *sel_man = efl_key_data_get(app, "__selection_manager");
if (!sel_man)
{
sel_man = efl_add(EFL_UI_SELECTION_MANAGER_CLASS, app);
efl_key_data_set(app, "__selection_manager", sel_man);
}
return sel_man;
}
void
_efl_ui_dnd_shutdown(void)
{
Eo *app = efl_app_main_get();
Eo *sel_man = efl_key_data_get(app, "__selection_manager");
efl_del(sel_man);
}
EOLIAN static void
_efl_ui_dnd_drag_start(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, Eina_Slice data,
Efl_Ui_Selection_Action action, void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb,
unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_drag_start(sel_man, obj, format, data, action,
icon_func_data, icon_func, icon_func_free_cb,
seat);
}
EOLIAN static void
_efl_ui_dnd_drag_cancel(Eo *obj, void *pd EINA_UNUSED, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_drag_cancel(sel_man, obj, seat);
}
EOLIAN static void
_efl_ui_dnd_drag_action_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Action action, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_drag_action_set(sel_man, obj, action, seat);
}
EOLIAN static void
_efl_ui_dnd_drop_target_add(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_drop_target_add(sel_man, obj, format, seat);
}
EOLIAN static void
_efl_ui_dnd_drop_target_del(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Format format, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_drop_target_del(sel_man, obj, format, seat);
}
EOLIAN static double
_efl_ui_dnd_container_drag_delay_time_get(const Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd)
{
return pd->drag_delay_time;
}
EOLIAN static void
_efl_ui_dnd_container_drag_delay_time_set(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Container_Data *pd, double drag_delay_time)
{
pd->drag_delay_time = drag_delay_time;
}
EOLIAN static void
_efl_ui_dnd_container_drag_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd,
void *data_func_data, Efl_Dnd_Drag_Data_Get data_func, Eina_Free_Cb data_func_free_cb,
void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb,
void *icon_func_data, Efl_Dnd_Drag_Icon_Create icon_func, Eina_Free_Cb icon_func_free_cb,
void *icon_list_func_data, Efl_Dnd_Drag_Icon_List_Create icon_list_func, Eina_Free_Cb icon_list_func_free_cb,
unsigned int seat)
{
double drag_delay_time = pd->drag_delay_time;
double anim_time = elm_config_drag_anim_duration_get();
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_container_drag_item_add(sel_man, obj, drag_delay_time, anim_time,
data_func_data, data_func, data_func_free_cb,
item_func_data, item_func, item_func_free_cb,
icon_func_data, icon_func, icon_func_free_cb,
icon_list_func_data, icon_list_func, icon_list_func_free_cb,
seat);
}
typedef struct {
Eo *win;
Efl_Ui_Dnd *obj;
} Efl_Ui_Drag_Start;
static void
_efl_ui_dnd_container_drag_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat)
_ecore_evas_drag_terminated(Ecore_Evas *ee EINA_UNUSED, unsigned int seat, void *data, Eina_Bool accepted)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seat);
Efl_Ui_Drag_Start *start = data;
Efl_Ui_Drag_Finished_Event ev = {seat, accepted};
efl_event_callback_call(start->obj, EFL_UI_DND_EVENT_DRAG_FINISHED, &ev);
efl_del(start->win);
free(start);
}
EOLIAN static void
_efl_ui_dnd_container_drop_item_add(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED,
Efl_Ui_Selection_Format format,
void *item_func_data, Efl_Dnd_Item_Get item_func, Eina_Free_Cb item_func_free_cb,
unsigned int seat)
EOLIAN static Efl_Content*
_efl_ui_dnd_drag_start(Eo *obj, Efl_Ui_Dnd_Data *pd, Eina_Content *content, const char* action, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_container_drop_item_add(sel_man, obj, format, item_func_data, item_func, item_func_free_cb, seat);
Eo *drag_win;
Efl_Ui_Drag_Start *start;
Efl_Ui_Drag_Started_Event ev = {seat};
Ecore_Evas *drag_ee;
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->ee, NULL);
start = calloc(1, sizeof(Efl_Ui_Drag_Start));
start->obj = obj;
start->win = drag_win = elm_win_add(NULL, "Elm-Drag", ELM_WIN_DND);
elm_win_alpha_set(drag_win, EINA_TRUE);
elm_win_override_set(drag_win, EINA_TRUE);
elm_win_borderless_set(drag_win, EINA_TRUE);
drag_ee = ecore_evas_ecore_evas_get(evas_object_evas_get(drag_win));
ecore_evas_drag_start(pd->ee, seat, content, drag_ee, action, _ecore_evas_drag_terminated, start);
evas_object_show(drag_win);
efl_event_callback_call(obj, EFL_UI_DND_EVENT_DRAG_STARTED, &ev);
return drag_win;
}
EOLIAN static void
_efl_ui_dnd_container_drop_item_del(Eo *obj, Efl_Ui_Dnd_Container_Data *pd EINA_UNUSED, unsigned int seat)
_efl_ui_dnd_drag_cancel(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seat);
ecore_evas_drag_cancel(pd->ee, seat);
}
///////////
typedef struct _Dnd_Icon_Create Dnd_Icon_Create;
typedef struct _Dnd_Drag_Pos Dnd_Drag_Pos;
typedef struct _Dnd_Drag_Accept Dnd_Drag_Accept;
typedef struct _Dnd_Drag_Done Dnd_Drag_Done;
typedef struct _Dnd_Drag_State Dnd_Drag_State;
typedef struct _Dnd_Drop Dnd_Drop;
typedef struct _Dnd_Cont_Drag_Pos Dnd_Cont_Drag_Pos;
typedef struct _Dnd_Cont_Drop Dnd_Cont_Drop;
typedef struct _Item_Container_Drag_Info Item_Container_Drag_Info;
struct _Dnd_Icon_Create
EOLIAN static Eina_Future*
_efl_ui_dnd_drop_data_get(Eo *obj EINA_UNUSED, Efl_Ui_Dnd_Data *pd, unsigned int seat, Eina_Iterator *acceptable_types)
{
void *icon_data;
Elm_Drag_Icon_Create_Cb icon_cb;
};
struct _Dnd_Drag_Pos
{
void *pos_data;
Elm_Drag_Pos pos_cb;
};
struct _Dnd_Drag_Accept
{
void *accept_data;
Elm_Drag_Accept accept_cb;
};
struct _Dnd_Drag_Done
{
void *done_data;
Elm_Drag_State done_cb;
//for deleting
Dnd_Drag_Pos *pos;
Dnd_Drag_Accept *accept;
};
struct _Dnd_Drag_State
{
void *state_data;
Elm_Drag_State state_cb;
};
struct _Dnd_Drop
{
Efl_Object *obj;
Elm_Sel_Format format;
void *drop_data;
Elm_Drop_Cb drop_cb;
//for deleting
Dnd_Drag_State *enter;
Dnd_Drag_State *leave;
Dnd_Drag_Pos *pos;
};
struct _Dnd_Cont_Drag_Pos
{
void *pos_data;
Elm_Drag_Item_Container_Pos pos_cb;
Elm_Xy_Item_Get_Cb item_get_cb;
};
struct _Dnd_Cont_Drop
{
Efl_Object *obj;
Elm_Sel_Format format;
void *drop_data;
Elm_Drop_Item_Container_Cb drop_cb;
Elm_Xy_Item_Get_Cb item_get_cb;
//for deleting
Dnd_Drag_State *enter;
Dnd_Drag_State *leave;
Dnd_Cont_Drag_Pos *pos;
};
struct _Item_Container_Drag_Info
{
Elm_Drag_User_Info user_info;
Elm_Object_Item *it;
Elm_Item_Container_Data_Get_Cb data_get_cb;
Elm_Xy_Item_Get_Cb item_get_cb;
};
static Efl_Object *
_dnd_icon_create_cb(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret)
{
Dnd_Icon_Create *ic = data;
Efl_Object *ret = ic->icon_cb(ic->icon_data, win, &pos_ret->x, &pos_ret->y);
free(ic);
return ret;
return ecore_evas_selection_get(pd->ee, seat, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, acceptable_types);
}
static void
_dnd_drag_pos_cb(void *data, const Efl_Event *event)
EOLIAN static Efl_Object *
_efl_ui_dnd_efl_object_constructor(Eo *obj, Efl_Ui_Dnd_Data *pd)
{
Dnd_Drag_Pos *pos = data;
Efl_Dnd_Drag_Pos *ddata = event->info;
if (!efl_constructor(efl_super(obj, EFL_UI_DND_MIXIN)))
return NULL;
if (pos->pos_cb)
pos->pos_cb(pos->pos_data, event->object, ddata->pos.x, ddata->pos.y,
(Elm_Xdnd_Action)ddata->action);
}
static void
_dnd_drag_accept_cb(void *data, const Efl_Event *event)
{
Dnd_Drag_Accept *accept = data;
if (accept->accept_cb)
accept->accept_cb(accept->accept_data, event->object, *(Eina_Bool *)event->info);
}
static void
_dnd_drag_done_cb(void *data, const Efl_Event *event)
{
Dnd_Drag_Done *done = data;
if (done->done_cb)
done->done_cb(done->done_data, event->object);
efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_POS,
_dnd_drag_pos_cb, done->pos);
efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_ACCEPT,
_dnd_drag_accept_cb, done->accept);
efl_event_callback_del(event->object, EFL_UI_DND_EVENT_DRAG_DONE,
_dnd_drag_done_cb, done);
free(done->pos);
free(done->accept);
free(done);
}
static void
_dnd_drag_enter_leave_cb(void *data, const Efl_Event *event)
{
Dnd_Drag_State *state = data;
if (state->state_cb)
state->state_cb(state->state_data, event->object);
}
static void
_dnd_drop_cb(void *data, const Efl_Event *event)
{
Dnd_Drop *drop = data;
Efl_Ui_Selection_Data *org_ddata = event->info;
Elm_Selection_Data ddata;
ddata.x = org_ddata->pos.x;
ddata.y = org_ddata->pos.y;
ddata.format = (Elm_Sel_Format)org_ddata->format;
ddata.action = (Elm_Xdnd_Action)org_ddata->action;
ddata.data = calloc(1, org_ddata->content.len);
if (!ddata.data) return;
ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len);
ddata.len = org_ddata->content.len;
if (drop->drop_cb)
drop->drop_cb(drop->drop_data, event->object, &ddata);
free(ddata.data);
}
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 icon_create_cb, void *icon_create_data,
Elm_Drag_Pos drag_pos_cb, void *drag_pos_data,
Elm_Drag_Accept drag_accept_cb, void *drag_accept_data,
Elm_Drag_State drag_done_cb, void *drag_done_data)
{
if (!data) return EINA_FALSE;
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
Eina_Slice sl;
Dnd_Drag_Pos *pos = calloc(1, sizeof(Dnd_Drag_Pos));
Dnd_Drag_Accept *accept = calloc(1, sizeof(Dnd_Drag_Accept));
Dnd_Drag_Done *done = calloc(1, sizeof(Dnd_Drag_Done));
Dnd_Icon_Create *ic = calloc(1, sizeof(Dnd_Icon_Create));
if (!pos || !accept || !done || !ic) goto on_error;
pos->pos_data = drag_pos_data;
pos->pos_cb = drag_pos_cb;
accept->accept_data = drag_accept_data;
accept->accept_cb = drag_accept_cb;
done->done_data = drag_done_data;
done->done_cb = drag_done_cb;
done->pos = pos;
done->accept = accept;
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS, _dnd_drag_pos_cb, pos);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ACCEPT, _dnd_drag_accept_cb, accept);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DONE, _dnd_drag_done_cb, done);
sl.mem = data;
sl.len = strlen(data);
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
ic->icon_data = icon_create_data;
ic->icon_cb = icon_create_cb;
efl_ui_selection_manager_drag_start(sel_man, obj, (Efl_Ui_Selection_Format)format, sl,
(Efl_Ui_Selection_Action)action,
ic, _dnd_icon_create_cb, NULL, seatid);
return EINA_TRUE;
on_error:
if (pos) free(pos);
if (accept) free(accept);
if (done) free(done);
if (ic) free(ic);
return EINA_FALSE;
}
EAPI Eina_Bool
elm_drag_action_set(Evas_Object *obj, Elm_Xdnd_Action action)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
efl_ui_selection_manager_drag_action_set(sel_man, obj, (Efl_Ui_Selection_Action)action, seatid);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_drag_cancel(Evas_Object *obj)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
efl_ui_selection_manager_drag_cancel(sel_man, obj, seatid);
return EINA_TRUE;
}
static void
_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Eina_List *drop_list;
Dnd_Drop *drop;
drop_list = efl_key_data_get(obj, "__drop_list");
EINA_LIST_FREE(drop_list, drop)
{
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER,
_dnd_drag_enter_leave_cb, drop->enter);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
_dnd_drag_enter_leave_cb, drop->leave);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS,
_dnd_drag_pos_cb, drop->pos);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP,
_dnd_drop_cb, drop);
free(drop->enter);
free(drop->leave);
free(drop->pos);
free(drop);
}
efl_key_data_set(obj, "__drop_list", NULL);
}
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)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
Dnd_Drag_State *enter, *leave;
Dnd_Drag_Pos *pos;
Dnd_Drop *drop;
Eina_List *drop_list;
enter = calloc(1, sizeof(Dnd_Drag_State));
leave = calloc(1, sizeof(Dnd_Drag_State));
pos = calloc(1, sizeof(Dnd_Drag_Pos));
drop = calloc(1, sizeof(Dnd_Drop));
if (!enter || !leave || !pos || !drop) goto on_error;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
enter->state_cb = enter_cb;
enter->state_data = enter_data;
leave->state_cb = leave_cb;
leave->state_data = leave_data;
pos->pos_cb = pos_cb;
pos->pos_data = pos_data;
drop->obj = obj;
drop->format = format;
drop->drop_cb = drop_cb;
drop->drop_data = drop_data;
drop->enter = enter;
drop->leave = leave;
drop->pos = pos;
drop_list = efl_key_data_get(obj, "__drop_list");
drop_list = eina_list_append(drop_list, drop);
efl_key_data_set(obj, "__drop_list", drop_list);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
_drop_obj_del_cb, NULL);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER,
_dnd_drag_enter_leave_cb, enter);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
_dnd_drag_enter_leave_cb, leave);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS,
_dnd_drag_pos_cb, pos);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP,
_dnd_drop_cb, drop);
efl_ui_selection_manager_drop_target_add(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid);
return EINA_TRUE;
on_error:
if (enter) free(enter);
if (leave) free(leave);
if (pos) free(pos);
if (drop) free(drop);
return EINA_FALSE;
}
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)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
//Eina_List *l, *l2;
Eina_List *drop_list;
Dnd_Drop *drop;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
drop_list = efl_key_data_get(obj, "__drop_list");
drop = eina_list_data_get(drop_list);
if (drop &&
(drop->format == format) &&
(drop->enter->state_cb == enter_cb) &&
(drop->enter->state_data == enter_data) &&
(drop->leave->state_cb == leave_cb) &&
(drop->leave->state_data == leave_data) &&
(drop->pos->pos_cb == pos_cb) &&
(drop->pos->pos_data == pos_data) &&
(drop->drop_cb == drop_cb) &&
(drop->drop_data == drop_data))
{
drop_list = eina_list_remove(drop_list, drop);
efl_key_data_set(obj, "__drop_list", drop_list);
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _drop_obj_del_cb);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER,
_dnd_drag_enter_leave_cb, drop->enter);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
_dnd_drag_enter_leave_cb, drop->leave);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS,
_dnd_drag_pos_cb, drop->pos);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP,
_dnd_drop_cb, drop);
free(drop->enter);
free(drop->leave);
free(drop->pos);
free(drop);
}
efl_ui_selection_manager_drop_target_del(sel_man, obj, (Efl_Ui_Selection_Format)format, seatid);
return EINA_TRUE;
}
static Efl_Object *
_dnd_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret)
{
Elm_Xy_Item_Get_Cb item_get_cb = data;
Evas_Coord x, y;
Efl_Object *obj = NULL;
x = y = 0;
if (item_get_cb)
obj = item_get_cb(item, pos.x, pos.y, &x, &y);
if (pos_ret)
{
pos_ret->x = x;
pos_ret->y = y;
}
pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
return obj;
}
static void
_dnd_cont_drag_pos_cb(void *data, const Efl_Event *event)
EOLIAN static void
_efl_ui_dnd_efl_object_invalidate(Eo *obj, Efl_Ui_Dnd_Data *pd)
{
Dnd_Cont_Drag_Pos *pos = data;
Efl_Dnd_Drag_Pos *ddata = event->info;
Evas_Coord xret = 0, yret = 0;
if (pos->item_get_cb)
if (pd->registered)
{
Evas_Coord x, y;
evas_object_geometry_get(event->object, &x, &y, NULL, NULL);
pos->item_get_cb(event->object, ddata->pos.x + x, ddata->pos.y + y,
&xret, &yret);
_drop_event_unregister(obj);
}
if (pos->pos_cb)
pos->pos_cb(pos->pos_data, event->object, ddata->item, ddata->pos.x, ddata->pos.y,
xret, yret, (Elm_Xdnd_Action)ddata->action);
efl_invalidate(efl_super(obj, EFL_UI_DND_MIXIN));
}
static void
_dnd_cont_drop_cb(void *data, const Efl_Event *event)
#define IS_DROP_EVENT(D) ( \
(D == EFL_UI_DND_EVENT_DROP_POSITION_CHANGED) || \
(D == EFL_UI_DND_EVENT_DROP_DROPPED) || \
(D == EFL_UI_DND_EVENT_DROP_LEFT) || \
(D == EFL_UI_DND_EVENT_DROP_ENTERED) \
)
EOLIAN static Efl_Object*
_efl_ui_dnd_efl_object_finalize(Eo *obj, Efl_Ui_Dnd_Data *pd)
{
Dnd_Cont_Drop *drop = data;
Efl_Ui_Selection_Data *org_ddata = event->info;
Elm_Selection_Data ddata;
Evas_Coord xret = 0, yret = 0;
if (pd->registered)
_drop_event_register(obj);
ddata.x = org_ddata->pos.x;
ddata.y = org_ddata->pos.y;
ddata.format = (Elm_Sel_Format)org_ddata->format;
ddata.action = (Elm_Xdnd_Action)org_ddata->action;
ddata.data = calloc(1, org_ddata->content.len);
if (!ddata.data) return;
ddata.data = memcpy(ddata.data, org_ddata->content.mem, org_ddata->content.len);
ddata.len = org_ddata->content.len;
return efl_finalize(efl_super(obj, EFL_UI_DND_MIXIN));
}
if (drop->item_get_cb)
EOLIAN static Eina_Bool
_efl_ui_dnd_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd,
const Efl_Event_Description *desc,
Efl_Callback_Priority priority,
Efl_Event_Cb func,
const void *user_data)
{
if (IS_DROP_EVENT(desc) && !pd->registered)
{
pd->registered = EINA_TRUE;
if (efl_finalized_get(obj))
_drop_event_register(obj);
}
return efl_event_callback_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), desc, priority, func, user_data);
}
EOLIAN static Eina_Bool
_efl_ui_dnd_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Dnd_Data *pd,
const Efl_Callback_Array_Item *array,
Efl_Callback_Priority priority,
const void *user_data)
{
for (int i = 0; array[i].desc; ++i)
{
Evas_Coord x, y;
evas_object_geometry_get(event->object, &x, &y, NULL, NULL);
drop->item_get_cb(event->object, ddata.x + x, ddata.y + y,
&xret, &yret);
}
if (drop->drop_cb)
drop->drop_cb(drop->drop_data, event->object, org_ddata->item,
&ddata, xret, yret);
free(ddata.data);
}
static void
_cont_drop_free_data(Evas_Object *obj)
{
Eina_List *cont_drop_list;
Dnd_Cont_Drop *drop;
cont_drop_list = efl_key_data_get(obj, "__cont_drop_item");
drop = eina_list_data_get(cont_drop_list);
if (drop)
{
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_ENTER,
_dnd_drag_enter_leave_cb, drop->enter);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
_dnd_drag_enter_leave_cb, drop->leave);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_POS,
_dnd_cont_drag_pos_cb, drop->pos);
efl_event_callback_del(drop->obj, EFL_UI_DND_EVENT_DRAG_DROP,
_dnd_cont_drop_cb, drop);
free(drop->enter);
free(drop->leave);
free(drop->pos);
cont_drop_list = eina_list_remove(cont_drop_list, drop);
efl_key_data_set(obj, "__cont_drop_item", cont_drop_list);
free(drop);
}
}
static void
_cont_drop_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
{
_cont_drop_free_data(obj);
}
EAPI Eina_Bool
elm_drop_item_container_add(Evas_Object *obj,
Elm_Sel_Format format,
Elm_Xy_Item_Get_Cb item_get_cb,
Elm_Drag_State enter_cb, void *enter_data,
Elm_Drag_State leave_cb, void *leave_data,
Elm_Drag_Item_Container_Pos pos_cb, void *pos_data,
Elm_Drop_Item_Container_Cb drop_cb, void *drop_data)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
Dnd_Drag_State *enter = NULL, *leave = NULL;
Dnd_Cont_Drag_Pos *pos = NULL;
Dnd_Cont_Drop *drop = NULL;
Eina_List *cont_drop_list;
enter = calloc(1, sizeof(Dnd_Drag_State));
leave = calloc(1, sizeof(Dnd_Drag_State));
pos = calloc(1, sizeof(Dnd_Cont_Drag_Pos));
drop = calloc(1, sizeof(Dnd_Cont_Drop));
if (!enter || !leave || !pos || !drop) goto on_error;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
enter->state_cb = enter_cb;
enter->state_data = enter_data;
leave->state_cb = leave_cb;
leave->state_data = leave_data;
pos->pos_cb = pos_cb;
pos->pos_data = pos_data;
pos->item_get_cb = item_get_cb;
drop->obj = obj;
drop->format = format;
drop->drop_cb = drop_cb;
drop->drop_data = drop_data;
drop->enter = enter;
drop->leave = leave;
drop->pos = pos;
cont_drop_list = efl_key_data_get(obj, "__cont_drop_item");
cont_drop_list = eina_list_append(cont_drop_list, drop);
efl_key_data_set(obj, "__cont_drop_item", cont_drop_list);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
_cont_drop_obj_del_cb, NULL);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_ENTER,
_dnd_drag_enter_leave_cb, enter);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_LEAVE,
_dnd_drag_enter_leave_cb, leave);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_POS,
_dnd_cont_drag_pos_cb, pos);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DRAG_DROP,
_dnd_cont_drop_cb, drop);
efl_ui_selection_manager_container_drop_item_add(sel_man, obj, (Efl_Ui_Selection_Format)format,
item_get_cb, _dnd_item_func, NULL,
seatid);
return EINA_TRUE;
on_error:
if (enter) free(enter);
if (leave) free(leave);
if (pos) free(pos);
if (drop) free(drop);
return EINA_FALSE;
}
EAPI Eina_Bool
elm_drop_item_container_del(Evas_Object *obj)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
_cont_drop_free_data(obj);
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drop_obj_del_cb);
efl_ui_selection_manager_container_drop_item_del(sel_man, obj, seatid);
return EINA_TRUE;
}
static void
_cont_drag_data_func(void *data, Efl_Object *obj, Efl_Ui_Selection_Format *format,
Eina_Rw_Slice *drag_data, Efl_Ui_Selection_Action *action)
{
Item_Container_Drag_Info *di;
di = data;
if (!di) return;
di->data_get_cb(obj, di->it, &di->user_info);
if (format) *format = (Efl_Ui_Selection_Format)di->user_info.format;
if (drag_data)
{
if (di->user_info.data)
if (IS_DROP_EVENT(array[i].desc) && !pd->registered)
{
drag_data->mem = (void *)di->user_info.data;
drag_data->len = strlen(di->user_info.data);
pd->registered = EINA_TRUE;
if (efl_finalized_get(obj))
_drop_event_register(obj);
}
}
if (action) *action = (Efl_Ui_Selection_Action)di->user_info.action;
return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_DND_MIXIN), array, priority, user_data);
}
static Eina_List *
_cont_drag_icon_list_create(void *data, Efl_Object *obj EINA_UNUSED)
{
Item_Container_Drag_Info *di;
di = data;
return di->user_info.icons;
}
static Efl_Object *
_cont_drag_icon_create(void *data, Efl_Object *win, Efl_Object *drag_obj EINA_UNUSED, Eina_Position2D *pos_ret)
{
Item_Container_Drag_Info *di;
Elm_Object_Item *it = NULL;
di = data;
if (!di) return NULL;
if (!di->user_info.createicon) return NULL;
it = di->user_info.createicon(di->user_info.createdata, win, &pos_ret->x, &pos_ret->y);
di->it = it;
return it;
}
static Efl_Object *
_cont_drag_item_func(void *data, Efl_Canvas_Object *item, Eina_Position2D pos, Eina_Position2D *pos_ret)
{
Item_Container_Drag_Info *di = data;
Evas_Coord x, y;
Efl_Object *obj = NULL;
x = y = 0;
if (di->item_get_cb)
obj = di->item_get_cb(item, pos.x, pos.y, &x, &y);
if (pos_ret)
{
pos_ret->x = x;
pos_ret->y = y;
}
di->it = obj;
return obj;
}
static void
_cont_drag_free_data(Evas_Object *obj)
{
Eina_List *di_list;
Item_Container_Drag_Info *di;
di_list = efl_key_data_get(obj, "__cont_drag_item");
di = eina_list_data_get(di_list);
di_list = eina_list_remove(di_list, di);
efl_key_data_set(obj, "__cont_drag_item", di_list);
free(di);
}
static void
_cont_drag_obj_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
{
_cont_drag_free_data(obj);
}
EAPI Eina_Bool
elm_drag_item_container_add(Evas_Object *obj, double anim_tm, double tm_to_drag,
Elm_Xy_Item_Get_Cb item_get_cb, Elm_Item_Container_Data_Get_Cb data_get_cb)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
Eina_List *di_list;
Item_Container_Drag_Info *di;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
di = calloc(1, sizeof(Item_Container_Drag_Info));
if (!di) return EINA_FALSE;
di->data_get_cb = data_get_cb;
di->item_get_cb = item_get_cb;
di_list = efl_key_data_get(obj, "__cont_drag_item");
di_list = eina_list_append(di_list, di);
efl_key_data_set(obj, "__cont_drag_item", di_list);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb, NULL);
efl_ui_selection_manager_container_drag_item_add(sel_man, obj, tm_to_drag, anim_tm,
di, _cont_drag_data_func, NULL,
di, _cont_drag_item_func, NULL,
di, _cont_drag_icon_create, NULL,
di, _cont_drag_icon_list_create, NULL,
seatid);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_drag_item_container_del(Evas_Object *obj)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
int seatid = 1;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
_cont_drag_free_data(obj);
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _cont_drag_obj_del_cb);
efl_ui_selection_manager_container_drag_item_del(sel_man, obj, seatid);
return EINA_TRUE;
}
#define EFL_UI_DND_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_dnd_efl_object_event_callback_priority_add), \
EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_dnd_efl_object_event_callback_array_priority_add), \
#include "efl_ui_dnd.eo.c"
#include "efl_ui_dnd_container.eo.c"

View File

@ -1,29 +1,40 @@
import efl_ui_dnd_types;
import eina_types;
mixin @beta Efl.Ui.Dnd {
data: null;
struct @beta Efl.Ui.Drop_Event {
[[Event struct that contains information about what is avaiable at which position, in which seat]]
position : Eina.Position2D; [[The position of the Drop event]]
seat : uint; [[In which seat it is happening]]
available_types : accessor<string>; [[which types are avaiable, you should use one of these for a call to @Efl.Ui.Dnd.drop_data_get ]]
}
struct @beta Efl.Ui.Drop_Dropped_Event {
dnd : Efl.Ui.Drop_Event; [[The overall information]]
action : string; [[The action the client should take]]
}
struct @beta Efl.Ui.Drag_Started_Event {
seat : uint;
}
struct @beta Efl.Ui.Drag_Finished_Event {
seat : uint;
accepted : bool;
}
mixin @beta Efl.Ui.Dnd requires Efl.Object {
methods {
drag_start {
[[Start a drag and drop process at the drag side.
During dragging, there are three events emitted as belows:
- EFL_UI_DND_EVENT_DRAG_POS
- EFL_UI_DND_EVENT_DRAG_ACCEPT
- EFL_UI_DND_EVENT_DRAG_DONE
[[Start a drag from this client.
@[Efl.Ui.Dnd.drag,started] will be emitted each time a successfull drag will be started.
@[Efl.Ui.Dnd.drag,finished] will be emitted every time a drag is finished.
]]
params {
@in format: Efl.Ui.Selection_Format; [[The data format]]
@in data: Eina.Slice; [[The drag data]]
@in action: Efl.Ui.Selection_Action; [[Action when data is transferred]]
@in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drag_action_set {
[[Set the action for the drag]]
params {
@in action: Efl.Ui.Selection_Action; [[Drag action]]
content : Eina.Content @by_ref; [[The content you want to provide via dnd]]
@in action: string; [[Action when data is transferred]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
return : Efl.Content; [[A UI element where you can just set your visual representation into]]
}
drag_cancel {
[[Cancel the on-going drag]]
@ -31,33 +42,26 @@ mixin @beta Efl.Ui.Dnd {
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drop_target_add {
[[Make the current object as drop target.
There are four events emitted:
- EFL_UI_DND_EVENT_DRAG_ENTER
- EFL_UI_DND_EVENT_DRAG_LEAVE
- EFL_UI_DND_EVENT_DRAG_POS
- EFL_UI_DND_EVENT_DRAG_DROP.]]
drop_data_get {
[[Get the data from the object that has selection]]
params {
@in format: Efl.Ui.Selection_Format; [[Accepted data format]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drop_target_del {
[[Delete the dropable status from object]]
params {
@in format: Efl.Ui.Selection_Format; [[Accepted data format]]
@in seat: uint; [[Specified seat for multiple seats case.]]
seat : uint; [[Specified seat for multiple seats case.]]
acceptable_types : iterator<string>; [[The types that are acceptable for you]]
}
return : future<Eina.Content> @move; [[fullfilled when the content is transmitted, and ready to use]]
}
}
events {
/* FIXME: This is not very future-proof. Better return a struct. */
drag,accept: ptr(bool); [[accept drag data]]
drag,done: void; [[drag is done (mouse up)]]
drag,enter: void; [[called when the drag object enters this object]]
drag,leave: void; [[called when the drag object leaves this object]]
drag,pos: Efl.Dnd.Drag_Pos; [[called when the drag object changes drag position]]
drag,drop: Efl.Ui.Selection_Data; [[called when the drag object dropped on this object]]
drop,entered : Efl.Ui.Drop_Event;
drop,left : Efl.Ui.Drop_Event;
drop,position,changed : Efl.Ui.Drop_Event;
drop,dropped : Efl.Ui.Drop_Dropped_Event;
drag,started : Efl.Ui.Drag_Started_Event;
drag,finished : Efl.Ui.Drag_Finished_Event;
}
implements {
Efl.Object.constructor;
Efl.Object.invalidate;
Efl.Object.finalize;
}
}

View File

@ -1,46 +0,0 @@
import efl_ui_dnd_types;
mixin @beta Efl.Ui.Dnd_Container {
methods {
@property drag_delay_time {
[[The time since mouse down happens to drag starts.]]
set {
}
get {
}
values {
time: double; [[The drag delay time]]
}
}
drag_item_add {
[[This registers a drag for items in a container. Many items can be
dragged at a time. During dragging, there are three events emitted:
EFL_DND_EVENT_DRAG_POS, EFL_DND_EVENT_DRAG_ACCEPT, EFL_DND_EVENT_DRAG_DONE.]]
params {
@in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]]
@in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]]
@in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]]
@in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations CHECKING ]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drag_item_del {
[[Remove drag function of items in the container object.]]
params {
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drop_item_add {
params {
@in format: Efl.Ui.Selection_Format; [[Accepted data formats]]
@in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drop_item_del {
params {
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
}
}

View File

@ -1,60 +0,0 @@
import efl_ui_selection_types;
function @beta Efl.Dnd.Drag_Icon_Create {
[[Function pointer for creating icon at the drag side.]]
params {
@in win: Efl.Canvas.Object; [[The window to create the objects relative to]]
@in drag_obj: Efl.Canvas.Object; [[The drag object]]
@out off: Eina.Position2D; [[Offset from the icon position to the cursor]]
}
return: Efl.Canvas.Object; [[The drag icon object]]
};
function @beta Efl.Dnd.Drag_Data_Get {
[[Function pointer for getting data and format at the drag side.]]
params {
@in obj: Efl.Canvas.Object; [[The container object]]
@out format: Efl.Ui.Selection_Format; [[Data format]]
@out drag_data: Eina.Rw_Slice; [[Data]]
@out action: Efl.Ui.Selection_Action; [[The drag action]]
}
};
function @beta Efl.Dnd.Item_Get {
[[Function pointer to find out which item is under position (x, y)]]
params {
@in obj: Efl.Canvas.Object; [[The container object]]
@in pos: Eina.Position2D; [[The coordinates to get item]]
@out posret: Eina.Position2D; [[position relative to item (left (-1), middle (0), right (1)]]
}
return: Efl.Object; [[Object under x,y coordinates or NULL if not found]]
};
function @beta Efl.Dnd.Drag_Icon_List_Create {
[[Function pointer to create list of icons at the drag side.
These icons are used for animation on combining selection icons
to one icon.]]
params {
@in obj: Efl.Canvas.Object; [[The container object]]
}
return: list<Efl.Canvas.Object>;
};
struct @beta Efl.Dnd.Drag_Accept {
accepted: bool;
}
struct @beta Efl.Dnd.Drag_Pos {
[[Dragging position information.]]
pos: Eina.Position2D; [[Evas Coordinate]]
action: Efl.Ui.Selection_Action; [[The drag action]]
format: Efl.Ui.Selection_Format; [[The drag format]]
item: Efl.Canvas.Object; [[The item object. It is only available for container object.]]
}
struct @beta Efl.Dnd.Drag_Item_Container_Drop {
[[Drop information for a drag&drop operation.]]
item: Efl.Canvas.Object; [[The item object]]
data: Efl.Ui.Selection_Data; [[The selection data]]
pos: Eina.Position2D; [[Position relative to item (left (-1), middle (0), right (1)]]
}

View File

@ -9,278 +9,115 @@
#define MY_CLASS EFL_UI_SELECTION_MIXIN
#define MY_CLASS_NAME "Efl.Ui.Selection"
#ifdef HAVE_ELEMENTARY_WL2
Ecore_Wl2_Window *_wl_window_get(const Evas_Object *obj);
#endif
typedef struct {
Ecore_Evas *ee;
Eina_Bool registered : 1;
} Efl_Ui_Selection_Data;
EOLIAN static void
_efl_ui_selection_selection_get(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format,
void *data_func_data, Efl_Ui_Selection_Data_Ready data_func, Eina_Free_Cb data_func_free_cb, unsigned int seat)
static inline Ecore_Evas_Selection_Buffer
_ee_buffer_get(Efl_Ui_Cnp_Buffer buffer)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_selection_get(sel_man, obj, type, format,
data_func_data, data_func,
data_func_free_cb, seat);
if (buffer == EFL_UI_CNP_BUFFER_SELECTION)
return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER;
else
return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER;
}
EOLIAN static Eina_Future *
_efl_ui_selection_selection_set(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, Efl_Ui_Selection_Format format, Eina_Slice data, unsigned int seat)
EOLIAN static Eina_Future*
_efl_ui_selection_selection_get(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat, Eina_Iterator *acceptable_types)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
return efl_ui_selection_manager_selection_set(sel_man, obj, type, format, data, seat);
return ecore_evas_selection_get(pd->ee, seat, _ee_buffer_get(buffer), acceptable_types);
}
EOLIAN static void
_efl_ui_selection_selection_clear(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat)
_efl_ui_selection_selection_set(Eo *obj, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, Eina_Content *content, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
efl_ui_selection_manager_selection_clear(sel_man, obj, type, seat);
_register_selection_changed(obj);
ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), content);
}
EOLIAN static void
_efl_ui_selection_selection_clear(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat)
{
ecore_evas_selection_set(pd->ee, seat, _ee_buffer_get(buffer), NULL);
}
EOLIAN static Eina_Bool
_efl_ui_selection_has_owner(Eo *obj, void *pd EINA_UNUSED, Efl_Ui_Selection_Type type, unsigned int seat)
_efl_ui_selection_has_selection(Eo *obj EINA_UNUSED, Efl_Ui_Selection_Data *pd, Efl_Ui_Cnp_Buffer buffer, unsigned int seat)
{
Eo *sel_man = _efl_ui_selection_manager_get(obj);
return efl_ui_selection_manager_selection_has_owner(sel_man, obj, type, seat);
return ecore_evas_selection_exists(pd->ee, seat, _ee_buffer_get(buffer));
}
////////// Support legacy APIs
//TODO: Clear this list (when sel_man is deleted)
Eina_List *lost_cb_list = NULL;
#ifdef HAVE_ELEMENTARY_WL2
static Ecore_Evas *
_wl_is_wl(const Evas_Object *obj)
EOLIAN static Efl_Object*
_efl_ui_selection_efl_object_constructor(Eo *obj, Efl_Ui_Selection_Data *pd)
{
Ecore_Evas *ee;
Evas *evas;
const char *engine_name;
if (!efl_constructor(efl_super(obj, EFL_UI_SELECTION_MIXIN)))
return NULL;
if (!(evas = evas_object_evas_get(obj)))
return NULL;
if (!(ee = ecore_evas_ecore_evas_get(evas)))
return NULL;
pd->ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
engine_name = ecore_evas_engine_name_get(ee);
if (!strcmp(engine_name, ELM_BUFFER))
return obj;
}
EOLIAN static void
_efl_ui_selection_efl_object_invalidate(Eo *obj, Efl_Ui_Selection_Data *pd)
{
if (pd->registered)
{
ee = ecore_evas_buffer_ecore_evas_parent_get(ee);
if (!ee) return NULL;
engine_name = ecore_evas_engine_name_get(ee);
_selection_changed_event_unregister(obj);
}
if (!strncmp(engine_name, "wayland", sizeof("wayland") - 1))
return ee;
return NULL;
efl_invalidate(efl_super(obj, EFL_UI_SELECTION_MIXIN));
}
int
_wl_default_seat_id_get(Evas_Object *obj)
EOLIAN static Eina_Bool
_efl_ui_selection_efl_object_event_callback_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd,
const Efl_Event_Description *desc,
Efl_Callback_Priority priority,
Efl_Event_Cb func,
const void *user_data)
{
Ecore_Wl2_Window *win = _wl_window_get(obj);
Eo *seat, *parent2, *ewin;
Eina_Bool is_wl = EINA_FALSE;
if (desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered)
{
if (obj)
pd->registered = EINA_TRUE;
if (efl_finalized_get(obj))
_selection_changed_event_register(obj);
}
return efl_event_callback_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), desc, priority, func, user_data);
}
EOLIAN static Eina_Bool
_efl_ui_selection_efl_object_event_callback_array_priority_add(Eo *obj, Efl_Ui_Selection_Data *pd,
const Efl_Callback_Array_Item *array,
Efl_Callback_Priority priority,
const void *user_data)
{
for (int i = 0; array[i].desc; ++i)
{
if (_wl_is_wl(obj)) is_wl = EINA_TRUE;
if (efl_isa(obj, EFL_UI_WIDGET_CLASS))
if (array[i].desc == EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED && !pd->registered)
{
Eo *top = elm_widget_top_get(obj);
if (efl_isa(top, EFL_UI_WIN_INLINED_CLASS))
{
parent2 = efl_ui_win_inlined_parent_get(top);
if (parent2) obj = elm_widget_top_get(parent2) ?: parent2;
}
/* fake win means canvas seat id will not match protocol seat id */
ewin = elm_win_get(obj);
if (elm_win_type_get(ewin) == ELM_WIN_FAKE) obj = NULL;
pd->registered = EINA_TRUE;
if (efl_finalized_get(obj))
_selection_changed_event_register(obj);
}
}
if (!obj)
{
if (is_wl)
{
Ecore_Wl2_Input *input;
Eina_Iterator *it;
it = ecore_wl2_display_inputs_get(ecore_wl2_window_display_get(win));
EINA_ITERATOR_FOREACH(it, input) break;
eina_iterator_free(it);
if (input)
return ecore_wl2_input_seat_id_get(input);
}
}
seat = evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT);
EINA_SAFETY_ON_NULL_RETURN_VAL(seat, 1);
return evas_device_seat_id_get(seat);
}
#endif
typedef struct _Cnp_Data_Cb_Wrapper Cnp_Data_Cb_Wrapper;
struct _Cnp_Data_Cb_Wrapper
{
void *udata;
Elm_Drop_Cb datacb;
};
static void
_selection_data_ready_cb(void *data, Efl_Object *obj, Efl_Ui_Selection_Data *seldata)
{
Cnp_Data_Cb_Wrapper *wdata = data;
if (!wdata) return;
Elm_Selection_Data ddata;
ddata.data = calloc(1, seldata->content.len + 1);
if (!ddata.data) return;
ddata.data = memcpy(ddata.data, seldata->content.mem, seldata->content.len);
ddata.len = seldata->content.len;
ddata.x = seldata->pos.x;
ddata.y = seldata->pos.y;
ddata.format = (Elm_Sel_Format)seldata->format;
ddata.action = (Elm_Xdnd_Action)seldata->action;
wdata->datacb(wdata->udata, obj, &ddata);
free(ddata.data);
return efl_event_callback_array_priority_add(efl_super(obj, EFL_UI_SELECTION_MIXIN), array, priority, user_data);
}
typedef struct _Sel_Lost_Data Sel_Lost_Data;
struct _Sel_Lost_Data
EOLIAN static Efl_Object*
_efl_ui_selection_efl_object_finalize(Eo *obj, Efl_Ui_Selection_Data *pd)
{
const Evas_Object *obj;
Elm_Sel_Type type;
void *udata;
Elm_Selection_Loss_Cb loss_cb;
};
if (pd->registered)
_selection_changed_event_register(obj);
static Eina_Value
_selection_lost_cb(void *data, const Eina_Value value)
{
Eina_List *l, *l2;
Sel_Lost_Data *ldata, *ldata2;
ldata = data;
EINA_LIST_FOREACH_SAFE(lost_cb_list, l, l2, ldata2)
{
if ((ldata->obj == ldata2->obj) &&
(ldata->type == ldata2->type))
{
ldata2->loss_cb(ldata2->udata, ldata2->type);
lost_cb_list = eina_list_remove(lost_cb_list, ldata2);
}
}
free(ldata);
return value;
return efl_finalize(efl_super(obj, MY_CLASS));
}
EAPI Eina_Bool
elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type type,
Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
{
int seatid = 1;
Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
Cnp_Data_Cb_Wrapper *wdata = calloc(1, sizeof(Cnp_Data_Cb_Wrapper));
if (!wdata) return EINA_FALSE;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get((Evas_Object *)obj);
#endif
wdata->udata = udata;
wdata->datacb = datacb;
efl_ui_selection_manager_selection_get(sel_man, (Evas_Object *)obj, (Efl_Ui_Selection_Type)type,
(Efl_Ui_Selection_Format)format,
wdata, _selection_data_ready_cb, NULL, seatid);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type type,
Elm_Sel_Format format, const void *selbuf, size_t buflen)
{
int seatid = 1;
Eina_Future *f;
Sel_Lost_Data *ldata;
Eo *sel_man = _efl_ui_selection_manager_get(obj);
Eina_Slice data;
ldata = calloc(1, sizeof(Sel_Lost_Data));
if (!ldata) return EINA_FALSE;
data.mem = selbuf;
data.len = buflen;
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
f = efl_ui_selection_manager_selection_set(sel_man, obj, (Efl_Ui_Selection_Type)type,
(Efl_Ui_Selection_Format)format, data, seatid);
ldata->obj = obj;
ldata->type = type;
eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata);
return EINA_TRUE;
}
EAPI Eina_Bool
elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type type)
{
int seatid = 1;
Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
efl_ui_selection_manager_selection_clear(sel_man, obj, (Efl_Ui_Selection_Type)type, seatid);
return EINA_TRUE;
}
EAPI void
elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type,
Elm_Selection_Loss_Cb func, const void *data)
{
Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data));
#if HAVE_ELEMENTARY_COCOA
// Currently, we have no way to track changes in Cocoa pasteboard.
// Therefore, don't track this...
return;
#endif
if (!ldata) return;
ldata->obj = obj;
ldata->type = type;
ldata->udata = (void *)data;
ldata->loss_cb = func;
lost_cb_list = eina_list_append(lost_cb_list, ldata);
}
EAPI Eina_Bool
elm_selection_selection_has_owner(Evas_Object *obj)
{
int seatid = 1;
Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
return efl_ui_selection_manager_selection_has_owner(sel_man, obj,
EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid);
}
EAPI Eina_Bool
elm_cnp_clipboard_selection_has_owner(Evas_Object *obj)
{
int seatid = 1;
Eo *sel_man = _efl_ui_selection_manager_get((Evas_Object *)obj);
#ifdef HAVE_ELEMENTARY_WL2
if (_wl_window_get(obj)) seatid = _wl_default_seat_id_get(obj);
#endif
return efl_ui_selection_manager_selection_has_owner(sel_man, obj,
EFL_UI_SELECTION_TYPE_CLIPBOARD, seatid);
}
#define EFL_UI_SELECTION_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_event_callback_priority_add, _efl_ui_selection_efl_object_event_callback_priority_add), \
EFL_OBJECT_OP_FUNC(efl_event_callback_array_priority_add, _efl_ui_selection_efl_object_event_callback_array_priority_add), \
#include "efl_ui_selection.eo.c"

View File

@ -1,45 +1,57 @@
import efl_ui_selection_types;
import eina_types;
mixin @beta Efl.Ui.Selection {
[[Efl Ui Selection class]]
data: null;
methods {
selection_set {
[[Set the selection data to the object]]
params {
@in type: Efl.Ui.Selection_Type; [[Selection Type]]
@in format: Efl.Ui.Selection_Format; [[Selection Format]]
@in data: Eina.Slice; [[Selection data]]
@in seat: uint;[[Specified seat for multiple seats case.]]
}
return: future<void>; [[Future for tracking when the selection is lost]]
}
selection_get {
[[Get the data from the object that has selection]]
params {
@in type: Efl.Ui.Selection_Type; [[Selection Type]]
@in format: Efl.Ui.Selection_Format; [[Selection Format]]
@in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]]
@in seat: uint;[[Specified seat for multiple seats case.]]
}
}
selection_clear {
[[Clear the selection data from the object]]
params {
@in type: Efl.Ui.Selection_Type; [[Selection Type]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
has_owner {
[[Determine whether the selection data has owner]]
params {
@in type: Efl.Ui.Selection_Type; [[Selection type]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
return: bool; [[EINA_TRUE if there is object owns selection, otherwise EINA_FALSE]]
}
}
events {
wm_selection,changed: Efl.Ui.Selection_Changed; [[Called when display server's selection has changed]]
}
enum @beta Efl.Ui.Cnp_Buffer{
selection = 0,
copy_and_paste = 1,
}
struct @beta Efl.Ui.Wm_Selection_Changed {
buffer : Efl.Ui.Cnp_Buffer;
caused_by : Efl.Ui.Selection;
seat : uint;
}
mixin @beta Efl.Ui.Selection requires Efl.Object {
methods {
selection_set {
[[Set the selection data to the object]]
params {
buffer : Efl.Ui.Cnp_Buffer;
content : Eina.Content @by_ref;
seat : uint;
}
}
selection_clear {
[[Clear the selection data from the object]]
params {
buffer : Efl.Ui.Cnp_Buffer;
seat : uint;
}
}
selection_get {
[[Get the data from the object that has selection]]
params {
buffer : Efl.Ui.Cnp_Buffer;
seat : uint;
acceptable_types : iterator<string>;
}
return : future<Eina.Content> @move;
}
has_selection {
[[Determine whether the selection data has owner]]
params {
buffer : Efl.Ui.Cnp_Buffer;
seat : uint;
}
return : bool; [[$true if there is a available selection, $false if not]]
}
}
implements {
Efl.Object.constructor;
Efl.Object.invalidate;
Efl.Object.finalize;
}
events {
wm_selection,changed : Efl.Ui.Wm_Selection_Changed;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,139 +0,0 @@
import efl_ui_dnd_types;
class @beta Efl.Ui.Selection_Manager extends Efl.Object {
methods {
selection_set @beta {
[[Set selection]]
params {
@in owner: Efl.Object; [[Seleciton owner]]
@in type: Efl.Ui.Selection_Type; [[Selection type]]
@in format: Efl.Ui.Selection_Format; [[Selection format]]
@in data: Eina.Slice; [[Selection data]]
@in seat: uint @optional;[[Specified seat for multiple seats case.]]
}
return: future<void>; [[Future for tracking when the selection is lost]]
}
selection_get @beta {
[[Get selection]]
params {
@in request: const(Efl.Object); [[Seleciton owner]]
@in type: Efl.Ui.Selection_Type; [[Selection type]]
@in format: Efl.Ui.Selection_Format; [[Selection Format]]
@in data_func: Efl.Ui.Selection_Data_Ready; [[Data ready function pointer]]
@in seat: uint @optional;[[Specified seat for multiple seats case.]]
}
}
selection_clear @beta {
params {
@in owner: Efl.Object; [[Seleciton owner]]
@in type: Efl.Ui.Selection_Type; [[Selection type]]
@in seat: uint @optional; [[Specified seat for multiple seats case.]]
}
}
selection_has_owner @beta {
[[Check if the request object has selection or not]]
params {
@in request: Efl.Object; [[Request object]]
@in type: Efl.Ui.Selection_Type; [[Selection type]]
@in seat: uint @optional; [[Specified seat for multiple seats case.]]
}
return: bool; [[EINA_TRUE if the request object has selection, otherwise, EINA_FALSE]]
}
drag_start @beta {
[[This starts a drag and drop process at the drag side.
During dragging, there are three events emitted as belows:
- EFL_UI_DND_EVENT_DRAG_POS
- EFL_UI_DND_EVENT_DRAG_ACCEPT
- EFL_UI_DND_EVENT_DRAG_DONE
]]
params {
@in drag_obj: Efl.Object; [[Drag object]]
@in format: Efl.Ui.Selection_Format; [[Data format]]
@in data: Eina.Slice; [[Data to transfer]]
@in action: Efl.Ui.Selection_Action; [[Action when data is transferred]]
@in icon_func: Efl.Dnd.Drag_Icon_Create; [[Function pointer to create icon]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drag_action_set @beta {
[[This sets the action for the drag]]
params {
@in drag_obj: Efl.Object; [[Drag object]]
@in action: Efl.Ui.Selection_Action; [[Drag action]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
drag_cancel @beta {
[[This cancels the on-going drag]]
params {
@in drag_obj: Efl.Object; [[Drag object]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
container_drag_item_add @beta {
[[This registers a drag for items in a container. Many items can be
dragged at a time. During dragging, there are three events emitted:
- EFL_UI_DND_EVENT_DRAG_POS
- EFL_UI_DND_EVENT_DRAG_ACCEPT
- EFL_UI_DND_EVENT_DRAG_DONE.]]
params {
@in cont: Efl.Object; [[Container object]]
@in time_to_drag: double; [[Time since mouse down happens to drag starts]]
@in anim_duration: double; [[animation duration]]
@in data_func: Efl.Dnd.Drag_Data_Get; [[Data and its format]]
@in item_func: Efl.Dnd.Item_Get; [[Item to determine drag start]]
@in icon_func: Efl.Dnd.Drag_Icon_Create; [[Icon used during drag]]
@in icon_list_func: Efl.Dnd.Drag_Icon_List_Create; [[Icons used for animations]]
@in seat: uint; [[Specified seat for multiple seats case]]
}
}
container_drag_item_del @beta {
[[Remove drag function of items in the container object.]]
params {
@in cont: Efl.Object; [[Container object]]
@in seat: uint; [[Specified seat for multiple seats case]]
}
}
drop_target_add @beta {
[[Add a dropable target. There are four events emitted:
- EFL_UI_DND_DROP_DRAG_ENTER
- EFL_UI_DND_DROP_DRAG_LEAVE
- EFL_UI_DND_DROP_DRAG_POS
- EFL_UI_DND_DROP_DRAG_DROP.]]
params {
@in target_obj: Efl.Object; [[Drop target]]
@in format: Efl.Ui.Selection_Format; [[Accepted data format]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
return: bool; [[$true on success, $false otherwise]]
}
drop_target_del @beta {
[[Remove a dropable target]]
params {
@in target_obj: Efl.Object; [[Drop target]]
@in format: Efl.Ui.Selection_Format; [[Accepted data format]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
container_drop_item_add @beta {
[[Add dropable target for a container in which items can drop to it]]
params {
@in cont: Efl.Object; [[Container object]]
@in format: Efl.Ui.Selection_Format; [[Accepted data formats]]
@in item_func: Efl.Dnd.Item_Get; [[Get item at specific position]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
container_drop_item_del @beta {
[[Remove dropable target for the container]]
params {
@in cont: Efl.Object; [[Container object]]
@in seat: uint; [[Specified seat for multiple seats case.]]
}
}
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
}
}

View File

@ -1,60 +0,0 @@
enum @beta Efl.Ui.Selection_Type
{
[[Selection type]]
primary, [[Primary text selection (highlighted or selected text)]]
secondary, [[Used when primary selection is in use]]
dnd, [[Drag and Drop]]
clipboard [[Clipboard selection (ctrl+C)]]
}
enum @beta Efl.Ui.Selection_Format
{
[[Selection format]]
targets = -1, [[For matching every possible atom]]
none = 0x0, [[Content is from outside of EFL]]
text = 0x01, [[Plain unformatted text: Used for things that don't want rich markup]]
markup = 0x2, [[Edje textblock markup, including inline images]]
image = 0x4, [[Images]]
vcard = 0x08, [[Vcards]]
html = 0x10 [[Raw HTML-like data (eg. webkit)]]
}
enum @beta Efl.Ui.Selection_Action
{
[[Defines the kind of action associated with the drop data]]
unknown, [[Action type is unknown]]
copy, [[Copy the data]]
move, [[Move the data]]
private, [[Private action type]]
ask, [[Ask the user what to do]]
list, [[List the data]]
link, [[Link the data]]
description [[Describe the data]]
}
struct @beta Efl.Ui.Selection_Data
{
[[Structure holding the info about selected data]]
pos: Eina.Position2D; [[Coordinates of the drop (DND operations only)]]
format: Efl.Ui.Selection_Format; [[Format of the selection]]
content: Eina.Slice; [[Selection data]]
action: Efl.Ui.Selection_Action; [[Action to perform with the data]]
item: Efl.Object; [[Item under the drag position. It is only available for container]]
}
function @beta Efl.Ui.Selection_Data_Ready {
[[Function pointer for getting selection]]
params {
@in obj: Efl.Object; [[Object which requested for the selection]]
@in seldata: ptr(Efl.Ui.Selection_Data); [[Selection data]]
}
};
struct @beta Efl.Ui.Selection_Changed
{
[[Selection-changed specific information.]] // TODO: This needs to be filled in.
type: Efl.Ui.Selection_Type; [[Selection type]]
seat: int; [[The seat on which the selection changed, or NULL for "default"]]
display: void_ptr; [[The display connection object, NULL under X11]]
exist: bool; [[EINA_TRUE if the selection has an owner]]
}

View File

@ -757,7 +757,7 @@ _view_init(Evas_Object *obj, Efl_Ui_Tags_Data *sd)
sd->entry = efl_add(EFL_UI_TEXTBOX_CLASS, sd->box,
efl_text_multiline_set(efl_added, EINA_FALSE),
efl_text_set(efl_added, ""),
efl_ui_textbox_cnp_mode_set(efl_added, EFL_UI_SELECTION_FORMAT_MARKUP),
efl_ui_textbox_cnp_dnd_mode_set(efl_added, EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP),
efl_input_text_input_panel_autoshow_set(efl_added, EINA_FALSE),
efl_text_interactive_editable_set(efl_added, EINA_TRUE),
efl_composite_attach(obj, efl_added));

View File

@ -22,7 +22,6 @@
typedef struct _Efl_Ui_Textbox_Data Efl_Ui_Textbox_Data;
typedef struct _Efl_Ui_Text_Rectangle Efl_Ui_Text_Rectangle;
typedef struct _Anchor Anchor;
typedef struct _Selection_Loss_Data Selection_Loss_Data;
/**
* Base widget smart data extended with entry instance data.
@ -69,7 +68,7 @@ struct _Efl_Ui_Textbox_Data
const char *hover_style; /**< style of a hover object */
} anchor_hover;
Efl_Ui_Selection_Format cnp_mode;
const char *cnp_mime_type;
Elm_Sel_Format drop_format;
struct {
@ -81,11 +80,7 @@ struct _Efl_Ui_Textbox_Data
Eina_Size2D scroll;
Eina_Size2D layout;
} last;
struct
{
Eina_Future *primary;
Eina_Future *clipboard;
} sel_future;
Efl_Ui_Textbox_Cnp_Content content;
Eina_Bool sel_handles_enabled : 1;
Eina_Bool start_handler_down : 1;
Eina_Bool start_handler_shown : 1;
@ -147,12 +142,6 @@ struct _Efl_Ui_Text_Rectangle
Evas_Object *obj_bg, *obj_fg, *obj;
};
struct _Selection_Loss_Data
{
Eo *obj;
Efl_Ui_Selection_Type stype;
};
#define MY_CLASS EFL_UI_TEXTBOX_CLASS
#define MY_CLASS_PFX efl_ui_textbox
#define MY_CLASS_NAME "Efl.Ui.Textbox"
@ -208,7 +197,7 @@ static void _anchors_free(Efl_Ui_Textbox_Data *sd);
static void _selection_defer(Eo *obj, Efl_Ui_Textbox_Data *sd);
static Eina_Position2D _decoration_calc_offset(Efl_Ui_Textbox_Data *sd);
static void _update_text_theme(Eo *obj, Efl_Ui_Textbox_Data *sd);
static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type);
static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type);
static Eina_Bool _key_action_copy(Evas_Object *obj, const char *params);
static Eina_Bool _key_action_paste(Evas_Object *obj, const char *params);
@ -407,16 +396,19 @@ _update_selection_handler(Eo *obj)
}
}
static void
_selection_data_cb(void *data EINA_UNUSED, Eo *obj,
Efl_Ui_Selection_Data *sel_data)
static Eina_Value
_selection_data_cb(Efl_Ui_Textbox *obj, void *data EINA_UNUSED, const Eina_Value value)
{
Eina_Content *content;
Eina_Slice slice;
Efl_Text_Cursor *cur, *start, *end;
Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
char *buf = eina_slice_strdup(sel_data->content);
size_t len = sel_data->content.len;
if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT)
return EINA_VALUE_EMPTY;
content = eina_value_to_content(&value);
slice = eina_content_data_get(content);
efl_text_interactive_selection_cursors_get(obj, &start, &end);
if (!efl_text_cursor_equal(start, end))
{
@ -426,83 +418,130 @@ _selection_data_cb(void *data EINA_UNUSED, Eo *obj,
cur = efl_text_interactive_main_cursor_get(obj);
info.type = EFL_TEXT_CHANGE_TYPE_INSERT;
info.position = efl_text_cursor_position_get(cur);
info.length = len;
info.content = buf;
if (sel_data->format == EFL_UI_SELECTION_FORMAT_MARKUP)
info.length = slice.len;
info.content = slice.mem;
if (eina_streq(eina_content_type_get(content), "application/x-elementary-markup"))
{
efl_text_cursor_markup_insert(cur, buf);
efl_text_cursor_markup_insert(cur, slice.mem);
}
else if (!strncmp(eina_content_type_get(content), "image/", strlen("image/")))
{
Eina_Strbuf *result = eina_strbuf_new();
eina_strbuf_append_printf(result, "<item absize=240x180 href=");
eina_strbuf_append_slice(result, slice);
eina_strbuf_append_printf(result, "></item>");
efl_text_cursor_markup_insert(cur, eina_strbuf_string_get(result));
eina_strbuf_free(result);
}
else // TEXT
{
efl_text_cursor_text_insert(cur, buf);
efl_text_cursor_text_insert(cur, slice.mem);
}
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
free(buf);
return EINA_VALUE_EMPTY;
}
static Eina_Array*
_figure_out_types(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
{
Eina_Array *types = eina_array_new(10);
if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP)
eina_array_push(types, "application/x-elementary-markup");
if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE)
{
eina_array_push(types, "image/png");
eina_array_push(types, "image/jpeg");
eina_array_push(types, "image/x-ms-bmp");
eina_array_push(types, "image/gif");
eina_array_push(types, "image/tiff");
eina_array_push(types, "image/svg+xml");
eina_array_push(types, "image/x-xpixmap");
eina_array_push(types, "image/x-tga");
eina_array_push(types, "image/x-portable-pixmap");
}
if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT)
eina_array_push(types, "text/plain;charset=utf-8");
return types;
}
static Eina_Bool
_accepting_drops(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Accessor *mime_types)
{
int i = 0;
const char *mime_type;
if (efl_ui_widget_disabled_get(obj)) return EINA_FALSE;
EINA_ACCESSOR_FOREACH(mime_types, i, mime_type)
{
if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT &&
eina_streq(mime_type, "text/plain;charset=utf-8"))
return EINA_TRUE;
if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE &&
strncmp(mime_type, "image/", strlen("image/")))
return EINA_TRUE;
if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP &&
eina_streq(mime_type, "application/x-elementary-markup"))
return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_dnd_enter_cb(void *data EINA_UNUSED,
Evas_Object *obj)
const Efl_Event *ev)
{
efl_ui_focus_util_focus(obj);
Efl_Ui_Drop_Event *dnd_enter = ev->info;
EFL_UI_TEXT_DATA_GET(ev->object, sd);
if (_accepting_drops(ev->object, sd, dnd_enter->available_types))
efl_ui_focus_util_focus(ev->object);
}
static void
_dnd_leave_cb(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED)
_dnd_pos_cb(void *data EINA_UNUSED, const Efl_Event *ev)
{
}
Efl_Ui_Drop_Event *dnd_pos = ev->info;
Eina_Position2D po, pe, pos;
EFL_UI_TEXT_DATA_GET(ev->object, sd);
int cursor_pos;
static void
_dnd_pos_cb(void *data EINA_UNUSED,
Evas_Object *obj,
Evas_Coord x,
Evas_Coord y,
Elm_Xdnd_Action action EINA_UNUSED)
{
int pos;
Eina_Rect o, e;
if (!_accepting_drops(ev->object, sd, dnd_pos->available_types))
return;
EFL_UI_TEXT_DATA_GET(obj, sd);
o = efl_gfx_entity_geometry_get(obj);
e = efl_gfx_entity_geometry_get(sd->entry_edje);
x = x + o.x - e.x;
y = y + o.y - e.y;
po = efl_gfx_entity_position_get(ev->object);
pe = efl_gfx_entity_position_get(sd->entry_edje);
pos.x = dnd_pos->position.x + po.x - pe.x;
pos.y = dnd_pos->position.y + po.x - pe.y;
edje_object_part_text_cursor_coord_set
(sd->entry_edje, "efl.text", EDJE_CURSOR_USER, x, y);
pos = edje_object_part_text_cursor_pos_get
(sd->entry_edje, "efl.text", EDJE_CURSOR_USER, pos.x, pos.y);
cursor_pos = edje_object_part_text_cursor_pos_get
(sd->entry_edje, "efl.text", EDJE_CURSOR_USER);
edje_object_part_text_cursor_pos_set(sd->entry_edje, "efl.text",
EDJE_CURSOR_MAIN, pos);
EDJE_CURSOR_MAIN, cursor_pos);
}
static Eina_Bool
_dnd_drop_cb(void *data EINA_UNUSED,
Evas_Object *obj,
Elm_Selection_Data *drop)
static void
_dnd_drop_cb(void *data EINA_UNUSED, const Efl_Event *ev)
{
Eina_Bool rv;
Efl_Ui_Drop_Event *drop = ev->info;
Eina_Future *future;
Eina_Array *types;
EFL_UI_TEXT_DATA_GET(obj, sd);
EFL_UI_TEXT_DATA_GET(ev->object, sd);
types = _figure_out_types(ev->object, sd);
rv = edje_object_part_text_cursor_coord_set
(sd->entry_edje, "efl.text", EDJE_CURSOR_MAIN, drop->x, drop->y);
if (!_accepting_drops(ev->object, sd, drop->available_types))
return;
if (!rv) WRN("Warning: Failed to position cursor: paste anyway");
future = efl_ui_dnd_drop_data_get(ev->object, 0, eina_array_iterator_new(types));
eina_array_free(types);
//rv = _selection_data_cb(NULL, obj, drop);
return rv;
}
static Elm_Sel_Format
_get_drop_format(Evas_Object *obj)
{
if (efl_text_interactive_editable_get(obj) && (efl_text_multiline_get(obj)) && (!efl_text_password_get(obj)) && (!efl_ui_widget_disabled_get(obj)))
return EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE;
return EFL_UI_SELECTION_FORMAT_MARKUP;
efl_future_then(ev->object, future, _selection_data_cb);
}
/* we can't reuse layout's here, because it's on entry_edje only */
@ -516,12 +555,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein
efl_ui_widget_disabled_set(efl_super(obj, MY_CLASS), disabled);
elm_drop_target_del(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
emission = efl_ui_widget_disabled_get(obj) ? "efl,state,disabled" : "efl,state,enabled";
efl_layout_signal_emit(sd->entry_edje, emission, "efl");
if (sd->scroll)
@ -529,15 +562,6 @@ _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Ein
efl_ui_scrollable_scroll_freeze_set(obj, efl_ui_widget_disabled_get(obj));
}
if (!efl_ui_widget_disabled_get(obj))
{
sd->drop_format = _get_drop_format(obj);
elm_drop_target_add(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
}
_update_text_theme(obj, sd);
}
@ -804,83 +828,36 @@ _popup_position(Evas_Object *obj)
efl_gfx_entity_geometry_set(sd->popup, EINA_RECT(r.x + cx, r.y + cy, m.w, m.h));
}
static Eina_Value
_selection_lost_cb(void *data, const Eina_Value value)
static void
_selection_lost_cb(void *data EINA_UNUSED, const Efl_Event *ev)
{
Selection_Loss_Data *sdata = data;
EFL_UI_TEXT_DATA_GET(sdata->obj, sd);
Efl_Ui_Wm_Selection_Changed *changed = ev->info;
EFL_UI_TEXT_DATA_GET(ev->object, sd);
efl_text_interactive_all_unselect(sdata->obj);
_selection_defer(sdata->obj, sd);
switch (sdata->stype)
if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && changed->caused_by != ev->object)
{
case EFL_UI_SELECTION_TYPE_CLIPBOARD:
sd->sel_future.clipboard = NULL;
break;
case EFL_UI_SELECTION_TYPE_PRIMARY:
default:
sd->sel_future.primary = NULL;
break;
efl_text_interactive_all_unselect(ev->object);
_selection_defer(ev->object, sd);
}
return value;
}
static void
_selection_store(Efl_Ui_Selection_Type seltype,
_selection_store(Efl_Ui_Cnp_Buffer buffer,
Evas_Object *obj)
{
char *sel;
Efl_Text_Cursor *start, *end;
Efl_Ui_Selection_Format selformat = EFL_UI_SELECTION_FORMAT_MARKUP;
Eina_Slice slice;
Selection_Loss_Data *ldata;
Eina_Future *f;
EFL_UI_TEXT_DATA_GET(obj, sd);
Eina_Content *content;
efl_text_interactive_selection_cursors_get(obj, &start, &end);
sel = efl_text_cursor_range_markup_get(start, end);
if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */
slice.len = strlen(sel);
slice.mem = sel;
content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(sel), "application/x-elementary-markup");
switch (seltype)
{
case EFL_UI_SELECTION_TYPE_CLIPBOARD:
if (sd->sel_future.clipboard)
{
eina_future_cancel(sd->sel_future.clipboard);
}
efl_ui_selection_set(obj, buffer, content, 0);
f = sd->sel_future.clipboard = efl_ui_selection_set(obj, seltype,
selformat, slice, 1);
break;
case EFL_UI_SELECTION_TYPE_PRIMARY:
default:
if (sd->sel_future.primary)
{
eina_future_cancel(sd->sel_future.primary);
}
f = sd->sel_future.primary = efl_ui_selection_set(obj, seltype,
selformat, slice, 1);
break;
}
ldata = calloc(1, sizeof(Selection_Loss_Data));
if (!ldata) goto end;
ldata->obj = obj;
eina_future_then_easy(f, _selection_lost_cb, NULL, NULL, EINA_VALUE_TYPE_UINT, ldata);
//if (seltype == EFL_UI_SELECTION_TYPE_CLIPBOARD)
// eina_stringshare_replace(&sd->cut_sel, sel);
end:
free(sel);
}
@ -956,7 +933,7 @@ _menu_call(Evas_Object *obj)
{
Eina_Bool ownersel;
ownersel = elm_selection_selection_has_owner(obj);
ownersel = elm_cnp_clipboard_selection_has_owner(obj);
/* prevent stupid blank hoversel */
if (efl_text_interactive_have_selection_get(obj) && efl_text_password_get(obj)) return;
if (_elm_config->desktop_entry && (!efl_text_interactive_have_selection_get(obj)) && ((!efl_text_interactive_editable_get(obj)) || (!ownersel)))
@ -1133,7 +1110,7 @@ _mouse_down_cb(void *data, const Efl_Event *event)
if (ev->button == 2)
{
_efl_ui_textbox_selection_paste_type(data, EFL_UI_SELECTION_TYPE_PRIMARY);
_efl_ui_textbox_selection_paste_type(data, sd, EFL_UI_CNP_BUFFER_SELECTION);
}
/* If right button is pressed and context menu disabled is true,
@ -1654,10 +1631,18 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd)
{
Eo *text_obj;
sd->content = EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP;
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
if (!elm_widget_theme_klass_get(obj))
elm_widget_theme_klass_set(obj, "text");
efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_lost_cb, NULL);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_ENTERED, _dnd_enter_cb, NULL);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _dnd_pos_cb, NULL);
efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_DROPPED, _dnd_drop_cb, NULL);
obj = efl_constructor(efl_super(obj, MY_CLASS));
efl_event_callback_add(obj, EFL_INPUT_EVENT_LONGPRESSED, _long_press_cb, obj);
@ -1674,11 +1659,9 @@ _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd)
efl_composite_attach(obj, text_obj);
sd->entry_edje = wd->resize_obj;
sd->cnp_mode = EFL_UI_SELECTION_FORMAT_TEXT;
sd->context_menu_enabled = EINA_TRUE;
efl_text_interactive_editable_set(obj, EINA_TRUE);
efl_text_interactive_selection_allowed_set(obj, EINA_TRUE);
sd->drop_format = EFL_UI_SELECTION_FORMAT_MARKUP | EFL_UI_SELECTION_FORMAT_IMAGE;
sd->last.scroll = EINA_SIZE2D(0, 0);
sd->sel_handles_enabled = EINA_FALSE;
@ -1691,12 +1674,6 @@ _efl_ui_textbox_efl_object_finalize(Eo *obj,
{
obj = efl_finalize(efl_super(obj, MY_CLASS));
elm_drop_target_add(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY);
_update_guide_text(obj, sd);
@ -1805,11 +1782,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E
efl_text_replacement_char_set(obj, ENTRY_PASSWORD_MASK_CHARACTER_UTF8);
efl_text_password_set(sd->text_obj, password);
elm_drop_target_del(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
if (password)
{
efl_text_multiline_set(obj, EINA_FALSE);
@ -1819,12 +1791,6 @@ _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, E
else
{
efl_text_multiline_set(obj, EINA_TRUE);
sd->drop_format = _get_drop_format(obj);
elm_drop_target_add(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
efl_input_text_input_content_type_set(obj, ((efl_input_text_input_content_type_get(obj) | EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) & ~EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA));
efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY);
}
@ -1891,19 +1857,8 @@ _efl_ui_textbox_efl_text_interactive_editable_set(Eo *obj, Efl_Ui_Textbox_Data *
efl_ui_widget_theme_apply(obj);
efl_ui_widget_focus_allow_set(obj, editable);
elm_drop_target_del(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
if (editable)
{
sd->drop_format = _get_drop_format(obj);
elm_drop_target_add(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
if (sd->cursor)
{
efl_gfx_entity_visible_set(sd->cursor, EINA_TRUE);
@ -1961,7 +1916,7 @@ _efl_ui_textbox_selection_cut(Eo *obj, Efl_Ui_Textbox_Data *sd)
/*In password mode, cut will remove text only*/
if (!efl_text_password_get(obj))
_selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj);
_selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj);
efl_text_interactive_selection_cursors_get(obj, &start, &end);
start_pos = efl_text_cursor_position_get(start);
@ -1993,25 +1948,27 @@ _efl_ui_textbox_selection_copy(Eo *obj, Efl_Ui_Textbox_Data *sd)
efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl");
efl_ui_widget_scroll_hold_pop(obj);
}
_selection_store(EFL_UI_SELECTION_TYPE_CLIPBOARD, obj);
_selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj);
efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_COPY, NULL);
}
static void
_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Selection_Type type)
_efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type)
{
Efl_Ui_Selection_Format formats = EFL_UI_SELECTION_FORMAT_TEXT | EFL_UI_SELECTION_FORMAT_MARKUP;
Eina_Future *future;
Eina_Array *types = _figure_out_types(obj, sd);
efl_ui_selection_get(obj, type, formats,
NULL, _selection_data_cb, NULL, 1);
future = efl_ui_selection_get(obj, type, 0, eina_array_iterator_new(types));
efl_future_then(obj, future, _selection_data_cb);
efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_PASTE, NULL);
eina_array_free(types);
}
EOLIAN static void
_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED)
_efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd)
{
_efl_ui_textbox_selection_paste_type(obj, EFL_UI_SELECTION_TYPE_CLIPBOARD);
_efl_ui_textbox_selection_paste_type(obj, sd, EFL_UI_CNP_BUFFER_COPY_AND_PASTE);
}
EOLIAN static void
@ -2028,44 +1985,15 @@ _efl_ui_textbox_context_menu_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textb
}
EOLIAN static void
_efl_ui_textbox_cnp_mode_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Selection_Format cnp_mode)
_efl_ui_textbox_cnp_dnd_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Efl_Ui_Textbox_Cnp_Content content)
{
Elm_Sel_Format dnd_format = EFL_UI_SELECTION_FORMAT_MARKUP;
if (cnp_mode != EFL_UI_SELECTION_FORMAT_TARGETS)
{
if (cnp_mode & EFL_UI_SELECTION_FORMAT_VCARD)
ERR("VCARD format not supported for copy & paste!");
else if (cnp_mode & EFL_UI_SELECTION_FORMAT_HTML)
ERR("HTML format not supported for copy & paste!");
cnp_mode &= ~EFL_UI_SELECTION_FORMAT_VCARD;
cnp_mode &= ~EFL_UI_SELECTION_FORMAT_HTML;
}
if (sd->cnp_mode == cnp_mode) return;
sd->cnp_mode = cnp_mode;
if (sd->cnp_mode == EFL_UI_SELECTION_FORMAT_TEXT)
dnd_format = EFL_UI_SELECTION_FORMAT_TEXT;
else if (cnp_mode == EFL_UI_SELECTION_FORMAT_IMAGE)
dnd_format |= EFL_UI_SELECTION_FORMAT_IMAGE;
elm_drop_target_del(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
sd->drop_format = dnd_format;
elm_drop_target_add(obj, sd->drop_format,
_dnd_enter_cb, NULL,
_dnd_leave_cb, NULL,
_dnd_pos_cb, NULL,
_dnd_drop_cb, NULL);
sd->content = content;
}
EOLIAN static Efl_Ui_Selection_Format
_efl_ui_textbox_cnp_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
EOLIAN static Efl_Ui_Textbox_Cnp_Content
_efl_ui_textbox_cnp_dnd_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
{
return sd->cnp_mode;
return sd->content;
}
EOLIAN static void
@ -3279,7 +3207,7 @@ _efl_ui_textbox_selection_changed_cb(void *data, const Efl_Event *event EINA_UNU
Eo *obj = data;
EFL_UI_TEXT_DATA_GET(obj, sd);
_edje_signal_emit(sd, "selection,changed", "efl.text");
_selection_store(EFL_UI_SELECTION_TYPE_PRIMARY, obj);
_selection_store(EFL_UI_CNP_BUFFER_SELECTION, obj);
_selection_defer(obj, sd);
}

View File

@ -1,3 +1,10 @@
enum Efl.Ui.Textbox_Cnp_Content {
Nothing = 0, [[You can paste or drop nothing]]
Text = 1, [[You can paste normal Text]]
Markup = 3, [[You can paste Markup (Normal text is also just markup)]]
Image = 4, [[You can paste Images]]
}
class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Clickable,
Efl.Access.Text, Efl.Access.Editable.Text
composites
@ -31,8 +38,7 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click
enabled: bool; [[$true to enable the contextual menu.]]
}
}
@property cnp_mode @beta {
/* FIXME: Efl.Ui.Selection_Format does not allow markup without images! */
@property cnp_dnd_mode @beta {
[[Control pasting of text and images for the widget.
Normally the entry allows both text and images to be pasted.
@ -44,7 +50,7 @@ class @beta Efl.Ui.Textbox extends Efl.Ui.Layout_Base implements Efl.Input.Click
get {
}
values {
format: Efl.Ui.Selection_Format; [[Format for copy & paste.]]
allowed_formats : Efl.Ui.Textbox_Cnp_Content; [[Format for cnp]]
}
}
@property selection_handles_enabled {

View File

@ -213,6 +213,9 @@ struct _Efl_Ui_Win_Data
int ignore_frame_resize;
Eina_Bool req_wh : 1;
Eina_Bool req_xy : 1;
Eina_Array *selection_changed;
Eina_Array *planned_changes;
Eina_Inarray *drop_target;
struct {
short pointer_move;
@ -382,6 +385,8 @@ static void _elm_win_frame_style_update(Efl_Ui_Win_Data *sd, Eina_Bool force_emi
static inline void _elm_win_need_frame_adjust(Efl_Ui_Win_Data *sd, const char *engine);
static void _elm_win_resize_objects_eval(Evas_Object *obj, Eina_Bool force_resize);
static void _elm_win_frame_obj_update(Efl_Ui_Win_Data *sd, Eina_Bool force);
static void _ee_backbone_init(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd);
static void _ee_backbone_shutdown(Efl_Ui_Win *obj, Efl_Ui_Win_Data *pd);
static inline Efl_Ui_Win_Type
_elm_win_type_to_efl_ui_win_type(Elm_Win_Type type)
@ -5933,6 +5938,7 @@ _efl_ui_win_efl_object_finalize(Eo *obj, Efl_Ui_Win_Data *sd)
efl_file_mmap_get(efl_super(efl_part(obj, "background"), EFL_UI_WIN_PART_CLASS)))
efl_file_load(efl_part(obj, "background"));
}
_ee_backbone_init(obj, sd);
return obj;
}
@ -5968,6 +5974,8 @@ _efl_ui_win_efl_object_destructor(Eo *obj, Efl_Ui_Win_Data *pd EINA_UNUSED)
if (pd->finalize_future)
eina_future_cancel(pd->finalize_future);
_ee_backbone_shutdown(obj, pd);
efl_destructor(efl_super(obj, MY_CLASS));
efl_unref(pd->provider);
@ -5984,6 +5992,7 @@ _efl_ui_win_efl_object_constructor(Eo *obj, Efl_Ui_Win_Data *pd)
pd->provider = efl_add_ref(EFL_UI_FOCUS_PARENT_PROVIDER_STANDARD_CLASS, NULL);
pd->profile.available = eina_array_new(4);
pd->max_w = pd->max_h = -1;
pd->planned_changes = eina_array_new(10);
// For bindings: if no parent, allow simple unref
if (!efl_parent_get(obj))
@ -9187,6 +9196,249 @@ elm_win_teamwork_uri_open(Efl_Ui_Win *obj EINA_UNUSED, const char *uri EINA_UNUS
ERR("Calling deprecrated function '%s'", __FUNCTION__);
}
/* What here follows is code that implements the glue between ecore evas and efl_ui* side */
typedef struct {
Eo *obj;
Eina_Bool currently_inside;
} Ui_Dnd_Target;
static inline Efl_Ui_Cnp_Buffer
_ui_buffer_get(Ecore_Evas_Selection_Buffer buffer)
{
if (buffer == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
return EFL_UI_CNP_BUFFER_SELECTION;
else if (buffer == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
return EFL_UI_CNP_BUFFER_COPY_AND_PASTE;
return -1;
}
void
_register_selection_changed(Efl_Ui_Selection *selection)
{
ELM_WIN_DATA_GET(efl_provider_find(selection, EFL_UI_WIN_CLASS), pd);
eina_array_push(pd->planned_changes, selection);
}
static Eina_Bool
_remove_object(void *data, void *gdata)
{
if (data == gdata)
return EINA_FALSE;
return EINA_TRUE;
}
static void
_selection_changed_cb(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer selection)
{
Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee);
Efl_Ui_Wm_Selection_Changed changed = {
.seat = seat,
.buffer = _ui_buffer_get(selection),
.caused_by = eina_array_count(pd->planned_changes) > 0 ? eina_array_data_get(pd->planned_changes, 0) : NULL,
};
for (unsigned int i = 0; i < eina_array_count(pd->selection_changed); ++i)
{
Eo *obj = eina_array_data_get(pd->selection_changed, i);
efl_event_callback_call(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, &changed);
}
if (changed.caused_by)
eina_array_remove(pd->planned_changes, _remove_object, changed.caused_by);
}
static void
_motion_cb(Ecore_Evas *ee, unsigned int seat, Eina_Position2D p)
{
Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee);
for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i)
{
Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i);
Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj);
Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y);
Efl_Ui_Drop_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)};
if (target->currently_inside && !inside)
{
target->currently_inside = EINA_FALSE;
efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEFT, &ev);
}
else if (!target->currently_inside && inside)
{
target->currently_inside = EINA_TRUE;
efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTERED, &ev);
}
else if (target->currently_inside && inside)
{
efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, &ev);
}
eina_accessor_free(ev.available_types);
}
}
static void
_enter_state_change_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, Eina_Bool move_inside)
{
Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee);
for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i)
{
Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i);
Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj);
Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y);
Efl_Ui_Drop_Event ev = {p, seat, ecore_evas_drop_available_types_get(ee, seat)};
if (inside && move_inside)
{
target->currently_inside = EINA_TRUE;
efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_ENTERED, &ev);
}
else if (!move_inside && !target->currently_inside)
{
target->currently_inside = EINA_FALSE;
efl_event_callback_call(target->obj, EFL_UI_DND_EVENT_DROP_LEFT, &ev);
}
}
}
static void
_drop_cb(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Position2D p, const char *action)
{
Eina_List *itr, *top_objects_list = NULL;
Efl_Ui_Win_Data *pd = _elm_win_associate_get(ee);
Eina_Array *tmp = eina_array_new(10);
Eo *top_obj;
for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i)
{
Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i);
Eina_Rect rect = efl_gfx_entity_geometry_get(target->obj);
Eina_Bool inside = eina_rectangle_coords_inside(&rect.rect, p.x, p.y);
if (inside)
{
EINA_SAFETY_ON_FALSE_GOTO(target->currently_inside, end);
eina_array_push(tmp, target->obj);
}
}
/* We retrieve the (non-smart) objects pointed by (px, py) */
top_objects_list = evas_tree_objects_at_xy_get(ecore_evas_get(ee), NULL, p.x, p.y);
/* We walk on this list from the last because if the list contains more than one
* element, all but the last will repeat events. The last one can repeat events
* or not. Anyway, this last one is the first that has to be taken into account
* for the determination of the drop target.
*/
EINA_LIST_REVERSE_FOREACH(top_objects_list, itr, top_obj)
{
Evas_Object *object = top_obj;
/* We search for the dropable data into the object. If not found, we search into its parent.
* For example, if a button is a drop target, the first object will be an (internal) image.
* The drop target is attached to the button, i.e to image's parent. That's why we need to
* walk on the parents until NULL.
* If we find this dropable data, we found our drop target.
*/
while (object)
{
unsigned int out_idx;
if (!eina_array_find(tmp, object, &out_idx))
{
object = evas_object_smart_parent_get(object);
}
else
{
Efl_Ui_Drop_Dropped_Event ev = {{p, seat, ecore_evas_drop_available_types_get(ee, seat)}, action};
efl_event_callback_call(object, EFL_UI_DND_EVENT_DROP_DROPPED, &ev);
goto end;
}
}
}
end:
eina_list_free(top_objects_list);
eina_array_free(tmp);
}
static void
_ee_backbone_init(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd)
{
pd->selection_changed = eina_array_new(1);
pd->drop_target = eina_inarray_new(sizeof(Ui_Dnd_Target), 1);
ecore_evas_callback_selection_changed_set(pd->ee, _selection_changed_cb);
ecore_evas_callback_drop_drop_set(pd->ee, _drop_cb);
ecore_evas_callback_drop_motion_set(pd->ee, _motion_cb);
ecore_evas_callback_drop_state_changed_set(pd->ee, _enter_state_change_cb);
}
static void
_ee_backbone_shutdown(Efl_Ui_Win *obj EINA_UNUSED, Efl_Ui_Win_Data *pd)
{
ecore_evas_callback_selection_changed_set(pd->ee, NULL);
ecore_evas_callback_drop_drop_set(pd->ee, NULL);
ecore_evas_callback_drop_motion_set(pd->ee, NULL);
ecore_evas_callback_drop_state_changed_set(pd->ee, NULL);
eina_array_free(pd->selection_changed);
pd->selection_changed = NULL;
eina_inarray_free(pd->drop_target);
pd->drop_target = NULL;
}
static Eina_Bool
_remove(void *data, void *gdata)
{
if (data == gdata)
return EINA_FALSE;
return EINA_TRUE;
}
void
_drop_event_register(Eo *obj)
{
Ui_Dnd_Target target = {obj, EINA_FALSE};
Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS);
EINA_SAFETY_ON_NULL_RETURN(pd);
eina_inarray_push(pd->drop_target, &target);
}
void
_drop_event_unregister(Eo *obj)
{
int idx = -1;
Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS);
for (unsigned int i = 0; i < eina_inarray_count(pd->drop_target); ++i)
{
Ui_Dnd_Target *target = eina_inarray_nth(pd->drop_target, i);
if (target->obj == obj)
{
//FIXME emit drop
target->currently_inside = EINA_FALSE;
idx = i;
}
}
if (idx != -1)
eina_inarray_remove_at(pd->drop_target, idx);
}
void
_selection_changed_event_register(Eo *obj)
{
Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS);
eina_array_push(pd->selection_changed, obj);
}
void
_selection_changed_event_unregister(Eo *obj)
{
Efl_Ui_Win_Data *pd = efl_data_scope_safe_get(efl_provider_find(obj, MY_CLASS), MY_CLASS);
eina_array_remove(pd->selection_changed, _remove, obj);
}
/* Internal EO APIs and hidden overrides */
ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_win, Efl_Ui_Win_Data)

View File

@ -0,0 +1,244 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include <Ecore_Evas.h>
#include "elm_priv.h"
#include "elm_entry_eo.h"
static inline Ecore_Evas_Selection_Buffer
_elm_sel_type_to_ee_type(Elm_Sel_Type type)
{
if (type == ELM_SEL_TYPE_PRIMARY)
return ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER;
if (type == ELM_SEL_TYPE_XDND)
return ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER;
if (type == ELM_SEL_TYPE_CLIPBOARD)
return ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER;
return ECORE_EVAS_SELECTION_BUFFER_LAST;
}
static inline Eina_Array*
_elm_sel_format_to_mime_type(Elm_Sel_Format format)
{
Eina_Array *ret = eina_array_new(10);
if (format & ELM_SEL_FORMAT_TEXT)
eina_array_push(ret, "text/plain;charset=utf-8");
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, "application/xhtml+xml");
if (eina_array_count(ret) == 0)
ERR("Specified mime type is not available");
return ret;
}
static inline const Elm_Sel_Format
_mime_type_to_elm_sel_format(const char *mime_type)
{
if (eina_streq(mime_type, "text/vcard"))
return ELM_SEL_FORMAT_VCARD;
else if (eina_streq(mime_type, "application/x-elementary-markup"))
return ELM_SEL_FORMAT_MARKUP;
else if (eina_streq(mime_type, "application/xhtml+xml"))
return ELM_SEL_FORMAT_HTML;
else if (!strncmp(mime_type, "text/", strlen("text/")))
return ELM_SEL_FORMAT_TEXT;
else if (!strncmp(mime_type, "image/", strlen("image/")))
return ELM_SEL_FORMAT_IMAGE;
return ELM_SEL_FORMAT_NONE;
}
static int
_default_seat(const Eo *obj)
{
return evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EFL_INPUT_DEVICE_TYPE_SEAT));
}
EAPI Eina_Bool
elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection,
Elm_Sel_Format format,
const void *buf, size_t buflen)
{
Eina_Content *content;
Ecore_Evas *ee;
const char *mime_type;
Eina_Slice data;
Eina_Array *tmp;
if (format == ELM_SEL_FORMAT_TEXT && ((char*)buf)[buflen - 1] != '\0')
{
data.mem = eina_memdup((unsigned char *)buf, buflen, EINA_TRUE);
data.len = buflen + 1;
}
else
{
data.mem = buf;
data.len = buflen;
}
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
tmp = _elm_sel_format_to_mime_type(format);
if (eina_array_count(tmp) != 1)
{
ERR("You cannot specify more than one format when setting selection");
}
mime_type = eina_array_data_get(tmp, 0);
content = eina_content_new(data, mime_type);
_register_selection_changed(obj);
return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), content);
}
EAPI Eina_Bool
elm_object_cnp_selection_clear(Evas_Object *obj,
Elm_Sel_Type selection)
{
Ecore_Evas *ee;
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
return ecore_evas_selection_set(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), NULL);
}
EAPI Eina_Bool
elm_cnp_clipboard_selection_has_owner(Evas_Object *obj)
{
Ecore_Evas *ee;
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
return ecore_evas_selection_exists(ee, _default_seat(obj), ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER);
}
typedef struct _Sel_Lost_Data Sel_Lost_Data;
struct _Sel_Lost_Data
{
const Evas_Object *obj;
Elm_Sel_Type type;
void *udata;
Elm_Selection_Loss_Cb loss_cb;
};
static void
_selection_changed_cb(void *data, const Efl_Event *ev)
{
Sel_Lost_Data *ldata = data;
Efl_Ui_Wm_Selection_Changed *changed = ev->info;
if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && ldata->type != ELM_SEL_TYPE_PRIMARY)
return;
if (changed->buffer == EFL_UI_CNP_BUFFER_COPY_AND_PASTE && ldata->type != ELM_SEL_TYPE_CLIPBOARD)
return;
if (ldata->obj == changed->caused_by)
return;
ldata->loss_cb(ldata->udata, ldata->type);
free(data);
efl_event_callback_del(ev->object, ev->desc, _selection_changed_cb, data);
}
EAPI void
elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type type, Elm_Selection_Loss_Cb func, const void *data)
{
Sel_Lost_Data *ldata = calloc(1, sizeof(Sel_Lost_Data));
if (!ldata) return;
ldata->obj = obj;
ldata->type = type;
ldata->udata = (void *)data;
ldata->loss_cb = func;
efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_changed_cb, ldata);
}
typedef struct {
Elm_Drop_Cb data_cb;
void *data;
Elm_Sel_Format format;
} Callback_Storage;
static Eina_Value
_callback_storage_deliver(Eo *obj, void *data, const Eina_Value value)
{
Callback_Storage *cb_storage = data;
Eina_Content *content = eina_value_to_content(&value);
Elm_Sel_Format format = _mime_type_to_elm_sel_format(eina_content_type_get(content));
Eina_Slice cdata;
cdata = eina_content_data_get(content);
Elm_Selection_Data d = { 0 };
d.data = eina_memdup((unsigned char*)cdata.bytes, cdata.len, EINA_FALSE);
d.len = cdata.len;
d.format = _mime_type_to_elm_sel_format(eina_content_type_get(content));
if (cb_storage->data_cb)
{
cb_storage->data_cb(cb_storage->data, obj, &d);
}
else
{
EINA_SAFETY_ON_FALSE_RETURN_VAL(format == ELM_SEL_FORMAT_TEXT || format == ELM_SEL_FORMAT_MARKUP || format == ELM_SEL_FORMAT_HTML, EINA_VALUE_EMPTY);
_elm_entry_entry_paste(obj, (const char *) d.data);
}
free(d.data);
return EINA_VALUE_EMPTY;
}
static Eina_Value
_callback_storage_error(Eo *obj EINA_UNUSED, void *data EINA_UNUSED, Eina_Error error)
{
ERR("Content cound not be received because of %s.", eina_error_msg_get(error));
return EINA_VALUE_EMPTY;
}
static void
_callback_storage_free(Eo *obj EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
{
free(data);
}
EAPI Eina_Bool
elm_cnp_selection_get(const Evas_Object *obj, Elm_Sel_Type selection,
Elm_Sel_Format format,
Elm_Drop_Cb data_cb, void *udata)
{
Ecore_Evas *ee;
Eina_Array *mime_types;
Eina_Future *future;
Callback_Storage *storage;
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
mime_types = _elm_sel_format_to_mime_type(format);
future = ecore_evas_selection_get(ee, _default_seat(obj), _elm_sel_type_to_ee_type(selection), eina_array_iterator_new(mime_types));
storage = calloc(1,sizeof(Callback_Storage));
storage->data_cb = data_cb;
storage->data = udata;
storage->format = format;
efl_future_then(obj, future, _callback_storage_deliver, _callback_storage_error, _callback_storage_free, EINA_VALUE_TYPE_CONTENT, storage);
return EINA_TRUE;
}

View File

@ -43,8 +43,6 @@
* @{
*/
# include <efl_ui_selection_types.eot.h>
/**
* Event notifying that the selection has changed
* @see Elm_Cnp_Event_Selection_Changed

View File

@ -0,0 +1,812 @@
#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), EFL_INPUT_DEVICE_TYPE_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(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_TEXT)
eina_array_push(ret, "text/plain;charset=utf-8");
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)
{
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 (!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;
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);
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 (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, y, w, h;
Efl_Ui_Widget *widget;
Elm_Drag_Data *dd;
const char *str_action;
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_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;
}

View File

@ -708,7 +708,7 @@ _selection_data_cb(void *data EINA_UNUSED,
char *entry_tag;
int len;
static const char *tag_string =
"<item absize=240x180 href=file://%s></item>";
"<item absize=240x180 href=%s></item>";
len = strlen(tag_string) + strlen(buf);
entry_tag = alloca(len + 1);
@ -1628,7 +1628,7 @@ _selection_store(Elm_Sel_Type seltype,
if ((!sel) || (!sel[0])) return; /* avoid deleting our own selection */
elm_cnp_selection_set
(obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel));
(obj, seltype, ELM_SEL_FORMAT_MARKUP, sel, strlen(sel) + 1);
elm_cnp_selection_loss_callback_set(obj, seltype, _selection_clear, obj);
if (seltype == ELM_SEL_TYPE_CLIPBOARD)
eina_stringshare_replace(&sd->cut_sel, sel);
@ -1731,7 +1731,7 @@ _menu_call(Evas_Object *obj)
const char *context_menu_orientation;
Eina_Bool ownersel;
ownersel = elm_selection_selection_has_owner(obj);
ownersel = elm_cnp_clipboard_selection_has_owner(obj);
if (!sd->items)
{
/* prevent stupid blank hoversel */

View File

@ -910,7 +910,6 @@ elm_quicklaunch_sub_shutdown(void)
_elm_module_shutdown();
if (_elm_prefs_initted)
_elm_prefs_shutdown();
_efl_ui_dnd_shutdown();
elm_color_class_shutdown();
}

View File

@ -165,7 +165,6 @@
# include "efl_ui_focus_parent_provider.eo.h"
# include "efl_ui_focus_parent_provider_standard.eo.h"
# include "efl_ui_selection_manager.eo.h"
# include "efl_datetime_manager.eo.h"
extern const char *_efl_model_property_itemw;
@ -668,9 +667,6 @@ void _elm_prefs_data_init(void);
void _elm_prefs_data_shutdown(void);
/* init functions for dnd and cnp */
Eo* _efl_ui_selection_manager_get(Eo *obj);
void _efl_ui_dnd_shutdown(void);
int _elm_ews_wm_init(void);
void _elm_ews_wm_shutdown(void);
void _elm_ews_wm_rescale(Elm_Theme *th,
@ -1060,4 +1056,10 @@ typedef struct
Efl_Ui_Shared_Win_Data* efl_ui_win_shared_data_get(Efl_Ui_Win *win);
void _selection_changed_event_register(Eo *obj);
void _selection_changed_event_unregister(Eo *obj);
void _drop_event_register(Eo *obj);
void _drop_event_unregister(Eo *obj);
void _register_selection_changed(Efl_Ui_Selection *selection);
#endif

View File

@ -142,7 +142,6 @@ pub_eo_files = [
'elm_code_widget.eo',
'efl_ui_selection.eo',
'efl_ui_dnd.eo',
'efl_ui_dnd_container.eo',
'efl_ui_focus_manager_window_root.eo',
'efl_ui_spotlight_container.eo',
'efl_ui_spotlight_manager.eo',
@ -210,8 +209,6 @@ endforeach
pub_eo_types_files = [
'elm_general.eot',
'efl_ui.eot',
'efl_ui_selection_types.eot',
'efl_ui_dnd_types.eot'
]
foreach eo_file : pub_eo_types_files
@ -235,7 +232,6 @@ priv_eo_files = [
'efl_ui_focus_parent_provider.eo',
'efl_ui_focus_parent_provider_standard.eo',
'efl_ui_state_model.eo',
'efl_ui_selection_manager.eo',
'efl_datetime_manager.eo',
'efl_ui_size_model.eo',
'efl_ui_homogeneous_model.eo',
@ -785,6 +781,8 @@ elementary_src = [
'elm_icon.c',
'efl_ui_image.c',
'elm_index.c',
'elm_cnp.c',
'elm_dnd.c',
'efl_access_object.c',
'efl_access_action.c',
'efl_access_component.c',
@ -907,7 +905,6 @@ elementary_src = [
'efl_ui_scroller.c',
'efl_ui_scroll_manager.c',
'efl_ui_pan.c',
'efl_ui_selection_manager.c',
'efl_ui_selection_manager_private.h',
'efl_ui_selection.c',
'efl_datetime_manager.c',

View File

@ -60,6 +60,8 @@ struct @extern Eina.Matrix3 {
zz: double; [[ZZ value.]]
}
struct @extern Eina.Content;
struct @extern Eina.Matrix4 {
[[A bidimensional array of floating point values with 4 rows and 4 columns.

View File

@ -120,6 +120,21 @@ _efl_gfx_image_load_error_to_evas_load_error(Eina_Error err)
return EVAS_LOAD_ERROR_GENERIC;
}
static Eina_Content*
_markup_to_utf8(Eina_Content *from, const char *to_type)
{
Eina_Slice slice = eina_content_data_get(from);
char *utf8 = evas_textblock_text_markup_to_utf8(NULL, slice.mem);
return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(utf8), to_type);
}
static Eina_Content*
_utf8_to_markup(Eina_Content *from, const char *to_type)
{
Eina_Slice slice = eina_content_data_get(from);
char *markup = evas_textblock_text_utf8_to_markup(NULL, slice.mem);
return eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(markup), to_type);
}
EAPI int
evas_init(void)
@ -179,6 +194,9 @@ evas_init(void)
_efl_gfx_image_load_error_init();
eina_content_converter_conversion_register("application/x-elementary-markup", "text/plain;charset=utf-8", _markup_to_utf8);
eina_content_converter_conversion_register("text/plain;charset=utf-8", "application/x-elementary-markup", _utf8_to_markup);
return _evas_init_count;
shutdown_filter:

View File

@ -44,6 +44,12 @@ EFL_START_TEST(text_cnp)
}
EFL_END_TEST
static void
_stop_event_soon(void *data EINA_UNUSED, const Efl_Event *ev)
{
efl_event_callback_stop(ev->object);
}
EFL_START_TEST(text_all_select_all_unselect)
{
Eo *txt;
@ -57,7 +63,7 @@ EFL_START_TEST(text_all_select_all_unselect)
efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED,
increment_int_changed, &i_selection)
);
efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL);
efl_text_set(txt, "Hello");
efl_text_interactive_all_select(txt);
Efl_Text_Cursor *c1=NULL, *c2 =NULL;
@ -122,6 +128,7 @@ EFL_START_TEST(text_selection)
Eo *win = win_add();
txt = efl_add(EFL_UI_TEXTBOX_CLASS, win);
efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL);
efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300));
efl_text_set(txt, "Hello");
get_me_to_those_events(txt);
@ -160,7 +167,7 @@ EFL_START_TEST(text_user_change)
txt = efl_add(EFL_UI_TEXTBOX_CLASS, win,
efl_event_callback_add(efl_added, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, user_changed, &info)
);
efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL);
efl_text_set(txt, "Hello");
efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300));
efl_text_interactive_all_select(txt);
@ -177,6 +184,7 @@ EFL_START_TEST(text_scroll_mode)
Eo *txt, *win, *cur;
win = win_add();
txt = efl_add(EFL_UI_TEXTBOX_CLASS, win);
efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL);
cur = efl_text_interactive_main_cursor_get(txt);
efl_text_set(txt, "Hello");
/*scroll mode is false by default*/
@ -199,6 +207,7 @@ EFL_START_TEST(text_change_event)
Eo *win = win_add();
txt = efl_add(EFL_UI_TEXTBOX_CLASS, win);
efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL);
efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300));
efl_text_set(txt, "Hello");
int i_changed = 0;
@ -223,6 +232,7 @@ EFL_START_TEST(text_keys_handler)
Eo *win = win_add();
txt = efl_add(EFL_UI_TEXTBOX_CLASS, win);
efl_event_callback_priority_add(txt, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, EFL_CALLBACK_PRIORITY_BEFORE, _stop_event_soon, NULL);
efl_gfx_entity_size_set(txt, EINA_SIZE2D(300, 300));
efl_text_set(txt, "Hello");