4d05511c631249ccdc9a59b299654995938df60f
[framework/uifw/e17.git] / src / bin / e_editable.c
1 #include "e.h"
2
3 #define E_EDITABLE_CURSOR_MARGIN 5
4
5 #define E_EDITABLE_BLOCK_SIZE 128
6 #define E_EDITABLE_SIZE_TO_ALLOC(length) \
7    (((length) + (E_EDITABLE_BLOCK_SIZE - 1)) / E_EDITABLE_BLOCK_SIZE) * E_EDITABLE_BLOCK_SIZE
8
9 typedef struct _E_Editable_Smart_Data E_Editable_Smart_Data;
10
11 struct _E_Editable_Smart_Data
12 {
13    Evas_Object *clip_object;
14    Evas_Object *event_object;
15    Evas_Object *text_object;
16    Evas_Object *cursor_object;
17    Evas_Object *selection_object;
18
19    int cursor_pos;
20    int cursor_visible;
21    int selection_pos;
22    int selection_visible;
23    int password_mode;
24
25    char *text;
26    int char_length;
27    int unicode_length;
28    int allocated_length;
29
30    int cursor_width;
31    int selection_on_fg;
32    int average_char_w;
33    int average_char_h;
34 };
35
36 /* local subsystem functions */
37 static int _e_editable_text_insert(Evas_Object *editable, int pos, const char *text);
38 static int _e_editable_text_delete(Evas_Object *editable, int start, int end);
39 static void _e_editable_cursor_update(Evas_Object *editable);
40 static void _e_editable_selection_update(Evas_Object *editable);
41 static void _e_editable_text_update(Evas_Object *editable);
42 static void _e_editable_text_position_update(Evas_Object *editable, Evas_Coord real_w);
43 static int _e_editable_char_geometry_get_from_pos(Evas_Object *editable, int utf_pos, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch);
44
45 static void _e_editable_smart_add(Evas_Object *object);
46 static void _e_editable_smart_del(Evas_Object *object);
47 static void _e_editable_smart_move(Evas_Object *object, Evas_Coord x, Evas_Coord y);
48 static void _e_editable_smart_resize(Evas_Object *object, Evas_Coord w, Evas_Coord h);
49 static void _e_editable_smart_show(Evas_Object *object);
50 static void _e_editable_smart_hide(Evas_Object *object);
51 static void _e_editable_color_set(Evas_Object *object, int r, int g, int b, int a);
52 static void _e_editable_clip_set(Evas_Object *object, Evas_Object *clip);
53 static void _e_editable_clip_unset(Evas_Object *object);
54
55 /* local subsystem globals */
56 static Evas_Smart *_e_editable_smart = NULL;
57 static int _e_editable_smart_use = 0;
58
59 /* externally accessible functions */
60
61 /**
62  * Creates a new editable object. An editable object is an evas smart object in
63  * which the user can type some single-line text, select it and delete it.
64  *
65  * @param evas The evas where to add the editable object
66  * @return Returns the new editable object
67  */
68 EAPI Evas_Object *
69 e_editable_add(Evas *evas)
70 {
71    if (!_e_editable_smart)
72      {
73         static const Evas_Smart_Class sc =
74           {
75              "e_editable",
76                EVAS_SMART_CLASS_VERSION,
77                _e_editable_smart_add,
78                _e_editable_smart_del,
79                _e_editable_smart_move,
80                _e_editable_smart_resize,
81                _e_editable_smart_show,
82                _e_editable_smart_hide,
83                _e_editable_color_set,
84                _e_editable_clip_set,
85                _e_editable_clip_unset,
86                NULL,
87                NULL,
88                NULL,
89                NULL,
90                NULL,
91                NULL,
92                NULL
93           };
94         _e_editable_smart = evas_smart_class_new(&sc);
95         _e_editable_smart_use = 0;
96      }
97
98    return evas_object_smart_add(evas, _e_editable_smart);
99 }
100
101 /**
102  * Sets the theme group to be used by the editable object.
103  * This function has to be called, or the cursor and the selection won't be
104  * visible.
105  *
106  * @param editable an editable object
107  * @param category the theme category to use for the editable object
108  * @param group the theme group to use for the editable object
109  */
110 EAPI void
111 e_editable_theme_set(Evas_Object *editable, const char *category, const char *group)
112 {
113    E_Editable_Smart_Data *sd;
114    char *obj_group;
115    const char *data;
116
117    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
118      return;
119    if ((!category) || (!group)) return;
120    obj_group = alloca(strlen(group) + strlen("/selection") + 1);
121
122    /* Gets the theme for the text object */
123    sprintf(obj_group, "%s/text", group);
124    e_theme_edje_object_set(sd->text_object, category, obj_group);
125    sd->average_char_w = -1;
126    sd->average_char_h = -1;
127
128    /* Gets the theme for the cursor */
129    sprintf(obj_group, "%s/cursor", group);
130    e_theme_edje_object_set(sd->cursor_object, category, obj_group);
131
132    edje_object_size_min_get(sd->cursor_object, &sd->cursor_width, NULL);
133    if (sd->cursor_width < 1) sd->cursor_width = 1;
134
135    /* Gets the theme for the selection */
136    sprintf(obj_group, "%s/selection", group);
137    e_theme_edje_object_set(sd->selection_object, category, obj_group);
138
139    data = edje_object_data_get(sd->selection_object, "on_foreground");
140    if ((data) && (strcmp(data, "1") == 0))
141      {
142         sd->selection_on_fg = 1;
143         evas_object_stack_above(sd->selection_object, sd->text_object);
144      }
145    else
146      {
147         sd->selection_on_fg = 0;
148         evas_object_stack_below(sd->selection_object, sd->text_object);
149      }
150
151    _e_editable_text_update(editable);
152    _e_editable_cursor_update(editable);
153 }
154
155 /**
156  * Sets whether or not the editable object is in password mode. In password
157  * mode, the editable object displays '*' instead of the characters
158  *
159  * @param editable an editable object
160  * @param password_mode 1 to turn on the password mode of the editable object,
161  * 0 to turn it off
162  */
163 EAPI void
164 e_editable_password_set(Evas_Object *editable, int password_mode)
165 {
166    E_Editable_Smart_Data *sd;
167
168    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
169      return;
170    if (sd->password_mode == password_mode) return;
171
172    sd->password_mode = password_mode;
173    _e_editable_text_update(editable);
174    _e_editable_cursor_update(editable);
175 }
176
177 /**
178  * Gets whether or not the editable is in password mode
179  *
180  * @param editable an editable object
181  * @return Returns 1 if the editable object is in the password mode, 0 otherwise
182  */
183 EAPI int
184 e_editable_password_get(Evas_Object *editable)
185 {
186    E_Editable_Smart_Data *sd;
187
188    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
189      return 0;
190    return sd->password_mode;
191 }
192
193 /**
194  * Sets the text of the editable object
195  *
196  * @param editable an editable object
197  * @param text the text to set
198  */
199 EAPI void
200 e_editable_text_set(Evas_Object *editable, const char *text)
201 {
202    E_Editable_Smart_Data *sd;
203
204    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
205      return;
206
207    if (sd->password_mode) memset(sd->text, 0, sd->char_length);
208    free(sd->text);
209    sd->text = NULL;
210    sd->char_length = 0;
211    sd->unicode_length = 0;
212    sd->allocated_length = -1;
213
214    if (_e_editable_text_insert(editable, 0, text) <= 0)
215      {
216         sd->text = malloc((E_EDITABLE_BLOCK_SIZE + 1) * sizeof(char));
217         sd->text[0] = '\0';
218         sd->char_length = 0;
219         sd->unicode_length = 0;
220         sd->allocated_length = E_EDITABLE_BLOCK_SIZE;
221         _e_editable_text_update(editable);
222      }
223
224    sd->cursor_pos = sd->unicode_length;
225    sd->selection_pos = sd->unicode_length;
226    _e_editable_cursor_update(editable);
227 }
228
229 /**
230  * Gets the entire text of the editable object
231  *
232  * @param editable an editable object
233  * @return Returns the entire text of the editable object
234  */
235 EAPI const char *
236 e_editable_text_get(Evas_Object *editable)
237 {
238    E_Editable_Smart_Data *sd;
239
240    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
241      return NULL;
242    return sd->text;
243 }
244
245 /**
246  * Gets a range of the text of the editable object, from position @a start to
247  * position @a end
248  *
249  * @param editable an editable object
250  * @param start the start position of the text range to get
251  * @param end the end position of the text range to get
252  * @return Returns the range of text. The returned string will have to be freed
253  */
254 EAPI char *
255 e_editable_text_range_get(Evas_Object *editable, int start, int end)
256 {
257    E_Editable_Smart_Data *sd;
258    char *range;
259    int start_id = 0, end_id = 0, i;
260
261    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
262      return NULL;
263
264    start = E_CLAMP(start, 0, sd->unicode_length);
265    end = E_CLAMP(end, 0, sd->unicode_length);
266    if (end <= start) return NULL;
267
268    for (i = 0; i < end; i++)
269      {
270         end_id = evas_string_char_next_get(sd->text, end_id, NULL);
271         if (i < start) start_id = end_id;
272      }
273
274    if (end_id <= start_id) return NULL;
275
276    range = malloc((end_id - start_id + 1) * sizeof(char));
277    strncpy(range, &sd->text[start_id], end_id - start_id);
278    range[end_id - start_id] = '\0';
279
280    return range;
281 }
282
283 /**
284  * Gets the unicode length of the text of the editable object. The unicode
285  * length is not always the length returned by strlen() since a UTF-8 char can
286  * take several bytes
287  *
288  * @param editable an editable object
289  * @return Returns the unicode length of the text of the editable object
290  */
291 EAPI int
292 e_editable_text_length_get(Evas_Object *editable)
293 {
294    E_Editable_Smart_Data *sd;
295
296    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
297      return 0;
298    return sd->unicode_length;
299 }
300
301 /**
302  * Inserts some text at the given position in the editable object
303  *
304  * @param editable the editable object in which the text should be inserted
305  * @param pos the position where to insert the text
306  * @param text the text to insert
307  * @return Returns 1 if the text has been modified, 0 otherwise
308  */
309 EAPI int
310 e_editable_insert(Evas_Object *editable, int pos, const char *text)
311 {
312    E_Editable_Smart_Data *sd;
313    int unicode_length;
314
315    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
316      return 0;
317
318    unicode_length = _e_editable_text_insert(editable, pos, text);
319    if (unicode_length <= 0) return 0;
320
321    if (sd->cursor_pos >= pos)
322      e_editable_cursor_pos_set(editable, sd->cursor_pos + unicode_length);
323    if (sd->selection_pos >= pos)
324      e_editable_selection_pos_set(editable, sd->selection_pos + unicode_length);
325
326    _e_editable_text_position_update(editable, -1);
327    return 1;
328 }
329
330 /**
331  * Deletes the text of the editable object, between position "start" and
332  * position "end"
333  *
334  * @param editable the editable object in which the text should be deleted
335  * @param start the position of the first char to delete
336  * @param end the position of the last char to delete
337  * @return Returns 1 if the text has been modified, 0 otherwise
338  */
339 EAPI int
340 e_editable_delete(Evas_Object *editable, int start, int end)
341 {
342    E_Editable_Smart_Data *sd;
343    int unicode_length;
344
345    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
346      return 0;
347
348    unicode_length = _e_editable_text_delete(editable, start, end);
349    if (unicode_length <= 0) return 0;
350
351    if (sd->cursor_pos > end)
352      e_editable_cursor_pos_set(editable, sd->cursor_pos - unicode_length);
353    else if (sd->cursor_pos > start)
354      e_editable_cursor_pos_set(editable, start);
355
356    if (sd->selection_pos > end)
357      e_editable_selection_pos_set(editable, sd->selection_pos - unicode_length);
358    else if (sd->selection_pos > start)
359      e_editable_selection_pos_set(editable, start);
360
361    _e_editable_text_position_update(editable, -1);
362    return 1;
363 }
364
365 /**
366  * Moves the cursor of the editable object to the given position
367  *
368  * @param editable an editable object
369  * @param pos the position where to move the cursor
370  */
371 EAPI void
372 e_editable_cursor_pos_set(Evas_Object *editable, int pos)
373 {
374    E_Editable_Smart_Data *sd;
375
376    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
377      return;
378
379    pos = E_CLAMP(pos, 0, sd->unicode_length);
380    if ((sd->cursor_pos == pos)) return;
381
382    sd->cursor_pos = pos;
383    _e_editable_cursor_update(editable);
384 }
385
386 /**
387  * Gets the position of the cursor of the editable object
388  *
389  * @param editable an editable object
390  * @return Returns the position of the cursor of the editable object
391  */
392 EAPI int
393 e_editable_cursor_pos_get(Evas_Object *editable)
394 {
395    E_Editable_Smart_Data *sd;
396
397    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
398      return 0;
399    return sd->cursor_pos;
400 }
401
402 /**
403  * Moves the cursor to the start of the editable object
404  *
405  * @param editable an editable object
406  */
407 EAPI void
408 e_editable_cursor_move_to_start(Evas_Object *editable)
409 {
410    if (!editable)
411      return;
412    e_editable_cursor_pos_set(editable, 0);
413 }
414
415 /**
416  * Moves the cursor to the end of the editable object
417  *
418  * @param editable an editable object
419  */
420 EAPI void
421 e_editable_cursor_move_to_end(Evas_Object *editable)
422 {
423    E_Editable_Smart_Data *sd;
424
425    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
426      return;
427    e_editable_cursor_pos_set(editable, sd->unicode_length);
428 }
429
430 /**
431  * Moves the cursor backward by one character offset
432  *
433  * @param editable an editable object
434  */
435 EAPI void
436 e_editable_cursor_move_left(Evas_Object *editable)
437 {
438    E_Editable_Smart_Data *sd;
439
440    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
441      return;
442    e_editable_cursor_pos_set(editable, sd->cursor_pos - 1);
443 }
444
445 /**
446  * Moves the cursor forward by one character offset
447  *
448  * @param editable an editable object
449  */
450 EAPI void
451 e_editable_cursor_move_right(Evas_Object *editable)
452 {
453    E_Editable_Smart_Data *sd;
454
455    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
456      return;
457    e_editable_cursor_pos_set(editable, sd->cursor_pos + 1);
458 }
459
460 /**
461  * Shows the cursor of the editable object
462  *
463  * @param editable the editable object whose cursor should be shown
464  */
465 EAPI void
466 e_editable_cursor_show(Evas_Object *editable)
467 {
468    E_Editable_Smart_Data *sd;
469
470    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
471      return;
472    if (sd->cursor_visible) return;
473
474    sd->cursor_visible = 1;
475    if (evas_object_visible_get(editable))
476      {
477         evas_object_show(sd->cursor_object);
478         edje_object_signal_emit(sd->cursor_object, "e,action,show,cursor", "e");
479      }
480 }
481
482 /**
483  * Hides the cursor of the editable object
484  *
485  * @param editable the editable object whose cursor should be hidden
486  */
487 EAPI void
488 e_editable_cursor_hide(Evas_Object *editable)
489 {
490    E_Editable_Smart_Data *sd;
491
492    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
493      return;
494    if (!sd->cursor_visible) return;
495
496    sd->cursor_visible = 0;
497    evas_object_hide(sd->cursor_object);
498 }
499
500 /**
501  * Moves the selection bound of the editable object to the given position
502  *
503  * @param editable an editable object
504  * @param pos the position where to move the selection bound
505  */
506 EAPI void
507 e_editable_selection_pos_set(Evas_Object *editable, int pos)
508 {
509    E_Editable_Smart_Data *sd;
510
511    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
512      return;
513
514    pos = E_CLAMP(pos, 0, sd->unicode_length);
515    if (sd->selection_pos == pos) return;
516
517    sd->selection_pos = pos;
518    _e_editable_selection_update(editable);
519 }
520
521 /**
522  * Gets the position of the selection bound of the editable object
523  *
524  * @param editable an editable object
525  * @return Returns the position of the selection bound of the editable object
526  */
527 EAPI int
528 e_editable_selection_pos_get(Evas_Object *editable)
529 {
530    E_Editable_Smart_Data *sd;
531
532    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
533      return 0;
534    return sd->selection_pos;
535 }
536
537 /**
538  * Moves the selection bound to the start of the editable object
539  *
540  * @param editable an editable object
541  */
542 EAPI void
543 e_editable_selection_move_to_start(Evas_Object *editable)
544 {
545    if (!editable)
546      return;
547    e_editable_selection_pos_set(editable, 0);
548 }
549
550 /**
551  * Moves the selection bound to the end of the editable object
552  *
553  * @param editable an editable object
554  */
555 EAPI void
556 e_editable_selection_move_to_end(Evas_Object *editable)
557 {
558    E_Editable_Smart_Data *sd;
559
560    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
561      return;
562    e_editable_selection_pos_set(editable, sd->unicode_length);
563 }
564
565 /**
566  * Moves the selection bound backward by one character offset
567  *
568  * @param editable an editable object
569  */
570 EAPI void
571 e_editable_selection_move_left(Evas_Object *editable)
572 {
573    E_Editable_Smart_Data *sd;
574
575    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
576      return;
577    e_editable_selection_pos_set(editable, sd->selection_pos - 1);
578 }
579
580 /**
581  * Moves the selection bound forward by one character offset
582  *
583  * @param editable an editable object
584  */
585 EAPI void
586 e_editable_selection_move_right(Evas_Object *editable)
587 {
588    E_Editable_Smart_Data *sd;
589
590    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
591      return;
592    e_editable_selection_pos_set(editable, sd->selection_pos + 1);
593 }
594
595 /**
596  * Selects all the text of the editable object. The selection bound will be
597  * moved to the start of the editable object and the cursor will be moved to
598  * the end
599  *
600  * @param editable an editable object
601  */
602 EAPI void
603 e_editable_select_all(Evas_Object *editable)
604 {
605    if (!editable) return;
606    e_editable_selection_move_to_start(editable);
607    e_editable_cursor_move_to_end(editable);
608 }
609
610 /**
611  * Unselects all the text of the editable object. The selection bound will be
612  * moved to the cursor position
613  *
614  * @param editable an editable object
615  */
616 EAPI void
617 e_editable_unselect_all(Evas_Object *editable)
618 {
619    E_Editable_Smart_Data *sd;
620
621    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
622      return;
623    e_editable_selection_pos_set(editable, sd->cursor_pos);
624 }
625
626 /**
627  * Selects the word at the provided character index
628  */
629 EAPI void
630 e_editable_select_word(Evas_Object *editable, int index)
631 {
632    E_Editable_Smart_Data *sd;
633    int spos = 0, epos = -1, i = 0, pos = 0;
634
635    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
636      return;
637    if ((index < 0) || (index >= sd->unicode_length)) return;
638
639    while (i < sd->char_length)
640      {
641         if (sd->text[i] == ' ')
642           {
643              if (pos < index) spos = pos + 1;
644              else if (pos > index)
645                {
646                   epos = pos;
647                   break;
648                }
649           }
650         i = evas_string_char_next_get(sd->text, i, NULL);
651         pos++;
652      }
653    if (epos == -1) epos = pos;
654    e_editable_selection_pos_set(editable, spos);
655    e_editable_cursor_pos_set(editable, epos);
656 }
657
658 /**
659  * Shows the selection of the editable object
660  *
661  * @param editable an editable object
662  */
663 EAPI void
664 e_editable_selection_show(Evas_Object *editable)
665 {
666    E_Editable_Smart_Data *sd;
667
668    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
669      return;
670    if (sd->selection_visible) return;
671    sd->selection_visible = 1;
672    if ((evas_object_visible_get(editable)) &&
673        (sd->cursor_pos != sd->selection_pos))
674      evas_object_show(sd->selection_object);
675 }
676
677 /**
678  * Hides the selection of the editable object
679  *
680  * @param editable an editable object
681  */
682 EAPI void
683 e_editable_selection_hide(Evas_Object *editable)
684 {
685    E_Editable_Smart_Data *sd;
686
687    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
688      return;
689    if (!sd->selection_visible) return;
690    sd->selection_visible = 0;
691    evas_object_hide(sd->selection_object);
692 }
693
694 /**
695  * Gets the cursor position at the coords ( @a x, @a y ). It's used to know
696  * where to place the cursor or the selection bound on mouse evevents.
697  *
698  * @param editable an editable object
699  * @param x the x coord, relative to the editable object
700  * @param y the y coord, relative to the editable object
701  * @return Returns the position where to place the cursor according to the
702  * given coords
703  */
704 EAPI int
705 e_editable_pos_get_from_coords(Evas_Object *editable, Evas_Coord x, Evas_Coord y)
706 {
707    E_Editable_Smart_Data *sd;
708    const Evas_Object *text_obj;
709    Evas_Coord ox, oy;
710    Evas_Coord tx, ty, tw, th;
711    Evas_Coord cx, cw;
712    Evas_Coord canvas_x, canvas_y;
713    int index, pos, i, j;
714    const char *text;
715
716    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
717      return 0;
718    if (!(text_obj = edje_object_part_object_get(sd->text_object, "e.text.text")))
719      return 0;
720
721    evas_object_geometry_get(editable, &ox, &oy, NULL, NULL);
722    evas_object_geometry_get(text_obj, &tx, &ty, &tw, &th);
723    canvas_x = ox + x;
724    canvas_y = oy + y;
725
726    if ((canvas_y < ty) || (canvas_x < tx))
727      pos = 0;
728    else if ((canvas_y > (ty + th)) || (canvas_x > (tx + tw)))
729      pos = sd->unicode_length;
730    else
731      {
732         index = evas_object_text_char_coords_get(text_obj,
733                                                  canvas_x - tx, canvas_y - ty,
734                                                  &cx, NULL, &cw, NULL);
735         text = evas_object_text_text_get(text_obj);
736         if ((index >= 0) && (text))
737           {
738              if ((canvas_x - tx) > (cx + (cw / 2))) index++;
739
740              i = 0;
741              j = -1;
742              pos = 0;
743              while ((i < index) && (j != i))
744                {
745                   pos++;
746                   j = i;
747                   i = evas_string_char_next_get(text, i, NULL);
748                }
749              if (pos > sd->unicode_length) pos = sd->unicode_length;
750           }
751         else pos = 0;
752      }
753    return pos;
754 }
755
756 /**
757  * A utility function to get the average size of a character written inside
758  * the editable object
759  *
760  * @param editable an editable object
761  * @param w the location where to store the average width of a character
762  * @param h the location where to store the average height of a character
763  */
764 EAPI void
765 e_editable_char_size_get(Evas_Object *editable, int *w, int *h)
766 {
767    int tw = 0, th = 0;
768    Evas *evas;
769    const Evas_Object *text_obj;
770    Evas_Object *obj;
771    E_Editable_Smart_Data *sd;
772    char *text = "Tout est bon dans l'abricot sauf le noyau!"
773                 "Wakey wakey! Eggs and Bakey!";
774    const char *font, *font_source;
775    Evas_Text_Style_Type style;
776    int font_size;
777
778    if (w) *w = 0;
779    if (h) *h = 0;
780    if ((!editable) || (!(evas = evas_object_evas_get(editable))))
781      return;
782    if (!(sd = evas_object_smart_data_get(editable))) return;
783    if (!(text_obj = edje_object_part_object_get(sd->text_object, "e.text.text")))
784      return;
785
786    if ((sd->average_char_w <= 0) || (sd->average_char_h <= 0))
787      {
788         font_source = evas_object_text_font_source_get(text_obj);
789         evas_object_text_font_get(text_obj, &font, &font_size);
790         style = evas_object_text_style_get(text_obj);
791
792         obj = evas_object_text_add(evas);
793         evas_object_scale_set(obj, edje_scale_get());
794         evas_object_text_font_source_set(obj, font_source);
795         evas_object_text_font_set(obj, font, font_size);
796         evas_object_text_style_set(obj, style);
797         evas_object_text_text_set(obj, text);
798         evas_object_geometry_get(obj, NULL, NULL, &tw, &th);
799         evas_object_del(obj);
800         sd->average_char_w = (tw / strlen(text));
801         sd->average_char_h = th;
802      }
803    if (w) *w = sd->average_char_w;
804    if (h) *h = sd->average_char_h;
805 }
806
807 EAPI void
808 e_editable_enable(Evas_Object *editable)
809 {
810    E_Editable_Smart_Data *sd;
811
812    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
813      return;
814
815    edje_object_signal_emit(sd->text_object, "e,state,enabled", "e");
816 }
817
818 EAPI void
819 e_editable_disable(Evas_Object *editable)
820 {
821    E_Editable_Smart_Data *sd;
822
823    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
824      return;
825
826    edje_object_signal_emit(sd->text_object, "e,state,disabled", "e");
827 }
828 /* Private functions */
829
830 /* A utility function to insert some text inside the editable object.
831  * It doesn't update the position of the cursor, nor the selection... */
832 static int
833 _e_editable_text_insert(Evas_Object *editable, int pos, const char *text)
834 {
835    E_Editable_Smart_Data *sd;
836    int char_length = -1, unicode_length = -1;
837    int prev_char_length, new_char_length, new_unicode_length;
838    int index = 0, i = 0;
839
840    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
841      return 0;
842    if ((!text) || (*text == '\0')) return 0;
843
844    if (pos < 0) pos = 0;
845    else if (pos > sd->unicode_length)
846      pos = sd->unicode_length;
847
848    for (i = 0; i != char_length; i = evas_string_char_next_get(text, i, NULL))
849      {
850         char_length = i;
851         unicode_length++;
852      }
853
854    for (i = 0; i < pos; i++)
855      index = evas_string_char_next_get(sd->text, index, NULL);
856
857    if ((unicode_length <= 0) || (char_length <= 0)) return 0;
858
859    prev_char_length = sd->char_length;
860    new_char_length = sd->char_length + char_length;
861    new_unicode_length = sd->unicode_length + unicode_length;
862
863    if (new_char_length > sd->allocated_length)
864      {
865         int new_allocated_length = E_EDITABLE_SIZE_TO_ALLOC(new_char_length);
866         char *old = sd->text;
867
868         if (sd->password_mode)
869           {
870              /* security -- copy contents into new buffer, and overwrite old contents */
871              sd->text = malloc(new_allocated_length + 1);
872              if (!sd->text)
873                {
874                   sd->text = old;
875                   return 0;
876                }
877              if (old)
878                {
879                   memcpy(sd->text, old, prev_char_length + 1);
880                   memset(old, 0, prev_char_length);
881                   free(old);
882                }
883           }
884         else
885           {
886              sd->text = realloc(sd->text, new_allocated_length + 1);
887              if (!sd->text)
888                {
889                   sd->text = old;
890                   return 0;
891                }
892           }
893         sd->allocated_length = new_allocated_length;
894      }
895    sd->unicode_length = new_unicode_length;
896    sd->char_length = new_char_length;
897
898    if (prev_char_length > index)
899      memmove(&sd->text[index + char_length], &sd->text[index], prev_char_length - index);
900    strncpy(&sd->text[index], text, char_length);
901    sd->text[sd->char_length] = '\0';
902
903    _e_editable_text_update(editable);
904    return unicode_length;
905 }
906
907 /* A utility function to delete a range of text from the editable object.
908  * It doesn't update the position of the cursor, nor the selection... */
909 static int
910 _e_editable_text_delete(Evas_Object *editable, int start, int end)
911 {
912    E_Editable_Smart_Data *sd;
913    int start_id = 0, end_id = 0, i = 0;
914
915    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
916      return 0;
917
918    start = E_CLAMP(start, 0, sd->unicode_length);
919    end = E_CLAMP(end, 0, sd->unicode_length);
920    if (end <= start) return 0;
921
922    for (i = 0; i < end; i++)
923      {
924         end_id = evas_string_char_next_get(sd->text, end_id, NULL);
925         if (i < start) start_id = end_id;
926      }
927
928    if (end_id <= start_id) return 0;
929
930    memmove(&sd->text[start_id], &sd->text[end_id], sd->char_length - end_id);
931    sd->char_length -= (end_id - start_id);
932    sd->unicode_length -= (end - start);
933    sd->text[sd->char_length] = '\0';
934
935    _e_editable_text_update(editable);
936
937    return (end - start);
938 }
939
940 /* Updates the position of the cursor
941  * It also updates automatically the text position and the selection */
942 static void
943 _e_editable_cursor_update(Evas_Object *editable)
944 {
945    E_Editable_Smart_Data *sd;
946    const Evas_Object *text_obj;
947    Evas_Coord tx, ty;
948    Evas_Coord cx, cy, ch;
949
950    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
951      return;
952    if (!(text_obj = edje_object_part_object_get(sd->text_object, "e.text.text")))
953      return;
954
955    evas_object_geometry_get(text_obj, &tx, &ty, NULL, NULL);
956    _e_editable_char_geometry_get_from_pos(editable, sd->cursor_pos,
957                                           &cx, &cy, NULL, &ch);
958
959    evas_object_move(sd->cursor_object, tx + cx, ty + cy);
960    evas_object_resize(sd->cursor_object, sd->cursor_width, ch);
961
962    if (sd->cursor_visible && evas_object_visible_get(editable))
963      {
964         evas_object_show(sd->cursor_object);
965         edje_object_signal_emit(sd->cursor_object, "e,action,show,cursor", "e");
966      }
967
968    _e_editable_selection_update(editable);
969    _e_editable_text_position_update(editable, -1);
970 }
971
972 /* Updates the selection of the editable object */
973 static void
974 _e_editable_selection_update(Evas_Object *editable)
975 {
976    E_Editable_Smart_Data *sd;
977    const Evas_Object *text_obj;
978    Evas_Coord tx, ty;
979    Evas_Coord cx, cy;
980    Evas_Coord sx, sy, sw, sh;
981    int start_pos, end_pos;
982
983    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
984      return;
985    if (!(text_obj = edje_object_part_object_get(sd->text_object, "e.text.text")))
986      return;
987
988    if ((sd->cursor_pos == sd->selection_pos) || (!sd->selection_visible))
989      evas_object_hide(sd->selection_object);
990    else
991      {
992         evas_object_geometry_get(text_obj, &tx, &ty, NULL, NULL);
993         start_pos = (sd->cursor_pos <= sd->selection_pos) ?
994           sd->cursor_pos : sd->selection_pos;
995         end_pos = (sd->cursor_pos >= sd->selection_pos) ?
996           sd->cursor_pos : sd->selection_pos;
997
998         _e_editable_char_geometry_get_from_pos(editable, start_pos,
999                                                &cx, &cy, NULL, NULL);
1000         sx = tx + cx;
1001         sy = ty + cy;
1002
1003         _e_editable_char_geometry_get_from_pos(editable, end_pos,
1004                                                &cx, NULL, NULL, &sh);
1005         sw = tx + cx - sx;
1006
1007         evas_object_move(sd->selection_object, sx, sy);
1008         evas_object_resize(sd->selection_object, sw, sh);
1009         evas_object_show(sd->selection_object);
1010      }
1011 }
1012
1013 /* Updates the text of the text object of the editable object 
1014  * (it fills it with '*' if the editable is in password mode)
1015  * It does not update the position of the text */
1016 static void
1017 _e_editable_text_update(Evas_Object *editable)
1018 {
1019    E_Editable_Smart_Data *sd;
1020    Evas_Coord minw, minh;
1021
1022    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
1023      return;
1024
1025    if (sd->password_mode)
1026      {
1027         char *text;
1028
1029         text = malloc((sd->unicode_length + 1) * sizeof(char));
1030         memset(text, '*', sd->unicode_length * sizeof(char));
1031         text[sd->unicode_length] = '\0';
1032         edje_object_part_text_set(sd->text_object, "e.text.text", text);
1033         free(text);
1034      }
1035    else
1036      edje_object_part_text_set(sd->text_object, "e.text.text", sd->text);
1037
1038    edje_object_size_min_calc(sd->text_object, &minw, &minh);
1039    evas_object_resize(sd->text_object, minw, minh);
1040 }
1041
1042 /* Updates the position of the text object according to the position of the
1043  * cursor (we make sure the cursor is visible) */
1044 static void
1045 _e_editable_text_position_update(Evas_Object *editable, Evas_Coord real_w)
1046 {
1047    E_Editable_Smart_Data *sd;
1048    Evas_Coord ox, oy, ow;
1049    Evas_Coord tx, ty, tw;
1050    Evas_Coord cx, cy, cw;
1051    Evas_Coord sx, sy;
1052    Evas_Coord offset_x = 0;
1053
1054    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
1055      return;
1056
1057    evas_object_geometry_get(editable, &ox, &oy, &ow, NULL);
1058    if (real_w >= 0) ow = real_w;
1059    evas_object_geometry_get(sd->text_object, &tx, &ty, &tw, NULL);
1060    evas_object_geometry_get(sd->cursor_object, &cx, &cy, &cw, NULL);
1061    evas_object_geometry_get(sd->selection_object, &sx, &sy, NULL, NULL);
1062
1063    if (tw <= ow)
1064      offset_x = ox - tx;
1065    else if (cx < (ox + E_EDITABLE_CURSOR_MARGIN))
1066      offset_x = ox + E_EDITABLE_CURSOR_MARGIN - cx;
1067    else if ((cx + cw + E_EDITABLE_CURSOR_MARGIN) > (ox + ow))
1068      offset_x = (ox + ow) - (cx + cw + E_EDITABLE_CURSOR_MARGIN);
1069
1070    if (tw > ow)
1071      {
1072         if ((tx + offset_x) > ox)
1073           offset_x = ox - tx;
1074         else if ((tx + tw + offset_x) < (ox + ow))
1075           offset_x = (ox + ow) - (tx + tw);
1076      }
1077
1078    if (offset_x != 0)
1079      {
1080         evas_object_move(sd->text_object, tx + offset_x, ty);
1081         evas_object_move(sd->cursor_object, cx + offset_x, cy);
1082         evas_object_move(sd->selection_object, sx + offset_x, sy);
1083      }
1084 }
1085
1086 /* Gets the geometry of the char according to its utf-8 pos */
1087 static int
1088 _e_editable_char_geometry_get_from_pos(Evas_Object *editable, int utf_pos, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
1089 {
1090    E_Editable_Smart_Data *sd;
1091    const Evas_Object *text_obj;
1092    const char *text;
1093    Evas_Coord x, w;
1094    int index = 0, i, last_pos, ret;
1095
1096    if (cx) *cx = 0;
1097    if (cy) *cy = 0;
1098    if (cw) *cw = 0;
1099    if (ch) *ch = 0;
1100
1101    if ((!editable) || (!(sd = evas_object_smart_data_get(editable))))
1102      return 0;
1103    if (!(text_obj = edje_object_part_object_get(sd->text_object, "e.text.text")))
1104      return 0;
1105
1106    text = evas_object_text_text_get(text_obj);
1107    if ((!text) || (sd->unicode_length <= 0) || (utf_pos <= 0))
1108      {
1109         e_editable_char_size_get(editable, cw, ch);
1110         return 1;
1111      }
1112    else
1113      {
1114         if (utf_pos >= sd->unicode_length)
1115           {
1116             utf_pos = sd->unicode_length - 1;
1117             last_pos = 1;
1118           }
1119         else
1120           last_pos = 0;
1121
1122         for (i = 0; i < utf_pos; i++)
1123           index = evas_string_char_next_get(text, index, NULL);
1124
1125         ret = evas_object_text_char_pos_get(text_obj, index, &x, cy, &w, ch);
1126         if (cx) *cx = x - 1 + (last_pos ? w : 0);
1127         if (cw) *cw = last_pos ? 1 : w;
1128         return ret;
1129      }
1130 }
1131
1132 /* Editable object's smart methods */
1133
1134 static void
1135 _e_editable_smart_add(Evas_Object *object)
1136 {
1137    Evas *evas;
1138    E_Editable_Smart_Data *sd;
1139    Evas_Coord ox, oy;
1140
1141    if ((!object) || !(evas = evas_object_evas_get(object)))
1142      return;
1143
1144    sd = malloc(sizeof(E_Editable_Smart_Data));
1145    if (!sd) return;
1146
1147    _e_editable_smart_use++;
1148    evas_object_smart_data_set(object, sd);
1149    evas_object_geometry_get(object, &ox, &oy, NULL, NULL);
1150
1151    sd->text = malloc((E_EDITABLE_BLOCK_SIZE + 1) * sizeof(char));
1152    sd->text[0] = '\0';
1153    sd->char_length = 0;
1154    sd->unicode_length = 0;
1155    sd->allocated_length = E_EDITABLE_BLOCK_SIZE;
1156
1157    sd->cursor_width = 1;
1158    sd->selection_on_fg = 0;
1159    sd->average_char_w = -1;
1160    sd->average_char_h = -1;
1161
1162    sd->cursor_pos = 0;
1163    sd->cursor_visible = 1;
1164    sd->selection_pos = 0;
1165    sd->selection_visible = 1;
1166    sd->password_mode = 0;
1167
1168    sd->clip_object = evas_object_rectangle_add(evas);
1169    evas_object_move(sd->clip_object, ox, oy);
1170    evas_object_smart_member_add(sd->clip_object, object);
1171
1172    sd->event_object = evas_object_rectangle_add(evas);
1173    evas_object_color_set(sd->event_object, 0, 0, 0, 0);
1174    evas_object_clip_set(sd->event_object, sd->clip_object);
1175    evas_object_move(sd->event_object, ox, oy);
1176    evas_object_smart_member_add(sd->event_object, object);
1177
1178    sd->text_object = edje_object_add(evas);
1179    evas_object_pass_events_set(sd->text_object, 1);
1180    evas_object_clip_set(sd->text_object, sd->clip_object);
1181    evas_object_move(sd->text_object, ox, oy);
1182    evas_object_smart_member_add(sd->text_object, object);
1183
1184    sd->selection_object = edje_object_add(evas);
1185    evas_object_pass_events_set(sd->selection_object, 1);
1186    evas_object_clip_set(sd->selection_object, sd->clip_object);
1187    evas_object_move(sd->selection_object, ox, oy);
1188    evas_object_smart_member_add(sd->selection_object, object);
1189
1190    sd->cursor_object = edje_object_add(evas);
1191    evas_object_pass_events_set(sd->cursor_object, 1);
1192    evas_object_clip_set(sd->cursor_object, sd->clip_object);
1193    evas_object_move(sd->cursor_object, ox, oy);
1194    evas_object_smart_member_add(sd->cursor_object, object);
1195
1196    _e_editable_cursor_update(object);
1197 }
1198
1199 /* Deletes the editable */
1200 static void
1201 _e_editable_smart_del(Evas_Object *object)
1202 {
1203    E_Editable_Smart_Data *sd;
1204
1205    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1206      return;
1207
1208    evas_object_del(sd->clip_object);
1209    evas_object_del(sd->event_object);
1210    evas_object_del(sd->text_object);
1211    evas_object_del(sd->cursor_object);
1212    evas_object_del(sd->selection_object);
1213    /* Security - clear out memory that contained a password */
1214    if (sd->password_mode) memset(sd->text, 0, sd->char_length);
1215    free(sd->text);
1216    free(sd);
1217
1218    _e_editable_smart_use--;
1219    if (_e_editable_smart_use <= 0)
1220      {
1221         evas_smart_free(_e_editable_smart);
1222         _e_editable_smart = NULL;
1223      }
1224 }
1225
1226 /* Moves the editable object */
1227 static void
1228 _e_editable_smart_move(Evas_Object *object, Evas_Coord x, Evas_Coord y)
1229 {
1230    E_Editable_Smart_Data *sd;
1231    Evas_Coord prev_x, prev_y;
1232    Evas_Coord ox, oy;
1233
1234    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1235      return;
1236
1237    evas_object_geometry_get(object, &prev_x, &prev_y, NULL, NULL);
1238    evas_object_move(sd->clip_object, x, y);
1239    evas_object_move(sd->event_object, x, y);
1240    evas_object_geometry_get(sd->text_object, &ox, &oy, NULL, NULL);
1241    evas_object_move(sd->text_object, ox + (x - prev_x), oy + (y - prev_y));
1242    evas_object_geometry_get(sd->cursor_object, &ox, &oy, NULL, NULL);
1243    evas_object_move(sd->cursor_object, ox + (x - prev_x), oy + (y - prev_y));
1244    evas_object_geometry_get(sd->selection_object, &ox, &oy, NULL, NULL);
1245    evas_object_move(sd->selection_object, ox + (x - prev_x), oy + (y - prev_y));
1246 }
1247
1248 /* Resizes the editable object */
1249 static void
1250 _e_editable_smart_resize(Evas_Object *object, Evas_Coord w, Evas_Coord h)
1251 {
1252    E_Editable_Smart_Data *sd;
1253
1254    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1255      return;
1256
1257    evas_object_resize(sd->clip_object, w, h);
1258    evas_object_resize(sd->event_object, w, h);
1259    _e_editable_text_position_update(object, w);
1260 }
1261
1262 /* Shows the editable object */
1263 static void
1264 _e_editable_smart_show(Evas_Object *object)
1265 {
1266    E_Editable_Smart_Data *sd;
1267
1268    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1269      return;
1270
1271    evas_object_show(sd->clip_object);
1272    evas_object_show(sd->event_object);
1273    evas_object_show(sd->text_object);
1274
1275    if (sd->cursor_visible)
1276      {
1277         evas_object_show(sd->cursor_object);
1278         edje_object_signal_emit(sd->cursor_object, "e,action,show,cursor", "e");
1279      }
1280
1281    if ((sd->selection_visible) && (sd->cursor_pos != sd->selection_pos))
1282      evas_object_show(sd->selection_object);
1283 }
1284
1285 /* Hides the editable object */
1286 static void
1287 _e_editable_smart_hide(Evas_Object *object)
1288 {
1289    E_Editable_Smart_Data *sd;
1290
1291    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1292      return;
1293
1294    evas_object_hide(sd->clip_object);
1295    evas_object_hide(sd->event_object);
1296    evas_object_hide(sd->text_object);
1297    evas_object_hide(sd->cursor_object);
1298    evas_object_hide(sd->selection_object);
1299 }
1300
1301 /* Changes the color of the editable object */
1302 static void
1303 _e_editable_color_set(Evas_Object *object, int r, int g, int b, int a)
1304 {
1305    E_Editable_Smart_Data *sd;
1306
1307    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1308      return;
1309    evas_object_color_set(sd->clip_object, r, g, b, a);
1310 }
1311
1312 /* Clips the editable object against "clip" */
1313 static void
1314 _e_editable_clip_set(Evas_Object *object, Evas_Object *clip)
1315 {
1316    E_Editable_Smart_Data *sd;
1317
1318    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1319      return;
1320    evas_object_clip_set(sd->clip_object, clip);
1321 }
1322
1323 /* Unclips the editable object */
1324 static void
1325 _e_editable_clip_unset(Evas_Object *object)
1326 {
1327    E_Editable_Smart_Data *sd;
1328
1329    if ((!object) || (!(sd = evas_object_smart_data_get(object))))
1330      return;
1331    evas_object_clip_unset(sd->clip_object);
1332 }