1 #include "edje_private.h"
2
3 #ifdef HAVE_ECORE_IMF
4 static Eina_Bool _edje_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
5 static void _edje_entry_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx, void *event_info);
6 static void _edje_entry_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx, void *event_info);
7 static void _edje_entry_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx, void *event);
8 static void _edje_entry_imf_event_selection_set_cb(void *data, Ecore_IMF_Context *ctx, void *event_info);
9 static Eina_Bool _edje_entry_imf_retrieve_selection_cb(void *data, Ecore_IMF_Context *ctx, char **text);
10 #endif
11
12 typedef struct _Entry Entry;
13 typedef struct _Sel Sel;
14 typedef struct _Anchor Anchor;
15 typedef struct _Item_Obj Item_Obj;
16
17 static void _edje_entry_imf_cursor_location_set(Entry *en);
18 static void _edje_entry_imf_cursor_info_set(Entry *en);
19 static void _range_del_emit(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en);
20 static void _text_filter_format_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c, const char *text);
21 static void _free_entry_change_info(void *_info);
22
23 struct _Entry
24 {
25 Edje_Real_Part *rp;
26 Edje *ed;
27 Evas_Coord ox, oy;
28 Evas_Object *cursor_bg;
29 Evas_Object *cursor_fg, *cursor_fg2;
30 /* CHANGE EDJE_ENTRY_NUM_CURSOR_OBJS IF YOU ADD MORE OBJECTS HERE */
31 Evas_Textblock_Cursor *cursor;
32 Evas_Textblock_Cursor *sel_start, *sel_end;
33 Evas_Textblock_Cursor *cursor_user, *cursor_user_extra;
34 Evas_Textblock_Cursor *preedit_start, *preedit_end;
35 Ecore_Timer *pw_timer;
36 Eina_List *sel;
37 Eina_List *anchors;
38 Eina_List *anchorlist;
39 Eina_List *itemlist;
40 Eina_List *seq;
41 Item_Obj *item_objs;
42 char *selection;
43 Edje_Input_Panel_Lang input_panel_lang;
44 Eina_Bool composing : 1;
45 Eina_Bool selecting : 1;
46 Eina_Bool have_selection : 1;
47 Eina_Bool select_allow : 1;
48 Eina_Bool select_mod_start : 1;
49 Eina_Bool select_mod_end : 1;
50 Eina_Bool had_sel : 1;
51 Eina_Bool input_panel_enable : 1;
52 Eina_Bool prediction_allow : 1;
53 Eina_Bool anchors_updated : 1;
54 Eina_Bool have_link_pressed : 1;
55
56 #ifdef HAVE_ECORE_IMF
57 Eina_Bool have_preedit : 1;
58 Eina_Bool commit_cancel : 1; // For skipping useless commit
59 Ecore_IMF_Context *imf_context;
60 #endif
61 };
62
63 struct _Sel
64 {
65 Evas_Textblock_Rectangle rect;
66 Evas_Object *obj_fg, *obj_bg, *obj, *sobj;
67 };
68
69 struct _Anchor
70 {
71 Entry *en;
72 char *name;
73 Evas_Textblock_Cursor *start, *end;
74 Eina_List *sel;
75 Eina_Bool item : 1;
76 };
77
78 struct _Item_Obj
79 {
80 EINA_INLIST;
81 Anchor *an;
82 char *name;
83 Evas_Object *obj;
84 };
85
86 #ifdef HAVE_ECORE_IMF
87 static void
_preedit_clear(Entry * en)88 _preedit_clear(Entry *en)
89 {
90 if (en->preedit_start)
91 {
92 evas_textblock_cursor_free(en->preedit_start);
93 en->preedit_start = NULL;
94 }
95
96 if (en->preedit_end)
97 {
98 evas_textblock_cursor_free(en->preedit_end);
99 en->preedit_end = NULL;
100 }
101
102 en->have_preedit = EINA_FALSE;
103 }
104
105 static void
_preedit_del(Entry * en)106 _preedit_del(Entry *en)
107 {
108 if (!en || !en->have_preedit) return;
109 if (!en->preedit_start || !en->preedit_end) return;
110 if (!evas_textblock_cursor_compare(en->preedit_start, en->preedit_end)) return;
111
112 /* delete the preedit characters */
113 evas_textblock_cursor_range_delete(en->preedit_start, en->preedit_end);
114 }
115
116 static void
_edje_entry_focus_in_cb(void * data,Evas_Object * o,const char * emission,const char * source EINA_UNUSED)117 _edje_entry_focus_in_cb(void *data, Evas_Object *o, const char *emission, const char *source EINA_UNUSED)
118 {
119 Efl_Input_Device *seat;
120 const char *seat_name;
121 Edje_Real_Part *rp;
122 Entry *en;
123 Edje *ed;
124
125 rp = data;
126 if ((!rp) || (rp->type != EDJE_RP_TYPE_TEXT) ||
127 (!rp->typedata.text)) return;
128 if (!rp->typedata.text->entry_data) return;
129
130 ed = _edje_fetch(o);
131 if (!ed) return;
132
133 en = rp->typedata.text->entry_data;
134 if (!en || !en->imf_context) return;
135
136 seat_name = emission + sizeof("focus,part,in,") - 1;
137 seat = _edje_seat_get(ed, seat_name);
138
139 if (efl_canvas_object_seat_focus_check(ed->obj, seat))
140 {
141 ecore_imf_context_focus_in(en->imf_context);
142 _edje_entry_imf_cursor_info_set(en);
143 }
144 }
145
146 static void
_edje_entry_focus_out_cb(void * data,Evas_Object * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)147 _edje_entry_focus_out_cb(void *data, Evas_Object *o EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
148 {
149 Edje_Real_Part *rp;
150 Entry *en;
151
152 rp = data;
153 if ((!rp) || (rp->type != EDJE_RP_TYPE_TEXT) ||
154 (!rp->typedata.text)) return;
155 if (!rp->typedata.text->entry_data) return;
156
157 en = rp->typedata.text->entry_data;
158 if (!en || !en->imf_context) return;
159
160 ecore_imf_context_reset(en->imf_context);
161 ecore_imf_context_focus_out(en->imf_context);
162 }
163
164 #endif
165
166 static void
_edje_focus_in(Edje * ed,Efl_Input_Device * seat)167 _edje_focus_in(Edje *ed, Efl_Input_Device *seat)
168 {
169 #ifdef HAVE_ECORE_IMF
170 Edje_Real_Part *rp;
171 Entry *en;
172 #endif
173
174 _edje_seat_emit(ed, seat, "focus,in", "");
175 #ifdef HAVE_ECORE_IMF
176 rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
177 if (!rp) return;
178 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
179 (!rp->typedata.text)) return;
180 en = rp->typedata.text->entry_data;
181 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
182 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
183 return;
184
185 if (!en->imf_context) return;
186
187 ecore_imf_context_focus_in(en->imf_context);
188 _edje_entry_imf_cursor_info_set(en);
189 #endif
190 }
191
192 static void
_edje_focus_in_cb(void * data,const Efl_Event * event)193 _edje_focus_in_cb(void *data, const Efl_Event *event)
194 {
195 Efl_Input_Focus *ev = event->info;
196
197 _edje_focus_in(data, efl_input_device_get(ev));
198 }
199
200 static void
_edje_focus_out(Edje * ed,Efl_Input_Device * seat)201 _edje_focus_out(Edje *ed, Efl_Input_Device *seat)
202 {
203 #ifdef HAVE_ECORE_IMF
204 Edje_Real_Part *rp;
205 Entry *en;
206 #endif
207
208 _edje_seat_emit(ed, seat, "focus,out", "");
209
210 #ifdef HAVE_ECORE_IMF
211 rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
212 if (!rp) return;
213 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
214 (!rp->typedata.text)) return;
215 en = rp->typedata.text->entry_data;
216 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
217 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
218 return;
219
220 if (!en->imf_context) return;
221
222 ecore_imf_context_reset(en->imf_context);
223 ecore_imf_context_focus_out(en->imf_context);
224 #endif
225 }
226
227 static void
_edje_focus_out_cb(void * data,const Efl_Event * event)228 _edje_focus_out_cb(void *data, const Efl_Event *event)
229 {
230 Efl_Input_Focus *ev = event->info;
231
232 _edje_focus_out(data, efl_input_device_get(ev));
233 }
234
235 static Edje_Entry_Change_Info *
_text_filter_markup_prepend_internal(Edje * ed,Entry * en,Evas_Textblock_Cursor * c,char * text,const char * fmtpre,const char * fmtpost,Eina_Bool clearsel,Eina_Bool changeinfo)236 _text_filter_markup_prepend_internal(Edje *ed, Entry *en, Evas_Textblock_Cursor *c,
237 char *text,
238 const char *fmtpre, const char *fmtpost,
239 Eina_Bool clearsel, Eina_Bool changeinfo)
240 {
241 Edje_Markup_Filter_Callback *cb;
242 Eina_List *l;
243 Eina_Bool have_sel = EINA_FALSE;
244
245 if ((clearsel) && (en->have_selection))
246 {
247 _range_del_emit(ed, en->cursor, en->rp->object, en);
248 have_sel = EINA_TRUE;
249 }
250
251 EINA_LIST_FOREACH(ed->markup_filter_callbacks, l, cb)
252 {
253 if (!strcmp(cb->part, en->rp->part->name))
254 {
255 cb->func(cb->data, ed->obj, cb->part, &text);
256 if (!text) break;
257 }
258 }
259 #ifdef HAVE_ECORE_IMF
260 // For skipping useless commit
261 if (en->have_preedit && (!text || !strcmp(text, "")))
262 en->commit_cancel = EINA_TRUE;
263 else
264 en->commit_cancel = EINA_FALSE;
265 #endif
266 if (text)
267 {
268 Edje_Entry_Change_Info *info = NULL;
269
270 if (changeinfo)
271 {
272 info = calloc(1, sizeof(*info));
273 if (!info)
274 {
275 ERR("Running very low on memory");
276 }
277 else
278 {
279 info->insert = EINA_TRUE;
280 info->change.insert.content = eina_stringshare_add(text);
281 info->change.insert.plain_length =
282 eina_unicode_utf8_get_len(info->change.insert.content);
283 }
284 }
285 if (info)
286 {
287 if (have_sel)
288 {
289 info->merge = EINA_TRUE;
290 }
291 info->change.insert.pos =
292 evas_textblock_cursor_pos_get(en->cursor);
293 }
294 if (fmtpre) _text_filter_format_prepend(ed, en, en->cursor, fmtpre);
295 evas_object_textblock_text_markup_prepend(c, text);
296 free(text);
297 if (fmtpost) _text_filter_format_prepend(ed, en, en->cursor, fmtpost);
298 return info;
299 }
300 return NULL;
301 }
302
303 static Edje_Entry_Change_Info *
_text_filter_text_prepend(Edje * ed,Entry * en,Evas_Textblock_Cursor * c,const char * text,const char * fmtpre,const char * fmtpost,Eina_Bool clearsel,Eina_Bool changeinfo)304 _text_filter_text_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c,
305 const char *text,
306 const char *fmtpre, const char *fmtpost,
307 Eina_Bool clearsel, Eina_Bool changeinfo)
308 {
309 char *text2 = NULL;
310 Edje_Text_Insert_Filter_Callback *cb;
311 Eina_List *l;
312
313 EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
314
315 if ((clearsel) && (en->have_selection))
316 {
317 _range_del_emit(ed, en->cursor, en->rp->object, en);
318 }
319
320 text2 = strdup(text);
321 EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
322 {
323 if (!strcmp(cb->part, en->rp->part->name))
324 {
325 cb->func(cb->data, ed->obj, cb->part, EDJE_TEXT_FILTER_TEXT, &text2);
326 if (!text2) break;
327 }
328 }
329 if (text2)
330 {
331 char *markup_text;
332 Edje_Entry_Change_Info *info = NULL;
333
334 markup_text = evas_textblock_text_utf8_to_markup(NULL, text2);
335 free(text2);
336 if (markup_text)
337 info = _text_filter_markup_prepend_internal(ed, en, c, markup_text,
338 fmtpre, fmtpost,
339 clearsel, changeinfo);
340 return info;
341 }
342 return NULL;
343 }
344
345 static void
_text_filter_format_prepend(Edje * ed,Entry * en,Evas_Textblock_Cursor * c,const char * text)346 _text_filter_format_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c, const char *text)
347 {
348 char *text2;
349 Edje_Text_Insert_Filter_Callback *cb;
350 Eina_List *l;
351
352 EINA_SAFETY_ON_NULL_RETURN(text);
353 text2 = strdup(text);
354 EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
355 {
356 if (!strcmp(cb->part, en->rp->part->name))
357 {
358 cb->func(cb->data, ed->obj, cb->part, EDJE_TEXT_FILTER_FORMAT, &text2);
359 if (!text2) break;
360 }
361 }
362 if (text2)
363 {
364 char *s, *markup_text;
365 size_t size;
366
367 s = text2;
368 if (*s == '+')
369 {
370 s++;
371 while (*s == ' ')
372 s++;
373 if (!*s)
374 {
375 free(text2);
376 return;
377 }
378 size = strlen(s);
379 markup_text = (char *)malloc(size + 3);
380 if (markup_text)
381 {
382 *(markup_text) = '<';
383 memcpy((markup_text + 1), s, size);
384 *(markup_text + size + 1) = '>';
385 *(markup_text + size + 2) = '\0';
386 }
387 }
388 else if (s[0] == '-')
389 {
390 s++;
391 while (*s == ' ')
392 s++;
393 if (!*s)
394 {
395 free(text2);
396 return;
397 }
398 size = strlen(s);
399 markup_text = (char *)malloc(size + 4);
400 if (markup_text)
401 {
402 *(markup_text) = '<';
403 *(markup_text + 1) = '/';
404 memcpy((markup_text + 2), s, size);
405 *(markup_text + size + 2) = '>';
406 *(markup_text + size + 3) = '\0';
407 }
408 }
409 else
410 {
411 size = strlen(s);
412 markup_text = (char *)malloc(size + 4);
413 if (markup_text)
414 {
415 *(markup_text) = '<';
416 memcpy((markup_text + 1), s, size);
417 *(markup_text + size + 1) = '/';
418 *(markup_text + size + 2) = '>';
419 *(markup_text + size + 3) = '\0';
420 }
421 }
422 free(text2);
423 if (markup_text)
424 _text_filter_markup_prepend_internal(ed, en, c, markup_text,
425 NULL, NULL,
426 EINA_FALSE, EINA_FALSE);
427 }
428 }
429
430 static Edje_Entry_Change_Info *
_text_filter_markup_prepend(Edje * ed,Entry * en,Evas_Textblock_Cursor * c,const char * text,const char * fmtpre,const char * fmtpost,Eina_Bool clearsel,Eina_Bool changeinfo)431 _text_filter_markup_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c,
432 const char *text,
433 const char *fmtpre, const char *fmtpost,
434 Eina_Bool clearsel, Eina_Bool changeinfo)
435 {
436 char *text2;
437 Edje_Text_Insert_Filter_Callback *cb;
438 Eina_List *l;
439
440 EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
441
442 if ((clearsel) && (en->have_selection))
443 {
444 _range_del_emit(ed, en->cursor, en->rp->object, en);
445 }
446
447 text2 = strdup(text);
448 EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
449 {
450 if (!strcmp(cb->part, en->rp->part->name))
451 {
452 cb->func(cb->data, ed->obj, cb->part, EDJE_TEXT_FILTER_MARKUP, &text2);
453 if (!text2) break;
454 }
455 }
456 if (text2)
457 {
458 Edje_Entry_Change_Info *info;
459
460 info = _text_filter_markup_prepend_internal(ed, en, c, text2,
461 fmtpre, fmtpost,
462 clearsel, changeinfo);
463 return info;
464 }
465 return NULL;
466 }
467
468 static void
_curs_update_from_curs(Evas_Textblock_Cursor * c,Evas_Object * o EINA_UNUSED,Entry * en,Evas_Coord * cx,Evas_Coord * cy)469 _curs_update_from_curs(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED, Entry *en, Evas_Coord *cx, Evas_Coord *cy)
470 {
471 Evas_Coord cw, ch;
472 Evas_Textblock_Cursor_Type cur_type;
473 if (c != en->cursor) return;
474 switch (en->rp->part->cursor_mode)
475 {
476 case EDJE_ENTRY_CURSOR_MODE_BEFORE:
477 cur_type = EVAS_TEXTBLOCK_CURSOR_BEFORE;
478 break;
479
480 case EDJE_ENTRY_CURSOR_MODE_UNDER:
481 /* no break for a reason */
482 default:
483 cur_type = EVAS_TEXTBLOCK_CURSOR_UNDER;
484 }
485 evas_textblock_cursor_geometry_get(c, cx, cy, &cw, &ch, NULL, cur_type);
486 *cx += (cw / 2);
487 *cy += (ch / 2);
488 }
489
490 static int
_curs_line_last_get(Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o,Entry * en EINA_UNUSED)491 _curs_line_last_get(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en EINA_UNUSED)
492 {
493 Evas_Textblock_Cursor *cc;
494 int ln;
495
496 cc = evas_object_textblock_cursor_new(o);
497 evas_textblock_cursor_paragraph_last(cc);
498 ln = evas_textblock_cursor_line_geometry_get(cc, NULL, NULL, NULL, NULL);
499 evas_textblock_cursor_free(cc);
500 return ln;
501 }
502
503 static void
_curs_lin_start(Evas_Textblock_Cursor * c,Evas_Object * o EINA_UNUSED,Entry * en EINA_UNUSED)504 _curs_lin_start(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED,
505 Entry *en EINA_UNUSED)
506 {
507 evas_textblock_cursor_line_char_first(c);
508 }
509
510 static void
_curs_lin_end(Evas_Textblock_Cursor * c,Evas_Object * o EINA_UNUSED,Entry * en EINA_UNUSED)511 _curs_lin_end(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED,
512 Entry *en EINA_UNUSED)
513 {
514 evas_textblock_cursor_line_char_last(c);
515 }
516
517 static void
_curs_start(Evas_Textblock_Cursor * c,Evas_Object * o EINA_UNUSED,Entry * en EINA_UNUSED)518 _curs_start(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED,
519 Entry *en EINA_UNUSED)
520 {
521 evas_textblock_cursor_paragraph_first(c);
522 }
523
524 static void
_curs_end(Evas_Textblock_Cursor * c,Evas_Object * o EINA_UNUSED,Entry * en EINA_UNUSED)525 _curs_end(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED, Entry *en EINA_UNUSED)
526 {
527 evas_textblock_cursor_paragraph_last(c);
528 }
529
530 static Eina_Bool
_curs_jump_line(Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en,int ln)531 _curs_jump_line(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en, int ln)
532 {
533 Evas_Coord cx, cy;
534 Evas_Coord lx, ly, lw, lh;
535 int last = _curs_line_last_get(c, o, en);
536
537 if (ln < 0) return EINA_FALSE;
538 if (ln > last) return EINA_FALSE;
539
540 _curs_update_from_curs(c, o, en, &cx, &cy);
541
542 if (!evas_object_textblock_line_number_geometry_get(o, ln, &lx, &ly, &lw, &lh))
543 return EINA_FALSE;
544 if (evas_textblock_cursor_cluster_coord_set(c, cx, ly + (lh / 2)))
545 return EINA_TRUE;
546 evas_textblock_cursor_line_set(c, ln);
547 if (cx < (lx + (lw / 2)))
548 {
549 if (ln == last) _curs_end(c, o, en);
550 _curs_lin_start(c, o, en);
551 }
552 else
553 {
554 if (ln == last)
555 _curs_end(c, o, en);
556 else
557 _curs_lin_end(c, o, en);
558 }
559 return EINA_TRUE;
560 }
561
562 static Eina_Bool
_curs_jump_line_by(Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en,int by)563 _curs_jump_line_by(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en, int by)
564 {
565 int ln;
566
567 ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL) + by;
568 return _curs_jump_line(c, o, en, ln);
569 }
570
571 static Eina_Bool
_curs_up(Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en)572 _curs_up(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
573 {
574 return _curs_jump_line_by(c, o, en, -1);
575 }
576
577 static Eina_Bool
_curs_down(Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en)578 _curs_down(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
579 {
580 return _curs_jump_line_by(c, o, en, 1);
581 }
582
583 static void
_sel_start(Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en)584 _sel_start(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
585 {
586 if (en->sel_start) return;
587 en->sel_start = evas_object_textblock_cursor_new(o);
588 evas_textblock_cursor_copy(c, en->sel_start);
589 en->sel_end = evas_object_textblock_cursor_new(o);
590 evas_textblock_cursor_copy(c, en->sel_end);
591
592 en->have_selection = EINA_FALSE;
593 if (en->selection)
594 {
595 free(en->selection);
596 en->selection = NULL;
597 }
598 }
599
600 static void
_sel_enable(Edje * ed,Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o EINA_UNUSED,Entry * en)601 _sel_enable(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED,
602 Evas_Object *o EINA_UNUSED, Entry *en)
603 {
604 if (en->have_selection) return;
605 en->have_selection = EINA_TRUE;
606 if (en->selection)
607 {
608 free(en->selection);
609 en->selection = NULL;
610 }
611
612 _edje_entry_imf_context_reset(en->rp);
613 _edje_emit(ed, "selection,start", en->rp->part->name);
614 }
615
616 static void
_emit_sel_state(Edje * ed,Entry * en)617 _emit_sel_state(Edje *ed, Entry *en)
618 {
619 if (!evas_textblock_cursor_compare(en->sel_start, en->sel_end))
620 {
621 _edje_emit(ed, "selection,reset", en->rp->part->name);
622 }
623 else
624 {
625 _edje_emit(ed, "selection,changed", en->rp->part->name);
626 }
627 }
628
629 static void
_sel_extend(Edje * ed,Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en)630 _sel_extend(Edje *ed, Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
631 {
632 if (!en->sel_end) return;
633 _sel_enable(ed, c, o, en);
634 if (!evas_textblock_cursor_compare(c, en->sel_end)) return;
635
636 evas_textblock_cursor_copy(c, en->sel_end);
637
638 _edje_entry_imf_cursor_info_set(en);
639
640 if (en->selection)
641 {
642 free(en->selection);
643 en->selection = NULL;
644 }
645 _emit_sel_state(ed, en);
646 }
647
648 static void
_sel_preextend(Edje * ed,Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en)649 _sel_preextend(Edje *ed, Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
650 {
651 if (!en->sel_end) return;
652 _sel_enable(ed, c, o, en);
653 if (!evas_textblock_cursor_compare(c, en->sel_start)) return;
654
655 evas_textblock_cursor_copy(c, en->sel_start);
656
657 _edje_entry_imf_cursor_info_set(en);
658
659 if (en->selection)
660 {
661 free(en->selection);
662 en->selection = NULL;
663 }
664 _emit_sel_state(ed, en);
665 }
666
667 static void
_sel_clear(Edje * ed,Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o EINA_UNUSED,Entry * en)668 _sel_clear(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
669 {
670 en->had_sel = EINA_FALSE;
671 if (en->sel_start)
672 {
673 evas_textblock_cursor_free(en->sel_start);
674 evas_textblock_cursor_free(en->sel_end);
675 en->sel_start = NULL;
676 en->sel_end = NULL;
677 }
678 if (en->selection)
679 {
680 free(en->selection);
681 en->selection = NULL;
682 }
683 while (en->sel)
684 {
685 Sel *sel;
686
687 sel = en->sel->data;
688 if (sel->obj_bg) evas_object_del(sel->obj_bg);
689 if (sel->obj_fg) evas_object_del(sel->obj_fg);
690 free(sel);
691 en->sel = eina_list_remove_list(en->sel, en->sel);
692 }
693 if (en->have_selection)
694 {
695 en->have_selection = EINA_FALSE;
696 _edje_emit(ed, "selection,cleared", en->rp->part->name);
697 }
698 }
699
700 static void
_sel_update(Edje * ed,Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o,Entry * en)701 _sel_update(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en)
702 {
703 Evas_Coord x, y;
704 Evas_Object *smart, *clip;
705
706 smart = evas_object_smart_parent_get(o);
707 clip = evas_object_clip_get(o);
708 if (!en->sel_start)
709 return;
710
711 evas_object_geometry_get(o, &x, &y, NULL, NULL);
712 if (en->have_selection)
713 {
714 Eina_Iterator *range = NULL;
715 Eina_List *l;
716 Sel *sel = NULL;
717 Evas_Textblock_Rectangle *r;
718
719 range = evas_textblock_cursor_range_simple_geometry_get(en->sel_start,
720 en->sel_end);
721
722 l = en->sel;
723 EINA_ITERATOR_FOREACH(range, r)
724 {
725 if (!l)
726 {
727 Evas_Object *ob;
728
729 sel = calloc(1, sizeof(Sel));
730 if (!sel)
731 {
732 ERR("Running very low on memory");
733 break;
734 }
735 en->sel = eina_list_append(en->sel, sel);
736 if (en->rp->part->source)
737 {
738 ob = edje_object_add(ed->base.evas);
739 edje_object_file_set(ob, ed->path, en->rp->part->source);
740 evas_object_smart_member_add(ob, smart);
741 evas_object_stack_below(ob, o);
742 evas_object_clip_set(ob, clip);
743 evas_object_pass_events_set(ob, EINA_TRUE);
744 evas_object_show(ob);
745 sel->obj_bg = ob;
746 _edje_subobj_register(ed, sel->obj_bg);
747 }
748
749 if (en->rp->part->source2)
750 {
751 ob = edje_object_add(ed->base.evas);
752 edje_object_file_set(ob, ed->path, en->rp->part->source2);
753 evas_object_smart_member_add(ob, smart);
754 evas_object_stack_above(ob, o);
755 evas_object_clip_set(ob, clip);
756 evas_object_pass_events_set(ob, EINA_TRUE);
757 evas_object_show(ob);
758 sel->obj_fg = ob;
759 _edje_subobj_register(ed, sel->obj_fg);
760 }
761 }
762 else
763 {
764 sel = eina_list_data_get(l);
765 l = l->next;
766 }
767 *(&(sel->rect)) = *r;
768
769 if (sel->obj_bg)
770 {
771 evas_object_move(sel->obj_bg, x + r->x, y + r->y);
772 evas_object_resize(sel->obj_bg, r->w, r->h);
773 }
774 if (sel->obj_fg)
775 {
776 evas_object_move(sel->obj_fg, x + r->x, y + r->y);
777 evas_object_resize(sel->obj_fg, r->w, r->h);
778 }
779 }
780 eina_iterator_free(range);
781
782 /* delete redundant selection rects */
783 while (l)
784 {
785 Eina_List *temp = l->next;
786 sel = eina_list_data_get(l);
787 if (sel)
788 {
789 if (sel->obj_bg) evas_object_del(sel->obj_bg);
790 if (sel->obj_fg) evas_object_del(sel->obj_fg);
791 free(sel);
792 }
793 en->sel = eina_list_remove_list(en->sel, l);
794 l = temp;
795 }
796 }
797 }
798
799 static Eina_Bool
_edje_entry_style_tag_check(Edje_Real_Part * rp,const char * tag)800 _edje_entry_style_tag_check(Edje_Real_Part *rp, const char *tag)
801 {
802 if (!tag) return EINA_FALSE;
803 const Evas_Textblock_Style *ts = NULL;
804
805 ts = evas_object_textblock_style_user_peek(rp->object);
806 if (!ts) ts = evas_object_textblock_style_get(rp->object);
807 if (ts)
808 {
809 const char *style_str = evas_textblock_style_get(ts);
810 if (!style_str) return EINA_FALSE;
811 if (strstr(style_str, tag)) return EINA_TRUE;
812 }
813
814 return EINA_FALSE;
815 }
816
817 static void
_edje_anchor_mouse_down_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)818 _edje_anchor_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
819 {
820 Anchor *an = data;
821 Evas_Event_Mouse_Down *ev = event_info;
822 Edje_Real_Part *rp = an->en->rp;
823 char *buf, *n;
824 size_t len;
825 int ignored;
826 Entry *en;
827 Edje *ed = an->en->ed;
828
829 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
830 (!rp->typedata.text)) return;
831 en = rp->typedata.text->entry_data;
832 if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
833 (en->select_allow))
834 return;
835
836 ignored = rp->ignore_flags & ev->event_flags;
837 if ((!ev->event_flags) || (!ignored))
838 {
839 n = an->name;
840 if (!n) n = "";
841 len = 200 + strlen(n);
842 buf = alloca(len);
843 if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
844 snprintf(buf, len, "anchor,mouse,down,%i,%s,triple", ev->button, n);
845 else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
846 snprintf(buf, len, "anchor,mouse,down,%i,%s,double", ev->button, n);
847 else
848 snprintf(buf, len, "anchor,mouse,down,%i,%s", ev->button, n);
849 _edje_emit(ed, buf, rp->part->name);
850
851 /* Link Pressed effect */
852 if (_edje_entry_style_tag_check(rp, "link_pressed="))
853 {
854 an->en->have_link_pressed = EINA_TRUE;
855 evas_textblock_cursor_format_append(an->start, "<link_pressed>");
856 evas_textblock_cursor_format_prepend(an->end, "</link_pressed>");
857 }
858 }
859 ev->event_flags |= rp->mask_flags;
860 }
861
862 static void
_edje_anchor_mouse_up_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)863 _edje_anchor_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
864 {
865 Anchor *an = data;
866 Evas_Event_Mouse_Up *ev = event_info;
867 Edje_Real_Part *rp = an->en->rp;
868 char *buf, *n;
869 size_t len;
870 int ignored;
871 Entry *en;
872 Edje *ed = an->en->ed;
873
874 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
875 (!rp->typedata.text)) return;
876
877 en = rp->typedata.text->entry_data;
878 ignored = rp->ignore_flags & ev->event_flags;
879 n = an->name;
880 if (!n) n = "";
881 len = 200 + strlen(n);
882 buf = alloca(len);
883 if ((rp->part->select_mode != EDJE_ENTRY_SELECTION_MODE_EXPLICIT) ||
884 (!en->select_allow))
885 {
886 if ((!ev->event_flags) || (!ignored))
887 {
888 snprintf(buf, len, "anchor,mouse,up,%i,%s", ev->button, n);
889 _edje_emit(ed, buf, rp->part->name);
890 /* Link Pressed effect */
891 if (an->en->have_link_pressed)
892 {
893 const Evas_Object_Textblock_Node_Format *node;
894 node = evas_textblock_node_format_first_get(rp->object);
895 for (; node; node = evas_textblock_node_format_next_get(node))
896 {
897 const char *text = evas_textblock_node_format_text_get(node);
898
899 if (text)
900 {
901 if (!strcmp(text, "+ link_pressed"))
902 {
903 evas_textblock_node_format_remove_pair(rp->object,
904 (Evas_Object_Textblock_Node_Format *)node);
905 break;
906 }
907 }
908 }
909 }
910 }
911 }
912
913 if ((rp->still_in) && (rp->clicked_button == ev->button) && (!ignored))
914 {
915 snprintf(buf, len, "anchor,mouse,clicked,%i,%s", ev->button, n);
916 _edje_emit(ed, buf, rp->part->name);
917 }
918 ev->event_flags |= rp->mask_flags;
919 }
920
921 static void
_edje_anchor_mouse_move_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)922 _edje_anchor_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
923 {
924 Anchor *an = data;
925 Evas_Event_Mouse_Move *ev = event_info;
926 Edje_Real_Part *rp = an->en->rp;
927 char *buf, *n;
928 size_t len;
929 int ignored;
930 Entry *en;
931 Edje *ed = an->en->ed;
932
933 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
934 (!rp->typedata.text)) return;
935 en = rp->typedata.text->entry_data;
936 if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
937 (en->select_allow))
938 return;
939
940 ignored = rp->ignore_flags & ev->event_flags;
941 if ((!ev->event_flags) || (!ignored))
942 {
943 n = an->name;
944 if (!n) n = "";
945 len = 200 + strlen(n);
946 buf = alloca(len);
947 snprintf(buf, len, "anchor,mouse,move,%s", n);
948 _edje_emit(ed, buf, rp->part->name);
949 }
950 ev->event_flags |= rp->mask_flags;
951 }
952
953 static void
_edje_anchor_mouse_in_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)954 _edje_anchor_mouse_in_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
955 {
956 Anchor *an = data;
957 Evas_Event_Mouse_In *ev = event_info;
958 Edje_Real_Part *rp = an->en->rp;
959 Edje *ed = an->en->ed;
960 char *buf, *n;
961 size_t len;
962 int ignored;
963
964 ignored = rp->ignore_flags & ev->event_flags;
965 if ((!ev->event_flags) || (!ignored))
966 {
967 /* set to allow handling in elementary, in case we have
968 * an unwanted event propagation */
969 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
970
971 n = an->name;
972 if (!n) n = "";
973 len = 200 + strlen(n);
974 buf = alloca(len);
975 snprintf(buf, len, "anchor,mouse,in,%s", n);
976 _edje_emit(ed, buf, rp->part->name);
977 }
978 ev->event_flags |= rp->mask_flags;
979 }
980
981 static void
_edje_anchor_mouse_out_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)982 _edje_anchor_mouse_out_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
983 {
984 Anchor *an = data;
985 Evas_Event_Mouse_Out *ev = event_info;
986 Edje_Real_Part *rp = an->en->rp;
987 char *buf, *n;
988 size_t len;
989 int ignored;
990 Edje *ed = an->en->ed;
991
992 ignored = rp->ignore_flags & ev->event_flags;
993 if ((!ev->event_flags) || (!ignored))
994 {
995 /* set to allow handling in elementary, in case we have
996 * an unwanted event propagation */
997 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
998
999 n = an->name;
1000 if (!n) n = "";
1001 len = 200 + strlen(n);
1002 buf = alloca(len);
1003 snprintf(buf, len, "anchor,mouse,out,%s", n);
1004 _edje_emit(ed, buf, rp->part->name);
1005 }
1006 ev->event_flags |= rp->mask_flags;
1007 }
1008
1009 static void
_item_obj_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1010 _item_obj_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1011 {
1012 Item_Obj *io = data;
1013 Anchor *an = io->an;
1014 Entry *en;
1015
1016 if (!an)
1017 {
1018 ERR("Failed to free item object struct. Anchor is NULL!");
1019 return;
1020 }
1021
1022 en = an->en;
1023 en->item_objs = (Item_Obj *)eina_inlist_remove(EINA_INLIST_GET(en->item_objs),
1024 EINA_INLIST_GET(io));
1025 io->an = NULL;
1026 free(io->name);
1027 free(io);
1028 }
1029
1030 static Evas_Object *
_item_obj_get(Anchor * an,Evas_Object * o,Evas_Object * smart,Evas_Object * clip)1031 _item_obj_get(Anchor *an, Evas_Object *o, Evas_Object *smart, Evas_Object *clip)
1032 {
1033 Evas_Object *obj;
1034 Item_Obj *io;
1035 Entry *en = an->en;
1036 Edje *ed = en->ed;
1037
1038 EINA_INLIST_FOREACH(en->item_objs, io)
1039 {
1040 if (!io->an && io->name && !strcmp(an->name ? an->name : "", io->name))
1041 {
1042 io->an = an;
1043 return io->obj;
1044 }
1045 }
1046
1047 io = calloc(1, sizeof(Item_Obj));
1048 if (!io)
1049 {
1050 ERR("Running very low on memory");
1051 return NULL;
1052 }
1053
1054 obj = ed->item_provider.func
1055 (ed->item_provider.data, smart,
1056 en->rp->part->name, an->name);
1057 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _item_obj_del_cb, io);
1058 evas_object_smart_member_add(obj, smart);
1059 evas_object_stack_above(obj, o);
1060 evas_object_clip_set(obj, clip);
1061 evas_object_pass_events_set(obj, EINA_TRUE);
1062
1063 io->an = an;
1064 io->name = strdup(an->name ? an->name : "");
1065 io->obj = obj;
1066 en->item_objs = (Item_Obj *)eina_inlist_append(EINA_INLIST_GET(en->item_objs),
1067 EINA_INLIST_GET(io));
1068
1069 return io->obj;
1070 }
1071
1072 static void
_unused_item_objs_free(Entry * en)1073 _unused_item_objs_free(Entry *en)
1074 {
1075 Item_Obj *io;
1076 Eina_Inlist *l;
1077
1078 EINA_INLIST_FOREACH_SAFE(en->item_objs, l, io)
1079 {
1080 if (!io->an)
1081 {
1082 if (io->obj)
1083 {
1084 evas_object_event_callback_del_full(io->obj, EVAS_CALLBACK_DEL, _item_obj_del_cb, io);
1085 evas_object_del(io->obj);
1086 }
1087
1088 en->item_objs = (Item_Obj *)eina_inlist_remove(EINA_INLIST_GET(en->item_objs),
1089 EINA_INLIST_GET(io));
1090 free(io->name);
1091 free(io);
1092 }
1093 }
1094 }
1095
1096 static Eina_Bool
_is_anchors_outside_viewport(Evas_Coord oxy,Evas_Coord axy,Evas_Coord awh,Evas_Coord vxy,Evas_Coord vwh)1097 _is_anchors_outside_viewport(Evas_Coord oxy, Evas_Coord axy, Evas_Coord awh,
1098 Evas_Coord vxy, Evas_Coord vwh)
1099 {
1100 if (((oxy + axy + awh) < vxy) || ((oxy + axy) > vwh))
1101 {
1102 return EINA_TRUE;
1103 }
1104
1105 return EINA_FALSE;
1106 }
1107
1108 static void
_anchors_update(Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o,Entry * en)1109 _anchors_update(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en)
1110 {
1111 Eina_List *l, *ll, *range = NULL;
1112 Evas_Coord x, y, w, h;
1113 Evas_Coord vx, vy, vw, vh;
1114 Evas_Coord tvh, tvw;
1115 Evas_Object *smart, *clip;
1116 Sel *sel = NULL;
1117 Anchor *an;
1118 Edje *ed = en->ed;
1119
1120 /* Better not to update anchors outside the view port. */
1121 if (en->anchors_updated) return;
1122
1123 smart = evas_object_smart_parent_get(o);
1124 clip = evas_object_clip_get(o);
1125 x = y = w = h = -1;
1126 evas_object_geometry_get(o, &x, &y, &w, &h);
1127 evas_output_viewport_get(en->ed->base.evas, &vx, &vy, &vw, &vh);
1128 tvw = vx + vw;
1129 tvh = vy + vh;
1130
1131 EINA_LIST_FOREACH(en->anchors, l, an)
1132 {
1133 // for item anchors
1134 if (an->item)
1135 {
1136 Evas_Coord cx, cy, cw, ch;
1137
1138 if (!evas_textblock_cursor_format_item_geometry_get
1139 (an->start, &cx, &cy, &cw, &ch))
1140 {
1141 continue;
1142 }
1143
1144 if (_is_anchors_outside_viewport(y, cy, ch, vy, tvh) ||
1145 _is_anchors_outside_viewport(x, cx, cw, vx, tvw))
1146 {
1147 if (an->sel)
1148 {
1149 sel = an->sel->data;
1150 evas_object_hide(sel->obj);
1151 }
1152 continue;
1153 }
1154
1155 if (!an->sel)
1156 {
1157 Evas_Object *ob;
1158
1159 sel = calloc(1, sizeof(Sel));
1160 if (!sel)
1161 {
1162 ERR("Running very low on memory");
1163 break;
1164 }
1165 an->sel = eina_list_append(an->sel, sel);
1166 if (!an->sel)
1167 {
1168 ERR("Running very low on memory");
1169 break;
1170 }
1171 if (ed->item_provider.func)
1172 {
1173 ob = _item_obj_get(an, o, smart, clip);
1174 sel->obj = ob;
1175 }
1176 }
1177 /* We have only one sel per item */
1178 sel = an->sel->data;
1179 evas_object_move(sel->obj, x + cx, y + cy);
1180 evas_object_resize(sel->obj, cw, ch);
1181 evas_object_show(sel->obj);
1182 }
1183 // for link anchors
1184 else
1185 {
1186 range =
1187 evas_textblock_cursor_range_geometry_get(an->start, an->end);
1188 if (eina_list_count(range) != eina_list_count(an->sel))
1189 {
1190 while (an->sel)
1191 {
1192 sel = an->sel->data;
1193 if (sel->obj_bg) evas_object_del(sel->obj_bg);
1194 if (sel->obj_fg) evas_object_del(sel->obj_fg);
1195 if (sel->obj) evas_object_del(sel->obj);
1196 free(sel);
1197 an->sel = eina_list_remove_list(an->sel, an->sel);
1198 }
1199 if (range)
1200 {
1201 Evas_Textblock_Rectangle *r, *r_last;
1202
1203 r = range->data;
1204 r_last = eina_list_last_data_get(range);
1205 if (r->y != r_last->y)
1206 {
1207 /* For multiple range */
1208 r->h = r->y + r_last->y + r_last->h;
1209 }
1210 /* For vertically layout entry */
1211 if (_is_anchors_outside_viewport(y, r->y, r->h, vy, tvh))
1212 {
1213 EINA_LIST_FREE(range, r)
1214 free(r);
1215 continue;
1216 }
1217 else
1218 {
1219 /* XXX: Should consider for horizontal entry but has
1220 * very minimal usage. Probably we should get the min x
1221 * and max w for range and then decide whether it is in
1222 * the viewport or not. Unnecessary calculation for this
1223 * minimal usage. Please test with large number of anchors
1224 * after implementing it, if its needed to be.
1225 */
1226 }
1227 for (ll = range; ll; ll = eina_list_next(ll))
1228 {
1229 Evas_Object *ob;
1230
1231 sel = calloc(1, sizeof(Sel));
1232 if (!sel)
1233 {
1234 ERR("Running very low on memory");
1235 break;
1236 }
1237 an->sel = eina_list_append(an->sel, sel);
1238 if (en->rp->part->source5)
1239 {
1240 ob = edje_object_add(ed->base.evas);
1241 edje_object_file_set(ob, ed->path, en->rp->part->source5);
1242 evas_object_smart_member_add(ob, smart);
1243 evas_object_stack_below(ob, o);
1244 evas_object_clip_set(ob, clip);
1245 evas_object_pass_events_set(ob, EINA_TRUE);
1246 sel->obj_bg = ob;
1247 _edje_subobj_register(ed, sel->obj_bg);
1248 }
1249
1250 if (en->rp->part->source6)
1251 {
1252 ob = edje_object_add(ed->base.evas);
1253 edje_object_file_set(ob, ed->path, en->rp->part->source6);
1254 evas_object_smart_member_add(ob, smart);
1255 evas_object_stack_above(ob, o);
1256 evas_object_clip_set(ob, clip);
1257 evas_object_pass_events_set(ob, EINA_TRUE);
1258 sel->obj_fg = ob;
1259 _edje_subobj_register(ed, sel->obj_fg);
1260 }
1261
1262 ob = evas_object_rectangle_add(ed->base.evas);
1263 evas_object_color_set(ob, 0, 0, 0, 0);
1264 evas_object_smart_member_add(ob, smart);
1265 evas_object_stack_above(ob, o);
1266 evas_object_clip_set(ob, clip);
1267 evas_object_repeat_events_set(ob, EINA_TRUE);
1268 evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_DOWN, _edje_anchor_mouse_down_cb, an);
1269 evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_UP, _edje_anchor_mouse_up_cb, an);
1270 evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_MOVE, _edje_anchor_mouse_move_cb, an);
1271 evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_IN, _edje_anchor_mouse_in_cb, an);
1272 evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_OUT, _edje_anchor_mouse_out_cb, an);
1273 sel->obj = ob;
1274 }
1275 }
1276 }
1277
1278 EINA_LIST_FOREACH(an->sel, ll, sel)
1279 {
1280 Evas_Textblock_Rectangle *r;
1281
1282 r = range->data;
1283 *(&(sel->rect)) = *r;
1284 if (_is_anchors_outside_viewport(y, r->y, r->h, vy, tvh) ||
1285 _is_anchors_outside_viewport(x, r->x, r->w, vx, tvw))
1286 {
1287 range = eina_list_remove_list(range, range);
1288 free(r);
1289 evas_object_hide(sel->obj_bg);
1290 evas_object_hide(sel->obj_fg);
1291 evas_object_hide(sel->obj);
1292 continue;
1293 }
1294
1295 if (sel->obj_bg)
1296 {
1297 evas_object_move(sel->obj_bg, x + r->x, y + r->y);
1298 evas_object_resize(sel->obj_bg, r->w, r->h);
1299 evas_object_show(sel->obj_bg);
1300 }
1301 if (sel->obj_fg)
1302 {
1303 evas_object_move(sel->obj_fg, x + r->x, y + r->y);
1304 evas_object_resize(sel->obj_fg, r->w, r->h);
1305 evas_object_show(sel->obj_fg);
1306 }
1307 if (sel->obj)
1308 {
1309 evas_object_move(sel->obj, x + r->x, y + r->y);
1310 evas_object_resize(sel->obj, r->w, r->h);
1311 evas_object_show(sel->obj);
1312 }
1313 range = eina_list_remove_list(range, range);
1314 free(r);
1315 }
1316 }
1317 }
1318
1319 _unused_item_objs_free(en);
1320 }
1321
1322 static void
_anchors_update_check(Edje * ed,Edje_Real_Part * rp)1323 _anchors_update_check(Edje *ed, Edje_Real_Part *rp)
1324 {
1325 Evas_Coord x, y, w, h;
1326 Evas_Coord vx, vy, vw, vh;
1327 Eina_Bool anchors_updated = EINA_FALSE;
1328 Entry *en;
1329
1330 en = rp->typedata.text->entry_data;
1331 x = y = w = h = -1;
1332 vx = vy = vw = vh = -1;
1333 evas_object_geometry_get(rp->object, &x, &y, &w, &h);
1334 evas_output_viewport_get(ed->base.evas, &vx, &vy, &vw, &vh);
1335 if (((y + h) <= vy) || (y >= (vy + vh)))
1336 anchors_updated = EINA_TRUE;
1337 else if (((x + w) <= vx) || (x >= (vx + vw)))
1338 anchors_updated = EINA_TRUE;
1339
1340 if (en->anchors_updated)
1341 en->anchors_updated = anchors_updated;
1342 _anchors_update(en->cursor, rp->object, en);
1343 en->anchors_updated = anchors_updated;
1344 }
1345
1346 static void
_anchors_need_update(Edje_Real_Part * rp)1347 _anchors_need_update(Edje_Real_Part *rp)
1348 {
1349 Entry *en;
1350 Eina_Bool anchors_updated;
1351
1352 en = rp->typedata.text->entry_data;
1353 anchors_updated = en->anchors_updated;
1354 en->anchors_updated = EINA_FALSE;
1355 _anchors_update(en->cursor, rp->object, en);
1356 en->anchors_updated = anchors_updated;
1357 }
1358
1359 static void
_anchors_clear(Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o EINA_UNUSED,Entry * en)1360 _anchors_clear(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
1361 {
1362 Item_Obj *io;
1363
1364 while (en->anchorlist)
1365 {
1366 free(en->anchorlist->data);
1367 en->anchorlist = eina_list_remove_list(en->anchorlist, en->anchorlist);
1368 }
1369 while (en->itemlist)
1370 {
1371 free(en->itemlist->data);
1372 en->itemlist = eina_list_remove_list(en->itemlist, en->itemlist);
1373 }
1374 while (en->anchors)
1375 {
1376 Anchor *an = en->anchors->data;
1377
1378 while (an->sel)
1379 {
1380 Sel *sel = an->sel->data;
1381 if (sel->obj_bg) evas_object_del(sel->obj_bg);
1382 if (sel->obj_fg) evas_object_del(sel->obj_fg);
1383 if (!an->item && sel->obj) evas_object_del(sel->obj);
1384 free(sel);
1385 an->sel = eina_list_remove_list(an->sel, an->sel);
1386 }
1387 evas_textblock_cursor_free(an->start);
1388 evas_textblock_cursor_free(an->end);
1389 free(an->name);
1390 free(an);
1391 en->anchors = eina_list_remove_list(en->anchors, en->anchors);
1392 }
1393
1394 EINA_INLIST_FOREACH(en->item_objs, io)
1395 io->an = NULL;
1396 }
1397
1398 /* FIXME: This is horrible. It's just a copy&paste (with some adjustments)
1399 * from textblock. I didn't want to introduce any non-API links between the
1400 * libs so I just copied it. Should have been handled differently. */
1401 static char *
_anchor_format_parse(const char * item)1402 _anchor_format_parse(const char *item)
1403 {
1404 const char *start, *end;
1405 char *tmp;
1406 size_t len;
1407
1408 start = strchr(item, '=');
1409 if (!start) return NULL;
1410
1411 start++; /* Advance after the '=' */
1412 /* If we can find a quote as the first non-space char,
1413 * our new delimiter is a quote, not a space. */
1414 while (*start == ' ')
1415 start++;
1416
1417 if (*start == '\'')
1418 {
1419 start++;
1420 end = strchr(start, '\'');
1421 while ((end) && (end > start) && (end[-1] == '\\'))
1422 end = strchr(end + 1, '\'');
1423 }
1424 else
1425 {
1426 end = strchr(start, ' ');
1427 while ((end) && (end > start) && (end[-1] == '\\'))
1428 end = strchr(end + 1, ' ');
1429 }
1430
1431 /* Null terminate before the spaces */
1432 if (end) len = end - start;
1433 else len = strlen(start);
1434
1435 tmp = malloc(len + 1);
1436 if (!tmp)
1437 {
1438 ERR("Running out of memory when allocating %lu byte string", (unsigned long)len + 1);
1439 return NULL;
1440 }
1441 strncpy(tmp, start, len);
1442 tmp[len] = '\0';
1443
1444 return tmp;
1445 }
1446
1447 static void
_anchors_get(Evas_Textblock_Cursor * c,Evas_Object * o,Entry * en)1448 _anchors_get(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
1449 {
1450 const Eina_List *anchors_a, *anchors_item;
1451 Anchor *an = NULL;
1452 _anchors_clear(c, o, en);
1453
1454 anchors_a = evas_textblock_node_format_list_get(o, "a");
1455 anchors_item = evas_textblock_node_format_list_get(o, "item");
1456
1457 if (anchors_a)
1458 {
1459 const Evas_Object_Textblock_Node_Format *node;
1460 const Eina_List *itr;
1461 EINA_LIST_FOREACH(anchors_a, itr, node)
1462 {
1463 const char *s = evas_textblock_node_format_text_get(node);
1464 char *p;
1465 an = calloc(1, sizeof(Anchor));
1466 if (!an)
1467 {
1468 ERR("Running very low on memory");
1469 break;
1470 }
1471
1472 an->en = en;
1473 p = strstr(s, "href=");
1474 if (p)
1475 {
1476 an->name = _anchor_format_parse(p);
1477 }
1478 en->anchors = eina_list_append(en->anchors, an);
1479 an->start = evas_object_textblock_cursor_new(o);
1480 an->end = evas_object_textblock_cursor_new(o);
1481 evas_textblock_cursor_at_format_set(an->start, node);
1482 evas_textblock_cursor_copy(an->start, an->end);
1483
1484 /* Close the anchor, if the anchor was without text,
1485 * free it as well */
1486 node = evas_textblock_node_format_next_get(node);
1487 for (; node; node = evas_textblock_node_format_next_get(node))
1488 {
1489 s = evas_textblock_node_format_text_get(node);
1490 if ((!strcmp(s, "- a")) || (!strcmp(s, "-a")))
1491 break;
1492 }
1493
1494 if (node)
1495 {
1496 evas_textblock_cursor_at_format_set(an->end, node);
1497 }
1498 else if (!evas_textblock_cursor_compare(an->start, an->end))
1499 {
1500 free(an->name);
1501 evas_textblock_cursor_free(an->start);
1502 evas_textblock_cursor_free(an->end);
1503 en->anchors = eina_list_remove(en->anchors, an);
1504 free(an);
1505 }
1506 an = NULL;
1507 }
1508 }
1509
1510 if (anchors_item)
1511 {
1512 const Evas_Object_Textblock_Node_Format *node;
1513 const Eina_List *itr;
1514 EINA_LIST_FOREACH(anchors_item, itr, node)
1515 {
1516 const char *s = evas_textblock_node_format_text_get(node);
1517 char *p;
1518 an = calloc(1, sizeof(Anchor));
1519 if (!an)
1520 {
1521 ERR("Running very low on memory");
1522 break;
1523 }
1524
1525 an->en = en;
1526 an->item = 1;
1527 p = strstr(s, "href=");
1528 if (p)
1529 {
1530 an->name = _anchor_format_parse(p);
1531 }
1532 en->anchors = eina_list_append(en->anchors, an);
1533 an->start = evas_object_textblock_cursor_new(o);
1534 an->end = evas_object_textblock_cursor_new(o);
1535 evas_textblock_cursor_at_format_set(an->start, node);
1536 evas_textblock_cursor_copy(an->start, an->end);
1537 /* Although needed in textblock, don't bother with finding the end
1538 * here cause it doesn't really matter. */
1539 }
1540 }
1541 }
1542
1543 static void
_free_entry_change_info(void * _info)1544 _free_entry_change_info(void *_info)
1545 {
1546 Edje_Entry_Change_Info *info = (Edje_Entry_Change_Info *)_info;
1547 if (info->insert)
1548 {
1549 eina_stringshare_del(info->change.insert.content);
1550 }
1551 else
1552 {
1553 eina_stringshare_del(info->change.del.content);
1554 }
1555 free(info);
1556 }
1557
1558 static void
_range_del_emit(Edje * ed,Evas_Textblock_Cursor * c EINA_UNUSED,Evas_Object * o EINA_UNUSED,Entry * en)1559 _range_del_emit(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
1560 {
1561 size_t start, end;
1562 char *tmp;
1563 Edje_Entry_Change_Info *info;
1564
1565 start = evas_textblock_cursor_pos_get(en->sel_start);
1566 end = evas_textblock_cursor_pos_get(en->sel_end);
1567 if (start == end)
1568 goto noop;
1569
1570 info = calloc(1, sizeof(*info));
1571 if (!info)
1572 {
1573 ERR("Running very low on memory");
1574 goto noop;
1575 }
1576 info->insert = EINA_FALSE;
1577 info->change.del.start = start;
1578 info->change.del.end = end;
1579
1580 tmp = evas_textblock_cursor_range_text_get(en->sel_start, en->sel_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
1581 info->change.del.content = eina_stringshare_add(tmp);
1582 if (tmp) free(tmp);
1583 evas_textblock_cursor_range_delete(en->sel_start, en->sel_end);
1584 _edje_emit(ed, "entry,changed", en->rp->part->name);
1585 _edje_emit_full(ed, "entry,changed,user", en->rp->part->name, info,
1586 _free_entry_change_info);
1587 noop:
1588 _sel_clear(ed, en->cursor, en->rp->object, en);
1589 }
1590
1591 //static void
1592 //_range_del(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
1593 //{
1594 // evas_textblock_cursor_range_delete(en->sel_start, en->sel_end);
1595 // _sel_clear(ed, en->cursor, en->rp->object, en);
1596 //}
1597
1598 static void
_delete_emit(Edje * ed,Evas_Textblock_Cursor * c,Entry * en,size_t pos,Eina_Bool backspace)1599 _delete_emit(Edje *ed, Evas_Textblock_Cursor *c, Entry *en, size_t pos,
1600 Eina_Bool backspace)
1601 {
1602
1603 if (backspace)
1604 {
1605 if (!evas_textblock_cursor_char_prev(c))
1606 {
1607 return;
1608 }
1609 evas_textblock_cursor_char_next(c);
1610 }
1611 else
1612 {
1613 if (!evas_textblock_cursor_char_next(c))
1614 {
1615 return;
1616 }
1617 evas_textblock_cursor_char_prev(c);
1618 }
1619
1620 Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
1621 if (!info)
1622 {
1623 ERR("Running very low on memory");
1624 return;
1625 }
1626 char *tmp = NULL;
1627
1628 info->insert = EINA_FALSE;
1629 if (backspace)
1630 {
1631
1632 Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(en->rp->object);
1633 evas_textblock_cursor_copy(c, cc);
1634 Eina_Bool remove_cluster = evas_textblock_cursor_at_cluster_as_single_glyph(cc,EINA_FALSE);
1635 if (remove_cluster)
1636 {
1637 evas_textblock_cursor_cluster_prev(cc);
1638 }
1639 else
1640 {
1641 evas_textblock_cursor_char_prev(cc);
1642 }
1643
1644 info->change.del.start = evas_textblock_cursor_pos_get(cc);
1645 info->change.del.end = pos;
1646
1647 tmp = evas_textblock_cursor_range_text_get(c, cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
1648 evas_textblock_cursor_range_delete(c, cc);
1649 evas_textblock_cursor_free(cc);
1650 }
1651 else
1652 {
1653 Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(en->rp->object);
1654 evas_textblock_cursor_copy(c, cc);
1655
1656 Eina_Bool remove_cluster = evas_textblock_cursor_at_cluster_as_single_glyph(cc,EINA_TRUE);
1657 if (remove_cluster)
1658 {
1659 evas_textblock_cursor_cluster_next(cc);
1660 }
1661 else
1662 {
1663 evas_textblock_cursor_char_next(cc);
1664 }
1665
1666 info->change.del.start = evas_textblock_cursor_pos_get(cc);
1667 info->change.del.end = pos;
1668
1669 tmp = evas_textblock_cursor_range_text_get(c, cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
1670 evas_textblock_cursor_range_delete(c, cc);
1671 evas_textblock_cursor_free(cc);
1672 }
1673
1674 info->change.del.content = eina_stringshare_add(tmp);
1675 if (tmp) free(tmp);
1676
1677 _edje_emit(ed, "entry,changed", en->rp->part->name);
1678 _edje_emit_full(ed, "entry,changed,user", en->rp->part->name,
1679 info, _free_entry_change_info);
1680 }
1681
1682 Eina_Bool
_edje_entry_hide_visible_password(Edje * ed,Edje_Real_Part * rp)1683 _edje_entry_hide_visible_password(Edje *ed, Edje_Real_Part *rp)
1684 {
1685 Eina_Bool int_ret = EINA_FALSE;
1686 const Evas_Object_Textblock_Node_Format *node;
1687 node = evas_textblock_node_format_first_get(rp->object);
1688 for (; node; node = evas_textblock_node_format_next_get(node))
1689 {
1690 const char *text = evas_textblock_node_format_text_get(node);
1691 if (text)
1692 {
1693 if (!strcmp(text, "+ password=off"))
1694 {
1695 evas_textblock_node_format_remove_pair(rp->object,
1696 (Evas_Object_Textblock_Node_Format *)node);
1697 _edje_emit(ed, "entry,changed", rp->part->name);
1698 int_ret = EINA_TRUE;
1699 break;
1700 }
1701 }
1702 }
1703 _edje_entry_real_part_configure(ed, rp);
1704
1705 return int_ret;
1706 }
1707
1708 static Eina_Bool
_password_timer_cb(void * data)1709 _password_timer_cb(void *data)
1710 {
1711 Entry *en = (Entry *)data;
1712 _edje_entry_hide_visible_password(en->ed, en->rp);
1713 en->pw_timer = NULL;
1714 return ECORE_CALLBACK_CANCEL;
1715 }
1716
1717 static Eina_Bool
_is_modifier(const char * key)1718 _is_modifier(const char *key)
1719 {
1720 if ((!strncmp(key, "Shift", 5)) ||
1721 (!strncmp(key, "Control", 7)) ||
1722 (!strncmp(key, "Alt", 3)) ||
1723 (!strncmp(key, "Meta", 4)) ||
1724 (!strncmp(key, "Super", 5)) ||
1725 (!strncmp(key, "Hyper", 5)) ||
1726 (!strcmp(key, "Scroll_Lock")) ||
1727 (!strcmp(key, "Num_Lock")) ||
1728 (!strcmp(key, "Caps_Lock")))
1729 return EINA_TRUE;
1730 return EINA_FALSE;
1731 }
1732
1733 static void
_compose_seq_reset(Entry * en)1734 _compose_seq_reset(Entry *en)
1735 {
1736 char *str;
1737
1738 EINA_LIST_FREE(en->seq, str)
1739 eina_stringshare_del(str);
1740 en->composing = EINA_FALSE;
1741 }
1742
1743 static void
_edje_key_down_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)1744 _edje_key_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
1745 {
1746 Edje *ed = data;
1747 Evas_Event_Key_Down *ev = event_info;
1748 Edje_Real_Part *rp;
1749 Efl_Input_Device *seat;
1750
1751 Entry *en;
1752 Eina_Bool control, alt, shift;
1753 #if defined(__APPLE__) && defined(__MACH__)
1754 Eina_Bool super, altgr;
1755 #endif
1756 Eina_Bool multiline;
1757 Eina_Bool cursor_changed;
1758 int old_cur_pos;
1759
1760 seat = efl_input_device_seat_get(ev->dev);
1761 rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
1762
1763 if (!rp) return;
1764 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
1765 (!rp->typedata.text)) return;
1766 en = rp->typedata.text->entry_data;
1767 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
1768 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
1769 return;
1770 if (!ev->key) return;
1771
1772 _edje_emit(ed, "entry,keydown", rp->part->name);
1773 #ifdef HAVE_ECORE_IMF
1774 if (en->imf_context)
1775 {
1776 Ecore_IMF_Event_Key_Down ecore_ev;
1777 ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
1778 if (!en->composing)
1779 {
1780 if (ecore_imf_context_filter_event(en->imf_context,
1781 ECORE_IMF_EVENT_KEY_DOWN,
1782 (Ecore_IMF_Event *)&ecore_ev))
1783 {
1784 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1785 return;
1786 }
1787 }
1788 }
1789 #endif
1790
1791 old_cur_pos = evas_textblock_cursor_pos_get(en->cursor);
1792
1793 #if defined(__APPLE__) && defined(__MACH__)
1794 super = evas_key_modifier_is_set(ev->modifiers, "Super");
1795 altgr = evas_key_modifier_is_set(ev->modifiers, "AltGr");
1796 #endif
1797 control = evas_key_modifier_is_set(ev->modifiers, "Control");
1798 alt = evas_key_modifier_is_set(ev->modifiers, "Alt");
1799 shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
1800 multiline = rp->part->multiline;
1801 cursor_changed = EINA_FALSE;
1802 if (!strcmp(ev->key, "Escape"))
1803 {
1804 _compose_seq_reset(en);
1805 // dead keys here. Escape for now (should emit these)
1806 _edje_emit(ed, "entry,key,escape", rp->part->name);
1807 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1808 }
1809 else if (!strcmp(ev->key, "Up") ||
1810 (!strcmp(ev->key, "KP_Up") && !ev->string))
1811 {
1812 _compose_seq_reset(en);
1813 if (multiline)
1814 {
1815 if (en->have_selection &&
1816 (evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
1817 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1818 if (en->select_allow)
1819 {
1820 if (shift)
1821 {
1822 _sel_start(en->cursor, rp->object, en);
1823 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1824 }
1825 else if (en->have_selection)
1826 {
1827 if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
1828 evas_textblock_cursor_copy(en->sel_start, en->cursor);
1829 else
1830 evas_textblock_cursor_copy(en->sel_end, en->cursor);
1831 _sel_clear(ed, en->cursor, rp->object, en);
1832 }
1833 }
1834 if (_curs_up(en->cursor, rp->object, en))
1835 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1836 if (en->select_allow)
1837 {
1838 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
1839 else _sel_clear(ed, en->cursor, rp->object, en);
1840 }
1841 }
1842 _edje_emit(ed, "entry,key,up", rp->part->name);
1843 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
1844 }
1845 else if (!strcmp(ev->key, "Down") ||
1846 (!strcmp(ev->key, "KP_Down") && !ev->string))
1847 {
1848 _compose_seq_reset(en);
1849 if (multiline)
1850 {
1851 if (en->have_selection &&
1852 (evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
1853 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1854 if (en->select_allow)
1855 {
1856 if (shift)
1857 {
1858 _sel_start(en->cursor, rp->object, en);
1859 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1860 }
1861 else if (en->have_selection)
1862 {
1863 if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
1864 evas_textblock_cursor_copy(en->sel_end, en->cursor);
1865 else
1866 evas_textblock_cursor_copy(en->sel_start, en->cursor);
1867 _sel_clear(ed, en->cursor, rp->object, en);
1868 }
1869 }
1870 if (_curs_down(en->cursor, rp->object, en))
1871 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1872 if (en->select_allow)
1873 {
1874 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
1875 else _sel_clear(ed, en->cursor, rp->object, en);
1876 }
1877 }
1878 _edje_emit(ed, "entry,key,down", rp->part->name);
1879 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
1880 }
1881 else if (!strcmp(ev->key, "Left") ||
1882 (!strcmp(ev->key, "KP_Left") && !ev->string))
1883 {
1884 _compose_seq_reset(en);
1885 if (en->have_selection &&
1886 (evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
1887 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1888 if (en->select_allow)
1889 {
1890 if (shift)
1891 {
1892 _sel_start(en->cursor, rp->object, en);
1893 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1894 }
1895 else
1896 {
1897 if (en->have_selection)
1898 {
1899 if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
1900 evas_textblock_cursor_copy(en->sel_start, en->cursor);
1901 else
1902 evas_textblock_cursor_copy(en->sel_end, en->cursor);
1903 _sel_clear(ed, en->cursor, rp->object, en);
1904 }
1905 }
1906 }
1907 if (evas_textblock_cursor_cluster_prev(en->cursor))
1908 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1909 #if defined(__APPLE__) && defined(__MACH__)
1910 if (altgr) evas_textblock_cursor_word_start(en->cursor);
1911 #else
1912 /* If control is pressed, go to the start of the word */
1913 if (control) evas_textblock_cursor_word_start(en->cursor);
1914 #endif
1915 if (en->select_allow)
1916 {
1917 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
1918 else _sel_clear(ed, en->cursor, rp->object, en);
1919 }
1920 _edje_emit(ed, "entry,key,left", rp->part->name);
1921 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
1922 }
1923 else if (!strcmp(ev->key, "Right") ||
1924 (!strcmp(ev->key, "KP_Right") && !ev->string))
1925 {
1926 _compose_seq_reset(en);
1927 if (en->have_selection &&
1928 (evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
1929 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1930 if (en->select_allow)
1931 {
1932 if (shift)
1933 {
1934 _sel_start(en->cursor, rp->object, en);
1935 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1936 }
1937 else
1938 {
1939 if (en->have_selection)
1940 {
1941 if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
1942 evas_textblock_cursor_copy(en->sel_end, en->cursor);
1943 else
1944 evas_textblock_cursor_copy(en->sel_start, en->cursor);
1945 _sel_clear(ed, en->cursor, rp->object, en);
1946 }
1947 }
1948 }
1949 /* If control is pressed, go to the end of the word */
1950 #if defined(__APPLE__) && defined(__MACH__)
1951 if (altgr) evas_textblock_cursor_word_end(en->cursor);
1952 #else
1953 if (control) evas_textblock_cursor_word_end(en->cursor);
1954 #endif
1955 if (evas_textblock_cursor_cluster_next(en->cursor))
1956 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1957 if (en->select_allow)
1958 {
1959 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
1960 else _sel_clear(ed, en->cursor, rp->object, en);
1961 }
1962 _edje_emit(ed, "entry,key,right", rp->part->name);
1963 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
1964 }
1965 else if (!strcmp(ev->key, "BackSpace"))
1966 {
1967 _compose_seq_reset(en);
1968 if (control && !en->have_selection)
1969 {
1970 // del to start of previous word
1971 _sel_start(en->cursor, rp->object, en);
1972
1973 evas_textblock_cursor_cluster_prev(en->cursor);
1974 evas_textblock_cursor_word_start(en->cursor);
1975
1976 _sel_preextend(ed, en->cursor, rp->object, en);
1977
1978 _range_del_emit(ed, en->cursor, rp->object, en);
1979 }
1980 else if ((alt) && (shift))
1981 {
1982 // undo last action
1983 }
1984 else
1985 {
1986 if (en->have_selection)
1987 {
1988 _range_del_emit(ed, en->cursor, rp->object, en);
1989 }
1990 else
1991 {
1992 //if (evas_textblock_cursor_char_prev(en->cursor))
1993 {
1994 _delete_emit(ed, en->cursor, en, old_cur_pos, EINA_TRUE);
1995 }
1996 }
1997 }
1998 _sel_clear(ed, en->cursor, rp->object, en);
1999 _anchors_get(en->cursor, rp->object, en);
2000 _edje_emit(ed, "entry,key,backspace", rp->part->name);
2001 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2002 }
2003 else if (!strcmp(ev->key, "Delete") ||
2004 (!strcmp(ev->key, "KP_Delete") && !ev->string))
2005 {
2006 _compose_seq_reset(en);
2007 if (control)
2008 {
2009 // del to end of next word
2010 _sel_start(en->cursor, rp->object, en);
2011
2012 evas_textblock_cursor_word_end(en->cursor);
2013 evas_textblock_cursor_cluster_next(en->cursor);
2014
2015 _sel_extend(ed, en->cursor, rp->object, en);
2016
2017 _range_del_emit(ed, en->cursor, rp->object, en);
2018 }
2019 else if (shift)
2020 {
2021 // cut
2022 }
2023 else
2024 {
2025 if (en->have_selection)
2026 {
2027 _range_del_emit(ed, en->cursor, rp->object, en);
2028 }
2029 else
2030 {
2031 _delete_emit(ed, en->cursor, en, old_cur_pos, EINA_FALSE);
2032 }
2033 }
2034 _sel_clear(ed, en->cursor, rp->object, en);
2035 _anchors_get(en->cursor, rp->object, en);
2036 _edje_emit(ed, "entry,key,delete", rp->part->name);
2037 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2038 }
2039 else if ((!alt) &&
2040 (!strcmp(ev->key, "Home") ||
2041 ((!strcmp(ev->key, "KP_Home")) && !ev->string)))
2042 {
2043 _compose_seq_reset(en);
2044 if (en->select_allow)
2045 {
2046 if (shift) _sel_start(en->cursor, rp->object, en);
2047 else _sel_clear(ed, en->cursor, rp->object, en);
2048 }
2049 if ((control) && (multiline))
2050 _curs_start(en->cursor, rp->object, en);
2051 else
2052 _curs_lin_start(en->cursor, rp->object, en);
2053 if (en->select_allow)
2054 {
2055 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
2056 }
2057 _edje_emit(ed, "entry,key,home", rp->part->name);
2058 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
2059 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2060 }
2061 else if ((!alt) &&
2062 (!strcmp(ev->key, "End") ||
2063 ((!strcmp(ev->key, "KP_End")) && !ev->string)))
2064 {
2065 _compose_seq_reset(en);
2066 if (en->select_allow)
2067 {
2068 if (shift) _sel_start(en->cursor, rp->object, en);
2069 else _sel_clear(ed, en->cursor, rp->object, en);
2070 }
2071 if ((control) && (multiline))
2072 _curs_end(en->cursor, rp->object, en);
2073 else
2074 _curs_lin_end(en->cursor, rp->object, en);
2075 if (en->select_allow)
2076 {
2077 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
2078 }
2079 _edje_emit(ed, "entry,key,end", rp->part->name);
2080 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
2081 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2082 }
2083 #if defined(__APPLE__) && defined(__MACH__)
2084 else if ((super) && (!shift) && (!strcmp(ev->key, "v")))
2085 #else
2086 else if ((control) && (!shift) && (!strcmp(ev->key, "v")))
2087 #endif
2088 {
2089 _compose_seq_reset(en);
2090 _edje_emit(ed, "entry,paste,request", rp->part->name);
2091 _edje_emit(ed, "entry,paste,request,3", rp->part->name);
2092 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2093 }
2094 #if defined(__APPLE__) && defined(__MACH__)
2095 else if ((super) && (!strcmp(ev->key, "a")))
2096 #else
2097 else if ((control) && (!strcmp(ev->key, "a")))
2098 #endif
2099 {
2100 _compose_seq_reset(en);
2101 if (shift)
2102 {
2103 _edje_emit(ed, "entry,selection,none,request", rp->part->name);
2104 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2105 }
2106 else
2107 {
2108 _edje_emit(ed, "entry,selection,all,request", rp->part->name);
2109 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2110 }
2111 }
2112 #if defined(__APPLE__) && defined(__MACH__)
2113 else if ((super) && (((!shift) && !strcmp(ev->key, "c")) || !strcmp(ev->key, "Insert")))
2114 #else
2115 else if ((control) && (((!shift) && !strcmp(ev->key, "c")) || !strcmp(ev->key, "Insert")))
2116 #endif
2117 {
2118 _compose_seq_reset(en);
2119 _edje_emit(ed, "entry,copy,notify", rp->part->name);
2120 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2121 }
2122 #if defined(__APPLE__) && defined(__MACH__)
2123 else if ((super) && (!shift) && ((!strcmp(ev->key, "x") || (!strcmp(ev->key, "m")))))
2124 #else
2125 else if ((control) && (!shift) && ((!strcmp(ev->key, "x") || (!strcmp(ev->key, "m")))))
2126 #endif
2127 {
2128 _compose_seq_reset(en);
2129 _edje_emit(ed, "entry,cut,notify", rp->part->name);
2130 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2131 }
2132 #if defined(__APPLE__) && defined(__MACH__)
2133 else if ((super) && (!strcmp(ev->key, "z")))
2134 #else
2135 else if ((control) && (!strcmp(ev->key, "z")))
2136 #endif
2137 {
2138 _compose_seq_reset(en);
2139 if (shift)
2140 {
2141 // redo
2142 _edje_emit(ed, "entry,redo,request", rp->part->name);
2143 }
2144 else
2145 {
2146 // undo
2147 _edje_emit(ed, "entry,undo,request", rp->part->name);
2148 }
2149 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2150 }
2151 #if defined(__APPLE__) && defined(__MACH__)
2152 else if ((super) && (!shift) && (!strcmp(ev->key, "y")))
2153 #else
2154 else if ((control) && (!shift) && (!strcmp(ev->key, "y")))
2155 #endif
2156 {
2157 _compose_seq_reset(en);
2158 // redo
2159 _edje_emit(ed, "entry,redo,request", rp->part->name);
2160 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2161 }
2162 //else if ((control) && (!shift) && (!strcmp(ev->key, "w")))
2163 //{
2164 //_compose_seq_reset(en);
2165 //_sel_clear(ed, en->cursor, rp->object, en);
2166 //select current word?
2167 //ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2168 //}
2169 else if (!strcmp(ev->key, "Tab"))
2170 {
2171 _compose_seq_reset(en);
2172 if (multiline)
2173 {
2174 if (shift)
2175 {
2176 // remove a tab
2177 }
2178 else
2179 {
2180 Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
2181 if (!info)
2182 {
2183 ERR("Running very low on memory");
2184 }
2185 else
2186 {
2187 info->insert = EINA_TRUE;
2188 info->change.insert.plain_length = 1;
2189
2190 if (en->have_selection)
2191 {
2192 _range_del_emit(ed, en->cursor, rp->object, en);
2193 info->merge = EINA_TRUE;
2194 }
2195 info->change.insert.pos =
2196 evas_textblock_cursor_pos_get(en->cursor);
2197 info->change.insert.content = eina_stringshare_add("<tab/>");
2198 _text_filter_format_prepend(ed, en, en->cursor, "tab");
2199 _anchors_get(en->cursor, rp->object, en);
2200 _edje_emit(ed, "entry,changed", rp->part->name);
2201 _edje_emit_full(ed, "entry,changed,user", rp->part->name,
2202 info, _free_entry_change_info);
2203 }
2204 }
2205 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2206 }
2207 _edje_emit(ed, "entry,key,tab", rp->part->name);
2208 }
2209 else if ((!strcmp(ev->key, "ISO_Left_Tab")) && (multiline))
2210 {
2211 _compose_seq_reset(en);
2212 // remove a tab
2213 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2214 }
2215 else if (!strcmp(ev->key, "Prior") ||
2216 (!strcmp(ev->key, "KP_Prior") && !ev->string))
2217 {
2218 _compose_seq_reset(en);
2219 if (en->select_allow)
2220 {
2221 if (shift) _sel_start(en->cursor, rp->object, en);
2222 else _sel_clear(ed, en->cursor, rp->object, en);
2223 }
2224 if (!_curs_jump_line_by(en->cursor, rp->object, en, -10))
2225 {
2226 evas_textblock_cursor_line_set(en->cursor, 0);
2227 _curs_lin_start(en->cursor, rp->object, en);
2228 }
2229 if (en->select_allow)
2230 {
2231 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
2232 else _sel_clear(ed, en->cursor, rp->object, en);
2233 }
2234 _edje_emit(ed, "entry,key,pgup", rp->part->name);
2235 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
2236 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2237 }
2238 else if (!strcmp(ev->key, "Next") ||
2239 (!strcmp(ev->key, "KP_Next") && !ev->string))
2240 {
2241 _compose_seq_reset(en);
2242 if (en->select_allow)
2243 {
2244 if (shift) _sel_start(en->cursor, rp->object, en);
2245 else _sel_clear(ed, en->cursor, rp->object, en);
2246 }
2247 if (!_curs_jump_line_by(en->cursor, rp->object, en, 10))
2248 {
2249 int last = _curs_line_last_get(en->cursor, rp->object, en);
2250 evas_textblock_cursor_line_set(en->cursor, last);
2251 _curs_lin_end(en->cursor, rp->object, en);
2252 }
2253 if (en->select_allow)
2254 {
2255 if (shift) _sel_extend(ed, en->cursor, rp->object, en);
2256 else _sel_clear(ed, en->cursor, rp->object, en);
2257 }
2258 _edje_emit(ed, "entry,key,pgdn", rp->part->name);
2259 _edje_emit(ed, "cursor,changed,manual", rp->part->name);
2260 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2261 }
2262 else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
2263 {
2264 _compose_seq_reset(en);
2265 if (multiline)
2266 {
2267 Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
2268 if (!info)
2269 {
2270 ERR("Running very low on memory");
2271 }
2272 else
2273 {
2274 info->insert = EINA_TRUE;
2275 info->change.insert.plain_length = 1;
2276 if (en->have_selection)
2277 {
2278 _range_del_emit(ed, en->cursor, rp->object, en);
2279 info->merge = EINA_TRUE;
2280 }
2281
2282 info->change.insert.pos =
2283 evas_textblock_cursor_pos_get(en->cursor);
2284 if (shift ||
2285 evas_object_textblock_legacy_newline_get(rp->object))
2286 {
2287 _text_filter_format_prepend(ed, en, en->cursor, "br");
2288 info->change.insert.content = eina_stringshare_add("<br/>");
2289 }
2290 else
2291 {
2292 _text_filter_format_prepend(ed, en, en->cursor, "ps");
2293 info->change.insert.content = eina_stringshare_add("<ps/>");
2294 }
2295 _anchors_get(en->cursor, rp->object, en);
2296 _edje_emit(ed, "entry,changed", rp->part->name);
2297 _edje_emit_full(ed, "entry,changed,user", rp->part->name,
2298 info, _free_entry_change_info);
2299 _edje_emit(ed, "cursor,changed", rp->part->name);
2300 cursor_changed = EINA_TRUE;
2301 }
2302 }
2303 _edje_emit(ed, "entry,key,enter", rp->part->name);
2304 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2305 }
2306 else
2307 {
2308 char *compres = NULL, *string = (char *)ev->string;
2309 Eina_Bool free_string = EINA_FALSE;
2310 Ecore_Compose_State state;
2311
2312 if (control) goto end;
2313 if (!en->composing)
2314 {
2315 _compose_seq_reset(en);
2316 en->seq = eina_list_append(en->seq, eina_stringshare_add(ev->key));
2317 state = ecore_compose_get(en->seq, &compres);
2318 if (state == ECORE_COMPOSE_MIDDLE) en->composing = EINA_TRUE;
2319 else en->composing = EINA_FALSE;
2320 if (!en->composing)
2321 {
2322 free(compres);
2323 compres = NULL;
2324 _compose_seq_reset(en);
2325 if (ev->string && (!ev->string[1]) &&
2326 ((ev->string[0] < 0x20) || (ev->string[0] == 0x7f)))
2327 goto end;
2328 }
2329 else
2330 {
2331 free(compres);
2332 compres = NULL;
2333 goto end;
2334 }
2335 }
2336 else
2337 {
2338 if (_is_modifier(ev->key)) goto end;
2339 en->seq = eina_list_append(en->seq, eina_stringshare_add(ev->key));
2340 state = ecore_compose_get(en->seq, &compres);
2341 if (state == ECORE_COMPOSE_NONE)
2342 {
2343 _compose_seq_reset(en);
2344 free(compres);
2345 compres = NULL;
2346 }
2347 else if (state == ECORE_COMPOSE_DONE)
2348 {
2349 _compose_seq_reset(en);
2350 if (compres)
2351 {
2352 string = compres;
2353 free_string = EINA_TRUE;
2354 }
2355 compres = NULL;
2356 }
2357 else
2358 {
2359 free(compres);
2360 compres = NULL;
2361 goto end;
2362 }
2363 }
2364 if (string)
2365 {
2366 Edje_Entry_Change_Info *info = NULL;
2367 // if PASSWORD_SHOW_LAST mode, appending text with password=off tag
2368 if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
2369 _edje_password_show_last)
2370 {
2371 _edje_entry_hide_visible_password(ed, en->rp);
2372 info = _text_filter_text_prepend(ed, en, en->cursor, string,
2373 "+ password=off",
2374 "- password",
2375 EINA_TRUE, EINA_TRUE);
2376 if (info)
2377 {
2378 if (en->pw_timer)
2379 {
2380 ecore_timer_del(en->pw_timer);
2381 en->pw_timer = NULL;
2382 }
2383 if (_edje_password_show_last_timeout >= 0)
2384 en->pw_timer = ecore_timer_add
2385 (_edje_password_show_last_timeout,
2386 _password_timer_cb, en);
2387 }
2388 }
2389 else
2390 info = _text_filter_text_prepend(ed, en, en->cursor, string,
2391 NULL, NULL,
2392 EINA_TRUE, EINA_TRUE);
2393 _anchors_get(en->cursor, rp->object, en);
2394 if (info)
2395 {
2396 _edje_emit(ed, "entry,changed", rp->part->name);
2397 _edje_emit_full(ed, "entry,changed,user", rp->part->name,
2398 info, _free_entry_change_info);
2399 _edje_emit(ed, "cursor,changed", rp->part->name);
2400 cursor_changed = EINA_TRUE;
2401 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2402 }
2403 if (free_string) free(string);
2404 }
2405 }
2406 end:
2407 if (!cursor_changed &&
2408 (old_cur_pos != evas_textblock_cursor_pos_get(en->cursor)))
2409 _edje_emit(ed, "cursor,changed", rp->part->name);
2410
2411 _edje_entry_imf_cursor_info_set(en);
2412 _edje_entry_real_part_configure(ed, rp);
2413 }
2414
2415 static void
_edje_key_up_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)2416 _edje_key_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
2417 {
2418 Evas_Event_Key_Up *ev = event_info;
2419 Efl_Input_Device *seat;
2420 Edje *ed = data;
2421 Edje_Real_Part *rp;
2422 Entry *en;
2423
2424 seat = efl_input_device_seat_get(ev->dev);
2425 rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
2426 if (!rp) return;
2427 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2428 (!rp->typedata.text)) return;
2429 en = rp->typedata.text->entry_data;
2430 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
2431 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
2432 return;
2433
2434 _edje_emit(ed, "entry,keyup", rp->part->name);
2435 #ifdef HAVE_ECORE_IMF
2436 if (en->imf_context)
2437 {
2438 Ecore_IMF_Event_Key_Up ecore_ev;
2439
2440 ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev);
2441 if (ecore_imf_context_filter_event(en->imf_context,
2442 ECORE_IMF_EVENT_KEY_UP,
2443 (Ecore_IMF_Event *)&ecore_ev))
2444 return;
2445 }
2446 #else
2447 (void)event_info;
2448 #endif
2449 }
2450
2451 static Evas_Textblock_Cursor *
_edje_cursor_cluster_coord_set(Edje_Real_Part * rp,Evas_Coord canvasx,Evas_Coord canvasy,Evas_Coord * cx,Evas_Coord * cy)2452 _edje_cursor_cluster_coord_set(Edje_Real_Part *rp, Evas_Coord canvasx, Evas_Coord canvasy, Evas_Coord *cx, Evas_Coord *cy)
2453 {
2454 Entry *en;
2455 Evas_Coord x, y, lh = 0, cly = 0;
2456 Evas_Textblock_Cursor *line_cur;
2457 Evas_Textblock_Cursor *tc;
2458
2459 en = rp->typedata.text->entry_data;
2460 tc = evas_object_textblock_cursor_new(rp->object);
2461 evas_textblock_cursor_copy(en->cursor, tc);
2462 evas_object_geometry_get(rp->object, &x, &y, NULL, NULL);
2463 *cx = canvasx - x;
2464 *cy = canvasy - y;
2465
2466 line_cur = evas_object_textblock_cursor_new(rp->object);
2467 evas_textblock_cursor_paragraph_last(line_cur);
2468 evas_textblock_cursor_line_geometry_get(line_cur, NULL, &cly, NULL, &lh);
2469 /* Consider a threshold of half the line height */
2470 if (*cy > (cly + lh) && *cy < (cly + lh + lh / 2))
2471 {
2472 *cy = cly + lh - 1; // Make it inside Textblock
2473 }
2474 evas_textblock_cursor_paragraph_first(line_cur);
2475 evas_textblock_cursor_line_geometry_get(line_cur, NULL, &cly, NULL, NULL);
2476
2477 if (*cy < cly && *cy > (cly - lh / 2))
2478 {
2479 *cy = cly;
2480 }
2481 evas_textblock_cursor_free(line_cur);
2482 /* No need to check return value if not able to set the char coord Textblock
2483 * will take care */
2484 evas_textblock_cursor_cluster_coord_set(en->cursor, *cx, *cy);
2485
2486 return tc;
2487 }
2488
2489 static void
_edje_part_move_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)2490 _edje_part_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2491 {
2492 Edje_Real_Part *rp = data;
2493 Entry *en;
2494 if (!rp) return;
2495 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2496 (!rp->typedata.text)) return;
2497 en = rp->typedata.text->entry_data;
2498 if (!en) return;
2499 _edje_entry_imf_cursor_location_set(en);
2500 }
2501
2502 static void
_edje_part_mouse_down_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)2503 _edje_part_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
2504 {
2505 Evas_Coord cx, cy;
2506 Edje_Real_Part *rp = data;
2507 Evas_Event_Mouse_Down *ev = event_info;
2508 Entry *en;
2509 // Eina_Bool multiline;
2510 Evas_Textblock_Cursor *tc = NULL;
2511 Eina_Bool dosel = EINA_FALSE;
2512 Eina_Bool shift;
2513
2514 if ((!rp) || (!ev)) return;
2515 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2516 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2517 (!rp->typedata.text)) return;
2518 en = rp->typedata.text->entry_data;
2519 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
2520 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
2521 return;
2522 if ((ev->button != 1) && (ev->button != 2)) return;
2523
2524 #ifdef HAVE_ECORE_IMF
2525 if (en->imf_context)
2526 {
2527 Ecore_IMF_Event_Mouse_Down ecore_ev;
2528 ecore_imf_evas_event_mouse_down_wrap(ev, &ecore_ev);
2529 if (ecore_imf_context_filter_event(en->imf_context,
2530 ECORE_IMF_EVENT_MOUSE_DOWN,
2531 (Ecore_IMF_Event *)&ecore_ev))
2532 return;
2533 }
2534 #endif
2535
2536 _edje_entry_imf_context_reset(rp);
2537
2538 shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
2539 en->select_mod_start = EINA_FALSE;
2540 en->select_mod_end = EINA_FALSE;
2541
2542 if (en->select_allow && ev->button != 2) dosel = EINA_TRUE;
2543 if (dosel)
2544 {
2545 if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
2546 {
2547 if (shift)
2548 {
2549 tc = evas_object_textblock_cursor_new(rp->object);
2550 evas_textblock_cursor_copy(en->cursor, tc);
2551 if (evas_textblock_cursor_compare(en->cursor, en->sel_start) < 0)
2552 evas_textblock_cursor_line_char_first(en->cursor);
2553 else
2554 evas_textblock_cursor_line_char_last(en->cursor);
2555 _sel_extend(en->ed, en->cursor, rp->object, en);
2556 }
2557 else
2558 {
2559 en->have_selection = EINA_FALSE;
2560 en->selecting = EINA_FALSE;
2561 _sel_clear(en->ed, en->cursor, rp->object, en);
2562 tc = evas_object_textblock_cursor_new(rp->object);
2563 evas_textblock_cursor_copy(en->cursor, tc);
2564 evas_textblock_cursor_line_char_first(en->cursor);
2565 _sel_start(en->cursor, rp->object, en);
2566 evas_textblock_cursor_line_char_last(en->cursor);
2567 _sel_extend(en->ed, en->cursor, rp->object, en);
2568 }
2569 goto end;
2570 }
2571 else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
2572 {
2573 if (shift)
2574 {
2575 tc = evas_object_textblock_cursor_new(rp->object);
2576 evas_textblock_cursor_copy(en->cursor, tc);
2577 if (evas_textblock_cursor_compare(en->cursor, en->sel_start) < 0)
2578 evas_textblock_cursor_word_start(en->cursor);
2579 else
2580 {
2581 evas_textblock_cursor_word_end(en->cursor);
2582 evas_textblock_cursor_cluster_next(en->cursor);
2583 }
2584 _sel_extend(en->ed, en->cursor, rp->object, en);
2585 }
2586 else
2587 {
2588 en->have_selection = EINA_FALSE;
2589 en->selecting = EINA_FALSE;
2590 _sel_clear(en->ed, en->cursor, rp->object, en);
2591 tc = evas_object_textblock_cursor_new(rp->object);
2592 evas_textblock_cursor_copy(en->cursor, tc);
2593 evas_textblock_cursor_word_start(en->cursor);
2594 _sel_start(en->cursor, rp->object, en);
2595 evas_textblock_cursor_word_end(en->cursor);
2596 evas_textblock_cursor_cluster_next(en->cursor);
2597 _sel_extend(en->ed, en->cursor, rp->object, en);
2598 }
2599 goto end;
2600 }
2601 }
2602 tc = _edje_cursor_cluster_coord_set(rp, ev->canvas.x, ev->canvas.y, &cx, &cy);
2603
2604 if (dosel)
2605 {
2606 if ((en->have_selection) &&
2607 (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT))
2608 {
2609 if (shift)
2610 _sel_extend(en->ed, en->cursor, rp->object, en);
2611 else
2612 {
2613 Eina_List *first, *last;
2614 FLOAT_T sc;
2615
2616 first = en->sel;
2617 last = eina_list_last(en->sel);
2618 if (first && last)
2619 {
2620 Evas_Textblock_Rectangle *r1, *r2;
2621 Evas_Coord d, d1, d2;
2622
2623 r1 = first->data;
2624 r2 = last->data;
2625 d = r1->x - cx;
2626 d1 = d * d;
2627 d = (r1->y + (r1->h / 2)) - cy;
2628 d1 += d * d;
2629 d = r2->x + r2->w - 1 - cx;
2630 d2 = d * d;
2631 d = (r2->y + (r2->h / 2)) - cy;
2632 d2 += d * d;
2633 sc = DIV(en->ed->scale, en->ed->file->base_scale);
2634 if (EQ(sc, ZERO)) sc = DIV(_edje_scale, en->ed->file->base_scale);
2635 d = (Evas_Coord)MUL(FROM_INT(20), sc); // FIXME: maxing number!
2636 d = d * d;
2637 if (d1 < d2)
2638 {
2639 if (d1 <= d)
2640 {
2641 en->select_mod_start = EINA_TRUE;
2642 en->selecting = EINA_TRUE;
2643 }
2644 }
2645 else
2646 {
2647 if (d2 <= d)
2648 {
2649 en->select_mod_end = EINA_TRUE;
2650 en->selecting = EINA_TRUE;
2651 }
2652 }
2653 }
2654 }
2655 }
2656 else
2657 {
2658 if (shift)
2659 {
2660 _sel_extend(en->ed, en->cursor, rp->object, en);
2661 }
2662 else
2663 {
2664 en->selecting = EINA_TRUE;
2665 _sel_clear(en->ed, en->cursor, rp->object, en);
2666 _sel_start(en->cursor, rp->object, en);
2667 }
2668 }
2669 }
2670 end:
2671 if (evas_textblock_cursor_compare(tc, en->cursor))
2672 {
2673 _edje_emit(en->ed, "cursor,changed", rp->part->name);
2674 _edje_emit(en->ed, "cursor,changed,manual", rp->part->name);
2675 }
2676 evas_textblock_cursor_free(tc);
2677
2678 _edje_entry_real_part_configure(en->ed, rp);
2679 if (ev->button == 2)
2680 {
2681 _edje_emit(en->ed, "entry,paste,request", rp->part->name);
2682 _edje_emit(en->ed, "entry,paste,request,1", rp->part->name);
2683 }
2684 }
2685
2686 static void
_edje_part_mouse_up_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)2687 _edje_part_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
2688 {
2689 Evas_Coord cx, cy;
2690 Edje_Real_Part *rp = data;
2691 Evas_Event_Mouse_Up *ev = event_info;
2692 Entry *en;
2693 Evas_Textblock_Cursor *tc;
2694
2695 if ((!ev) || (ev->button != 1)) return;
2696 if (!rp) return;
2697 if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK) return;
2698 if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) return;
2699 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2700 (!rp->typedata.text)) return;
2701 en = rp->typedata.text->entry_data;
2702 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
2703 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
2704 return;
2705
2706 /* We don't check for ON_HOLD because we'd like to end selection anyway when
2707 * mouse is up, even if it's held. */
2708
2709 #ifdef HAVE_ECORE_IMF
2710 if (en->imf_context)
2711 {
2712 Ecore_IMF_Event_Mouse_Up ecore_ev;
2713 ecore_imf_evas_event_mouse_up_wrap(ev, &ecore_ev);
2714 if (ecore_imf_context_filter_event(en->imf_context,
2715 ECORE_IMF_EVENT_MOUSE_UP,
2716 (Ecore_IMF_Event *)&ecore_ev))
2717 return;
2718 }
2719 #endif
2720
2721 /* cx cy are unused but needed in mouse down, please bear with it */
2722 tc = _edje_cursor_cluster_coord_set(rp, ev->canvas.x, ev->canvas.y, &cx, &cy);
2723
2724 if (en->select_allow)
2725 {
2726 if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
2727 {
2728 if (en->had_sel)
2729 {
2730 if (en->select_mod_end)
2731 _sel_extend(en->ed, en->cursor, rp->object, en);
2732 else if (en->select_mod_start)
2733 _sel_preextend(en->ed, en->cursor, rp->object, en);
2734 }
2735 else
2736 _sel_extend(en->ed, en->cursor, rp->object, en);
2737 //evas_textblock_cursor_copy(en->cursor, en->sel_end);
2738 }
2739 else
2740 {
2741 evas_textblock_cursor_copy(en->cursor, en->sel_end);
2742 }
2743 }
2744 if (en->selecting)
2745 {
2746 if (en->have_selection)
2747 en->had_sel = EINA_TRUE;
2748 en->selecting = EINA_FALSE;
2749 }
2750 if (evas_textblock_cursor_compare(tc, en->cursor))
2751 {
2752 _edje_emit(en->ed, "cursor,changed", rp->part->name);
2753 _edje_emit(en->ed, "cursor,changed,manual", rp->part->name);
2754 }
2755
2756 _edje_entry_imf_cursor_info_set(en);
2757
2758 evas_textblock_cursor_free(tc);
2759
2760 _edje_entry_real_part_configure(en->ed, rp);
2761 }
2762
2763 static void
_edje_part_mouse_move_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)2764 _edje_part_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
2765 {
2766 Evas_Coord cx, cy;
2767 Edje_Real_Part *rp = data;
2768 Evas_Event_Mouse_Move *ev = event_info;
2769 Entry *en;
2770 Evas_Coord x, y, w, h;
2771 Evas_Textblock_Cursor *tc;
2772
2773 if ((!rp) || (!ev)) return;
2774 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2775 (!rp->typedata.text)) return;
2776 en = rp->typedata.text->entry_data;
2777 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
2778 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
2779 return;
2780
2781 #ifdef HAVE_ECORE_IMF
2782 if (en->imf_context)
2783 {
2784 Ecore_IMF_Event_Mouse_Move ecore_ev;
2785 ecore_imf_evas_event_mouse_move_wrap(ev, &ecore_ev);
2786 if (ecore_imf_context_filter_event(en->imf_context,
2787 ECORE_IMF_EVENT_MOUSE_MOVE,
2788 (Ecore_IMF_Event *)&ecore_ev))
2789 return;
2790 }
2791 #endif
2792
2793 if (en->selecting)
2794 {
2795 tc = evas_object_textblock_cursor_new(rp->object);
2796 evas_textblock_cursor_copy(en->cursor, tc);
2797 evas_object_geometry_get(rp->object, &x, &y, &w, &h);
2798 cx = ev->cur.canvas.x - x;
2799 cy = ev->cur.canvas.y - y;
2800 if (!evas_textblock_cursor_cluster_coord_set(en->cursor, cx, cy))
2801 {
2802 Evas_Coord lx, ly, lw, lh;
2803
2804 if (evas_textblock_cursor_line_coord_set(en->cursor, cy) < 0)
2805 {
2806 if (rp->part->multiline)
2807 _curs_end(en->cursor, rp->object, en);
2808 else
2809 {
2810 evas_textblock_cursor_paragraph_first(en->cursor);
2811 evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
2812 if (!evas_textblock_cursor_cluster_coord_set(en->cursor, cx, ly + (lh / 2)))
2813 _curs_end(en->cursor, rp->object, en);
2814 }
2815 }
2816 else
2817 {
2818 evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
2819 if (cx <= lx)
2820 _curs_lin_start(en->cursor, rp->object, en);
2821 else
2822 _curs_lin_end(en->cursor, rp->object, en);
2823 }
2824 }
2825 if (en->select_allow)
2826 {
2827 if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
2828 {
2829 if (en->had_sel)
2830 {
2831 if (en->select_mod_end)
2832 _sel_extend(en->ed, en->cursor, rp->object, en);
2833 else if (en->select_mod_start)
2834 _sel_preextend(en->ed, en->cursor, rp->object, en);
2835 }
2836 else
2837 _sel_extend(en->ed, en->cursor, rp->object, en);
2838 }
2839 else
2840 {
2841 _sel_extend(en->ed, en->cursor, rp->object, en);
2842 }
2843
2844 if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) != 0)
2845 _sel_enable(en->ed, en->cursor, rp->object, en);
2846 if (en->have_selection)
2847 _sel_update(en->ed, en->cursor, rp->object, en);
2848 }
2849 if (evas_textblock_cursor_compare(tc, en->cursor))
2850 {
2851 _edje_emit(en->ed, "cursor,changed", rp->part->name);
2852 _edje_emit(en->ed, "cursor,changed,manual", rp->part->name);
2853 }
2854 evas_textblock_cursor_free(tc);
2855
2856 _edje_entry_real_part_configure(en->ed, rp);
2857 }
2858 }
2859
2860 static void
_canvas_viewport_resize_cb(void * data,Evas * e EINA_UNUSED,void * event_info EINA_UNUSED)2861 _canvas_viewport_resize_cb(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
2862 {
2863 Edje_Real_Part *rp = data;
2864 Entry *en;
2865 if ((!rp)) return;
2866
2867 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2868 (!rp->typedata.text)) return;
2869 en = rp->typedata.text->entry_data;
2870 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
2871 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
2872 return;
2873
2874 _anchors_need_update(rp);
2875 }
2876
2877 static void
_evas_focus_in_cb(void * data,const Efl_Event * event)2878 _evas_focus_in_cb(void *data, const Efl_Event *event)
2879 {
2880 Efl_Input_Focus *ev = event->info;
2881 Evas *e = event->object;
2882 Efl_Input_Device *seat;
2883 Edje *ed = data;
2884
2885 if (!ed) return;
2886
2887 seat = efl_input_device_get(ev);
2888 if (evas_canvas_seat_focus_get(e, seat) == ed->obj)
2889 {
2890 _edje_focus_in(data, seat);
2891 }
2892 }
2893
2894 static void
_evas_focus_out_cb(void * data,const Efl_Event * event)2895 _evas_focus_out_cb(void *data, const Efl_Event *event)
2896 {
2897 Efl_Input_Focus *ev = event->info;
2898 Evas *e = event->object;
2899 Efl_Input_Device *seat;
2900 Edje *ed = data;
2901
2902 if (!ed) return;
2903
2904 seat = efl_input_device_get(ev);
2905 if (evas_canvas_seat_focus_get(e, seat) == ed->obj)
2906 {
2907 _edje_focus_out(data, seat);
2908 }
2909 }
2910
2911 /***************************************************************/
2912 void
_edje_entry_init(Edje * ed)2913 _edje_entry_init(Edje *ed)
2914 {
2915 if (!ed->has_entries)
2916 return;
2917 if (ed->entries_inited)
2918 return;
2919 ed->entries_inited = EINA_TRUE;
2920
2921 efl_event_callback_add(ed->obj, EFL_EVENT_FOCUS_IN, _edje_focus_in_cb, ed);
2922 efl_event_callback_add(ed->obj, EFL_EVENT_FOCUS_OUT, _edje_focus_out_cb, ed);
2923 evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_KEY_DOWN,
2924 _edje_key_down_cb, ed);
2925 evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_KEY_UP,
2926 _edje_key_up_cb, ed);
2927 efl_event_callback_add(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_IN,
2928 _evas_focus_in_cb, ed);
2929 efl_event_callback_add(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_OUT,
2930 _evas_focus_out_cb, ed);
2931 }
2932
2933 void
_edje_entry_shutdown(Edje * ed)2934 _edje_entry_shutdown(Edje *ed)
2935 {
2936 if ((!ed) || (!ed->has_entries))
2937 return;
2938 if (!ed->entries_inited)
2939 return;
2940 ed->entries_inited = EINA_FALSE;
2941
2942 efl_event_callback_del(ed->obj, EFL_EVENT_FOCUS_IN, _edje_focus_in_cb, ed);
2943 efl_event_callback_del(ed->obj, EFL_EVENT_FOCUS_OUT, _edje_focus_out_cb, ed);
2944 evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_KEY_DOWN,
2945 _edje_key_down_cb);
2946 evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_KEY_UP,
2947 _edje_key_up_cb);
2948 efl_event_callback_del(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_IN,
2949 _evas_focus_in_cb, ed);
2950 efl_event_callback_del(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_OUT,
2951 _evas_focus_out_cb, ed);
2952 }
2953
2954 int
_edje_entry_real_part_cursor_objs_get(Edje_Real_Part * rp,Evas_Object ** cursor_objs)2955 _edje_entry_real_part_cursor_objs_get(Edje_Real_Part *rp, Evas_Object **cursor_objs)
2956 {
2957 Entry *en;
2958 int ret = 0;
2959
2960 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2961 (!rp->typedata.text) || (!rp->typedata.text->entry_data)) return -1;
2962
2963 en = rp->typedata.text->entry_data;
2964
2965 if (en->cursor_bg) cursor_objs[ret++] = en->cursor_bg;
2966 if (en->cursor_fg) cursor_objs[ret++] = en->cursor_fg;
2967 if (en->cursor_fg2) cursor_objs[ret++] = en->cursor_fg2;
2968 return ret;
2969 }
2970
2971 void
_edje_entry_real_part_init(Edje * ed,Edje_Real_Part * rp)2972 _edje_entry_real_part_init(Edje *ed, Edje_Real_Part *rp)
2973 {
2974 Entry *en;
2975 #ifdef HAVE_ECORE_IMF
2976 const char *ctx_id;
2977 const Ecore_IMF_Context_Info *ctx_info;
2978 #endif
2979
2980 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
2981 (!rp->typedata.text)) return;
2982 en = calloc(1, sizeof(Entry));
2983 if (!en)
2984 {
2985 ERR("Running very low on memory");
2986 return;
2987 }
2988 rp->typedata.text->entry_data = en;
2989 en->rp = rp;
2990 en->ed = ed;
2991
2992 evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOVE, _edje_part_move_cb, rp);
2993
2994 evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_DOWN, _edje_part_mouse_down_cb, rp);
2995 evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_UP, _edje_part_mouse_up_cb, rp);
2996 evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_MOVE, _edje_part_mouse_move_cb, rp);
2997 evas_event_callback_add(ed->base.evas, EVAS_CALLBACK_CANVAS_VIEWPORT_RESIZE, _canvas_viewport_resize_cb, rp);
2998
2999 if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_DEFAULT)
3000 en->select_allow = EINA_TRUE;
3001
3002 if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
3003 {
3004 Edje_Part_Description_Text *txt;
3005
3006 txt = (Edje_Part_Description_Text *)rp->chosen_description;
3007
3008 en->select_allow = EINA_FALSE;
3009 if (txt && edje_string_get(&txt->text.repch))
3010 evas_object_textblock_replace_char_set(rp->object, edje_string_get(&txt->text.repch));
3011 else
3012 evas_object_textblock_replace_char_set(rp->object, "*");
3013 }
3014
3015 if (rp->part->source3)
3016 {
3017 en->cursor_bg = edje_object_add(ed->base.evas);
3018 edje_object_file_set(en->cursor_bg, ed->path, rp->part->source3);
3019 evas_object_smart_member_add(en->cursor_bg, ed->obj);
3020 evas_object_stack_below(en->cursor_bg, rp->object);
3021 evas_object_clip_set(en->cursor_bg, evas_object_clip_get(rp->object));
3022 evas_object_pass_events_set(en->cursor_bg, EINA_TRUE);
3023 _edje_subobj_register(ed, en->cursor_bg);
3024 }
3025 if (rp->part->source4)
3026 {
3027 en->cursor_fg = edje_object_add(ed->base.evas);
3028 edje_object_file_set(en->cursor_fg, ed->path, rp->part->source4);
3029 evas_object_smart_member_add(en->cursor_fg, ed->obj);
3030 evas_object_stack_above(en->cursor_fg, rp->object);
3031 evas_object_clip_set(en->cursor_fg, evas_object_clip_get(rp->object));
3032 evas_object_pass_events_set(en->cursor_fg, EINA_TRUE);
3033 _edje_subobj_register(ed, en->cursor_fg);
3034
3035 /* A proxy to the main cursor. */
3036 if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
3037 {
3038 en->cursor_fg2 = edje_object_add(ed->base.evas);
3039 edje_object_file_set(en->cursor_fg2, ed->path, rp->part->source4);
3040 evas_object_smart_member_add(en->cursor_fg2, ed->obj);
3041 evas_object_stack_above(en->cursor_fg2, rp->object);
3042 evas_object_clip_set(en->cursor_fg2, evas_object_clip_get(rp->object));
3043 evas_object_pass_events_set(en->cursor_fg2, EINA_TRUE);
3044 _edje_subobj_register(ed, en->cursor_fg2);
3045 }
3046 }
3047
3048 evas_object_textblock_legacy_newline_set(rp->object, EINA_TRUE);
3049
3050 if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
3051 {
3052 if (en->cursor_bg) evas_object_show(en->cursor_bg);
3053 if (en->cursor_fg) evas_object_show(en->cursor_fg);
3054 if (en->cursor_fg2) evas_object_show(en->cursor_fg2);
3055 en->input_panel_enable = EINA_TRUE;
3056
3057 #ifdef HAVE_ECORE_IMF
3058 _edje_need_imf();
3059
3060 en->commit_cancel = EINA_FALSE;
3061
3062 edje_object_signal_callback_add(ed->obj, "focus,part,in,*",
3063 rp->part->name,
3064 _edje_entry_focus_in_cb, rp);
3065 edje_object_signal_callback_add(ed->obj, "focus,part,out,*",
3066 rp->part->name,
3067 _edje_entry_focus_out_cb, rp);
3068
3069 ctx_id = ecore_imf_context_default_id_get();
3070 if (ctx_id)
3071 {
3072 ctx_info = ecore_imf_context_info_by_id_get(ctx_id);
3073 if (!ctx_info->canvas_type ||
3074 strcmp(ctx_info->canvas_type, "evas") == 0)
3075 {
3076 en->imf_context = ecore_imf_context_add(ctx_id);
3077 }
3078 else
3079 {
3080 ctx_id = ecore_imf_context_default_id_by_canvas_type_get("evas");
3081 if (ctx_id)
3082 {
3083 en->imf_context = ecore_imf_context_add(ctx_id);
3084 }
3085 }
3086 }
3087 else
3088 en->imf_context = NULL;
3089
3090 if (!en->imf_context) goto done;
3091
3092 ecore_imf_context_client_window_set
3093 (en->imf_context,
3094 (void *)ecore_evas_window_get
3095 (ecore_evas_ecore_evas_get(ed->base.evas)));
3096 ecore_imf_context_client_canvas_set(en->imf_context, ed->base.evas);
3097
3098 ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context,
3099 _edje_entry_imf_retrieve_surrounding_cb, ed);
3100 ecore_imf_context_retrieve_selection_callback_set(en->imf_context, _edje_entry_imf_retrieve_selection_cb, ed);
3101 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _edje_entry_imf_event_commit_cb, ed);
3102 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _edje_entry_imf_event_delete_surrounding_cb, ed);
3103 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _edje_entry_imf_event_preedit_changed_cb, ed);
3104 ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_SELECTION_SET, _edje_entry_imf_event_selection_set_cb, ed);
3105 ecore_imf_context_input_mode_set(en->imf_context,
3106 rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD ?
3107 ECORE_IMF_INPUT_MODE_INVISIBLE : ECORE_IMF_INPUT_MODE_FULL);
3108
3109 if (rp->part->multiline)
3110 ecore_imf_context_input_hint_set(en->imf_context,
3111 ecore_imf_context_input_hint_get(en->imf_context) | ECORE_IMF_INPUT_HINT_MULTILINE);
3112
3113 if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
3114 ecore_imf_context_input_panel_language_set(en->imf_context, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET);
3115 #endif
3116 }
3117 #ifdef HAVE_ECORE_IMF
3118 done:
3119 #endif
3120 en->cursor = (Evas_Textblock_Cursor *)evas_object_textblock_cursor_get(rp->object);
3121 }
3122
3123 void
_edje_entry_real_part_shutdown(Edje * ed,Edje_Real_Part * rp)3124 _edje_entry_real_part_shutdown(Edje *ed, Edje_Real_Part *rp)
3125 {
3126 Entry *en;
3127
3128 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3129 (!rp->typedata.text)) return;
3130 en = rp->typedata.text->entry_data;
3131 if (!en) return;
3132 rp->typedata.text->entry_data = NULL;
3133 _sel_clear(ed, en->cursor, rp->object, en);
3134 _anchors_clear(en->cursor, rp->object, en);
3135 _unused_item_objs_free(en);
3136 #ifdef HAVE_ECORE_IMF
3137 _preedit_clear(en);
3138 #endif
3139 evas_object_del(en->cursor_bg);
3140 evas_object_del(en->cursor_fg);
3141 evas_object_del(en->cursor_fg2);
3142
3143 if (en->cursor_user)
3144 evas_textblock_cursor_free(en->cursor_user);
3145
3146 if (en->cursor_user_extra)
3147 evas_textblock_cursor_free(en->cursor_user_extra);
3148
3149 if (en->pw_timer)
3150 {
3151 ecore_timer_del(en->pw_timer);
3152 en->pw_timer = NULL;
3153 }
3154
3155 evas_event_callback_del_full(ed->base.evas, EVAS_CALLBACK_CANVAS_VIEWPORT_RESIZE, _canvas_viewport_resize_cb, rp);
3156
3157 #ifdef HAVE_ECORE_IMF
3158 if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
3159 {
3160 if (en->imf_context)
3161 {
3162 ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _edje_entry_imf_event_commit_cb);
3163 ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _edje_entry_imf_event_delete_surrounding_cb);
3164 ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _edje_entry_imf_event_preedit_changed_cb);
3165 ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_SELECTION_SET, _edje_entry_imf_event_selection_set_cb);
3166
3167 ecore_imf_context_del(en->imf_context);
3168 en->imf_context = NULL;
3169 }
3170
3171 edje_object_signal_callback_del(ed->obj, "focus,part,in,*",
3172 rp->part->name,
3173 _edje_entry_focus_in_cb);
3174 edje_object_signal_callback_del(ed->obj, "focus,part,out,*",
3175 rp->part->name,
3176 _edje_entry_focus_out_cb);
3177 }
3178 #endif
3179 _compose_seq_reset(en);
3180
3181 free(en);
3182 }
3183
3184 void
_edje_entry_real_part_configure(Edje * ed,Edje_Real_Part * rp)3185 _edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp)
3186 {
3187 Evas_Coord x, y, w, h, xx, yy, ww, hh, xx2, yy2;
3188 Entry *en;
3189 Evas_Textblock_Cursor_Type cur_type;
3190 Eina_Bool bidi_cursor = EINA_FALSE;
3191
3192 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3193 (!rp->typedata.text)) return;
3194 en = rp->typedata.text->entry_data;
3195 if (!en) return;
3196
3197 _sel_update(ed, en->cursor, rp->object, en);
3198 _anchors_update_check(ed, rp);
3199 if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
3200 {
3201 switch (rp->part->cursor_mode)
3202 {
3203 case EDJE_ENTRY_CURSOR_MODE_BEFORE:
3204 cur_type = EVAS_TEXTBLOCK_CURSOR_BEFORE;
3205 break;
3206
3207 case EDJE_ENTRY_CURSOR_MODE_UNDER:
3208 /* no break for a reason */
3209 default:
3210 cur_type = EVAS_TEXTBLOCK_CURSOR_UNDER;
3211 }
3212 x = y = w = h = -1;
3213 xx = yy = ww = hh = -1;
3214 evas_object_geometry_get(rp->object, &x, &y, &w, &h);
3215 bidi_cursor = evas_textblock_cursor_geometry_bidi_get(en->cursor, &xx, &yy, &ww, &hh, &xx2, &yy2, NULL, NULL, cur_type);
3216 if (ww < 1) ww = 1;
3217 if (hh < 1) hh = 1;
3218 if (en->cursor_bg)
3219 {
3220 int bg_w = ww;
3221
3222 if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
3223 edje_object_size_min_restricted_calc(en->cursor_bg, &bg_w, NULL, ww, 0);
3224
3225 evas_object_move(en->cursor_bg, x + xx, y + yy);
3226 evas_object_resize(en->cursor_bg, bg_w, hh);
3227 }
3228 if (en->cursor_fg)
3229 {
3230 int fg_w = ww;
3231
3232 if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
3233 edje_object_size_min_restricted_calc(en->cursor_fg, &fg_w, NULL, ww, 0);
3234
3235 evas_object_move(en->cursor_fg, x + xx, y + yy);
3236
3237 if (bidi_cursor)
3238 {
3239 if (en->cursor_fg2)
3240 {
3241 evas_object_move(en->cursor_fg2, x + xx2, y + yy2 + (hh / 2));
3242 evas_object_resize(en->cursor_fg, fg_w, hh / 2);
3243 evas_object_resize(en->cursor_fg2, fg_w, hh / 2);
3244 evas_object_show(en->cursor_fg2);
3245 }
3246 }
3247 else
3248 {
3249 evas_object_resize(en->cursor_fg, fg_w, hh);
3250 if (en->cursor_fg2)
3251 evas_object_hide(en->cursor_fg2);
3252 }
3253 }
3254 }
3255 }
3256
3257 const char *
_edje_entry_selection_get(Edje_Real_Part * rp)3258 _edje_entry_selection_get(Edje_Real_Part *rp)
3259 {
3260 Entry *en;
3261
3262 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3263 (!rp->typedata.text)) return NULL;
3264 en = rp->typedata.text->entry_data;
3265 if (!en) return NULL;
3266 // get selection - convert to markup
3267 if ((!en->selection) && (en->have_selection))
3268 en->selection = evas_textblock_cursor_range_text_get
3269 (en->sel_start, en->sel_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
3270 return en->selection;
3271 }
3272
3273 const char *
_edje_entry_text_get(Edje_Real_Part * rp)3274 _edje_entry_text_get(Edje_Real_Part *rp)
3275 {
3276 Entry *en;
3277
3278 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3279 (!rp->typedata.text)) return NULL;
3280 en = rp->typedata.text->entry_data;
3281 if (!en) return NULL;
3282 // get text - convert to markup
3283 return evas_object_textblock_text_markup_get(rp->object);
3284 }
3285
3286 void
_edje_entry_text_markup_set(Edje_Real_Part * rp,const char * text)3287 _edje_entry_text_markup_set(Edje_Real_Part *rp, const char *text)
3288 {
3289 Entry *en;
3290 const char *ptext;
3291
3292 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3293 (!rp->typedata.text)) return;
3294 en = rp->typedata.text->entry_data;
3295 if (!en) return;
3296 ptext = evas_object_textblock_text_markup_get(rp->object);
3297 // some simple "do nothing if the text is the same" logic
3298 if (ptext == text) return;
3299 // if prev and cur is empty
3300 if (!ptext) ptext = "";
3301 if (!text) text = "";
3302 if ((!ptext[0]) && (!text[0])) return;
3303 // same content
3304 if (!strcmp(ptext, text)) return;
3305
3306 _edje_entry_imf_context_reset(rp);
3307 // set text as markup
3308 _sel_clear(en->ed, en->cursor, rp->object, en);
3309 evas_object_textblock_text_markup_set(rp->object, text);
3310 _edje_entry_set_cursor_start(rp);
3311
3312 _anchors_get(en->cursor, rp->object, en);
3313 _edje_emit(en->ed, "entry,changed", rp->part->name);
3314 _edje_entry_imf_cursor_info_set(en);
3315
3316 _edje_entry_real_part_configure(en->ed, rp);
3317 #if 0
3318 /* Don't emit cursor changed cause it didn't. It's just init to 0. */
3319 _edje_emit(en->ed, "cursor,changed", rp->part->name);
3320 #endif
3321 }
3322
3323 void
_edje_entry_text_markup_append(Edje_Real_Part * rp,const char * text)3324 _edje_entry_text_markup_append(Edje_Real_Part *rp, const char *text)
3325 {
3326 Entry *en;
3327
3328 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3329 (!rp->typedata.text)) return;
3330 en = rp->typedata.text->entry_data;
3331 Evas_Textblock_Cursor *end_cur;
3332 if (!en) return;
3333 end_cur = evas_object_textblock_cursor_new(rp->object);
3334 evas_textblock_cursor_paragraph_last(end_cur);
3335
3336 _text_filter_markup_prepend(en->ed, en, end_cur, text, NULL, NULL,
3337 EINA_TRUE, EINA_FALSE);
3338 evas_textblock_cursor_free(end_cur);
3339
3340 /* We are updating according to the real cursor on purpose */
3341 _anchors_get(en->cursor, rp->object, en);
3342 _edje_emit(en->ed, "entry,changed", rp->part->name);
3343
3344 _edje_entry_real_part_configure(en->ed, rp);
3345 }
3346
3347 void
_edje_entry_text_markup_insert(Edje_Real_Part * rp,const char * text)3348 _edje_entry_text_markup_insert(Edje_Real_Part *rp, const char *text)
3349 {
3350 Entry *en;
3351
3352 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3353 (!rp->typedata.text)) return;
3354 en = rp->typedata.text->entry_data;
3355 if (!en) return;
3356 _edje_entry_imf_context_reset(rp);
3357
3358 _text_filter_markup_prepend(en->ed, en, en->cursor, text, NULL, NULL,
3359 EINA_TRUE, EINA_FALSE);
3360 _anchors_get(en->cursor, rp->object, en);
3361 _edje_emit(en->ed, "entry,changed", rp->part->name);
3362 _edje_emit(en->ed, "cursor,changed", rp->part->name);
3363
3364 _edje_entry_imf_cursor_info_set(en);
3365 _edje_entry_real_part_configure(en->ed, rp);
3366 }
3367
3368 void
_edje_entry_set_cursor_start(Edje_Real_Part * rp)3369 _edje_entry_set_cursor_start(Edje_Real_Part *rp)
3370 {
3371 Entry *en;
3372
3373 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3374 (!rp->typedata.text)) return;
3375 en = rp->typedata.text->entry_data;
3376 if (!en) return;
3377 _curs_start(en->cursor, rp->object, en);
3378
3379 _edje_entry_imf_cursor_info_set(en);
3380 }
3381
3382 void
_edje_entry_set_cursor_end(Edje_Real_Part * rp)3383 _edje_entry_set_cursor_end(Edje_Real_Part *rp)
3384 {
3385 Entry *en;
3386
3387 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3388 (!rp->typedata.text)) return;
3389 en = rp->typedata.text->entry_data;
3390 if (!en) return;
3391 _curs_end(en->cursor, rp->object, en);
3392
3393 _edje_entry_imf_cursor_info_set(en);
3394 }
3395
3396 void
_edje_entry_select_none(Edje_Real_Part * rp)3397 _edje_entry_select_none(Edje_Real_Part *rp)
3398 {
3399 Entry *en;
3400
3401 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3402 (!rp->typedata.text)) return;
3403 en = rp->typedata.text->entry_data;
3404 if (!en) return;
3405 _sel_clear(en->ed, en->cursor, rp->object, en);
3406 }
3407
3408 void
_edje_entry_select_all(Edje_Real_Part * rp)3409 _edje_entry_select_all(Edje_Real_Part *rp)
3410 {
3411 Entry *en;
3412
3413 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3414 (!rp->typedata.text)) return;
3415 en = rp->typedata.text->entry_data;
3416 if (!en) return;
3417
3418 _edje_entry_imf_context_reset(rp);
3419
3420 _sel_clear(en->ed, en->cursor, rp->object, en);
3421 _curs_start(en->cursor, rp->object, en);
3422 _edje_entry_imf_context_reset(en->rp);
3423 _sel_start(en->cursor, rp->object, en);
3424 _curs_end(en->cursor, rp->object, en);
3425 _sel_extend(en->ed, en->cursor, rp->object, en);
3426
3427 _edje_entry_real_part_configure(en->ed, rp);
3428 }
3429
3430 void
_edje_entry_select_begin(Edje_Real_Part * rp)3431 _edje_entry_select_begin(Edje_Real_Part *rp)
3432 {
3433 Entry *en;
3434
3435 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3436 (!rp->typedata.text)) return;
3437 en = rp->typedata.text->entry_data;
3438 if (!en) return;
3439
3440 _sel_clear(en->ed, en->cursor, rp->object, en);
3441 _sel_enable(en->ed, en->cursor, rp->object, en);
3442 _sel_start(en->cursor, rp->object, en);
3443 _sel_extend(en->ed, en->cursor, rp->object, en);
3444
3445 _edje_entry_real_part_configure(en->ed, rp);
3446 }
3447
3448 void
_edje_entry_select_extend(Edje_Real_Part * rp)3449 _edje_entry_select_extend(Edje_Real_Part *rp)
3450 {
3451 Entry *en;
3452
3453 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3454 (!rp->typedata.text)) return;
3455 en = rp->typedata.text->entry_data;
3456 if (!en) return;
3457 _sel_extend(en->ed, en->cursor, rp->object, en);
3458
3459 _edje_entry_real_part_configure(en->ed, rp);
3460 }
3461
3462 const Eina_List *
_edje_entry_anchor_geometry_get(Edje_Real_Part * rp,const char * anchor)3463 _edje_entry_anchor_geometry_get(Edje_Real_Part *rp, const char *anchor)
3464 {
3465 Entry *en;
3466 Eina_List *l;
3467 Anchor *an;
3468
3469 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3470 (!rp->typedata.text)) return NULL;
3471 en = rp->typedata.text->entry_data;
3472 if (!en) return NULL;
3473 /* Update the anchors first in case entry is not inside the canvas
3474 * viewport */
3475 _anchors_need_update(rp);
3476 EINA_LIST_FOREACH(en->anchors, l, an)
3477 {
3478 const char *n = an->name;
3479 if ((an->item) || (!n)) continue;
3480 if (!strcmp(anchor, n))
3481 return an->sel;
3482 }
3483 return NULL;
3484 }
3485
3486 const Eina_List *
_edje_entry_anchors_list(Edje_Real_Part * rp)3487 _edje_entry_anchors_list(Edje_Real_Part *rp)
3488 {
3489 Entry *en;
3490 Eina_List *l, *anchors = NULL;
3491 Anchor *an;
3492
3493 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3494 (!rp->typedata.text)) return NULL;
3495 en = rp->typedata.text->entry_data;
3496 if (!en) return NULL;
3497 /* Update the anchors first in case entry is not inside the canvas
3498 * viewport */
3499 _anchors_need_update(rp);
3500 if (!en->anchorlist)
3501 {
3502 EINA_LIST_FOREACH(en->anchors, l, an)
3503 {
3504 const char *n = an->name;
3505 if ((an->item) || (!n)) continue;
3506 anchors = eina_list_append(anchors, strdup(n));
3507 }
3508 en->anchorlist = anchors;
3509 }
3510 return en->anchorlist;
3511 }
3512
3513 Eina_Bool
_edje_entry_item_geometry_get(Edje_Real_Part * rp,const char * item,Evas_Coord * cx,Evas_Coord * cy,Evas_Coord * cw,Evas_Coord * ch)3514 _edje_entry_item_geometry_get(Edje_Real_Part *rp, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
3515 {
3516 Entry *en;
3517 Eina_List *l;
3518 Anchor *an;
3519
3520 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3521 (!rp->typedata.text)) return EINA_FALSE;
3522 en = rp->typedata.text->entry_data;
3523 if (!en) return EINA_FALSE;
3524 EINA_LIST_FOREACH(en->anchors, l, an)
3525 {
3526 const char *n = an->name;
3527 if (!an->item) continue;
3528 if (!n) n = "";
3529 if (!strcmp(item, n))
3530 {
3531 evas_textblock_cursor_format_item_geometry_get(an->start, cx, cy, cw, ch);
3532 return EINA_TRUE;
3533 }
3534 }
3535 return EINA_FALSE;
3536 }
3537
3538 const Eina_List *
_edje_entry_items_list(Edje_Real_Part * rp)3539 _edje_entry_items_list(Edje_Real_Part *rp)
3540 {
3541 Entry *en;
3542 Eina_List *l, *items = NULL;
3543 Anchor *an;
3544
3545 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3546 (!rp->typedata.text)) return NULL;
3547 en = rp->typedata.text->entry_data;
3548 if (!en) return NULL;
3549 /* Update the anchors first in case entry is not inside the canvas
3550 * viewport */
3551 _anchors_need_update(rp);
3552 if (!en->itemlist)
3553 {
3554 EINA_LIST_FOREACH(en->anchors, l, an)
3555 {
3556 const char *n = an->name;
3557 if (!an->item) continue;
3558 if (!n) n = "";
3559 items = eina_list_append(items, strdup(n));
3560 }
3561 en->itemlist = items;
3562 }
3563 return en->itemlist;
3564 }
3565
3566 void
_edje_entry_cursor_geometry_get(Edje_Real_Part * rp,Evas_Coord * cx,Evas_Coord * cy,Evas_Coord * cw,Evas_Coord * ch,Evas_BiDi_Direction * cdir)3567 _edje_entry_cursor_geometry_get(Edje_Real_Part *rp, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *cdir)
3568 {
3569 Evas_Coord x, y, w, h, xx, yy, ww, hh;
3570 Entry *en;
3571 Evas_Textblock_Cursor_Type cur_type;
3572 Evas_BiDi_Direction dir;
3573
3574 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3575 (!rp->typedata.text)) return;
3576 en = rp->typedata.text->entry_data;
3577 if (!en) return;
3578 switch (rp->part->cursor_mode)
3579 {
3580 case EDJE_ENTRY_CURSOR_MODE_BEFORE:
3581 cur_type = EVAS_TEXTBLOCK_CURSOR_BEFORE;
3582 break;
3583
3584 case EDJE_ENTRY_CURSOR_MODE_UNDER:
3585 /* no break for a reason */
3586 default:
3587 cur_type = EVAS_TEXTBLOCK_CURSOR_UNDER;
3588 }
3589
3590 x = y = w = h = -1;
3591 xx = yy = ww = hh = -1;
3592 evas_object_geometry_get(rp->object, &x, &y, &w, &h);
3593 evas_textblock_cursor_geometry_get(en->cursor, &xx, &yy, &ww, &hh, &dir, cur_type);
3594 if (ww < 1) ww = 1;
3595 if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
3596 edje_object_size_min_restricted_calc(en->cursor_fg, &ww, NULL, ww, 0);
3597 if (hh < 1) hh = 1;
3598 if (cx) *cx = x + xx;
3599 if (cy) *cy = y + yy;
3600 if (cw) *cw = ww;
3601 if (ch) *ch = hh;
3602 if (cdir) *cdir = dir;
3603 }
3604
3605 void
_edje_entry_user_insert(Edje_Real_Part * rp,const char * text)3606 _edje_entry_user_insert(Edje_Real_Part *rp, const char *text)
3607 {
3608 Entry *en;
3609 Edje_Entry_Change_Info *info;
3610
3611 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3612 (!rp->typedata.text)) return;
3613 en = rp->typedata.text->entry_data;
3614 if (!en) return;
3615 _edje_entry_imf_context_reset(rp);
3616 info = _text_filter_markup_prepend(en->ed, en, en->cursor, text, NULL, NULL,
3617 EINA_TRUE, EINA_TRUE);
3618 _anchors_get(en->cursor, rp->object, en);
3619 if (info)
3620 {
3621 _edje_emit(en->ed, "entry,changed", rp->part->name);
3622 _edje_emit_full(en->ed, "entry,changed,user", rp->part->name,
3623 info, _free_entry_change_info);
3624 _edje_emit(en->ed, "cursor,changed", rp->part->name);
3625 }
3626
3627 _edje_entry_imf_cursor_info_set(en);
3628 _edje_entry_real_part_configure(en->ed, rp);
3629 }
3630
3631 void
_edje_entry_select_allow_set(Edje_Real_Part * rp,Eina_Bool allow)3632 _edje_entry_select_allow_set(Edje_Real_Part *rp, Eina_Bool allow)
3633 {
3634 Entry *en;
3635
3636 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3637 (!rp->typedata.text)) return;
3638 en = rp->typedata.text->entry_data;
3639 if (!en) return;
3640
3641 en->select_allow = allow;
3642 }
3643
3644 Eina_Bool
_edje_entry_select_allow_get(const Edje_Real_Part * rp)3645 _edje_entry_select_allow_get(const Edje_Real_Part *rp)
3646 {
3647 Entry *en;
3648
3649 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3650 (!rp->typedata.text)) return EINA_FALSE;
3651 en = rp->typedata.text->entry_data;
3652 if (!en) return EINA_FALSE;
3653 return en->select_allow;
3654 }
3655
3656 void
_edje_entry_select_abort(Edje_Real_Part * rp)3657 _edje_entry_select_abort(Edje_Real_Part *rp)
3658 {
3659 Entry *en;
3660
3661 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3662 (!rp->typedata.text)) return;
3663 en = rp->typedata.text->entry_data;
3664 if (!en) return;
3665 if (en->selecting)
3666 {
3667 en->selecting = EINA_FALSE;
3668
3669 _edje_entry_imf_context_reset(rp);
3670 _edje_entry_imf_cursor_info_set(en);
3671 _edje_entry_real_part_configure(en->ed, rp);
3672 }
3673 }
3674
3675 void *
_edje_entry_imf_context_get(Edje_Real_Part * rp)3676 _edje_entry_imf_context_get(Edje_Real_Part *rp)
3677 {
3678 #ifdef HAVE_ECORE_IMF
3679 Entry *en;
3680
3681 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3682 (!rp->typedata.text)) return NULL;
3683 en = rp->typedata.text->entry_data;
3684 if (!en) return NULL;
3685
3686 return en->imf_context;
3687 #else
3688 return NULL;
3689 (void)rp;
3690 #endif
3691 }
3692
3693 void
_edje_entry_autocapital_type_set(Edje_Real_Part * rp,Edje_Text_Autocapital_Type autocapital_type)3694 _edje_entry_autocapital_type_set(Edje_Real_Part *rp, Edje_Text_Autocapital_Type autocapital_type)
3695 {
3696 #ifdef HAVE_ECORE_IMF
3697 Entry *en;
3698
3699 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3700 (!rp->typedata.text)) return;
3701 en = rp->typedata.text->entry_data;
3702 if (!en) return;
3703
3704 if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
3705 autocapital_type = EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
3706
3707 if (en->imf_context)
3708 ecore_imf_context_autocapital_type_set(en->imf_context, (Ecore_IMF_Autocapital_Type)autocapital_type);
3709 #else
3710 (void)rp;
3711 (void)autocapital_type;
3712 #endif
3713 }
3714
3715 Edje_Text_Autocapital_Type
_edje_entry_autocapital_type_get(Edje_Real_Part * rp)3716 _edje_entry_autocapital_type_get(Edje_Real_Part *rp)
3717 {
3718 #ifdef HAVE_ECORE_IMF
3719 Entry *en;
3720
3721 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3722 (!rp->typedata.text)) return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
3723 en = rp->typedata.text->entry_data;
3724 if (!en) return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
3725
3726 if (en->imf_context)
3727 return (Edje_Text_Autocapital_Type)ecore_imf_context_autocapital_type_get(en->imf_context);
3728 return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
3729 #else
3730 return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
3731 (void)rp;
3732 #endif
3733 }
3734
3735 void
_edje_entry_prediction_allow_set(Edje_Real_Part * rp,Eina_Bool prediction)3736 _edje_entry_prediction_allow_set(Edje_Real_Part *rp, Eina_Bool prediction)
3737 {
3738 Entry *en;
3739
3740 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3741 (!rp->typedata.text)) return;
3742 en = rp->typedata.text->entry_data;
3743 if (!en) return;
3744 en->prediction_allow = prediction;
3745 #ifdef HAVE_ECORE_IMF
3746 if (en->imf_context)
3747 ecore_imf_context_prediction_allow_set(en->imf_context, prediction);
3748 #endif
3749 }
3750
3751 Eina_Bool
_edje_entry_prediction_allow_get(Edje_Real_Part * rp)3752 _edje_entry_prediction_allow_get(Edje_Real_Part *rp)
3753 {
3754 Entry *en;
3755
3756 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3757 (!rp->typedata.text)) return EINA_FALSE;
3758 en = rp->typedata.text->entry_data;
3759 if (!en) return EINA_FALSE;
3760 return en->prediction_allow;
3761 }
3762
3763 void
_edje_entry_input_hint_set(Edje_Real_Part * rp,Edje_Input_Hints input_hints)3764 _edje_entry_input_hint_set(Edje_Real_Part *rp, Edje_Input_Hints input_hints)
3765 {
3766 Entry *en;
3767
3768 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3769 (!rp->typedata.text)) return;
3770 en = rp->typedata.text->entry_data;
3771 if (!en) return;
3772 #ifdef HAVE_ECORE_IMF
3773 if (en->imf_context)
3774 ecore_imf_context_input_hint_set(en->imf_context, (Ecore_IMF_Input_Hints)input_hints);
3775 #else
3776 (void)input_hints;
3777 #endif
3778 }
3779
3780 Edje_Input_Hints
_edje_entry_input_hint_get(const Edje_Real_Part * rp)3781 _edje_entry_input_hint_get(const Edje_Real_Part *rp)
3782 {
3783 Entry *en;
3784
3785 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3786 (!rp->typedata.text)) return EDJE_INPUT_HINT_NONE;
3787 en = rp->typedata.text->entry_data;
3788 if (!en) return EDJE_INPUT_HINT_NONE;
3789 #ifdef HAVE_ECORE_IMF
3790 if (en->imf_context)
3791 return (Edje_Input_Hints)ecore_imf_context_input_hint_get(en->imf_context);
3792 #endif
3793
3794 return EDJE_INPUT_HINT_NONE;
3795 }
3796
3797 void
_edje_entry_input_panel_enabled_set(Edje_Real_Part * rp,Eina_Bool enabled)3798 _edje_entry_input_panel_enabled_set(Edje_Real_Part *rp, Eina_Bool enabled)
3799 {
3800 Entry *en;
3801
3802 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3803 (!rp->typedata.text)) return;
3804 en = rp->typedata.text->entry_data;
3805 if (!en) return;
3806 en->input_panel_enable = enabled;
3807 #ifdef HAVE_ECORE_IMF
3808 if (en->imf_context)
3809 ecore_imf_context_input_panel_enabled_set(en->imf_context, enabled);
3810 #endif
3811 }
3812
3813 Eina_Bool
_edje_entry_input_panel_enabled_get(Edje_Real_Part * rp)3814 _edje_entry_input_panel_enabled_get(Edje_Real_Part *rp)
3815 {
3816 Entry *en;
3817
3818 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3819 (!rp->typedata.text)) return EINA_FALSE;
3820 en = rp->typedata.text->entry_data;
3821 if (!en) return EINA_FALSE;
3822 return en->input_panel_enable;
3823 }
3824
3825 void
_edje_entry_input_panel_show(Edje_Real_Part * rp)3826 _edje_entry_input_panel_show(Edje_Real_Part *rp)
3827 {
3828 #ifdef HAVE_ECORE_IMF
3829 Entry *en;
3830
3831 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3832 (!rp->typedata.text)) return;
3833 en = rp->typedata.text->entry_data;
3834 if (!en) return;
3835 if (en->imf_context)
3836 ecore_imf_context_input_panel_show(en->imf_context);
3837 #else
3838 (void)rp;
3839 #endif
3840 }
3841
3842 void
_edje_entry_input_panel_hide(Edje_Real_Part * rp)3843 _edje_entry_input_panel_hide(Edje_Real_Part *rp)
3844 {
3845 #ifdef HAVE_ECORE_IMF
3846 Entry *en;
3847
3848 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3849 (!rp->typedata.text)) return;
3850 en = rp->typedata.text->entry_data;
3851 if (!en) return;
3852 if (en->imf_context)
3853 ecore_imf_context_input_panel_hide(en->imf_context);
3854 #else
3855 (void)rp;
3856 #endif
3857 }
3858
3859 void
_edje_entry_input_panel_language_set(Edje_Real_Part * rp,Edje_Input_Panel_Lang lang)3860 _edje_entry_input_panel_language_set(Edje_Real_Part *rp, Edje_Input_Panel_Lang lang)
3861 {
3862 Entry *en;
3863
3864 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3865 (!rp->typedata.text)) return;
3866 en = rp->typedata.text->entry_data;
3867 if (!en) return;
3868 en->input_panel_lang = lang;
3869 #ifdef HAVE_ECORE_IMF
3870 if (en->imf_context)
3871 ecore_imf_context_input_panel_language_set(en->imf_context, (Ecore_IMF_Input_Panel_Lang)lang);
3872 #endif
3873 }
3874
3875 Edje_Input_Panel_Lang
_edje_entry_input_panel_language_get(Edje_Real_Part * rp)3876 _edje_entry_input_panel_language_get(Edje_Real_Part *rp)
3877 {
3878 Entry *en;
3879
3880 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3881 (!rp->typedata.text)) return EDJE_INPUT_PANEL_LANG_AUTOMATIC;
3882 en = rp->typedata.text->entry_data;
3883 if (!en) return EDJE_INPUT_PANEL_LANG_AUTOMATIC;
3884 return en->input_panel_lang;
3885 }
3886
3887 void
_edje_entry_input_panel_imdata_set(Edje_Real_Part * rp,const void * data,int len)3888 _edje_entry_input_panel_imdata_set(Edje_Real_Part *rp, const void *data, int len)
3889 {
3890 #ifdef HAVE_ECORE_IMF
3891 Entry *en;
3892
3893 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3894 (!rp->typedata.text)) return;
3895 en = rp->typedata.text->entry_data;
3896 if (!en) return;
3897 if (en->imf_context)
3898 ecore_imf_context_input_panel_imdata_set(en->imf_context, data, len);
3899 #else
3900 (void)rp;
3901 (void)data;
3902 (void)len;
3903 #endif
3904 }
3905
3906 void
_edje_entry_input_panel_imdata_get(Edje_Real_Part * rp,void * data,int * len)3907 _edje_entry_input_panel_imdata_get(Edje_Real_Part *rp, void *data, int *len)
3908 {
3909 #ifdef HAVE_ECORE_IMF
3910 Entry *en;
3911
3912 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3913 (!rp->typedata.text)) return;
3914 en = rp->typedata.text->entry_data;
3915 if (!en) return;
3916 if (en->imf_context)
3917 ecore_imf_context_input_panel_imdata_get(en->imf_context, data, len);
3918 #else
3919 (void)rp;
3920 (void)data;
3921 (void)len;
3922 #endif
3923 }
3924
3925 void
_edje_entry_input_panel_return_key_type_set(Edje_Real_Part * rp,Edje_Input_Panel_Return_Key_Type return_key_type)3926 _edje_entry_input_panel_return_key_type_set(Edje_Real_Part *rp, Edje_Input_Panel_Return_Key_Type return_key_type)
3927 {
3928 #ifdef HAVE_ECORE_IMF
3929 Entry *en;
3930
3931 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3932 (!rp->typedata.text)) return;
3933 en = rp->typedata.text->entry_data;
3934 if (!en) return;
3935 if (en->imf_context)
3936 ecore_imf_context_input_panel_return_key_type_set(en->imf_context, (Ecore_IMF_Input_Panel_Return_Key_Type)return_key_type);
3937 #else
3938 (void)rp;
3939 (void)return_key_type;
3940 #endif
3941 }
3942
3943 Edje_Input_Panel_Return_Key_Type
_edje_entry_input_panel_return_key_type_get(Edje_Real_Part * rp)3944 _edje_entry_input_panel_return_key_type_get(Edje_Real_Part *rp)
3945 {
3946 #ifdef HAVE_ECORE_IMF
3947 Entry *en;
3948
3949 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3950 (!rp->typedata.text)) return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
3951 en = rp->typedata.text->entry_data;
3952 if (!en) return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
3953 if (en->imf_context)
3954 return (Edje_Input_Panel_Return_Key_Type)ecore_imf_context_input_panel_return_key_type_get(en->imf_context);
3955 return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
3956 #else
3957 return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
3958 (void)rp;
3959 #endif
3960 }
3961
3962 void
_edje_entry_input_panel_return_key_disabled_set(Edje_Real_Part * rp,Eina_Bool disabled)3963 _edje_entry_input_panel_return_key_disabled_set(Edje_Real_Part *rp, Eina_Bool disabled)
3964 {
3965 #ifdef HAVE_ECORE_IMF
3966 Entry *en;
3967
3968 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3969 (!rp->typedata.text)) return;
3970 en = rp->typedata.text->entry_data;
3971 if (!en) return;
3972 if (en->imf_context)
3973 ecore_imf_context_input_panel_return_key_disabled_set(en->imf_context, disabled);
3974 #else
3975 (void)rp;
3976 (void)disabled;
3977 #endif
3978 }
3979
3980 Eina_Bool
_edje_entry_input_panel_return_key_disabled_get(Edje_Real_Part * rp)3981 _edje_entry_input_panel_return_key_disabled_get(Edje_Real_Part *rp)
3982 {
3983 #ifdef HAVE_ECORE_IMF
3984 Entry *en;
3985
3986 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
3987 (!rp->typedata.text)) return EINA_FALSE;
3988 en = rp->typedata.text->entry_data;
3989 if (!en) return EINA_FALSE;
3990 if (en->imf_context)
3991 return ecore_imf_context_input_panel_return_key_disabled_get(en->imf_context);
3992 return EINA_FALSE;
3993 #else
3994 return EINA_FALSE;
3995 (void)rp;
3996 #endif
3997 }
3998
3999 #ifdef HAVE_ECORE_IMF
4000 void
_edje_entry_input_panel_show_on_demand_set(Edje_Real_Part * rp,Eina_Bool ondemand)4001 _edje_entry_input_panel_show_on_demand_set(Edje_Real_Part *rp, Eina_Bool ondemand)
4002 #else
4003 void
4004 _edje_entry_input_panel_show_on_demand_set(Edje_Real_Part *rp, Eina_Bool ondemand EINA_UNUSED)
4005 #endif
4006 {
4007 Entry *en;
4008
4009 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4010 (!rp->typedata.text)) return;
4011 en = rp->typedata.text->entry_data;
4012 if (!en) return;
4013 #ifdef HAVE_ECORE_IMF
4014 if (en->imf_context)
4015 ecore_imf_context_input_panel_show_on_demand_set(en->imf_context, ondemand);
4016 #endif
4017 }
4018
4019 Eina_Bool
_edje_entry_input_panel_show_on_demand_get(Edje_Real_Part * rp)4020 _edje_entry_input_panel_show_on_demand_get(Edje_Real_Part *rp)
4021 {
4022 Entry *en;
4023
4024 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4025 (!rp->typedata.text)) return EINA_FALSE;
4026 en = rp->typedata.text->entry_data;
4027 if (!en) return EINA_FALSE;
4028 #ifdef HAVE_ECORE_IMF
4029 if (en->imf_context)
4030 {
4031 Eina_Bool ret = ecore_imf_context_input_panel_show_on_demand_get(en->imf_context);
4032 return ret;
4033 }
4034 #endif
4035 return EINA_FALSE;
4036 }
4037
4038 static Evas_Textblock_Cursor *
_cursor_get(Edje_Real_Part * rp,Edje_Cursor cur)4039 _cursor_get(Edje_Real_Part *rp, Edje_Cursor cur)
4040 {
4041 Entry *en;
4042
4043 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4044 (!rp->typedata.text)) return NULL;
4045 en = rp->typedata.text->entry_data;
4046 if (!en) return NULL;
4047 switch (cur)
4048 {
4049 case EDJE_CURSOR_MAIN:
4050 return en->cursor;
4051
4052 case EDJE_CURSOR_SELECTION_BEGIN:
4053 return en->sel_start;
4054
4055 case EDJE_CURSOR_SELECTION_END:
4056 return en->sel_end;
4057
4058 case EDJE_CURSOR_PREEDIT_START:
4059 if (!en->preedit_start)
4060 en->preedit_start = evas_object_textblock_cursor_new(rp->object);
4061 return en->preedit_start;
4062
4063 case EDJE_CURSOR_PREEDIT_END:
4064 if (!en->preedit_end)
4065 en->preedit_end = evas_object_textblock_cursor_new(rp->object);
4066 return en->preedit_end;
4067
4068 case EDJE_CURSOR_USER:
4069 if (!en->cursor_user)
4070 en->cursor_user = evas_object_textblock_cursor_new(rp->object);
4071 return en->cursor_user;
4072
4073 case EDJE_CURSOR_USER_EXTRA:
4074 if (!en->cursor_user_extra)
4075 en->cursor_user_extra = evas_object_textblock_cursor_new(rp->object);
4076 return en->cursor_user_extra;
4077
4078 default:
4079 break;
4080 }
4081 return NULL;
4082 }
4083
4084 Eina_Bool
_edje_text_cursor_next(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4085 _edje_text_cursor_next(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4086 {
4087 Entry *en;
4088
4089 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4090 (!rp->typedata.text)) return EINA_FALSE;
4091 en = rp->typedata.text->entry_data;
4092 if (!en) return EINA_FALSE;
4093
4094 if (!c) return EINA_FALSE;
4095
4096 _edje_entry_imf_context_reset(rp);
4097
4098 if (!evas_textblock_cursor_cluster_next(c))
4099 {
4100 return EINA_FALSE;
4101 }
4102 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4103 _edje_entry_imf_cursor_info_set(en);
4104
4105 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4106 _edje_entry_real_part_configure(en->ed, rp);
4107 return EINA_TRUE;
4108 }
4109
4110 Eina_Bool
_edje_entry_cursor_next(Edje_Real_Part * rp,Edje_Cursor cur)4111 _edje_entry_cursor_next(Edje_Real_Part *rp, Edje_Cursor cur)
4112 {
4113 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4114 return _edje_text_cursor_next(rp, c);
4115 }
4116
4117
4118 Eina_Bool
_edje_text_cursor_prev(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4119 _edje_text_cursor_prev(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4120 {
4121 Entry *en;
4122
4123 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4124 (!rp->typedata.text)) return EINA_FALSE;
4125 en = rp->typedata.text->entry_data;
4126 if (!en) return EINA_FALSE;
4127 if (!c) return EINA_FALSE;
4128
4129 _edje_entry_imf_context_reset(rp);
4130
4131 if (!evas_textblock_cursor_cluster_prev(c))
4132 {
4133 if (evas_textblock_cursor_paragraph_prev(c)) goto ok;
4134 else return EINA_FALSE;
4135 }
4136 ok:
4137 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4138
4139 _edje_entry_imf_cursor_info_set(en);
4140
4141 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4142 _edje_entry_real_part_configure(en->ed, rp);
4143 return EINA_TRUE;
4144 }
4145
4146 Eina_Bool
_edje_entry_cursor_prev(Edje_Real_Part * rp,Edje_Cursor cur)4147 _edje_entry_cursor_prev(Edje_Real_Part *rp, Edje_Cursor cur)
4148 {
4149 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4150 return _edje_text_cursor_prev(rp, c);
4151 }
4152
4153 Eina_Bool
_edje_text_cursor_up(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4154 _edje_text_cursor_up(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4155 {
4156 Entry *en;
4157 Evas_Coord lx, ly, lw, lh, cx, cy, cw, ch;
4158 int ln;
4159
4160 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4161 (!rp->typedata.text)) return EINA_FALSE;
4162 en = rp->typedata.text->entry_data;
4163 if (!en) return EINA_FALSE;
4164 if (!c) return EINA_FALSE;
4165
4166 _edje_entry_imf_context_reset(rp);
4167
4168 ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
4169 ln--;
4170 if (ln < 0) return EINA_FALSE;
4171 if (!evas_object_textblock_line_number_geometry_get(rp->object, ln,
4172 &lx, &ly, &lw, &lh))
4173 return EINA_FALSE;
4174 evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
4175 if (!evas_textblock_cursor_cluster_coord_set(c, cx, ly + (lh / 2)))
4176 evas_textblock_cursor_line_char_last(c);
4177 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4178
4179 _edje_entry_imf_cursor_info_set(en);
4180
4181 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4182 _edje_entry_real_part_configure(en->ed, rp);
4183 return EINA_TRUE;
4184 }
4185
4186 Eina_Bool
_edje_entry_cursor_up(Edje_Real_Part * rp,Edje_Cursor cur)4187 _edje_entry_cursor_up(Edje_Real_Part *rp, Edje_Cursor cur)
4188 {
4189 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4190 return _edje_text_cursor_up(rp, c);
4191 }
4192
4193 Eina_Bool
_edje_text_cursor_down(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4194 _edje_text_cursor_down(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4195 {
4196 Entry *en;
4197 Evas_Coord lx, ly, lw, lh, cx, cy, cw, ch;
4198 int ln;
4199
4200 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4201 (!rp->typedata.text)) return EINA_FALSE;
4202 en = rp->typedata.text->entry_data;
4203 if (!en) return EINA_FALSE;
4204 if (!c) return EINA_FALSE;
4205
4206 _edje_entry_imf_context_reset(rp);
4207
4208 ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
4209 ln++;
4210 if (!evas_object_textblock_line_number_geometry_get(rp->object, ln,
4211 &lx, &ly, &lw, &lh))
4212 return EINA_FALSE;
4213 evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
4214 if (!evas_textblock_cursor_cluster_coord_set(c, cx, ly + (lh / 2)))
4215 evas_textblock_cursor_line_char_last(c);
4216
4217 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4218
4219 _edje_entry_imf_cursor_info_set(en);
4220 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4221 _edje_entry_real_part_configure(en->ed, rp);
4222 return EINA_TRUE;
4223 }
4224
4225 Eina_Bool
_edje_entry_cursor_down(Edje_Real_Part * rp,Edje_Cursor cur)4226 _edje_entry_cursor_down(Edje_Real_Part *rp, Edje_Cursor cur)
4227 {
4228 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4229 return _edje_text_cursor_down(rp, c);
4230 }
4231
4232 void
_edje_text_cursor_begin(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4233 _edje_text_cursor_begin(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4234 {
4235 Entry *en;
4236 int old_cur_pos;
4237
4238 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4239 (!rp->typedata.text)) return;
4240 en = rp->typedata.text->entry_data;
4241 if (!en) return;
4242 if (!c) return;
4243
4244 _edje_entry_imf_context_reset(rp);
4245
4246 old_cur_pos = evas_textblock_cursor_pos_get(c);
4247 evas_textblock_cursor_paragraph_first(c);
4248
4249 if (old_cur_pos == evas_textblock_cursor_pos_get(c))
4250 return;
4251
4252 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4253
4254 _edje_entry_imf_cursor_info_set(en);
4255 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4256 _edje_entry_real_part_configure(en->ed, rp);
4257 }
4258
4259 void
_edje_entry_cursor_begin(Edje_Real_Part * rp,Edje_Cursor cur)4260 _edje_entry_cursor_begin(Edje_Real_Part *rp, Edje_Cursor cur)
4261 {
4262 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4263 _edje_text_cursor_begin(rp, c);
4264
4265 }
4266
4267 void
_edje_text_cursor_end(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4268 _edje_text_cursor_end(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4269 {
4270 Entry *en;
4271 int old_cur_pos;
4272
4273 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4274 (!rp->typedata.text)) return;
4275 en = rp->typedata.text->entry_data;
4276 if (!en) return;
4277 if (!c) return;
4278
4279 _edje_entry_imf_context_reset(rp);
4280
4281 old_cur_pos = evas_textblock_cursor_pos_get(c);
4282 _curs_end(c, rp->object, rp->typedata.text->entry_data);
4283
4284 if (old_cur_pos == evas_textblock_cursor_pos_get(c))
4285 return;
4286
4287 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4288
4289 _edje_entry_imf_cursor_info_set(en);
4290
4291 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4292 _edje_entry_real_part_configure(en->ed, rp);
4293 }
4294 void
_edje_entry_cursor_end(Edje_Real_Part * rp,Edje_Cursor cur)4295 _edje_entry_cursor_end(Edje_Real_Part *rp, Edje_Cursor cur)
4296 {
4297 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4298 _edje_text_cursor_end(rp, c);
4299 }
4300
4301 void
_edje_text_cursor_copy(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * d,Efl_Text_Cursor_Handle * c)4302 _edje_text_cursor_copy(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *d, Efl_Text_Cursor_Handle *c)
4303 {
4304 Entry *en;
4305
4306 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4307 (!rp->typedata.text)) return;
4308 en = rp->typedata.text->entry_data;
4309 if (!en) return;
4310 evas_textblock_cursor_copy(c, d);
4311 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4312
4313 _edje_entry_imf_context_reset(rp);
4314 _edje_entry_imf_cursor_info_set(en);
4315 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4316 _edje_entry_real_part_configure(en->ed, rp);
4317 }
4318
4319 void
_edje_entry_cursor_copy(Edje_Real_Part * rp,Edje_Cursor cur,Edje_Cursor dst)4320 _edje_entry_cursor_copy(Edje_Real_Part *rp, Edje_Cursor cur, Edje_Cursor dst)
4321 {
4322 Evas_Textblock_Cursor *c;
4323 Evas_Textblock_Cursor *d;
4324 c = _cursor_get(rp, cur);
4325 if (!c) return;
4326 d = _cursor_get(rp, dst);
4327 if (!d) return;
4328 _edje_text_cursor_copy(rp, d, c);
4329 }
4330
4331 void
_edje_text_cursor_line_begin(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4332 _edje_text_cursor_line_begin(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4333 {
4334 Entry *en;
4335 int old_cur_pos;
4336
4337 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4338 (!rp->typedata.text)) return;
4339 en = rp->typedata.text->entry_data;
4340 if (!en) return;
4341 if (!c) return;
4342 _edje_entry_imf_context_reset(rp);
4343
4344 old_cur_pos = evas_textblock_cursor_pos_get(c);
4345 evas_textblock_cursor_line_char_first(c);
4346
4347 if (old_cur_pos == evas_textblock_cursor_pos_get(c))
4348 return;
4349
4350 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4351
4352 _edje_entry_imf_cursor_info_set(en);
4353
4354 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4355 _edje_entry_real_part_configure(en->ed, rp);
4356 }
4357
4358 void
_edje_entry_cursor_line_begin(Edje_Real_Part * rp,Edje_Cursor cur)4359 _edje_entry_cursor_line_begin(Edje_Real_Part *rp, Edje_Cursor cur)
4360 {
4361 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4362 _edje_text_cursor_line_begin(rp, c);
4363 }
4364
4365 void
_edje_text_cursor_line_end(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c)4366 _edje_text_cursor_line_end(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c)
4367 {
4368 Entry *en;
4369 int old_cur_pos;
4370
4371 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4372 (!rp->typedata.text)) return;
4373 en = rp->typedata.text->entry_data;
4374 if (!en) return;
4375 if (!c) return;
4376 _edje_entry_imf_context_reset(rp);
4377
4378 old_cur_pos = evas_textblock_cursor_pos_get(c);
4379 evas_textblock_cursor_line_char_last(c);
4380
4381 if (old_cur_pos == evas_textblock_cursor_pos_get(c))
4382 return;
4383
4384 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4385
4386 _edje_entry_imf_cursor_info_set(en);
4387 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4388 _edje_entry_real_part_configure(en->ed, rp);
4389 }
4390
4391 void
_edje_entry_cursor_line_end(Edje_Real_Part * rp,Edje_Cursor cur)4392 _edje_entry_cursor_line_end(Edje_Real_Part *rp, Edje_Cursor cur)
4393 {
4394 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4395 _edje_text_cursor_line_end(rp, c);
4396 }
4397
4398 Eina_Bool
_edje_text_cursor_coord_set(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c,Evas_Coord x,Evas_Coord y)4399 _edje_text_cursor_coord_set(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c,
4400 Evas_Coord x, Evas_Coord y)
4401 {
4402 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4403 (!rp->typedata.text)) return EINA_FALSE;
4404 Entry *en = rp->typedata.text->entry_data;
4405 if (!en) return EINA_FALSE;
4406 if ((c == _cursor_get(rp, EDJE_CURSOR_SELECTION_BEGIN)) ||
4407 (c == _cursor_get(rp, EDJE_CURSOR_SELECTION_END)))
4408 {
4409 if (en->have_selection)
4410 {
4411 if (en->selection)
4412 {
4413 free(en->selection);
4414 en->selection = NULL;
4415 }
4416 _edje_emit(en->ed, "selection,changed", rp->part->name);
4417 }
4418 }
4419 return evas_textblock_cursor_cluster_coord_set(c, x, y);
4420 }
4421
4422 Eina_Bool
_edje_entry_cursor_coord_set(Edje_Real_Part * rp,Edje_Cursor cur,Evas_Coord x,Evas_Coord y)4423 _edje_entry_cursor_coord_set(Edje_Real_Part *rp, Edje_Cursor cur,
4424 Evas_Coord x, Evas_Coord y)
4425 {
4426 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4427 if (!c) return EINA_FALSE;
4428 return _edje_text_cursor_coord_set(rp, c, x, y);
4429 }
4430
4431 Eina_Bool
_edje_entry_cursor_is_format_get(Edje_Real_Part * rp,Edje_Cursor cur)4432 _edje_entry_cursor_is_format_get(Edje_Real_Part *rp, Edje_Cursor cur)
4433 {
4434 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4435 if (!c) return EINA_FALSE;
4436 if (evas_textblock_cursor_is_format(c)) return EINA_TRUE;
4437 return EINA_FALSE;
4438 }
4439
4440 Eina_Bool
_edje_entry_cursor_is_visible_format_get(Edje_Real_Part * rp,Edje_Cursor cur)4441 _edje_entry_cursor_is_visible_format_get(Edje_Real_Part *rp, Edje_Cursor cur)
4442 {
4443 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4444 if (!c) return EINA_FALSE;
4445 return evas_textblock_cursor_format_is_visible_get(c);
4446 }
4447
4448 char *
_edje_text_cursor_content_get(Edje_Real_Part * rp EINA_UNUSED,Efl_Text_Cursor_Handle * c)4449 _edje_text_cursor_content_get(Edje_Real_Part *rp EINA_UNUSED, Efl_Text_Cursor_Handle *c)
4450 {
4451 return evas_textblock_cursor_content_get(c);
4452 }
4453
4454 char *
_edje_entry_cursor_content_get(Edje_Real_Part * rp,Edje_Cursor cur)4455 _edje_entry_cursor_content_get(Edje_Real_Part *rp, Edje_Cursor cur)
4456 {
4457 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4458
4459 if (!c) return NULL;
4460
4461 return _edje_text_cursor_content_get(rp, c);
4462 }
4463
4464 void
_edje_text_cursor_pos_set(Edje_Real_Part * rp,Efl_Text_Cursor_Handle * c,int pos)4465 _edje_text_cursor_pos_set(Edje_Real_Part *rp, Efl_Text_Cursor_Handle *c, int pos)
4466 {
4467 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4468 (!rp->typedata.text)) return;
4469 Entry *en = rp->typedata.text->entry_data;
4470 if (!en) return;
4471 if (!c) return;
4472 /* Abort if cursor position didn't really change */
4473 if (evas_textblock_cursor_pos_get(c) == pos)
4474 return;
4475
4476 _edje_entry_imf_context_reset(rp);
4477 evas_textblock_cursor_pos_set(c, pos);
4478 _sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
4479
4480 _edje_entry_imf_cursor_info_set(en);
4481 _edje_emit(en->ed, "cursor,changed", rp->part->name);
4482 _edje_entry_real_part_configure(en->ed, rp);
4483 }
4484
4485 void
_edje_entry_cursor_pos_set(Edje_Real_Part * rp,Edje_Cursor cur,int pos)4486 _edje_entry_cursor_pos_set(Edje_Real_Part *rp, Edje_Cursor cur, int pos)
4487 {
4488 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4489
4490 _edje_text_cursor_pos_set(rp, c, pos);
4491 }
4492
4493 int
_edje_text_cursor_pos_get(Edje_Real_Part * rp EINA_UNUSED,Efl_Text_Cursor_Handle * c)4494 _edje_text_cursor_pos_get(Edje_Real_Part *rp EINA_UNUSED, Efl_Text_Cursor_Handle *c)
4495 {
4496 return evas_textblock_cursor_pos_get(c);
4497 }
4498
4499 int
_edje_entry_cursor_pos_get(Edje_Real_Part * rp,Edje_Cursor cur)4500 _edje_entry_cursor_pos_get(Edje_Real_Part *rp, Edje_Cursor cur)
4501 {
4502 Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
4503 if (!c) return 0;
4504 return _edje_text_cursor_pos_get(rp, c);
4505 }
4506
4507 void
_edje_entry_input_panel_layout_set(Edje_Real_Part * rp,Edje_Input_Panel_Layout layout)4508 _edje_entry_input_panel_layout_set(Edje_Real_Part *rp, Edje_Input_Panel_Layout layout)
4509 {
4510 #ifdef HAVE_ECORE_IMF
4511 Entry *en;
4512
4513 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4514 (!rp->typedata.text)) return;
4515 en = rp->typedata.text->entry_data;
4516 if (!en) return;
4517 if (en->imf_context)
4518 ecore_imf_context_input_panel_layout_set(en->imf_context, (Ecore_IMF_Input_Panel_Layout)layout);
4519 #else
4520 (void)rp;
4521 (void)layout;
4522 #endif
4523 }
4524
4525 Edje_Input_Panel_Layout
_edje_entry_input_panel_layout_get(Edje_Real_Part * rp)4526 _edje_entry_input_panel_layout_get(Edje_Real_Part *rp)
4527 {
4528 #ifdef HAVE_ECORE_IMF
4529 Entry *en;
4530
4531 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4532 (!rp->typedata.text)) return EDJE_INPUT_PANEL_LAYOUT_INVALID;
4533 en = rp->typedata.text->entry_data;
4534 if (!en) return EDJE_INPUT_PANEL_LAYOUT_INVALID;
4535 if (en->imf_context)
4536 return (Edje_Input_Panel_Layout)ecore_imf_context_input_panel_layout_get(en->imf_context);
4537 return EDJE_INPUT_PANEL_LAYOUT_INVALID;
4538 #else
4539 return EDJE_INPUT_PANEL_LAYOUT_INVALID;
4540 (void)rp;
4541 #endif
4542 }
4543
4544 void
_edje_entry_input_panel_layout_variation_set(Edje_Real_Part * rp,int variation)4545 _edje_entry_input_panel_layout_variation_set(Edje_Real_Part *rp, int variation)
4546 {
4547 Entry *en;
4548
4549 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4550 (!rp->typedata.text)) return;
4551 en = rp->typedata.text->entry_data;
4552 if (!en) return;
4553 #ifdef HAVE_ECORE_IMF
4554 if (en->imf_context)
4555 ecore_imf_context_input_panel_layout_variation_set(en->imf_context, variation);
4556 #else
4557 (void)variation;
4558 #endif
4559 }
4560
4561 int
_edje_entry_input_panel_layout_variation_get(Edje_Real_Part * rp)4562 _edje_entry_input_panel_layout_variation_get(Edje_Real_Part *rp)
4563 {
4564 Entry *en;
4565
4566 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4567 (!rp->typedata.text)) return 0;
4568 en = rp->typedata.text->entry_data;
4569 if (!en) return 0;
4570 #ifdef HAVE_ECORE_IMF
4571 if (en->imf_context)
4572 return ecore_imf_context_input_panel_layout_variation_get(en->imf_context);
4573 #endif
4574
4575 return 0;
4576 }
4577
4578 void
_edje_entry_imf_context_reset(Edje_Real_Part * rp)4579 _edje_entry_imf_context_reset(Edje_Real_Part *rp)
4580 {
4581 #ifdef HAVE_ECORE_IMF
4582 Entry *en;
4583
4584 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4585 (!rp->typedata.text)) return;
4586 en = rp->typedata.text->entry_data;
4587 if (!en) return;
4588 if (en->imf_context)
4589 ecore_imf_context_reset(en->imf_context);
4590 if (en->commit_cancel)
4591 en->commit_cancel = EINA_FALSE;
4592 #else
4593 (void)rp;
4594 #endif
4595 }
4596
4597 static void
_edje_entry_imf_cursor_location_set(Entry * en)4598 _edje_entry_imf_cursor_location_set(Entry *en)
4599 {
4600 #ifdef HAVE_ECORE_IMF
4601 Evas_Coord cx = 0, cy = 0, cw = 0, ch = 0;
4602 Evas_BiDi_Direction dir = 0;
4603 if (!en || !en->rp || !en->imf_context) return;
4604
4605 _edje_entry_cursor_geometry_get(en->rp, &cx, &cy, &cw, &ch, &dir);
4606 ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch);
4607 ecore_imf_context_bidi_direction_set(en->imf_context, (Ecore_IMF_BiDi_Direction)dir);
4608 #else
4609 (void)en;
4610 #endif
4611 }
4612
4613 static void
_edje_entry_imf_cursor_info_set(Entry * en)4614 _edje_entry_imf_cursor_info_set(Entry *en)
4615 {
4616 int cursor_pos;
4617
4618 #ifdef HAVE_ECORE_IMF
4619 if (!en || !en->rp || !en->imf_context) return;
4620
4621 if (en->have_selection)
4622 {
4623 if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
4624 cursor_pos = evas_textblock_cursor_pos_get(en->sel_start);
4625 else
4626 cursor_pos = evas_textblock_cursor_pos_get(en->sel_end);
4627 }
4628 else
4629 cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
4630
4631 ecore_imf_context_cursor_position_set(en->imf_context, cursor_pos);
4632
4633 _edje_entry_imf_cursor_location_set(en);
4634 #else
4635 (void)en;
4636 #endif
4637 }
4638
4639 void
_edje_entry_prediction_hint_set(Edje_Real_Part * rp,const char * prediction_hint)4640 _edje_entry_prediction_hint_set(Edje_Real_Part *rp, const char *prediction_hint)
4641 {
4642 Entry *en;
4643
4644 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4645 (!rp->typedata.text)) return;
4646 en = rp->typedata.text->entry_data;
4647 if (!en) return;
4648 #ifdef HAVE_ECORE_IMF
4649 if (en->imf_context)
4650 ecore_imf_context_prediction_hint_set(en->imf_context, prediction_hint);
4651 #else
4652 (void)prediction_hint;
4653 #endif
4654 }
4655
4656 Eina_Bool
_edje_entry_prediction_hint_hash_set(Edje_Real_Part * rp,const char * key,const char * value)4657 _edje_entry_prediction_hint_hash_set(Edje_Real_Part *rp, const char *key, const char *value)
4658 {
4659 Entry *en;
4660
4661 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4662 (!rp->typedata.text)) return EINA_FALSE;
4663 en = rp->typedata.text->entry_data;
4664 if (!en) return EINA_FALSE;
4665 #ifdef HAVE_ECORE_IMF
4666 if (en->imf_context)
4667 return ecore_imf_context_prediction_hint_hash_set(en->imf_context, key, value);
4668 #else
4669 (void)key;
4670 (void)value;
4671 #endif
4672
4673 return EINA_FALSE;
4674 }
4675
4676 Eina_Bool
_edje_entry_prediction_hint_hash_del(Edje_Real_Part * rp,const char * key)4677 _edje_entry_prediction_hint_hash_del(Edje_Real_Part *rp, const char *key)
4678 {
4679 Entry *en;
4680
4681 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4682 (!rp->typedata.text)) return EINA_FALSE;
4683 en = rp->typedata.text->entry_data;
4684 if (!en) return EINA_FALSE;
4685 #ifdef HAVE_ECORE_IMF
4686 if (en->imf_context)
4687 return ecore_imf_context_prediction_hint_hash_del(en->imf_context, key);
4688 #else
4689 (void)key;
4690 #endif
4691
4692 return EINA_FALSE;
4693 }
4694
4695 #ifdef HAVE_ECORE_IMF
4696
4697 static Edje_Real_Part *
_edje_entry_imf_default_focused_rp_get(Edje * ed)4698 _edje_entry_imf_default_focused_rp_get(Edje *ed)
4699 {
4700 Eina_Stringshare *seat_name;
4701 Efl_Input_Device *seat;
4702 Evas *e;
4703
4704 e = evas_object_evas_get(ed->obj);
4705 seat = evas_default_device_get(e, EVAS_DEVICE_CLASS_SEAT);
4706 seat_name = _edje_seat_name_get(ed, seat);
4707
4708 return _edje_focused_part_get(ed, seat_name);
4709 }
4710
4711 static Eina_Bool
_edje_entry_imf_retrieve_surrounding_cb(void * data,Ecore_IMF_Context * ctx EINA_UNUSED,char ** text,int * cursor_pos)4712 _edje_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text, int *cursor_pos)
4713 {
4714 Edje *ed = data;
4715 Edje_Real_Part *rp;
4716 Entry *en = NULL;
4717 const char *str;
4718 char *plain_text;
4719
4720 rp = _edje_entry_imf_default_focused_rp_get(ed);
4721 if (!rp) return EINA_FALSE;
4722 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4723 (!rp->typedata.text)) return EINA_FALSE;
4724 else
4725 en = rp->typedata.text->entry_data;
4726 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
4727 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
4728 return EINA_FALSE;
4729
4730 if (text)
4731 {
4732 str = _edje_entry_text_get(rp);
4733 if (str)
4734 {
4735 plain_text = evas_textblock_text_markup_to_utf8(NULL, str);
4736
4737 if (plain_text)
4738 {
4739 if (ecore_imf_context_input_hint_get(ctx) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA)
4740 {
4741 int idx = 0;
4742 char *itr = NULL;
4743 size_t len = eina_unicode_utf8_get_len(plain_text);
4744 char *u_text = (char *)malloc(len * sizeof(char) + 1);
4745 if (!u_text)
4746 {
4747 free(plain_text);
4748 return EINA_FALSE;
4749 }
4750
4751 itr = u_text;
4752 while (eina_unicode_utf8_next_get(plain_text, &idx))
4753 {
4754 *itr = '*';
4755 itr++;
4756 }
4757 *itr = 0;
4758
4759 free(plain_text);
4760 plain_text = strdup(u_text);
4761 free(u_text);
4762 u_text = NULL;
4763 }
4764
4765 *text = strdup(plain_text);
4766 free(plain_text);
4767 plain_text = NULL;
4768 }
4769 else
4770 {
4771 *text = strdup("");
4772 }
4773 }
4774 else
4775 {
4776 *text = strdup("");
4777 }
4778 }
4779
4780 if (cursor_pos)
4781 {
4782 if (en->have_selection && en->sel_start)
4783 *cursor_pos = evas_textblock_cursor_pos_get(en->sel_start);
4784 else if (en->cursor)
4785 *cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
4786 else
4787 *cursor_pos = 0;
4788 }
4789
4790 return EINA_TRUE;
4791 }
4792
4793 static void
_edje_entry_imf_event_commit_cb(void * data,Ecore_IMF_Context * ctx EINA_UNUSED,void * event_info)4794 _edje_entry_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
4795 {
4796 Edje *ed = data;
4797 Edje_Real_Part *rp;
4798 Entry *en = NULL;
4799 char *commit_str = event_info;
4800 Edje_Entry_Change_Info *info = NULL;
4801
4802 rp = _edje_entry_imf_default_focused_rp_get(ed);
4803 if ((!rp)) return;
4804 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4805 (!rp->typedata.text)) return;
4806 else
4807 en = rp->typedata.text->entry_data;
4808 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
4809 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
4810 return;
4811
4812 if (en->have_selection)
4813 {
4814 if (strcmp(commit_str, ""))
4815 {
4816 /* delete selected characters */
4817 _range_del_emit(ed, en->cursor, rp->object, en);
4818 _sel_clear(ed, en->cursor, rp->object, en);
4819 }
4820 }
4821
4822 /* delete preedit characters */
4823 _preedit_del(en);
4824 _preedit_clear(en);
4825
4826 // Skipping commit process when it is useless
4827 if (en->commit_cancel)
4828 {
4829 en->commit_cancel = EINA_FALSE;
4830 return;
4831 }
4832
4833 if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
4834 _edje_password_show_last)
4835 _edje_entry_hide_visible_password(ed, en->rp);
4836 if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
4837 _edje_password_show_last && (!en->preedit_start))
4838 {
4839 info = _text_filter_text_prepend(ed, en, en->cursor, commit_str,
4840 "+ password=off", "- password",
4841 EINA_TRUE, EINA_TRUE);
4842 if (info)
4843 {
4844 if (en->pw_timer)
4845 {
4846 ecore_timer_del(en->pw_timer);
4847 en->pw_timer = NULL;
4848 }
4849 if (_edje_password_show_last_timeout >= 0)
4850 en->pw_timer = ecore_timer_add
4851 (_edje_password_show_last_timeout,
4852 _password_timer_cb, en);
4853 }
4854 }
4855 else
4856 {
4857 info = _text_filter_text_prepend(ed, en, en->cursor, commit_str,
4858 NULL, NULL,
4859 EINA_TRUE, EINA_TRUE);
4860 }
4861
4862 _edje_entry_imf_cursor_info_set(en);
4863 _anchors_get(en->cursor, rp->object, en);
4864 if (info)
4865 {
4866 _edje_emit(ed, "entry,changed", rp->part->name);
4867 _edje_emit_full(ed, "entry,changed,user", rp->part->name,
4868 info, _free_entry_change_info);
4869 _edje_emit(ed, "cursor,changed", rp->part->name);
4870 }
4871 _edje_entry_imf_cursor_info_set(en);
4872 _edje_entry_real_part_configure(ed, rp);
4873 }
4874
4875 static int
_sort_cb(const void * a1,const void * a2)4876 _sort_cb(const void *a1, const void *a2)
4877 {
4878 Ecore_IMF_Preedit_Attr *attr1 = (Ecore_IMF_Preedit_Attr *)a1;
4879 Ecore_IMF_Preedit_Attr *attr2 = (Ecore_IMF_Preedit_Attr *)a2;
4880
4881 EINA_SAFETY_ON_NULL_RETURN_VAL(attr1, 0);
4882 EINA_SAFETY_ON_NULL_RETURN_VAL(attr2, 0);
4883
4884 if (attr1->start_index < attr2->start_index) return -1;
4885 else if (attr1->start_index == attr2->start_index) return 0;
4886 else return 1;
4887 }
4888
4889 static void
_edje_entry_imf_event_preedit_changed_cb(void * data,Ecore_IMF_Context * ctx EINA_UNUSED,void * event_info EINA_UNUSED)4890 _edje_entry_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info EINA_UNUSED)
4891 {
4892 Edje *ed = data;
4893 Edje_Real_Part *rp;
4894 Entry *en = NULL;
4895 Edje_Entry_Change_Info *info = NULL;
4896 int cursor_pos;
4897 int preedit_start_pos, preedit_end_pos;
4898 char *preedit_string;
4899 char *markup_txt = NULL;
4900 char *tagname[] = {
4901 NULL, "preedit",
4902 // XXX: FIXME: EFL2 - make these 2 preedit_sel's different for efl
4903 // 2.0 and beyond. maybe use "preedit_sel", "preedit_hilight",
4904 // See https://phab.enlightenment.org/D2980 for this issue
4905 "preedit_sel", "preedit_sel",
4906 "preedit_sub1", "preedit_sub2", "preedit_sub3", "preedit_sub4"
4907 };
4908 int i;
4909 size_t preedit_type_size = sizeof(tagname) / sizeof(tagname[0]);
4910 Eina_Bool preedit_end_state = EINA_FALSE;
4911 Eina_List *attrs = NULL, *l = NULL;
4912 Ecore_IMF_Preedit_Attr *attr;
4913 Eina_Strbuf *buf;
4914 Eina_Strbuf *preedit_attr_str;
4915
4916 rp = _edje_entry_imf_default_focused_rp_get(ed);
4917 if ((!rp)) return;
4918
4919 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
4920 (!rp->typedata.text)) return;
4921 else
4922 en = rp->typedata.text->entry_data;
4923 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
4924 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
4925 return;
4926
4927 if (!en->imf_context) return;
4928
4929 ecore_imf_context_preedit_string_with_attributes_get(en->imf_context,
4930 &preedit_string,
4931 &attrs, &cursor_pos);
4932 if (!preedit_string) return;
4933
4934 if (!strcmp(preedit_string, ""))
4935 preedit_end_state = EINA_TRUE;
4936
4937 if (en->have_selection && !preedit_end_state)
4938 _range_del_emit(ed, en->cursor, rp->object, en);
4939
4940 /* delete preedit characters */
4941 _preedit_del(en);
4942
4943 preedit_start_pos = evas_textblock_cursor_pos_get(en->cursor);
4944
4945 /* insert preedit character(s) */
4946 if (strlen(preedit_string) > 0)
4947 {
4948 buf = eina_strbuf_new();
4949 if (attrs)
4950 {
4951 attrs = eina_list_sort(attrs, 0, EINA_COMPARE_CB(_sort_cb));
4952
4953 EINA_LIST_FOREACH(attrs, l, attr)
4954 {
4955 if (attr->preedit_type < preedit_type_size)
4956 {
4957 preedit_attr_str = eina_strbuf_new();
4958 if (preedit_attr_str)
4959 {
4960 eina_strbuf_append_n(preedit_attr_str, preedit_string + attr->start_index, attr->end_index - attr->start_index);
4961 markup_txt = evas_textblock_text_utf8_to_markup(NULL, eina_strbuf_string_get(preedit_attr_str));
4962
4963 if (markup_txt)
4964 {
4965 if (tagname[attr->preedit_type])
4966 eina_strbuf_append_printf(buf, "<%s>%s</%s>", tagname[attr->preedit_type], markup_txt, tagname[attr->preedit_type]);
4967 else
4968 eina_strbuf_append_printf(buf, "%s", markup_txt);
4969 free(markup_txt);
4970 }
4971 eina_strbuf_free(preedit_attr_str);
4972 }
4973 }
4974 else
4975 eina_strbuf_append(buf, preedit_string);
4976 }
4977 }
4978 else
4979 {
4980 eina_strbuf_append(buf, preedit_string);
4981 }
4982
4983 // For skipping useless commit
4984 if (!preedit_end_state)
4985 en->have_preedit = EINA_TRUE;
4986
4987 if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
4988 _edje_password_show_last)
4989 {
4990 _edje_entry_hide_visible_password(ed, en->rp);
4991 info = _text_filter_markup_prepend(ed, en, en->cursor,
4992 eina_strbuf_string_get(buf),
4993 "+ password=off",
4994 "- password",
4995 EINA_TRUE, EINA_TRUE);
4996 if (info)
4997 {
4998 if (en->pw_timer)
4999 {
5000 ecore_timer_del(en->pw_timer);
5001 en->pw_timer = NULL;
5002 }
5003 if (_edje_password_show_last_timeout >= 0)
5004 en->pw_timer = ecore_timer_add
5005 (_edje_password_show_last_timeout,
5006 _password_timer_cb, en);
5007 }
5008 }
5009 else
5010 info = _text_filter_markup_prepend(ed, en, en->cursor,
5011 eina_strbuf_string_get(buf),
5012 NULL, NULL,
5013 EINA_TRUE, EINA_TRUE);
5014 eina_strbuf_free(buf);
5015 }
5016
5017 if (!preedit_end_state)
5018 {
5019 /* set preedit start cursor */
5020 if (!en->preedit_start)
5021 en->preedit_start = evas_object_textblock_cursor_new(rp->object);
5022 evas_textblock_cursor_copy(en->cursor, en->preedit_start);
5023
5024 /* set preedit end cursor */
5025 if (!en->preedit_end)
5026 en->preedit_end = evas_object_textblock_cursor_new(rp->object);
5027 evas_textblock_cursor_copy(en->cursor, en->preedit_end);
5028
5029 preedit_end_pos = evas_textblock_cursor_pos_get(en->cursor);
5030
5031 for (i = 0; i < (preedit_end_pos - preedit_start_pos); i++)
5032 {
5033 evas_textblock_cursor_char_prev(en->preedit_start);
5034 }
5035
5036 en->have_preedit = EINA_TRUE;
5037
5038 /* set cursor position */
5039 evas_textblock_cursor_pos_set(en->cursor, preedit_start_pos + cursor_pos);
5040 }
5041
5042 _edje_entry_imf_cursor_info_set(en);
5043 _anchors_get(en->cursor, rp->object, en);
5044 _edje_emit_full(ed, "preedit,changed", rp->part->name, info,
5045 _free_entry_change_info);
5046 _edje_emit(ed, "cursor,changed", rp->part->name);
5047
5048 /* delete attribute list */
5049 if (attrs)
5050 {
5051 EINA_LIST_FREE(attrs, attr)
5052 free(attr);
5053 }
5054
5055 free(preedit_string);
5056 }
5057
5058 static void
_edje_entry_imf_event_delete_surrounding_cb(void * data,Ecore_IMF_Context * ctx EINA_UNUSED,void * event_info)5059 _edje_entry_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
5060 {
5061 Edje *ed = data;
5062 Edje_Real_Part *rp;
5063 Entry *en = NULL;
5064 Ecore_IMF_Event_Delete_Surrounding *ev = event_info;
5065 Evas_Textblock_Cursor *del_start, *del_end;
5066 Edje_Entry_Change_Info *info;
5067 int cursor_pos;
5068 int start, end;
5069 char *tmp;
5070
5071 rp = _edje_entry_imf_default_focused_rp_get(ed);
5072 if ((!rp)) return;
5073 if ((!rp) || (!ev)) return;
5074 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
5075 (!rp->typedata.text)) return;
5076 else
5077 en = rp->typedata.text->entry_data;
5078 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
5079 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
5080 return;
5081
5082 cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
5083
5084 del_start = evas_object_textblock_cursor_new(en->rp->object);
5085 evas_textblock_cursor_pos_set(del_start, cursor_pos + ev->offset);
5086
5087 del_end = evas_object_textblock_cursor_new(en->rp->object);
5088 evas_textblock_cursor_pos_set(del_end, cursor_pos + ev->offset + ev->n_chars);
5089
5090 start = evas_textblock_cursor_pos_get(del_start);
5091 end = evas_textblock_cursor_pos_get(del_end);
5092 if (start == end) goto end;
5093
5094 info = calloc(1, sizeof(*info));
5095 if (!info)
5096 {
5097 ERR("Running very low on memory");
5098 return;
5099 }
5100 info->insert = EINA_FALSE;
5101 info->change.del.start = start;
5102 info->change.del.end = end;
5103
5104 tmp = evas_textblock_cursor_range_text_get(del_start, del_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
5105 info->change.del.content = eina_stringshare_add(tmp);
5106 if (tmp) free(tmp);
5107
5108 evas_textblock_cursor_range_delete(del_start, del_end);
5109 _anchors_get(en->cursor, rp->object, en);
5110 _anchors_update_check(ed, rp);
5111
5112 _edje_emit(ed, "entry,changed", en->rp->part->name);
5113 _edje_emit_full(ed, "entry,changed,user", en->rp->part->name, info,
5114 _free_entry_change_info);
5115 _edje_emit(ed, "cursor,changed", en->rp->part->name);
5116 _edje_emit(ed, "cursor,changed,manual", en->rp->part->name);
5117
5118 _edje_entry_imf_cursor_info_set(en);
5119 _edje_entry_real_part_configure(ed, rp);
5120
5121 end:
5122 evas_textblock_cursor_free(del_start);
5123 evas_textblock_cursor_free(del_end);
5124 }
5125
5126 static void
_edje_entry_imf_event_selection_set_cb(void * data,Ecore_IMF_Context * ctx EINA_UNUSED,void * event_info)5127 _edje_entry_imf_event_selection_set_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
5128 {
5129 Edje *ed = data;
5130 Edje_Real_Part *rp;
5131 Entry *en = NULL;
5132 Ecore_IMF_Event_Selection *ev = event_info;
5133
5134 rp = _edje_entry_imf_default_focused_rp_get(ed);
5135 if ((!rp) || (!ev)) return;
5136 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
5137 (!rp->typedata.text)) return;
5138 else
5139 en = rp->typedata.text->entry_data;
5140 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
5141 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
5142 return;
5143
5144 if (ev->start == ev->end)
5145 {
5146 _edje_entry_cursor_pos_set(rp, EDJE_CURSOR_MAIN, ev->start);
5147 }
5148 else
5149 {
5150 _sel_clear(ed, en->cursor, rp->object, en);
5151 evas_textblock_cursor_pos_set(en->cursor, ev->start);
5152 _sel_enable(ed, en->cursor, rp->object, en);
5153 _sel_start(en->cursor, rp->object, en);
5154 evas_textblock_cursor_pos_set(en->cursor, ev->end);
5155 _sel_extend(ed, en->cursor, rp->object, en);
5156 }
5157
5158 _edje_entry_real_part_configure(en->ed, rp);
5159 }
5160
5161 static Eina_Bool
_edje_entry_imf_retrieve_selection_cb(void * data,Ecore_IMF_Context * ctx EINA_UNUSED,char ** text)5162 _edje_entry_imf_retrieve_selection_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text)
5163 {
5164 Edje *ed = data;
5165 Edje_Real_Part *rp;
5166 Entry *en = NULL;
5167 const char *selection_text = NULL;
5168
5169 rp = _edje_entry_imf_default_focused_rp_get(ed);
5170 if (!rp) return EINA_FALSE;
5171 if ((rp->type != EDJE_RP_TYPE_TEXT) ||
5172 (!rp->typedata.text)) return EINA_FALSE;
5173 else
5174 en = rp->typedata.text->entry_data;
5175 if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
5176 (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
5177 return EINA_FALSE;
5178
5179 if (en->have_selection)
5180 {
5181 selection_text = _edje_entry_selection_get(rp);
5182
5183 if (text)
5184 *text = selection_text ? strdup(selection_text) : NULL;
5185
5186 return selection_text ? EINA_TRUE : EINA_FALSE;
5187 }
5188 else
5189 return EINA_FALSE;
5190 }
5191
5192 #endif
5193
5194 Evas_Textblock_Cursor *
_edje_text_cursor_get(Edje_Real_Part * rp,Edje_Cursor cur)5195 _edje_text_cursor_get(Edje_Real_Part *rp, Edje_Cursor cur)
5196 {
5197 return _cursor_get(rp, cur);
5198 }
5199
5200 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
5201