elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs

Summary:
Cluster consist of one glyph, expected to be removed on backspace or delete key.
Cluster consist of multible glyph, expectd to remove part of on backspace or delete key.

This is behaviour founded in Android. (our current way of handling similar to Qt)

**New Behaviour**
{F3750386}

**Old Behaviour**
{F3750387}

Test Plan:
Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry
```
#include <Elementary.h>

EAPI_MAIN int
elm_main(int argc, char **argv)
{
   Evas_Object *win,*box,*entry;

   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

   win = elm_win_util_standard_add("", "");
   elm_win_autodel_set(win, EINA_TRUE);

   box = elm_box_add(win);
   entry = elm_entry_add(box);

   evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL);

   elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>");
   evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9);
   evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL);
   evas_object_show(entry);
   evas_object_show(box);

   elm_box_pack_end(box,entry);
   elm_win_resize_object_add(win,box);
   evas_object_resize(win,320,480);

   evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1);
   evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL);

   evas_object_show(win);
   elm_run();

   return 0;
}
ELM_MAIN()

```

Reviewers: tasn, woohyun, bowonryu

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D9628
This commit is contained in:
Ali Alzyod 2019-09-05 14:52:51 +09:00 committed by WooHyun Jung
parent 8dcd638829
commit 7a05d8d769
3 changed files with 128 additions and 11 deletions

View File

@ -1600,11 +1600,23 @@ static void
_delete_emit(Edje *ed, Evas_Textblock_Cursor *c, Entry *en, size_t pos,
Eina_Bool backspace)
{
if (!evas_textblock_cursor_char_next(c))
if (backspace)
{
return;
if (!evas_textblock_cursor_char_prev(c))
{
return;
}
evas_textblock_cursor_char_next(c);
}
else
{
if (!evas_textblock_cursor_char_next(c))
{
return;
}
evas_textblock_cursor_char_prev(c);
}
evas_textblock_cursor_char_prev(c);
Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
if (!info)
@ -1617,16 +1629,40 @@ _delete_emit(Edje *ed, Evas_Textblock_Cursor *c, Entry *en, size_t pos,
info->insert = EINA_FALSE;
if (backspace)
{
info->change.del.start = pos - 1;
Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(en->rp->object);
evas_textblock_cursor_copy(c, cc);
Eina_Bool remove_cluster = evas_textblock_cursor_at_cluster_as_single_glyph(cc,EINA_FALSE);
if (remove_cluster)
{
evas_textblock_cursor_cluster_prev(cc);
}
else
{
evas_textblock_cursor_char_prev(cc);
}
info->change.del.start = evas_textblock_cursor_pos_get(cc);
info->change.del.end = pos;
tmp = evas_textblock_cursor_content_get(c);
evas_textblock_cursor_char_delete(c);
tmp = evas_textblock_cursor_range_text_get(c, cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
evas_textblock_cursor_range_delete(c, cc);
evas_textblock_cursor_free(cc);
}
else
{
Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(en->rp->object);
evas_textblock_cursor_copy(c, cc);
evas_textblock_cursor_cluster_next(cc);
Eina_Bool remove_cluster = evas_textblock_cursor_at_cluster_as_single_glyph(cc,EINA_TRUE);
if (remove_cluster)
{
evas_textblock_cursor_cluster_next(cc);
}
else
{
evas_textblock_cursor_char_next(cc);
}
info->change.del.start = evas_textblock_cursor_pos_get(cc);
info->change.del.end = pos;
@ -1954,7 +1990,7 @@ _edje_key_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
}
else
{
if (evas_textblock_cursor_char_prev(en->cursor))
//if (evas_textblock_cursor_char_prev(en->cursor))
{
_delete_emit(ed, en->cursor, en, old_cur_pos, EINA_TRUE);
}

View File

@ -148,6 +148,17 @@ EWAPI extern const Efl_Event_Description _EFL_ANIMATION_PLAYER_EVENT_PRE_STARTED
#define EFL_ANIMATION_PLAYER_EVENT_PRE_STARTED (&(_EFL_ANIMATION_PLAYER_EVENT_PRE_STARTED))
/* Efl.Animation.Player END */
/*TextBlock Internal function*/
/**
* Check if cursor is at cluster with one glyph (replace codepoints with new codepoint).
*
* @param cur the cursor.
* @param forward if Eina_True check cluster after cusror position, else before cursor position.
*/
EAPI Eina_Bool evas_textblock_cursor_at_cluster_as_single_glyph(Evas_Textblock_Cursor *cur,Eina_Bool forward);
#ifdef __cplusplus
}
#endif

View File

@ -9662,7 +9662,7 @@ _evas_textblock_grapheme_breaks_new(Evas_Object_Textblock_Item *it, size_t len)
}
static size_t
_evas_textblock_cursor_cluster_pos_get(Evas_Textblock_Cursor *cur, Eina_Bool inc)
_evas_textblock_cursor_cluster_pos_get(Evas_Textblock_Cursor *cur, Eina_Bool inc, Eina_Bool *is_single_glyph)
{
Evas_Object_Textblock_Paragraph *par;
Efl_Canvas_Text_Data *o;
@ -9728,6 +9728,64 @@ _evas_textblock_cursor_cluster_pos_get(Evas_Textblock_Cursor *cur, Eina_Bool inc
free(grapheme_breaks);
}
if (is_single_glyph)
{
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(last_it);
Evas_Text_Props_Info *info = ti->text_props.info;
int it_index = ((inc) ? cur->pos : ret) - last_it->text_pos;
Evas_Font_OT_Info ot;
if (ti->text_props.len != ti->text_props.text_len)/*if code point count same as glyph count skip it*/
{
Evas_BiDi_Direction itdir = ti->text_props.bidi_dir;
int i = 0;
if (itdir == EFL_TEXT_BIDIRECTIONAL_TYPE_RTL)
{
for (i = ti->text_props.len-1 ; i >= 0; i--)
{
ot = info->ot[i];
if (ot.source_cluster >= (size_t)it_index)
break;
}
if (i <= 0)
{
if (ti->text_props.text_len - ot.source_cluster >= 2)
*is_single_glyph = EINA_TRUE;
}
else
{
Evas_Font_OT_Info ot_next = info->ot[i - 1];
if (ot_next.source_cluster - ot.source_cluster >= 2)
*is_single_glyph = EINA_TRUE;
}
}
else
{
for (i = 0; i < (int) ti->text_props.len; i++)
{
ot = info->ot[i];
if ((int)ot.source_cluster >= it_index)
break;
}
if ((i + 1) >= (int) ti->text_props.len)
{
if (ti->text_props.text_len - ot.source_cluster >= 2)
*is_single_glyph = EINA_TRUE;
}
else
{
Evas_Font_OT_Info ot_next = info->ot[i + 1];
if (ot_next.source_cluster - ot.source_cluster >= 2)
*is_single_glyph = EINA_TRUE;
}
}
}
else
{
is_single_glyph = EINA_FALSE;
}
}
}
}
}
@ -9735,6 +9793,18 @@ _evas_textblock_cursor_cluster_pos_get(Evas_Textblock_Cursor *cur, Eina_Bool inc
return ret;
}
EAPI Eina_Bool evas_textblock_cursor_at_cluster_as_single_glyph(Evas_Textblock_Cursor *cur,Eina_Bool forward)
{
Eina_Bool is_single_glyph = EINA_FALSE;
size_t ret = _evas_textblock_cursor_cluster_pos_get(cur, forward, &is_single_glyph);
if ((abs(ret-cur->pos) > 1) && is_single_glyph)
{
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_evas_textblock_cursor_next(Evas_Textblock_Cursor *cur, Eina_Bool per_cluster)
{
@ -9754,7 +9824,7 @@ _evas_textblock_cursor_next(Evas_Textblock_Cursor *cur, Eina_Bool per_cluster)
if (text[ind])
{
if (per_cluster)
ind = _evas_textblock_cursor_cluster_pos_get(cur, EINA_TRUE);
ind = _evas_textblock_cursor_cluster_pos_get(cur, EINA_TRUE, NULL);
if (ind <= (int)cur->pos)
ind = cur->pos + 1;
@ -9801,7 +9871,7 @@ _evas_textblock_cursor_prev(Evas_Textblock_Cursor *cur, Eina_Bool per_cluster)
{
if (per_cluster)
{
size_t ret = _evas_textblock_cursor_cluster_pos_get(cur, EINA_FALSE);
size_t ret = _evas_textblock_cursor_cluster_pos_get(cur, EINA_FALSE, NULL);
if (ret != cur->pos)
{