From a70abbb3811bd9426bc3e30bd70fb3b027cc29e6 Mon Sep 17 00:00:00 2001 From: Tom 'TAsn' Hacohen Date: Mon, 14 Jan 2013 16:18:07 +0000 Subject: [PATCH] Efl textblock/entry: Added support for split BiDi cursor. If logical cursor is between LTR/RTL text two cursors will be shown. Upper cursor is shown for the text of the same direction as paragraph, lower cursor - for opposite. NOT DONE YET Signed-off-by: Tom 'TAsn' Hacohen --- src/lib/edje/edje_entry.c | 38 ++++++++- src/lib/evas/Evas.h | 5 ++ src/lib/evas/canvas/evas_object_textblock.c | 94 +++++++++++++++++++++ 3 files changed, 134 insertions(+), 3 deletions(-) diff --git a/src/lib/edje/edje_entry.c b/src/lib/edje/edje_entry.c index 5f43d39a28..d7b0f771c6 100644 --- a/src/lib/edje/edje_entry.c +++ b/src/lib/edje/edje_entry.c @@ -21,7 +21,7 @@ struct _Entry Edje_Real_Part *rp; Edje *ed; Evas_Object *cursor_bg; - Evas_Object *cursor_fg; + Evas_Object *cursor_fg, *cursor_fg2; Evas_Textblock_Cursor *cursor; Evas_Textblock_Cursor *sel_start, *sel_end; Evas_Textblock_Cursor *cursor_user, *cursor_user_extra; @@ -2406,12 +2406,26 @@ _edje_entry_real_part_init(Edje *ed, Edje_Real_Part *rp) evas_object_pass_events_set(en->cursor_fg, EINA_TRUE); _edje_subobj_register(ed, en->cursor_fg); + /* A proxy to the main cursor. */ + if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE) + { + en->cursor_fg2 = evas_object_image_add(rp->edje->base->evas); + evas_object_image_source_set(en->cursor_fg2, en->cursor_fg); + evas_object_image_fill_set(en->cursor_fg2, 0, 0, 1, 1); + evas_object_smart_member_add(en->cursor_fg2, rp->edje->obj); + evas_object_stack_above(en->cursor_fg2, rp->object); + evas_object_clip_set(en->cursor_fg2, evas_object_clip_get(rp->object)); + evas_object_pass_events_set(en->cursor_fg2, EINA_TRUE); + _edje_subobj_register(en->rp->edje, en->cursor_fg2); + } + evas_object_textblock_legacy_newline_set(rp->object, EINA_TRUE); if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE) { evas_object_show(en->cursor_bg); evas_object_show(en->cursor_fg); + evas_object_show(en->cursor_fg2); en->input_panel_enable = EINA_TRUE; #ifdef HAVE_ECORE_IMF @@ -2487,6 +2501,7 @@ _edje_entry_real_part_shutdown(Edje *ed, Edje_Real_Part *rp) #endif evas_object_del(en->cursor_bg); evas_object_del(en->cursor_fg); + evas_object_del(en->cursor_fg2); if (en->pw_timer) { @@ -2519,9 +2534,10 @@ _edje_entry_real_part_shutdown(Edje *ed, Edje_Real_Part *rp) void _edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp) { - Evas_Coord x, y, w, h, xx, yy, ww, hh; + Evas_Coord x, y, w, h, xx, yy, ww, hh, xx2, yy2; Entry *en; Evas_Textblock_Cursor_Type cur_type; + Eina_Bool bidi_cursor = EINA_FALSE; if ((rp->type != EDJE_RP_TYPE_TEXT) || (!rp->typedata.text)) return; @@ -2543,7 +2559,7 @@ _edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp) x = y = w = h = -1; xx = yy = ww = hh = -1; evas_object_geometry_get(rp->object, &x, &y, &w, &h); - evas_textblock_cursor_geometry_get(en->cursor, &xx, &yy, &ww, &hh, NULL, cur_type); + bidi_cursor = evas_textblock_cursor_geometry_bidi_get(en->cursor, &xx, &yy, &ww, &hh, &xx2, &yy2, NULL, NULL, cur_type); if (ww < 1) ww = 1; if (hh < 1) hh = 1; if (en->cursor_bg) @@ -2556,6 +2572,22 @@ _edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp) evas_object_move(en->cursor_fg, x + xx, y + yy); evas_object_resize(en->cursor_fg, ww, hh); } + if (en->cursor_fg2) + { + if (bidi_cursor) + { + evas_object_image_fill_set(en->cursor_fg2, 0, 0, ww, hh / 2); + evas_object_move(en->cursor_fg2, x + xx2, y + yy2 + (hh / 2)); + evas_object_resize(en->cursor_fg, ww, hh / 2); + evas_object_resize(en->cursor_fg2, ww, hh / 2); + + evas_object_show(en->cursor_fg2); + } + else + { + evas_object_hide(en->cursor_fg2); + } + } } const char * diff --git a/src/lib/evas/Evas.h b/src/lib/evas/Evas.h index 900836e533..9d3603b06b 100644 --- a/src/lib/evas/Evas.h +++ b/src/lib/evas/Evas.h @@ -11628,6 +11628,11 @@ EAPI char *evas_textblock_cursor_range_text_g */ EAPI char *evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; +/** FIXME: doc. + * The cw2 and etc are not valid if false is returned. */ +EAPI Eina_Bool +evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype); + /** * Returns the geometry of the cursor. Depends on the type of cursor requested. * This should be used instead of char_geometry_get because there are weird diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index fce36eec79..994b258a65 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -8950,6 +8950,100 @@ evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) return EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(text[cur->pos]); } +EAPI Eina_Bool +evas_textblock_cursor_geometry_bidi_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_Coord *cx2, Evas_Coord *cy2, Evas_Coord *cw2, Evas_Coord *ch2, Evas_Textblock_Cursor_Type ctype) +{ + const Evas_Textblock_Cursor *dir_cur; + Evas_Textblock_Cursor cur2; + if (!cur) return EINA_FALSE; + Evas_Object_Textblock *o = eo_data_get(cur->obj, MY_CLASS); + if (!o->formatted.valid) _relayout(cur->obj); + + dir_cur = cur; + if (ctype == EVAS_TEXTBLOCK_CURSOR_UNDER) + { + evas_textblock_cursor_pen_geometry_get(cur, cx, cy, cw, ch); + return EINA_FALSE; + } + else + { + Evas_Object_Textblock_Line *ln = NULL; + Evas_Object_Textblock_Item *it = NULL; + _find_layout_item_match(cur, &ln, &it); + if (ln && it) + { + if (cw) *cw = 0; + if (cw2) *cw2 = 0; + /* If we are at the start or the end of the item there's a chance + * we'll want a split cursor. + * FIXME: Handle the last char of the last paragraph. + * FIXME: Handle multiple items of the same direction. + * FIXME: Handle items across different lines.. */ + if (cur->pos == it->text_pos) + { + Evas_BiDi_Direction itdir = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? + _ITEM_TEXT(it)->text_props.bidi_dir : _ITEM_FORMAT(it)->bidi_dir; + Evas_Object_Textblock_Item *previt = NULL; + Evas_BiDi_Direction previtdir = EVAS_BIDI_DIRECTION_NEUTRAL; + /* Get the logically previous item. */ + { + Eina_List *itr; + Evas_Object_Textblock_Item *ititr; + EINA_LIST_FOREACH(ln->par->logical_items, itr, ititr) + { + if (ititr == it) + break; + previt = ititr; + } + + if (previt) + { + previtdir = (previt->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? + _ITEM_TEXT(previt)->text_props.bidi_dir : _ITEM_FORMAT(previt)->bidi_dir; + } + } + + if (previt && (itdir != previtdir)) + { + Evas_Object_Textblock_Item *curit = NULL; + /* If the current dir is different than the paragraph dir + * this is our item. */ + if (itdir != ln->par->direction) + { + curit = it; + } + else + { + curit = previt; + } + + if (((curit == it) && (ln->par->direction == EVAS_BIDI_DIRECTION_LTR)) || + ((curit == previt) && (ln->par->direction == EVAS_BIDI_DIRECTION_RTL))) + { + if (cx) *cx = ln->x + curit->x; + if (cx2) *cx2 = ln->x + curit->x + curit->w; + } + else + { + if (cx) *cx = ln->x + curit->x + curit->w; + if (cx2) *cx2 = ln->x + curit->x; + } + + if (cy) *cy = ln->par->y + ln->y; + if (ch) *ch = curit->h; + + if (cy2) *cy2 = ln->par->y + ln->y; + if (ch2) *ch2 = curit->h; + return EINA_TRUE; + } + } + } + } + + evas_textblock_cursor_geometry_get(cur, cx, cy, cw, ch, NULL, ctype); + return EINA_FALSE; +} + EAPI int evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype) {