From b509f97696fff8174a5bc5aca96e726f131316bd Mon Sep 17 00:00:00 2001 From: Thiep Ha Date: Tue, 12 Apr 2016 20:44:48 +0900 Subject: [PATCH] Add copy and paste UI Copy and paste UI which includes copy and paste popup, selection handlers, cursor handler, and releated funcions are added. The copy and paste UI works in the same maner as in Tizen 2.4. @tizen_feature Change-Id: I47d73079b53af1058ec627ace9db4abb8c0fb659 Signed-off-by: Thiep Ha --- configure.ac | 1 + src/lib/elm_entry.c | 1509 ++++++++++++++++++++- src/lib/elm_module_priv.h | 52 + src/lib/elm_widget_entry.h | 15 + src/modules/Makefile.am | 3 +- src/modules/copypasteUI_ctxpopup/Makefile.am | 24 + src/modules/copypasteUI_ctxpopup/cbhm_helper.c | 341 +++++ src/modules/copypasteUI_ctxpopup/cbhm_helper.h | 38 + src/modules/copypasteUI_ctxpopup/copypaste.c | 1711 ++++++++++++++++++++++++ 9 files changed, 3643 insertions(+), 51 deletions(-) create mode 100644 src/lib/elm_module_priv.h create mode 100644 src/modules/copypasteUI_ctxpopup/Makefile.am create mode 100644 src/modules/copypasteUI_ctxpopup/cbhm_helper.c create mode 100644 src/modules/copypasteUI_ctxpopup/cbhm_helper.h create mode 100644 src/modules/copypasteUI_ctxpopup/copypaste.c diff --git a/configure.ac b/configure.ac index ce12b18..1058ec1 100644 --- a/configure.ac +++ b/configure.ac @@ -498,6 +498,7 @@ src/bin/Makefile src/modules/Makefile src/modules/prefs/Makefile src/modules/access_output/Makefile +src/modules/copypasteUI_ctxpopup/Makefile src/modules/datetime_input_ctxpopup/Makefile src/modules/test_entry/Makefile src/modules/test_map/Makefile diff --git a/src/lib/elm_entry.c b/src/lib/elm_entry.c index 916d026..bcab530 100644 --- a/src/lib/elm_entry.c +++ b/src/lib/elm_entry.c @@ -10,6 +10,7 @@ #include #include "elm_priv.h" #include "elm_widget_entry.h" +#include "elm_module_priv.h" #define MY_CLASS ELM_ENTRY_CLASS @@ -83,9 +84,671 @@ struct _Mod_Api void (*obj_hook)(Evas_Object *obj); void (*obj_unhook)(Evas_Object *obj); void (*obj_longpress)(Evas_Object *obj); + // TIZEN ONLY (20150205): Support CopyPasteUI + void (*obj_hidemenu) (Evas_Object *obj); + void (*obj_mouseup) (Evas_Object *obj); + void (*obj_update_popup_pos) (Evas_Object *obj); + Eina_Bool (*obj_popup_showing_get) (Evas_Object *obj); + // }; -static void _create_selection_handlers(Evas_Object *obj, Elm_Entry_Data *sd); +static void _create_selection_handlers(Evas_Object *obj, Elm_Entry_Data *sd); + +///////////////////////////////////////////////////////////////// +// TIZEN ONLY : START +// 20150129: Add more control when drop happens. +// 20150129: Add drag feature. +// 20150201: Add cursor handler. +// 20150205: Add support for CopyPaste module. +// 20150310: Hide cbhm when unfocus. +// 20150807: Apply user stye in drag and drop +// 20150811: Apply scale in drag and drop +// 20150820: Adjust end of line cursor to prevent zero selection +// 20150829: Keep selection over text only on long press and move +// 20150909: Update cursor position on mouse up, not mouse down (with edje) +// 20151012: Modify scale in drag and drop +///////////////////////////////////////////////////////////////// + +static void _magnifier_create(void *data); +static void _magnifier_show(void *data); +static void _magnifier_hide(void *data); +static void _magnifier_move(void *data, Evas_Coord x, Evas_Coord y); +static void _menu_call(Evas_Object *obj); +static void _hover_cancel_cb(void *data, Evas_Object *obj, void *event_info); +static void _copy_cb(void *data, Evas_Object *obj, void *event_info); +static void _cut_cb(void *data, Evas_Object *obj, void *event_info); +static void _paste_cb(void *data, Evas_Object *obj, void *event_info); +static Eina_Rectangle *_viewport_region_get(Evas_Object *obj); +static Evas_Coord_Rectangle _layout_region_get(Evas_Object *obj); + +static inline Eina_Iterator * +_selection_range_geometry_get(Evas_Object *obj) +{ + ELM_ENTRY_DATA_GET(obj, sd); + + Eina_Iterator *range = NULL; + Evas_Coord start_pos, end_pos; + Evas_Textblock_Cursor *start_cur = NULL, *end_cur = NULL; + const Evas_Object *tb = NULL; + + start_pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, + "elm.text", EDJE_CURSOR_SELECTION_BEGIN); + end_pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, + "elm.text", EDJE_CURSOR_SELECTION_END); + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + start_cur = evas_object_textblock_cursor_new(tb); + evas_textblock_cursor_pos_set(start_cur, start_pos); + end_cur = evas_object_textblock_cursor_new(tb); + evas_textblock_cursor_pos_set(end_cur, end_pos); + + range = evas_textblock_cursor_range_simple_geometry_get( + start_cur, end_cur); + + evas_textblock_cursor_free(start_cur); + evas_textblock_cursor_free(end_cur); + + return range; +} + +static Evas_Coord_Rectangle +_selection_geometry_get(Evas_Object *obj) +{ + Evas_Coord_Rectangle rect; + Eina_Iterator *range = NULL; + Evas_Textblock_Rectangle *r = NULL; + Evas_Coord min_x = 0, min_y = 0, max_x = 0, max_y = 0; + Evas_Coord xo = 0, yo = 0; + int i = 0; + + ELM_ENTRY_DATA_GET(obj, sd); + evas_object_geometry_get(edje_object_part_object_get + (sd->entry_edje, "elm.text"), + &xo, &yo, NULL, NULL); + range = _selection_range_geometry_get(obj); + EINA_ITERATOR_FOREACH(range, r) + { + if (i == 0) + { + min_x = r->x; + min_y = r->y; + } + if (r->x < min_x) min_x = r->x; + if (r->y < min_y) min_y = r->y; + if ((r->x + r->w) > max_x) + max_x = r->x + r->w; + if ((r->y + r->h) > max_y) + max_y = r->y + r->h; + i++; + } + eina_iterator_free(range); + + rect.x = min_x + xo; + rect.y = min_y + yo; + rect.w = max_x - min_x; + rect.h = max_y - min_y; + + return rect; +} + +static Eina_Bool +_hit_selection_check(Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + Eina_Iterator *range = NULL; + Evas_Textblock_Rectangle *r = NULL; + Eina_Bool hit = EINA_FALSE; + Evas_Coord xo = 0, yo = 0; + + ELM_ENTRY_DATA_GET(obj, sd); + evas_object_geometry_get(edje_object_part_object_get + (sd->entry_edje, "elm.text"), + &xo, &yo, NULL, NULL); + x -= xo; + y -= yo; + range = _selection_range_geometry_get(obj); + EINA_ITERATOR_FOREACH(range, r) + { + if ((x >= r->x) && (x <= r->x + r->w) && + (y >= r->y) && (y <= r->y + r->h)) + { + hit = EINA_TRUE; + break; + } + } + eina_iterator_free(range); + + return hit; +} + +static Evas_Object * +_entry_icon_create_cb(void *data, Evas_Object *parent, Evas_Coord *xoff, Evas_Coord *yoff) +{ + int xm, ym; + Evas_Object *icon; + int r, g, b, a; + const char *text; + Evas_Coord margin_w = 0, margin_h = 0; + Evas_Coord_Rectangle rect; + ELM_ENTRY_DATA_GET(data, sd); + + icon = evas_object_textblock_add(evas_object_evas_get(parent)); + text = edje_object_part_text_selection_get(sd->entry_edje, "elm.text"); + + evas_object_color_get(data, &r, &g, &b, &a); + evas_object_color_set(icon, r, g, b, a); + + // Copy style + Evas_Textblock_Style *tb_style = + (Evas_Textblock_Style *)evas_object_textblock_style_get + (elm_entry_textblock_get(data)); + evas_object_textblock_style_set(icon, tb_style); + + Evas_Textblock_Style *tb_style_user = + (Evas_Textblock_Style *)evas_object_textblock_style_user_peek + (elm_entry_textblock_get(data)); + if (tb_style_user) + { + const char *tb_style_text; + tb_style_text = evas_textblock_style_get(tb_style_user); + tb_style_user = evas_textblock_style_new(); + evas_textblock_style_set(tb_style_user, tb_style_text); + evas_object_textblock_style_user_push(icon, tb_style_user); + evas_textblock_style_free(tb_style_user); + } + + evas_object_scale_set(icon, + elm_config_scale_get() + * elm_object_scale_get(data) + / edje_object_base_scale_get(sd->entry_edje)); + + evas_object_textblock_size_formatted_get(icon, &margin_w, &margin_h); + evas_object_textblock_text_markup_set(icon, text); + + rect = _selection_geometry_get(data); + + evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_move(icon, rect.x, rect.y); + evas_object_resize(icon, rect.w + margin_w, rect.h + margin_h); + evas_object_show(icon); + + evas_pointer_canvas_xy_get(evas_object_evas_get(data), &xm, &ym); + if (xoff) *xoff = xm - (rect.w / 2); + if (yoff) *yoff = ym - (rect.h / 2); + + return icon; +} + +static void +_dnd_enter_cb(void *data, + Evas_Object *obj EINA_UNUSED) +{ + elm_object_focus_set(data, EINA_TRUE); +} + +static void +_dnd_leave_cb(void *data, + Evas_Object *obji EINA_UNUSED) +{ + if (_elm_config->desktop_entry) + elm_object_focus_set(data, EINA_FALSE); +} + +static void +_dnd_pos_cb(void *data, Evas_Object *obj EINA_UNUSED, Evas_Coord x, Evas_Coord y, + Elm_Xdnd_Action action EINA_UNUSED) +{ + elm_object_focus_set(data, EINA_TRUE); + + ELM_ENTRY_DATA_GET(data, sd); + + Evas_Coord ox, oy, ex, ey; + evas_object_geometry_get(obj, &ox, &oy, NULL, NULL); + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + x = x + ox - ex; + y = y + oy - ey; + + edje_object_part_text_cursor_coord_set + (sd->entry_edje, "elm.text", EDJE_CURSOR_USER, x, y); + int pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_USER); + elm_entry_cursor_pos_set(data, pos); +} + + +static Eina_Bool +_cursor_handler_long_press_cb(void *data) +{ + ELM_ENTRY_DATA_GET(data, sd); + + Evas_Coord ex, ey; + Evas_Coord cx, cy, cw, ch; + + edje_object_part_text_cursor_geometry_get(sd->entry_edje, "elm.text", + &cx, &cy, &cw, &ch); + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + if (sd->has_text) + { + _magnifier_create(data); + _magnifier_show(data); + _magnifier_move(data, ex + cx, ey + cy); + } + sd->cursor_handler_longpress_timer = NULL; + + return ECORE_CALLBACK_CANCEL; +} + +static void +_cursor_handler_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + ELM_ENTRY_DATA_GET(data, sd); + + Evas_Event_Mouse_Down *ev = event_info; + Evas_Coord ex, ey; + Evas_Coord cx, cy, cw, ch; + + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + sd->cursor_handler_down = EINA_TRUE; + edje_object_part_text_cursor_geometry_get(sd->entry_edje, "elm.text", + &cx, &cy, &cw, &ch); + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + sd->ox = ev->canvas.x - (ex + cx + (cw / 2)); + sd->oy = ev->canvas.y - (ey + cy + (ch / 2)); + if (_elm_config->magnifier_enable) + { + sd->cursor_handler_down_pos = sd->cursor_pos; + + ELM_SAFE_FREE(sd->cursor_handler_longpress_timer, ecore_timer_del); + sd->cursor_handler_longpress_timer = ecore_timer_add + (_elm_config->longpress_timeout, _cursor_handler_long_press_cb, data); + + } +} + +static void +_cursor_handler_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + ELM_ENTRY_DATA_GET(data, sd); + + if (!sd->cursor_handler_down) return; + + ELM_SAFE_FREE(sd->cursor_handler_longpress_timer, ecore_timer_del); + sd->cursor_handler_down = EINA_FALSE; + if (_elm_config->magnifier_enable) + _magnifier_hide(data); + if (!_elm_config->desktop_entry) + _menu_call(data); +} + +static void +_cursor_handler_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + ELM_ENTRY_DATA_GET(data, sd); + + Evas_Event_Mouse_Move *ev = event_info; + Evas_Coord ex, ey; + Evas_Coord cx, cy, cw, ch, chx, chy, chh; + Evas_Coord lh, th; + const Evas_Textblock *tb; + Evas_Textblock_Cursor *cur; + Evas_Coord_Rectangle layrect; + int pos = 0; + + if (!sd->cursor_handler_down) return; + pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN); + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + evas_object_textblock_size_formatted_get(tb, NULL, &th); + cur = evas_object_textblock_cursor_new((Evas_Object *)tb); + evas_textblock_cursor_pos_set(cur, pos); + evas_textblock_cursor_line_geometry_get(cur, NULL, NULL, NULL, &lh); + evas_textblock_cursor_free(cur); + + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + cx = ev->cur.canvas.x - sd->ox - ex; + cy = ev->cur.canvas.y - sd->oy - ey; + if (cx <= 0) cx = 1; + if (cy < (lh / 2)) cy = lh / 2; + if (cy >= th) cy = th - 1; + + edje_object_part_text_cursor_coord_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_USER, cx, cy); + pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_USER); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN, pos); + + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + edje_object_part_text_cursor_geometry_get(sd->entry_edje, "elm.text", + &cx, &cy, &cw, &ch); + chx = ex + cx + (cw / 2); + chy = ey + cy + ch; + evas_object_move(sd->cursor_handler, chx, chy); + layrect = _layout_region_get(data); + edje_object_parts_extends_calc(sd->cursor_handler, NULL, NULL, NULL, &chh); + if (chy + chh > layrect.y + layrect.h) + { + evas_object_move(sd->cursor_handler, chx, chy - ch); + edje_object_signal_emit(sd->cursor_handler, "edje,cursor,handle,top", "edje"); + } + else + { + edje_object_signal_emit(sd->cursor_handler, "edje,cursor,handle,show", "edje"); + } + edje_object_message_signal_process(sd->cursor_handler); + + if (_elm_config->magnifier_enable) + { + if (sd->has_text) + { + if (sd->cursor_handler_down_pos != sd->cursor_pos) + { + if (sd->cursor_handler_longpress_timer) + { + ELM_SAFE_FREE(sd->cursor_handler_longpress_timer, ecore_timer_del); + _magnifier_create(data); + _magnifier_show(data); + } + _magnifier_move(data, ex + cx, ey + cy); + } + } + } +} + +static void +_create_cursor_handler(Evas_Object *obj, Elm_Entry_Data *sd) +{ + if (sd->cursor_handler) return; + Evas_Object *handle; + + handle = edje_object_add(evas_object_evas_get(obj)); + sd->cursor_handler = handle; + _elm_theme_object_set(obj, handle, "entry", "cursor_handle", "default"); + evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_DOWN, + _cursor_handler_mouse_down_cb, obj); + evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_MOVE, + _cursor_handler_mouse_move_cb, obj); + evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_UP, + _cursor_handler_mouse_up_cb, obj); + evas_object_layer_set(handle, EVAS_LAYER_MAX - 1); + edje_object_signal_emit(handle, "edje,cursor,handle,show", "edje"); // FOR 2.3 theme +} + +static void +_update_cursor_handler(Evas_Object *obj, Elm_Entry_Data *sd) +{ + Evas_Coord ex, ey; + Evas_Coord cx, cy, cw, ch, chx, chy, chh; + Evas_Coord_Rectangle layrect; + Eina_Rectangle *rect; + + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + edje_object_part_text_cursor_geometry_get(sd->entry_edje, "elm.text", + &cx, &cy, &cw, &ch); + chx = ex + cx + (cw / 2); + chy = ey + cy + ch; + evas_object_move(sd->cursor_handler, chx, chy); + layrect = _layout_region_get(obj); + edje_object_parts_extends_calc(sd->cursor_handler, NULL, NULL, NULL, &chh); + if (chy + chh > layrect.y + layrect.h) + { + evas_object_move(sd->cursor_handler, chx, chy - ch); + edje_object_signal_emit(sd->cursor_handler, "edje,cursor,handle,top", "edje"); + } + else + { + edje_object_signal_emit(sd->cursor_handler, "edje,cursor,handle,show", "edje"); + } + edje_object_message_signal_process(sd->cursor_handler); + + rect = _viewport_region_get(obj); + if (!eina_rectangle_xcoord_inside(rect, chx) || + !eina_rectangle_ycoord_inside(rect, chy)) + { + evas_object_hide(sd->cursor_handler); + } + else + { + evas_object_show(sd->cursor_handler); + } +} + +static void +_select_all(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + ELM_ENTRY_DATA_GET(data, sd); + + sd->sel_mode = EINA_TRUE; + + if (edje_object_part_text_selection_get(sd->entry_edje, "elm.text") == NULL) + { + edje_object_part_text_select_none(sd->entry_edje, "elm.text"); + edje_object_signal_emit(sd->entry_edje, "elm,state,select,on", "elm"); + edje_object_part_text_select_all(sd->entry_edje, "elm.text"); + } + else + { + edje_object_part_text_cursor_begin_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + edje_object_part_text_cursor_begin_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END); + edje_object_part_text_cursor_end_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN); + edje_object_part_text_select_extend(sd->entry_edje, "elm.text"); + } + sd->have_selection = EINA_TRUE; + _menu_call(data); +} + +static void +_adjust_eol_cursor(Evas_Object *obj) +{ + const Evas_Object *tb = NULL; + Evas_Textblock_Cursor *c = NULL; + Eina_Bool eol; + + ELM_ENTRY_DATA_GET(obj, sd); + + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + c = evas_object_textblock_cursor_get(tb); + eol = evas_textblock_cursor_eol_get(c); + if (eol) + { + Evas_Textblock_Cursor *cp; + Evas_Coord ly, lpy; + + cp = evas_object_textblock_cursor_new(tb); + evas_textblock_cursor_copy(c, cp); + evas_textblock_cursor_cluster_prev(cp); + evas_textblock_cursor_line_geometry_get(c, NULL, &ly, NULL, NULL); + evas_textblock_cursor_line_geometry_get(cp, NULL, &lpy, NULL, NULL); + if (ly != lpy) + evas_textblock_cursor_cluster_prev(c); + evas_textblock_cursor_free(cp); + } +} + +static Eina_Bool +_cursor_coordinate_check(Evas_Object *obj, Evas_Coord canvasx) +{ + const Evas_Textblock *tb = NULL; + const Evas_Textblock_Cursor *c = NULL; + Evas_Coord x, cx, clx = 0, clw = 0; + + ELM_ENTRY_DATA_GET(obj, sd); + + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + c = evas_object_textblock_cursor_get(tb); + evas_object_geometry_get(tb, &x, NULL, NULL, NULL); + evas_textblock_cursor_line_geometry_get(c, &clx, NULL, &clw, NULL); + cx = canvasx - x; + + if ((cx < clx) || (cx > (clx + clw))) + { + return EINA_FALSE; + } + else + { + return EINA_TRUE; + } +} + +static void +_cursor_down_pos_set(Evas_Object *obj) +{ + Evas_Coord ex, ey, cx, cy; + ELM_ENTRY_DATA_GET(obj, sd); + + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + cx = sd->downx - ex; + cy = sd->downy - ey; + edje_object_part_text_cursor_coord_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN, cx, cy); +} + +static void +_select_word(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + ELM_ENTRY_DATA_GET(data, sd); + + const Evas_Object *tb = NULL; + Evas_Textblock_Cursor *cur = NULL; + int pos = 0; + + sd->sel_mode = EINA_TRUE; + + _adjust_eol_cursor(data); + + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_TRUE); + edje_object_signal_emit(sd->entry_edje, "elm,state,select,on", "elm"); + + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + cur = evas_object_textblock_cursor_new(tb); + pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, + "elm.text", EDJE_CURSOR_MAIN); + sd->cursor_move_pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN); + evas_textblock_cursor_pos_set(cur, pos); + evas_textblock_cursor_word_start(cur); + pos = evas_textblock_cursor_pos_get(cur); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN, pos); + edje_object_part_text_select_begin(sd->entry_edje, "elm.text"); + evas_textblock_cursor_word_end(cur); + evas_textblock_cursor_char_next(cur); + pos = evas_textblock_cursor_pos_get(cur); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN, pos); + edje_object_part_text_select_extend(sd->entry_edje, "elm.text"); + evas_textblock_cursor_free(cur); + + if (edje_object_part_text_selection_get(sd->entry_edje, "elm.text")) + sd->have_selection = EINA_TRUE; + if (!sd->long_pressed || event_info) + _menu_call(data); + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_FALSE); +} + +static void +_keep_selection(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + ELM_ENTRY_DATA_GET(obj, sd); + + sd->start_sel_pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, + "elm.text", EDJE_CURSOR_SELECTION_BEGIN); + sd->end_sel_pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, + "elm.text", EDJE_CURSOR_SELECTION_END); +} + +static void +_paste_translation(void *data, Evas_Object *obj, void *event_info) +{ + ELM_ENTRY_DATA_GET(obj, sd); + + elm_entry_cursor_pos_set(obj, sd->start_sel_pos); + elm_entry_cursor_selection_begin(obj); + elm_entry_cursor_pos_set(obj, sd->end_sel_pos); + elm_entry_cursor_selection_end(obj); + if (data) + _elm_entry_entry_paste(obj, data); + if ((data) && (event_info)) + _elm_entry_entry_paste(obj, " "); + if (event_info) + _elm_entry_entry_paste(obj, event_info); +} + +static void +_is_selected_all(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + if ((!data) || (!obj)) return; + ELM_ENTRY_DATA_GET(obj, sd); + int pos = 0; + Eina_Bool *ret = (Eina_Bool *)data; + + pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_USER, pos); + if (edje_object_part_text_cursor_prev(sd->entry_edje, "elm.text", + EDJE_CURSOR_USER)) + { + *ret = EINA_FALSE; + return; + } + else + { + pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_USER, pos); + if (edje_object_part_text_cursor_next(sd->entry_edje, "elm.text", + EDJE_CURSOR_USER)) + { + *ret = EINA_FALSE; + return; + } + } + *ret = EINA_TRUE; +} + +EAPI void elm_entry_extension_module_data_get(Evas_Object *obj, Elm_Entry_Extension_data *ext_mod) +{ + ELM_ENTRY_DATA_GET(obj, sd); + + ext_mod->cancel = _hover_cancel_cb; + ext_mod->copy = _copy_cb; + ext_mod->cut = _cut_cb; + ext_mod->paste = _paste_cb; + ext_mod->select = _select_word; + ext_mod->selectall = _select_all; + ext_mod->ent = sd->entry_edje; + ext_mod->items = sd->items; + ext_mod->editable = sd->editable; + ext_mod->have_selection = sd->have_selection; + ext_mod->password = sd->password; + ext_mod->selmode = sd->sel_mode; + ext_mod->context_menu = sd->context_menu; + ext_mod->cnp_mode = sd->cnp_mode; + ext_mod->_elm_config = _elm_config; + ext_mod->viewport_rect = _viewport_region_get(obj); + ext_mod->selection_rect = _selection_geometry_get(obj); + ext_mod->keep_selection = _keep_selection; + ext_mod->paste_translation = _paste_translation; + ext_mod->is_selected_all = _is_selected_all; + ext_mod->start_handler = sd->start_handler; + ext_mod->end_handler = sd->end_handler; + ext_mod->cursor_handler = sd->cursor_handler; + ext_mod->cursor_handler_shown = sd->cursor_handler_shown; + ext_mod->ent_scroll = sd->scroll; +} +///////////////////////////////////////////////////////////////// +// TIZEN ONLY : END +///////////////////////////////////////////////////////////////// + static Mod_Api * _module_find(Evas_Object *obj EINA_UNUSED) @@ -104,6 +767,17 @@ _module_find(Evas_Object *obj EINA_UNUSED) _elm_module_symbol_get(m, "obj_unhook"); ((Mod_Api *)(m->api))->obj_longpress = // called on long press menu _elm_module_symbol_get(m, "obj_longpress"); + // TIZEN ONLY (20150205): Support CopyPasteUI + ((Mod_Api *)(m->api))->obj_hidemenu = // called on hide menu + _elm_module_symbol_get(m, "obj_hidemenu"); + ((Mod_Api *)(m->api))->obj_mouseup = // called on mouseup + _elm_module_symbol_get(m, "obj_mouseup"); + ((Mod_Api *)(m->api))->obj_update_popup_pos = //in update selection handler + _elm_module_symbol_get(m, "obj_update_popup_pos"); + ((Mod_Api *)(m->api))->obj_popup_showing_get = // check cnp popup showing status + _elm_module_symbol_get(m, "obj_popup_showing_get"); + // + ok: // ok - return api return m->api; } @@ -411,12 +1085,18 @@ _hide_selection_handler(Evas_Object *obj) if (sd->start_handler_shown) { - edje_object_signal_emit(sd->start_handler, "elm,handler,hide", "elm"); + // TIZEN ONLY (20150901): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->start_handler, "elm,handler,hide", "elm");*/ + evas_object_hide(sd->start_handler); + // sd->start_handler_shown = EINA_FALSE; } if (sd->end_handler_shown) { - edje_object_signal_emit(sd->end_handler, "elm,handler,hide", "elm"); + // TIZEN ONLY (20150901): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->end_handler, "elm,handler,hide", "elm");*/ + evas_object_hide(sd->end_handler); + // sd->end_handler_shown = EINA_FALSE; } } @@ -454,26 +1134,61 @@ _viewport_region_get(Evas_Object *obj) return rect; } +// TIZEN ONLY (20150723): Show sel handler on top +static Evas_Coord_Rectangle +_layout_region_get(Evas_Object *obj) +{ + Evas_Coord_Rectangle r; + Evas_Object *child = NULL, *parent = NULL; + + r.x = r.y = r.w = r.h = -1; + if (!obj || !elm_widget_type_get(obj)) return r; + + child = obj; + parent = elm_widget_parent_get(obj); + while (parent) + { + const char *wt = elm_widget_type_get(parent); + if (wt && !strcmp(wt, "Elm_Conformant")) + { + evas_object_geometry_get(child, &r.x, &r.y, &r.w, &r.h); + return r; + } + child = parent; + parent = elm_widget_parent_get(parent); + } + return r; +} +// + static void _update_selection_handler(Evas_Object *obj) { ELM_ENTRY_DATA_GET(obj, sd); - Evas_Coord sx, sy, sh; + Evas_Coord sx, sy, sw, sh; Evas_Coord ent_x, ent_y; - Evas_Coord ex, ey, eh; + Evas_Coord ex, ey, ew, eh; int start_pos, end_pos, last_pos; - if (!sd->sel_handler_disabled) - { + // TIZEN ONLY (20150603): CopyPasteUI Tizen 2.4 + //if ((!sd->sel_handler_disabled)) + if ((!sd->sel_handler_disabled) && ((!evas_object_visible_get(sd->mgf_bg)) || + (sd->start_handler_down || sd->end_handler_down))) + {// Eina_Rectangle *rect; - Evas_Coord hx, hy; + Evas_Coord_Rectangle layrect; + Evas_Coord hx, hy, hh; Eina_Bool hidden = EINA_FALSE; if (!sd->start_handler) _create_selection_handlers(obj, sd); rect = _viewport_region_get(obj); + // TIZEN ONLY (20150723): Show sel handler on top + layrect = _layout_region_get(obj); + edje_object_parts_extends_calc(sd->start_handler, NULL, NULL, NULL, &hh); + // start_pos = edje_object_part_text_cursor_pos_get (sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_BEGIN); end_pos = edje_object_part_text_cursor_pos_get @@ -485,11 +1200,11 @@ _update_selection_handler(Evas_Object *obj) edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN, start_pos); edje_object_part_text_cursor_geometry_get(sd->entry_edje, "elm.text", - &sx, &sy, NULL, &sh); + &sx, &sy, &sw, &sh); edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN, end_pos); edje_object_part_text_cursor_geometry_get(sd->entry_edje, "elm.text", - &ex, &ey, NULL, &eh); + &ex, &ey, &ew, &eh); edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN, last_pos); if (start_pos < end_pos) @@ -504,6 +1219,21 @@ _update_selection_handler(Evas_Object *obj) hy = ent_y + ey + eh; evas_object_move(sd->start_handler, hx, hy); } + // TIZEN ONLY (20150901): Show start sel handler on top by default + if (ent_y + sy - hh < layrect.y) + { + hy--; + edje_object_signal_emit(sd->start_handler, "elm,state,bottom", "elm"); + } + else + { + edje_object_signal_emit(sd->start_handler, "elm,state,top", "elm"); + hy = hy - sh; + evas_object_move(sd->start_handler, hx, hy); + } + edje_object_message_signal_process(sd->start_handler); + // + if (!eina_rectangle_xcoord_inside(rect, hx) || !eina_rectangle_ycoord_inside(rect, hy)) { @@ -511,14 +1241,20 @@ _update_selection_handler(Evas_Object *obj) } if (!sd->start_handler_shown && !hidden) { - edje_object_signal_emit(sd->start_handler, - "elm,handler,show", "elm"); + // TIZEN ONLY (20140204): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->start_handler, + "elm,handler,show", "elm");*/ + evas_object_show(sd->start_handler); + // sd->start_handler_shown = EINA_TRUE; } else if (sd->start_handler_shown && hidden) { - edje_object_signal_emit(sd->start_handler, - "elm,handler,hide", "elm"); + // TIZEN ONLY (20140204): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->start_handler, + "elm,handler,hide", "elm");*/ + evas_object_hide(sd->start_handler); + // sd->start_handler_shown = EINA_FALSE; } @@ -535,6 +1271,21 @@ _update_selection_handler(Evas_Object *obj) hy = ent_y + sy + sh; evas_object_move(sd->end_handler, hx, hy); } + // TIZEN ONLY (20150723): Show sel handler on top + if (hy + hh > layrect.y + layrect.h) + { + edje_object_signal_emit(sd->end_handler, "elm,state,top", "elm"); + hy = hy - sh; + evas_object_move(sd->end_handler, hx, hy); + } + else + { + hy--; + edje_object_signal_emit(sd->end_handler, "elm,state,bottom", "elm"); + } + edje_object_message_signal_process(sd->end_handler); + // + if (!eina_rectangle_xcoord_inside(rect, hx) || !eina_rectangle_ycoord_inside(rect, hy)) { @@ -542,14 +1293,20 @@ _update_selection_handler(Evas_Object *obj) } if (!sd->end_handler_shown && !hidden) { - edje_object_signal_emit(sd->end_handler, - "elm,handler,show", "elm"); + // TIZEN ONLY (20140204): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->end_handler, + "elm,handler,show", "elm");*/ + evas_object_show(sd->end_handler); + // sd->end_handler_shown = EINA_TRUE; } else if (sd->end_handler_shown && hidden) { - edje_object_signal_emit(sd->end_handler, - "elm,handler,hide", "elm"); + // TIZEN ONLY (20140204): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->end_handler, + "elm,handler,hide", "elm");*/ + evas_object_hide(sd->end_handler); + // sd->end_handler_shown = EINA_FALSE; } eina_rectangle_free(rect); @@ -558,17 +1315,38 @@ _update_selection_handler(Evas_Object *obj) { if (sd->start_handler_shown) { - edje_object_signal_emit(sd->start_handler, - "elm,handler,hide", "elm"); + // TIZEN ONLY (20150901): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->start_handler, + "elm,handler,hide", "elm");*/ + evas_object_hide(sd->start_handler); + // sd->start_handler_shown = EINA_FALSE; } if (sd->end_handler_shown) { - edje_object_signal_emit(sd->end_handler, - "elm,handler,hide", "elm"); + // TIZEN ONLY (20140204): Support tizen 2.4 CNPUI + /*edje_object_signal_emit(sd->end_handler, + "elm,handler,hide", "elm");*/ + evas_object_hide(sd->end_handler); + // sd->end_handler_shown = EINA_FALSE; } } + // TIZEN ONLY (20150201): Add cursor handler + if (sd->cursor_handler_shown) + { + evas_object_hide(sd->cursor_handler); + sd->cursor_handler_shown = EINA_FALSE; + } + // + // TIZEN ONLY (20150522): update cnp popup position + if ((sd->api) && (sd->api->obj_update_popup_pos) && + (!sd->start_handler_down) && (!sd->end_handler_down) && + (!sd->cursor_handler_down)) + { + sd->api->obj_update_popup_pos(obj); + } + // } static const char * @@ -733,11 +1511,19 @@ _get_drop_format(Evas_Object *obj) EOLIAN static Eina_Bool _elm_entry_elm_widget_disable(Eo *obj, Elm_Entry_Data *sd) { - elm_drop_target_del(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_del(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_del(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// if (elm_object_disabled_get(obj)) { edje_object_signal_emit(sd->entry_edje, "elm,state,disabled", "elm"); @@ -758,11 +1544,19 @@ _elm_entry_elm_widget_disable(Eo *obj, Elm_Entry_Data *sd) } sd->disabled = EINA_FALSE; sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_add(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_add(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// } return EINA_TRUE; @@ -1191,7 +1985,13 @@ _elm_entry_elm_widget_on_focus(Eo *obj, Elm_Entry_Data *sd, Elm_Object_Item *ite eo_do(obj, eo_event_callback_call(ELM_WIDGET_EVENT_UNFOCUSED, NULL)); if (_elm_config->atspi_mode) elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE); - + // TIZEN ONLY (20150201): Add cursor handler + if (sd->cursor_handler_shown) + { + evas_object_hide(sd->cursor_handler); + sd->cursor_handler_shown = EINA_FALSE; + } + // if (_elm_config->selection_clear_enable) { if ((sd->have_selection) && (!sd->hoversel)) @@ -1788,16 +2588,107 @@ _long_press_cb(void *data) { ELM_ENTRY_DATA_GET(data, sd); - if (_elm_config->magnifier_enable) + // TIZEN ONLY: START //////////////////////////////////////////// + if (!elm_widget_focus_get(data)) { - _magnifier_create(data); - _magnifier_show(data); - _magnifier_move(data, sd->downx, sd->downy); + sd->longpress_timer = NULL; + return ECORE_CALLBACK_CANCEL; } - else if (!_elm_config->desktop_entry) - _menu_call(data); + // 20150229: Add drag feature. + Eina_Bool hit_selection = EINA_FALSE; sd->long_pressed = EINA_TRUE; + sd->long_pressing = EINA_TRUE; + if (sd->cursor_handler_shown) + { + evas_object_hide(sd->cursor_handler); + sd->cursor_handler_shown = EINA_FALSE; + } + hit_selection = _hit_selection_check(data, sd->downx, sd->downy); + + if (!hit_selection) + { + sd->drag_started = EINA_FALSE; + } + else if (!sd->password) + { + const char *sel = + edje_object_part_text_selection_get(sd->entry_edje, "elm.text"); + + if ((sel) && (sel[0])) + { + sd->drag_started = EINA_TRUE; + elm_drag_start(data, ELM_SEL_FORMAT_TEXT, + sel, + ELM_XDND_ACTION_COPY, + _entry_icon_create_cb, data, + NULL, /*Elm_Drag_Pos dragpos*/ + NULL, /*void *dragdata*/ + NULL, /*Elm_Drag_Accept acceptcb*/ + NULL, /*void *acceptdata*/ + NULL, /*Elm_Drag_Done dragdone*/ + NULL); /*void *donecbdata*/ + _hover_cancel_cb(data, NULL, NULL); + elm_widget_scroll_freeze_push(data); + } + } + if (!sd->drag_started) //TIZEN ONLY : END + { + if (_elm_config->magnifier_enable) + { + // TIZEN ONLY (20150205): CopyPasteUI 2.4 + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + // + + // TIZEN ONLY (20150603): CopyPasteUI 2.4 + if (sd->has_text) + { + // TIZEN_ONLY (20150829): Keep selection over text only + if (_cursor_coordinate_check(data, sd->downx)) + { + _cursor_down_pos_set(data); + _magnifier_create(data); + _magnifier_show(data); + //_magnifier_move(data, sd->downx, sd->downy); + Evas_Coord cx, cy, cw, ch; + Evas_Coord ex, ey; + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); + edje_object_part_text_cursor_geometry_get(sd->entry_edje, + "elm.text", &cx, &cy, &cw, &ch); + _magnifier_move(data, ex + cx, ey + cy); + // do select word + _select_word(data, NULL, NULL); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_MAIN, sd->cursor_move_pos); + // + } + // + } + // + } + //TIZEN_ONLY (20150806): Enable word selection when magnifier is disabled + else if (sd->has_text) + { + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + _cursor_down_pos_set(data); + if (_cursor_coordinate_check(data, sd->downx)) + { + _select_word(data, NULL, NULL); + elm_widget_scroll_freeze_push(data); + } + if (!_elm_config->desktop_entry) + { + _menu_call(data); + } + } + // + else if (!_elm_config->desktop_entry) + _menu_call(data); + } + + //sd->long_pressed = EINA_TRUE; sd->longpress_timer = NULL; eo_do(data, eo_event_callback_call @@ -1814,6 +2705,11 @@ _key_down_cb(void *data, { Evas_Event_Key_Down *ev = event_info; + // TIZEN ONLY (20150205): Support CopyPasteUI + ELM_ENTRY_DATA_GET(data, sd); + if ((sd->api) && (sd->api->obj_hidemenu) && (!sd->sel_mode)) + sd->api->obj_hidemenu(data); + // if (!strcmp(ev->key, "Menu")) _menu_call(data); } @@ -1866,10 +2762,41 @@ _mouse_up_cb(void *data, if (ev->button == 1) { ELM_SAFE_FREE(sd->longpress_timer, ecore_timer_del); - if ((sd->long_pressed) && (_elm_config->magnifier_enable)) + // TIZEN ONLY (20150717): For selection clear on mouse up + sd->long_pressing = EINA_FALSE; + if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK) return; + if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) return; + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; + if (!_elm_config->desktop_entry && sd->have_selection && !sd->long_pressed) + elm_entry_select_none(data); + // + //TIZEN_ONLY (20150806): Enable word selection when magnifier is disabled + //if ((sd->long_pressed) && (_elm_config->magnifier_enable)) + // { + // _magnifier_hide(data); + if (sd->long_pressed) { - _magnifier_hide(data); - _menu_call(data); + if (_elm_config->magnifier_enable) + _magnifier_hide(data); + // + // TIZEN ONLY (20150603): CopyPasteUI 2.4 + Eina_Bool popup_showing = EINA_FALSE; + if (elm_widget_scroll_freeze_get(data)) + elm_widget_scroll_freeze_pop(data); + if (sd->have_selection) + { + if (elm_widget_focus_get(data)) + _update_selection_handler(data); + else + elm_entry_select_none(data); + } + if ((sd->api) && (sd->api->obj_popup_showing_get)) + popup_showing = sd->api->obj_popup_showing_get(data); + if (!popup_showing) + { + _menu_call(data); + } + // } else { @@ -1883,7 +2810,40 @@ _mouse_up_cb(void *data, !edje_object_part_text_imf_context_get(sd->entry_edje, "elm.text")) elm_win_keyboard_mode_set(top, ELM_WIN_KEYBOARD_ON); } + // TIZEN ONY (20150603): CopyPaste 2.4 + if (sd->editable && elm_widget_focus_get(data) && + (!sd->have_selection) && (sd->has_text)) + { + Evas_Coord dx, dy; + + dx = sd->downx - ev->canvas.x; + dx *= dx; + dy = sd->downy - ev->canvas.y; + dy *= dy; + if ((dx + dy) <= + ((_elm_config->finger_size / 2) * + (_elm_config->finger_size / 2))) + { + _create_cursor_handler(data, sd); + _update_cursor_handler(data, sd); + evas_object_show(sd->cursor_handler); + sd->cursor_handler_shown = EINA_TRUE; + } + else if (sd->cursor_handler_shown) + { + evas_object_hide(sd->cursor_handler); + sd->cursor_handler_shown = EINA_FALSE; + } + } + // + } + // TIZEN ONLY (20150729): Freeze scrolling on draging + if (sd->drag_started) + { + elm_widget_scroll_freeze_pop(data); + sd->drag_started = EINA_FALSE; } + // } else if ((ev->button == 3) && (!_elm_config->desktop_entry)) { @@ -1905,15 +2865,40 @@ _mouse_move_cb(void *data, if (sd->disabled) return; if (ev->buttons == 1) { - if ((sd->long_pressed) && (_elm_config->magnifier_enable)) + // TIZEN ONLY: START /////////////////////////////////////// + // 20150129: Add drag feature. + /*if ((sd->long_pressed) && (_elm_config->magnifier_enable))*/ + if ((sd->long_pressed) && (!sd->drag_started)) + // TIZEN ONLY: END ///////////////////////////////////////// { Evas_Coord x, y; Eina_Bool rv; evas_object_geometry_get(sd->entry_edje, &x, &y, NULL, NULL); + // TIZEN ONLY (20150716): for easy movement in single line + Evas_Coord cury; + const Evas_Object *tb = NULL; + Evas_Textblock_Cursor *tc; + Evas_Coord fy = 0, fh = 0, ly = 0, lh = 0; + + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + tc = evas_object_textblock_cursor_new(tb); + evas_textblock_cursor_paragraph_first(tc); + evas_textblock_cursor_line_geometry_get(tc, NULL, &fy, NULL, &fh); + evas_textblock_cursor_paragraph_last(tc); + evas_textblock_cursor_line_geometry_get(tc, NULL, &ly, NULL, &lh); + evas_textblock_cursor_free(tc); + cury = ev->cur.canvas.y - y; + if (cury < fy + fh / 2) cury = fy + fh / 2; + if (cury > ly + lh) cury = ly + lh - 1; rv = edje_object_part_text_cursor_coord_set (sd->entry_edje, "elm.text", EDJE_CURSOR_USER, - ev->cur.canvas.x - x, ev->cur.canvas.y - y); + ev->cur.canvas.x - x, cury); + /*rv = edje_object_part_text_cursor_coord_set + (sd->entry_edje, "elm.text", EDJE_CURSOR_USER, + ev->cur.canvas.x - x, ev->cur.canvas.y - y);*/ + // + if (rv) { edje_object_part_text_cursor_copy @@ -1921,8 +2906,26 @@ _mouse_move_cb(void *data, } else WRN("Warning: Cannot move cursor"); - - _magnifier_move(data, ev->cur.canvas.x, ev->cur.canvas.y); + // TIZEN_ONLY (20150829): Keep selection over text only + if (_cursor_coordinate_check(data, ev->cur.canvas.x)) + { + // TIZEN ONLY (20150603): Support CopyPasteUI + if ((sd->has_text) && (_elm_config->magnifier_enable)) + { + //_magnifier_move(data, ev->cur.canvas.x, ev->cur.canvas.y); + Evas_Coord cx, cy, cw, ch; + edje_object_part_text_cursor_geometry_get(sd->entry_edje, + "elm.text", &cx, &cy, &cw, &ch); + _magnifier_move(data, x + cx, y + cy); + } + //do select word + int cur_pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN); + if (cur_pos != sd->cursor_move_pos) + _select_word(data, NULL, NULL); + // + } + // } } if (!sd->sel_mode) @@ -1973,6 +2976,33 @@ _entry_changed_handle(void *data, ELM_ENTRY_DATA_GET(data, sd); + // TIZEN ONLY(20150815): feature: remove mgf, popup, handlers if entry changed + if (sd->cursor_handler_down || sd->start_handler_down || + sd->end_handler_down || sd->long_pressed) + { + if (sd->cursor_handler_down) + sd->cursor_handler_down = EINA_FALSE; + else if (sd->start_handler_down) + sd->start_handler_down = EINA_FALSE; + else if (sd->end_handler_down) + sd->end_handler_down = EINA_FALSE; + else if (sd->long_pressed) + sd->long_pressed = EINA_FALSE; + if (_elm_config->magnifier_enable) + { + if (sd->has_text) + _magnifier_hide(data); + } + } + else if (sd->longpress_timer) + { + ELM_SAFE_FREE(sd->longpress_timer, ecore_timer_del); + // TIZEN_ONLY(20150924): Renew longpress timer when entry is changed. + sd->longpress_timer = ecore_timer_add + (_elm_config->longpress_timeout, _long_press_cb, data); + // + } + // evas_event_freeze(evas_object_evas_get(data)); sd->changed = EINA_TRUE; /* Reset the size hints which are no more relevant. Keep the @@ -2002,6 +3032,18 @@ _entry_changed_handle(void *data, else _elm_entry_guide_update(data, EINA_FALSE); } + + // TIZEN ONLY (20150205): Support CopyPasteUI + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + // + // TIZEN ONLY (20150201): Add cursor handler + if (sd->cursor_handler_shown) + { + evas_object_hide(sd->cursor_handler); + sd->cursor_handler_shown = EINA_FALSE; + } + // _validate(data); /* callback - this could call callbacks that delete the @@ -2129,6 +3171,12 @@ _entry_selection_none_signal_cb(void *data, const char *source EINA_UNUSED) { elm_entry_select_none(data); + + // TIZEN ONLY (20150205): Support CopyPasteUI + ELM_ENTRY_DATA_GET(data, sd); + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + // } static void @@ -2158,6 +3206,13 @@ _entry_selection_cleared_signal_cb(void *data, if (!sd->have_selection) return; + // TIZEN ONLY (20150205): Support CopyPasteUI + if (!sd->long_pressing) + { + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + } + // sd->have_selection = EINA_FALSE; eo_do(data, eo_event_callback_call (EVAS_SELECTABLE_INTERFACE_EVENT_SELECTION_CLEARED, NULL)); @@ -2170,7 +3225,11 @@ _entry_selection_cleared_signal_cb(void *data, ELM_SAFE_FREE(sd->cut_sel, eina_stringshare_del); } - else + // TIZEN ONLY: START /////////////////////////////////////// + // 20150129: Add drag feature. + /*else*/ + else if (!sd->drag_started) + // TIZEN ONLY: END ///////////////////////////////////////// { elm_object_cnp_selection_clear(data, ELM_SEL_TYPE_PRIMARY); } @@ -2255,6 +3314,13 @@ _entry_cursor_changed_manual_signal_cb(void *data, (ELM_ENTRY_EVENT_CURSOR_CHANGED_MANUAL, NULL)); if (_elm_config->atspi_mode) eo_do(ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN, elm_interface_atspi_accessible_event_emit(data, ELM_INTERFACE_ATSPI_TEXT_EVENT_ACCESS_TEXT_CARET_MOVED, NULL)); + // TIZEN ONLY (20150715): update cursor handler when cursor pos changes + ELM_ENTRY_DATA_GET(data, sd); + if (sd->cursor_handler_shown) + { + _update_cursor_handler(data, sd); + } + // } static void @@ -2552,6 +3618,16 @@ _entry_mouse_double_signal_cb(void *data, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) { + // TIZEN ONLY (20140205): Support CopyPaste UI + ELM_ENTRY_DATA_GET(data, sd); + if (sd->disabled) return; //??? + + if (!_elm_config->desktop_entry) + { + _cursor_down_pos_set(data); + _select_word(data, NULL, NULL); + } + // eo_do(data, eo_event_callback_call (EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED_DOUBLE, NULL)); } @@ -3248,6 +4324,13 @@ _start_handler_mouse_down_cb(void *data, Evas_Coord cx, cy, cw, ch; int start_pos, end_pos, main_pos, pos; + // TIZEN ONLY (20150205): Support CopyPasteUI + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_TRUE); + // sd->start_handler_down = EINA_TRUE; start_pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_BEGIN); @@ -3293,10 +4376,59 @@ _start_handler_mouse_up_cb(void *data, ELM_ENTRY_DATA_GET(data, sd); sd->start_handler_down = EINA_FALSE; + + // TIZEN ONLY(20150815): feature: remove mgf, popup, handlers if entry changed + int start_pos, end_pos; + Eina_Bool hidden = EINA_FALSE; + + start_pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_BEGIN); + end_pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_END); + if (start_pos < end_pos) + { + if (!sd->start_handler_shown) + hidden = EINA_TRUE; + } + else + { + if (!sd->end_handler_shown) + hidden = EINA_TRUE; + } + + if (hidden) + { + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_FALSE); + return; + } + // + // TIZEN ONLY (20150720): Keep at least one character in selection + int pos1 = 0, pos2 = 0; + pos1 = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + pos2 = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END); + if (pos1 > pos2) + { + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN, pos2); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END, pos1); + } + // if (_elm_config->magnifier_enable) _magnifier_hide(data); - if ((!_elm_config->desktop_entry) && (sd->long_pressed)) + // TIZEN ONLY (20150205): Support CopyPaste UI + /*if ((!_elm_config->desktop_entry) && (sd->long_pressed)) + _menu_call(data);*/ + if (!_elm_config->desktop_entry) _menu_call(data); + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_FALSE); + // } static void @@ -3313,15 +4445,58 @@ _start_handler_mouse_move_cb(void *data, Evas_Coord cx, cy, ch; int pos; + // TIZEN ONLY(20150815): feature: remove mgf, popup, handlers if entry changed + if (!sd->start_handler_shown) + { + ELM_SAFE_FREE(sd->longpress_timer, ecore_timer_del); + sd->long_pressed = EINA_FALSE; + return; + } + // + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); cx = ev->cur.canvas.x - sd->ox - ex; cy = ev->cur.canvas.y - sd->oy - ey; if (cx <= 0) cx = 1; + // TIZEN ONLY (20150715): for easy movement in single line + const Evas_Object *tb = NULL; + Evas_Textblock_Cursor *tc; + Evas_Coord fy = 0, fh = 0, ly = 0, lh = 0; + + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + tc = evas_object_textblock_cursor_new(tb); + evas_textblock_cursor_paragraph_first(tc); + evas_textblock_cursor_line_geometry_get(tc, NULL, &fy, NULL, &fh); + evas_textblock_cursor_paragraph_last(tc); + evas_textblock_cursor_line_geometry_get(tc, NULL, &ly, NULL, &lh); + evas_textblock_cursor_free(tc); + if (cy < fy + fh / 2) cy = fy + fh / 2; + else if (cy > ly + lh) cy = ly + lh - 1; + // + edje_object_part_text_cursor_coord_set(sd->entry_edje, "elm.text", sd->sel_handler_cursor, cx, cy); pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", sd->sel_handler_cursor); + // TIZEN ONLY (20150720): Keep at least one character in selection + int pos1 = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END); + if (pos == pos1) + { + pos++; + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN, pos); + pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + if (pos == pos1) + { + pos--; + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN, pos); + } + } + // edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN, pos); edje_object_part_text_cursor_geometry_get(sd->entry_edje, @@ -3346,6 +4521,13 @@ _end_handler_mouse_down_cb(void *data, Evas_Coord cx, cy, cw, ch; int pos, start_pos, end_pos, main_pos; + // TIZEN ONLY (20150205): Support CopyPasteUI + if ((sd->api) && (sd->api->obj_hidemenu)) + sd->api->obj_hidemenu(data); + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_TRUE); + // sd->end_handler_down = EINA_TRUE; start_pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_BEGIN); @@ -3392,10 +4574,58 @@ _end_handler_mouse_up_cb(void *data, ELM_ENTRY_DATA_GET(data, sd); sd->end_handler_down = EINA_FALSE; + // TIZEN ONLY(20150815): feature: remove mgf, popup, handlers if entry changed + int start_pos, end_pos; + Eina_Bool hidden = EINA_FALSE; + + start_pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_BEGIN); + end_pos = edje_object_part_text_cursor_pos_get + (sd->entry_edje, "elm.text", EDJE_CURSOR_SELECTION_END); + if (start_pos < end_pos) + { + if (!sd->end_handler_shown) + hidden = EINA_TRUE; + } + else + { + if (!sd->start_handler_shown) + hidden = EINA_TRUE; + } + + if (hidden) + { + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_FALSE); + return; + } + // + // TIZEN ONLY (20150720): Keep at least one character in selection + int pos1 = 0, pos2 = 0; + pos1 = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + pos2 = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END); + if (pos1 > pos2) + { + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN, pos2); + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END, pos1); + } + // if (_elm_config->magnifier_enable) _magnifier_hide(data); - if ((!_elm_config->desktop_entry) && (sd->long_pressed)) + // TIZEN ONLY (20150205): Support CopyPaste UI + /*if ((!_elm_config->desktop_entry) && (sd->long_pressed)) + _menu_call(data);*/ + if (!_elm_config->desktop_entry) _menu_call(data); + if (!_elm_config->desktop_entry) + edje_object_part_text_select_allow_set(sd->entry_edje, "elm.text", + EINA_FALSE); + // } static void @@ -3412,15 +4642,53 @@ _end_handler_mouse_move_cb(void *data, Evas_Coord cx, cy, ch; int pos; + // TIZEN ONLY(20150815): feature: remove mgf, popup, handlers if entry changed + if (!sd->end_handler_shown) + { + ELM_SAFE_FREE(sd->longpress_timer, ecore_timer_del); + sd->long_pressed = EINA_FALSE; + return; + } + // + evas_object_geometry_get(sd->entry_edje, &ex, &ey, NULL, NULL); cx = ev->cur.canvas.x - sd->ox - ex; cy = ev->cur.canvas.y - sd->oy - ey; if (cx <= 0) cx = 1; + // TIZEN ONLY (20150715): for easy movement in single line + const Evas_Object *tb = NULL; + Evas_Textblock_Cursor *tc; + Evas_Coord fy = 0, fh = 0, ly = 0, lh = 0; + + tb = edje_object_part_object_get(sd->entry_edje, "elm.text"); + tc = evas_object_textblock_cursor_new(tb); + evas_textblock_cursor_paragraph_first(tc); + evas_textblock_cursor_line_geometry_get(tc, NULL, &fy, NULL, &fh); + evas_textblock_cursor_paragraph_last(tc); + evas_textblock_cursor_line_geometry_get(tc, NULL, &ly, NULL, &lh); + evas_textblock_cursor_free(tc); + if (cy < fy + fh / 2) cy = fy + fh / 2; + if (cy > ly + lh) cy = ly + lh - 1; + // + edje_object_part_text_cursor_coord_set(sd->entry_edje, "elm.text", sd->sel_handler_cursor, cx, cy); pos = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", sd->sel_handler_cursor); + // TIZEN ONLY (20150720): Keep at least one character in selection + int pos1 = edje_object_part_text_cursor_pos_get(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + if (pos == pos1) + { + if (pos > 0) + pos--; + else + pos++; + edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", + EDJE_CURSOR_SELECTION_END, pos); + } + // edje_object_part_text_cursor_pos_set(sd->entry_edje, "elm.text", EDJE_CURSOR_MAIN, pos); edje_object_part_text_cursor_geometry_get(sd->entry_edje, @@ -3449,11 +4717,19 @@ _elm_entry_evas_object_smart_add(Eo *obj, Elm_Entry_Data *priv) priv->editable = EINA_TRUE; priv->drop_format = ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_IMAGE; - elm_drop_target_add(obj, priv->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_add(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_add(obj, priv->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// if (!elm_layout_theme_set(obj, "entry", "base", elm_widget_style_get(obj))) CRI("Failed to set layout!"); @@ -3591,6 +4867,8 @@ _elm_entry_evas_object_smart_add(Eo *obj, Elm_Entry_Data *priv) if (_elm_config->desktop_entry) priv->sel_handler_disabled = EINA_TRUE; + + priv->cursor_handler_shown = EINA_FALSE; // TIZEN ONLY (20150201) } static void @@ -3602,6 +4880,11 @@ _create_selection_handlers(Evas_Object *obj, Elm_Entry_Data *sd) handle = edje_object_add(evas_object_evas_get(obj)); sd->start_handler = handle; _elm_theme_object_set(obj, handle, "entry", "handler/start", style); + // TIZEN ONLY(20150605): support tizen theme + edje_object_signal_emit(handle, "edje,focus,in", "edje"); + edje_object_signal_emit(handle, "elm,state,bottom", "elm"); + sd->start_handler_shown = EINA_TRUE; + // evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_DOWN, _start_handler_mouse_down_cb, obj); evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_MOVE, @@ -3613,6 +4896,12 @@ _create_selection_handlers(Evas_Object *obj, Elm_Entry_Data *sd) handle = edje_object_add(evas_object_evas_get(obj)); sd->end_handler = handle; _elm_theme_object_set(obj, handle, "entry", "handler/end", style); + // TIZEN ONLY(20150605): support tizen theme + edje_object_signal_emit(handle, "edje,focus,in", "edje"); + //edje_object_signal_emit(handle, "elm,state,top", "elm"); + edje_object_signal_emit(handle, "elm,state,bottom", "elm"); + sd->end_handler_shown = EINA_TRUE; + // evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_DOWN, _end_handler_mouse_down_cb, obj); evas_object_event_callback_add(handle, EVAS_CALLBACK_MOUSE_MOVE, @@ -3696,9 +4985,44 @@ _elm_entry_evas_object_smart_del(Eo *obj, Elm_Entry_Data *sd) evas_object_del(sd->end_handler); } + // TIZEN ONLY (20150201): Add cursor handler + if (sd->cursor_handler) + { + evas_object_del(sd->cursor_handler); + } + // + // TIZEN ONLY (20150721): use job to get correct parent's gometry + if (sd->sel_handler_update_job) + ecore_job_del(sd->sel_handler_update_job); + if (sd->cursor_handler_update_job) + ecore_job_del(sd->cursor_handler_update_job); + // + eo_do_super(obj, MY_CLASS, evas_obj_smart_del()); } +// TIZEN ONLY (20150721): use job to get correct parent's gometry +static void +_sel_handler_update_job_cb(void *data) +{ + Evas_Object *obj = data; + + ELM_ENTRY_DATA_GET(obj, sd); + sd->sel_handler_update_job = NULL; + _update_selection_handler(obj); +} + +static void +_cursor_handler_update_job_cb(void *data) +{ + Evas_Object *obj = data; + + ELM_ENTRY_DATA_GET(obj, sd); + sd->cursor_handler_update_job = NULL; + _update_cursor_handler(obj, sd); +} +// + EOLIAN static void _elm_entry_evas_object_smart_move(Eo *obj, Elm_Entry_Data *sd, Evas_Coord x, Evas_Coord y) { @@ -3709,7 +5033,25 @@ _elm_entry_evas_object_smart_move(Eo *obj, Elm_Entry_Data *sd, Evas_Coord x, Eva if (sd->hoversel) _hoversel_position(obj); if (edje_object_part_text_selection_get(sd->entry_edje, "elm.text")) - _update_selection_handler(obj); + { + _update_selection_handler(obj); + // TIZEN ONLY (20150721): use job to get correct parent's gometry + if (sd->sel_handler_update_job) + ecore_job_del(sd->sel_handler_update_job); + sd->sel_handler_update_job = + ecore_job_add(_sel_handler_update_job_cb, obj); + // + } + // TIZEN ONLY (20150306): Update cursor handler + if (sd->cursor_handler_shown) + { + _update_cursor_handler(obj, sd); + if (sd->cursor_handler_update_job) + ecore_job_del(sd->cursor_handler_update_job); + sd->cursor_handler_update_job = + ecore_job_add(_cursor_handler_update_job_cb, obj); + } + // } EOLIAN static void @@ -3719,7 +5061,15 @@ _elm_entry_evas_object_smart_resize(Eo *obj, Elm_Entry_Data *sd, Evas_Coord w, E evas_object_resize(sd->hit_rect, w, h); if (sd->have_selection) - _update_selection_handler(obj); + { + _update_selection_handler(obj); + // TIZEN ONLY (20150721): use job to get correct parent's gometry + if (sd->sel_handler_update_job) + ecore_job_del(sd->sel_handler_update_job); + sd->sel_handler_update_job = + ecore_job_add(_sel_handler_update_job_cb, obj); + // + } } EOLIAN static void @@ -3870,11 +5220,19 @@ _elm_entry_password_set(Eo *obj, Elm_Entry_Data *sd, Eina_Bool password) if (sd->password == password) return; sd->password = password; - elm_drop_target_del(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_del(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_del(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// if (password) { sd->single_line = EINA_TRUE; @@ -3886,11 +5244,19 @@ _elm_entry_password_set(Eo *obj, Elm_Entry_Data *sd, Eina_Bool password) else { sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_add(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_add(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// elm_entry_input_hint_set(obj, ((sd->input_hints | ELM_INPUT_HINT_AUTO_COMPLETE) & ~ELM_INPUT_HINT_SENSITIVE_DATA)); _entry_selection_callbacks_register(obj); @@ -4024,19 +5390,35 @@ _elm_entry_editable_set(Eo *obj, Elm_Entry_Data *sd, Eina_Bool editable) sd->editable = editable; eo_do(obj, elm_obj_widget_theme_apply()); - elm_drop_target_del(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_del(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_del(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// if (editable) { sd->drop_format = _get_drop_format(obj); - elm_drop_target_add(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_add(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_add(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// } } @@ -4716,17 +6098,30 @@ _elm_entry_cnp_mode_set(Eo *obj, Elm_Entry_Data *sd, Elm_Cnp_Mode cnp_mode) else if (cnp_mode == ELM_CNP_MODE_MARKUP) format |= ELM_SEL_FORMAT_IMAGE; - elm_drop_target_del(obj, sd->drop_format, + ///////////////////////////////////////////////////////////////// + // TIZEN ONLY (20150129) Add more control when drop happens. + /*elm_drop_target_del(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_del(obj, sd->drop_format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); sd->drop_format = format; - elm_drop_target_add(obj, sd->drop_format, + /*elm_drop_target_add(obj, sd->drop_format, NULL, NULL, NULL, NULL, NULL, NULL, + _drag_drop_cb, NULL);*/ + elm_drop_target_add(obj, format, + _dnd_enter_cb, obj, + _dnd_leave_cb, obj, + _dnd_pos_cb, obj, _drag_drop_cb, NULL); + ///////////////////////////////////////////////////////////////// } EOLIAN static Elm_Cnp_Mode @@ -4752,6 +6147,20 @@ _scroll_cb(Evas_Object *obj, void *data EINA_UNUSED) if (sd->have_selection) _update_selection_handler(obj); + // TIZEN ONLY (20150625): Update cursor handler + if (sd->cursor_handler_shown) + { + if (!sd->cursor_handler_down) + { + evas_object_hide(sd->cursor_handler); + sd->cursor_handler_shown = EINA_FALSE; + } + else + { + _update_cursor_handler(obj, sd); + } + } + // } EOLIAN static void diff --git a/src/lib/elm_module_priv.h b/src/lib/elm_module_priv.h new file mode 100644 index 0000000..6fac4a2 --- /dev/null +++ b/src/lib/elm_module_priv.h @@ -0,0 +1,52 @@ +// TIZEN ONLY header file +#ifndef ELM_MODULE_PRIV_H +#define ELM_MODULE_PRIV_H + +typedef struct _Elm_Entry_Extension_data Elm_Entry_Extension_data; +typedef void (*cpfunc)(void *data, Evas_Object *obj, void *event_info); + +struct _Elm_Entry_Extension_data +{ + Evas_Object *popup; + Evas_Object *ent; + Evas_Object *caller; + Eina_Rectangle *viewport_rect; + Evas_Coord_Rectangle selection_rect; + Eina_List *items; + cpfunc select; + cpfunc copy; + cpfunc cut; + cpfunc paste; + cpfunc cancel; + cpfunc selectall; + cpfunc cnpinit; + cpfunc keep_selection; + cpfunc paste_translation; + cpfunc is_selected_all; + Elm_Config *_elm_config; + Eina_Bool password : 1; + Eina_Bool editable : 1; + Eina_Bool have_selection: 1; + Eina_Bool selmode : 1; + Eina_Bool context_menu : 1; + Elm_Cnp_Mode cnp_mode : 2; + Eina_Bool popup_showing : 1; + Eina_Bool mouse_up : 1; + Eina_Bool mouse_move : 1; + Eina_Bool mouse_down : 1; + Eina_Bool entry_move : 1; + Eina_Bool popup_clicked : 1; + Eina_Bool cursor_handler_shown : 1; + Eina_Bool ent_scroll : 1; + Evas_Object *ctx_par; + Evas_Object *start_handler; + Evas_Object *end_handler; + Evas_Object *cursor_handler; + Ecore_Timer *show_timer; + char *source_text; + char *target_text; +}; + +void elm_entry_extension_module_data_get(Evas_Object *obj,Elm_Entry_Extension_data *ext_mod); + +#endif diff --git a/src/lib/elm_widget_entry.h b/src/lib/elm_widget_entry.h index 2b492a1..f2108e6 100644 --- a/src/lib/elm_widget_entry.h +++ b/src/lib/elm_widget_entry.h @@ -37,8 +37,14 @@ struct _Elm_Entry_Data Evas_Object *mgf_proxy; Evas_Object *start_handler; Evas_Object *end_handler; + Evas_Object *cursor_handler; // TIZEN ONLY Ecore_Job *deferred_recalc_job; + Ecore_Job *sel_handler_update_job; // TIZEN ONLY + Ecore_Job *cursor_handler_update_job; // TIZEN ONLY + Ecore_Event_Handler *sel_notify_handler; // TIZEN ONLY + Ecore_Event_Handler *sel_clear_handler; // TIZEN ONLY Ecore_Timer *longpress_timer; + Ecore_Timer *cursor_handler_longpress_timer; // TIZEN ONLY Ecore_Timer *delay_write; /* for deferred appending */ Ecore_Idler *append_text_idler; @@ -62,6 +68,10 @@ struct _Elm_Entry_Data Ecore_Job *hov_deljob; Mod_Api *api; // module api if supplied int cursor_pos; + int mgf_r, mgf_g, mgf_b, mgf_a; // TIZEN ONLY + int start_sel_pos, end_sel_pos; // TIZEN ONLY + int cursor_move_pos; // TIZEN ONLY + int cursor_handler_down_pos; // TIZEN ONLY Elm_Scroller_Policy policy_h, policy_v; Elm_Wrap_Type line_wrap; Elm_Input_Panel_Layout input_panel_layout; @@ -115,6 +125,11 @@ struct _Elm_Entry_Data Eina_Bool changed : 1; Eina_Bool scroll : 1; Eina_Bool input_panel_show_on_demand : 1; + Eina_Bool drag_started : 1; // TIZEN ONLY + Eina_Bool cursor_handler_down : 1; // TIZEN ONLY + Eina_Bool cursor_handler_shown : 1; // TIZEN ONLY + Eina_Bool mgf_bg_color_set : 1; // TIZEN ONLY + Eina_Bool long_pressing : 1; // TIZEN ONLY }; typedef struct _Elm_Entry_Item_Provider Elm_Entry_Item_Provider; diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 00fbcc0..dba19bb 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -6,4 +6,5 @@ prefs \ test_entry \ test_map \ access_output \ -datetime_input_ctxpopup +datetime_input_ctxpopup \ +copypasteUI_ctxpopup diff --git a/src/modules/copypasteUI_ctxpopup/Makefile.am b/src/modules/copypasteUI_ctxpopup/Makefile.am new file mode 100644 index 0000000..379930a --- /dev/null +++ b/src/modules/copypasteUI_ctxpopup/Makefile.am @@ -0,0 +1,24 @@ + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-DELM_INTERNAL_API_ARGESFSDFEFC=1 \ +-I. \ +-I$(top_builddir) \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/lib \ +-I$(top_builddir)/src/lib \ +-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DELEMENTARY_BUILD \ +@ELEMENTARY_CFLAGS@ + +pkgdir = $(pkglibdir)/modules/copypasteUI_ctxpopup/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la + +module_la_SOURCES = copypaste.c \ + cbhm_helper.c + +module_la_LIBADD = @ELEMENTARY_LIBS@ $(top_builddir)/src/lib/libelementary.la +module_la_LDFLAGS = -no-undefined -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/src/modules/copypasteUI_ctxpopup/cbhm_helper.c b/src/modules/copypasteUI_ctxpopup/cbhm_helper.c new file mode 100644 index 0000000..e67f891 --- /dev/null +++ b/src/modules/copypasteUI_ctxpopup/cbhm_helper.c @@ -0,0 +1,341 @@ +#include "cbhm_helper.h" + +#ifdef HAVE_ELEMENTARY_X +#include +#include +#define ATOM_CBHM_WINDOW_NAME "CBHM_XWIN" +#define ATOM_CBHM_MSG "CBHM_MSG" +#define ATOM_CBHM_COUNT_GET "CBHM_cCOUNT" +#define ATOM_CBHM_TEXT_COUNT_GET "CBHM_TEXT_cCOUNT" +#define ATOM_CBHM_IMAGE_COUNT_GET "CBHM_IMAGE_cCOUNT" +#define ATOM_CBHM_SERIAL_NUMBER "CBHM_SERIAL_NUMBER" +#define MSG_CBHM_COUNT_GET "get count" +#define ATOM_CBHM_ERROR "CBHM_ERROR" +#define ATOM_CBHM_ITEM "CBHM_ITEM" +#endif + +#ifdef HAVE_ELEMENTARY_X +Ecore_X_Window +_elm_ee_xwin_get(const Ecore_Evas *ee) +{ + const char *engine_name; + if (!ee) return 0; + + engine_name = ecore_evas_engine_name_get(ee); + if (EINA_UNLIKELY(!engine_name)) return 0; + + if (!strcmp(engine_name, "software_x11")) + { + return ecore_evas_software_x11_window_get(ee); + } + else if (!strcmp(engine_name, "opengl_x11")) + { + return ecore_evas_gl_x11_window_get(ee); + } + return 0; +} + +static Ecore_X_Window +_x11_elm_widget_xwin_get(const Evas_Object *obj) +{ + Evas_Object *top; + Ecore_X_Window xwin = 0; + + top = elm_widget_top_get(obj); + if (!top) top = elm_widget_top_get(elm_widget_parent_widget_get(obj)); + if (top) xwin = elm_win_xwindow_get(top); + if (!xwin) + { + Ecore_Evas *ee; + Evas *evas = evas_object_evas_get(obj); + if (!evas) return 0; + ee = ecore_evas_ecore_evas_get(evas); + if (!ee) return 0; + xwin = _elm_ee_xwin_get(ee); + } + return xwin; +} + +Ecore_X_Window +_cbhm_window_get() +{ + Ecore_X_Atom x_atom_cbhm = ecore_x_atom_get(ATOM_CBHM_WINDOW_NAME); + Ecore_X_Window x_cbhm_win = 0; + unsigned char *buf = NULL; + int num = 0; + int ret = ecore_x_window_prop_property_get(0, x_atom_cbhm, XA_WINDOW, 0, &buf, &num); + DMSG("ret: %d, num: %d\n", ret, num); + if (ret && num) + memcpy(&x_cbhm_win, buf, sizeof(Ecore_X_Window)); + if (buf) + free(buf); + return x_cbhm_win; +} +#endif + +Eina_Bool +_cbhm_msg_send(Evas_Object *obj, char *msg) +{ +#ifdef HAVE_ELEMENTARY_X + Ecore_X_Window x_cbhm_win = _cbhm_window_get(); + Ecore_X_Atom x_atom_cbhm_msg = ecore_x_atom_get(ATOM_CBHM_MSG); + + Ecore_X_Window xwin = _x11_elm_widget_xwin_get(obj); + if (!xwin) + { + DMSG("ERROR: can't get x window\n"); + return EINA_FALSE; + } + + DMSG("x_cbhm: 0x%x\n", x_cbhm_win); + if (!x_cbhm_win || !x_atom_cbhm_msg) + return EINA_FALSE; + + XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = ecore_x_display_get(); + m.window = xwin; + m.message_type = x_atom_cbhm_msg; + m.format = 8; + snprintf(m.data.b, 20, "%s", msg); + + XSendEvent(ecore_x_display_get(), x_cbhm_win, False, NoEventMask, (XEvent*)&m); + + ecore_x_sync(); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + +#ifdef HAVE_ELEMENTARY_X +void * +_cbhm_reply_get(Ecore_X_Window xwin, Ecore_X_Atom property, Ecore_X_Atom *x_data_type, int *num) +{ + unsigned char *data = NULL; + if (x_data_type) + *x_data_type = 0; + if (!property) + return NULL; + ecore_x_sync(); + if (num) + *num = 0; + + long unsigned int num_ret = 0, bytes = 0; + int ret = 0, size_ret; + unsigned int i; + unsigned char *prop_ret; + Ecore_X_Atom type_ret; + ret = XGetWindowProperty(ecore_x_display_get(), xwin, property, 0, LONG_MAX, + False, ecore_x_window_prop_any_type(), (Atom *)&type_ret, &size_ret, + &num_ret, &bytes, &prop_ret); + if (ret != Success) + return NULL; + if (!num_ret) + { + XFree(prop_ret); + return NULL; + } + + if (!(data = malloc(num_ret * size_ret / 8))) + { + XFree(prop_ret); + return NULL; + } + + switch (size_ret) { + case 8: + for (i = 0; i < num_ret; i++) + (data)[i] = prop_ret[i]; + break; + + case 16: + for (i = 0; i < num_ret; i++) + ((unsigned short *)data)[i] = ((unsigned short *)prop_ret)[i]; + break; + + case 32: + for (i = 0; i < num_ret; i++) + ((unsigned int *)data)[i] = ((unsigned long *)prop_ret)[i]; + break; + } + + XFree(prop_ret); + + if (num) + *num = num_ret; + if (x_data_type) + *x_data_type = type_ret; + + return data; +} +#endif + +int +_cbhm_item_count_get(Evas_Object *obj EINA_UNUSED, int atom_index) +{ +#ifdef HAVE_ELEMENTARY_X + char *ret, count; + Ecore_X_Atom x_atom_cbhm_count_get = 0; + + if (atom_index == ATOM_INDEX_CBHM_COUNT_ALL) + x_atom_cbhm_count_get = ecore_x_atom_get(ATOM_CBHM_COUNT_GET); + else if (atom_index == ATOM_INDEX_CBHM_COUNT_TEXT) + x_atom_cbhm_count_get = ecore_x_atom_get(ATOM_CBHM_TEXT_COUNT_GET); + else if (atom_index == ATOM_INDEX_CBHM_COUNT_IMAGE) + x_atom_cbhm_count_get = ecore_x_atom_get(ATOM_CBHM_IMAGE_COUNT_GET); + + Ecore_X_Window cbhm_xwin = _cbhm_window_get(); + DMSG("x_win: 0x%x, x_atom: %d\n", cbhm_xwin, x_atom_cbhm_count_get); + ret = _cbhm_reply_get(cbhm_xwin, x_atom_cbhm_count_get, NULL, NULL); + if (ret) + { + count = atoi(ret); + DMSG("count: %d\n", count); + free(ret); + return count; + } + DMSG("ret: 0x%x\n", ret); +#endif + return -1; +} +/* +int +_cbhm_item_count_get(Evas_Object *obj) +{ +#ifdef HAVE_ELEMENTARY_X + char *ret, count; + if(_cbhm_msg_send(obj, MSG_CBHM_COUNT_GET)) + { + DMSG("message send success\n"); + Ecore_X_Atom x_atom_cbhm_count_get = ecore_x_atom_get(ATOM_CBHM_COUNT_GET); + Ecore_X_Window xwin = ecore_evas_software_x11_window_get( + ecore_evas_ecore_evas_get(evas_object_evas_get(obj))); + DMSG("x_win: 0x%x, x_atom: %d\n", xwin, x_atom_cbhm_count_get); + ret = _cbhm_reply_get(xwin, x_atom_cbhm_count_get, NULL, NULL); + if (ret) + { + count = atoi(ret); + DMSG("count: %d\n", count); + free(ret); + return count; + } + DMSG("ret: 0x%x\n", ret); + } +#endif + return -1; +} +*/ + +#ifdef HAVE_ELEMENTARY_X +Eina_Bool +_cbhm_item_get(Evas_Object *obj EINA_UNUSED, int idx, Ecore_X_Atom *data_type, char **buf) +#else +Eina_Bool +_cbhm_item_get(Evas_Object *obj, int idx, void *data_type, char **buf) +#endif + +{ + if (buf) + *buf = NULL; + if (data_type) + *(int *)data_type = 0; + +#ifdef HAVE_ELEMENTARY_X + Ecore_X_Window cbhm_xwin = _cbhm_window_get(); + char send_buf[20]; + char *ret; + + snprintf(send_buf, 20, "CBHM_ITEM%d", idx); + Ecore_X_Atom x_atom_cbhm_item = ecore_x_atom_get(send_buf); + Ecore_X_Atom x_atom_item_type = 0; + + DMSG("x_win: 0x%x, x_atom: %d\n", cbhm_xwin, x_atom_cbhm_item); + ret = _cbhm_reply_get(cbhm_xwin, x_atom_cbhm_item, &x_atom_item_type, NULL); + if (ret) + { + DMSG("data_type: %d, buf: %s\n", x_atom_item_type, ret); + if (buf) + *buf = ret; + else + free(ret); + + if (data_type) + *data_type = x_atom_item_type; + + Ecore_X_Atom x_atom_cbhm_error = ecore_x_atom_get(ATOM_CBHM_ERROR); + if (x_atom_item_type == x_atom_cbhm_error) + return EINA_FALSE; + } + DMSG("ret: 0x%x\n", ret); +/* + Ecore_X_Window xwin = ecore_evas_software_x11_window_get( + ecore_evas_ecore_evas_get(evas_object_evas_get(obj))); + char send_buf[20]; + char *ret; + + snprintf(send_buf, 20, "GET_ITEM%d", idx); + if (_cbhm_msg_send(obj, send_buf)) + { + DMSG("message send success\n"); + Ecore_X_Atom x_atom_cbhm_item = ecore_x_atom_get(ATOM_CBHM_ITEM); + Ecore_X_Atom x_atom_item_type = 0; + + DMSG("x_win: 0x%x, x_atom: %d\n", xwin, x_atom_cbhm_item); + ret = _cbhm_reply_get(xwin, x_atom_cbhm_item, &x_atom_item_type, NULL); + if (ret) + { + DMSG("data_type: %d, buf: %s\n", x_atom_item_type, ret); + if (buf) + *buf = ret; + else + free(ret); + if (data_type) + *data_type = x_atom_item_type; + + Ecore_X_Atom x_atom_cbhm_error = ecore_x_atom_get(ATOM_CBHM_ERROR); + if (x_atom_item_type == x_atom_cbhm_error) + return EINA_FALSE; + } + DMSG("ret: 0x%x\n", ret); + } +*/ +#endif + return EINA_FALSE; +} + +#ifdef HAVE_ELEMENTARY_X +Eina_Bool +_cbhm_item_set(Evas_Object *obj, Ecore_X_Atom data_type, char *item_data) +{ + Ecore_X_Window x_cbhm_win = _cbhm_window_get(); + Ecore_X_Atom x_atom_cbhm_item = ecore_x_atom_get(ATOM_CBHM_ITEM); + ecore_x_window_prop_property_set(x_cbhm_win, x_atom_cbhm_item, data_type, 8, item_data, strlen(item_data) + 1); + ecore_x_sync(); + if (_cbhm_msg_send(obj, "SET_ITEM")) + { + DMSG("message send success\n"); + return EINA_TRUE; + } + return EINA_FALSE; +} +#endif + +unsigned int +_cbhm_serial_number_get() +{ + unsigned int senum = 0; +#ifdef HAVE_ELEMENTARY_X + unsigned char *buf = NULL; + Ecore_X_Atom x_atom_cbhm_SN = ecore_x_atom_get(ATOM_CBHM_SERIAL_NUMBER); + Ecore_X_Window x_cbhm_win = _cbhm_window_get(); + buf = _cbhm_reply_get(x_cbhm_win, x_atom_cbhm_SN, NULL, NULL); + if (buf) + { + memcpy(&senum, buf, sizeof(senum)); + free(buf); + } +#endif + return senum; +} diff --git a/src/modules/copypasteUI_ctxpopup/cbhm_helper.h b/src/modules/copypasteUI_ctxpopup/cbhm_helper.h new file mode 100644 index 0000000..7a200ad --- /dev/null +++ b/src/modules/copypasteUI_ctxpopup/cbhm_helper.h @@ -0,0 +1,38 @@ +#ifdef HAVE_CONFIG_H +#include "elementary_config.h" +#endif + +#include +#include +#include "elm_priv.h" + +#ifdef HAVE_ELEMENTARY_X +#include +#endif + +//#define DEBUG + +#ifdef DEBUG +#define DMSG(fmt, args...) printf("[%s], "fmt, __func__, ##args) +#else +#define DMSG(args...) +#endif + +enum ATOM_INDEX_CBHM_COUNT { + ATOM_INDEX_CBHM_COUNT_ALL = 0, + ATOM_INDEX_CBHM_COUNT_TEXT = 1, + ATOM_INDEX_CBHM_COUNT_IMAGE = 2, + ATOM_INDEX_CBHM_COUNT_MAX = 3 +}; + +Eina_Bool _cbhm_msg_send(Evas_Object* obj, char *msg); +int _cbhm_item_count_get(Evas_Object *obj EINA_UNUSED, int atom_index); +#ifdef HAVE_ELEMENTARY_X +Eina_Bool _cbhm_item_get(Evas_Object *obj EINA_UNUSED, int index, Ecore_X_Atom *data_type, char **buf); +#else +Eina_Bool _cbhm_item_get(Evas_Object *obj, int index, void *data_type, char **buf); +#endif + +#ifdef HAVE_ELEMENTARY_X +Eina_Bool _cbhm_item_set(Evas_Object *obj, Ecore_X_Atom data_type, char *item_data); +#endif diff --git a/src/modules/copypasteUI_ctxpopup/copypaste.c b/src/modules/copypasteUI_ctxpopup/copypaste.c new file mode 100644 index 0000000..b6bd01b --- /dev/null +++ b/src/modules/copypasteUI_ctxpopup/copypaste.c @@ -0,0 +1,1711 @@ +#include "cbhm_helper.h" +#include +#include "elm_priv.h" +#include "elm_module_priv.h" + +#if HAVE_APPSVC +#include +#endif + + +#define S_TRANSLATE dgettext("elementary", "Translate") + +/*#define CP_ICON_ADD(icon, item) icon = edje_object_add(evas_object_evas_get(ext_mod->popup)); \ + elm_widget_theme_object_set(ext_mod->popup, \ + icon,"copypaste", item, "default")*/ +#define CP_ICON_ADD(icon, item) icon = NULL + +#define ACCESS_FOCUS_ENABLE() if (ext_mod->_elm_config->access_mode) \ + { \ + elm_object_focus_allow_set(((Elm_Widget_Item_Data *)added_item)->view, EINA_FALSE); \ + ao = ((Elm_Widget_Item_Data *)added_item)->access_obj; \ + elm_object_focus_allow_set(ao, EINA_FALSE); \ + lao = eina_list_append(lao, ao); \ + } + +#define GET_CTX_AVAI_DIR() elm_layout_sizing_eval(ext_mod->popup); \ + dir = elm_ctxpopup_direction_get(ext_mod->popup) + +#define DEBUGON 1 +#ifdef DEBUGON +#define LOG(fmt, args...) printf("[CNP]%s %d: " fmt "\n", __func__, __LINE__, ##args) +#else +#define LOG(x...) do { } while (0) +#endif + +Elm_Entry_Extension_data *ext_mod; +static int _mod_hook_count = 0; +static Evas_Coord _previous_pressed_point_x = -1; +static Evas_Coord _previous_pressed_point_y = -1; +static int _copy_paste_move_threshold = 15; + +typedef struct _Elm_Entry_Context_Menu_Item Elm_Entry_Context_Menu_Item; + +struct _Elm_Entry_Context_Menu_Item +{ + Evas_Object *obj; + const char *label; + const char *icon_file; + const char *icon_group; + Elm_Icon_Type icon_type; + Evas_Smart_Cb func; + void *data; +}; + +static void _entry_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _entry_hide_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _entry_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _entry_mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _entry_mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _entry_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _entry_scroll_cb(void *data, Evas_Object *scroller, void *event_info); +static void _ctxpopup_hide(Evas_Object *popup); +static void _ctxpopup_dismissed_cb(void *data, Evas_Object *obj, void *event_info); +void obj_longpress(Evas_Object *obj); + +#if HAVE_APPSVC +static char * +_remove_tags(const char *str) +{ + char *ret; + if (!str) + return NULL; + + Eina_Strbuf *buf = eina_strbuf_new(); + if (!buf) + return NULL; + + if (!eina_strbuf_append(buf, str)) + { + eina_strbuf_free(buf); + return NULL; + } + + eina_strbuf_replace_all(buf, "
", " "); + eina_strbuf_replace_all(buf, "
", " "); + eina_strbuf_replace_all(buf, "", " "); + eina_strbuf_replace_all(buf, "", " "); + + while (EINA_TRUE) + { + const char *temp = eina_strbuf_string_get(buf); + + char *startTag = NULL; + char *endTag = NULL; + + startTag = strstr(temp, "<"); + if (startTag) + endTag = strstr(startTag, ">"); + else + break; + if (!endTag || startTag > endTag) + break; + + size_t sindex = startTag - temp; + size_t eindex = endTag - temp + 1; + if (!eina_strbuf_remove(buf, sindex, eindex)) + break; + } + ret = eina_strbuf_string_steal(buf); + eina_strbuf_free(buf); + return ret; +} +#endif + +static void +_parent_mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if ((!ext_mod) || (!ext_mod->popup)) + return; + ext_mod->popup_clicked = EINA_TRUE; + evas_object_hide(ext_mod->popup); + ext_mod->mouse_up = EINA_FALSE; + ext_mod->entry_move = EINA_FALSE; +} + +static void +_parent_mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if ((!ext_mod) || (!ext_mod->popup)) + return; + if ((ext_mod->popup_clicked) && (ext_mod->popup_showing)) + { + ext_mod->popup_showing = EINA_FALSE; + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_DEL, _entry_del_cb); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_HIDE, _entry_hide_cb); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_MOVE, _entry_move_cb); + + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_MOUSE_DOWN, + _entry_mouse_down_cb); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_MOUSE_MOVE, + _entry_mouse_move_cb); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_MOUSE_UP, + _entry_mouse_up_cb); + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_DOWN, + _parent_mouse_down_cb); + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_UP, + _parent_mouse_up_cb); + evas_object_smart_callback_del(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb); + if (ext_mod->ent_scroll) + { + evas_object_smart_callback_del(obj, "scroll", _entry_scroll_cb); + } + } +} + +static void +_entry_del_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if (ext_mod) + { + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_DOWN, + _parent_mouse_down_cb); + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_UP, + _parent_mouse_up_cb); + if (ext_mod->popup) + { + _ctxpopup_hide(ext_mod->popup); + evas_object_del(ext_mod->popup); + ext_mod->popup = NULL; + } + } +} + +static void +_entry_hide_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + evas_object_hide(data); +} + +static void +_entry_mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if ((!ext_mod) || (!ext_mod->popup)) + return; + ext_mod->mouse_up = EINA_FALSE; + ext_mod->mouse_move = EINA_FALSE; + ext_mod->mouse_down = EINA_TRUE; + + Evas_Event_Mouse_Down *ev = event_info; + + _previous_pressed_point_x = ev->canvas.x; + _previous_pressed_point_y = ev->canvas.y; +} + +static Eina_Bool +_ctx_show(void *data) +{ + ext_mod->show_timer = NULL; + if (!data) return ECORE_CALLBACK_CANCEL; + ext_mod->entry_move = EINA_FALSE; + if (ext_mod->popup_showing) + { + obj_longpress(data); + } + return ECORE_CALLBACK_CANCEL; +} + +static void +_entry_mouse_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + if ((!ext_mod) || (!ext_mod->popup)) + return; + + if (!ext_mod->mouse_down) + return; + + Evas_Event_Mouse_Move *ev = event_info; + if ((abs(_previous_pressed_point_x - ev->cur.canvas.x) >= _copy_paste_move_threshold)||(abs(_previous_pressed_point_y - ev->cur.canvas.y) >= _copy_paste_move_threshold)) + { + ext_mod->popup_clicked = EINA_FALSE; + ext_mod->mouse_move = EINA_TRUE; + } + else + { + return; + } + + evas_object_hide(ext_mod->popup); + evas_object_smart_callback_del(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb); + if (ext_mod->show_timer) + { + ecore_timer_del(ext_mod->show_timer); + ext_mod->show_timer = NULL; + } +} + +static void +_entry_scroll_cb(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + if (!ext_mod) + return; + evas_object_hide(ext_mod->popup); + evas_object_smart_callback_del(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb); + if (ext_mod->show_timer) ecore_timer_del(ext_mod->show_timer); + ext_mod->show_timer = ecore_timer_add(0.1, _ctx_show, obj); +} + +static void +_entry_mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + _previous_pressed_point_x = -1; + _previous_pressed_point_y = -1; + + if (!ext_mod) + return; + if ((ext_mod->mouse_down && ext_mod->entry_move) || (ext_mod->mouse_down && ext_mod->mouse_move)) + { + evas_object_smart_callback_del(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb); + if (ext_mod->show_timer) + { + ecore_timer_del(ext_mod->show_timer); + ext_mod->show_timer = NULL; + } + + if (ext_mod->popup && !evas_object_visible_get(ext_mod->popup)) + { + ext_mod->show_timer = ecore_timer_add(0.1, _ctx_show, obj); + } + } + ext_mod->mouse_up = EINA_TRUE; + ext_mod->mouse_move = EINA_FALSE; + ext_mod->mouse_down = EINA_FALSE; +} + +static void +_entry_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + if (!ext_mod) + return; + ext_mod->entry_move = EINA_TRUE; + ext_mod->popup_clicked = EINA_FALSE; + evas_object_hide(ext_mod->popup); + evas_object_smart_callback_del(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb); + if (ext_mod->show_timer) ecore_timer_del(ext_mod->show_timer); + ext_mod->show_timer = ecore_timer_add(0.1, _ctx_show, obj); +} + +static void +_ctxpopup_hide(Evas_Object *popup) +{ + if (!ext_mod->popup_showing) return; + ext_mod->popup_showing = EINA_FALSE; + evas_object_hide(popup); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_DEL, _entry_del_cb); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_HIDE, _entry_hide_cb); + evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_MOVE, _entry_move_cb); + //FIXME: check access API to disable/enable highlight + if (ext_mod->_elm_config->access_mode && ext_mod->caller) + //_elm_access_highlight_set(ext_mod->caller, EINA_TRUE); + _elm_access_highlight_set(ext_mod->caller); +} + +static Eina_Bool +_in_viewport_check() +{ + if (!ext_mod) return EINA_FALSE; + + Eina_Rectangle vp; + + /*update*/ + if (ext_mod->caller) + { + if (ext_mod->viewport_rect) + eina_rectangle_free(ext_mod->viewport_rect); + elm_entry_extension_module_data_get(ext_mod->caller, ext_mod); + } + /* Entry returns x y coordinate to be 0 when intersection is not obtained + * but x y coordinate can be 0 */ + if ((ext_mod->viewport_rect->x == 0) && (ext_mod->viewport_rect->y == 0) && + (ext_mod->viewport_rect->w == 0) && (ext_mod->viewport_rect->h == 0)) + { + ext_mod->viewport_rect->x = -1; + ext_mod->viewport_rect->y = -1; + ext_mod->viewport_rect->w = -1; + ext_mod->viewport_rect->h = -1; + } + vp.x = ext_mod->viewport_rect->x; + vp.y = ext_mod->viewport_rect->y; + vp.w = ext_mod->viewport_rect->w; + vp.h = ext_mod->viewport_rect->h; + + if (ext_mod->have_selection) + { + if ((ext_mod->viewport_rect->x != -1) || (ext_mod->viewport_rect->y != -1) || + (ext_mod->viewport_rect->w != -1) || (ext_mod->viewport_rect->h != -1)) + { + Evas_Coord ex, ey; + Eina_Rectangle sel; + + evas_object_geometry_get(ext_mod->ent, &ex, &ey, NULL, NULL); + sel.x = ext_mod->selection_rect.x; + sel.y = ext_mod->selection_rect.y; + sel.w = ext_mod->selection_rect.w; + sel.h = ext_mod->selection_rect.h; + LOG("sel geo: %d %d %d %d\n", sel.x, sel.y, sel.w, sel.h); + LOG("vpr geo: %d %d %d %d\n", vp.x, vp.y, vp.w, vp.h); + if (eina_rectangle_intersection(&sel, &vp)) + { + return EINA_TRUE; + } + return EINA_FALSE; + } + return EINA_TRUE; + } + else + { + if ((ext_mod->viewport_rect->x != -1) || (ext_mod->viewport_rect->y != -1) || + (ext_mod->viewport_rect->w != -1) || (ext_mod->viewport_rect->h != -1)) + { + Evas_Coord ex, ey; + Evas_Coord cx, cy, cw, ch; + Eina_Rectangle cur; + + evas_object_geometry_get(ext_mod->ent, &ex, &ey, NULL, NULL); + edje_object_part_text_cursor_geometry_get(ext_mod->ent, "elm.text", + &cx, &cy, &cw, &ch); + cx = ex + cx; + cy = ey + cy; + cur.x = cx; + cur.y = cy; + cur.w = cw; + cur.h = ch; + if (eina_rectangle_intersection(&cur, &vp)) + { + return EINA_TRUE; + } + return EINA_FALSE; + } + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_ctxpopup_position(Evas_Object *obj EINA_UNUSED) +{ + if(!ext_mod) return; + + Evas_Coord ex, ey; + Evas_Coord sx, sy, sw, sh; + Evas_Coord x, y, w; + int gap = 35; //in GUI + Elm_Ctxpopup_Direction dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN; + + evas_object_geometry_get(ext_mod->ent, &ex, &ey, NULL, NULL); + elm_ctxpopup_direction_priority_set(ext_mod->popup, ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT); + if (!ext_mod->have_selection) + { //cannot get selection shape + LOG("Cannot get selection (have no sel)\n"); + Evas_Coord cx = 0, cy = 0, cw = 0, ch = 0; + Evas_Coord chx = 0, chy = 0, chw = 0, chh = 0; + Eina_Bool ch_visible = EINA_FALSE; + Eina_Bool need_update = EINA_FALSE; + + edje_object_part_text_cursor_geometry_get(ext_mod->ent, "elm.text", + &cx, &cy, &cw, &ch); + x = ex + cx; + y = ey + cy; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + { + elm_ctxpopup_direction_priority_set(ext_mod->popup, + ELM_CTXPOPUP_DIRECTION_DOWN, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT); + x = ex + cx; + y = ey + cy + ch; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_UP) + need_update = EINA_TRUE; + } + + //limit ctx in viewport + if (ext_mod->viewport_rect->x != -1 || ext_mod->viewport_rect->y != -1 + || ext_mod->viewport_rect->w != -1 || ext_mod->viewport_rect->h != -1) + { + if (ext_mod->viewport_rect->x > x) + x = ext_mod->viewport_rect->x; + else if (x > ext_mod->viewport_rect->x + ext_mod->viewport_rect->w) + x = ext_mod->viewport_rect->x + ext_mod->viewport_rect->w; + + if (ext_mod->viewport_rect->y > y) + y = ext_mod->viewport_rect->y; + else if (y > ext_mod->viewport_rect->y + ext_mod->viewport_rect->h) + y = ext_mod->viewport_rect->y + ext_mod->viewport_rect->h; + } + + evas_object_move(ext_mod->popup, x, y); + + ch_visible = ext_mod->cursor_handler_shown; + if (ext_mod->cursor_handler) + { + Evas_Coord xx, yy; + evas_object_geometry_get(ext_mod->cursor_handler, &chx, &chy, NULL, NULL); + edje_object_parts_extends_calc(ext_mod->cursor_handler, &xx, &yy, &chw, &chh); + chx += xx; + chy += yy; + LOG("Cursor handler: %d %d %d %d\n", chx, chy, chw, chh); + } + + GET_CTX_AVAI_DIR(); + //move to above or below cursor handler + if (ch_visible && strcmp(edje_object_part_text_get(ext_mod->ent, "elm.text"), "")) + { + if ((chy < ey + cy) && (dir == ELM_CTXPOPUP_DIRECTION_UP)) + { + y = chy; + evas_object_move(ext_mod->popup, x, y); + LOG("Ctxpopup pos: %d %d\n", x, y); + GET_CTX_AVAI_DIR(); + if (dir != ELM_CTXPOPUP_DIRECTION_UP) + need_update = EINA_TRUE; + } + else if ((chy > ey + cy) && (dir == ELM_CTXPOPUP_DIRECTION_DOWN)) + { + y = chy + chh; + evas_object_move(ext_mod->popup, x, y); + LOG("Ctxpopup pos: %d %d\n", x, y); + GET_CTX_AVAI_DIR(); + if (dir != ELM_CTXPOPUP_DIRECTION_DOWN) + need_update = EINA_TRUE; + } + } + if (((dir != ELM_CTXPOPUP_DIRECTION_UP) && (dir != ELM_CTXPOPUP_DIRECTION_DOWN)) || need_update) + { + y = ey + cy + ch / 2; + elm_ctxpopup_direction_priority_set(ext_mod->popup, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_DOWN); + evas_object_move(ext_mod->popup, x, y); + LOG("Ctxpopup pos: %d %d\n", x, y); + } + } + else //get selection shape + { + LOG("Have selection\n"); + Evas_Coord shx = 0, shy = 0, shw = 0, shh = 0; + Evas_Coord ehx = 0, ehy = 0, ehw = 0, ehh = 0; + /* Currently, we cannot get size of ctxpopup, we must set hard value for threshold. + After fixing ctxpopup, we can get correctly threshold */ + Evas_Coord threshold = 300; + + sx = ext_mod->selection_rect.x; + sy = ext_mod->selection_rect.y; + sw = ext_mod->selection_rect.w; + sh = ext_mod->selection_rect.h; + LOG("sel geo: %d %d %d %d\n", sx, sy, sw, sh); + if (ext_mod->start_handler) + { + Evas_Coord xx, yy; + evas_object_geometry_get(ext_mod->start_handler, &shx, ­, NULL, NULL); + edje_object_parts_extends_calc(ext_mod->start_handler, &xx, &yy, &shw, &shh); + shx += xx; + shy += yy; + } + if (ext_mod->end_handler) + { + Evas_Coord xx, yy; + evas_object_geometry_get(ext_mod->end_handler, &ehx, &ehy, NULL, NULL); + edje_object_parts_extends_calc(ext_mod->end_handler, &xx, &yy, &ehw, &ehh); + ehx += xx; + ehy += yy; + } + LOG("start handler: %d %d %d %d, end handler: %d %d %d %d\n", shx, shy, shw, shh, ehx, ehy, ehw, ehh); + if (ext_mod->viewport_rect->x != -1 || ext_mod->viewport_rect->y != -1 + || ext_mod->viewport_rect->w != -1 || ext_mod->viewport_rect->h != -1) + { + Evas_Coord vx, vy, vw, vh, x2, y2; + x2 = sx + sw; + if ((ehh > 0) && (ehy + ehh > sy + sh)) + { + //y2 = ey + ehy + ehh; + y2 = ehy + gap; + } + else + y2 = sy + sh; + vx = ext_mod->viewport_rect->x; + vy = ext_mod->viewport_rect->y; + vw = ext_mod->viewport_rect->w; + vh = ext_mod->viewport_rect->h; + + //limit ctx in viewport + x = sx; + if (sx < vx) x = vx; + if (sy < vy) + { + LOG("start of selection is behind viewport"); + if (ehy + ehh < vy + vh) //end handler is showing + { + y = ehy + ehh; + if (x2 > vx + vw) x2 = vx + vw; + w = x2 - x; + elm_ctxpopup_direction_priority_set(ext_mod->popup, + ELM_CTXPOPUP_DIRECTION_DOWN, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT); + evas_object_move(ext_mod->popup, x + w/2, y); + LOG("move: %d %d", x + w/2, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + { + LOG("show down"); + return; + } + else + { + elm_ctxpopup_direction_priority_set(ext_mod->popup, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_DOWN, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT); + y = vy + (vh / 2); + LOG("show middle of sel: %d %d", x, y); + } + } + else + { + y = vy + (vh / 2); + LOG("show middle of sel: %d %d", x, y); + } + } + else + { + if ((sx >= vx) && (shy < sy)) //case: start handler is upside + { + y = shy; + w = x2 - x; + evas_object_move(ext_mod->popup, x + w/2, y); + GET_CTX_AVAI_DIR(); + if (dir != ELM_CTXPOPUP_DIRECTION_UP) + { + y = sy - gap; + } + } + else if ((sx + sw <= vx + vw) && (ehy < sy)) + { + y = ehy; + } + else + y = sy; + } + if (x2 > vx + vw) x2 = vx + vw; + if (y2 > vy + vh) y2 = vy + vh; + w = x2 - x; + evas_object_move(ext_mod->popup, x + w/2, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_UP) + return; + } + else //get selection & cannot get viewport + { + Evas_Coord ww = 0, wh = 0, x2, y2; + x2 = sx + sw; + if (ehy + ehh > sy + sh) + y2 = ehy + ehh; //end handler is downside + else + y2 = sy + sh; + + //FIXME: check this +#ifdef HAVE_ELEMENTARY_X + ecore_x_window_size_get(ecore_x_window_root_first_get(), &ww, &wh); +#endif + + x = sx; + if (sx < 0) x = 0; + if (sy < 0) + { + y = 0; //start of selection is negative + } + else + { + if (shy < sy) //start handler is upside + { + y = shy; + w = x2 - x; + evas_object_move(ext_mod->popup, x + w/2, y); + GET_CTX_AVAI_DIR(); + if (dir != ELM_CTXPOPUP_DIRECTION_UP) + { + y = sy - gap; + } + } + else + { + y = sy; + } + } + if (x2 > ww) x2 = ww; + if (y2 > wh) y2 = wh; + w = x2 - x; + } + x = x + (w / 2); + evas_object_move(ext_mod->popup, x, y); + + GET_CTX_AVAI_DIR(); + if (dir != ELM_CTXPOPUP_DIRECTION_UP) + { + Eina_Rectangle vp; + Eina_Rectangle sel; //selection area which is not covered by start,end sel handlers + Evas_Coord cry; + + elm_ctxpopup_direction_priority_set(ext_mod->popup, ELM_CTXPOPUP_DIRECTION_DOWN, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT); + vp.x = ext_mod->viewport_rect->x; + vp.y = ext_mod->viewport_rect->y; + vp.w = ext_mod->viewport_rect->w; + vp.h = ext_mod->viewport_rect->h; + sel.x = sx; + if (shy + shh < sy + sh) + sel.y = sy > shy + shh ? sy : shy + shh; + else + sel.y = sy; + sel.w = sw; + cry = sy + sh < ehy ? sy + sh : ehy; + sel.h = cry > sel.y ? cry - sel.y : sel.y - cry; + if ((eina_rectangle_intersection(&sel, &vp)) && (sel.h > threshold)) + { + elm_ctxpopup_direction_priority_set(ext_mod->popup, ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_DOWN, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT); + evas_object_move(ext_mod->popup, x, sel.y + sel.h/2); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_UP) + return; + } + + y = sel.y + sel.h; + if ((y < ehy + ehh) && (ehy < vp.y + vp.h)) //end handler is downside + { + y = ehy + ehh; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + return; + y = sy + sh + gap; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + return; + } + y = ehy + ehh; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + return; + + // not enough space and small viewport (like landscape mode) + sel.x = sx; + sel.y = sy; + sel.w = sw; + sel.h = sh; + if (!eina_rectangle_intersection(&sel, &vp)) + return; + + if (shy < sel.y) //start handler is up side + { + y = shy; + while (y <= sel.y + ehh/2) + { + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_UP) + return; + y += shh/4; + } + } + else + { + if (ehy + ehh > sel.y + sel.h) //end handler is down side + { + y = ehy + ehh; + while (y > sel.y + sel.h - ehh/2) + { + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + return; + y -= ehh/4; + } + } + else + { + y = sel.y + sel.h; + while (y > sel.y + sel.h - ehh/2) + { + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_DOWN) + return; + y -= ehh/4; + } + } + } + + elm_ctxpopup_direction_priority_set(ext_mod->popup, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_RIGHT, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_DOWN); + x = sel.x; + y = sel.y + sel.h/2; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_LEFT) + return; + + x = sel.x; + y = sel.y + sel.h; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_LEFT) + return; + + elm_ctxpopup_direction_priority_set(ext_mod->popup, + ELM_CTXPOPUP_DIRECTION_RIGHT, + ELM_CTXPOPUP_DIRECTION_LEFT, + ELM_CTXPOPUP_DIRECTION_UP, + ELM_CTXPOPUP_DIRECTION_DOWN); + x = sel.x + sel.w; + y = sel.y + sel.h/2; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_RIGHT) + return; + + x = sel.x + sel.w; + y = sel.y + sel.h; + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_RIGHT) + return; + + x = sel.x; + y = sel.y + sel.h/2; + while (x < sel.x + sel.w/2) + { + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_LEFT) + return; + x += sel.w/4; + } + + x = sel.x + sel.w; + y = sel.y + sel.h/2; + while (x > sel.x + sel.w/2) + { + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_RIGHT) + return; + x -= sel.w/4; + } + + x = sel.x + sel.w; + y = sel.y + sel.h; + while (x > sel.x + sel.w/2) + { + evas_object_move(ext_mod->popup, x, y); + GET_CTX_AVAI_DIR(); + if (dir == ELM_CTXPOPUP_DIRECTION_RIGHT) + return; + x -= sel.w/4; + } + } + } +} + +static void +_select_all(void *data, Evas_Object *obj, void *event_info) +{ + if((!ext_mod) || (!data)) return; + + _ctxpopup_hide(obj); + ext_mod->selectall(data, obj, event_info); +} + +static void +_select(void *data, Evas_Object *obj, void *event_info) +{ + if((!ext_mod) || (!data)) return; + + _ctxpopup_hide(obj); + ext_mod->select(data, obj, event_info); +} + +static void +_paste(void *data, Evas_Object *obj, void *event_info) +{ + if((!ext_mod) || (!data)) return; + + ext_mod->paste(data, obj, event_info); + _ctxpopup_hide(obj); +} + +static void +_cut(void *data, Evas_Object *obj, void *event_info) +{ + if((!ext_mod) || (!data)) return; + + ext_mod->cut(data, obj, event_info); + _ctxpopup_hide(obj); +} + +static void +_copy(void *data, Evas_Object *obj, void *event_info) +{ + if((!ext_mod) || (!data)) return; + + if (edje_object_part_text_selection_get(ext_mod->ent, "elm.text")) + { + int pos = 0, pos1 = 0, pos2 = 0; + pos1 = edje_object_part_text_cursor_pos_get(ext_mod->ent, "elm.text", + EDJE_CURSOR_SELECTION_BEGIN); + pos2 = edje_object_part_text_cursor_pos_get(ext_mod->ent, "elm.text", + EDJE_CURSOR_SELECTION_END); + pos = pos1 > pos2 ? pos1 : pos2; + edje_object_part_text_cursor_pos_set(ext_mod->ent, "elm.text", + EDJE_CURSOR_MAIN, pos); + } + ext_mod->copy(data, obj, event_info); + _ctxpopup_hide(obj); + elm_entry_select_none(data); +} + +static void +_cancel(void *data, Evas_Object *obj, void *event_info) +{ + if((!ext_mod) || (!data)) return; + + ext_mod->cancel(data, obj, event_info); + _ctxpopup_hide(obj); +} + +#if HAVE_APPSVC +static void +_recvd_bundle(const char *key, const int type EINA_UNUSED, const bundle_keyval_t *kv, void *date EINA_UNUSED) +{ + char *val; + size_t size; + + if (!ext_mod) return; + + if (bundle_keyval_type_is_array((bundle_keyval_t *)kv) <= 0) + { + bundle_keyval_get_basic_val((bundle_keyval_t *)kv, (void **)&val, &size); + if (!strcmp(key, "source_text")) + { + ext_mod->source_text = strdup(val); + } + if (!strcmp(key, "target_text")) + { + ext_mod->target_text = strdup(val); + } + } +} + +static void +_translate_cb(bundle *b, int request_code EINA_UNUSED, appsvc_result_val rv, void *data EINA_UNUSED) +{ + if (!ext_mod) return; + + if (ext_mod->source_text) + { + free(ext_mod->source_text); + ext_mod->source_text = NULL; + } + if (ext_mod->target_text) + { + free(ext_mod->target_text); + ext_mod->target_text = NULL; + } + if ((rv == APPSVC_RES_CANCEL) || (rv == APPSVC_RES_NOT_OK)) //CANCEL, NOT_OK, OK + { + return; + } + else + { + bundle_foreach(b, _recvd_bundle, NULL); + } + if ((ext_mod->source_text) || (ext_mod->target_text)) + { + if (ext_mod->editable) + { + ext_mod->paste_translation(ext_mod->source_text, + ext_mod->caller, ext_mod->target_text); + } + } +} + +static unsigned int +_get_window_id() +{ + Evas_Object *top; + Ecore_X_Window xwin; + + top = elm_widget_top_get(ext_mod->caller); + xwin = elm_win_xwindow_get(top); + + return xwin; +} + +static void +_translate_menu(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + if (!ext_mod) return; + + bundle *b = bundle_create(); + if (!b) + { + return; + } + ext_mod->keep_selection(NULL, ext_mod->caller, NULL); + + appsvc_set_operation(b, APPSVC_OPERATION_PICK); + appsvc_set_appid(b, "com.samsung.stranslator-shared"); + + if (ext_mod->selmode) + { + const char *selection = elm_entry_selection_get(ext_mod->caller); + if (selection) + { + unsigned int winid = _get_window_id(); + char wis[20]; + snprintf(wis, 20, "%u", winid); + appsvc_add_data(b, "winid", wis); + appsvc_add_data(b, "display", "yes"); + appsvc_add_data(b, "text_type", "plain_text"); + appsvc_add_data(b, "source_language", "recently_used"); //auto_detection, recently_used + appsvc_add_data(b, "target_language", "recently_used"); //recently_used, specify(en_US) + appsvc_add_data(b, "result_type", "selective"); //target_only, selective, both + if (ext_mod->editable) + appsvc_add_data(b, "mode", "edit_mode_translate"); //edit_mode, edit_mode_translate + else + appsvc_add_data(b, "mode", "view_mode_translate"); //view_mode, view_mode_translate + + char *str = _remove_tags(selection); + if (str) + appsvc_add_data(b, "source_text", str); + else + appsvc_add_data(b, "source_text", selection); + } + } + appsvc_run_service(b, 0, _translate_cb, NULL); + bundle_free(b); + elm_entry_input_panel_hide(ext_mod->caller); + _ctxpopup_hide(obj); +} +#endif + +static void +_clipboard_menu(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + if(!ext_mod) return; + + // start for cbhm +#ifdef HAVE_ELEMENTARY_X + Evas_Object *top; + Ecore_X_Window xwin; + top = elm_widget_top_get(ext_mod->caller); + xwin = elm_win_xwindow_get(top); + ecore_x_selection_secondary_set(xwin, NULL, 0); +#endif + if (ext_mod->cnp_mode != ELM_CNP_MODE_MARKUP) + _cbhm_msg_send(data, "show0"); + else + _cbhm_msg_send(data, "show1"); + _ctxpopup_hide(obj); + // end for cbhm + elm_entry_select_none(data); +} + +static void +_item_clicked(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Elm_Entry_Context_Menu_Item *it = data; + Evas_Object *obj2 = it->obj; + + if (it->func) it->func(it->data, obj2, NULL); + _ctxpopup_hide(obj); +} + +static void +_ctxpopup_dismissed_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Elm_Ctxpopup_Direction dir; + if (!ext_mod) return; + + dir = elm_ctxpopup_direction_get(obj); + //clear selection if ctxpopup is dismissed by clicking (not parent resizing) + if (dir != ELM_CTXPOPUP_DIRECTION_UNKNOWN) + { + if ((ext_mod->mouse_up) && (ext_mod->entry_move)) + { + _ctxpopup_position(obj); + evas_object_show(ext_mod->popup); + } + else + { + elm_entry_select_none(data); + ext_mod->popup_showing = EINA_FALSE; + //FIXME: check access API to disable/enable highlight + if (ext_mod->_elm_config->access_mode) + //_elm_access_highlight_set(ext_mod->caller, EINA_FALSE); + _elm_access_highlight_set(ext_mod->caller); + } + } + else if (ext_mod->popup_showing) + { + if (_in_viewport_check()) + { + if (ext_mod->show_timer) ecore_timer_del(ext_mod->show_timer); + ext_mod->show_timer = ecore_timer_add(0.1, _ctx_show, data); + } + } + ext_mod->mouse_up = EINA_FALSE; +} + +// module api funcs needed +EAPI int +elm_modapi_init(void *m EINA_UNUSED) +{ + return 1; // succeed always +} + +EAPI int +elm_modapi_shutdown(void *m EINA_UNUSED) +{ + return 1; // succeed always +} + +// module funcs for the specific module type +EAPI void +obj_hook(Evas_Object *obj) +{ + _mod_hook_count++; + //if(_mod_hook_count > 1) return; + + if(!ext_mod) + { + ext_mod = ELM_NEW(Elm_Entry_Extension_data); + if (!ext_mod) return; + if (ext_mod->viewport_rect) + eina_rectangle_free(ext_mod->viewport_rect); + elm_entry_extension_module_data_get(obj, ext_mod); + ext_mod->mouse_up = EINA_FALSE; + ext_mod->mouse_down = EINA_FALSE; + ext_mod->entry_move = EINA_FALSE; + } + // Clipboard item: can be removed by application + elm_entry_context_menu_item_add(obj, "Clipboard", NULL, + ELM_ICON_STANDARD, NULL, NULL); + +#if HAVE_APPSVC + // Tranlate item: can be removed by application + elm_entry_context_menu_item_add(obj, "Translate", NULL, + ELM_ICON_STANDARD, NULL, NULL); +#endif +} + +EAPI void +obj_unhook(Evas_Object *obj EINA_UNUSED) +{ + _mod_hook_count--; + if(_mod_hook_count > 0) return; + + if(ext_mod) + { + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_DOWN, + _parent_mouse_down_cb); + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_UP, + _parent_mouse_up_cb); + if (ext_mod->show_timer) + { + ecore_timer_del(ext_mod->show_timer); + ext_mod->show_timer = NULL; + } + if (ext_mod->popup) + { + evas_object_del(ext_mod->popup); + ext_mod->popup = NULL; + } + if (ext_mod->source_text) + { + free(ext_mod->source_text); + ext_mod->source_text = NULL; + } + if (ext_mod->target_text) + { + free(ext_mod->target_text); + ext_mod->target_text = NULL; + } + if (ext_mod->viewport_rect) + eina_rectangle_free(ext_mod->viewport_rect); + free(ext_mod); + ext_mod = NULL; + } +} + +EAPI void +obj_longpress(Evas_Object *obj) +{ + if(!ext_mod) return; + LOG("IN\n\n"); + + Evas_Object *ctxparent; + Evas_Object *parent, *child; + const Eina_List *l; + const Elm_Entry_Context_Menu_Item *it; + const char *context_menu_orientation; + Evas_Object* icon; + Elm_Object_Item *added_item = NULL; + Eina_Bool has_clipboard = EINA_FALSE; +#if HAVE_APPSVC + Eina_Bool has_translate = EINA_FALSE; +#endif + Ecore_X_Atom first_cbhm_item_type = 0; + Eina_Bool has_focused = EINA_FALSE; + + /*update*/ + if (ext_mod->viewport_rect) + eina_rectangle_free(ext_mod->viewport_rect); + elm_entry_extension_module_data_get(obj, ext_mod); + has_focused = elm_widget_focus_get(obj); + if (ext_mod->context_menu && has_focused) + { + Eina_List *lao = NULL; + Evas_Object *ao = NULL; +#ifdef HAVE_ELEMENTARY_X + int cbhm_count = 0; + if (elm_entry_cnp_mode_get(obj) != ELM_CNP_MODE_MARKUP) + cbhm_count = _cbhm_item_count_get(obj, ATOM_INDEX_CBHM_COUNT_TEXT); + else + cbhm_count = _cbhm_item_count_get(obj, ATOM_INDEX_CBHM_COUNT_ALL); +#endif + if (ext_mod->popup) + { + evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, _entry_del_cb); + evas_object_event_callback_del(obj, EVAS_CALLBACK_HIDE, _entry_hide_cb); + evas_object_event_callback_del(obj, EVAS_CALLBACK_MOVE, _entry_move_cb); + evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_DOWN, _entry_mouse_down_cb); + evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE, _entry_mouse_move_cb); + evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _entry_mouse_up_cb); + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_DOWN, + _parent_mouse_down_cb); + evas_object_event_callback_del(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_UP, + _parent_mouse_up_cb); + evas_object_smart_callback_del(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb); + if (ext_mod->ent_scroll) + { + evas_object_smart_callback_del(obj, "scroll", _entry_scroll_cb); + } + evas_object_del(ext_mod->popup); + ext_mod->popup = NULL; + } + ctxparent = elm_widget_top_get(obj); + parent = elm_widget_parent_get(obj); + child = obj; + if (parent) + { + while(parent) + { + const char *type = elm_widget_type_get(parent); + if ((type) && (!strcmp(type, "Elm_Conformant"))) + { + ctxparent = child; + break; + } + child = parent; + parent = elm_widget_parent_get(parent); + } + } + ext_mod->ctx_par = ctxparent; + + if(ctxparent) + { + ext_mod->popup = elm_ctxpopup_add(ctxparent); + if (ext_mod->_elm_config->access_mode) + { + elm_object_tree_focus_allow_set(ext_mod->popup, EINA_TRUE); + elm_object_focus_allow_set(ext_mod->popup, EINA_FALSE); + } + else + { + elm_object_tree_focus_allow_set(ext_mod->popup, EINA_FALSE); + } + evas_object_smart_callback_add(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb, obj); + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _entry_del_cb, ext_mod->popup); + evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _entry_hide_cb, ext_mod->popup); + } + else + { + ext_mod->caller = NULL; + LOG("Have no parent\n"); + return; + } + elm_object_style_set(ext_mod->popup, "copypaste"); + + elm_ctxpopup_horizontal_set(ext_mod->popup, EINA_TRUE); + context_menu_orientation = edje_object_data_get + (ext_mod->ent, "context_menu_orientation"); + if ((context_menu_orientation) && + (!strcmp(context_menu_orientation, "vertical"))) + elm_ctxpopup_horizontal_set(ext_mod->popup, EINA_FALSE); + + EINA_LIST_FOREACH(ext_mod->items, l, it) + { + if (!strcmp(it->label, "Clipboard")) + has_clipboard = EINA_TRUE; +#if HAVE_APPSVC + else if (!strcmp(it->label, "Translate")) + has_translate = EINA_TRUE; +#endif + } + + if (!ext_mod->selmode && !ext_mod->have_selection) + { + if (!elm_entry_is_empty(obj)) + { + if (!ext_mod->password) + { +#ifndef ELM_FEATURE_WEARABLE + CP_ICON_ADD(icon, "select"); + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_SK_SELECT"), icon, _select, obj); + ACCESS_FOCUS_ENABLE(); +#endif + } + + CP_ICON_ADD(icon, "select_all"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _select_all, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_SELECT_ALL"), + icon, _select_all, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + +#ifdef HAVE_ELEMENTARY_X + if (cbhm_count) +#else + if (1) // need way to detect if someone has a selection +#endif + { + if (elm_entry_cnp_mode_get(obj) == ELM_CNP_MODE_PLAINTEXT) + { +#ifdef HAVE_ELEMENTARY_X + _cbhm_item_get(obj, 0, &first_cbhm_item_type, NULL); + if (ext_mod->editable && + !(first_cbhm_item_type == ecore_x_atom_get("text/uri")) && + !(first_cbhm_item_type == ecore_x_atom_get("text/uri-list"))) +#endif + { + CP_ICON_ADD(icon, "paste"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _paste, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_PASTE"), + icon, _paste, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + else + { + if (ext_mod->editable) + { + CP_ICON_ADD(icon, "paste"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _paste, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_PASTE"), + icon, _paste, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + } + // start for cbhm +#ifdef HAVE_ELEMENTARY_X + if ((ext_mod->editable) && (cbhm_count) && (has_clipboard)) +#else + if ((ext_mod->editable) && (has_clipboard)) +#endif + { + CP_ICON_ADD(icon, "clipboard"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _clipboard_menu, obj); // Clipboard +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_CLIPBOARD"), + icon, _clipboard_menu, obj); // Clipboard +#endif + ACCESS_FOCUS_ENABLE(); + } + // end for cbhm +#if HAVE_APPSVC + const char *entry_str; + entry_str = elm_entry_selection_get(obj); + if ((entry_str) && (has_translate)) + { + CP_ICON_ADD(icon, "translate"); + added_item = elm_ctxpopup_item_append(ext_mod->popup, S_TRANSLATE, + icon, _translate_menu, obj); + ACCESS_FOCUS_ENABLE(); + } +#endif + } + else + { + if (ext_mod->have_selection) + { + Eina_Bool selected_all = EINA_TRUE; + ext_mod->is_selected_all(&selected_all, obj, NULL); + if (selected_all == EINA_FALSE) + { + CP_ICON_ADD(icon, "select_all"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _select_all, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_SELECT_ALL"), + icon, _select_all, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + + if (!ext_mod->password) + { + CP_ICON_ADD(icon, "copy"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _copy, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_COPY"), + icon, _copy, obj); +#endif + ACCESS_FOCUS_ENABLE(); + if (ext_mod->editable) + { + CP_ICON_ADD(icon, "cut"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _cut, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_CUT"), + icon, _cut, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + +#ifdef HAVE_ELEMENTARY_X + if (ext_mod->editable && cbhm_count) +#else + if (ext_mod->editable) +#endif + { + if (elm_entry_cnp_mode_get(obj) == ELM_CNP_MODE_PLAINTEXT) + { +#ifdef HAVE_ELEMENTARY_X + _cbhm_item_get(obj, 0, &first_cbhm_item_type, NULL); + if (!(first_cbhm_item_type == ecore_x_atom_get("text/uri")) && + !(first_cbhm_item_type == ecore_x_atom_get("text/uri-list"))) +#endif + { + CP_ICON_ADD(icon, "paste"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _paste, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_PASTE"), + icon, _paste, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + else + { + CP_ICON_ADD(icon, "paste"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _paste, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_PASTE"), + icon, _paste, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + } + else + { + _cancel(obj,ext_mod->popup,NULL); + if (!elm_entry_is_empty(obj)) + { + if (!ext_mod->password) + { +#ifndef ELM_FEATURE_WEARABLE + CP_ICON_ADD(icon, "select"); + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_SK_SELECT"), + icon, _select, obj); + ACCESS_FOCUS_ENABLE(); +#endif + } + + CP_ICON_ADD(icon, "select_all"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _select_all, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_SELECT_ALL"), + icon, _select_all, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } +#ifdef HAVE_ELEMENTARY_X + if (cbhm_count) +#else + if (1) // need way to detect if someone has a selection +#endif + { + if (ext_mod->editable) + { + if (elm_entry_cnp_mode_get(obj) == ELM_CNP_MODE_PLAINTEXT) + { +#ifdef HAVE_ELEMENTARY_X + _cbhm_item_get(obj, 0, &first_cbhm_item_type, NULL); + if (!(first_cbhm_item_type == ecore_x_atom_get("text/uri")) && + !(first_cbhm_item_type == ecore_x_atom_get("text/uri-list"))) +#endif + { + CP_ICON_ADD(icon, "paste"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _paste, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_PASTE"), + icon, _paste, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + else + { + CP_ICON_ADD(icon, "paste"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _paste, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_PASTE"), + icon, _paste, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + } + } + // start for cbhm +#ifdef HAVE_ELEMENTARY_X + if ((ext_mod->editable) && (cbhm_count) && (has_clipboard)) +#else + if ((ext_mod->editable) && (has_clipboard)) +#endif + { + CP_ICON_ADD(icon, "clipboard"); +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + icon, _clipboard_menu, obj); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, dgettext("elementary", "IDS_COM_BODY_CLIPBOARD"), + icon, _clipboard_menu, obj); +#endif + ACCESS_FOCUS_ENABLE(); + } + // end for cbhm +#if HAVE_APPSVC + const char *entry_str; + entry_str = elm_entry_selection_get(obj); + if ((entry_str) && (has_translate)) + { + CP_ICON_ADD(icon, "translate"); + added_item = elm_ctxpopup_item_append(ext_mod->popup, S_TRANSLATE, + icon, _translate_menu, obj); + ACCESS_FOCUS_ENABLE(); + } +#endif + } + EINA_LIST_FOREACH(ext_mod->items, l, it) + { + if (strcmp(it->label, "Clipboard") && strcmp(it->label, "Translate")) + { + Evas_Object *ic = NULL; + if (it->icon_file) + { + ic = elm_icon_add(obj); + elm_image_resizable_set(ic, EINA_FALSE, EINA_TRUE); + if (it->icon_type == ELM_ICON_FILE) + elm_image_file_set(ic, it->icon_file, it->icon_group); + else if (it->icon_type == ELM_ICON_STANDARD) + elm_icon_standard_set(ic, it->icon_file); + } +#ifdef ELM_FEATURE_WEARABLE + added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, + ic, _item_clicked, it ); +#else + added_item = elm_ctxpopup_item_append(ext_mod->popup, it->label, + ic, _item_clicked, it ); +#endif + ACCESS_FOCUS_ENABLE(); + } + } + if (ext_mod->popup && added_item) + { + Evas_Object *first_it_ao, *cur_it_ao, *prev_it_ao; + Evas_Object *popup_ao; + Elm_Widget_Smart_Data *wd; + Evas_Object *po; + int layer; + int count, itn; + Eina_List *lc; + + ext_mod->caller = obj; + if (_in_viewport_check()) + { + ext_mod->popup_showing = EINA_TRUE; + _ctxpopup_position(obj); + evas_object_show(ext_mod->popup); + ext_mod->popup_clicked = EINA_FALSE; + ext_mod->mouse_up = EINA_FALSE; + LOG("In viewport: will show popup\n"); + } + else + LOG("NOT IN VIEWPORT, NO POPUP SHOWING\n\n"); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _entry_move_cb, ext_mod->popup); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + _entry_mouse_down_cb, ext_mod->popup); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, + _entry_mouse_move_cb, ext_mod->popup); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, + _entry_mouse_up_cb, ext_mod->popup); + evas_object_event_callback_add(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_DOWN, + _parent_mouse_down_cb, ext_mod->popup); + evas_object_event_callback_add(ext_mod->ctx_par, EVAS_CALLBACK_MOUSE_UP, + _parent_mouse_up_cb, ext_mod->popup); + if (ext_mod->ent_scroll) + { + evas_object_smart_callback_add(obj, "scroll", _entry_scroll_cb, ext_mod->popup); + } + layer = evas_object_layer_get(ext_mod->caller); + layer = layer >= EVAS_LAYER_MAX ? EVAS_LAYER_MAX : layer + 1; + evas_object_layer_set(ext_mod->popup, layer); + + if (ext_mod->_elm_config->access_mode) + { + wd = evas_object_smart_data_get(ext_mod->popup); + po = (Evas_Object *)edje_object_part_object_get(wd->resize_obj, + "access.outline"); + popup_ao = elm_access_object_get(po); + count = eina_list_count(lao); + first_it_ao = eina_list_data_get(lao); + elm_access_highlight_next_set(popup_ao, + ELM_HIGHLIGHT_DIR_NEXT, + first_it_ao); + elm_access_highlight_next_set(first_it_ao, + ELM_HIGHLIGHT_DIR_PREVIOUS, + popup_ao); + prev_it_ao = eina_list_data_get(lao); + itn = 1; + EINA_LIST_FOREACH(lao, lc, cur_it_ao) + { + if (itn == count) + { + elm_access_highlight_next_set(prev_it_ao, + ELM_HIGHLIGHT_DIR_NEXT, + cur_it_ao); + elm_access_highlight_next_set(cur_it_ao, + ELM_HIGHLIGHT_DIR_PREVIOUS, + prev_it_ao); + elm_access_highlight_next_set(cur_it_ao, + ELM_HIGHLIGHT_DIR_NEXT, + popup_ao); + elm_access_highlight_next_set(popup_ao, + ELM_HIGHLIGHT_DIR_PREVIOUS, + cur_it_ao); + } + else if (itn > 1) + { + elm_access_highlight_next_set(prev_it_ao, + ELM_HIGHLIGHT_DIR_NEXT, + cur_it_ao); + elm_access_highlight_next_set(cur_it_ao, + ELM_HIGHLIGHT_DIR_PREVIOUS, + prev_it_ao); + } + itn++; + prev_it_ao = cur_it_ao; + } + elm_access_highlight_set(popup_ao); + } + eina_list_free(lao); + } + else + ext_mod->caller = NULL; + } +} + +EAPI void +obj_mouseup(Evas_Object *obj) +{ + if (!obj || !ext_mod) + return; +} + + +EAPI void +obj_hidemenu(Evas_Object *obj) +{ + if (!obj || !ext_mod || obj != ext_mod->caller) + return; + + _ctxpopup_hide(ext_mod->popup); + // if (ext_mod->popup) evas_object_del(ext_mod->popup); +} + +EAPI void +obj_update_popup_pos(Evas_Object *obj) +{ + if (!obj || !ext_mod || !ext_mod->popup || !ext_mod->popup_showing || + (obj != ext_mod->caller)) + return; + + elm_entry_extension_module_data_get(obj, ext_mod); + LOG("call _ctxpopup_position"); + _ctxpopup_position(obj); +} + +EAPI Eina_Bool +obj_popup_showing_get(Evas_Object *obj) +{ + if ((!obj) || (!ext_mod) || (obj != ext_mod->caller)) + return EINA_FALSE; + if (!ext_mod->popup) + return EINA_FALSE; + return evas_object_visible_get(ext_mod->popup); +} -- 2.7.4