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 <mail@marcel-hollerbach.de>
Reviewed-by: WooHyun Jung <wh0705.jung@samsung.com>
Differential Revision: https://phab.enlightenment.org/D10968
This commit is contained in:
Ali Alzyod 2020-01-22 07:33:58 +00:00 committed by Marcel Hollerbach
parent 8143b81dd6
commit 4cdd5505e9
4 changed files with 178 additions and 35 deletions

View File

@ -25,13 +25,17 @@ interface @beta Efl.Text_Interactive extends Efl.Text, Efl.Text_Font_Properties,
} }
@property selection_cursors { @property selection_cursors {
[[The cursors used for selection handling. [[The cursors used for selection handling.
If the cursors are equal there's no selection. 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 { values {
start: Efl.Text.Cursor; [[The start of the selection.]] start: Efl.Text.Cursor; [[The start of the selection.]]
end: Efl.Text.Cursor; [[The end of the selection.]] end: Efl.Text.Cursor; [[The end of the selection.]]

View File

@ -14,6 +14,7 @@
typedef struct _Efl_Ui_Internal_Text_Interactive_Data typedef struct _Efl_Ui_Internal_Text_Interactive_Data
{ {
Efl_Text_Cursor *sel_start, *sel_end; Efl_Text_Cursor *sel_start, *sel_end;
Eina_Bool watch_selection;
Efl_Text_Cursor *main_cursor; Efl_Text_Cursor *main_cursor;
Efl_Text_Cursor *preedit_start, *preedit_end; Efl_Text_Cursor *preedit_start, *preedit_end;
Ecore_Timer *pw_timer; Ecore_Timer *pw_timer;
@ -44,13 +45,17 @@ typedef struct _Efl_Ui_Internal_Text_Interactive_Data
} 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_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_init(Efl_Text_Cursor *c, 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_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_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 _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 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 _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 static void
_text_filter_format_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en, _text_filter_format_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
Efl_Text_Cursor *c, const char *text); 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)); 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 #ifdef HAVE_ECORE_IMF
static void static void
_preedit_clear(Efl_Ui_Internal_Text_Interactive_Data *en) _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); _sel_clear(obj, en);
efl_text_cursor_position_set(cur, ev->start); efl_text_cursor_position_set(cur, ev->start);
_sel_enable(cur, obj, en); _sel_enable(obj, en);
_sel_init(cur, obj, en); _sel_init(cur, en);
efl_text_cursor_position_set(cur, ev->end); efl_text_cursor_position_set(cur, ev->end);
_sel_extend(cur, obj, en); _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 static void
_sel_cursor_changed(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) _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)
{ {
// Eo *obj = data; 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 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) if (en->have_selection)
return; return;
_sel_watch_freeze(en);
_cur_pos_copy(c, en->sel_start); _cur_pos_copy(c, en->sel_start);
_cur_pos_copy(c, en->sel_end); _cur_pos_copy(c, en->sel_end);
_sel_watch_thaw(en);
en->have_selection = EINA_FALSE; en->have_selection = EINA_FALSE;
if (en->selection) 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 static void
_sel_enable(Efl_Text_Cursor *c EINA_UNUSED, _sel_enable(Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en)
Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
{ {
if (en->have_selection) return; if (en->have_selection) return;
en->have_selection = EINA_TRUE; 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)) if (!efl_text_cursor_compare(en->sel_start, en->sel_end))
{ {
Eina_Bool b_value = EINA_FALSE; _sel_clear(o, en);
efl_event_callback_call(o, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED, &b_value);
} }
else else
{ {
@ -805,11 +870,12 @@ _emit_sel_state( Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en)
static void static void
_sel_extend(Efl_Text_Cursor *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en) _sel_extend(Efl_Text_Cursor *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en)
{ {
if (!en->sel_end) return; _sel_enable(o, en);
_sel_enable(c, o, en);
if (efl_text_cursor_equal(c, en->sel_end)) return; if (efl_text_cursor_equal(c, en->sel_end)) return;
_sel_watch_freeze(en);
_cur_pos_copy(c, en->sel_end); _cur_pos_copy(c, en->sel_end);
_sel_watch_thaw(en);
_entry_imf_cursor_info_set(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; en->have_selection = EINA_FALSE;
Eina_Bool b_value = en->have_selection; Eina_Bool b_value = en->have_selection;
_sel_watch_freeze(en);
_cur_pos_copy(en->sel_start, en->sel_end); _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); 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( _efl_ui_internal_text_interactive_efl_text_interactive_have_selection_get(
const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en) 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); return !efl_text_cursor_equal(en->sel_start, en->sel_end);
} }
EOLIAN static void EOLIAN static void
_efl_ui_internal_text_interactive_efl_text_interactive_all_select( _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)) if (!efl_text_interactive_selection_allowed_get(obj))
return; return;
Efl_Text_Cursor *cur = efl_text_interactive_main_cursor_get(obj); Eo *c1 = efl_canvas_textblock_cursor_create(obj);
_entry_imf_context_reset(en); Eo *c2 = efl_canvas_textblock_cursor_create(obj);
efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST); efl_text_cursor_move(c1, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
_entry_imf_context_reset(en); efl_text_cursor_move(c2, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
_sel_init(cur, obj, en);
efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LAST); efl_text_interactive_selection_cursors_set(obj, c1, c2);
_sel_extend(cur, obj, en);
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) if (shift)
{ {
_sel_init(cur, obj, en); _sel_init(cur, en);
} }
else if (en->have_selection) else if (en->have_selection)
{ {
@ -1032,6 +1103,7 @@ _key_down_sel_pre(Efl_Ui_Internal_Text_Interactive *obj, Efl_Text_Cursor *cur, E
_cur_pos_copy(en->sel_end, cur); _cur_pos_copy(en->sel_end, cur);
else else
_cur_pos_copy(en->sel_start, cur); _cur_pos_copy(en->sel_start, cur);
_sel_clear(obj, en); _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); tc = efl_canvas_textblock_cursor_create(obj);
_cur_pos_copy(cur, tc); _cur_pos_copy(cur, tc);
efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START); 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); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END);
_sel_extend(cur, obj, en); _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); tc = efl_canvas_textblock_cursor_create(obj);
_cur_pos_copy(cur, tc); _cur_pos_copy(cur, tc);
efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START); 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_WORD_END);
efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT); efl_text_cursor_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
_sel_extend(cur, obj, en); _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; en->selecting = EINA_TRUE;
_sel_clear(obj, en); _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); _sel_extend(cur, obj, en);
if (!efl_text_cursor_equal(en->sel_start, en->sel_end)) if (!efl_text_cursor_equal(en->sel_start, en->sel_end))
_sel_enable(cur, obj, en); _sel_enable(obj, en);
} }
efl_del(tc); 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)); obj = efl_constructor(efl_super(obj, MY_CLASS));
en->select_allow = EINA_TRUE; en->select_allow = EINA_TRUE;
en->editable = EINA_TRUE; en->editable = EINA_TRUE;
en->watch_selection = EINA_TRUE;
return obj; 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_start = efl_canvas_textblock_cursor_create(obj);
en->sel_end = 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); _sel_cursor_changed, obj);
#ifdef HAVE_ECORE_IMF #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 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) _efl_ui_internal_text_interactive_efl_text_interactive_editable_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd, Eina_Bool editable)
{ {

View File

@ -9,7 +9,7 @@ class @beta Efl.Ui.Internal.Text.Interactive extends Efl.Canvas.Textblock implem
Efl.Object.finalize; Efl.Object.finalize;
Efl.Text_Interactive.main_cursor { get; } Efl.Text_Interactive.main_cursor { get; }
Efl.Text_Interactive.selection_allowed { get; set; } 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.editable { get; set; }
Efl.Text_Interactive.all_unselect; Efl.Text_Interactive.all_unselect;
Efl.Text_Interactive.all_select; Efl.Text_Interactive.all_select;

View File

@ -72,6 +72,45 @@ EFL_START_TEST(text_all_select_all_unselect)
ecore_main_loop_iterate(); ecore_main_loop_iterate();
ck_assert_int_eq(i_have_selection, 2); ck_assert_int_eq(i_have_selection, 2);
ck_assert_int_eq(i_selection, 1); 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(txt);
efl_del(win); efl_del(win);
} }