From 4cdd5505e957c6cdf6ac0f6f99cda3295ab23bc1 Mon Sep 17 00:00:00 2001 From: Ali Alzyod Date: Wed, 22 Jan 2020 07:33:58 +0000 Subject: [PATCH] efl_text_interactive: selection enhancment 1- Implement setting selection range programmatically by modifying selection cursors from **efl_text_interactive_selection_cursors_get** 2- Add setter with **efl_text_interactive_selection_cursors_set** to set the range at once (modify start and end) Reviewed-by: Marcel Hollerbach Reviewed-by: WooHyun Jung Differential Revision: https://phab.enlightenment.org/D10968 --- src/lib/elementary/efl_text_interactive.eo | 14 +- .../efl_ui_internal_text_interactive.c | 158 ++++++++++++++---- .../efl_ui_internal_text_interactive.eo | 2 +- src/tests/elementary/efl_ui_test_text.c | 39 +++++ 4 files changed, 178 insertions(+), 35 deletions(-) diff --git a/src/lib/elementary/efl_text_interactive.eo b/src/lib/elementary/efl_text_interactive.eo index f090648bf3..cc15cdc15b 100644 --- a/src/lib/elementary/efl_text_interactive.eo +++ b/src/lib/elementary/efl_text_interactive.eo @@ -25,13 +25,17 @@ interface @beta Efl.Text_Interactive extends Efl.Text, Efl.Text_Font_Properties, } @property selection_cursors { [[The cursors used for selection handling. - If the cursors are equal there's no selection. - - You are allowed to retain and modify them. Modifying them modifies - the selection of the object. ]] - get {} + get { + [[You are allowed to retain and modify them. Modifying them modifies + the selection of the object (recommended to extend selection range).]] + } + set { + [[The positions of passed cursors will be used to set selection cursors positions. + Further modification for passed @Efl.Text.Cursor objects, will not affect selection. + Setter is recommended to set new range for selection.]] + } values { start: Efl.Text.Cursor; [[The start of the selection.]] end: Efl.Text.Cursor; [[The end of the selection.]] diff --git a/src/lib/elementary/efl_ui_internal_text_interactive.c b/src/lib/elementary/efl_ui_internal_text_interactive.c index dd9f8a41f8..63b722cfea 100644 --- a/src/lib/elementary/efl_ui_internal_text_interactive.c +++ b/src/lib/elementary/efl_ui_internal_text_interactive.c @@ -14,6 +14,7 @@ typedef struct _Efl_Ui_Internal_Text_Interactive_Data { Efl_Text_Cursor *sel_start, *sel_end; + Eina_Bool watch_selection; Efl_Text_Cursor *main_cursor; Efl_Text_Cursor *preedit_start, *preedit_end; Ecore_Timer *pw_timer; @@ -44,13 +45,17 @@ typedef struct _Efl_Ui_Internal_Text_Interactive_Data } Efl_Ui_Internal_Text_Interactive_Data; static void _sel_range_del_emit(Evas_Object *obj, Efl_Ui_Internal_Text_Interactive_Data *en); -static void _sel_init(Efl_Text_Cursor *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en); -static void _sel_enable(Efl_Text_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en); +static void _sel_init(Efl_Text_Cursor *c, Efl_Ui_Internal_Text_Interactive_Data *en); +static void _sel_enable(Evas_Object *o,Efl_Ui_Internal_Text_Interactive_Data *en); static void _sel_extend(Efl_Text_Cursor *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en); static void _sel_clear(Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en); +static void _emit_sel_state( Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en); static const char *_entry_selection_get(Efl_Ui_Internal_Text_Interactive *obj, Efl_Ui_Internal_Text_Interactive_Data *en); static void _entry_imf_cursor_info_set(Efl_Ui_Internal_Text_Interactive_Data *en); +static void _sel_watch_freeze(Efl_Ui_Internal_Text_Interactive_Data *en); +static void _sel_watch_thaw(Efl_Ui_Internal_Text_Interactive_Data *en); + static void _text_filter_format_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Text_Cursor *c, const char *text); @@ -82,6 +87,18 @@ _cur_pos_copy(Efl_Text_Cursor *src, Efl_Text_Cursor *dest) efl_text_cursor_position_set(dest, efl_text_cursor_position_get(src)); } +static void +_sel_watch_freeze(Efl_Ui_Internal_Text_Interactive_Data *en) +{ + en->watch_selection = EINA_FALSE; +} + +static void +_sel_watch_thaw(Efl_Ui_Internal_Text_Interactive_Data *en) +{ + en->watch_selection = EINA_TRUE; +} + #ifdef HAVE_ECORE_IMF static void _preedit_clear(Efl_Ui_Internal_Text_Interactive_Data *en) @@ -628,8 +645,8 @@ _entry_imf_event_selection_set_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED { _sel_clear(obj, en); efl_text_cursor_position_set(cur, ev->start); - _sel_enable(cur, obj, en); - _sel_init(cur, obj, en); + _sel_enable(obj, en); + _sel_init(cur, en); efl_text_cursor_position_set(cur, ev->end); _sel_extend(cur, obj, en); } @@ -747,19 +764,69 @@ _entry_selection_get(Efl_Ui_Internal_Text_Interactive *obj EINA_UNUSED, Efl_Ui_I } static void -_sel_cursor_changed(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) -{ -// Eo *obj = data; +_sel_reset(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en){ + + if (!en->watch_selection) + return; + + if (!en->have_selection && efl_text_cursor_equal(en->sel_start, en->sel_end)) + return; + + if (en->have_selection) + { + if (efl_text_cursor_equal(en->sel_start, en->sel_end)) + { + _sel_clear(obj, en); + } + else + { + _entry_imf_cursor_info_set(en); + if (en->selection) + { + free(en->selection); + en->selection = NULL; + } + _emit_sel_state(obj, en); + } + } + else + { + if (!efl_text_cursor_equal(en->sel_start, en->sel_end)) + { + _sel_enable(obj, en); + _entry_imf_cursor_info_set(en); + if (en->selection) + { + free(en->selection); + en->selection = NULL; + } + _emit_sel_state(obj, en); + } + } } static void -_sel_init(Efl_Text_Cursor *c, Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en) +_sel_cursor_changed(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) +{ + Efl_Ui_Internal_Text_Interactive *obj = data; + Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS); + + if (!efl_text_interactive_selection_allowed_get(obj)) + return; + + _sel_reset(obj, en); +} + +static void +_sel_init(Efl_Text_Cursor *c, Efl_Ui_Internal_Text_Interactive_Data *en) { if (en->have_selection) return; + _sel_watch_freeze(en); _cur_pos_copy(c, en->sel_start); _cur_pos_copy(c, en->sel_end); + _sel_watch_thaw(en); en->have_selection = EINA_FALSE; if (en->selection) @@ -770,8 +837,7 @@ _sel_init(Efl_Text_Cursor *c, Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_I } static void -_sel_enable(Efl_Text_Cursor *c EINA_UNUSED, - Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en) +_sel_enable(Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en) { if (en->have_selection) return; en->have_selection = EINA_TRUE; @@ -791,8 +857,7 @@ _emit_sel_state( Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en) { if (!efl_text_cursor_compare(en->sel_start, en->sel_end)) { - Eina_Bool b_value = EINA_FALSE; - efl_event_callback_call(o, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED, &b_value); + _sel_clear(o, en); } else { @@ -805,11 +870,12 @@ _emit_sel_state( Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en) static void _sel_extend(Efl_Text_Cursor *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en) { - if (!en->sel_end) return; - _sel_enable(c, o, en); + _sel_enable(o, en); if (efl_text_cursor_equal(c, en->sel_end)) return; + _sel_watch_freeze(en); _cur_pos_copy(c, en->sel_end); + _sel_watch_thaw(en); _entry_imf_cursor_info_set(en); @@ -835,7 +901,9 @@ _sel_clear(Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en { en->have_selection = EINA_FALSE; Eina_Bool b_value = en->have_selection; + _sel_watch_freeze(en); _cur_pos_copy(en->sel_start, en->sel_end); + _sel_watch_thaw(en); efl_event_callback_call(o, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED, &b_value); } } @@ -851,25 +919,28 @@ EOLIAN static Eina_Bool _efl_ui_internal_text_interactive_efl_text_interactive_have_selection_get( const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en) { + if (!en->have_selection) return en->have_selection; return !efl_text_cursor_equal(en->sel_start, en->sel_end); } EOLIAN static void _efl_ui_internal_text_interactive_efl_text_interactive_all_select( - Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en) + Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en EINA_UNUSED) { if (!efl_text_interactive_selection_allowed_get(obj)) return; - Efl_Text_Cursor *cur = efl_text_interactive_main_cursor_get(obj); - _entry_imf_context_reset(en); + Eo *c1 = efl_canvas_textblock_cursor_create(obj); + Eo *c2 = efl_canvas_textblock_cursor_create(obj); - efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST); - _entry_imf_context_reset(en); - _sel_init(cur, obj, en); - efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LAST); - _sel_extend(cur, obj, en); + efl_text_cursor_move(c1, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST); + efl_text_cursor_move(c2, EFL_TEXT_CURSOR_MOVE_TYPE_LAST); + + efl_text_interactive_selection_cursors_set(obj, c1, c2); + + efl_del(c1); + efl_del(c2); } @@ -1023,7 +1094,7 @@ _key_down_sel_pre(Efl_Ui_Internal_Text_Interactive *obj, Efl_Text_Cursor *cur, E { if (shift) { - _sel_init(cur, obj, en); + _sel_init(cur, en); } else if (en->have_selection) { @@ -1031,7 +1102,8 @@ _key_down_sel_pre(Efl_Ui_Internal_Text_Interactive *obj, Efl_Text_Cursor *cur, E if ((sel_forward && movement_forward) || (!sel_forward && !movement_forward)) _cur_pos_copy(en->sel_end, cur); else - _cur_pos_copy(en->sel_start, cur); + _cur_pos_copy(en->sel_start, cur); + _sel_clear(obj, en); } } @@ -1570,7 +1642,7 @@ _mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EIN tc = efl_canvas_textblock_cursor_create(obj); _cur_pos_copy(cur, tc); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START); - _sel_init(cur, obj, en); + _sel_init(cur, en); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END); _sel_extend(cur, obj, en); } @@ -1599,7 +1671,7 @@ _mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EIN tc = efl_canvas_textblock_cursor_create(obj); _cur_pos_copy(cur, tc); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START); - _sel_init(cur, obj, en); + _sel_init(cur, en); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT); _sel_extend(cur, obj, en); @@ -1619,7 +1691,7 @@ _mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EIN { en->selecting = EINA_TRUE; _sel_clear(obj, en); - _sel_init(cur, obj, en); + _sel_init(cur, en); } } @@ -1718,7 +1790,7 @@ _mouse_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, vo _sel_extend(cur, obj, en); if (!efl_text_cursor_equal(en->sel_start, en->sel_end)) - _sel_enable(cur, obj, en); + _sel_enable(obj, en); } efl_del(tc); } @@ -1736,6 +1808,7 @@ _efl_ui_internal_text_interactive_efl_object_constructor(Eo *obj, Efl_Ui_Interna obj = efl_constructor(efl_super(obj, MY_CLASS)); en->select_allow = EINA_TRUE; en->editable = EINA_TRUE; + en->watch_selection = EINA_TRUE; return obj; } @@ -1753,7 +1826,9 @@ _efl_ui_internal_text_interactive_efl_object_finalize(Eo *obj, Efl_Ui_Internal_T en->sel_start = efl_canvas_textblock_cursor_create(obj); en->sel_end = efl_canvas_textblock_cursor_create(obj); - efl_event_callback_add(efl_text_interactive_main_cursor_get(obj), EFL_TEXT_CURSOR_EVENT_CHANGED, + efl_event_callback_add(en->sel_start, EFL_TEXT_CURSOR_EVENT_CHANGED, + _sel_cursor_changed, obj); + efl_event_callback_add(en->sel_end, EFL_TEXT_CURSOR_EVENT_CHANGED, _sel_cursor_changed, obj); #ifdef HAVE_ECORE_IMF @@ -1872,6 +1947,31 @@ _efl_ui_internal_text_interactive_efl_text_interactive_selection_cursors_get(con } } +EOLIAN static void +_efl_ui_internal_text_interactive_efl_text_interactive_selection_cursors_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Text_Cursor *start, Efl_Text_Cursor *end) +{ + if (!efl_text_interactive_selection_allowed_get(obj)) + return; + + int new_sel_start_pos = efl_text_cursor_position_get(start); + int new_sel_end_pos = efl_text_cursor_position_get(end); + + int current_sel_start_pos = efl_text_cursor_position_get(en->sel_start); + int current_sel_end_pos = efl_text_cursor_position_get(en->sel_end); + + Eina_Bool b_start_changed = (new_sel_start_pos == current_sel_start_pos); + Eina_Bool b_end_changed = (new_sel_end_pos == current_sel_end_pos); + + if (b_start_changed && b_end_changed) + return; + + _sel_watch_freeze(en); + efl_text_cursor_position_set(en->sel_start, new_sel_start_pos); + efl_text_cursor_position_set(en->sel_end, new_sel_end_pos); + _sel_watch_thaw(en); + _sel_reset(obj, en); +} + EOLIAN static void _efl_ui_internal_text_interactive_efl_text_interactive_editable_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd, Eina_Bool editable) { diff --git a/src/lib/elementary/efl_ui_internal_text_interactive.eo b/src/lib/elementary/efl_ui_internal_text_interactive.eo index 448f7a0c6c..0688334500 100644 --- a/src/lib/elementary/efl_ui_internal_text_interactive.eo +++ b/src/lib/elementary/efl_ui_internal_text_interactive.eo @@ -9,7 +9,7 @@ class @beta Efl.Ui.Internal.Text.Interactive extends Efl.Canvas.Textblock implem Efl.Object.finalize; Efl.Text_Interactive.main_cursor { get; } Efl.Text_Interactive.selection_allowed { get; set; } - Efl.Text_Interactive.selection_cursors { get; } + Efl.Text_Interactive.selection_cursors { get; set; } Efl.Text_Interactive.editable { get; set; } Efl.Text_Interactive.all_unselect; Efl.Text_Interactive.all_select; diff --git a/src/tests/elementary/efl_ui_test_text.c b/src/tests/elementary/efl_ui_test_text.c index a49c7e7cc9..b7886544f1 100644 --- a/src/tests/elementary/efl_ui_test_text.c +++ b/src/tests/elementary/efl_ui_test_text.c @@ -72,6 +72,45 @@ EFL_START_TEST(text_all_select_all_unselect) ecore_main_loop_iterate(); ck_assert_int_eq(i_have_selection, 2); ck_assert_int_eq(i_selection, 1); + + /*Partial select, the select all*/ + Eo *sel1, *sel2; + i_selection = 0; + efl_text_interactive_selection_cursors_get(txt, &sel1, &sel2); + efl_text_cursor_position_set(sel1, 1); + efl_text_cursor_position_set(sel2, 2); + ck_assert_int_eq(i_selection, 2); + efl_text_interactive_all_select(txt); + ck_assert_int_eq(i_selection, 3); + ck_assert_int_eq(efl_text_cursor_position_get(sel1), 0); + ck_assert_int_eq(efl_text_cursor_position_get(sel2), 5); + + Eo *cur1 = efl_ui_textbox_cursor_create(txt); + Eo *cur2 = efl_ui_textbox_cursor_create(txt); + efl_text_cursor_position_set(cur1, 1); + efl_text_cursor_position_set(cur2, 2); + efl_text_interactive_selection_cursors_set(txt, cur1, cur2); + ck_assert_int_eq(i_selection, 4); + efl_text_interactive_selection_cursors_get(txt, &sel1, &sel2); + ck_assert_int_eq(efl_text_cursor_position_get(sel1),1); + ck_assert_int_eq(efl_text_cursor_position_get(sel2),2); + + + /*Select part then select all*/ + efl_text_interactive_all_unselect(txt); + i_have_selection = 0, i_selection = 0; + efl_text_cursor_position_set(cur1, 1); + efl_text_cursor_position_set(cur2, 2); + efl_text_interactive_selection_cursors_set(txt, cur1, cur2); + ck_assert_int_eq(i_selection, 1); + ck_assert_int_eq(i_have_selection, 1); + efl_text_interactive_all_select(txt); + ck_assert_int_eq(i_selection, 2); + ck_assert_int_eq(i_have_selection, 1); + efl_text_interactive_all_unselect(txt); + ck_assert_int_eq(i_have_selection, 2); + + efl_del(txt); efl_del(win); }