1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_TEXT_PROTECTED
7 #define EFL_ACCESS_EDITABLE_TEXT_PROTECTED
8 #define ELM_LAYOUT_PROTECTED
9 #define EFL_PART_PROTECTED
10 #define EFL_INPUT_CLICKABLE_PROTECTED
11 
12 #include <Elementary.h>
13 #include <Elementary_Cursor.h>
14 #include "elm_priv.h"
15 
16 #include "elm_entry_common.h"
17 #include "elm_widget_entry.h"
18 #include "efl_ui_textbox_part.eo.h"
19 #include "elm_part_helper.h"
20 #include "efl_canvas_textblock_internal.h"
21 
22 typedef struct _Efl_Ui_Textbox_Data        Efl_Ui_Textbox_Data;
23 typedef struct _Efl_Ui_Text_Rectangle   Efl_Ui_Text_Rectangle;
24 typedef struct _Anchor                  Anchor;
25 
26 /**
27  * Base widget smart data extended with entry instance data.
28  */
29 struct _Efl_Ui_Textbox_Data
30 {
31    Evas_Object                          *hit_rect, *entry_edje;
32 
33    Eo                                   *popup;
34    Eo                                   *popup_list;
35    Eo                                   *text_obj;
36    Eo                                   *text_guide_obj;
37    Eo                                   *text_table;
38    Eo                                   *pan;
39    Eo                                   *scroller;
40    Eo                                   *manager;
41    Eo                                   *cursor;
42    Eo                                   *cursor_bidi;
43    Evas_Object                          *start_handler;
44    Evas_Object                          *end_handler;
45    Eina_Future                          *deferred_decoration_job;
46    /* for deferred appending */
47    int                                   append_text_position;
48    int                                   append_text_len;
49    /* Only for clipboard */
50    const char                           *text;
51    Evas_Coord                            ent_w, ent_h;
52    Evas_Coord                            downx, downy;
53    Evas_Coord                            ox, oy;
54    Eina_List                            *anchors;
55    int                                  gen;
56    Eina_List                            *sel;
57    Efl_Canvas_Textblock_Factory              *item_factory;
58    Efl_Canvas_Textblock_Factory              *item_fallback_factory;
59    Mod_Api                              *api; // module api if supplied
60    int                                   cursor_pos;
61    Elm_Scroller_Policy                   policy_h, policy_v;
62    Efl_Text_Cursor_Object                      *sel_handler_cursor;
63    struct
64      {
65         Evas_Object *hover_parent; /**< hover parent object. entry is a hover parent object by default */
66         Evas_Object *pop; /**< hidden icon for hover target */
67         Evas_Object *hover; /**< hover object */
68         const char  *hover_style; /**< style of a hover object */
69      } anchor_hover;
70 
71    const char                           *cnp_mime_type;
72    Elm_Sel_Format                        drop_format;
73 
74    struct {
75         char                             *text;
76         Eina_Bool                        enabled;
77    } async;
78 
79    struct {
80         Eina_Size2D                      scroll;
81         Eina_Size2D                      layout;
82    } last;
83    Efl_Ui_Textbox_Cnp_Content            content;
84    Eina_Bool                             sel_handles_enabled : 1;
85    Eina_Bool                             start_handler_down : 1;
86    Eina_Bool                             start_handler_shown : 1;
87    Eina_Bool                             end_handler_down : 1;
88    Eina_Bool                             end_handler_shown : 1;
89    Eina_Bool                             deferred_decoration_selection : 1;
90    Eina_Bool                             deferred_decoration_cursor : 1;
91    Eina_Bool                             deferred_decoration_anchor : 1;
92    Eina_Bool                             context_menu_enabled : 1;
93    Eina_Bool                             long_pressed : 1;
94    Eina_Bool                             has_text : 1;
95    Eina_Bool                             use_down : 1;
96    Eina_Bool                             sel_mode : 1;
97    Eina_Bool                             changed : 1;
98    Eina_Bool                             scroll : 1;
99    Eina_Bool                             text_changed : 1;
100    Eina_Bool                             calc_force : 1;
101    Eina_Bool                             cursor_update : 1;
102    Eina_Bool                             color_is_set : 1;
103 };
104 
105 struct _Anchor
106 {
107    Eo                    *obj;
108    char                  *name;
109    Efl_Text_Attribute_Handle *annotation;
110    Eina_List             *rects;
111    int                   gen;
112    Eina_Bool              item : 1;
113    Eina_Bool              updated : 1;
114 };
115 
116 #define EFL_UI_TEXT_DATA_GET(o, sd) \
117   Efl_Ui_Textbox_Data * sd = efl_data_scope_get(o, EFL_UI_TEXTBOX_CLASS)
118 
119 #define EFL_UI_TEXT_DATA_GET_OR_RETURN(o, ptr)         \
120   EFL_UI_TEXT_DATA_GET(o, ptr);                        \
121   if (EINA_UNLIKELY(!ptr))                           \
122     {                                                \
123        ERR("No widget data for object %p (%s)",      \
124            o, efl_class_name_get(o));              \
125        return;                                       \
126     }
127 
128 #define EFL_UI_TEXT_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
129   EFL_UI_TEXT_DATA_GET(o, ptr);                         \
130   if (EINA_UNLIKELY(!ptr))                            \
131     {                                                 \
132        ERR("No widget data for object %p (%s)",       \
133            o, efl_class_name_get(o));               \
134        return val;                                    \
135     }
136 
137 #define EFL_UI_TEXT_CHECK(obj)                              \
138   if (EINA_UNLIKELY(!efl_isa((obj), EFL_UI_TEXTBOX_CLASS))) \
139     return
140 
141 struct _Efl_Ui_Text_Rectangle
142 {
143    Evas_Object             *obj_bg, *obj_fg, *obj;
144 };
145 
146 #define MY_CLASS EFL_UI_TEXTBOX_CLASS
147 #define MY_CLASS_PFX efl_ui_textbox
148 #define MY_CLASS_NAME "Efl.Ui.Textbox"
149 #define MY_CLASS_NAME_LEGACY "elm_entry"
150 
151 #include "efl_ui_internal_text_interactive.h"
152 #include "efl_ui_internal_text_scroller.h"
153 
154 /* Maximum chunk size to be inserted to the entry at once
155  * FIXME: This size is arbitrary, should probably choose a better size.
156  * Possibly also find a way to set it to a low value for weak computers,
157  * and to a big value for better computers. */
158 #define EFL_UI_TEXT_CHUNK_SIZE 10000
159 #define EFL_UI_TEXT_DELAY_WRITE_TIME 2.0
160 
161 #define ENTRY_PASSWORD_MASK_CHARACTER      0x002A
162 #define ENTRY_PASSWORD_MASK_CHARACTER_UTF8 "\x2A"
163 
164 static Eina_List *entries = NULL;
165 
166 struct _Mod_Api
167 {
168    void (*obj_hook)(Evas_Object *obj);
169    void (*obj_unhook)(Evas_Object *obj);
170    void (*obj_longpress)(Evas_Object *obj);
171 };
172 
173 static const char PART_NAME_HANDLER_START[] = "handler/start";
174 static const char PART_NAME_HANDLER_END[] = "handler/end";
175 static const char PART_NAME_CURSOR[] = "cursor";
176 static const char PART_NAME_SELECTION[] = "selection";
177 static const char PART_NAME_ANCHOR[] = "anchor";
178 
179 static void _create_selection_handlers(Evas_Object *obj, Efl_Ui_Textbox_Data *sd);
180 static void _update_decorations(Eo *obj);
181 static void _create_text_cursors(Eo *obj, Efl_Ui_Textbox_Data *sd);
182 static void _efl_ui_textbox_changed_cb(void *data, const Efl_Event *event);
183 static void _efl_ui_textbox_changed_user_cb(void *data, const Efl_Event *event);
184 static void _efl_ui_textbox_selection_start_clear_cb(void *data, const Efl_Event *event);
185 static void _efl_ui_textbox_selection_changed_cb(void *data, const Efl_Event *event);
186 static void _efl_ui_textbox_cursor_changed_cb(void *data, const Efl_Event *event);
187 static void _text_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED);
188 static void _scroller_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED);
189 static void _text_position_changed_cb(void *data, const Efl_Event *event EINA_UNUSED);
190 static void _efl_ui_textbox_move_cb(void *data, const Efl_Event *event EINA_UNUSED);
191 static const char* _efl_ui_textbox_selection_get(const Eo *obj, Efl_Ui_Textbox_Data *sd);
192 static void _edje_signal_emit(Efl_Ui_Textbox_Data *obj, const char *sig, const char *src);
193 static void _decoration_defer_all(Eo *obj);
194 static inline Eo * _decoration_create(Eo *obj, Efl_Ui_Textbox_Data *sd, const char *source, Eina_Bool above);
195 static void _decoration_defer(Eo *obj);
196 static void _clear_text_selection(Efl_Ui_Textbox_Data *sd);
197 static void _anchors_free(Efl_Ui_Textbox_Data *sd);
198 static void _selection_defer(Eo *obj, Efl_Ui_Textbox_Data *sd);
199 static Eina_Position2D _decoration_calc_offset(Efl_Ui_Textbox_Data *sd);
200 static void _update_text_theme(Eo *obj, Efl_Ui_Textbox_Data *sd);
201 static void _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type);
202 
203 static Eina_Bool _key_action_copy(Evas_Object *obj, const char *params);
204 static Eina_Bool _key_action_paste(Evas_Object *obj, const char *params);
205 static Eina_Bool _key_action_cut(Evas_Object *obj, const char *params);
206 static Eina_Bool _key_action_menu(Evas_Object *obj, const char *params);
207 
208 static const Elm_Action key_actions[] = {
209    {"copy", _key_action_copy},
210    {"paste", _key_action_paste},
211    {"cut", _key_action_cut},
212    {"menu", _key_action_menu},
213    {NULL, NULL}
214 };
215 
216 static void
_efl_ui_textbox_guide_update(Evas_Object * obj,Eina_Bool has_text)217 _efl_ui_textbox_guide_update(Evas_Object *obj,
218                         Eina_Bool has_text)
219 {
220    EFL_UI_TEXT_DATA_GET(obj, sd);
221 
222    if ((has_text) && (!sd->has_text))
223      efl_layout_signal_emit(sd->entry_edje, "efl,guide,disabled", "efl");
224    else if ((!has_text) && (sd->has_text))
225      efl_layout_signal_emit(sd->entry_edje, "efl,guide,enabled", "efl");
226 
227    sd->has_text = has_text;
228 }
229 
230 static void
_mirrored_set(Evas_Object * obj,Eina_Bool rtl)231 _mirrored_set(Evas_Object *obj,
232               Eina_Bool rtl)
233 {
234    EFL_UI_TEXT_DATA_GET(obj, sd);
235 
236    efl_ui_mirrored_set(sd->entry_edje, rtl);
237 
238    if (sd->anchor_hover.hover)
239      efl_ui_mirrored_set(sd->anchor_hover.hover, rtl);
240 }
241 
242 static void
_hide_selection_handler(Evas_Object * obj)243 _hide_selection_handler(Evas_Object *obj)
244 {
245    EFL_UI_TEXT_DATA_GET(obj, sd);
246 
247    if (!sd->start_handler) return;
248 
249    if (sd->start_handler_shown)
250      {
251         efl_layout_signal_emit(sd->start_handler, "efl,handler,hide", "efl");
252         sd->start_handler_shown = EINA_FALSE;
253      }
254    if (sd->end_handler_shown)
255      {
256         efl_layout_signal_emit(sd->end_handler, "efl,handler,hide", "efl");
257         sd->end_handler_shown = EINA_FALSE;
258      }
259 }
260 
261 static Eina_Rect
_viewport_region_get(Evas_Object * obj)262 _viewport_region_get(Evas_Object *obj)
263 {
264    EFL_UI_TEXT_DATA_GET(obj, sd);
265    Eina_Rect rect;
266    Evas_Object *parent;
267 
268    if (sd->scroll)
269      {
270         rect = efl_ui_scrollable_viewport_geometry_get(sd->scroller);
271      }
272    else
273      {
274         rect = efl_gfx_entity_geometry_get(sd->text_obj);
275      }
276 
277    parent = efl_ui_widget_parent_get(obj);
278    while (parent)
279      {
280         if (efl_isa(parent, EFL_UI_SCROLLABLE_INTERFACE))
281           {
282              Eina_Rect r = efl_gfx_entity_geometry_get(parent);
283              if (!eina_rectangle_intersection(&rect.rect, &r.rect))
284                {
285                   rect = EINA_RECT_EMPTY();
286                   break;
287                }
288           }
289         parent = efl_ui_widget_parent_get(parent);
290      }
291 
292    return rect;
293 }
294 
295 static void
_update_selection_handler(Eo * obj)296 _update_selection_handler(Eo *obj)
297 {
298    EFL_UI_TEXT_DATA_GET(obj, sd);
299 
300    Evas_Coord sx, sy, sh;
301    Evas_Coord ex, ey, eh;
302 
303    if (!efl_text_interactive_have_selection_get(obj))
304      {
305         _hide_selection_handler(obj);
306         return;
307      }
308 
309    if (sd->sel_handles_enabled)
310      {
311         Eina_Rect rect;
312         Eina_Position2D off;
313         Evas_Coord hx, hy;
314         Eina_Bool hidden = EINA_FALSE;
315         Efl_Text_Cursor_Object *sel_start, *sel_end;
316         Eina_Rect rc_tmp;
317 
318         efl_text_interactive_selection_cursors_get(obj, &sel_start, &sel_end);
319 
320         if (!sd->start_handler)
321           _create_selection_handlers(obj, sd);
322 
323         //evas_object_geometry_get(sd->entry_edje, &ent_x, &ent_y, NULL, NULL);
324 
325         rc_tmp = efl_text_cursor_object_cursor_geometry_get(sel_start, EFL_TEXT_CURSOR_TYPE_BEFORE);
326         sx = rc_tmp.x;
327         sy = rc_tmp.y;
328         sh = rc_tmp.h;
329 
330         off = _decoration_calc_offset(sd);
331         hx = off.x + sx;
332         hy = off.y + sy + sh;
333         efl_gfx_entity_position_set(sd->start_handler, EINA_POSITION2D(hx, hy));
334 
335         rect = _viewport_region_get(obj);
336 
337         if (!eina_rectangle_xcoord_inside(&rect.rect, hx) ||
338             !eina_rectangle_ycoord_inside(&rect.rect, hy))
339           {
340              hidden = EINA_TRUE;
341           }
342         if (!sd->start_handler_shown && !hidden)
343           {
344              efl_layout_signal_emit(sd->start_handler,
345                                      "efl,handler,show", "efl");
346              sd->start_handler_shown = EINA_TRUE;
347           }
348         else if (sd->start_handler_shown && hidden)
349           {
350              efl_layout_signal_emit(sd->start_handler,
351                                      "efl,handler,hide", "efl");
352              sd->start_handler_shown = EINA_FALSE;
353           }
354 
355         hidden = EINA_FALSE;
356         rc_tmp = efl_text_cursor_object_cursor_geometry_get(sel_end, EFL_TEXT_CURSOR_TYPE_BEFORE);
357         ex = rc_tmp.x;
358         ey = rc_tmp.y;
359         eh = rc_tmp.h;
360 
361         hx = off.x + ex;
362         hy = off.y + ey + eh;
363         efl_gfx_entity_position_set(sd->end_handler, EINA_POSITION2D(hx, hy));
364 
365         if (!eina_rectangle_xcoord_inside(&rect.rect, hx) ||
366             !eina_rectangle_ycoord_inside(&rect.rect, hy))
367           {
368              hidden = EINA_TRUE;
369           }
370         if (!sd->end_handler_shown && !hidden)
371           {
372              efl_layout_signal_emit(sd->end_handler,
373                                      "efl,handler,show", "efl");
374              sd->end_handler_shown = EINA_TRUE;
375           }
376         else if (sd->end_handler_shown && hidden)
377           {
378              efl_layout_signal_emit(sd->end_handler,
379                                      "efl,handler,hide", "efl");
380              sd->end_handler_shown = EINA_FALSE;
381           }
382      }
383    else
384      {
385         if (sd->start_handler_shown)
386           {
387              efl_layout_signal_emit(sd->start_handler,
388                                      "efl,handler,hide", "efl");
389              sd->start_handler_shown = EINA_FALSE;
390           }
391         if (sd->end_handler_shown)
392           {
393              efl_layout_signal_emit(sd->end_handler,
394                                      "efl,handler,hide", "efl");
395              sd->end_handler_shown = EINA_FALSE;
396           }
397      }
398 }
399 
400 static Eina_Value
_selection_data_cb(Efl_Ui_Textbox * obj,void * data EINA_UNUSED,const Eina_Value value)401 _selection_data_cb(Efl_Ui_Textbox *obj, void *data EINA_UNUSED, const Eina_Value value)
402 {
403    Eina_Content *content;
404    Eina_Slice slice;
405    Efl_Text_Cursor_Object *cur, *start, *end;
406    Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
407 
408    if (eina_value_type_get(&value) != EINA_VALUE_TYPE_CONTENT)
409      return EINA_VALUE_EMPTY;
410 
411    content = eina_value_to_content(&value);
412    slice = eina_content_data_get(content);
413    efl_text_interactive_selection_cursors_get(obj, &start, &end);
414    if (!efl_text_cursor_object_equal(start, end))
415      {
416         efl_text_cursor_object_range_delete(start, end);
417         efl_text_interactive_all_unselect(obj);
418      }
419    cur = efl_text_interactive_main_cursor_get(obj);
420    info.type = EFL_TEXT_CHANGE_TYPE_INSERT;
421    info.position = efl_text_cursor_object_position_get(cur);
422    info.length = slice.len;
423    info.content = slice.mem;
424    if (eina_streq(eina_content_type_get(content), "application/x-elementary-markup"))
425      {
426         efl_text_cursor_object_markup_insert(cur, slice.mem);
427      }
428    else if (!strncmp(eina_content_type_get(content), "image/", strlen("image/")))
429      {
430         Eina_Strbuf *result = eina_strbuf_new();
431         eina_strbuf_append_printf(result, "<item absize=240x180 href=");
432         eina_strbuf_append_slice(result, slice);
433         eina_strbuf_append_printf(result, "></item>");
434         efl_text_cursor_object_markup_insert(cur, eina_strbuf_string_get(result));
435         eina_strbuf_free(result);
436      }
437    else // TEXT
438      {
439         efl_text_cursor_object_text_insert(cur, slice.mem);
440      }
441    efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
442 
443    return EINA_VALUE_EMPTY;
444 }
445 
446 static Eina_Array*
_figure_out_types(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)447 _figure_out_types(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
448 {
449    Eina_Array *types = eina_array_new(10);
450 
451    if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP)
452      eina_array_push(types, "application/x-elementary-markup");
453    if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE)
454      {
455         eina_array_push(types, "image/png");
456         eina_array_push(types, "image/jpeg");
457         eina_array_push(types, "image/x-ms-bmp");
458         eina_array_push(types, "image/gif");
459         eina_array_push(types, "image/tiff");
460         eina_array_push(types, "image/svg+xml");
461         eina_array_push(types, "image/x-xpixmap");
462         eina_array_push(types, "image/x-tga");
463         eina_array_push(types, "image/x-portable-pixmap");
464      }
465    if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT)
466      eina_array_push(types, "text/plain;charset=utf-8");
467    return types;
468 }
469 
470 static Eina_Bool
_accepting_drops(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Accessor * mime_types)471 _accepting_drops(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Accessor *mime_types)
472 {
473    int i = 0;
474    const char *mime_type;
475 
476    if (efl_ui_widget_disabled_get(obj)) return EINA_FALSE;
477 
478    EINA_ACCESSOR_FOREACH(mime_types, i, mime_type)
479      {
480         if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_TEXT &&
481             eina_streq(mime_type, "text/plain;charset=utf-8"))
482           return EINA_TRUE;
483 
484         if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_IMAGE &&
485             strncmp(mime_type, "image/", strlen("image/")))
486           return EINA_TRUE;
487 
488         if (sd->content & EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP &&
489             eina_streq(mime_type, "application/x-elementary-markup"))
490           return EINA_TRUE;
491      }
492    return EINA_FALSE;
493 }
494 
495 static void
_dnd_enter_cb(void * data EINA_UNUSED,const Efl_Event * ev)496 _dnd_enter_cb(void *data EINA_UNUSED,
497               const Efl_Event *ev)
498 {
499    Efl_Ui_Drop_Event *dnd_enter = ev->info;
500    EFL_UI_TEXT_DATA_GET(ev->object, sd);
501    if (_accepting_drops(ev->object, sd, dnd_enter->available_types))
502      efl_ui_focus_util_focus(ev->object);
503 }
504 
505 static void
_dnd_pos_cb(void * data EINA_UNUSED,const Efl_Event * ev)506 _dnd_pos_cb(void *data EINA_UNUSED, const Efl_Event *ev)
507 {
508    Efl_Ui_Drop_Event *dnd_pos = ev->info;
509    Eina_Position2D po, pe, pos;
510    EFL_UI_TEXT_DATA_GET(ev->object, sd);
511    int cursor_pos;
512 
513    if (!_accepting_drops(ev->object, sd, dnd_pos->available_types))
514      return;
515 
516    po = efl_gfx_entity_position_get(ev->object);
517    pe = efl_gfx_entity_position_get(sd->entry_edje);
518    pos.x = dnd_pos->position.x + po.x - pe.x;
519    pos.y = dnd_pos->position.y + po.x - pe.y;
520 
521    edje_object_part_text_cursor_coord_set
522       (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, pos.x, pos.y);
523    cursor_pos = edje_object_part_text_cursor_pos_get
524       (sd->entry_edje, "efl.text", EDJE_CURSOR_USER);
525    edje_object_part_text_cursor_pos_set(sd->entry_edje, "efl.text",
526                                         EDJE_CURSOR_MAIN, cursor_pos);
527 }
528 
529 static void
_dnd_drop_cb(void * data EINA_UNUSED,const Efl_Event * ev)530 _dnd_drop_cb(void *data EINA_UNUSED, const Efl_Event *ev)
531 {
532    Efl_Ui_Drop_Event *drop = ev->info;
533 
534    Eina_Array *types;
535 
536    EFL_UI_TEXT_DATA_GET(ev->object, sd);
537    types = _figure_out_types(ev->object, sd);
538 
539    if (_accepting_drops(ev->object, sd, drop->available_types))
540      {
541         Eina_Future *future;
542 
543         future = efl_ui_dnd_drop_data_get(ev->object, evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(ev->object), EVAS_DEVICE_CLASS_SEAT)), eina_array_iterator_new(types));
544         efl_future_then(ev->object, future, _selection_data_cb);
545      }
546 
547    eina_array_free(types);
548 }
549 
550 /* we can't reuse layout's here, because it's on entry_edje only */
551 EOLIAN static void
_efl_ui_textbox_efl_ui_widget_disabled_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Bool disabled)552 _efl_ui_textbox_efl_ui_widget_disabled_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Bool disabled)
553 {
554    const char *emission;
555 
556    if (efl_ui_widget_disabled_get(obj) == disabled)
557      return;
558 
559    efl_ui_widget_disabled_set(efl_super(obj, MY_CLASS), disabled);
560 
561    emission = efl_ui_widget_disabled_get(obj) ? "efl,state,disabled" : "efl,state,enabled";
562    efl_layout_signal_emit(sd->entry_edje, emission, "efl");
563    if (sd->scroll)
564      {
565         efl_ui_scrollable_scroll_freeze_set(obj, efl_ui_widget_disabled_get(obj));
566      }
567 
568    _update_text_theme(obj, sd);
569 }
570 
571 /* we can't issue the layout's theming code here, cause it assumes an
572  * unique edje object, always */
573 EOLIAN static Eina_Error
_efl_ui_textbox_efl_ui_widget_theme_apply(Eo * obj,Efl_Ui_Textbox_Data * sd)574 _efl_ui_textbox_efl_ui_widget_theme_apply(Eo *obj, Efl_Ui_Textbox_Data *sd)
575 {
576    Eina_Error theme_apply;
577 
578    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
579 
580    theme_apply = efl_ui_widget_theme_apply(efl_super(obj,MY_CLASS));
581    if (theme_apply == EFL_UI_THEME_APPLY_ERROR_GENERIC) return EFL_UI_THEME_APPLY_ERROR_GENERIC;
582 
583    _update_text_theme(obj, sd);
584 
585    efl_event_freeze(obj);
586 
587    edje_object_mirrored_set
588      (wd->resize_obj, efl_ui_mirrored_get(obj));
589 
590    efl_gfx_entity_scale_set
591      (wd->resize_obj,
592      efl_gfx_entity_scale_get(obj) * elm_config_scale_get());
593 
594    _mirrored_set(obj, efl_ui_mirrored_get(obj));
595 
596    elm_widget_element_update(obj, sd->entry_edje,
597                                    elm_widget_theme_element_get(obj));
598 
599    // elm_entry_cursor_pos_set -> cursor,changed -> widget_show_region_set
600    // -> smart_objects_calculate will call all smart calculate functions,
601    // and one of them can delete elm_entry.
602    efl_ref(obj);
603 
604    if (efl_ui_focus_object_focus_get(obj))
605      {
606         efl_layout_signal_emit(sd->entry_edje, "efl,action,focus", "efl");
607      }
608 
609    efl_layout_signal_process(sd->entry_edje, EINA_FALSE);
610 
611    Evas_Object* clip = efl_canvas_object_clipper_get(sd->entry_edje);
612    efl_canvas_object_clipper_set(sd->hit_rect, clip);
613 
614    if (sd->start_handler)
615      {
616         elm_widget_element_update(obj, sd->start_handler, PART_NAME_HANDLER_START);
617         elm_widget_element_update(obj, sd->end_handler, PART_NAME_HANDLER_END);
618      }
619 
620    sd->has_text = !sd->has_text;
621    _efl_ui_textbox_guide_update(obj, !sd->has_text);
622    efl_event_thaw(obj);
623 
624    efl_event_callback_call(obj, EFL_UI_LAYOUT_EVENT_THEME_CHANGED, NULL);
625 
626    efl_unref(obj);
627 
628    if (efl_content_get(efl_part(sd->entry_edje, "efl.text")) == NULL && !sd->scroller)
629      {
630         efl_pack_table(sd->text_table, sd->text_obj, 0, 0, 1, 1);
631         efl_pack_table(sd->text_table, sd->text_guide_obj, 0, 0, 1, 1);
632         efl_content_set(efl_part(sd->entry_edje, "efl.text"), sd->text_table);
633      }
634 
635    if (!sd->cursor && !sd->cursor_bidi)
636      _create_text_cursors(obj, sd);
637 
638    return theme_apply;
639 }
640 
641 static void
_cursor_geometry_recalc(Evas_Object * obj)642 _cursor_geometry_recalc(Evas_Object *obj)
643 {
644    EFL_UI_TEXT_DATA_GET(obj, sd);
645 
646    Evas_Coord cx, cy, cw, ch;
647    Eina_Rect rc;
648 
649    if (!efl_text_interactive_editable_get(obj)) return;
650 
651    cx = cy = cw = ch = 0;
652 
653    Efl_Text_Cursor_Object *main_cur =
654       efl_text_interactive_main_cursor_get(obj);
655 
656    rc = efl_text_cursor_object_cursor_geometry_get(main_cur, EFL_TEXT_CURSOR_TYPE_BEFORE);
657    cx = rc.x;
658    cy = rc.y;
659    cw = rc.w;
660    ch = rc.h;
661 
662    edje_object_size_min_restricted_calc(sd->cursor, &cw, NULL, cw, 0);
663    if (cw < 1) cw = 1;
664    if (ch < 1) ch = 1;
665    edje_object_size_min_restricted_calc(sd->cursor, &cw, NULL, cw, 0);
666 
667    efl_ui_scrollable_scroll(sd->scroller, EINA_RECT(cx, cy, cw, ch), EINA_FALSE);
668 
669 }
670 
671 #define SIZE2D_EQ(X, Y) (((X).w == (Y).w) && ((X).h == (Y).h))
672 
673 EOLIAN static void
_efl_ui_textbox_efl_canvas_group_group_calculate(Eo * obj,Efl_Ui_Textbox_Data * sd)674 _efl_ui_textbox_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Textbox_Data *sd)
675 {
676    Eina_Size2D min = EINA_SIZE2D(0, 0);
677    Eina_Size2D edmin = EINA_SIZE2D(0, 0);
678    Eina_Size2D sz = EINA_SIZE2D(0, 0);
679 
680    efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
681    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
682 
683    sz = efl_gfx_entity_size_get(obj);
684    if (!sd->calc_force && SIZE2D_EQ(sd->last.layout, sz) &&
685          !sd->text_changed)
686      {
687         return;
688      }
689 
690    sd->calc_force = EINA_FALSE;
691    sd->last.layout.w = sz.w;
692    sd->last.layout.h = sz.h;
693    sd->text_changed = EINA_FALSE;
694 
695    if (sd->scroll)
696      {
697         efl_canvas_group_calculate(sd->scroller);
698         min = efl_gfx_hint_size_min_get(sd->scroller);
699         if (!efl_text_multiline_get(obj))
700           {
701              edje_object_size_min_calc(wd->resize_obj, &edmin.w, &edmin.h);
702              min.w = edmin.w;
703              min.h = edmin.h;
704              efl_gfx_hint_size_restricted_min_set(obj, min);
705           }
706 
707         sd->cursor_update = EINA_TRUE;
708         _decoration_defer_all(obj);
709      }
710    else
711      {
712         Eina_Size2D text_sz = efl_gfx_entity_size_get(sd->text_obj);
713         edje_object_size_min_calc(wd->resize_obj, &edmin.w, &edmin.h);
714         efl_event_freeze(sd->text_obj);
715         efl_gfx_entity_size_set(sd->text_obj, EINA_SIZE2D(sz.w, 0));
716         /* ignore current object size for single-line since we always need to know the actual size */
717         if (!efl_text_multiline_get(obj))
718           min = efl_canvas_textblock_size_native_get(sd->text_obj);
719         else
720           min = efl_canvas_textblock_size_formatted_get(sd->text_obj);
721         efl_gfx_entity_size_set(sd->text_obj, text_sz);
722         efl_event_thaw(sd->text_obj);
723         min.w += edmin.w;
724         min.h += edmin.h;
725         efl_gfx_hint_size_restricted_min_set(obj, min);
726      }
727 }
728 
729 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_ui_focus_object_on_focus_update(Eo * obj,Efl_Ui_Textbox_Data * sd)730 _efl_ui_textbox_efl_ui_focus_object_on_focus_update(Eo *obj, Efl_Ui_Textbox_Data *sd)
731 {
732    Efl_Object *top;
733 
734    if (!efl_text_interactive_editable_get(obj)) return EINA_FALSE;
735 
736    top = efl_provider_find(obj, EFL_UI_WIN_CLASS);
737 
738    if (efl_ui_focus_object_focus_get(obj))
739      {
740         efl_canvas_object_key_focus_set(sd->text_obj, EINA_TRUE);
741 
742         _edje_signal_emit(sd, "efl,action,focus", "efl");
743 
744         if (efl_input_text_input_panel_autoshow_get(obj) && !efl_input_text_input_panel_show_on_demand_get(obj))
745           elm_win_keyboard_mode_set(top, ELM_WIN_KEYBOARD_ON);
746         if (_elm_config->atspi_mode)
747           efl_access_state_changed_signal_emit(obj, EFL_ACCESS_STATE_TYPE_FOCUSED, EINA_TRUE);
748      }
749    else
750      {
751         Eo *sw = sd->text_obj;
752 
753         _edje_signal_emit(sd, "efl,action,unfocus", "efl");
754         efl_canvas_object_key_focus_set(sw, EINA_FALSE);
755 
756         if (efl_input_text_input_panel_autoshow_get(obj))
757           elm_win_keyboard_mode_set(top, ELM_WIN_KEYBOARD_OFF);
758         if (_elm_config->atspi_mode)
759           efl_access_state_changed_signal_emit(obj, EFL_ACCESS_STATE_TYPE_FOCUSED, EINA_FALSE);
760 
761         if (_elm_config->selection_clear_enable)
762           {
763              if ((efl_text_interactive_have_selection_get(obj)) && (!sd->popup))
764                {
765                   sd->sel_mode = EINA_FALSE;
766                   efl_ui_widget_scroll_hold_pop(obj);
767                   edje_object_part_text_select_allow_set(sd->entry_edje, "efl.text", EINA_FALSE);
768                   efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl");
769                   edje_object_part_text_select_none(sd->entry_edje, "efl.text");
770                }
771           }
772      }
773 
774    return EINA_TRUE;
775 }
776 
777 EOLIAN static Eina_Rect
_efl_ui_textbox_efl_ui_widget_interest_region_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)778 _efl_ui_textbox_efl_ui_widget_interest_region_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
779 {
780    Eina_Rect edje, elm;
781    Eina_Rect r = {};
782 
783    r = efl_text_cursor_object_cursor_geometry_get(
784          efl_text_interactive_main_cursor_get(obj), EFL_TEXT_CURSOR_TYPE_BEFORE);
785 
786    if (!efl_text_multiline_get(obj))
787      {
788         Eina_Rect rr = efl_gfx_entity_geometry_get(sd->entry_edje);
789         r.h = rr.h;
790         r.y = 0;
791      }
792 
793    edje = efl_gfx_entity_geometry_get(sd->entry_edje);
794    elm = efl_gfx_entity_geometry_get(obj);
795 
796    r.x += edje.x - elm.x;
797    r.y += edje.y - elm.y;
798    if (r.w < 1) r.w = 1;
799    if (r.h < 1) r.h = 1;
800 
801    return r;
802 }
803 
804 static void
_popup_position(Evas_Object * obj)805 _popup_position(Evas_Object *obj)
806 {
807    Eina_Rect r;
808    Evas_Coord cx, cy, cw, ch;
809    Eina_Size2D m;
810 
811    EFL_UI_TEXT_DATA_GET(obj, sd);
812 
813    cx = cy = 0;
814    cw = ch = 1;
815    r = efl_gfx_entity_geometry_get(sd->entry_edje);
816    if (sd->use_down)
817      {
818         cx = sd->downx - r.x;
819         cy = sd->downy - r.y;
820         cw = 1;
821         ch = 1;
822      }
823    else
824      edje_object_part_text_cursor_geometry_get
825        (sd->entry_edje, "efl.text", &cx, &cy, &cw, &ch);
826 
827    m = efl_gfx_hint_size_restricted_min_get(sd->popup);
828    if (cx + m.w > r.w)
829      cx = r.w - m.w;
830    if (cy + m.h > r.h)
831      cy = r.h - m.h;
832    efl_gfx_entity_geometry_set(sd->popup, EINA_RECT(r.x + cx, r.y + cy, m.w, m.h));
833 }
834 
835 static void
_selection_lost_cb(void * data EINA_UNUSED,const Efl_Event * ev)836 _selection_lost_cb(void *data EINA_UNUSED, const Efl_Event *ev)
837 {
838    Efl_Ui_Wm_Selection_Changed *changed = ev->info;
839    EFL_UI_TEXT_DATA_GET(ev->object, sd);
840 
841    if (changed->buffer == EFL_UI_CNP_BUFFER_SELECTION && changed->caused_by != ev->object)
842      {
843         efl_text_interactive_all_unselect(ev->object);
844         _selection_defer(ev->object, sd);
845      }
846 }
847 
848 static void
_selection_store(Efl_Ui_Cnp_Buffer buffer,Evas_Object * obj)849 _selection_store(Efl_Ui_Cnp_Buffer buffer,
850                  Evas_Object *obj)
851 {
852    char *sel;
853    Efl_Text_Cursor_Object *start, *end;
854    Eina_Content *content;
855 
856    efl_text_interactive_selection_cursors_get(obj, &start, &end);
857    sel = efl_text_cursor_object_range_markup_get(start, end);
858 
859    if ((!sel) || (!sel[0])) return;  /* avoid deleting our own selection */
860 
861    content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(sel), "application/x-elementary-markup");
862 
863    efl_ui_selection_set(obj, buffer, content, evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EVAS_DEVICE_CLASS_SEAT)));
864 
865    free(sel);
866 }
867 
868 static void
_popup_dismiss(Efl_Ui_Textbox_Data * sd)869 _popup_dismiss( Efl_Ui_Textbox_Data *sd)
870 {
871    efl_del(sd->popup_list);
872    efl_del(sd->popup);
873    sd->popup = NULL;
874    sd->popup_list = NULL;
875 }
876 
877 static void
_backwall_clicked(void * data,const Efl_Event * ev EINA_UNUSED)878 _backwall_clicked(void *data, const Efl_Event *ev EINA_UNUSED)
879 {
880    EFL_UI_TEXT_DATA_GET(data, sd);
881    _popup_dismiss(sd);
882 }
883 
884 static void
_popup_item_cut_cb(void * data,const Efl_Event * ev EINA_UNUSED)885 _popup_item_cut_cb(void *data, const Efl_Event *ev EINA_UNUSED)
886 {
887    EFL_UI_TEXT_DATA_GET(data, sd);
888    efl_ui_textbox_selection_cut(data);
889    _popup_dismiss(sd);
890 }
891 
892 static void
_popup_item_copy_cb(void * data,const Efl_Event * ev EINA_UNUSED)893 _popup_item_copy_cb(void *data, const Efl_Event *ev EINA_UNUSED)
894 {
895    EFL_UI_TEXT_DATA_GET(data, sd);
896    efl_ui_textbox_selection_copy(data);
897    _popup_dismiss(sd);
898 }
899 
900 static void
_popup_item_cancel_cb(void * data,const Efl_Event * ev EINA_UNUSED)901 _popup_item_cancel_cb(void *data, const Efl_Event *ev EINA_UNUSED)
902 {
903    EFL_UI_TEXT_DATA_GET(data, sd);
904 
905    if (!efl_text_interactive_selection_allowed_get(data)) return;
906 
907    if (!_elm_config->desktop_entry)
908      efl_ui_widget_scroll_hold_pop(data);
909 
910    sd->sel_mode = EINA_FALSE;
911    efl_text_interactive_all_unselect(data);
912    _popup_dismiss(sd);
913 }
914 
915 static void
_popup_item_paste_cb(void * data,const Efl_Event * ev EINA_UNUSED)916 _popup_item_paste_cb(void *data, const Efl_Event *ev EINA_UNUSED)
917 {
918    EFL_UI_TEXT_DATA_GET(data, sd);
919    efl_ui_textbox_selection_paste(data);
920    _popup_dismiss(sd);
921 }
922 
923 static void
_menu_call(Evas_Object * obj)924 _menu_call(Evas_Object *obj)
925 {
926    EFL_UI_TEXT_DATA_GET(obj, sd);
927 
928    if (sd->anchor_hover.hover) return;
929 
930    efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_CONTEXT_OPEN, NULL);
931 
932    if ((sd->api) && (sd->api->obj_longpress))
933      {
934         sd->api->obj_longpress(obj);
935      }
936    else if (sd->context_menu_enabled)
937      {
938         Eina_Bool ownersel;
939 
940         ownersel = elm_cnp_clipboard_selection_has_owner(obj);
941         /* prevent stupid blank hoversel */
942         if (efl_text_interactive_have_selection_get(obj) && efl_text_password_get(obj)) return;
943         if (_elm_config->desktop_entry && (!efl_text_interactive_have_selection_get(obj)) && ((!efl_text_interactive_editable_get(obj)) || (!ownersel)))
944         return;
945         if (sd->popup) _popup_dismiss(sd);
946         else efl_ui_widget_scroll_freeze_push(obj);
947 
948         sd->popup = efl_add(EFL_UI_POPUP_CLASS, obj);
949 
950         sd->popup_list = efl_add(EFL_UI_LIST_CLASS, sd->popup);
951         efl_content_set(sd->popup, sd->popup_list);
952         efl_gfx_hint_align_set(sd->popup_list, 1.0, 1.0);
953         efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
954 
955         efl_ui_widget_sub_object_add(obj, sd->popup);
956         efl_ui_popup_anchor_set(sd->popup, obj);
957         efl_event_callback_add(sd->popup, EFL_UI_POPUP_EVENT_BACKWALL_CLICKED, _backwall_clicked, obj);
958 
959         if (efl_text_interactive_have_selection_get(obj))
960           {
961              if (!efl_text_password_get(obj))
962                {
963                   if (efl_text_interactive_editable_get(obj))
964                     {
965                        Eo *il = NULL;
966                        il = efl_add(EFL_UI_LIST_DEFAULT_ITEM_CLASS, sd->popup_list);
967                        efl_text_set(il, E_("Cut"));
968                        efl_gfx_hint_align_set(il, 1.0, 1.0);
969                        efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
970                        efl_pack_end(sd->popup_list, il);
971                        efl_event_callback_add(il, EFL_UI_EVENT_SELECTED_CHANGED, _popup_item_cut_cb, obj);
972 
973                        il = efl_add(EFL_UI_LIST_DEFAULT_ITEM_CLASS, sd->popup_list);
974                        efl_text_set(il, E_("Copy"));
975                        efl_gfx_hint_align_set(il, 1.0, 1.0);
976                        efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
977                        efl_pack_end(sd->popup_list, il);
978                        efl_event_callback_add(il, EFL_UI_EVENT_SELECTED_CHANGED, _popup_item_copy_cb, obj);
979 
980                        il = efl_add(EFL_UI_LIST_DEFAULT_ITEM_CLASS, sd->popup_list);
981                        efl_text_set(il, E_("Paste"));
982                        efl_gfx_hint_align_set(il, 1.0, 1.0);
983                        efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
984                        efl_pack_end(sd->popup_list, il);
985                        efl_event_callback_add(il, EFL_UI_EVENT_SELECTED_CHANGED, _popup_item_paste_cb, obj);
986 
987                        il = efl_add(EFL_UI_LIST_DEFAULT_ITEM_CLASS, sd->popup_list);
988                        efl_text_set(il, E_("Cancel"));
989                        efl_gfx_hint_align_set(il, 1.0, 1.0);
990                        efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
991                        efl_pack_end(sd->popup_list, il);
992                        efl_event_callback_add(il, EFL_UI_EVENT_SELECTED_CHANGED, _popup_item_cancel_cb, obj);
993                     }
994                }
995           }
996         else
997           {
998              if (!sd->sel_mode)
999                {
1000                   if (ownersel)
1001                     {
1002                        if (efl_text_interactive_editable_get(obj))
1003                          {
1004                             Eo *il = NULL;
1005                             il = efl_add(EFL_UI_LIST_DEFAULT_ITEM_CLASS, sd->popup_list);
1006                             efl_text_set(il, E_("Paste"));
1007                             efl_gfx_hint_align_set(il, 1.0, 1.0);
1008                             efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
1009                             efl_pack_end(sd->popup_list, il);
1010                             efl_event_callback_add(il, EFL_UI_EVENT_SELECTED_CHANGED, _popup_item_paste_cb, obj);
1011                          }
1012                     }
1013                }
1014              else
1015                {
1016                   Eo *il = NULL;
1017                   il = efl_add(EFL_UI_LIST_DEFAULT_ITEM_CLASS, sd->popup_list);
1018                   efl_text_set(il, E_("Cancel"));
1019                   efl_gfx_hint_align_set(il, 1.0, 1.0);
1020                   efl_gfx_hint_weight_set(sd->popup_list, 1.0, 1.0);
1021                   efl_pack_end(sd->popup_list, il);
1022                   efl_event_callback_add(il, EFL_UI_EVENT_SELECTED_CHANGED, _popup_item_cancel_cb, obj);
1023                }
1024           }
1025 
1026         if (sd->popup)
1027           {
1028              _popup_position(obj);
1029           }
1030      }
1031 }
1032 
1033 static Eina_Bool
_is_pointer_inside_viewport(Eo * textbox,Efl_Ui_Textbox_Data * sd)1034 _is_pointer_inside_viewport(Eo *textbox,Efl_Ui_Textbox_Data *sd)
1035 {
1036    if (sd->scroller)
1037      {
1038         Eo *top = efl_provider_find(textbox, EFL_UI_WIN_CLASS);
1039         Eina_Position2D pos = {0};
1040         if (efl_canvas_scene_pointer_position_get(top, NULL, &pos))
1041           {
1042              Eina_Rect rc = efl_ui_scrollable_viewport_geometry_get(sd->scroller);
1043              if (!eina_rectangle_coords_inside(&rc.rect, pos.x, pos.y))
1044                return EINA_FALSE;
1045           }
1046      }
1047    return EINA_TRUE;
1048 }
1049 
1050 static void
_long_press_cb(void * data,const Efl_Event * ev EINA_UNUSED)1051 _long_press_cb(void *data, const Efl_Event *ev EINA_UNUSED)
1052 {
1053    EFL_UI_TEXT_DATA_GET(data, sd);
1054 
1055    if (!_is_pointer_inside_viewport(data, sd))
1056      return;
1057 
1058    /* Context menu will not appear if context menu disabled is set
1059     * as false on a long press callback */
1060    if (!_elm_config->context_menu_disabled &&
1061             (!_elm_config->desktop_entry))
1062      _menu_call(data);
1063 
1064    sd->long_pressed = EINA_TRUE;
1065 }
1066 
1067 
1068 static Eina_Bool
_key_action_copy(Evas_Object * obj,const char * params EINA_UNUSED)1069 _key_action_copy(Evas_Object *obj, const char *params EINA_UNUSED)
1070 {
1071    efl_ui_textbox_selection_copy(obj);
1072    return EINA_TRUE;
1073 }
1074 
1075 static Eina_Bool
_key_action_cut(Evas_Object * obj,const char * params EINA_UNUSED)1076 _key_action_cut(Evas_Object *obj, const char *params EINA_UNUSED)
1077 {
1078    efl_ui_textbox_selection_cut(obj);
1079    return EINA_TRUE;
1080 }
1081 
1082 static Eina_Bool
_key_action_paste(Evas_Object * obj,const char * params EINA_UNUSED)1083 _key_action_paste(Evas_Object *obj, const char *params EINA_UNUSED)
1084 {
1085    efl_ui_textbox_selection_paste(obj);
1086    return EINA_TRUE;
1087 }
1088 
1089 static Eina_Bool
_key_action_menu(Evas_Object * obj,const char * params EINA_UNUSED)1090 _key_action_menu(Evas_Object *obj, const char *params EINA_UNUSED)
1091 {
1092    Eina_Bool b_ret = EINA_FALSE;
1093    if (!_elm_config->context_menu_disabled)
1094      {
1095         _menu_call(obj);
1096         b_ret = EINA_TRUE;
1097      }
1098    return b_ret;
1099 }
1100 
1101 static void
_mouse_down_cb(void * data,const Efl_Event * event)1102 _mouse_down_cb(void *data, const Efl_Event *event)
1103 {
1104    Efl_Input_Pointer_Data *ev;
1105    ev = efl_data_scope_get(event->info, EFL_INPUT_POINTER_CLASS);
1106    EFL_UI_TEXT_DATA_GET(data, sd);
1107 
1108    if (efl_ui_widget_disabled_get(data)) return;
1109    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1110    sd->downx = ev->cur.x;
1111    sd->downy = ev->cur.y;
1112    sd->long_pressed = EINA_FALSE;
1113 
1114 
1115    if (ev->button == 2)
1116      {
1117         _efl_ui_textbox_selection_paste_type(data, sd, EFL_UI_CNP_BUFFER_SELECTION);
1118      }
1119 
1120     /* If right button is pressed and context menu disabled is true,
1121      * then only context menu will appear */
1122    if (ev->button == 3 && (!_elm_config->context_menu_disabled))
1123      {
1124         if (_elm_config->desktop_entry)
1125           {
1126              if (!_is_pointer_inside_viewport(data, sd))
1127                return;
1128              sd->use_down = 1;
1129              _menu_call(data);
1130           }
1131      }
1132 }
1133 
1134 static void
_mouse_up_cb(void * data,const Efl_Event * event)1135 _mouse_up_cb(void *data, const Efl_Event *event)
1136 {
1137    Efl_Input_Pointer_Data *ev;
1138    ev = efl_data_scope_get(event->info, EFL_INPUT_POINTER_CLASS);
1139    Efl_Object *top;
1140 
1141    EFL_UI_TEXT_DATA_GET(data, sd);
1142 
1143    if (efl_ui_widget_disabled_get(data)) return;
1144    if (ev->button == 1)
1145      {
1146         efl_input_clickable_longpress_abort(data, 1);
1147 
1148         /* Since context menu disabled flag was checked at long press start while mouse
1149          * down, hence the same should be checked at mouse up from a long press
1150          * as well */
1151         if (sd->long_pressed)
1152           {
1153              if (!_elm_config->context_menu_disabled)
1154                {
1155                   _menu_call(data);
1156                }
1157           }
1158         else
1159           {
1160              top = efl_provider_find(data, EFL_UI_WIN_CLASS);
1161              if (efl_input_text_input_panel_autoshow_get(data) && efl_input_text_input_panel_show_on_demand_get(data))
1162                elm_win_keyboard_mode_set(top, ELM_WIN_KEYBOARD_ON);
1163           }
1164      }
1165   /* Since context menu disabled flag was checked at mouse right key down,
1166    * hence the same should be stopped at mouse up of right key as well */
1167    else if ((ev->button == 3) && (!_elm_config->context_menu_disabled) &&
1168             (!_elm_config->desktop_entry))
1169      {
1170          sd->use_down = 1;
1171          _menu_call(data);
1172      }
1173 }
1174 
1175 static void
_mouse_move_cb(void * data,const Efl_Event * event)1176 _mouse_move_cb(void *data, const Efl_Event *event)
1177 {
1178    Efl_Input_Pointer_Data *ev;
1179    ev = efl_data_scope_get(event->info, EFL_INPUT_POINTER_CLASS);
1180    Evas_Coord dx, dy;
1181 
1182    EFL_UI_TEXT_DATA_GET(data, sd);
1183 
1184    if (efl_ui_widget_disabled_get(data)) return;
1185    if (ev->pressed_buttons == 1)
1186      {
1187         if (sd->long_pressed)
1188           {
1189              Eina_Rect r;
1190              Eina_Bool rv;
1191 
1192              r = efl_gfx_entity_geometry_get(sd->entry_edje);
1193              rv = edje_object_part_text_cursor_coord_set
1194                (sd->entry_edje, "efl.text", EDJE_CURSOR_USER,
1195                ev->cur.x - r.x, ev->cur.y - r.y);
1196              if (rv)
1197                {
1198                   edje_object_part_text_cursor_copy
1199                     (sd->entry_edje, "efl.text", EDJE_CURSOR_USER, EDJE_CURSOR_MAIN);
1200                }
1201              else
1202                WRN("Warning: Cannot move cursor");
1203 
1204           }
1205      }
1206    if (!sd->sel_mode)
1207      {
1208         if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
1209           {
1210              efl_input_clickable_longpress_abort(data, 1);
1211           }
1212      }
1213 
1214    dx = sd->downx - ev->cur.x;
1215    dx *= dx;
1216    dy = sd->downy - ev->cur.y;
1217    dy *= dy;
1218    if ((dx + dy) > ((_elm_config->finger_size / 2) *
1219                     (_elm_config->finger_size / 2)))
1220      {
1221         efl_input_clickable_longpress_abort(data, 1);
1222      }
1223 }
1224 
1225 static Evas_Object *
_item_get(void * data,const char * item)1226 _item_get(void *data, const char *item)
1227 {
1228    Evas_Object *o = NULL;
1229 
1230    EFL_UI_TEXT_DATA_GET(data, sd);
1231 
1232    if (item)
1233      {
1234         if (sd->item_factory)
1235           {
1236              o = efl_canvas_textblock_factory_create(sd->item_factory, data, item);
1237           }
1238         else if (sd->item_fallback_factory)
1239           {
1240              o = efl_canvas_textblock_factory_create(sd->item_fallback_factory,
1241                    data, item);
1242           }
1243      }
1244    return o;
1245 }
1246 
1247 static void
_selection_handlers_offset_calc(Evas_Object * obj,Evas_Object * handler)1248 _selection_handlers_offset_calc(Evas_Object *obj, Evas_Object *handler)
1249 {
1250    Evas_Coord cx, cy, cw, ch;
1251    Evas_Coord hh;
1252    Eina_Position2D pos;
1253    Eina_Rect rc;
1254 
1255    EFL_UI_TEXT_DATA_GET(obj, sd);
1256 
1257    pos = efl_gfx_entity_position_get(sd->text_obj);
1258    rc = efl_text_cursor_object_cursor_geometry_get(
1259          efl_text_interactive_main_cursor_get(obj), EFL_TEXT_CURSOR_TYPE_BEFORE);
1260    cx = rc.x;
1261    cy = rc.y;
1262    cw = rc.w;
1263    ch = rc.h;
1264 
1265    edje_object_size_min_calc(handler, NULL, &hh);
1266 
1267    sd->ox = pos.x + cx + (cw / 2);
1268    if (ch > hh)
1269      {
1270         sd->oy = pos.y + cy + ch;
1271      }
1272    else
1273      {
1274         sd->oy = pos.y + cy + (ch / 2);
1275      }
1276 
1277    efl_input_clickable_longpress_abort(obj, 1);
1278    sd->long_pressed = EINA_FALSE;
1279 }
1280 
1281 static void
_start_handler_mouse_down_cb(void * data,const Efl_Event * event EINA_UNUSED)1282 _start_handler_mouse_down_cb(void *data, const Efl_Event *event EINA_UNUSED)
1283 {
1284    EFL_UI_TEXT_DATA_GET(data, sd);
1285 
1286    int start_pos, end_pos, pos;
1287    Efl_Text_Cursor_Object *sel_start, *sel_end;
1288    Efl_Text_Cursor_Object *main_cur;
1289 
1290    Eo *text_obj = sd->text_obj;
1291 
1292    sd->start_handler_down = EINA_TRUE;
1293 
1294    /* Get the cursors */
1295    efl_text_interactive_selection_cursors_get(text_obj, &sel_start, &sel_end);
1296    main_cur = efl_text_interactive_main_cursor_get(text_obj);
1297 
1298    start_pos = efl_text_cursor_object_position_get(sel_start);
1299    end_pos = efl_text_cursor_object_position_get(sel_end);
1300 
1301    if (start_pos <= end_pos)
1302      {
1303         pos = start_pos;
1304         sd->sel_handler_cursor = sel_start;
1305      }
1306    else
1307      {
1308         pos = end_pos;
1309         sd->sel_handler_cursor = sel_end;
1310      }
1311    efl_text_cursor_object_position_set(main_cur, pos);
1312    _selection_handlers_offset_calc(data, sd->start_handler);
1313 }
1314 
1315 static void
_start_handler_mouse_up_cb(void * data,const Efl_Event * event EINA_UNUSED)1316 _start_handler_mouse_up_cb(void *data, const Efl_Event *event EINA_UNUSED)
1317 {
1318    EFL_UI_TEXT_DATA_GET(data, sd);
1319 
1320    sd->start_handler_down = EINA_FALSE;
1321    /* Context menu should not appear, even in case of selector mode, if the
1322     * flag is false (disabled) */
1323    if ((!_elm_config->context_menu_disabled) &&
1324        (!_elm_config->desktop_entry) && (sd->long_pressed))
1325      _menu_call(data);
1326 }
1327 
1328 static void
_start_handler_mouse_move_cb(void * data,const Efl_Event * event)1329 _start_handler_mouse_move_cb(void *data, const Efl_Event *event)
1330 {
1331    EFL_UI_TEXT_DATA_GET(data, sd);
1332 
1333    if (!sd->start_handler_down) return;
1334    Efl_Input_Pointer_Data *ev;
1335    ev = efl_data_scope_get(event->info, EFL_INPUT_POINTER_CLASS);
1336    Eina_Rect re;
1337    Evas_Coord cx, cy;
1338    int pos;
1339 
1340    re = efl_gfx_entity_geometry_get(sd->entry_edje);
1341    cx = ev->cur.x - sd->ox - re.x;
1342    cy = ev->cur.y - sd->oy - re.y;
1343    if (cx <= 0) cx = 1;
1344 
1345    efl_text_cursor_object_char_coord_set(sd->sel_handler_cursor, EINA_POSITION2D(cx, cy));
1346    pos = efl_text_cursor_object_position_get(sd->sel_handler_cursor);
1347 
1348    /* Set the main cursor. */
1349    efl_text_cursor_object_position_set(
1350          efl_text_interactive_main_cursor_get(sd->text_obj), pos);
1351 
1352    efl_input_clickable_longpress_abort(data, 1);
1353    sd->long_pressed = EINA_FALSE;
1354 }
1355 
1356 static void
_end_handler_mouse_down_cb(void * data,const Efl_Event * event EINA_UNUSED)1357 _end_handler_mouse_down_cb(void *data, const Efl_Event *event EINA_UNUSED)
1358 {
1359    EFL_UI_TEXT_DATA_GET(data, sd);
1360 
1361    Efl_Text_Cursor_Object *sel_start, *sel_end;
1362    Efl_Text_Cursor_Object *main_cur;
1363    int pos, start_pos, end_pos;
1364 
1365    sd->end_handler_down = EINA_TRUE;
1366 
1367    Eo *text_obj = sd->text_obj;
1368 
1369    efl_text_interactive_selection_cursors_get(text_obj, &sel_start, &sel_end);
1370    main_cur = efl_text_interactive_main_cursor_get(text_obj);
1371 
1372    start_pos = efl_text_cursor_object_position_get(sel_start);
1373    end_pos = efl_text_cursor_object_position_get(sel_end);
1374 
1375    if (start_pos < end_pos)
1376      {
1377         pos = end_pos;
1378         sd->sel_handler_cursor = sel_end;
1379      }
1380    else
1381      {
1382         pos = start_pos;
1383         sd->sel_handler_cursor = sel_start;
1384      }
1385 
1386    efl_text_cursor_object_position_set(main_cur, pos);
1387    _selection_handlers_offset_calc(data, sd->end_handler);
1388 }
1389 
1390 static void
_end_handler_mouse_up_cb(void * data,const Efl_Event * event EINA_UNUSED)1391 _end_handler_mouse_up_cb(void *data, const Efl_Event *event EINA_UNUSED)
1392 {
1393    EFL_UI_TEXT_DATA_GET(data, sd);
1394 
1395    sd->end_handler_down = EINA_FALSE;
1396    /* Context menu appear was checked in case of selector start, and hence
1397     * the same should be checked at selector end as well */
1398    if ((!_elm_config->context_menu_disabled) &&
1399        (!_elm_config->desktop_entry) && (sd->long_pressed))
1400      _menu_call(data);
1401 }
1402 
1403 static void
_end_handler_mouse_move_cb(void * data,const Efl_Event * event)1404 _end_handler_mouse_move_cb(void *data, const Efl_Event *event)
1405 {
1406    EFL_UI_TEXT_DATA_GET(data, sd);
1407    Efl_Input_Pointer_Data *ev;
1408    ev = efl_data_scope_get(event->info, EFL_INPUT_POINTER_CLASS);
1409 
1410    if (!sd->end_handler_down) return;
1411    Eina_Rect re;
1412    Evas_Coord cx, cy;
1413    int pos;
1414 
1415    re = efl_gfx_entity_geometry_get(sd->entry_edje);
1416    cx = ev->cur.x - sd->ox - re.x;
1417    cy = ev->cur.y - sd->oy - re.y;
1418    if (cx <= 0) cx = 1;
1419 
1420    efl_text_cursor_object_char_coord_set(sd->sel_handler_cursor, EINA_POSITION2D(cx, cy));
1421    pos = efl_text_cursor_object_position_get(sd->sel_handler_cursor);
1422    /* Set the main cursor. */
1423    efl_text_cursor_object_position_set(efl_text_interactive_main_cursor_get(data), pos);
1424    efl_input_clickable_longpress_abort(data, 1);
1425    sd->long_pressed = EINA_FALSE;
1426 }
1427 
1428 static void
_create_selection_handlers(Evas_Object * obj,Efl_Ui_Textbox_Data * sd)1429 _create_selection_handlers(Evas_Object *obj, Efl_Ui_Textbox_Data *sd)
1430 {
1431    Evas_Object *handle;
1432 
1433    handle = _decoration_create(obj, sd, PART_NAME_HANDLER_START, EINA_TRUE);
1434    efl_canvas_object_pass_events_set(handle, EINA_FALSE);
1435    sd->start_handler = handle;
1436    efl_event_callback_add(handle, EFL_EVENT_POINTER_DOWN,
1437                                   _start_handler_mouse_down_cb, obj);
1438    efl_event_callback_add(handle, EFL_EVENT_POINTER_MOVE,
1439                                   _start_handler_mouse_move_cb, obj);
1440    efl_event_callback_add(handle, EFL_EVENT_POINTER_UP,
1441                                   _start_handler_mouse_up_cb, obj);
1442    efl_gfx_entity_visible_set(handle, EINA_TRUE);
1443 
1444    handle = _decoration_create(obj, sd, PART_NAME_HANDLER_END, EINA_TRUE);
1445    efl_canvas_object_pass_events_set(handle, EINA_FALSE);
1446    sd->end_handler = handle;
1447    efl_event_callback_add(handle, EFL_EVENT_POINTER_DOWN,
1448                                   _end_handler_mouse_down_cb, obj);
1449    efl_event_callback_add(handle, EFL_EVENT_POINTER_MOVE,
1450                                   _end_handler_mouse_move_cb, obj);
1451    efl_event_callback_add(handle, EFL_EVENT_POINTER_UP,
1452                                   _end_handler_mouse_up_cb, obj);
1453    efl_gfx_entity_visible_set(handle, EINA_TRUE);
1454 }
1455 
1456 EOLIAN static void
_efl_ui_textbox_efl_gfx_entity_position_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Position2D pos)1457 _efl_ui_textbox_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Position2D pos)
1458 {
1459    efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos);
1460    efl_gfx_entity_position_set(sd->hit_rect, pos);
1461 
1462    if (sd->popup) _popup_position(obj);
1463 }
1464 
1465 EOLIAN static void
_efl_ui_textbox_efl_gfx_entity_size_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Size2D sz)1466 _efl_ui_textbox_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Size2D sz)
1467 {
1468    efl_gfx_entity_size_set(sd->hit_rect, sz);
1469    _update_selection_handler(obj);
1470 
1471    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz);
1472 }
1473 
1474 EOLIAN static void
_efl_ui_textbox_efl_gfx_entity_visible_set(Eo * obj,Efl_Ui_Textbox_Data * sd EINA_UNUSED,Eina_Bool vis)1475 _efl_ui_textbox_efl_gfx_entity_visible_set(Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED, Eina_Bool vis)
1476 {
1477    efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), vis);
1478    if (vis) _update_selection_handler(obj);
1479 }
1480 
1481 EOLIAN static void
_efl_ui_textbox_efl_canvas_group_group_member_add(Eo * obj,Efl_Ui_Textbox_Data * sd,Evas_Object * member)1482 _efl_ui_textbox_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Textbox_Data *sd, Evas_Object *member)
1483 {
1484    efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member);
1485 
1486    if (sd->hit_rect)
1487      efl_gfx_stack_raise_to_top(sd->hit_rect);
1488 }
1489 
1490 static void
_update_guide_text(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)1491 _update_guide_text(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
1492 {
1493    const char *txt;
1494    Eina_Bool show_guide;
1495 
1496    txt = efl_text_get(sd->text_obj);
1497 
1498    show_guide = (!txt || (txt[0] == '\0'));
1499 
1500    efl_gfx_entity_visible_set(sd->text_guide_obj, show_guide);
1501 
1502 }
1503 
1504 /**
1505  * @internal
1506  * Returns the numeric value of HEX chars for example for ch = 'A'
1507  * the function will return 10.
1508  *
1509  * @param ch The HEX char.
1510  * @return numeric value of HEX.
1511  */
1512 static int
_hex_string_get(char ch,Eina_Bool * ok)1513 _hex_string_get(char ch, Eina_Bool *ok)
1514 {
1515    if ((ch >= '0') && (ch <= '9')) return (ch - '0');
1516    else if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
1517    else if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
1518    *ok = EINA_FALSE;
1519    return 0;
1520 }
1521 
1522 
1523 static inline Eina_Bool
_format_color_parse(const char * str,int slen,unsigned char * r,unsigned char * g,unsigned char * b,unsigned char * a)1524 _format_color_parse(const char *str, int slen,
1525       unsigned char *r, unsigned char *g,
1526       unsigned char *b, unsigned char *a)
1527 {
1528    Eina_Bool v = EINA_TRUE;
1529 
1530    *r = *g = *b = *a = 0;
1531 
1532    if (slen == 7) /* #RRGGBB */
1533      {
1534         *r = (_hex_string_get(str[1], &v) << 4) | (_hex_string_get(str[2], &v));
1535         *g = (_hex_string_get(str[3], &v) << 4) | (_hex_string_get(str[4], &v));
1536         *b = (_hex_string_get(str[5], &v) << 4) | (_hex_string_get(str[6], &v));
1537         *a = 0xff;
1538      }
1539    else if (slen == 9) /* #RRGGBBAA */
1540      {
1541         *r = (_hex_string_get(str[1], &v) << 4) | (_hex_string_get(str[2], &v));
1542         *g = (_hex_string_get(str[3], &v) << 4) | (_hex_string_get(str[4], &v));
1543         *b = (_hex_string_get(str[5], &v) << 4) | (_hex_string_get(str[6], &v));
1544         *a = (_hex_string_get(str[7], &v) << 4) | (_hex_string_get(str[8], &v));
1545      }
1546    else if (slen == 4) /* #RGB */
1547      {
1548         *r = _hex_string_get(str[1], &v);
1549         *r = (*r << 4) | *r;
1550         *g = _hex_string_get(str[2], &v);
1551         *g = (*g << 4) | *g;
1552         *b = _hex_string_get(str[3], &v);
1553         *b = (*b << 4) | *b;
1554         *a = 0xff;
1555      }
1556    else if (slen == 5) /* #RGBA */
1557      {
1558         *r = _hex_string_get(str[1], &v);
1559         *r = (*r << 4) | *r;
1560         *g = _hex_string_get(str[2], &v);
1561         *g = (*g << 4) | *g;
1562         *b = _hex_string_get(str[3], &v);
1563         *b = (*b << 4) | *b;
1564         *a = _hex_string_get(str[4], &v);
1565         *a = (*a << 4) | *a;
1566      }
1567    else v = EINA_FALSE;
1568 
1569    *r = (*r * *a) / 255;
1570    *g = (*g * *a) / 255;
1571    *b = (*b * *a) / 255;
1572    return v;
1573 }
1574 
1575 /**
1576   * @internal
1577   * Updates the text properties of the object from the theme.
1578   *
1579   * This update functions skips any property that was already set,
1580   * to allow users to override the theme during the construction of the widget.
1581   */
1582 static void
_update_text_theme(Eo * obj,Efl_Ui_Textbox_Data * sd)1583 _update_text_theme(Eo *obj, Efl_Ui_Textbox_Data *sd)
1584 {
1585    const char *font_name;
1586    const char *font_size;
1587    const char *colorcode = NULL;
1588    Eina_Bool disabled;
1589 
1590    int font_size_n;
1591    unsigned char r, g, b, a;
1592 
1593    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1594    disabled = efl_ui_widget_disabled_get(obj);
1595 
1596    // Main Text
1597    // font_set
1598    if (!efl_text_font_family_get(sd->text_obj))
1599      {
1600         font_name = efl_layout_group_data_get(wd->resize_obj, "font.name");
1601         efl_text_font_family_set(sd->text_obj, font_name);
1602      }
1603    if (!efl_text_font_size_get(sd->text_obj))
1604      {
1605         font_size = efl_layout_group_data_get(wd->resize_obj, "font.size");
1606         font_size_n = font_size ? atoi(font_size) : 0;
1607         efl_text_font_size_set(sd->text_obj, font_size_n);
1608      }
1609 
1610    // color
1611    if (!sd->color_is_set)
1612      {
1613         // If user set color by him self, we will not change it back even if
1614         // control become disabled.
1615         if (disabled)
1616           colorcode = efl_layout_group_data_get(wd->resize_obj, "style.color_disabled");
1617         if (!colorcode)
1618           colorcode = efl_layout_group_data_get(wd->resize_obj, "style.color");
1619         if (colorcode && _format_color_parse(colorcode, strlen(colorcode), &r, &g, &b, &a))
1620           {
1621              efl_text_color_set(sd->text_obj, r, g, b, a);
1622           }
1623      }
1624 
1625    // Guide Text
1626    if (!efl_text_font_family_get(sd->text_guide_obj))
1627      {
1628         font_name = efl_layout_group_data_get(wd->resize_obj, "guide.font.name");
1629         efl_text_font_family_set(sd->text_guide_obj, font_name);
1630      }
1631    if (!efl_text_font_size_get(sd->text_guide_obj))
1632      {
1633         font_size = efl_layout_group_data_get(wd->resize_obj, "guide.font.size");
1634         font_size_n = font_size ? atoi(font_size) : 0;
1635         efl_text_font_size_set(sd->text_guide_obj, font_size_n);
1636      }
1637 
1638    colorcode = NULL;
1639    // color
1640    if (disabled)
1641      colorcode = efl_layout_group_data_get(wd->resize_obj, "guide.style.color_disabled");
1642    if (!colorcode)
1643      colorcode = efl_layout_group_data_get(wd->resize_obj, "guide.style.color");
1644    if (colorcode && _format_color_parse(colorcode, strlen(colorcode), &r, &g, &b, &a))
1645      {
1646         efl_text_color_set(sd->text_guide_obj, r, g, b, a);
1647      }
1648 }
1649 
1650 EOLIAN static Eo *
_efl_ui_textbox_efl_object_constructor(Eo * obj,Efl_Ui_Textbox_Data * sd)1651 _efl_ui_textbox_efl_object_constructor(Eo *obj, Efl_Ui_Textbox_Data *sd)
1652 {
1653    Eo *text_obj;
1654 
1655    sd->content = EFL_UI_TEXTBOX_CNP_CONTENT_MARKUP;
1656 
1657    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
1658 
1659    if (!elm_widget_theme_klass_get(obj))
1660      elm_widget_theme_klass_set(obj, "text");
1661 
1662    efl_event_callback_add(obj, EFL_UI_SELECTION_EVENT_WM_SELECTION_CHANGED, _selection_lost_cb, NULL);
1663    efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_ENTERED, _dnd_enter_cb, NULL);
1664    efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_POSITION_CHANGED, _dnd_pos_cb, NULL);
1665    efl_event_callback_add(obj, EFL_UI_DND_EVENT_DROP_DROPPED, _dnd_drop_cb, NULL);
1666 
1667    obj = efl_constructor(efl_super(obj, MY_CLASS));
1668    efl_event_callback_add(obj, EFL_INPUT_EVENT_LONGPRESSED, _long_press_cb, obj);
1669 
1670    text_obj = efl_add(EFL_UI_INTERNAL_TEXT_INTERACTIVE_CLASS, obj);
1671    efl_event_callback_forwarder_add(text_obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, obj);
1672    efl_event_callback_forwarder_add(text_obj, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED, obj);
1673    efl_event_callback_forwarder_add(text_obj, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED, obj);
1674    efl_event_callback_forwarder_add(text_obj, EFL_TEXT_INTERACTIVE_EVENT_REDO_REQUEST, obj);
1675    efl_event_callback_forwarder_add(text_obj, EFL_TEXT_INTERACTIVE_EVENT_UNDO_REQUEST, obj);
1676    efl_event_callback_forwarder_add(text_obj, EFL_TEXT_INTERACTIVE_EVENT_PREEDIT_CHANGED, obj);
1677    sd->text_obj = text_obj;
1678    sd->text_guide_obj = efl_add(EFL_CANVAS_TEXTBLOCK_CLASS, obj);
1679    sd->text_table = efl_add(EFL_UI_TABLE_CLASS, obj);
1680    efl_composite_attach(obj, text_obj);
1681 
1682    sd->entry_edje = wd->resize_obj;
1683    sd->context_menu_enabled = EINA_TRUE;
1684    efl_text_interactive_editable_set(obj, EINA_TRUE);
1685    efl_text_interactive_selection_allowed_set(obj, EINA_TRUE);
1686    sd->last.scroll = EINA_SIZE2D(0, 0);
1687    sd->sel_handles_enabled = EINA_FALSE;
1688 
1689    return obj;
1690 }
1691 
1692 EOLIAN static Eo *
_efl_ui_textbox_efl_object_finalize(Eo * obj,Efl_Ui_Textbox_Data * sd)1693 _efl_ui_textbox_efl_object_finalize(Eo *obj,
1694                                  Efl_Ui_Textbox_Data *sd)
1695 {
1696    obj = efl_finalize(efl_super(obj, MY_CLASS));
1697 
1698    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY);
1699 
1700    _update_guide_text(obj, sd);
1701 
1702    sd->item_fallback_factory = efl_add(EFL_UI_TEXT_FACTORY_FALLBACK_CLASS, obj);
1703 
1704    efl_gfx_hint_weight_set
1705       (sd->entry_edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1706    efl_gfx_hint_align_set
1707       (sd->entry_edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
1708    efl_event_callback_add(sd->text_obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER,
1709          _efl_ui_textbox_changed_user_cb, obj);
1710    efl_event_callback_add(sd->text_obj, EFL_CANVAS_TEXTBLOCK_EVENT_CHANGED,
1711          _efl_ui_textbox_changed_cb, obj);
1712    efl_event_callback_add(sd->text_obj, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED,
1713          _efl_ui_textbox_selection_start_clear_cb, obj);
1714    efl_event_callback_add(sd->text_obj, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED,
1715          _efl_ui_textbox_selection_changed_cb, obj);
1716    efl_event_callback_add(efl_text_interactive_main_cursor_get(sd->text_obj), EFL_TEXT_CURSOR_OBJECT_EVENT_CHANGED,
1717          _efl_ui_textbox_cursor_changed_cb, obj);
1718    efl_event_callback_add(sd->text_obj, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED,
1719          _text_position_changed_cb, obj);
1720    efl_event_callback_add(sd->entry_edje, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED,
1721          _efl_ui_textbox_move_cb, obj);
1722 
1723    efl_event_callback_add
1724      (sd->entry_edje, EFL_EVENT_POINTER_DOWN, _mouse_down_cb, obj);
1725    efl_event_callback_add
1726      (sd->entry_edje, EFL_EVENT_POINTER_UP, _mouse_up_cb, obj);
1727    efl_event_callback_add
1728      (sd->entry_edje, EFL_EVENT_POINTER_MOVE, _mouse_move_cb, obj);
1729    efl_ui_action_connector_bind_clickable_to_object(sd->entry_edje, obj);
1730 
1731    efl_event_callback_add(obj, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED,
1732          _text_size_changed_cb, obj);
1733 
1734    efl_ui_widget_focus_allow_set(obj, efl_text_interactive_editable_get(obj));
1735 
1736    efl_input_text_input_panel_layout_set(obj, EFL_INPUT_TEXT_PANEL_LAYOUT_TYPE_NORMAL);
1737    efl_input_text_input_panel_autoshow_set(obj, EINA_TRUE);
1738    efl_input_text_predictable_set(obj, EINA_TRUE);
1739    efl_input_text_input_content_type_set(obj, EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE);
1740 
1741    sd->calc_force = EINA_TRUE;
1742 
1743    return obj;
1744 
1745 }
1746 
1747 EOLIAN static void
_efl_ui_textbox_efl_object_destructor(Eo * obj,Efl_Ui_Textbox_Data * sd)1748 _efl_ui_textbox_efl_object_destructor(Eo *obj, Efl_Ui_Textbox_Data *sd)
1749 {
1750    efl_event_freeze(obj);
1751 
1752    _popup_dismiss(sd);
1753    if ((sd->api) && (sd->api->obj_unhook))
1754      sd->api->obj_unhook(obj);  // module - unhook
1755 
1756    entries = eina_list_remove(entries, obj);
1757    eina_stringshare_del(sd->text);
1758    eina_stringshare_del(sd->anchor_hover.hover_style);
1759 
1760    efl_event_thaw(obj);
1761 
1762    if (sd->start_handler)
1763      {
1764         efl_del(sd->start_handler);
1765         efl_del(sd->end_handler);
1766      }
1767 
1768    _anchors_free(sd);
1769    _clear_text_selection(sd);
1770 
1771    if (sd->item_factory) efl_unref(sd->item_factory);
1772 
1773    efl_destructor(efl_super(obj, MY_CLASS));
1774 }
1775 
1776 EOLIAN static void
_efl_ui_textbox_efl_text_format_multiline_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Bool enabled)1777 _efl_ui_textbox_efl_text_format_multiline_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Bool enabled)
1778 {
1779    enabled = !!enabled;
1780    if (efl_text_multiline_get(obj) == enabled) return;
1781    efl_text_multiline_set(sd->text_obj, enabled);
1782 
1783    if (sd->scroller)
1784      {
1785         if (enabled)
1786           {
1787              efl_ui_internal_text_scroller_mode_set(sd->scroller, EFL_UI_TEXT_SCROLLER_MODE_MULTILINE);
1788           }
1789         else
1790           {
1791              efl_ui_internal_text_scroller_mode_set(sd->scroller, EFL_UI_TEXT_SCROLLER_MODE_SINGLELINE);
1792           }
1793      }
1794 }
1795 
1796 EOLIAN static void
_efl_ui_textbox_efl_text_format_password_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Bool password)1797 _efl_ui_textbox_efl_text_format_password_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Bool password)
1798 {
1799    password = !!password;
1800 
1801    if (efl_text_password_get(obj) == password) return;
1802    if (!efl_text_replacement_char_get(obj))
1803      efl_text_replacement_char_set(obj, ENTRY_PASSWORD_MASK_CHARACTER_UTF8);
1804    efl_text_password_set(sd->text_obj, password);
1805 
1806    if (password)
1807      {
1808         efl_text_multiline_set(obj, EINA_FALSE);
1809         efl_input_text_input_content_type_set(obj, ((efl_input_text_input_content_type_get(obj) & ~EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) | EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA));
1810         efl_access_object_role_set(obj, EFL_ACCESS_ROLE_PASSWORD_TEXT);
1811      }
1812    else
1813      {
1814         efl_text_multiline_set(obj, EINA_TRUE);
1815         efl_input_text_input_content_type_set(obj, ((efl_input_text_input_content_type_get(obj) | EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) & ~EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA));
1816         efl_access_object_role_set(obj, EFL_ACCESS_ROLE_ENTRY);
1817      }
1818 }
1819 
1820 EOLIAN static void
_efl_ui_textbox_efl_text_style_text_color_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd,unsigned char r,unsigned char g,unsigned char b,unsigned char a)1821 _efl_ui_textbox_efl_text_style_text_color_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
1822 {
1823    pd->color_is_set = EINA_TRUE;
1824    efl_text_color_set(pd->text_obj, r, g, b, a);
1825 }
1826 static void
_efl_ui_textbox_calc_force(Eo * obj,Efl_Ui_Textbox_Data * sd)1827 _efl_ui_textbox_calc_force(Eo *obj, Efl_Ui_Textbox_Data *sd)
1828 {
1829    sd->calc_force = EINA_TRUE;
1830    edje_object_calc_force(sd->entry_edje);
1831    efl_canvas_group_calculate(obj);
1832 }
1833 
1834 static const char*
_efl_ui_textbox_selection_get(const Eo * obj,Efl_Ui_Textbox_Data * sd EINA_UNUSED)1835 _efl_ui_textbox_selection_get(const Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED)
1836 {
1837    Efl_Text_Cursor_Object *start_obj, *end_obj;
1838 
1839    if ((efl_text_password_get(obj))) return NULL;
1840 
1841    efl_text_interactive_selection_cursors_get(obj, &start_obj, &end_obj);
1842    return efl_text_cursor_object_range_text_get(start_obj, end_obj);
1843 }
1844 
1845 EOLIAN static void
_efl_ui_textbox_selection_handles_enabled_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool enabled)1846 _efl_ui_textbox_selection_handles_enabled_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool enabled)
1847 {
1848    if (sd->sel_handles_enabled == enabled) return;
1849    sd->sel_handles_enabled = enabled;
1850 }
1851 
1852 EOLIAN static Eina_Bool
_efl_ui_textbox_selection_handles_enabled_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)1853 _efl_ui_textbox_selection_handles_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
1854 {
1855    return sd->sel_handles_enabled;
1856 }
1857 
1858 static void
_efl_ui_textbox_entry_insert(Eo * obj,Efl_Ui_Textbox_Data * sd,const char * entry)1859 _efl_ui_textbox_entry_insert(Eo *obj, Efl_Ui_Textbox_Data *sd, const char *entry)
1860 {
1861    Efl_Text_Cursor_Object *cur_obj = efl_text_interactive_main_cursor_get(obj);
1862    efl_text_cursor_object_text_insert(cur_obj, entry);
1863    sd->text_changed = EINA_TRUE;
1864    efl_canvas_group_change(obj);
1865 }
1866 
1867 EOLIAN static Efl_Text_Cursor_Object *
_efl_ui_textbox_cursor_create(Eo * obj,Efl_Ui_Textbox_Data * pd)1868 _efl_ui_textbox_cursor_create(Eo *obj, Efl_Ui_Textbox_Data *pd)
1869 {
1870    Eo* cursor = efl_text_cursor_object_create(pd->text_obj);;
1871    efl_text_cursor_object_text_object_set(cursor, pd->text_obj, obj);
1872    return cursor;
1873 }
1874 
1875 EOLIAN static void
_efl_ui_textbox_efl_text_interactive_editable_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Bool editable)1876 _efl_ui_textbox_efl_text_interactive_editable_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Bool editable)
1877 {
1878    if (efl_text_interactive_editable_get(obj) == editable) return;
1879 
1880    efl_text_interactive_editable_set(efl_super(obj, MY_CLASS), editable);
1881 
1882    efl_ui_widget_focus_allow_set(obj, editable);
1883 
1884    if (editable)
1885      {
1886         if (sd->cursor)
1887           {
1888              efl_gfx_entity_visible_set(sd->cursor, EINA_TRUE);
1889              efl_gfx_entity_visible_set(sd->cursor_bidi, EINA_TRUE);
1890           }
1891      }
1892    if (!editable && sd->cursor)
1893      {
1894         efl_gfx_entity_visible_set(sd->cursor, EINA_FALSE);
1895         efl_gfx_entity_visible_set(sd->cursor_bidi, EINA_FALSE);
1896      }
1897 }
1898 
1899 static void
_efl_ui_textbox_select_region_set(Eo * obj,Efl_Ui_Textbox_Data * sd EINA_UNUSED,int start,int end)1900 _efl_ui_textbox_select_region_set(Eo *obj, Efl_Ui_Textbox_Data *sd EINA_UNUSED, int start, int end)
1901 {
1902    Efl_Text_Cursor_Object *sel_start, *sel_end;
1903 
1904    if (efl_text_password_get(obj)) return;
1905 
1906    efl_text_interactive_selection_cursors_get(obj, &sel_start, &sel_end);
1907 
1908    efl_text_cursor_object_position_set(sel_start, start);
1909    efl_text_cursor_object_position_set(sel_end, end);
1910 }
1911 
1912 static void
_efl_ui_textbox_select_region_get(Eo * obj,int * start,int * end)1913 _efl_ui_textbox_select_region_get(Eo *obj, int *start, int *end)
1914 {
1915    Efl_Text_Cursor_Object *sel_start, *sel_end;
1916 
1917    efl_text_interactive_selection_cursors_get(obj, &sel_start, &sel_end);
1918 
1919    if(start) *start = efl_text_cursor_object_position_get(sel_start);
1920    if(end) *end = efl_text_cursor_object_position_get(sel_end);
1921 }
1922 
1923 EOLIAN static void
_efl_ui_textbox_selection_cut(Eo * obj,Efl_Ui_Textbox_Data * sd)1924 _efl_ui_textbox_selection_cut(Eo *obj, Efl_Ui_Textbox_Data *sd)
1925 {
1926    Efl_Text_Cursor_Object *start, *end;
1927    Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
1928    char *tmp;
1929    int end_pos, start_pos;
1930 
1931    /* Store it */
1932    sd->sel_mode = EINA_FALSE;
1933    if (!_elm_config->desktop_entry)
1934      edje_object_part_text_select_allow_set
1935        (sd->entry_edje, "efl.text", EINA_FALSE);
1936    efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl");
1937 
1938    if (!_elm_config->desktop_entry)
1939      efl_ui_widget_scroll_hold_pop(obj);
1940 
1941    /*In password mode, cut will remove text only*/
1942    if (!efl_text_password_get(obj))
1943      _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj);
1944    efl_text_interactive_selection_cursors_get(obj, &start, &end);
1945 
1946    start_pos = efl_text_cursor_object_position_get(start);
1947    end_pos = efl_text_cursor_object_position_get(end);
1948    tmp = efl_text_cursor_object_range_text_get(start, end);
1949    info.type = EFL_TEXT_CHANGE_TYPE_REMOVE;
1950    info.position = start_pos;
1951    info.length = end_pos - start_pos;
1952    info.content = tmp;
1953    efl_text_cursor_object_range_delete(start, end);
1954    efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
1955    free(tmp);
1956    tmp = NULL;
1957    efl_text_interactive_all_unselect(obj);
1958 
1959    efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_CUT, NULL);
1960 }
1961 
1962 EOLIAN static void
_efl_ui_textbox_selection_copy(Eo * obj,Efl_Ui_Textbox_Data * sd)1963 _efl_ui_textbox_selection_copy(Eo *obj, Efl_Ui_Textbox_Data *sd)
1964 {
1965    if (efl_text_password_get(obj)) return;
1966 
1967    sd->sel_mode = EINA_FALSE;
1968    if (!_elm_config->desktop_entry)
1969      {
1970         edje_object_part_text_select_allow_set
1971           (sd->entry_edje, "efl.text", EINA_FALSE);
1972         efl_layout_signal_emit(sd->entry_edje, "efl,state,select,off", "efl");
1973         efl_ui_widget_scroll_hold_pop(obj);
1974      }
1975    _selection_store(EFL_UI_CNP_BUFFER_COPY_AND_PASTE, obj);
1976    efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_COPY, NULL);
1977 }
1978 static void
_efl_ui_textbox_selection_paste_type(Eo * obj,Efl_Ui_Textbox_Data * sd,Efl_Ui_Cnp_Buffer type)1979 _efl_ui_textbox_selection_paste_type(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Ui_Cnp_Buffer type)
1980 {
1981    Eina_Future *future;
1982    Eina_Array *types = _figure_out_types(obj, sd);
1983 
1984    future = efl_ui_selection_get(obj, type, evas_device_seat_id_get(evas_default_device_get(evas_object_evas_get(obj), EVAS_DEVICE_CLASS_SEAT)), eina_array_iterator_new(types));
1985 
1986    efl_future_then(obj, future, _selection_data_cb);
1987 
1988    efl_event_callback_call(obj, EFL_UI_TEXTBOX_EVENT_SELECTION_PASTE, NULL);
1989    eina_array_free(types);
1990 }
1991 
1992 EOLIAN static void
_efl_ui_textbox_selection_paste(Eo * obj,Efl_Ui_Textbox_Data * sd)1993 _efl_ui_textbox_selection_paste(Eo *obj, Efl_Ui_Textbox_Data *sd)
1994 {
1995    _efl_ui_textbox_selection_paste_type(obj, sd, EFL_UI_CNP_BUFFER_COPY_AND_PASTE);
1996 }
1997 
1998 EOLIAN static void
_efl_ui_textbox_context_menu_enabled_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool enabled)1999 _efl_ui_textbox_context_menu_enabled_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool enabled)
2000 {
2001    if (sd->context_menu_enabled == enabled) return;
2002    sd->context_menu_enabled = enabled;
2003 }
2004 
2005 EOLIAN static Eina_Bool
_efl_ui_textbox_context_menu_enabled_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)2006 _efl_ui_textbox_context_menu_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
2007 {
2008    return sd->context_menu_enabled;
2009 }
2010 
2011 EOLIAN static void
_efl_ui_textbox_cnp_dnd_mode_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Efl_Ui_Textbox_Cnp_Content content)2012 _efl_ui_textbox_cnp_dnd_mode_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Efl_Ui_Textbox_Cnp_Content content)
2013 {
2014    sd->content = content;
2015 }
2016 
2017 EOLIAN static Efl_Ui_Textbox_Cnp_Content
_efl_ui_textbox_cnp_dnd_mode_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)2018 _efl_ui_textbox_cnp_dnd_mode_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
2019 {
2020    return sd->content;
2021 }
2022 
2023 EOLIAN static void
_efl_ui_textbox_scrollable_set(Eo * obj,Efl_Ui_Textbox_Data * sd,Eina_Bool scroll)2024 _efl_ui_textbox_scrollable_set(Eo *obj, Efl_Ui_Textbox_Data *sd, Eina_Bool scroll)
2025 {
2026    if (sd->scroll == scroll) return;
2027    sd->scroll = scroll;
2028 
2029    if (scroll)
2030      {
2031         efl_content_set(efl_part(sd->entry_edje, "efl.text"), NULL);
2032         sd->scroller = efl_add(EFL_UI_INTERNAL_TEXT_SCROLLER_CLASS, obj,
2033               efl_ui_internal_text_scroller_initialize(efl_added,
2034                  sd->text_obj, sd->text_table));
2035 
2036         if (efl_text_multiline_get(obj))
2037           efl_ui_internal_text_scroller_mode_set(sd->scroller, EFL_UI_TEXT_SCROLLER_MODE_MULTILINE);
2038         else
2039           efl_ui_internal_text_scroller_mode_set(sd->scroller, EFL_UI_TEXT_SCROLLER_MODE_SINGLELINE);
2040 
2041         efl_content_set(efl_part(sd->entry_edje, "efl.text"), sd->scroller);
2042         efl_canvas_object_clipper_set(sd->cursor,
2043               efl_ui_internal_text_scroller_viewport_clip_get(sd->scroller));
2044         efl_event_callback_add(sd->scroller, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED,
2045               _scroller_size_changed_cb, obj);
2046      }
2047    else
2048      {
2049         /* sd->text_table should not be deleted, so we need to use content_unset
2050          * instead of efl_content_set(sd->scroller, NULL)
2051         */
2052         efl_content_unset(sd->scroller);
2053         efl_content_set(efl_part(sd->entry_edje, "efl.text"), sd->text_table);
2054         efl_del(sd->scroller);
2055         sd->scroller = NULL;
2056      }
2057    efl_canvas_group_change(obj);
2058 }
2059 
2060 EOLIAN static Eina_Bool
_efl_ui_textbox_scrollable_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)2061 _efl_ui_textbox_scrollable_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
2062 {
2063    return sd->scroll;
2064 }
2065 
2066 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_ui_widget_on_access_activate(Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,Efl_Ui_Activate act)2067 _efl_ui_textbox_efl_ui_widget_on_access_activate(Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, Efl_Ui_Activate act)
2068 {
2069    if (act != EFL_UI_ACTIVATE_DEFAULT) return EINA_FALSE;
2070 
2071    EFL_UI_TEXT_DATA_GET(obj, sd);
2072 
2073    if (!efl_ui_widget_disabled_get(obj) &&
2074        !(efl_event_freeze_count_get(obj) > 0))
2075      {
2076         efl_event_callback_call(obj, EFL_INPUT_EVENT_CLICKED, NULL);
2077         if (efl_text_interactive_editable_get(obj) && efl_input_text_input_panel_autoshow_get(obj))
2078           edje_object_part_text_input_panel_show(sd->entry_edje, "efl.text");
2079      }
2080    return EINA_TRUE;
2081 }
2082 
2083 // ATSPI Accessibility
2084 
2085 EOLIAN static Eina_Unicode
_efl_ui_textbox_efl_access_text_character_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,int offset)2086 _efl_ui_textbox_efl_access_text_character_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, int offset)
2087 {
2088    const char *txt;
2089    int idx = 0;
2090    Eina_Unicode ret = 0;
2091    if (offset < 0) return ret;
2092 
2093    if (efl_text_password_get(obj)) return ENTRY_PASSWORD_MASK_CHARACTER;
2094 
2095    txt = efl_text_get(obj);
2096    if (!txt) return ret;
2097 
2098    ret = eina_unicode_utf8_next_get(txt, &idx);
2099    while (offset--) ret = eina_unicode_utf8_next_get(txt, &idx);
2100 
2101    return ret;
2102 }
2103 
2104 EOLIAN static int
_efl_ui_textbox_efl_access_text_character_count_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED)2105 _efl_ui_textbox_efl_access_text_character_count_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED)
2106 {
2107    const char *txt;
2108 
2109    txt = efl_text_get(obj);
2110    if (!txt) return -1;
2111    return eina_unicode_utf8_get_len(txt);
2112 }
2113 
2114 EOLIAN static void
_efl_ui_textbox_efl_access_text_string_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd,Efl_Access_Text_Granularity granularity,int * start_offset,int * end_offset,char ** ret EFL_TRANSFER_OWNERSHIP)2115 _efl_ui_textbox_efl_access_text_string_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd, Efl_Access_Text_Granularity granularity, int *start_offset, int *end_offset, char **ret EFL_TRANSFER_OWNERSHIP)
2116 {
2117    Evas_Textblock_Cursor *cur = NULL, *cur2 = NULL;
2118 
2119    EINA_SAFETY_ON_NULL_RETURN(ret);
2120    *ret = NULL;
2121 
2122    cur = evas_object_textblock_cursor_new(pd->text_obj);
2123    cur2 = evas_object_textblock_cursor_new(pd->text_obj);
2124    if (!cur || !cur2) goto fail;
2125 
2126    evas_textblock_cursor_pos_set(cur, *start_offset);
2127    if (evas_textblock_cursor_pos_get(cur) != *start_offset) goto fail;
2128 
2129    switch (granularity)
2130      {
2131       case EFL_ACCESS_TEXT_GRANULARITY_CHAR:
2132          break;
2133       case EFL_ACCESS_TEXT_GRANULARITY_WORD:
2134          evas_textblock_cursor_word_start(cur);
2135          break;
2136       case EFL_ACCESS_TEXT_GRANULARITY_SENTENCE:
2137          // TODO - add sentence support in textblock first
2138          break;
2139       case EFL_ACCESS_TEXT_GRANULARITY_LINE:
2140          evas_textblock_cursor_line_char_first(cur);
2141          break;
2142       case EFL_ACCESS_TEXT_GRANULARITY_PARAGRAPH:
2143          evas_textblock_cursor_paragraph_char_first(cur);
2144          break;
2145      }
2146 
2147    *start_offset = evas_textblock_cursor_pos_get(cur);
2148    evas_textblock_cursor_copy(cur, cur2);
2149 
2150    switch (granularity)
2151      {
2152       case EFL_ACCESS_TEXT_GRANULARITY_CHAR:
2153          evas_textblock_cursor_char_next(cur2);
2154          break;
2155       case EFL_ACCESS_TEXT_GRANULARITY_WORD:
2156          evas_textblock_cursor_word_end(cur2);
2157          // since word_end sets cursor position ON (before) last
2158          // char of word, we need to manually advance cursor to get
2159          // proper string from function range_text_get
2160          evas_textblock_cursor_char_next(cur2);
2161          break;
2162       case EFL_ACCESS_TEXT_GRANULARITY_SENTENCE:
2163          // TODO - add sentence support in textblock first
2164          break;
2165       case EFL_ACCESS_TEXT_GRANULARITY_LINE:
2166          evas_textblock_cursor_line_char_last(cur2);
2167          break;
2168       case EFL_ACCESS_TEXT_GRANULARITY_PARAGRAPH:
2169          evas_textblock_cursor_paragraph_char_last(cur2);
2170          break;
2171      }
2172 
2173    if (end_offset) *end_offset = evas_textblock_cursor_pos_get(cur2);
2174 
2175    *ret = evas_textblock_cursor_range_text_get(cur, cur2, EVAS_TEXTBLOCK_TEXT_PLAIN);
2176 
2177    evas_textblock_cursor_free(cur);
2178    evas_textblock_cursor_free(cur2);
2179 
2180    if (*ret && efl_text_password_get(obj))
2181      {
2182         int i = 0;
2183         while (*ret[i] != '\0')
2184          *ret[i++] = ENTRY_PASSWORD_MASK_CHARACTER;
2185      }
2186 
2187    return;
2188 
2189 fail:
2190    if (start_offset) *start_offset = -1;
2191    if (end_offset) *end_offset = -1;
2192    if (cur) evas_textblock_cursor_free(cur);
2193    if (cur2) evas_textblock_cursor_free(cur2);
2194    *ret = NULL;
2195 }
2196 
2197 EOLIAN static char*
_efl_ui_textbox_efl_access_text_access_text_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd EINA_UNUSED,int start_offset,int end_offset)2198 _efl_ui_textbox_efl_access_text_access_text_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd EINA_UNUSED, int start_offset, int end_offset)
2199 {
2200    Evas_Textblock_Cursor *cur = NULL, *cur2 = NULL;
2201    char *ret = NULL;
2202    Eo *text_obj = pd->text_obj;
2203 
2204    cur = evas_object_textblock_cursor_new(text_obj);
2205    cur2 = evas_object_textblock_cursor_new(text_obj);
2206    if (!cur || !cur2) goto fail;
2207 
2208    evas_textblock_cursor_pos_set(cur, start_offset);
2209    if (evas_textblock_cursor_pos_get(cur) != start_offset) goto fail;
2210 
2211    evas_textblock_cursor_pos_set(cur2, end_offset);
2212    if (evas_textblock_cursor_pos_get(cur2) != end_offset) goto fail;
2213 
2214    ret = evas_textblock_cursor_range_text_get(cur, cur2, EVAS_TEXTBLOCK_TEXT_PLAIN);
2215 
2216    evas_textblock_cursor_free(cur);
2217    evas_textblock_cursor_free(cur2);
2218 
2219    if (ret && efl_text_password_get(obj))
2220      {
2221         int i = 0;
2222         while (ret[i] != '\0')
2223          ret[i++] = ENTRY_PASSWORD_MASK_CHARACTER;
2224      }
2225 
2226    return ret;
2227 
2228 fail:
2229    if (cur) evas_textblock_cursor_free(cur);
2230    if (cur2) evas_textblock_cursor_free(cur2);
2231    return NULL;
2232 }
2233 
2234 EOLIAN static int
_efl_ui_textbox_efl_access_text_caret_offset_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED)2235 _efl_ui_textbox_efl_access_text_caret_offset_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED)
2236 {
2237    return efl_text_cursor_object_position_get(efl_text_interactive_main_cursor_get(obj));
2238 }
2239 
2240 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_caret_offset_set(Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,int offset)2241 _efl_ui_textbox_efl_access_text_caret_offset_set(Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, int offset)
2242 {
2243    efl_text_cursor_object_position_set(efl_text_interactive_main_cursor_get(obj), offset);
2244    return EINA_TRUE;
2245 }
2246 
2247 EOLIAN static int
_efl_ui_textbox_efl_access_text_selections_count_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED)2248 _efl_ui_textbox_efl_access_text_selections_count_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED)
2249 {
2250    return _efl_ui_textbox_selection_get(obj, _pd) ? 1 : 0;
2251 }
2252 
2253 EOLIAN static void
_efl_ui_textbox_efl_access_text_access_selection_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,int selection_number,int * start_offset,int * end_offset)2254 _efl_ui_textbox_efl_access_text_access_selection_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, int selection_number, int *start_offset, int *end_offset)
2255 {
2256    if (selection_number != 0) return;
2257 
2258    _efl_ui_textbox_select_region_get((Eo *)obj, start_offset, end_offset);
2259 }
2260 
2261 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_access_selection_set(Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,int selection_number,int start_offset,int end_offset)2262 _efl_ui_textbox_efl_access_text_access_selection_set(Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, int selection_number, int start_offset, int end_offset)
2263 {
2264    if (selection_number != 0) return EINA_FALSE;
2265 
2266    _efl_ui_textbox_select_region_set(obj, _pd, start_offset, end_offset);
2267 
2268    return EINA_TRUE;
2269 }
2270 
2271 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_selection_remove(Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,int selection_number)2272 _efl_ui_textbox_efl_access_text_selection_remove(Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, int selection_number)
2273 {
2274    if (selection_number != 0) return EINA_FALSE;
2275    efl_text_interactive_all_unselect(obj);
2276    return EINA_TRUE;
2277 }
2278 
2279 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_selection_add(Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,int start_offset,int end_offset)2280 _efl_ui_textbox_efl_access_text_selection_add(Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, int start_offset, int end_offset)
2281 {
2282    _efl_ui_textbox_select_region_set(obj, pd, start_offset, end_offset);
2283 
2284    return EINA_TRUE;
2285 }
2286 
2287 EOLIAN static Eina_List*
_efl_ui_textbox_efl_access_text_bounded_ranges_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,Eina_Bool screen_coods EINA_UNUSED,Eina_Rect rect EINA_UNUSED,Efl_Access_Text_Clip_Type xclip EINA_UNUSED,Efl_Access_Text_Clip_Type yclip EINA_UNUSED)2288 _efl_ui_textbox_efl_access_text_bounded_ranges_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, Eina_Bool screen_coods EINA_UNUSED, Eina_Rect rect EINA_UNUSED, Efl_Access_Text_Clip_Type xclip EINA_UNUSED, Efl_Access_Text_Clip_Type yclip EINA_UNUSED)
2289 {
2290    return NULL;
2291 }
2292 
2293 EOLIAN static int
_efl_ui_textbox_efl_access_text_offset_at_point_get(const Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,Eina_Bool screen_coods,int x,int y)2294 _efl_ui_textbox_efl_access_text_offset_at_point_get(const Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, Eina_Bool screen_coods, int x, int y)
2295 {
2296    Evas_Textblock_Cursor *cur;
2297    int ret;
2298    Eo *text_obj = pd->text_obj;
2299 
2300    if (!text_obj) return -1;
2301 
2302    cur = evas_object_textblock_cursor_new(text_obj);
2303    if (!cur) return -1;
2304 
2305    if (screen_coods)
2306      {
2307         int ee_x, ee_y;
2308         Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
2309         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
2310         x -= ee_x;
2311         y -= ee_y;
2312      }
2313 
2314    if (!evas_textblock_cursor_char_coord_set(cur, x, y))
2315      {
2316         evas_textblock_cursor_free(cur);
2317         return -1;
2318      }
2319 
2320    ret = evas_textblock_cursor_pos_get(cur);
2321    evas_textblock_cursor_free(cur);
2322 
2323    return ret;
2324 }
2325 
2326 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_character_extents_get(const Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,int offset,Eina_Bool screen_coods,Eina_Rect * rect)2327 _efl_ui_textbox_efl_access_text_character_extents_get(const Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, int offset, Eina_Bool screen_coods, Eina_Rect *rect)
2328 {
2329    Evas_Textblock_Cursor *cur;
2330    int ret;
2331    Eo *text_obj = pd->text_obj;
2332 
2333    if (!text_obj) return EINA_FALSE;
2334 
2335    cur = evas_object_textblock_cursor_new(text_obj);
2336    if (!cur) return EINA_FALSE;
2337 
2338    evas_textblock_cursor_pos_set(cur, offset);
2339 
2340    ret = evas_textblock_cursor_char_geometry_get(cur, &rect->x, &rect->y, &rect->w, &rect->h);
2341    evas_textblock_cursor_free(cur);
2342 
2343    if (ret == -1) return EINA_FALSE;
2344 
2345    if (screen_coods)
2346      {
2347         int ee_x, ee_y;
2348         Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
2349         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
2350         rect->x += ee_x;
2351         rect->y += ee_y;
2352      }
2353 
2354    return EINA_TRUE;
2355 }
2356 
2357 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_range_extents_get(const Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,Eina_Bool screen_coods,int start_offset,int end_offset,Eina_Rect * rect)2358 _efl_ui_textbox_efl_access_text_range_extents_get(const Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, Eina_Bool screen_coods, int start_offset, int end_offset, Eina_Rect *rect)
2359 {
2360    Evas_Textblock_Cursor *cur1, *cur2;
2361    int ret;
2362    int x, xx, y, yy;
2363    Eo *text_obj = pd->text_obj;
2364 
2365    if (!text_obj) return EINA_FALSE;
2366 
2367    cur1 = evas_object_textblock_cursor_new(text_obj);
2368    if (!cur1) return EINA_FALSE;
2369 
2370    cur2 = evas_object_textblock_cursor_new(text_obj);
2371    if (!cur2)
2372      {
2373         evas_textblock_cursor_free(cur1);
2374         return EINA_FALSE;
2375      }
2376 
2377    evas_textblock_cursor_pos_set(cur1, start_offset);
2378    evas_textblock_cursor_pos_set(cur2, end_offset);
2379 
2380    ret = evas_textblock_cursor_char_geometry_get(cur1, &x, &y, NULL, NULL);
2381    ret += evas_textblock_cursor_char_geometry_get(cur2, &xx, &yy, NULL, NULL);
2382 
2383    evas_textblock_cursor_free(cur1);
2384    evas_textblock_cursor_free(cur2);
2385 
2386    if (ret != 0) return EINA_FALSE;
2387 
2388    rect->x = x < xx ? x : xx;
2389    rect->y = y < yy ? y : yy;
2390    rect->w = abs(x - xx);
2391    rect->h = abs(y - yy);
2392 
2393    if (screen_coods)
2394      {
2395         int ee_x, ee_y;
2396         Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
2397         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
2398         rect->x += ee_x;
2399         rect->y += ee_y;
2400      }
2401 
2402    return EINA_TRUE;
2403 }
2404 
2405 static Efl_Access_Text_Attribute*
_textblock_node_format_to_atspi_text_attr(Efl_Text_Attribute_Handle * annotation)2406 _textblock_node_format_to_atspi_text_attr(Efl_Text_Attribute_Handle *annotation)
2407 {
2408    Efl_Access_Text_Attribute *ret;
2409    const char *txt;
2410 
2411    txt = efl_text_formatter_attribute_get(annotation);
2412    if (!txt) return NULL;
2413 
2414    ret = calloc(1, sizeof(Efl_Access_Text_Attribute));
2415    if (!ret) return NULL;
2416 
2417    ret->value = eina_stringshare_add(txt);
2418    int size = strlen(txt);
2419    ret->name = eina_stringshare_add_length(txt, size);
2420 
2421    return ret;
2422 }
2423 
2424 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_text_attribute_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,const char * attr_name EINA_UNUSED,int * start_offset,int * end_offset,char ** value)2425 _efl_ui_textbox_efl_access_text_attribute_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, const char *attr_name EINA_UNUSED, int *start_offset, int *end_offset, char **value)
2426 {
2427    Efl_Text_Cursor_Object *cur1, *cur2;
2428    Efl_Access_Text_Attribute *attr;
2429    Eina_Iterator *annotations;
2430    Efl_Text_Attribute_Handle *an;
2431 
2432    Eo *mobj = (Eo *)obj;
2433    cur1 = efl_ui_textbox_cursor_create(mobj);
2434    if (!cur1) return EINA_FALSE;
2435 
2436    cur2 = efl_ui_textbox_cursor_create(mobj);
2437    if (!cur2)
2438      {
2439         efl_del(cur1);
2440         return EINA_FALSE;
2441      }
2442 
2443    efl_text_cursor_object_position_set(cur1, *start_offset);
2444    efl_text_cursor_object_position_set(cur2, *end_offset);
2445 
2446    annotations = efl_text_formatter_range_attributes_get(cur1, cur2);
2447 
2448    efl_del(cur1);
2449    efl_del(cur2);
2450 
2451    if (!annotations) return EINA_FALSE;
2452 
2453    EINA_ITERATOR_FOREACH(annotations, an)
2454      {
2455         attr = _textblock_node_format_to_atspi_text_attr(an);
2456         if (!attr) continue;
2457         if (!strcmp(attr->name, attr_name))
2458           {
2459              *value = attr->value ? strdup(attr->value) : NULL;
2460              elm_atspi_text_text_attribute_free(attr);
2461              return EINA_TRUE;
2462           }
2463         elm_atspi_text_text_attribute_free(attr);
2464      }
2465    eina_iterator_free(annotations);
2466 
2467    return EINA_FALSE;
2468 }
2469 
2470 EOLIAN static void
_efl_ui_textbox_efl_access_text_text_attributes_get(const Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,int * start_offset,int * end_offset,Eina_List ** ret EFL_TRANSFER_OWNERSHIP)2471 _efl_ui_textbox_efl_access_text_text_attributes_get(const Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, int *start_offset, int *end_offset, Eina_List **ret EFL_TRANSFER_OWNERSHIP)
2472 {
2473    Efl_Text_Cursor_Object *cur1, *cur2;
2474    Efl_Access_Text_Attribute *attr;
2475    Eina_Iterator *annotations;
2476    Efl_Text_Attribute_Handle *an;
2477    Eo *mobj = (Eo *)obj;
2478 
2479    EINA_SAFETY_ON_NULL_RETURN(ret);
2480    *ret = NULL;
2481 
2482    cur1 = efl_ui_textbox_cursor_create(mobj);
2483    if (!cur1) return;
2484 
2485    cur2 = efl_ui_textbox_cursor_create(mobj);
2486    if (!cur2)
2487      {
2488         efl_del(cur1);
2489         return;
2490      }
2491 
2492    efl_text_cursor_object_position_set(cur1, *start_offset);
2493    efl_text_cursor_object_position_set(cur2, *end_offset);
2494 
2495    annotations = efl_text_formatter_range_attributes_get(cur1, cur2);
2496 
2497    efl_del(cur1);
2498    efl_del(cur2);
2499 
2500    if (!annotations) return;
2501 
2502    EINA_ITERATOR_FOREACH(annotations, an)
2503      {
2504         attr = _textblock_node_format_to_atspi_text_attr(an);
2505         if (!attr) continue;
2506         *ret = eina_list_append(*ret, attr);
2507      }
2508    eina_iterator_free(annotations);
2509 }
2510 
2511 EOLIAN static Eina_List*
_efl_ui_textbox_efl_access_text_default_attributes_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED)2512 _efl_ui_textbox_efl_access_text_default_attributes_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED)
2513 {
2514    Eina_List *ret = NULL;
2515    Efl_Access_Text_Attribute *attr;
2516    Efl_Text_Cursor_Object *start, *end;
2517    Eina_Iterator *annotations;
2518    Efl_Text_Attribute_Handle *an;
2519 
2520    /* Retrieve all annotations in the text. */
2521    Eo *mobj = (Eo *)obj; /* XXX const */
2522    start = efl_ui_textbox_cursor_create(mobj);
2523    end = efl_ui_textbox_cursor_create(mobj);
2524 
2525    efl_text_cursor_object_move(start, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
2526    efl_text_cursor_object_move(end, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
2527 
2528    annotations = efl_text_formatter_range_attributes_get(start, end);
2529 
2530    EINA_ITERATOR_FOREACH(annotations, an)
2531      {
2532         attr = _textblock_node_format_to_atspi_text_attr(an);
2533         if (!attr) continue;
2534         ret = eina_list_append(ret, attr);
2535      }
2536    eina_iterator_free(annotations);
2537 
2538    return ret;
2539 }
2540 
2541 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_editable_text_text_content_set(Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,const char * content)2542 _efl_ui_textbox_efl_access_editable_text_text_content_set(Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, const char *content)
2543 {
2544    efl_text_set(obj, content);
2545    return EINA_TRUE;
2546 }
2547 
2548 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_editable_text_insert(Eo * obj,Efl_Ui_Textbox_Data * pd,const char * string,int position)2549 _efl_ui_textbox_efl_access_editable_text_insert(Eo *obj, Efl_Ui_Textbox_Data *pd, const char *string, int position)
2550 {
2551    Efl_Text_Cursor_Object *cur_obj = efl_text_interactive_main_cursor_get(obj);
2552    efl_text_cursor_object_position_set(cur_obj, position);
2553    _efl_ui_textbox_entry_insert(obj, pd, string);
2554 
2555    return EINA_TRUE;
2556 }
2557 
2558 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_editable_text_copy(Eo * obj,Efl_Ui_Textbox_Data * pd,int start,int end)2559 _efl_ui_textbox_efl_access_editable_text_copy(Eo *obj, Efl_Ui_Textbox_Data *pd, int start, int end)
2560 {
2561    _efl_ui_textbox_select_region_set(obj, pd, start, end);
2562    efl_ui_textbox_selection_copy(obj);
2563 
2564    return EINA_TRUE;
2565 }
2566 
2567 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_editable_text_delete(Eo * obj,Efl_Ui_Textbox_Data * pd,int start_offset,int end_offset)2568 _efl_ui_textbox_efl_access_editable_text_delete(Eo *obj, Efl_Ui_Textbox_Data *pd, int start_offset, int end_offset)
2569 {
2570    Evas_Textblock_Cursor *cur1, *cur2;
2571    Eo *text_obj = pd->text_obj;
2572 
2573    if (!text_obj) return EINA_FALSE;
2574 
2575    cur1 = evas_object_textblock_cursor_new(text_obj);
2576    if (!cur1) return EINA_FALSE;
2577 
2578    cur2 = evas_object_textblock_cursor_new(text_obj);
2579    if (!cur2)
2580      {
2581         evas_textblock_cursor_free(cur1);
2582         return EINA_FALSE;
2583      }
2584 
2585    evas_textblock_cursor_pos_set(cur1, start_offset);
2586    evas_textblock_cursor_pos_set(cur2, end_offset);
2587 
2588    evas_textblock_cursor_range_delete(cur1, cur2);
2589 
2590    evas_textblock_cursor_free(cur1);
2591    evas_textblock_cursor_free(cur2);
2592 
2593    _efl_ui_textbox_calc_force(obj, pd);
2594 
2595    return EINA_TRUE;
2596 }
2597 
2598 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_editable_text_paste(Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED,int position)2599 _efl_ui_textbox_efl_access_editable_text_paste(Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED, int position)
2600 {
2601    Efl_Text_Cursor_Object *cur_obj = efl_text_interactive_main_cursor_get(obj);
2602    efl_text_cursor_object_position_set(cur_obj, position);
2603    efl_ui_textbox_selection_paste(obj);
2604    return EINA_TRUE;
2605 }
2606 
2607 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_access_editable_text_cut(Eo * obj,Efl_Ui_Textbox_Data * pd EINA_UNUSED,int start,int end)2608 _efl_ui_textbox_efl_access_editable_text_cut(Eo *obj, Efl_Ui_Textbox_Data *pd EINA_UNUSED, int start, int end)
2609 {
2610    _efl_ui_textbox_select_region_set(obj, pd, start, end);
2611    efl_ui_textbox_selection_cut(obj);
2612    return EINA_TRUE;
2613 }
2614 
2615 EOLIAN static Efl_Access_State_Set
_efl_ui_textbox_efl_access_object_state_set_get(const Eo * obj,Efl_Ui_Textbox_Data * _pd EINA_UNUSED)2616 _efl_ui_textbox_efl_access_object_state_set_get(const Eo *obj, Efl_Ui_Textbox_Data *_pd EINA_UNUSED)
2617 {
2618    Efl_Access_State_Set ret;
2619    ret = efl_access_object_state_set_get(efl_super(obj, EFL_UI_TEXTBOX_CLASS));
2620 
2621    if (efl_text_interactive_editable_get(obj))
2622      STATE_TYPE_SET(ret, EFL_ACCESS_STATE_TYPE_EDITABLE);
2623 
2624    return ret;
2625 }
2626 
2627 EOLIAN static const char*
_efl_ui_textbox_efl_access_object_i18n_name_get(const Eo * obj,Efl_Ui_Textbox_Data * pd)2628 _efl_ui_textbox_efl_access_object_i18n_name_get(const Eo *obj, Efl_Ui_Textbox_Data *pd)
2629 {
2630    const char *name;
2631    name = efl_access_object_i18n_name_get(efl_super(obj, EFL_UI_TEXTBOX_CLASS));
2632    if (name && strncmp("", name, 1)) return name;
2633    const char *ret = edje_object_part_text_get(pd->entry_edje, "efl.guide");
2634    return ret;
2635 }
2636 
2637 static void
_edje_signal_emit(Efl_Ui_Textbox_Data * sd,const char * sig,const char * src)2638 _edje_signal_emit(Efl_Ui_Textbox_Data *sd, const char *sig, const char *src)
2639 {
2640    efl_layout_signal_emit(sd->entry_edje, sig, src);
2641    efl_layout_signal_emit(sd->cursor, sig, src);
2642    efl_layout_signal_emit(sd->cursor_bidi, sig, src);
2643 }
2644 
2645 static inline Eo *
_decoration_create(Eo * obj,Efl_Ui_Textbox_Data * sd,const char * group_name,Eina_Bool above)2646 _decoration_create(Eo *obj, Efl_Ui_Textbox_Data *sd,
2647       const char *group_name, Eina_Bool above)
2648 {
2649    Eo *ret = NULL;
2650    Eo *clip = efl_ui_internal_text_scroller_viewport_clip_get(sd->scroller);
2651 
2652    ret = efl_add(EFL_CANVAS_LAYOUT_CLASS, obj);
2653    elm_widget_element_update(obj, ret, group_name);
2654    efl_canvas_group_member_add(sd->entry_edje, ret);
2655    if (above)
2656      {
2657         efl_gfx_stack_above(ret, sd->text_table);
2658      }
2659    else
2660      {
2661         efl_gfx_stack_below(ret, NULL);
2662      }
2663    efl_canvas_object_clipper_set(ret, clip);
2664    efl_canvas_object_pass_events_set(ret, EINA_TRUE);
2665    return ret;
2666 }
2667 
2668 static void
_create_text_cursors(Eo * obj,Efl_Ui_Textbox_Data * sd)2669 _create_text_cursors(Eo *obj, Efl_Ui_Textbox_Data *sd)
2670 {
2671    sd->cursor = _decoration_create(obj, sd, PART_NAME_CURSOR, EINA_TRUE);
2672    sd->cursor_bidi = _decoration_create(obj, sd, PART_NAME_CURSOR, EINA_TRUE);
2673 
2674    if (!efl_text_interactive_editable_get(obj))
2675      {
2676         efl_gfx_entity_visible_set(sd->cursor, EINA_FALSE);
2677         efl_gfx_entity_visible_set(sd->cursor_bidi, EINA_FALSE);
2678      }
2679 }
2680 
2681 static Eina_Position2D
_decoration_calc_offset(Efl_Ui_Textbox_Data * sd)2682 _decoration_calc_offset(Efl_Ui_Textbox_Data *sd)
2683 {
2684    Eina_Position2D ret;
2685    Eina_Position2D text;
2686    Eina_Position2D ed = EINA_POSITION2D(0,0), scr = EINA_POSITION2D(0, 0);
2687 
2688    text = efl_gfx_entity_position_get(sd->text_obj);
2689 
2690    ret.x = ed.x + scr.x + text.x;
2691    ret.y = ed.y + scr.y + text.y;
2692 
2693    return ret;
2694 }
2695 
2696 static void
_update_text_cursors(Eo * obj)2697 _update_text_cursors(Eo *obj)
2698 {
2699    Evas_Coord xx, yy, ww, hh;
2700    Eina_Position2D off;
2701    Eo *text_obj;
2702    Eina_Rect rc_tmp1;
2703    Eina_Rect rc_tmp2;
2704    Eina_Bool bidi_cursor;
2705 
2706    EFL_UI_TEXT_DATA_GET(obj, sd);
2707    if (!sd->deferred_decoration_cursor) return;
2708    sd->deferred_decoration_cursor = EINA_FALSE;
2709 
2710    text_obj = sd->text_obj;
2711 
2712    xx = yy = ww = hh = -1;
2713    off =_decoration_calc_offset(sd);
2714    rc_tmp1 = efl_text_cursor_object_cursor_geometry_get(efl_text_interactive_main_cursor_get(text_obj), EFL_TEXT_CURSOR_TYPE_BEFORE);
2715    bidi_cursor = efl_text_cursor_object_lower_cursor_geometry_get(efl_text_interactive_main_cursor_get(text_obj), &rc_tmp2);
2716    xx = rc_tmp1.x;
2717    yy = rc_tmp1.y;
2718    ww = rc_tmp1.w;
2719    hh = rc_tmp1.h;
2720 
2721    if (ww < 1) ww = 1;
2722    if (hh < 1) hh = 1;
2723    if (sd->cursor)
2724      {
2725         efl_gfx_entity_geometry_set(sd->cursor, EINA_RECT(off.x + xx, off.y + yy, ww, hh));
2726      }
2727    if (sd->cursor_bidi)
2728      {
2729         if (bidi_cursor)
2730           {
2731              efl_gfx_entity_geometry_set(sd->cursor_bidi,
2732                                       EINA_RECT(off.x + rc_tmp2.x, off.y + rc_tmp2.y + (hh / 2),
2733                                       ww, hh / 2));
2734              efl_gfx_entity_size_set(sd->cursor, EINA_SIZE2D(ww, hh / 2));
2735              efl_gfx_entity_visible_set(sd->cursor_bidi, EINA_TRUE);
2736           }
2737         else
2738           {
2739              efl_gfx_entity_visible_set(sd->cursor_bidi, EINA_FALSE);
2740           }
2741      }
2742    if (sd->cursor_update)
2743      {
2744         sd->cursor_update = EINA_FALSE;
2745         _cursor_geometry_recalc(obj);
2746      }
2747 }
2748 
2749 static void
_clear_text_selection(Efl_Ui_Textbox_Data * sd)2750 _clear_text_selection(Efl_Ui_Textbox_Data *sd)
2751 {
2752    Efl_Ui_Text_Rectangle *r;
2753 
2754    EINA_LIST_FREE(sd->sel, r)
2755      {
2756         free(r);
2757      }
2758 
2759 }
2760 
2761 static void
_update_text_selection(Eo * obj,Eo * text_obj)2762 _update_text_selection(Eo *obj, Eo *text_obj)
2763 {
2764    Eina_Position2D off;
2765    Efl_Text_Cursor_Object *sel_start, *sel_end;
2766 
2767    Eina_List *l;
2768    Eina_Iterator *range;
2769    Efl_Ui_Text_Rectangle *rect;
2770    Eina_Rectangle *r;
2771 
2772    EFL_UI_TEXT_DATA_GET(obj, sd);
2773 
2774    if (!sd->deferred_decoration_selection) return;
2775    sd->deferred_decoration_selection = EINA_FALSE;
2776 
2777    off = _decoration_calc_offset(sd);
2778 
2779    efl_text_interactive_selection_cursors_get(text_obj, &sel_start, &sel_end);
2780 
2781    range = efl_text_cursor_object_range_geometry_get(sel_start, sel_end);
2782 
2783    l = sd->sel;
2784    EINA_ITERATOR_FOREACH(range, r)
2785      {
2786         /* Create if there isn't a rectangle to populate. */
2787         if (!l)
2788           {
2789              rect = calloc(1, sizeof(Efl_Ui_Text_Rectangle));
2790              sd->sel = eina_list_append(sd->sel, rect);
2791 
2792              rect->obj_bg = _decoration_create(obj, sd, PART_NAME_SELECTION, EINA_FALSE);
2793              efl_gfx_entity_visible_set(rect->obj_bg, EINA_TRUE);
2794           }
2795         else
2796           {
2797              rect = eina_list_data_get(l);
2798              l = l->next;
2799           }
2800 
2801         if (rect->obj_bg)
2802           {
2803              efl_gfx_entity_geometry_set(rect->obj_bg, EINA_RECT(off.x + r->x, off.y + r->y,
2804                                       r->w, r->h));
2805           }
2806      }
2807    eina_iterator_free(range);
2808 
2809    /* delete redundant rectection rects */
2810    while (l)
2811      {
2812         Eina_List *temp = l->next;
2813         rect = eina_list_data_get(l);
2814         if (rect)
2815           {
2816              if (rect->obj_bg) efl_del(rect->obj_bg);
2817              free(rect);
2818           }
2819         sd->sel = eina_list_remove_list(sd->sel, l);
2820         l = temp;
2821      }
2822 
2823    /* Update selection handlers */
2824    _update_selection_handler(obj);
2825 }
2826 
2827 static void
_anchors_free(Efl_Ui_Textbox_Data * sd)2828 _anchors_free(Efl_Ui_Textbox_Data *sd)
2829 {
2830    Anchor *an;
2831 
2832    EINA_LIST_FREE(sd->anchors, an)
2833      {
2834         Efl_Ui_Text_Rectangle *rect;
2835         EINA_LIST_FREE(an->rects, rect)
2836           {
2837              free(rect);
2838           }
2839         free(an->name);
2840         free(an);
2841      }
2842 }
2843 
2844 static char *
_anchor_format_parse(const char * item)2845 _anchor_format_parse(const char *item)
2846 {
2847    const char *start, *end;
2848    char *tmp;
2849    size_t len;
2850 
2851    start = strchr(item, '=');
2852    if (!start) return NULL;
2853 
2854    start++; /* Advance after the '=' */
2855    /* If we can find a quote as the first non-space char,
2856     * our new delimiter is a quote, not a space. */
2857    while (*start == ' ')
2858      start++;
2859 
2860    if (*start == '\'')
2861      {
2862         start++;
2863         end = strchr(start, '\'');
2864         while ((end) && (end > start) && (end[-1] == '\\'))
2865           end = strchr(end + 1, '\'');
2866      }
2867    else
2868      {
2869         end = strchr(start, ' ');
2870         while ((end) && (end > start) && (end[-1] == '\\'))
2871           end = strchr(end + 1, ' ');
2872      }
2873 
2874    /* Null terminate before the spaces */
2875    if (end) len = end - start;
2876    else len = strlen(start);
2877 
2878    tmp = malloc(len + 1);
2879    strncpy(tmp, start, len);
2880    tmp[len] = '\0';
2881 
2882    return tmp;
2883 }
2884 
2885 static Anchor *
_anchor_get(Eo * obj,Efl_Ui_Textbox_Data * sd,Efl_Text_Attribute_Handle * an)2886 _anchor_get(Eo *obj, Efl_Ui_Textbox_Data *sd, Efl_Text_Attribute_Handle *an)
2887 {
2888    Anchor *anc;
2889    Eina_List *i;
2890    const char *str;
2891 
2892    str = efl_text_formatter_attribute_get(an);
2893 
2894    EINA_LIST_FOREACH(sd->anchors, i, anc)
2895      {
2896         if (anc->annotation == an) break;
2897      }
2898 
2899    if (!anc && (efl_text_formatter_attribute_is_item(an) || !strncmp(str, "a ", 2)))
2900      {
2901         const char *p;
2902 
2903         anc = calloc(1, sizeof(Anchor));
2904         if (anc)
2905           {
2906              anc->obj = obj;
2907              anc->annotation = an;
2908              anc->item = efl_text_formatter_attribute_is_item(an);
2909              p = strstr(str, "href=");
2910              if (p)
2911                {
2912                   anc->name = _anchor_format_parse(p);
2913                }
2914              sd->anchors = eina_list_append(sd->anchors, anc);
2915           }
2916      }
2917 
2918    return anc;
2919 }
2920 
2921 /**
2922  * @internal
2923  * Recreates and updates the anchors in the text.
2924  */
2925 static void
_anchors_update(Eo * obj,Efl_Ui_Textbox_Data * sd)2926 _anchors_update(Eo *obj, Efl_Ui_Textbox_Data *sd)
2927 {
2928    Evas_Object *smart, *clip;
2929    Eina_Iterator *it;
2930    Eina_Position2D off;
2931    Efl_Text_Cursor_Object *start, *end;
2932    Efl_Text_Attribute_Handle *an;
2933    Eina_List *i, *ii;
2934    Anchor *anc;
2935 
2936    if (!sd->deferred_decoration_anchor) return;
2937    sd->deferred_decoration_anchor = EINA_FALSE;
2938 
2939    sd->gen++;
2940 
2941    start = efl_canvas_textblock_cursor_create(sd->text_obj);
2942    end = efl_canvas_textblock_cursor_create(sd->text_obj);
2943 
2944    /* Retrieve all annotations in the text. */
2945    efl_text_cursor_object_move(start, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
2946    efl_text_cursor_object_move(end, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
2947 
2948    it = efl_text_formatter_range_attributes_get(start, end);
2949    efl_del(start);
2950    efl_del(end);
2951 
2952    smart = efl_canvas_object_render_parent_get(obj);
2953    clip = efl_canvas_object_clipper_get(sd->text_obj);
2954    off = _decoration_calc_offset(sd);
2955 
2956    EINA_ITERATOR_FOREACH(it, an)
2957      {
2958         anc = _anchor_get(obj, sd, an);
2959 
2960         if (anc)
2961           {
2962              anc->gen = sd->gen;
2963 
2964              if (anc->item)
2965                {
2966                   Efl_Ui_Text_Rectangle *rect;
2967                   Evas_Coord cx, cy, cw, ch;
2968 
2969                   // Item anchor (one rectangle)
2970                   if (!anc->rects)
2971                     {
2972                        Eo *ob;
2973 
2974                        rect = calloc(1, sizeof(Efl_Ui_Text_Rectangle));
2975                        anc->rects = eina_list_append(anc->rects, rect);
2976 
2977                        ob = _item_get(obj, anc->name);
2978 
2979                        if (ob)
2980                          {
2981                             efl_canvas_group_member_add(smart, ob);
2982                             efl_gfx_stack_above(ob, obj);
2983                             efl_canvas_object_clipper_set(ob, clip);
2984                             efl_canvas_object_pass_events_set(ob, EINA_TRUE);
2985                             rect->obj = ob;
2986                          }
2987                     }
2988 
2989                   rect = eina_list_data_get(anc->rects);
2990                   efl_text_formatter_item_geometry_get(anc->annotation, &cx, &cy, &cw, &ch);
2991                   efl_gfx_entity_size_set(rect->obj, EINA_SIZE2D(cw, ch));
2992                   efl_gfx_entity_position_set(rect->obj,
2993                         EINA_POSITION2D(off.x + cx, off.y + cy));
2994                }
2995              else
2996                {
2997                   // Link anchor (multiple rectangles) i.e. "a href=..."
2998                   Eina_Iterator *range;
2999                   Eina_List *l;
3000                   Eina_Rectangle *r;
3001                   size_t count;
3002                   start = efl_ui_textbox_cursor_create(obj);
3003                   end = efl_ui_textbox_cursor_create(obj);
3004                   efl_text_formatter_attribute_cursors_get(anc->annotation, start, end);
3005 
3006                   range = efl_text_cursor_object_range_geometry_get(start, end);
3007                   count = eina_list_count(eina_iterator_container_get(range));
3008 
3009                   // Add additional rectangles if needed
3010                   while (count > eina_list_count(anc->rects))
3011                     {
3012                        Efl_Ui_Text_Rectangle *rect;
3013                        Eo *ob;
3014                        rect = calloc(1, sizeof(Efl_Ui_Text_Rectangle));
3015                        anc->rects = eina_list_append(anc->rects, rect);
3016 
3017                        ob = _decoration_create(obj, sd, PART_NAME_ANCHOR, EINA_TRUE);
3018                        rect->obj_fg = ob;
3019                        // hit-rectangle
3020                        ob = efl_add(EFL_CANVAS_RECTANGLE_CLASS, obj);
3021                        efl_gfx_color_set(ob, 0, 0, 0, 0);
3022                        efl_canvas_group_member_add(smart, ob);
3023                        efl_gfx_stack_above(ob, obj);
3024                        efl_canvas_object_clipper_set(ob, clip);
3025                        efl_canvas_object_repeat_events_set(ob, EINA_TRUE);
3026                        rect->obj = ob;
3027                        //FIXME: add event handlers
3028                     }
3029 
3030                   // Remove extra rectangles if needed
3031                   while (count < eina_list_count(anc->rects))
3032                     {
3033                        Efl_Ui_Text_Rectangle *rect;
3034 
3035                        rect = eina_list_data_get(anc->rects);
3036                        if (rect->obj) efl_del(rect->obj);
3037                        if (rect->obj_fg) efl_del(rect->obj_fg);
3038                        if (rect->obj_bg) efl_del(rect->obj_bg);
3039                        free(rect);
3040                        anc->rects = eina_list_remove_list(anc->rects, anc->rects);
3041                     }
3042 
3043                   l = anc->rects;
3044                   EINA_ITERATOR_FOREACH(range, r)
3045                     {
3046                        Efl_Ui_Text_Rectangle *rect;
3047 
3048                        rect = eina_list_data_get(l);
3049                        if (rect->obj_bg)
3050                          {
3051                             efl_gfx_entity_geometry_set(rect->obj_bg,
3052                                                      EINA_RECT(off.x + r->x, off.y + r->y,
3053                                                      r->w, r->h));
3054                             efl_gfx_entity_visible_set(rect->obj_bg, EINA_TRUE);
3055                          }
3056                        if (rect->obj_fg)
3057                          {
3058                             efl_gfx_entity_geometry_set(rect->obj_fg,
3059                                                      EINA_RECT(off.x + r->x, off.y + r->y,
3060                                                      r->w, r->h));
3061                             efl_gfx_entity_visible_set(rect->obj_fg, EINA_TRUE);
3062                          }
3063                        if (rect->obj)
3064                          {
3065                             efl_gfx_entity_geometry_set(rect->obj,
3066                                                      EINA_RECT(off.x + r->x, off.y + r->y,
3067                                                      r->w, r->h));
3068                             efl_gfx_entity_visible_set(rect->obj, EINA_TRUE);
3069                          }
3070 
3071                        l = eina_list_next(l);
3072                     }
3073                   eina_iterator_free(range);
3074                }
3075           }
3076      }
3077    eina_iterator_free(it);
3078 
3079    // Remove anchors that weren't matched to any annotation
3080    EINA_LIST_FOREACH_SAFE(sd->anchors, i, ii, anc)
3081      {
3082         if (anc->gen != sd->gen)
3083           {
3084              Efl_Ui_Text_Rectangle *rect;
3085              sd->anchors = eina_list_remove_list(sd->anchors, i);
3086              EINA_LIST_FREE(anc->rects, rect)
3087                {
3088                   efl_del(rect->obj);
3089                   efl_del(rect->obj_bg);
3090                   efl_del(rect->obj_fg);
3091                   free(rect);
3092                }
3093              free(anc->name);
3094              free(anc);
3095           }
3096      }
3097 }
3098 
3099 static void
_update_decorations(Eo * obj)3100 _update_decorations(Eo *obj)
3101 {
3102    EFL_UI_TEXT_DATA_GET(obj, sd);
3103    Eo *text_obj = sd->text_obj;
3104 
3105    efl_event_freeze(sd->text_obj);
3106    _update_text_cursors(obj);
3107    _update_text_selection(obj, text_obj);
3108    _anchors_update(obj, sd);
3109    efl_event_thaw(sd->text_obj);
3110 }
3111 
3112 static Eina_Value
_deferred_decoration_job(Eo * o,void * data EINA_UNUSED,const Eina_Value value EINA_UNUSED)3113 _deferred_decoration_job(Eo *o, void *data EINA_UNUSED, const Eina_Value value EINA_UNUSED)
3114 {
3115    EFL_UI_TEXT_DATA_GET(o, sd);
3116    _update_decorations(o);
3117    sd->deferred_decoration_job = NULL;
3118 
3119    return EINA_VALUE_EMPTY;
3120 }
3121 
3122 static void
_decoration_defer(Eo * obj)3123 _decoration_defer(Eo *obj)
3124 {
3125    EFL_UI_TEXT_DATA_GET(obj, sd);
3126    if (sd->deferred_decoration_job) return;
3127 
3128    Eina_Future *f = efl_loop_job(efl_main_loop_get());
3129    sd->deferred_decoration_job = efl_future_then(obj, f, _deferred_decoration_job);
3130 }
3131 
3132 static void
_selection_defer(Eo * obj,Efl_Ui_Textbox_Data * sd)3133 _selection_defer(Eo *obj, Efl_Ui_Textbox_Data *sd)
3134 {
3135    sd->deferred_decoration_selection = EINA_TRUE;
3136    _decoration_defer(obj);
3137 }
3138 
3139 static void
_decoration_defer_all(Eo * obj)3140 _decoration_defer_all(Eo *obj)
3141 {
3142    EFL_UI_TEXT_DATA_GET(obj, sd);
3143    sd->deferred_decoration_anchor = EINA_TRUE;
3144    sd->deferred_decoration_cursor = EINA_TRUE;
3145    sd->deferred_decoration_selection = EINA_TRUE;
3146    _decoration_defer(obj);
3147 }
3148 
3149 static void
_efl_ui_textbox_changed_cb(void * data,const Efl_Event * event)3150 _efl_ui_textbox_changed_cb(void *data, const Efl_Event *event)
3151 {
3152    if (efl_invalidated_get(event->object)) return;
3153    EFL_UI_TEXT_DATA_GET(data, sd);
3154    sd->text_changed = EINA_TRUE;
3155    sd->cursor_update = EINA_TRUE;
3156    _update_guide_text(data, sd);
3157    efl_event_callback_call(data, EFL_UI_TEXTBOX_EVENT_CHANGED, NULL);
3158    efl_canvas_group_change(data);
3159    _decoration_defer(data);
3160 }
3161 
3162 static void
_efl_ui_textbox_changed_user_cb(void * data,const Efl_Event * event)3163 _efl_ui_textbox_changed_user_cb(void *data, const Efl_Event *event)
3164 {
3165    Eo *obj = data;
3166 
3167    if (efl_invalidated_get(event->object)) return;
3168    EFL_UI_TEXT_DATA_GET(obj, sd);
3169    sd->text_changed = EINA_TRUE;
3170    _update_guide_text(data, sd);
3171    efl_canvas_group_change(obj);
3172    _decoration_defer_all(obj);
3173 }
3174 
3175 static void
_efl_ui_textbox_cursor_changed_cb(void * data,const Efl_Event * event EINA_UNUSED)3176 _efl_ui_textbox_cursor_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
3177 {
3178    if (efl_invalidated_get(event->object)) return;
3179    EFL_UI_TEXT_DATA_GET(data, sd);
3180    sd->cursor_update = EINA_TRUE;
3181    sd->deferred_decoration_cursor = EINA_TRUE;
3182    _decoration_defer(data);
3183 }
3184 
3185 static void
_scroller_size_changed_cb(void * data,const Efl_Event * event EINA_UNUSED)3186 _scroller_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
3187 {
3188    if (efl_invalidated_get(event->object)) return;
3189 
3190    _decoration_defer_all(data);
3191 }
3192 
3193 static void
_text_size_changed_cb(void * data,const Efl_Event * event EINA_UNUSED)3194 _text_size_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
3195 {
3196    if (efl_invalidated_get(event->object)) return;
3197 
3198    _decoration_defer_all(data);
3199 }
3200 
3201 static void
_text_position_changed_cb(void * data,const Efl_Event * event EINA_UNUSED)3202 _text_position_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
3203 {
3204    if (efl_invalidated_get(event->object)) return;
3205 
3206    _decoration_defer_all(data);
3207 }
3208 
3209 static void
_efl_ui_textbox_selection_start_clear_cb(void * data,const Efl_Event * event EINA_UNUSED)3210 _efl_ui_textbox_selection_start_clear_cb(void *data, const Efl_Event *event EINA_UNUSED)
3211 {
3212    if (efl_invalidated_get(event->object)) return;
3213    Eo *obj = data;
3214    EFL_UI_TEXT_DATA_GET(obj, sd);
3215 
3216    if (efl_text_interactive_have_selection_get(data))
3217      {
3218         if (efl_invalidated_get(event->object)) return;
3219         _edje_signal_emit(sd, "selection,start", "efl.text");
3220         _selection_defer(obj, sd);
3221      }
3222    else
3223      {
3224         Eo *obj = data;
3225         _edje_signal_emit(sd, "selection,cleared", "efl.text");
3226         _selection_defer(obj, sd);
3227      }
3228 }
3229 
3230 static void
_efl_ui_textbox_selection_changed_cb(void * data,const Efl_Event * event EINA_UNUSED)3231 _efl_ui_textbox_selection_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
3232 {
3233    if (efl_invalidated_get(event->object)) return;
3234    Eo *obj = data;
3235    EFL_UI_TEXT_DATA_GET(obj, sd);
3236    _edje_signal_emit(sd, "selection,changed", "efl.text");
3237    _selection_store(EFL_UI_CNP_BUFFER_SELECTION, obj);
3238    _selection_defer(obj, sd);
3239 }
3240 
3241 static void
_efl_ui_textbox_move_cb(void * data,const Efl_Event * event EINA_UNUSED)3242 _efl_ui_textbox_move_cb(void *data, const Efl_Event *event EINA_UNUSED)
3243 {
3244    _decoration_defer_all(data);
3245 }
3246 
3247 static void
_efl_ui_textbox_item_factory_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd,Efl_Canvas_Textblock_Factory * item_factory)3248 _efl_ui_textbox_item_factory_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd,
3249       Efl_Canvas_Textblock_Factory *item_factory)
3250 {
3251    if (pd->item_factory) efl_unref(pd->item_factory);
3252    pd->item_factory = efl_ref(item_factory);
3253 }
3254 
3255 static Eo *
_efl_ui_textbox_item_factory_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd)3256 _efl_ui_textbox_item_factory_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd)
3257 {
3258    return pd->item_factory;
3259 }
3260 
3261 /*Efl.Ui.Scrollable*/
3262 EOLIAN static Eina_Size2D
_efl_ui_textbox_efl_ui_scrollable_content_size_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3263 _efl_ui_textbox_efl_ui_scrollable_content_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
3264 {
3265    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EINA_SIZE2D(0, 0));
3266    return efl_ui_scrollable_content_size_get(sd->scroller);
3267 }
3268 
3269 EOLIAN static Eina_Rect
_efl_ui_textbox_efl_ui_scrollable_viewport_geometry_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3270 _efl_ui_textbox_efl_ui_scrollable_viewport_geometry_get(const Eo *obj EINA_UNUSED,
3271                                                                        Efl_Ui_Textbox_Data *sd)
3272 {
3273    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EINA_RECT_EMPTY());
3274    return efl_ui_scrollable_viewport_geometry_get(sd->scroller);
3275 }
3276 
3277 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_match_content_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool w,Eina_Bool h)3278 _efl_ui_textbox_efl_ui_scrollable_match_content_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool w, Eina_Bool h)
3279 {
3280    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3281    return efl_ui_scrollable_match_content_set(sd->scroller, !!w, !!h);
3282 }
3283 
3284 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_step_size_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Position2D step)3285 _efl_ui_textbox_efl_ui_scrollable_step_size_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Position2D step)
3286 {
3287    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3288    efl_ui_scrollable_step_size_set(sd->scroller, step);
3289 }
3290 
3291 EOLIAN static Eina_Position2D
_efl_ui_textbox_efl_ui_scrollable_step_size_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3292 _efl_ui_textbox_efl_ui_scrollable_step_size_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
3293 {
3294    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EINA_POSITION2D(0, 0));
3295    return efl_ui_scrollable_step_size_get(sd->scroller);
3296 }
3297 
3298 EOLIAN static Eina_Position2D
_efl_ui_textbox_efl_ui_scrollable_content_pos_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3299 _efl_ui_textbox_efl_ui_scrollable_content_pos_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
3300 {
3301    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EINA_POSITION2D(0, 0));
3302    return efl_ui_scrollable_content_pos_get(sd->scroller);
3303 }
3304 
3305 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_content_pos_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Position2D pos)3306 _efl_ui_textbox_efl_ui_scrollable_content_pos_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Position2D pos)
3307 {
3308    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3309    efl_ui_scrollable_content_pos_set(sd->scroller, pos);
3310 }
3311 
3312 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_ui_scrollable_scroll_hold_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3313 _efl_ui_textbox_efl_ui_scrollable_scroll_hold_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
3314 {
3315    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EINA_FALSE);
3316    return efl_ui_scrollable_scroll_hold_get(sd->scroller);
3317 }
3318 
3319 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_scroll_hold_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool hold)3320 _efl_ui_textbox_efl_ui_scrollable_scroll_hold_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool hold)
3321 {
3322    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3323    efl_ui_scrollable_scroll_hold_set(sd->scroller, !!hold);
3324 }
3325 
3326 EOLIAN static Eina_Bool
_efl_ui_textbox_efl_ui_scrollable_scroll_freeze_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3327 _efl_ui_textbox_efl_ui_scrollable_scroll_freeze_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
3328 {
3329    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EINA_FALSE);
3330    return efl_ui_scrollable_scroll_freeze_get(sd->scroller);
3331 }
3332 
3333 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_scroll_freeze_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool freeze)3334 _efl_ui_textbox_efl_ui_scrollable_scroll_freeze_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool freeze)
3335 {
3336    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3337    efl_ui_scrollable_scroll_freeze_set(sd->scroller, !!freeze);
3338 }
3339 
3340 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_bounce_enabled_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool horiz,Eina_Bool vert)3341 _efl_ui_textbox_efl_ui_scrollable_bounce_enabled_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool horiz, Eina_Bool vert)
3342 {
3343    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3344    efl_ui_scrollable_bounce_enabled_set(sd->scroller, !!horiz, !!vert);
3345 }
3346 
3347 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_bounce_enabled_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool * horiz,Eina_Bool * vert)3348 _efl_ui_textbox_efl_ui_scrollable_bounce_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool *horiz, Eina_Bool *vert)
3349 {
3350    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3351    efl_ui_scrollable_bounce_enabled_get(sd->scroller, horiz, vert);
3352 }
3353 
3354 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_scroll(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Rect rect,Eina_Bool animation)3355 _efl_ui_textbox_efl_ui_scrollable_scroll(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Rect rect, Eina_Bool animation)
3356 {
3357    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3358    efl_ui_scrollable_scroll(sd->scroller, rect, animation);
3359 }
3360 
3361 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_gravity_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,double * x,double * y)3362 _efl_ui_textbox_efl_ui_scrollable_gravity_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, double *x, double *y)
3363 {
3364    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3365    efl_ui_scrollable_gravity_get(sd->scroller, x, y);
3366 }
3367 
3368 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_gravity_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,double x,double y)3369 _efl_ui_textbox_efl_ui_scrollable_gravity_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, double x, double y)
3370 {
3371    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3372    efl_ui_scrollable_gravity_set(sd->scroller, x, y);
3373 }
3374 
3375 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_movement_block_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Efl_Ui_Layout_Orientation block)3376 _efl_ui_textbox_efl_ui_scrollable_movement_block_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Efl_Ui_Layout_Orientation block)
3377 {
3378    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3379    efl_ui_scrollable_movement_block_set(sd->scroller, block);
3380 }
3381 
3382 EOLIAN static Efl_Ui_Layout_Orientation
_efl_ui_textbox_efl_ui_scrollable_movement_block_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd)3383 _efl_ui_textbox_efl_ui_scrollable_movement_block_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd)
3384 {
3385    EINA_SAFETY_ON_NULL_RETURN_VAL(sd->scroller, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
3386    return efl_ui_scrollable_movement_block_get(sd->scroller);
3387 }
3388 
3389 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_looping_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool loop_h,Eina_Bool loop_v)3390 _efl_ui_textbox_efl_ui_scrollable_looping_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool loop_h, Eina_Bool loop_v)
3391 {
3392    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3393    efl_ui_scrollable_looping_set(sd->scroller, !!loop_h, !!loop_v);
3394 }
3395 
3396 EOLIAN static void
_efl_ui_textbox_efl_ui_scrollable_looping_get(const Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * sd,Eina_Bool * loop_h,Eina_Bool * loop_v)3397 _efl_ui_textbox_efl_ui_scrollable_looping_get(const Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *sd, Eina_Bool *loop_h, Eina_Bool *loop_v)
3398 {
3399    EINA_SAFETY_ON_NULL_RETURN(sd->scroller);
3400    efl_ui_scrollable_looping_get(sd->scroller, loop_h, loop_v);
3401 }
3402 
3403 /* Efl.Part begin */
3404 
3405 static Eina_Bool
_efl_ui_textbox_text_set(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd,const char * part,const char * text)3406 _efl_ui_textbox_text_set(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd,
3407       const char *part, const char *text)
3408 {
3409    if (!part) return EINA_FALSE;
3410 
3411    if (!strcmp("efl.text_guide", part))
3412      {
3413         efl_text_set(pd->text_guide_obj, text);
3414         return EINA_TRUE;
3415      }
3416    else if (!strcmp("efl.text", part))
3417      {
3418         efl_text_set(pd->text_obj, text);
3419         return EINA_TRUE;
3420      }
3421 
3422    return EINA_FALSE;
3423 }
3424 
3425 static const char *
_efl_ui_textbox_text_get(Eo * obj EINA_UNUSED,Efl_Ui_Textbox_Data * pd,const char * part)3426 _efl_ui_textbox_text_get(Eo *obj EINA_UNUSED, Efl_Ui_Textbox_Data *pd,
3427       const char *part)
3428 {
3429    if (!part) return NULL;
3430 
3431    if (!strcmp("efl.text_guide", part))
3432      {
3433         return efl_text_get(pd->text_guide_obj);
3434      }
3435    else if (!strcmp("efl.text", part))
3436      {
3437         return efl_text_get(pd->text_obj);
3438      }
3439 
3440    return NULL;
3441 }
3442 
3443 static Eina_Bool
_part_is_efl_ui_textbox_part(const Eo * obj EINA_UNUSED,const char * part)3444 _part_is_efl_ui_textbox_part(const Eo *obj EINA_UNUSED, const char *part)
3445 {
3446    if (eina_streq(part, "efl.text_guide") || eina_streq(part, "efl.text"))
3447      return EINA_TRUE;
3448 
3449    return EINA_FALSE;
3450 }
3451 
3452 /* Standard widget overrides */
3453 
ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_textbox,Efl_Ui_Textbox_Data)3454 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_textbox, Efl_Ui_Textbox_Data)
3455 
3456 ELM_PART_OVERRIDE_PARTIAL(efl_ui_textbox, EFL_UI_TEXTBOX, Efl_Ui_Textbox_Data, _part_is_efl_ui_textbox_part)
3457 ELM_PART_OVERRIDE_TEXT_SET(efl_ui_textbox, EFL_UI_TEXTBOX, Efl_Ui_Textbox_Data)
3458 ELM_PART_OVERRIDE_TEXT_GET(efl_ui_textbox, EFL_UI_TEXTBOX, Efl_Ui_Textbox_Data)
3459 
3460 #include "efl_ui_textbox_part.eo.c"
3461 
3462 /* Efl.Part end */
3463 
3464 /* Internal EO APIs and hidden overrides */
3465 
3466 //EFL_UI_LAYOUT_CONTENT_ALIASES_IMPLEMENT(MY_CLASS_PFX)
3467 
3468 #include "efl_ui_textbox.eo.c"
3469 
3470 EOLIAN static Eo *
3471 _efl_ui_textbox_async_efl_object_constructor(Eo *obj, void *_pd EINA_UNUSED)
3472 {
3473    EFL_UI_TEXT_DATA_GET(obj, sd);
3474 
3475    sd->async.enabled = EINA_TRUE;
3476 
3477    // FIXME: should we have to keep this efl_ui_text_xxx classes?
3478    // Then, going to make new theme for these classes? ex) efl/text_async?
3479    if (!elm_widget_theme_klass_get(obj))
3480      elm_widget_theme_klass_set(obj, "text");
3481    obj = efl_constructor(efl_super(obj, EFL_UI_TEXTBOX_ASYNC_CLASS));
3482 
3483    _update_text_theme(obj, sd);
3484    return obj;
3485 }
3486 
3487 #include "efl_ui_textbox_async.eo.c"
3488