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