elementary/elm_widget : Focus should be moved by "clicked" not by
[framework/uifw/elementary.git] / src / lib / elm_widget.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static const char SMART_NAME[] = "elm_widget";
5
6 #define API_ENTRY                                    \
7   Smart_Data * sd = evas_object_smart_data_get(obj); \
8   if ((!obj) || (!sd) || (!_elm_widget_is(obj)))
9 #define INTERNAL_ENTRY                               \
10   Smart_Data * sd = evas_object_smart_data_get(obj); \
11   if (!sd) return;
12
13 #undef elm_widget_text_set_hook_set
14 #undef elm_widget_text_get_hook_set
15 #undef elm_widget_content_set_hook_set
16 #undef elm_widget_content_get_hook_set
17 #undef elm_widget_content_unset_hook_set
18
19 typedef struct _Smart_Data        Smart_Data;
20 typedef struct _Edje_Signal_Data  Edje_Signal_Data;
21 typedef struct _Elm_Event_Cb_Data Elm_Event_Cb_Data;
22 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
23
24 struct _Smart_Data
25 {
26    Evas_Object *obj;
27    const char  *type;
28    Evas_Object *parent_obj;
29    Evas_Object *parent2;
30    Evas_Coord   x, y, w, h;
31    Eina_List   *subobjs;
32    Evas_Object *resize_obj;
33    Evas_Object *hover_obj;
34    Eina_List   *tooltips, *cursors;
35    void       (*del_func)(Evas_Object *obj);
36    void       (*del_pre_func)(Evas_Object *obj);
37    void       (*focus_func)(Evas_Object *obj);
38    void       (*activate_func)(Evas_Object *obj);
39    void       (*disable_func)(Evas_Object *obj);
40    void       (*theme_func)(Evas_Object *obj);
41    void       (*translate_func)(Evas_Object *obj);
42    Eina_Bool  (*event_func)(Evas_Object       *obj,
43                             Evas_Object       *source,
44                             Evas_Callback_Type type,
45                             void              *event_info);
46    void       (*signal_func)(Evas_Object *obj,
47                              const char  *emission,
48                              const char  *source);
49    void       (*callback_add_func)(Evas_Object   *obj,
50                                    const char    *emission,
51                                    const char    *source,
52                                    Edje_Signal_Cb func,
53                                    void          *data);
54    void       (*callback_del_func)(Evas_Object   *obj,
55                                    const char    *emission,
56                                    const char    *source,
57                                    Edje_Signal_Cb func,
58                                    void          *data);
59    void       (*changed_func)(Evas_Object *obj);
60    Eina_Bool  (*focus_next_func)(const Evas_Object  *obj,
61                                  Elm_Focus_Direction dir,
62                                  Evas_Object       **next);
63    void       (*on_focus_func)(void        *data,
64                                Evas_Object *obj);
65    void        *on_focus_data;
66    void       (*on_change_func)(void        *data,
67                                 Evas_Object *obj);
68    void        *on_change_data;
69    void       (*on_show_region_func)(void        *data,
70                                      Evas_Object *obj);
71    void        *on_show_region_data;
72    void       (*focus_region_func)(Evas_Object *obj,
73                                    Evas_Coord   x,
74                                    Evas_Coord   y,
75                                    Evas_Coord   w,
76                                    Evas_Coord   h);
77    void       (*on_focus_region_func)(const Evas_Object *obj,
78                                       Evas_Coord        *x,
79                                       Evas_Coord        *y,
80                                       Evas_Coord        *w,
81                                       Evas_Coord        *h);
82    Elm_Widget_On_Text_Set_Cb on_text_set_func;
83    Elm_Widget_On_Text_Get_Cb on_text_get_func;
84    Elm_Widget_On_Content_Set_Cb on_content_set_func;
85    Elm_Widget_On_Content_Get_Cb on_content_get_func;
86    Elm_Widget_On_Content_Unset_Cb on_content_unset_func;
87    void        *data;
88    Evas_Coord   rx, ry, rw, rh;
89    int          scroll_hold;
90    int          scroll_freeze;
91    double       scale;
92    Elm_Theme   *theme;
93    const char  *style;
94    const char  *access_info;
95    unsigned int focus_order;
96    Eina_Bool    focus_order_on_calc;
97
98    int          child_drag_x_locked;
99    int          child_drag_y_locked;
100
101    Eina_List   *edje_signals;
102    Eina_List   *translate_strings;
103
104    Eina_Bool    drag_x_locked : 1;
105    Eina_Bool    drag_y_locked : 1;
106
107    Eina_Bool    can_focus : 1;
108    Eina_Bool    child_can_focus : 1;
109    Eina_Bool    focused : 1;
110    Eina_Bool    top_win_focused : 1;
111    Eina_Bool    tree_unfocusable : 1;
112    Eina_Bool    highlight_ignore : 1;
113    Eina_Bool    highlight_in_theme : 1;
114    Eina_Bool    disabled : 1;
115    Eina_Bool    is_mirrored : 1;
116    Eina_Bool    mirrored_auto_mode : 1;   /* This is TRUE by default */
117    Eina_Bool    still_in : 1;
118
119    Eina_List   *focus_chain;
120    Eina_List   *event_cb;
121 };
122
123 struct _Edje_Signal_Data
124 {
125    Evas_Object   *obj;
126    Edje_Signal_Cb func;
127    const char    *emission;
128    const char    *source;
129    void          *data;
130 };
131
132 struct _Elm_Event_Cb_Data
133 {
134    Elm_Event_Cb func;
135    const void  *data;
136 };
137
138 struct _Elm_Translate_String_Data
139 {
140    const char *id;
141    const char *domain;
142    const char *string;
143 };
144
145 /* local subsystem functions */
146 static void _smart_reconfigure(Smart_Data *sd);
147 static void _smart_add(Evas_Object *obj);
148 static void _smart_del(Evas_Object *obj);
149 static void _smart_move(Evas_Object *obj,
150                         Evas_Coord   x,
151                         Evas_Coord   y);
152 static void _smart_resize(Evas_Object *obj,
153                           Evas_Coord   w,
154                           Evas_Coord   h);
155 static void _smart_show(Evas_Object *obj);
156 static void _smart_hide(Evas_Object *obj);
157 static void _smart_color_set(Evas_Object *obj,
158                              int          r,
159                              int          g,
160                              int          b,
161                              int          a);
162 static void _smart_clip_set(Evas_Object *obj,
163                             Evas_Object *clip);
164 static void _smart_clip_unset(Evas_Object *obj);
165 static void _smart_calculate(Evas_Object *obj);
166 static void _smart_init(void);
167
168 static void _if_focused_revert(Evas_Object *obj,
169                                Eina_Bool    can_focus_only);
170 static Evas_Object *_newest_focus_order_get(Evas_Object  *obj,
171                                             unsigned int *newest_focus_order,
172                                             Eina_Bool     can_focus_only);
173
174 /* local subsystem globals */
175 static Evas_Smart *_e_smart = NULL;
176 static Eina_List  *widtypes = NULL;
177
178 static unsigned int focus_order = 0;
179
180 // internal funcs
181 static inline Eina_Bool
182 _elm_widget_is(const Evas_Object *obj)
183 {
184    const char *type = evas_object_type_get(obj);
185    return type == SMART_NAME;
186 }
187
188 static inline Eina_Bool
189 _is_focusable(Evas_Object *obj)
190 {
191    API_ENTRY return EINA_FALSE;
192    return sd->can_focus || (sd->child_can_focus);
193 }
194
195 static void
196 _unfocus_parents(Evas_Object *obj)
197 {
198    for (; obj; obj = elm_widget_parent_get(obj))
199      {
200         INTERNAL_ENTRY
201         if (!sd->focused) return;
202         sd->focused = 0;
203      }
204 }
205
206 static void
207 _focus_parents(Evas_Object *obj)
208 {
209    for (; obj; obj = elm_widget_parent_get(obj))
210      {
211         INTERNAL_ENTRY
212         if (sd->focused) return;
213         sd->focused = 1;
214      }
215 }
216
217 static void
218 _sub_obj_del(void        *data,
219              Evas        *e __UNUSED__,
220              Evas_Object *obj,
221              void        *event_info __UNUSED__)
222 {
223    Smart_Data *sd = data;
224
225    if (_elm_widget_is(obj))
226      {
227         if (elm_widget_focus_get(obj)) _unfocus_parents(sd->obj);
228      }
229    if (obj == sd->resize_obj)
230      sd->resize_obj = NULL;
231    else if (obj == sd->hover_obj)
232      sd->hover_obj = NULL;
233    else
234      sd->subobjs = eina_list_remove(sd->subobjs, obj);
235    evas_object_smart_callback_call(sd->obj, "sub-object-del", obj);
236 }
237
238 static void
239 _sub_obj_hide(void        *data __UNUSED__,
240               Evas        *e __UNUSED__,
241               Evas_Object *obj,
242               void        *event_info __UNUSED__)
243 {
244    elm_widget_focus_hide_handle(obj);
245 }
246
247 static void
248 _sub_obj_mouse_down(void        *data,
249                     Evas        *e __UNUSED__,
250                     Evas_Object *obj __UNUSED__,
251                     void        *event_info)
252 {
253    Smart_Data *sd = data;
254    Evas_Event_Mouse_Down *ev = event_info;
255    if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD))
256            sd->still_in = 1;
257 }
258
259 static void
260 _sub_obj_mouse_move(void        *data,
261                     Evas        *e __UNUSED__,
262                     Evas_Object *obj,
263                     void        *event_info)
264 {
265    Smart_Data *sd = data;
266    Evas_Event_Mouse_Move *ev = event_info;
267    if (sd->still_in)
268      {
269         if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
270           sd->still_in = 0;
271         else
272           {
273              Evas_Coord x, y, w, h;
274              evas_object_geometry_get(obj, &x, &y, &w, &h);
275              if ((ev->cur.canvas.x < x) || (ev->cur.canvas.y < y) ||
276                  (ev->cur.canvas.x >= (x + w)) || (ev->cur.canvas.y >= (y + h)))
277                sd->still_in = 0;
278           }
279      }
280 }
281
282 static void
283 _sub_obj_mouse_up(void        *data,
284                   Evas        *e __UNUSED__,
285                   Evas_Object *obj,
286                   void        *event_info __UNUSED__)
287 {
288    Smart_Data *sd = data;
289    if (sd->still_in)
290      elm_widget_focus_mouse_up_handle(obj);
291    sd->still_in = 0;
292 }
293
294 static void
295 _propagate_x_drag_lock(Evas_Object *obj,
296                        int          dir)
297 {
298    INTERNAL_ENTRY
299    if (sd->parent_obj)
300      {
301         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
302         if (sd2)
303           {
304              sd2->child_drag_x_locked += dir;
305              _propagate_x_drag_lock(sd->parent_obj, dir);
306           }
307      }
308 }
309
310 static void
311 _propagate_y_drag_lock(Evas_Object *obj,
312                        int          dir)
313 {
314    INTERNAL_ENTRY
315    if (sd->parent_obj)
316      {
317         Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
318         if (sd2)
319           {
320              sd2->child_drag_y_locked += dir;
321              _propagate_y_drag_lock(sd->parent_obj, dir);
322           }
323      }
324 }
325
326 static void
327 _propagate_event(void        *data,
328                  Evas        *e __UNUSED__,
329                  Evas_Object *obj,
330                  void        *event_info)
331 {
332    INTERNAL_ENTRY
333    Evas_Callback_Type type = (Evas_Callback_Type)(long)data;
334    Evas_Event_Flags *event_flags = NULL;
335
336    switch (type)
337      {
338       case EVAS_CALLBACK_KEY_DOWN:
339           {
340             Evas_Event_Key_Down *ev = event_info;
341             event_flags = &(ev->event_flags);
342           }
343         break;
344
345       case EVAS_CALLBACK_KEY_UP:
346           {
347              Evas_Event_Key_Up *ev = event_info;
348              event_flags = &(ev->event_flags);
349           }
350         break;
351
352       case EVAS_CALLBACK_MOUSE_WHEEL:
353           {
354             Evas_Event_Mouse_Wheel *ev = event_info;
355             event_flags = &(ev->event_flags);
356           }
357         break;
358
359       default:
360         break;
361      }
362
363    elm_widget_event_propagate(obj, type, event_info, event_flags);
364 }
365
366 static void
367 _parent_focus(Evas_Object *obj)
368 {
369    API_ENTRY return;
370    if (sd->focused) return;
371
372    Evas_Object *o = elm_widget_parent_get(obj);
373    sd->focus_order_on_calc = EINA_TRUE;
374
375    if (o) _parent_focus(o);
376
377    if (!sd->focus_order_on_calc)
378      return; /* we don't want to override it if by means of any of the
379                 callbacks below one gets to calculate our order
380                 first. */
381
382    focus_order++;
383    sd->focus_order = focus_order;
384    if (sd->top_win_focused)
385      {
386         sd->focused = EINA_TRUE;
387         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
388         if (sd->focus_func) sd->focus_func(obj);
389         _elm_widget_focus_region_show(obj);
390      }
391    sd->focus_order_on_calc = EINA_FALSE;
392 }
393
394 static void
395 _elm_object_focus_chain_del_cb(void        *data,
396                                Evas        *e __UNUSED__,
397                                Evas_Object *obj,
398                                void        *event_info __UNUSED__)
399 {
400    Smart_Data *sd = data;
401
402    sd->focus_chain = eina_list_remove(sd->focus_chain, obj);
403 }
404
405 // exposed util funcs to elm
406 void
407 _elm_widget_type_clear(void)
408 {
409    const char **ptr;
410
411    EINA_LIST_FREE(widtypes, ptr)
412      {
413         eina_stringshare_del(*ptr);
414         *ptr = NULL;
415      }
416 }
417
418 void
419 _elm_widget_focus_region_show(const Evas_Object *obj)
420 {
421    Evas_Coord x, y, w, h, ox, oy;
422    Smart_Data *sd2;
423    Evas_Object *o;
424
425    API_ENTRY return;
426
427    o = elm_widget_parent_get(obj);
428    if (!o) return;
429
430    elm_widget_focus_region_get(obj, &x, &y, &w, &h);
431    evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
432    while (o)
433      {
434         Evas_Coord px, py;
435         sd2 = evas_object_smart_data_get(o);
436         if (sd2->focus_region_func)
437           {
438              sd2->focus_region_func(o, x, y, w, h);
439              elm_widget_focus_region_get(o, &x, &y, &w, &h);
440           }
441         else
442           {
443              evas_object_geometry_get(o, &px, &py, NULL, NULL);
444              x += ox - px;
445              y += oy - py;
446              ox = px;
447              oy = py;
448           }
449         o = elm_widget_parent_get(o);
450      }
451 }
452
453 /**
454  * @defgroup Widget Widget
455  *
456  * @internal
457  * Exposed api for making widgets
458  */
459 EAPI void
460 elm_widget_type_register(const char **ptr)
461 {
462    widtypes = eina_list_append(widtypes, (void *)ptr);
463 }
464
465 /**
466  * @defgroup Widget Widget
467  *
468  * @internal
469  * Disposed api for making widgets
470  */
471 EAPI void
472 elm_widget_type_unregister(const char **ptr)
473 {
474    widtypes = eina_list_remove(widtypes, (void *)ptr);
475 }
476
477 EAPI Eina_Bool
478 elm_widget_api_check(int ver)
479 {
480    if (ver != ELM_INTERNAL_API_VERSION)
481      {
482         CRITICAL("Elementary widget api versions do not match");
483         return EINA_FALSE;
484      }
485    return EINA_TRUE;
486 }
487
488 EAPI Evas_Object *
489 elm_widget_add(Evas *evas)
490 {
491    Evas_Object *obj;
492    _smart_init();
493    obj = evas_object_smart_add(evas, _e_smart);
494    elm_widget_mirrored_set(obj, elm_mirrored_get());
495    return obj;
496 }
497
498 EAPI void
499 elm_widget_del_hook_set(Evas_Object *obj,
500                         void       (*func)(Evas_Object *obj))
501 {
502    API_ENTRY return;
503    sd->del_func = func;
504 }
505
506 EAPI void
507 elm_widget_del_pre_hook_set(Evas_Object *obj,
508                             void       (*func)(Evas_Object *obj))
509 {
510    API_ENTRY return;
511    sd->del_pre_func = func;
512 }
513
514 EAPI void
515 elm_widget_focus_hook_set(Evas_Object *obj,
516                           void       (*func)(Evas_Object *obj))
517 {
518    API_ENTRY return;
519    sd->focus_func = func;
520 }
521
522 EAPI void
523 elm_widget_activate_hook_set(Evas_Object *obj,
524                              void       (*func)(Evas_Object *obj))
525 {
526    API_ENTRY return;
527    sd->activate_func = func;
528 }
529
530 EAPI void
531 elm_widget_disable_hook_set(Evas_Object *obj,
532                             void       (*func)(Evas_Object *obj))
533 {
534    API_ENTRY return;
535    sd->disable_func = func;
536 }
537
538 EAPI void
539 elm_widget_theme_hook_set(Evas_Object *obj,
540                           void       (*func)(Evas_Object *obj))
541 {
542    API_ENTRY return;
543    sd->theme_func = func;
544 }
545
546 EAPI void
547 elm_widget_translate_hook_set(Evas_Object *obj,
548                               void       (*func)(Evas_Object *obj))
549 {
550    API_ENTRY return;
551    sd->translate_func = func;
552 }
553
554 EAPI void
555 elm_widget_event_hook_set(Evas_Object *obj,
556                           Eina_Bool  (*func)(Evas_Object       *obj,
557                                              Evas_Object       *source,
558                                              Evas_Callback_Type type,
559                                              void              *event_info))
560 {
561    API_ENTRY return;
562    sd->event_func = func;
563 }
564
565 EAPI void
566 elm_widget_text_set_hook_set(Evas_Object *obj,
567                              Elm_Widget_On_Text_Set_Cb func)
568 {
569    API_ENTRY return;
570    sd->on_text_set_func = func;
571 }
572
573 EAPI void
574 elm_widget_text_get_hook_set(Evas_Object *obj,
575                              Elm_Widget_On_Text_Get_Cb func)
576 {
577    API_ENTRY return;
578    sd->on_text_get_func = func;
579 }
580
581 EAPI void
582 elm_widget_content_set_hook_set(Evas_Object *obj,
583                                 Elm_Widget_On_Content_Set_Cb func)
584 {
585    API_ENTRY return;
586    sd->on_content_set_func = func;
587 }
588
589 EAPI void
590 elm_widget_content_get_hook_set(Evas_Object *obj,
591                                 Elm_Widget_On_Content_Get_Cb func)
592 {
593    API_ENTRY return;
594    sd->on_content_get_func = func;
595 }
596
597 EAPI void
598 elm_widget_content_unset_hook_set(Evas_Object *obj,
599                                   Elm_Widget_On_Content_Unset_Cb func)
600 {
601    API_ENTRY return;
602    sd->on_content_unset_func = func;
603 }
604
605 EAPI void
606 elm_widget_changed_hook_set(Evas_Object *obj,
607                             void       (*func)(Evas_Object *obj))
608 {
609    API_ENTRY return;
610    sd->changed_func = func;
611 }
612
613 EAPI void
614 elm_widget_signal_emit_hook_set(Evas_Object *obj,
615                                 void       (*func)(Evas_Object *obj,
616                                                    const char *emission,
617                                                    const char *source))
618 {
619    API_ENTRY return;
620    sd->signal_func = func;
621 }
622
623 EAPI void
624 elm_widget_signal_callback_add_hook_set(Evas_Object *obj,
625                                         void       (*func)(Evas_Object   *obj,
626                                                            const char    *emission,
627                                                            const char    *source,
628                                                            Edje_Signal_Cb func_cb,
629                                                            void          *data))
630 {
631    API_ENTRY return;
632    sd->callback_add_func = func;
633 }
634
635 EAPI void
636 elm_widget_signal_callback_del_hook_set(Evas_Object *obj,
637                                         void       (*func)(Evas_Object   *obj,
638                                                            const char    *emission,
639                                                            const char    *source,
640                                                            Edje_Signal_Cb func_cb,
641                                                            void          *data))
642 {
643    API_ENTRY return;
644    sd->callback_del_func = func;
645 }
646
647 EAPI void
648 elm_widget_theme(Evas_Object *obj)
649 {
650    const Eina_List *l;
651    Evas_Object *child;
652    Elm_Tooltip *tt;
653    Elm_Cursor *cur;
654
655    API_ENTRY return;
656    EINA_LIST_FOREACH(sd->subobjs, l, child) elm_widget_theme(child);
657    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
658    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
659    EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt);
660    EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur);
661    if (sd->theme_func) sd->theme_func(obj);
662 }
663
664 EAPI void
665 elm_widget_theme_specific(Evas_Object *obj,
666                           Elm_Theme   *th,
667                           Eina_Bool    force)
668 {
669    const Eina_List *l;
670    Evas_Object *child;
671    Elm_Tooltip *tt;
672    Elm_Cursor *cur;
673    Elm_Theme *th2, *thdef;
674
675    API_ENTRY return;
676    thdef = elm_theme_default_get();
677    if (!th) th = thdef;
678    if (!force)
679      {
680         th2 = sd->theme;
681         if (!th2) th2 = thdef;
682         while (th2)
683           {
684              if (th2 == th)
685                {
686                   force = EINA_TRUE;
687                   break;
688                }
689              if (th2 == thdef) break;
690              th2 = th2->ref_theme;
691              if (!th2) th2 = thdef;
692           }
693      }
694    if (!force) return;
695    EINA_LIST_FOREACH(sd->subobjs, l, child)
696      elm_widget_theme_specific(child, th, force);
697    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
698    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
699    EINA_LIST_FOREACH(sd->tooltips, l, tt) elm_tooltip_theme(tt);
700    EINA_LIST_FOREACH(sd->cursors, l, cur) elm_cursor_theme(cur);
701    if (sd->theme_func) sd->theme_func(obj);
702 }
703
704 /**
705  * @internal
706  *
707  * Set hook to get next object in object focus chain.
708  *
709  * @param obj The widget object.
710  * @param func The hook to be used with this widget.
711  *
712  * @ingroup Widget
713  */
714 EAPI void
715 elm_widget_focus_next_hook_set(Evas_Object *obj,
716                                Eina_Bool  (*func)(const Evas_Object   *obj,
717                                                    Elm_Focus_Direction dir,
718                                                    Evas_Object       **next))
719 {
720    API_ENTRY return;
721    sd->focus_next_func = func;
722 }
723
724 /**
725  * Returns the widget's mirrored mode.
726  *
727  * @param obj The widget.
728  * @return mirrored mode of the object.
729  *
730  **/
731 EAPI Eina_Bool
732 elm_widget_mirrored_get(const Evas_Object *obj)
733 {
734    API_ENTRY return EINA_FALSE;
735    return sd->is_mirrored;
736 }
737
738 /**
739  * Sets the widget's mirrored mode.
740  *
741  * @param obj The widget.
742  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
743  */
744 EAPI void
745 elm_widget_mirrored_set(Evas_Object *obj,
746                         Eina_Bool    mirrored)
747 {
748    API_ENTRY return;
749    if (sd->is_mirrored != mirrored)
750      {
751         sd->is_mirrored = mirrored;
752         elm_widget_theme(obj);
753      }
754 }
755
756 /**
757  * @internal
758  * Resets the mirrored mode from the system mirror mode for widgets that are in
759  * automatic mirroring mode. This function does not call elm_widget_theme.
760  *
761  * @param obj The widget.
762  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
763  */
764 void
765 _elm_widget_mirrored_reload(Evas_Object *obj)
766 {
767    API_ENTRY return;
768    Eina_Bool mirrored = elm_mirrored_get();
769    if (elm_widget_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored))
770      {
771         sd->is_mirrored = mirrored;
772      }
773 }
774
775 /**
776  * Returns the widget's mirrored mode setting.
777  *
778  * @param obj The widget.
779  * @return mirrored mode setting of the object.
780  *
781  **/
782 EAPI Eina_Bool
783 elm_widget_mirrored_automatic_get(const Evas_Object *obj)
784 {
785    API_ENTRY return EINA_FALSE;
786    return sd->mirrored_auto_mode;
787 }
788
789 /**
790  * Sets the widget's mirrored mode setting.
791  * When widget in automatic mode, it follows the system mirrored mode set by
792  * elm_mirrored_set().
793  * @param obj The widget.
794  * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual.
795  */
796 EAPI void
797 elm_widget_mirrored_automatic_set(Evas_Object *obj,
798                                   Eina_Bool    automatic)
799 {
800    API_ENTRY return;
801    if (sd->mirrored_auto_mode != automatic)
802      {
803         sd->mirrored_auto_mode = automatic;
804
805         if (automatic)
806           {
807              elm_widget_mirrored_set(obj, elm_mirrored_get());
808           }
809      }
810 }
811
812 EAPI void
813 elm_widget_on_focus_hook_set(Evas_Object *obj,
814                              void       (*func)(void *data,
815                                                 Evas_Object *obj),
816                              void        *data)
817 {
818    API_ENTRY return;
819    sd->on_focus_func = func;
820    sd->on_focus_data = data;
821 }
822
823 EAPI void
824 elm_widget_on_change_hook_set(Evas_Object *obj,
825                               void       (*func)(void *data,
826                                                  Evas_Object *obj),
827                               void        *data)
828 {
829    API_ENTRY return;
830    sd->on_change_func = func;
831    sd->on_change_data = data;
832 }
833
834 EAPI void
835 elm_widget_on_show_region_hook_set(Evas_Object *obj,
836                                    void       (*func)(void *data,
837                                                       Evas_Object *obj),
838                                    void        *data)
839 {
840    API_ENTRY return;
841    sd->on_show_region_func = func;
842    sd->on_show_region_data = data;
843 }
844
845 /**
846  * @internal
847  *
848  * Set the hook to use to show the focused region.
849  *
850  * Whenever a new widget gets focused or it's needed to show the focused
851  * area of the current one, this hook will be called on objects that may
852  * want to move their children into their visible area.
853  * The area given in the hook function is relative to the @p obj widget.
854  *
855  * @param obj The widget object
856  * @param func The function to call to show the specified area.
857  *
858  * @ingroup Widget
859  */
860 EAPI void
861 elm_widget_focus_region_hook_set(Evas_Object *obj,
862                                  void       (*func)(Evas_Object *obj,
863                                                     Evas_Coord x,
864                                                     Evas_Coord y,
865                                                     Evas_Coord w,
866                                                     Evas_Coord h))
867 {
868    API_ENTRY return;
869    sd->focus_region_func = func;
870 }
871
872 /**
873  * @internal
874  *
875  * Set the hook to retrieve the focused region of a widget.
876  *
877  * This hook will be called by elm_widget_focus_region_get() whenever
878  * it's needed to get the focused area of a widget. The area must be relative
879  * to the widget itself and if no hook is set, it will default to the entire
880  * object.
881  *
882  * @param obj The widget object
883  * @param func The function used to retrieve the focus region.
884  *
885  * @ingroup Widget
886  */
887 EAPI void
888 elm_widget_on_focus_region_hook_set(Evas_Object *obj,
889                                     void       (*func)(const Evas_Object *obj,
890                                                        Evas_Coord *x,
891                                                        Evas_Coord *y,
892                                                        Evas_Coord *w,
893                                                        Evas_Coord *h))
894 {
895    API_ENTRY return;
896    sd->on_focus_region_func = func;
897 }
898
899 EAPI void
900 elm_widget_data_set(Evas_Object *obj,
901                     void        *data)
902 {
903    API_ENTRY return;
904    sd->data = data;
905 }
906
907 EAPI void *
908 elm_widget_data_get(const Evas_Object *obj)
909 {
910    API_ENTRY return NULL;
911    return sd->data;
912 }
913
914 EAPI void
915 elm_widget_sub_object_add(Evas_Object *obj,
916                           Evas_Object *sobj)
917 {
918    API_ENTRY return;
919    double scale, pscale = elm_widget_scale_get(sobj);
920    Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
921    Eina_Bool mirrored, pmirrored = elm_widget_mirrored_get(obj);
922
923    if (_elm_widget_is(sobj))
924      {
925         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
926         if (sd2)
927           {
928              if (sd2->parent_obj == obj)
929                return;
930              if (sd2->parent_obj)
931                elm_widget_sub_object_del(sd2->parent_obj, sobj);
932              sd2->parent_obj = obj;
933              sd2->top_win_focused = sd->top_win_focused;
934              if (!sd->child_can_focus && (_is_focusable(sobj)))
935                sd->child_can_focus = EINA_TRUE;
936           }
937      }
938    else
939      {
940         void *data = evas_object_data_get(sobj, "elm-parent");
941         if (data)
942           {
943              if (data == obj) return;
944              evas_object_event_callback_del(sobj, EVAS_CALLBACK_DEL,
945                                             _sub_obj_del);
946           }
947      }
948
949    sd->subobjs = eina_list_append(sd->subobjs, sobj);
950    evas_object_data_set(sobj, "elm-parent", obj);
951    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
952    if (_elm_widget_is(sobj))
953      evas_object_event_callback_add(sobj, EVAS_CALLBACK_HIDE, _sub_obj_hide, sd);
954    evas_object_smart_callback_call(obj, "sub-object-add", sobj);
955    scale = elm_widget_scale_get(sobj);
956    th = elm_widget_theme_get(sobj);
957    mirrored = elm_widget_mirrored_get(sobj);
958    if ((scale != pscale) || (th != pth) || (pmirrored != mirrored)) elm_widget_theme(sobj);
959    if (elm_widget_focus_get(sobj)) _focus_parents(obj);
960 }
961
962 EAPI void
963 elm_widget_sub_object_del(Evas_Object *obj,
964                           Evas_Object *sobj)
965 {
966    Evas_Object *sobj_parent;
967    API_ENTRY return;
968    if (!sobj) return;
969
970    sobj_parent = evas_object_data_del(sobj, "elm-parent");
971    if (sobj_parent != obj)
972      {
973         static int abort_on_warn = -1;
974         ERR("removing sub object %p from parent %p, "
975             "but elm-parent is different %p!",
976             sobj, obj, sobj_parent);
977         if (EINA_UNLIKELY(abort_on_warn == -1))
978           {
979              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
980              else abort_on_warn = 0;
981           }
982         if (abort_on_warn == 1) abort();
983      }
984    if (_elm_widget_is(sobj))
985      {
986         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
987         if (sd2)
988           {
989              sd2->parent_obj = NULL;
990              if (sd2->resize_obj == sobj)
991                sd2->resize_obj = NULL;
992              else
993                sd->subobjs = eina_list_remove(sd->subobjs, sobj);
994           }
995         else
996           sd->subobjs = eina_list_remove(sd->subobjs, sobj);
997         if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
998         if ((sd->child_can_focus) && (_is_focusable(sobj)))
999           {
1000              Evas_Object *subobj;
1001              const Eina_List *l;
1002              sd->child_can_focus = EINA_FALSE;
1003              EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1004                {
1005                   if (_is_focusable(subobj))
1006                     {
1007                        sd->child_can_focus = EINA_TRUE;
1008                        break;
1009                     }
1010                }
1011           }
1012      }
1013    else
1014      sd->subobjs = eina_list_remove(sd->subobjs, sobj);
1015    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
1016                                        _sub_obj_del, sd);
1017    if (_elm_widget_is(sobj))
1018      evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_HIDE,
1019                                          _sub_obj_hide, sd);
1020    evas_object_smart_callback_call(obj, "sub-object-del", sobj);
1021 }
1022
1023 EAPI void
1024 elm_widget_resize_object_set(Evas_Object *obj,
1025                              Evas_Object *sobj)
1026 {
1027    API_ENTRY return;
1028    // orphan previous resize obj
1029    if (sd->resize_obj)
1030      {
1031         evas_object_clip_unset(sd->resize_obj);
1032         evas_object_data_del(sd->resize_obj, "elm-parent");
1033         if (_elm_widget_is(sd->resize_obj))
1034           {
1035              Smart_Data *sd2 = evas_object_smart_data_get(sd->resize_obj);
1036              if (sd2) sd2->parent_obj = NULL;
1037              evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_HIDE,
1038                                                  _sub_obj_hide, sd);
1039           }
1040         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_DEL,
1041                                             _sub_obj_del, sd);
1042         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_DOWN,
1043                                             _sub_obj_mouse_down, sd);
1044         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_MOVE,
1045                                             _sub_obj_mouse_move, sd);
1046         evas_object_event_callback_del_full(sd->resize_obj, EVAS_CALLBACK_MOUSE_UP,
1047                                             _sub_obj_mouse_up, sd);
1048         evas_object_smart_member_del(sd->resize_obj);
1049         if (_elm_widget_is(sd->resize_obj))
1050           {
1051              if (elm_widget_focus_get(sd->resize_obj)) _unfocus_parents(obj);
1052           }
1053      }
1054
1055    sd->resize_obj = sobj;
1056    if (!sobj) return;
1057
1058    // orphan new resize obj
1059    evas_object_data_del(sobj, "elm-parent");
1060    if (_elm_widget_is(sobj))
1061      {
1062         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
1063         if (sd2) sd2->parent_obj = NULL;
1064         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_HIDE,
1065                                             _sub_obj_hide, sd);
1066      }
1067    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL,
1068                                        _sub_obj_del, sd);
1069    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_DOWN,
1070                                        _sub_obj_mouse_down, sd);
1071    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_MOVE,
1072                                        _sub_obj_mouse_move, sd);
1073    evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_MOUSE_UP,
1074                                        _sub_obj_mouse_up, sd);
1075    evas_object_smart_member_del(sobj);
1076    if (_elm_widget_is(sobj))
1077      {
1078         if (elm_widget_focus_get(sobj)) _unfocus_parents(obj);
1079      }
1080
1081    // set the resize obj up
1082    if (_elm_widget_is(sobj))
1083      {
1084         Smart_Data *sd2 = evas_object_smart_data_get(sobj);
1085         if (sd2)
1086           {
1087              sd2->parent_obj = obj;
1088              sd2->top_win_focused = sd->top_win_focused;
1089           }
1090         evas_object_event_callback_add(sobj, EVAS_CALLBACK_HIDE,
1091                                        _sub_obj_hide, sd);
1092      }
1093    evas_object_clip_set(sobj, evas_object_clip_get(obj));
1094    evas_object_smart_member_add(sobj, obj);
1095    evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1096                                   _sub_obj_del, sd);
1097    evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_DOWN,
1098                                   _sub_obj_mouse_down, sd);
1099    evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_MOVE,
1100                                   _sub_obj_mouse_move, sd);
1101    evas_object_event_callback_add(sobj, EVAS_CALLBACK_MOUSE_UP,
1102                                   _sub_obj_mouse_up, sd);
1103    _smart_reconfigure(sd);
1104    evas_object_data_set(sobj, "elm-parent", obj);
1105    evas_object_smart_callback_call(obj, "sub-object-add", sobj);
1106    if (_elm_widget_is(sobj))
1107      {
1108         if (elm_widget_focus_get(sobj)) _focus_parents(obj);
1109      }
1110 }
1111
1112 EAPI void
1113 elm_widget_hover_object_set(Evas_Object *obj,
1114                             Evas_Object *sobj)
1115 {
1116    API_ENTRY return;
1117    if (sd->hover_obj)
1118      {
1119         evas_object_event_callback_del_full(sd->hover_obj, EVAS_CALLBACK_DEL,
1120                                             _sub_obj_del, sd);
1121      }
1122    sd->hover_obj = sobj;
1123    if (sd->hover_obj)
1124      {
1125         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1126                                        _sub_obj_del, sd);
1127         _smart_reconfigure(sd);
1128      }
1129 }
1130
1131 EAPI void
1132 elm_widget_can_focus_set(Evas_Object *obj,
1133                          Eina_Bool    can_focus)
1134 {
1135    API_ENTRY return;
1136    sd->can_focus = can_focus;
1137    if (can_focus)
1138      {
1139         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
1140                                        _propagate_event,
1141                                        (void *)(long)EVAS_CALLBACK_KEY_DOWN);
1142         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP,
1143                                        _propagate_event,
1144                                        (void *)(long)EVAS_CALLBACK_KEY_UP);
1145         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1146                                        _propagate_event,
1147                                        (void *)(long)EVAS_CALLBACK_MOUSE_WHEEL);
1148      }
1149    else
1150      {
1151         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_DOWN,
1152                                        _propagate_event);
1153         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_UP,
1154                                        _propagate_event);
1155         evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1156                                        _propagate_event);
1157      }
1158 }
1159
1160 EAPI Eina_Bool
1161 elm_widget_can_focus_get(const Evas_Object *obj)
1162 {
1163    API_ENTRY return EINA_FALSE;
1164    return sd->can_focus;
1165 }
1166
1167 EAPI Eina_Bool
1168 elm_widget_child_can_focus_get(const Evas_Object *obj)
1169 {
1170    API_ENTRY return EINA_FALSE;
1171    return sd->child_can_focus;
1172 }
1173
1174 /**
1175  * @internal
1176  *
1177  * This API makes the widget object and its children to be unfocusable.
1178  *
1179  * This API can be helpful for an object to be deleted.
1180  * When an object will be deleted soon, it and its children may not
1181  * want to get focus (by focus reverting or by other focus controls).
1182  * Then, just use this API before deleting.
1183  *
1184  * @param obj The widget root of sub-tree
1185  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1186  *
1187  * @ingroup Widget
1188  */
1189 EAPI void
1190 elm_widget_tree_unfocusable_set(Evas_Object *obj,
1191                                 Eina_Bool    tree_unfocusable)
1192 {
1193    API_ENTRY return;
1194
1195    if (sd->tree_unfocusable == tree_unfocusable) return;
1196    sd->tree_unfocusable = !!tree_unfocusable;
1197    elm_widget_focus_tree_unfocusable_handle(obj);
1198 }
1199
1200 /**
1201  * @internal
1202  *
1203  * This returns true, if the object sub-tree is unfocusable.
1204  *
1205  * @param obj The widget root of sub-tree
1206  * @return EINA_TRUE if the object sub-tree is unfocusable
1207  *
1208  * @ingroup Widget
1209  */
1210 EAPI Eina_Bool
1211 elm_widget_tree_unfocusable_get(const Evas_Object *obj)
1212 {
1213    API_ENTRY return EINA_FALSE;
1214    return sd->tree_unfocusable;
1215 }
1216
1217 /**
1218  * @internal
1219  *
1220  * Get the list of focusable child objects.
1221  *
1222  * This function retruns list of child objects which can get focus.
1223  *
1224  * @param obj The parent widget
1225  * @retrun list of focusable child objects.
1226  *
1227  * @ingroup Widget
1228  */
1229 EAPI Eina_List *
1230 elm_widget_can_focus_child_list_get(const Evas_Object *obj)
1231 {
1232    API_ENTRY return NULL;
1233
1234    const Eina_List *l;
1235    Eina_List *child_list = NULL;
1236    Evas_Object *child;
1237
1238    if (sd->subobjs)
1239      {
1240         EINA_LIST_FOREACH(sd->subobjs, l, child)
1241           {
1242              if ((elm_widget_can_focus_get(child)) &&
1243                  (evas_object_visible_get(child)) &&
1244                  (!elm_widget_disabled_get(child)))
1245                child_list = eina_list_append(child_list, child);
1246              else if (elm_widget_is(child))
1247                {
1248                   Eina_List *can_focus_list;
1249                   can_focus_list = elm_widget_can_focus_child_list_get(child);
1250                   if (can_focus_list)
1251                     child_list = eina_list_merge(child_list, can_focus_list);
1252                }
1253           }
1254      }
1255    return child_list;
1256 }
1257
1258 EAPI void
1259 elm_widget_highlight_ignore_set(Evas_Object *obj,
1260                                 Eina_Bool    ignore)
1261 {
1262    API_ENTRY return;
1263    sd->highlight_ignore = !!ignore;
1264 }
1265
1266 EAPI Eina_Bool
1267 elm_widget_highlight_ignore_get(const Evas_Object *obj)
1268 {
1269    API_ENTRY return EINA_FALSE;
1270    return sd->highlight_ignore;
1271 }
1272
1273 EAPI void
1274 elm_widget_highlight_in_theme_set(Evas_Object *obj,
1275                                   Eina_Bool    highlight)
1276 {
1277    API_ENTRY return;
1278    sd->highlight_in_theme = !!highlight;
1279    /* FIXME: if focused, it should switch from one mode to the other */
1280 }
1281
1282 EAPI Eina_Bool
1283 elm_widget_highlight_in_theme_get(const Evas_Object *obj)
1284 {
1285    API_ENTRY return EINA_FALSE;
1286    return sd->highlight_in_theme;
1287 }
1288
1289 EAPI Eina_Bool
1290 elm_widget_focus_get(const Evas_Object *obj)
1291 {
1292    API_ENTRY return EINA_FALSE;
1293    return sd->focused;
1294 }
1295
1296 EAPI Evas_Object *
1297 elm_widget_focused_object_get(const Evas_Object *obj)
1298 {
1299    const Evas_Object *subobj;
1300    const Eina_List *l;
1301    API_ENTRY return NULL;
1302
1303    if (!sd->focused) return NULL;
1304    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1305      {
1306         Evas_Object *fobj = elm_widget_focused_object_get(subobj);
1307         if (fobj) return fobj;
1308      }
1309    return (Evas_Object *)obj;
1310 }
1311
1312 EAPI Evas_Object *
1313 elm_widget_top_get(const Evas_Object *obj)
1314 {
1315    API_ENTRY return NULL;
1316    if (sd->parent_obj) return elm_widget_top_get(sd->parent_obj);
1317    return (Evas_Object *)obj;
1318 }
1319
1320 EAPI Eina_Bool
1321 elm_widget_is(const Evas_Object *obj)
1322 {
1323    return _elm_widget_is(obj);
1324 }
1325
1326 EAPI Evas_Object *
1327 elm_widget_parent_widget_get(const Evas_Object *obj)
1328 {
1329    Evas_Object *parent;
1330
1331    if (_elm_widget_is(obj))
1332      {
1333         Smart_Data *sd = evas_object_smart_data_get(obj);
1334         if (!sd) return NULL;
1335         parent = sd->parent_obj;
1336      }
1337    else
1338      {
1339         parent = evas_object_data_get(obj, "elm-parent");
1340         if (!parent) parent = evas_object_smart_parent_get(obj);
1341      }
1342
1343    while (parent)
1344      {
1345         Evas_Object *elm_parent;
1346         if (_elm_widget_is(parent)) break;
1347         elm_parent = evas_object_data_get(parent, "elm-parent");
1348         if (elm_parent) parent = elm_parent;
1349         else parent = evas_object_smart_parent_get(parent);
1350      }
1351    return parent;
1352 }
1353
1354 EAPI Evas_Object *
1355 elm_widget_parent2_get(const Evas_Object *obj)
1356 {
1357    if (_elm_widget_is(obj))
1358      {
1359         Smart_Data *sd = evas_object_smart_data_get(obj);
1360         if (sd) return sd->parent2;
1361      }
1362    return NULL;
1363 }
1364
1365 EAPI void
1366 elm_widget_parent2_set(Evas_Object *obj, Evas_Object *parent)
1367 {
1368    API_ENTRY return;
1369    sd->parent2 = parent;
1370 }
1371
1372 EAPI void
1373 elm_widget_event_callback_add(Evas_Object *obj,
1374                               Elm_Event_Cb func,
1375                               const void  *data)
1376 {
1377    API_ENTRY return;
1378    EINA_SAFETY_ON_NULL_RETURN(func);
1379    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
1380    ecb->func = func;
1381    ecb->data = data;
1382    sd->event_cb = eina_list_append(sd->event_cb, ecb);
1383 }
1384
1385 EAPI void *
1386 elm_widget_event_callback_del(Evas_Object *obj,
1387                               Elm_Event_Cb func,
1388                               const void  *data)
1389 {
1390    API_ENTRY return NULL;
1391    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
1392    Eina_List *l;
1393    Elm_Event_Cb_Data *ecd;
1394    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
1395      if ((ecd->func == func) && (ecd->data == data))
1396        {
1397           free(ecd);
1398           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
1399           return (void *)data;
1400        }
1401    return NULL;
1402 }
1403
1404 EAPI Eina_Bool
1405 elm_widget_event_propagate(Evas_Object       *obj,
1406                            Evas_Callback_Type type,
1407                            void              *event_info,
1408                            Evas_Event_Flags  *event_flags)
1409 {
1410    API_ENTRY return EINA_FALSE; //TODO reduce.
1411    if (!_elm_widget_is(obj)) return EINA_FALSE;
1412    Evas_Object *parent = obj;
1413    Elm_Event_Cb_Data *ecd;
1414    Eina_List *l, *l_prev;
1415
1416    while (parent &&
1417           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
1418      {
1419         sd = evas_object_smart_data_get(parent);
1420         if ((!sd) || (!_elm_widget_is(obj)))
1421           return EINA_FALSE; //Not Elm Widget
1422
1423         if (sd->event_func && (sd->event_func(parent, obj, type, event_info)))
1424           return EINA_TRUE;
1425
1426         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1427           {
1428              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1429                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1430                return EINA_TRUE;
1431           }
1432         parent = sd->parent_obj;
1433      }
1434
1435    return EINA_FALSE;
1436 }
1437
1438 /**
1439  * @internal
1440  *
1441  * Set custom focus chain.
1442  *
1443  * This function i set one new and overwrite any previous custom focus chain
1444  * with the list of objects. The previous list will be deleted and this list
1445  * will be managed. After setted, don't modity it.
1446  *
1447  * @note On focus cycle, only will be evaluated children of this container.
1448  *
1449  * @param obj The container widget
1450  * @param objs Chain of objects to pass focus
1451  * @ingroup Widget
1452  */
1453 EAPI void
1454 elm_widget_focus_custom_chain_set(Evas_Object *obj,
1455                                   Eina_List   *objs)
1456 {
1457    API_ENTRY return;
1458    if (!sd->focus_next_func)
1459      return;
1460
1461    elm_widget_focus_custom_chain_unset(obj);
1462
1463    Eina_List *l;
1464    Evas_Object *o;
1465
1466    EINA_LIST_FOREACH(objs, l, o)
1467      {
1468         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1469                                        _elm_object_focus_chain_del_cb, sd);
1470      }
1471
1472    sd->focus_chain = objs;
1473 }
1474
1475 /**
1476  * @internal
1477  *
1478  * Get custom focus chain
1479  *
1480  * @param obj The container widget
1481  * @ingroup Widget
1482  */
1483 EAPI const Eina_List *
1484 elm_widget_focus_custom_chain_get(const Evas_Object *obj)
1485 {
1486    API_ENTRY return NULL;
1487    return (const Eina_List *)sd->focus_chain;
1488 }
1489
1490 /**
1491  * @internal
1492  *
1493  * Unset custom focus chain
1494  *
1495  * @param obj The container widget
1496  * @ingroup Widget
1497  */
1498 EAPI void
1499 elm_widget_focus_custom_chain_unset(Evas_Object *obj)
1500 {
1501    API_ENTRY return;
1502    Eina_List *l, *l_next;
1503    Evas_Object *o;
1504
1505    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1506      {
1507         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1508                                             _elm_object_focus_chain_del_cb, sd);
1509         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1510      }
1511 }
1512
1513 /**
1514  * @internal
1515  *
1516  * Append object to custom focus chain.
1517  *
1518  * @note If relative_child equal to NULL or not in custom chain, the object
1519  * will be added in end.
1520  *
1521  * @note On focus cycle, only will be evaluated children of this container.
1522  *
1523  * @param obj The container widget
1524  * @param child The child to be added in custom chain
1525  * @param relative_child The relative object to position the child
1526  * @ingroup Widget
1527  */
1528 EAPI void
1529 elm_widget_focus_custom_chain_append(Evas_Object *obj,
1530                                      Evas_Object *child,
1531                                      Evas_Object *relative_child)
1532 {
1533    API_ENTRY return;
1534    EINA_SAFETY_ON_NULL_RETURN(child);
1535    if (!sd->focus_next_func)
1536      return;
1537
1538    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1539                                        _elm_object_focus_chain_del_cb, sd);
1540
1541    if (!relative_child)
1542      {
1543         sd->focus_chain = eina_list_append(sd->focus_chain, child);
1544         return;
1545      }
1546
1547    sd->focus_chain = eina_list_append_relative(sd->focus_chain, child, relative_child);
1548    return;
1549 }
1550
1551 /**
1552  * @internal
1553  *
1554  * Prepend object to custom focus chain.
1555  *
1556  * @note If relative_child equal to NULL or not in custom chain, the object
1557  * will be added in begin.
1558  *
1559  * @note On focus cycle, only will be evaluated children of this container.
1560  *
1561  * @param obj The container widget
1562  * @param child The child to be added in custom chain
1563  * @param relative_child The relative object to position the child
1564  * @ingroup Widget
1565  */
1566 EAPI void
1567 elm_widget_focus_custom_chain_prepend(Evas_Object *obj,
1568                                       Evas_Object *child,
1569                                       Evas_Object *relative_child)
1570 {
1571    API_ENTRY return;
1572    EINA_SAFETY_ON_NULL_RETURN(child);
1573    if (!sd->focus_next_func)
1574      return;
1575
1576    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1577                                        _elm_object_focus_chain_del_cb, sd);
1578
1579    if (!relative_child)
1580      {
1581         sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1582         return;
1583      }
1584
1585    sd->focus_chain = eina_list_prepend_relative(sd->focus_chain, child, relative_child);
1586    return;
1587 }
1588
1589 /**
1590  * @internal
1591  *
1592  * Give focus to next object in object tree.
1593  *
1594  * Give focus to next object in focus chain of one object sub-tree.
1595  * If the last object of chain already have focus, the focus will go to the
1596  * first object of chain.
1597  *
1598  * @param obj The widget root of sub-tree
1599  * @param dir Direction to cycle the focus
1600  *
1601  * @ingroup Widget
1602  */
1603 EAPI void
1604 elm_widget_focus_cycle(Evas_Object        *obj,
1605                        Elm_Focus_Direction dir)
1606 {
1607    Evas_Object *target = NULL;
1608    if (!_elm_widget_is(obj))
1609      return;
1610    elm_widget_focus_next_get(obj, dir, &target);
1611    if (target)
1612      elm_widget_focus_steal(target);
1613 }
1614
1615 /**
1616  * @internal
1617  *
1618  * Give focus to near object in one direction.
1619  *
1620  * Give focus to near object in direction of one object.
1621  * If none focusable object in given direction, the focus will not change.
1622  *
1623  * @param obj The reference widget
1624  * @param x Horizontal component of direction to focus
1625  * @param y Vertical component of direction to focus
1626  *
1627  * @ingroup Widget
1628  */
1629 EAPI void
1630 elm_widget_focus_direction_go(Evas_Object *obj __UNUSED__,
1631                               int          x __UNUSED__,
1632                               int          y __UNUSED__)
1633 {
1634    return; /* TODO */
1635 }
1636
1637 /**
1638  * @internal
1639  *
1640  * Get next object in focus chain of object tree.
1641  *
1642  * Get next object in focus chain of one object sub-tree.
1643  * Return the next object by reference. If don't have any candidate to receive
1644  * focus before chain end, the first candidate will be returned.
1645  *
1646  * @param obj The widget root of sub-tree
1647  * @param dir Direction os focus chain
1648  * @param next The next object in focus chain
1649  * @return EINA_TRUE if don't need focus chain restart/loop back
1650  *         to use 'next' obj.
1651  *
1652  * @ingroup Widget
1653  */
1654 EAPI Eina_Bool
1655 elm_widget_focus_next_get(const Evas_Object  *obj,
1656                           Elm_Focus_Direction dir,
1657                           Evas_Object       **next)
1658 {
1659    if (!next)
1660      return EINA_FALSE;
1661    *next = NULL;
1662
1663    API_ENTRY return EINA_FALSE;
1664
1665    /* Ignore if disabled */
1666    if ((!evas_object_visible_get(obj))
1667        || (elm_widget_disabled_get(obj))
1668        || (elm_widget_tree_unfocusable_get(obj)))
1669      return EINA_FALSE;
1670
1671    /* Try use hook */
1672    if (sd->focus_next_func)
1673      return sd->focus_next_func(obj, dir, next);
1674
1675    if (!elm_widget_can_focus_get(obj))
1676      return EINA_FALSE;
1677
1678    /* Return */
1679    *next = (Evas_Object *)obj;
1680    return !elm_widget_focus_get(obj);
1681 }
1682
1683 /**
1684  * @internal
1685  *
1686  * Get next object in focus chain of object tree in list.
1687  *
1688  * Get next object in focus chain of one object sub-tree ordered by one list.
1689  * Return the next object by reference. If don't have any candidate to receive
1690  * focus before list end, the first candidate will be returned.
1691  *
1692  * @param obj The widget root of sub-tree
1693  * @param dir Direction os focus chain
1694  * @param items list with ordered objects
1695  * @param list_data_get function to get the object from one item of list
1696  * @param next The next object in focus chain
1697  * @return EINA_TRUE if don't need focus chain restart/loop back
1698  *         to use 'next' obj.
1699  *
1700  * @ingroup Widget
1701  */
1702 EAPI Eina_Bool
1703 elm_widget_focus_list_next_get(const Evas_Object  *obj,
1704                                const Eina_List    *items,
1705                                void *(*list_data_get)(const Eina_List * list),
1706                                Elm_Focus_Direction dir,
1707                                Evas_Object       **next)
1708 {
1709    Eina_List *(*list_next)(const Eina_List * list) = NULL;
1710
1711    if (!next)
1712      return EINA_FALSE;
1713    *next = NULL;
1714
1715    if (!_elm_widget_is(obj))
1716      return EINA_FALSE;
1717
1718    if (!items)
1719      return EINA_FALSE;
1720
1721    /* Direction */
1722    if (dir == ELM_FOCUS_PREVIOUS)
1723      {
1724         items = eina_list_last(items);
1725         list_next = eina_list_prev;
1726      }
1727    else if (dir == ELM_FOCUS_NEXT)
1728      list_next = eina_list_next;
1729    else
1730      return EINA_FALSE;
1731
1732    const Eina_List *l = items;
1733
1734    /* Recovery last focused sub item */
1735    if (elm_widget_focus_get(obj))
1736      for (; l; l = list_next(l))
1737        {
1738           Evas_Object *cur = list_data_get(l);
1739           if (elm_widget_focus_get(cur)) break;
1740        }
1741
1742    const Eina_List *start = l;
1743    Evas_Object *to_focus = NULL;
1744
1745    /* Interate sub items */
1746    /* Go to end of list */
1747    for (; l; l = list_next(l))
1748      {
1749         Evas_Object *tmp = NULL;
1750         Evas_Object *cur = list_data_get(l);
1751
1752         if (elm_widget_parent_get(cur) != obj)
1753           continue;
1754
1755         /* Try Focus cycle in subitem */
1756         if (elm_widget_focus_next_get(cur, dir, &tmp))
1757           {
1758              *next = tmp;
1759              return EINA_TRUE;
1760           }
1761         else if ((tmp) && (!to_focus))
1762           to_focus = tmp;
1763      }
1764
1765    l = items;
1766
1767    /* Get First possible */
1768    for (; l != start; l = list_next(l))
1769      {
1770         Evas_Object *tmp = NULL;
1771         Evas_Object *cur = list_data_get(l);
1772
1773         if (elm_widget_parent_get(cur) != obj)
1774           continue;
1775
1776         /* Try Focus cycle in subitem */
1777         elm_widget_focus_next_get(cur, dir, &tmp);
1778         if (tmp)
1779           {
1780              *next = tmp;
1781              return EINA_FALSE;
1782           }
1783      }
1784
1785    *next = to_focus;
1786    return EINA_FALSE;
1787 }
1788
1789 EAPI void
1790 elm_widget_signal_emit(Evas_Object *obj,
1791                        const char  *emission,
1792                        const char  *source)
1793 {
1794    API_ENTRY return;
1795    if (!sd->signal_func) return;
1796    sd->signal_func(obj, emission, source);
1797 }
1798
1799 static void
1800 _edje_signal_callback(void        *data,
1801                       Evas_Object *obj __UNUSED__,
1802                       const char  *emission,
1803                       const char  *source)
1804 {
1805    Edje_Signal_Data *esd = data;
1806    esd->func(esd->data, esd->obj, emission, source);
1807 }
1808
1809 EAPI void
1810 elm_widget_signal_callback_add(Evas_Object   *obj,
1811                                const char    *emission,
1812                                const char    *source,
1813                                Edje_Signal_Cb func,
1814                                void          *data)
1815 {
1816    Edje_Signal_Data *esd;
1817    API_ENTRY return;
1818    if (!sd->callback_add_func) return;
1819    EINA_SAFETY_ON_NULL_RETURN(func);
1820
1821    esd = ELM_NEW(Edje_Signal_Data);
1822    if (!esd) return;
1823
1824    esd->obj = obj;
1825    esd->func = func;
1826    esd->emission = eina_stringshare_add(emission);
1827    esd->source = eina_stringshare_add(source);
1828    esd->data = data;
1829    sd->edje_signals = eina_list_append(sd->edje_signals, esd);
1830    sd->callback_add_func(obj, emission, source, _edje_signal_callback, esd);
1831 }
1832
1833 EAPI void *
1834 elm_widget_signal_callback_del(Evas_Object   *obj,
1835                                const char    *emission,
1836                                const char    *source,
1837                                Edje_Signal_Cb func)
1838 {
1839    Edje_Signal_Data *esd;
1840    Eina_List *l;
1841    void *data = NULL;
1842    API_ENTRY return NULL;
1843    if (!sd->callback_del_func) return NULL;
1844
1845    EINA_LIST_FOREACH(sd->edje_signals, l, esd)
1846      {
1847         if ((esd->func == func) && (!strcmp(esd->emission, emission)) &&
1848             (!strcmp(esd->source, source)))
1849           {
1850              sd->edje_signals = eina_list_remove_list(sd->edje_signals, l);
1851              eina_stringshare_del(esd->emission);
1852              eina_stringshare_del(esd->source);
1853              data = esd->data;
1854              free(esd);
1855              break;
1856           }
1857      }
1858    sd->callback_del_func(obj, emission, source, _edje_signal_callback, esd);
1859    return data;
1860 }
1861
1862 EAPI void
1863 elm_widget_focus_set(Evas_Object *obj,
1864                      int          first)
1865 {
1866    API_ENTRY return;
1867    if (!sd->focused)
1868      {
1869         focus_order++;
1870         sd->focus_order = focus_order;
1871         sd->focused = EINA_TRUE;
1872         if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1873      }
1874    if (sd->focus_func)
1875      {
1876         sd->focus_func(obj);
1877         return;
1878      }
1879    else
1880      {
1881         if (first)
1882           {
1883              if ((_is_focusable(sd->resize_obj)) &&
1884                  (!elm_widget_disabled_get(sd->resize_obj)))
1885                {
1886                   elm_widget_focus_set(sd->resize_obj, first);
1887                }
1888              else
1889                {
1890                   const Eina_List *l;
1891                   Evas_Object *child;
1892                   EINA_LIST_FOREACH(sd->subobjs, l, child)
1893                     {
1894                        if ((_is_focusable(child)) &&
1895                            (!elm_widget_disabled_get(child)))
1896                          {
1897                             elm_widget_focus_set(child, first);
1898                             break;
1899                          }
1900                     }
1901                }
1902           }
1903         else
1904           {
1905              const Eina_List *l;
1906              Evas_Object *child;
1907              EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
1908                {
1909                   if ((_is_focusable(child)) &&
1910                       (!elm_widget_disabled_get(child)))
1911                     {
1912                        elm_widget_focus_set(child, first);
1913                        break;
1914                     }
1915                }
1916              if (!l)
1917                {
1918                   if ((_is_focusable(sd->resize_obj)) &&
1919                       (!elm_widget_disabled_get(sd->resize_obj)))
1920                     {
1921                        elm_widget_focus_set(sd->resize_obj, first);
1922                     }
1923                }
1924           }
1925      }
1926 }
1927
1928 EAPI Evas_Object *
1929 elm_widget_parent_get(const Evas_Object *obj)
1930 {
1931    API_ENTRY return NULL;
1932    return sd->parent_obj;
1933 }
1934
1935 EAPI void
1936 elm_widget_focused_object_clear(Evas_Object *obj)
1937 {
1938    API_ENTRY return;
1939    if (!sd->focused) return;
1940    if (elm_widget_focus_get(sd->resize_obj))
1941      elm_widget_focused_object_clear(sd->resize_obj);
1942    else
1943      {
1944         const Eina_List *l;
1945         Evas_Object *child;
1946         EINA_LIST_FOREACH(sd->subobjs, l, child)
1947           {
1948              if (elm_widget_focus_get(child))
1949                {
1950                   elm_widget_focused_object_clear(child);
1951                   break;
1952                }
1953           }
1954      }
1955    sd->focused = EINA_FALSE;
1956    if (sd->on_focus_func) sd->on_focus_func(sd->on_focus_data, obj);
1957    if (sd->focus_func) sd->focus_func(obj);
1958 }
1959
1960 EAPI void
1961 elm_widget_focus_steal(Evas_Object *obj)
1962 {
1963    Evas_Object *parent, *parent2, *o;
1964    API_ENTRY return;
1965
1966    if (sd->focused) return;
1967    if (sd->disabled) return;
1968    if (!sd->can_focus) return;
1969    if (sd->tree_unfocusable) return;
1970    parent = obj;
1971    for (;;)
1972      {
1973         o = elm_widget_parent_get(parent);
1974         if (!o) break;
1975         sd = evas_object_smart_data_get(o);
1976         if (sd->disabled || sd->tree_unfocusable) return;
1977         if (sd->focused) break;
1978         parent = o;
1979      }
1980    if ((!elm_widget_parent_get(parent)) &&
1981        (!elm_widget_parent2_get(parent)))
1982       elm_widget_focused_object_clear(parent);
1983    else
1984      {
1985         parent2 = elm_widget_parent_get(parent);
1986         if (!parent2) parent2 = elm_widget_parent2_get(parent);
1987         parent = parent2;
1988         sd = evas_object_smart_data_get(parent);
1989         if (sd)
1990           {
1991              if ((sd->resize_obj) && (elm_widget_focus_get(sd->resize_obj)))
1992                 elm_widget_focused_object_clear(sd->resize_obj);
1993              else
1994                {
1995                   const Eina_List *l;
1996                   Evas_Object *child;
1997                   EINA_LIST_FOREACH(sd->subobjs, l, child)
1998                     {
1999                        if (elm_widget_focus_get(child))
2000                          {
2001                             elm_widget_focused_object_clear(child);
2002                             break;
2003                          }
2004                     }
2005                }
2006           }
2007      }
2008    _parent_focus(obj);
2009    return;
2010 }
2011
2012 EAPI void
2013 elm_widget_focus_restore(Evas_Object *obj)
2014 {
2015    Evas_Object *newest = NULL;
2016    unsigned int newest_focus_order = 0;
2017    API_ENTRY return;
2018
2019    newest = _newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
2020    if (newest)
2021      {
2022         elm_object_focus_set(newest, EINA_FALSE);
2023         elm_object_focus_set(newest, EINA_TRUE);
2024      }
2025 }
2026
2027 void
2028 _elm_widget_top_win_focused_set(Evas_Object *obj, Eina_Bool top_win_focused)
2029 {
2030    const Eina_List *l;
2031    Evas_Object *child;
2032    API_ENTRY return;
2033
2034    if (sd->top_win_focused == top_win_focused) return;
2035    if (sd->resize_obj)
2036      _elm_widget_top_win_focused_set(sd->resize_obj, top_win_focused);
2037    EINA_LIST_FOREACH(sd->subobjs, l, child)
2038      {
2039         _elm_widget_top_win_focused_set(child, top_win_focused);
2040      }
2041    sd->top_win_focused = top_win_focused;
2042 }
2043
2044 Eina_Bool
2045 _elm_widget_top_win_focused_get(const Evas_Object *obj)
2046 {
2047    API_ENTRY return EINA_FALSE;
2048    return sd->top_win_focused;
2049 }
2050
2051 EAPI void
2052 elm_widget_activate(Evas_Object *obj)
2053 {
2054    API_ENTRY return;
2055    elm_widget_change(obj);
2056    if (sd->activate_func) sd->activate_func(obj);
2057 }
2058
2059 EAPI void
2060 elm_widget_change(Evas_Object *obj)
2061 {
2062    API_ENTRY return;
2063    elm_widget_change(elm_widget_parent_get(obj));
2064    if (sd->on_change_func) sd->on_change_func(sd->on_change_data, obj);
2065 }
2066
2067 EAPI void
2068 elm_widget_disabled_set(Evas_Object *obj,
2069                         Eina_Bool    disabled)
2070 {
2071    API_ENTRY return;
2072
2073    if (sd->disabled == disabled) return;
2074    sd->disabled = !!disabled;
2075    elm_widget_focus_disabled_handle(obj);
2076    if (sd->disable_func) sd->disable_func(obj);
2077 }
2078
2079 EAPI Eina_Bool
2080 elm_widget_disabled_get(const Evas_Object *obj)
2081 {
2082    API_ENTRY return 0;
2083    return sd->disabled;
2084 }
2085
2086 EAPI void
2087 elm_widget_show_region_set(Evas_Object *obj,
2088                            Evas_Coord   x,
2089                            Evas_Coord   y,
2090                            Evas_Coord   w,
2091                            Evas_Coord   h,
2092                            Eina_Bool    forceshow)
2093 {
2094    Evas_Object *parent_obj, *child_obj;
2095    Evas_Coord px, py, cx, cy;
2096
2097    API_ENTRY return;
2098    if (!forceshow && (x == sd->rx) && (y == sd->ry)
2099             && (w == sd->rw) && (h == sd->rh)) return;
2100    sd->rx = x;
2101    sd->ry = y;
2102    sd->rw = w;
2103    sd->rh = h;
2104    if (sd->on_show_region_func)
2105      sd->on_show_region_func(sd->on_show_region_data, obj);
2106
2107    do
2108      {
2109         parent_obj = sd->parent_obj;
2110         child_obj = sd->obj;
2111         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
2112         sd = evas_object_smart_data_get(parent_obj);
2113         if (!sd) break;
2114
2115         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
2116         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
2117
2118         x += (cx - px);
2119         y += (cy - py);
2120         sd->rx = x;
2121         sd->ry = y;
2122         sd->rw = w;
2123         sd->rh = h;
2124
2125         if (sd->on_show_region_func)
2126           {
2127              sd->on_show_region_func(sd->on_show_region_data, parent_obj);
2128           }
2129      }
2130    while (parent_obj);
2131 }
2132
2133 EAPI void
2134 elm_widget_show_region_get(const Evas_Object *obj,
2135                            Evas_Coord        *x,
2136                            Evas_Coord        *y,
2137                            Evas_Coord        *w,
2138                            Evas_Coord        *h)
2139 {
2140    API_ENTRY return;
2141    if (x) *x = sd->rx;
2142    if (y) *y = sd->ry;
2143    if (w) *w = sd->rw;
2144    if (h) *h = sd->rh;
2145 }
2146
2147 /**
2148  * @internal
2149  *
2150  * Get the focus region of the given widget.
2151  *
2152  * The focus region is the area of a widget that should brought into the
2153  * visible area when the widget is focused. Mostly used to show the part of
2154  * an entry where the cursor is, for example. The area returned is relative
2155  * to the object @p obj.
2156  * If the @p obj doesn't have the proper on_focus_region_hook set, this
2157  * function will return the full size of the object.
2158  *
2159  * @param obj The widget object
2160  * @param x Where to store the x coordinate of the area
2161  * @param y Where to store the y coordinate of the area
2162  * @param w Where to store the width of the area
2163  * @param h Where to store the height of the area
2164  *
2165  * @ingroup Widget
2166  */
2167 EAPI void
2168 elm_widget_focus_region_get(const Evas_Object *obj,
2169                             Evas_Coord        *x,
2170                             Evas_Coord        *y,
2171                             Evas_Coord        *w,
2172                             Evas_Coord        *h)
2173 {
2174    Smart_Data *sd;
2175
2176    if (!obj) return;
2177
2178    sd = evas_object_smart_data_get(obj);
2179    if (!sd || !_elm_widget_is(obj) || !sd->on_focus_region_func)
2180      {
2181         evas_object_geometry_get(obj, NULL, NULL, w, h);
2182         if (x) *x = 0;
2183         if (y) *y = 0;
2184         return;
2185      }
2186    sd->on_focus_region_func(obj, x, y, w, h);
2187 }
2188
2189 EAPI void
2190 elm_widget_scroll_hold_push(Evas_Object *obj)
2191 {
2192    API_ENTRY return;
2193    sd->scroll_hold++;
2194    if (sd->scroll_hold == 1)
2195      evas_object_smart_callback_call(obj, "scroll-hold-on", obj);
2196    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
2197    // FIXME: on delete/reparent hold pop
2198 }
2199
2200 EAPI void
2201 elm_widget_scroll_hold_pop(Evas_Object *obj)
2202 {
2203    API_ENTRY return;
2204    sd->scroll_hold--;
2205    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
2206    if (!sd->scroll_hold)
2207      evas_object_smart_callback_call(obj, "scroll-hold-off", obj);
2208    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
2209 }
2210
2211 EAPI int
2212 elm_widget_scroll_hold_get(const Evas_Object *obj)
2213 {
2214    API_ENTRY return 0;
2215    return sd->scroll_hold;
2216 }
2217
2218 EAPI void
2219 elm_widget_scroll_freeze_push(Evas_Object *obj)
2220 {
2221    API_ENTRY return;
2222    sd->scroll_freeze++;
2223    if (sd->scroll_freeze == 1)
2224      evas_object_smart_callback_call(obj, "scroll-freeze-on", obj);
2225    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
2226    // FIXME: on delete/reparent freeze pop
2227 }
2228
2229 EAPI void
2230 elm_widget_scroll_freeze_pop(Evas_Object *obj)
2231 {
2232    API_ENTRY return;
2233    sd->scroll_freeze--;
2234    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
2235    if (!sd->scroll_freeze)
2236      evas_object_smart_callback_call(obj, "scroll-freeze-off", obj);
2237    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
2238 }
2239
2240 EAPI int
2241 elm_widget_scroll_freeze_get(const Evas_Object *obj)
2242 {
2243    API_ENTRY return 0;
2244    return sd->scroll_freeze;
2245 }
2246
2247 EAPI void
2248 elm_widget_scale_set(Evas_Object *obj,
2249                      double       scale)
2250 {
2251    API_ENTRY return;
2252    if (scale <= 0.0) scale = 0.0;
2253    if (sd->scale != scale)
2254      {
2255         sd->scale = scale;
2256         elm_widget_theme(obj);
2257      }
2258 }
2259
2260 EAPI double
2261 elm_widget_scale_get(const Evas_Object *obj)
2262 {
2263    API_ENTRY return 1.0;
2264    // FIXME: save walking up the tree by storing/caching parent scale
2265    if (sd->scale == 0.0)
2266      {
2267         if (sd->parent_obj)
2268           return elm_widget_scale_get(sd->parent_obj);
2269         else
2270           return 1.0;
2271      }
2272    return sd->scale;
2273 }
2274
2275 EAPI void
2276 elm_widget_theme_set(Evas_Object *obj,
2277                      Elm_Theme   *th)
2278 {
2279    API_ENTRY return;
2280    if (sd->theme != th)
2281      {
2282         if (sd->theme) elm_theme_free(sd->theme);
2283         sd->theme = th;
2284         if (th) th->ref++;
2285         elm_widget_theme(obj);
2286      }
2287 }
2288
2289 EAPI void
2290 elm_widget_text_part_set(Evas_Object *obj, const char *part, const char *label)
2291 {
2292    API_ENTRY return;
2293
2294    if (!sd->on_text_set_func)
2295      return;
2296
2297    sd->on_text_set_func(obj, part, label);
2298 }
2299
2300 EAPI const char *
2301 elm_widget_text_part_get(const Evas_Object *obj, const char *part)
2302 {
2303    API_ENTRY return NULL;
2304
2305    if (!sd->on_text_get_func)
2306      return NULL;
2307
2308    return sd->on_text_get_func(obj, part);
2309 }
2310
2311 EAPI void
2312 elm_widget_domain_translatable_text_part_set(Evas_Object *obj, const char *part, const char *domain, const char *label)
2313 {
2314    const char *str;
2315    Eina_List *l;
2316    Elm_Translate_String_Data *ts = NULL;
2317    API_ENTRY return;
2318
2319    str = eina_stringshare_add(part);
2320    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2321       if (ts->id == str)
2322         break;
2323       else
2324         ts = NULL;
2325
2326    if (!ts && !label)
2327      eina_stringshare_del(str);
2328    else if (!ts)
2329      {
2330         ts = malloc(sizeof(Elm_Translate_String_Data));
2331         if (!ts) return;
2332
2333         ts->id = str;
2334         ts->domain = eina_stringshare_add(domain);
2335         ts->string = eina_stringshare_add(label);
2336         sd->translate_strings = eina_list_append(sd->translate_strings, ts);
2337      }
2338    else
2339      {
2340         if (label)
2341           {
2342              eina_stringshare_replace(&ts->domain, domain);
2343              eina_stringshare_replace(&ts->string, label);
2344           }
2345         else
2346           {
2347              sd->translate_strings = eina_list_remove_list(
2348                                                 sd->translate_strings, l);
2349              eina_stringshare_del(ts->id);
2350              eina_stringshare_del(ts->domain);
2351              eina_stringshare_del(ts->string);
2352              free(ts);
2353           }
2354         eina_stringshare_del(str);
2355      }
2356
2357 #ifdef HAVE_GETTEXT
2358    if (label && label[0])
2359      label = dgettext(domain, label);
2360 #endif
2361    elm_widget_text_part_set(obj, part, label);
2362 }
2363
2364 EAPI const char *
2365 elm_widget_translatable_text_part_get(const Evas_Object *obj, const char *part)
2366 {
2367    const char *str, *ret = NULL;
2368    Eina_List *l;
2369    Elm_Translate_String_Data *ts;
2370    API_ENTRY return NULL;
2371
2372    str = eina_stringshare_add(part);
2373    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2374       if (ts->id == str)
2375         {
2376            ret = ts->string;
2377            break;
2378         }
2379    eina_stringshare_del(str);
2380    return ret;
2381 }
2382
2383 EAPI void
2384 elm_widget_translate(Evas_Object *obj)
2385 {
2386    const Eina_List *l;
2387    Evas_Object *child;
2388    Elm_Translate_String_Data *ts;
2389
2390    API_ENTRY return;
2391    EINA_LIST_FOREACH(sd->subobjs, l, child) elm_widget_translate(child);
2392    if (sd->resize_obj) elm_widget_translate(sd->resize_obj);
2393    if (sd->hover_obj) elm_widget_translate(sd->hover_obj);
2394    if (sd->translate_func) sd->translate_func(obj);
2395
2396 #ifdef HAVE_GETTEXT
2397    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
2398      {
2399         const char *s = dgettext(ts->domain, ts->string);
2400         elm_widget_text_part_set(obj, ts->id, s);
2401      }
2402 #endif
2403 }
2404
2405 EAPI void
2406 elm_widget_content_part_set(Evas_Object *obj, const char *part, Evas_Object *content)
2407 {
2408    API_ENTRY return;
2409
2410    if (!sd->on_content_set_func)  return;
2411    sd->on_content_set_func(obj, part, content);
2412 }
2413
2414 EAPI Evas_Object *
2415 elm_widget_content_part_get(const Evas_Object *obj, const char *part)
2416 {
2417    API_ENTRY return NULL;
2418
2419    if (!sd->on_content_get_func) return NULL;
2420    return sd->on_content_get_func(obj, part);
2421 }
2422
2423 EAPI Evas_Object *
2424 elm_widget_content_part_unset(Evas_Object *obj, const char *part)
2425 {
2426    API_ENTRY return NULL;
2427
2428    if (!sd->on_content_unset_func) return NULL;
2429    return sd->on_content_unset_func(obj, part);
2430 }
2431
2432 EAPI void
2433 elm_widget_access_info_set(Evas_Object *obj, const char *txt)
2434 {
2435    API_ENTRY return;
2436    if (sd->access_info) eina_stringshare_del(sd->access_info);
2437    if (!txt) sd->access_info = NULL;
2438    else sd->access_info = eina_stringshare_add(txt);
2439 }
2440
2441 EAPI const char *
2442 elm_widget_access_info_get(Evas_Object *obj)
2443 {
2444    API_ENTRY return NULL;
2445    return sd->access_info;
2446 }
2447
2448 EAPI Elm_Theme *
2449 elm_widget_theme_get(const Evas_Object *obj)
2450 {
2451    API_ENTRY return NULL;
2452    if (!sd->theme)
2453      {
2454         if (sd->parent_obj)
2455           return elm_widget_theme_get(sd->parent_obj);
2456         else
2457           return NULL;
2458      }
2459    return sd->theme;
2460 }
2461
2462 EAPI void
2463 elm_widget_style_set(Evas_Object *obj,
2464                      const char  *style)
2465 {
2466    API_ENTRY return;
2467
2468    if (eina_stringshare_replace(&sd->style, style))
2469      elm_widget_theme(obj);
2470 }
2471
2472 EAPI const char *
2473 elm_widget_style_get(const Evas_Object *obj)
2474 {
2475    API_ENTRY return NULL;
2476    if (sd->style) return sd->style;
2477    return "default";
2478 }
2479
2480 EAPI void
2481 elm_widget_type_set(Evas_Object *obj,
2482                     const char  *type)
2483 {
2484    API_ENTRY return;
2485    eina_stringshare_replace(&sd->type, type);
2486 }
2487
2488 EAPI const char *
2489 elm_widget_type_get(const Evas_Object *obj)
2490 {
2491    API_ENTRY return NULL;
2492    if (sd->type) return sd->type;
2493    return "";
2494 }
2495
2496 EAPI void
2497 elm_widget_tooltip_add(Evas_Object *obj,
2498                        Elm_Tooltip *tt)
2499 {
2500    API_ENTRY return;
2501    sd->tooltips = eina_list_append(sd->tooltips, tt);
2502 }
2503
2504 EAPI void
2505 elm_widget_tooltip_del(Evas_Object *obj,
2506                        Elm_Tooltip *tt)
2507 {
2508    API_ENTRY return;
2509    sd->tooltips = eina_list_remove(sd->tooltips, tt);
2510 }
2511
2512 EAPI void
2513 elm_widget_cursor_add(Evas_Object *obj,
2514                       Elm_Cursor  *cur)
2515 {
2516    API_ENTRY return;
2517    sd->cursors = eina_list_append(sd->cursors, cur);
2518 }
2519
2520 EAPI void
2521 elm_widget_cursor_del(Evas_Object *obj,
2522                       Elm_Cursor  *cur)
2523 {
2524    API_ENTRY return;
2525    sd->cursors = eina_list_remove(sd->cursors, cur);
2526 }
2527
2528 EAPI void
2529 elm_widget_drag_lock_x_set(Evas_Object *obj,
2530                            Eina_Bool    lock)
2531 {
2532    API_ENTRY return;
2533    if (sd->drag_x_locked == lock) return;
2534    sd->drag_x_locked = lock;
2535    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
2536    else _propagate_x_drag_lock(obj, -1);
2537 }
2538
2539 EAPI void
2540 elm_widget_drag_lock_y_set(Evas_Object *obj,
2541                            Eina_Bool    lock)
2542 {
2543    API_ENTRY return;
2544    if (sd->drag_y_locked == lock) return;
2545    sd->drag_y_locked = lock;
2546    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
2547    else _propagate_y_drag_lock(obj, -1);
2548 }
2549
2550 EAPI Eina_Bool
2551 elm_widget_drag_lock_x_get(const Evas_Object *obj)
2552 {
2553    API_ENTRY return EINA_FALSE;
2554    return sd->drag_x_locked;
2555 }
2556
2557 EAPI Eina_Bool
2558 elm_widget_drag_lock_y_get(const Evas_Object *obj)
2559 {
2560    API_ENTRY return EINA_FALSE;
2561    return sd->drag_y_locked;
2562 }
2563
2564 EAPI int
2565 elm_widget_drag_child_locked_x_get(const Evas_Object *obj)
2566 {
2567    API_ENTRY return 0;
2568    return sd->child_drag_x_locked;
2569 }
2570
2571 EAPI int
2572 elm_widget_drag_child_locked_y_get(const Evas_Object *obj)
2573 {
2574    API_ENTRY return 0;
2575    return sd->child_drag_y_locked;
2576 }
2577
2578 EAPI Eina_Bool
2579 elm_widget_theme_object_set(Evas_Object *obj,
2580                             Evas_Object *edj,
2581                             const char  *wname,
2582                             const char  *welement,
2583                             const char  *wstyle)
2584 {
2585    API_ENTRY return EINA_FALSE;
2586    return _elm_theme_object_set(obj, edj, wname, welement, wstyle);
2587 }
2588
2589 EAPI Eina_Bool
2590 elm_widget_is_check(const Evas_Object *obj)
2591 {
2592    static int abort_on_warn = -1;
2593    if (elm_widget_is(obj))
2594       return EINA_TRUE;
2595
2596    ERR("Passing Object: %p.", obj);
2597    if (abort_on_warn == -1)
2598      {
2599         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2600         else abort_on_warn = 0;
2601      }
2602    if (abort_on_warn == 1) abort();
2603    return EINA_FALSE;
2604 }
2605
2606 EAPI Eina_Bool
2607 elm_widget_type_check(const Evas_Object *obj,
2608                       const char        *type,
2609                       const char        *func)
2610 {
2611    const char *provided, *expected = "(unknown)";
2612    static int abort_on_warn = -1;
2613    provided = elm_widget_type_get(obj);
2614    if (EINA_LIKELY(provided == type)) return EINA_TRUE;
2615    if (type) expected = type;
2616    if ((!provided) || (!provided[0]))
2617      {
2618         provided = evas_object_type_get(obj);
2619         if ((!provided) || (!provided[0]))
2620           provided = "(unknown)";
2621      }
2622    ERR("Passing Object: %p in function: %s, of type: '%s' when expecting type: '%s'", obj, func, provided, expected);
2623    if (abort_on_warn == -1)
2624      {
2625         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2626         else abort_on_warn = 0;
2627      }
2628    if (abort_on_warn == 1) abort();
2629    return EINA_FALSE;
2630 }
2631
2632 /**
2633  * @internal
2634  *
2635  * Split string in words
2636  *
2637  * @param str Source string
2638  * @return List of const words
2639  *
2640  * @see elm_widget_stringlist_free()
2641  * @ingroup Widget
2642  */
2643 EAPI Eina_List *
2644 elm_widget_stringlist_get(const char *str)
2645 {
2646    Eina_List *list = NULL;
2647    const char *s, *b;
2648    if (!str) return NULL;
2649    for (b = s = str; 1; s++)
2650      {
2651         if ((*s == ' ') || (!*s))
2652           {
2653              char *t = malloc(s - b + 1);
2654              if (t)
2655                {
2656                   strncpy(t, b, s - b);
2657                   t[s - b] = 0;
2658                   list = eina_list_append(list, eina_stringshare_add(t));
2659                   free(t);
2660                }
2661              b = s + 1;
2662           }
2663         if (!*s) break;
2664      }
2665    return list;
2666 }
2667
2668 EAPI void
2669 elm_widget_stringlist_free(Eina_List *list)
2670 {
2671    const char *s;
2672    EINA_LIST_FREE(list, s) eina_stringshare_del(s);
2673 }
2674
2675 EAPI void
2676 elm_widget_focus_hide_handle(Evas_Object *obj)
2677 {
2678    _if_focused_revert(obj, EINA_TRUE);
2679 }
2680
2681 EAPI void
2682 elm_widget_focus_mouse_up_handle(Evas_Object *obj)
2683 {
2684    Evas_Object *o = obj;
2685    do
2686      {
2687         if (_elm_widget_is(o)) break;
2688         o = evas_object_smart_parent_get(o);
2689      }
2690    while (o);
2691    if (!o) return;
2692    if (!_is_focusable(o)) return;
2693    elm_widget_focus_steal(o);
2694 }
2695
2696 EAPI void
2697 elm_widget_focus_tree_unfocusable_handle(Evas_Object *obj)
2698 {
2699    API_ENTRY return;
2700
2701    if (!elm_widget_parent_get(obj))
2702      elm_widget_focused_object_clear(obj);
2703    else
2704      _if_focused_revert(obj, EINA_TRUE);
2705 }
2706
2707 EAPI void
2708 elm_widget_focus_disabled_handle(Evas_Object *obj)
2709 {
2710    API_ENTRY return;
2711
2712    elm_widget_focus_tree_unfocusable_handle(obj);
2713 }
2714
2715 /**
2716  * @internal
2717  *
2718  * Allocate a new Elm_Widget_Item-derived structure.
2719  *
2720  * The goal of this structure is to provide common ground for actions
2721  * that a widget item have, such as the owner widget, callback to
2722  * notify deletion, data pointer and maybe more.
2723  *
2724  * @param widget the owner widget that holds this item, must be an elm_widget!
2725  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
2726  *        be used to allocate memory.
2727  *
2728  * @return allocated memory that is already zeroed out, or NULL on errors.
2729  *
2730  * @see elm_widget_item_new() convenience macro.
2731  * @see elm_widget_item_del() to release memory.
2732  * @ingroup Widget
2733  */
2734 EAPI Elm_Widget_Item *
2735 _elm_widget_item_new(Evas_Object *widget,
2736                      size_t       alloc_size)
2737 {
2738    if (!_elm_widget_is(widget))
2739      return NULL;
2740
2741    Elm_Widget_Item *item;
2742
2743    EINA_SAFETY_ON_TRUE_RETURN_VAL(alloc_size < sizeof(Elm_Widget_Item), NULL);
2744    EINA_SAFETY_ON_TRUE_RETURN_VAL(!_elm_widget_is(widget), NULL);
2745
2746    item = calloc(1, alloc_size);
2747    EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
2748
2749    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
2750    item->widget = widget;
2751    return item;
2752 }
2753
2754 /**
2755  * @internal
2756  *
2757  * Releases widget item memory, calling back del_cb() if it exists.
2758  *
2759  * If there is a Elm_Widget_Item::del_cb, then it will be called prior
2760  * to memory release. Note that elm_widget_item_pre_notify_del() calls
2761  * this function and then unset it, thus being useful for 2 step
2762  * cleanup whenever the del_cb may use any of the data that must be
2763  * deleted from item.
2764  *
2765  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
2766  * is presented!
2767  *
2768  * @param item a valid #Elm_Widget_Item to be deleted.
2769  * @see elm_widget_item_del() convenience macro.
2770  * @ingroup Widget
2771  */
2772 EAPI void
2773 _elm_widget_item_del(Elm_Widget_Item *item)
2774 {
2775    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2776
2777    if (item->del_cb)
2778      item->del_cb((void *)item->data, item->widget, item);
2779
2780    if (item->view)
2781      evas_object_del(item->view);
2782
2783    if (item->access)
2784      {
2785         _elm_access_clear(item->access);
2786         free(item->access);
2787         item->access = NULL;
2788      }
2789    if (item->access_info)
2790      {
2791         eina_stringshare_del(item->access_info);
2792         item->access_info = NULL;
2793      }
2794
2795    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
2796    free(item);
2797 }
2798
2799 /**
2800  * @internal
2801  *
2802  * Notify object will be deleted without actually deleting it.
2803  *
2804  * This function will callback Elm_Widget_Item::del_cb if it is set
2805  * and then unset it so it is not called twice (ie: from
2806  * elm_widget_item_del()).
2807  *
2808  * @param item a valid #Elm_Widget_Item to be notified
2809  * @see elm_widget_item_pre_notify_del() convenience macro.
2810  * @ingroup Widget
2811  */
2812 EAPI void
2813 _elm_widget_item_pre_notify_del(Elm_Widget_Item *item)
2814 {
2815    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2816    if (!item->del_cb) return;
2817    item->del_cb((void *)item->data, item->widget, item);
2818    item->del_cb = NULL;
2819 }
2820
2821 /**
2822  * @internal
2823  *
2824  * Set the function to notify when item is being deleted.
2825  *
2826  * This function will complain if there was a callback set already,
2827  * however it will set the new one.
2828  *
2829  * The callback will be called from elm_widget_item_pre_notify_del()
2830  * or elm_widget_item_del() will be called with:
2831  *   - data: the Elm_Widget_Item::data value.
2832  *   - obj: the Elm_Widget_Item::widget evas object.
2833  *   - event_info: the item being deleted.
2834  *
2835  * @param item a valid #Elm_Widget_Item to be notified
2836  * @see elm_widget_item_del_cb_set() convenience macro.
2837  * @ingroup Widget
2838  */
2839 EAPI void
2840 _elm_widget_item_del_cb_set(Elm_Widget_Item *item,
2841                             Evas_Smart_Cb    del_cb)
2842 {
2843    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2844
2845    if ((item->del_cb) && (item->del_cb != del_cb))
2846      WRN("You're replacing a previously set del_cb %p of item %p with %p",
2847          item->del_cb, item, del_cb);
2848
2849    item->del_cb = del_cb;
2850 }
2851
2852 /**
2853  * @internal
2854  *
2855  * Set user-data in this item.
2856  *
2857  * User data may be used to identify this item or just store any
2858  * application data. It is automatically given as the first parameter
2859  * of the deletion notify callback.
2860  *
2861  * @param item a valid #Elm_Widget_Item to store data in.
2862  * @param data user data to store.
2863  * @see elm_widget_item_del_cb_set() convenience macro.
2864  * @ingroup Widget
2865  */
2866 EAPI void
2867 _elm_widget_item_data_set(Elm_Widget_Item *item,
2868                           const void      *data)
2869 {
2870    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2871    if ((item->data) && (item->data != data))
2872      DBG("Replacing item %p data %p with %p", item, item->data, data);
2873    item->data = data;
2874 }
2875
2876 /**
2877  * @internal
2878  *
2879  * Retrieves user-data of this item.
2880  *
2881  * @param item a valid #Elm_Widget_Item to get data from.
2882  * @see elm_widget_item_data_set()
2883  * @ingroup Widget
2884  */
2885 EAPI void *
2886 _elm_widget_item_data_get(const Elm_Widget_Item *item)
2887 {
2888    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
2889    return (void *)item->data;
2890 }
2891
2892 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
2893
2894 struct _Elm_Widget_Item_Tooltip
2895 {
2896    Elm_Widget_Item            *item;
2897    Elm_Tooltip_Item_Content_Cb func;
2898    Evas_Smart_Cb               del_cb;
2899    const void                 *data;
2900 };
2901
2902 static Evas_Object *
2903 _elm_widget_item_tooltip_label_create(void        *data,
2904                                       Evas_Object *obj __UNUSED__,
2905                                       Evas_Object *tooltip,
2906                                       void        *item __UNUSED__)
2907 {
2908    Evas_Object *label = elm_label_add(tooltip);
2909    if (!label)
2910      return NULL;
2911    elm_object_style_set(label, "tooltip");
2912    elm_object_text_set(label, data);
2913    return label;
2914 }
2915
2916 static Evas_Object *
2917 _elm_widget_item_tooltip_trans_label_create(void        *data,
2918                                             Evas_Object *obj __UNUSED__,
2919                                             Evas_Object *tooltip,
2920                                             void        *item __UNUSED__)
2921 {
2922    Evas_Object *label = elm_label_add(tooltip);
2923    if (!label)
2924      return NULL;
2925    elm_object_style_set(label, "tooltip");
2926    elm_object_translatable_text_set(label, data);
2927    return label;
2928 }
2929
2930 static void
2931 _elm_widget_item_tooltip_label_del_cb(void        *data,
2932                                       Evas_Object *obj __UNUSED__,
2933                                       void        *event_info __UNUSED__)
2934 {
2935    eina_stringshare_del(data);
2936 }
2937
2938 /**
2939  * @internal
2940  *
2941  * Set the text to be shown in the widget item.
2942  *
2943  * @param item Target item
2944  * @param text The text to set in the content
2945  *
2946  * Setup the text as tooltip to object. The item can have only one tooltip,
2947  * so any previous tooltip data is removed.
2948  *
2949  * @ingroup Widget
2950  */
2951 EAPI void
2952 _elm_widget_item_tooltip_text_set(Elm_Widget_Item *item,
2953                                   const char      *text)
2954 {
2955    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2956    EINA_SAFETY_ON_NULL_RETURN(text);
2957
2958    text = eina_stringshare_add(text);
2959    _elm_widget_item_tooltip_content_cb_set
2960      (item, _elm_widget_item_tooltip_label_create, text,
2961      _elm_widget_item_tooltip_label_del_cb);
2962 }
2963
2964 EAPI void
2965 _elm_widget_item_tooltip_translatable_text_set(Elm_Widget_Item *item,
2966                                                const char      *text)
2967 {
2968    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
2969    EINA_SAFETY_ON_NULL_RETURN(text);
2970
2971    text = eina_stringshare_add(text);
2972    _elm_widget_item_tooltip_content_cb_set
2973      (item, _elm_widget_item_tooltip_trans_label_create, text,
2974      _elm_widget_item_tooltip_label_del_cb);
2975 }
2976
2977 static Evas_Object *
2978 _elm_widget_item_tooltip_create(void        *data,
2979                                 Evas_Object *obj,
2980                                 Evas_Object *tooltip)
2981 {
2982    Elm_Widget_Item_Tooltip *wit = data;
2983    return wit->func((void *)wit->data, obj, tooltip, wit->item);
2984 }
2985
2986 static void
2987 _elm_widget_item_tooltip_del_cb(void        *data,
2988                                 Evas_Object *obj,
2989                                 void        *event_info __UNUSED__)
2990 {
2991    Elm_Widget_Item_Tooltip *wit = data;
2992    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item);
2993    free(wit);
2994 }
2995
2996 /**
2997  * @internal
2998  *
2999  * Set the content to be shown in the tooltip item
3000  *
3001  * Setup the tooltip to item. The item can have only one tooltip,
3002  * so any previous tooltip data is removed. @p func(with @p data) will
3003  * be called every time that need show the tooltip and it should
3004  * return a valid Evas_Object. This object is then managed fully by
3005  * tooltip system and is deleted when the tooltip is gone.
3006  *
3007  * @param item the widget item being attached a tooltip.
3008  * @param func the function used to create the tooltip contents.
3009  * @param data what to provide to @a func as callback data/context.
3010  * @param del_cb called when data is not needed anymore, either when
3011  *        another callback replaces @func, the tooltip is unset with
3012  *        elm_widget_item_tooltip_unset() or the owner @a item
3013  *        dies. This callback receives as the first parameter the
3014  *        given @a data, and @c event_info is the item.
3015  *
3016  * @ingroup Widget
3017  */
3018 EAPI void
3019 _elm_widget_item_tooltip_content_cb_set(Elm_Widget_Item            *item,
3020                                         Elm_Tooltip_Item_Content_Cb func,
3021                                         const void                 *data,
3022                                         Evas_Smart_Cb               del_cb)
3023 {
3024    Elm_Widget_Item_Tooltip *wit;
3025
3026    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
3027
3028    if (!func)
3029      {
3030         _elm_widget_item_tooltip_unset(item);
3031         return;
3032      }
3033
3034    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
3035    if (!wit) goto error;
3036    wit->item = item;
3037    wit->func = func;
3038    wit->data = data;
3039    wit->del_cb = del_cb;
3040
3041    elm_object_sub_tooltip_content_cb_set
3042      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
3043      _elm_widget_item_tooltip_del_cb);
3044
3045    return;
3046
3047 error_noitem:
3048    if (del_cb) del_cb((void *)data, NULL, item);
3049    return;
3050 error:
3051    if (del_cb) del_cb((void *)data, item->widget, item);
3052 }
3053
3054 /**
3055  * @internal
3056  *
3057  * Unset tooltip from item
3058  *
3059  * @param item widget item to remove previously set tooltip.
3060  *
3061  * Remove tooltip from item. The callback provided as del_cb to
3062  * elm_widget_item_tooltip_content_cb_set() will be called to notify
3063  * it is not used anymore.
3064  *
3065  * @see elm_widget_item_tooltip_content_cb_set()
3066  *
3067  * @ingroup Widget
3068  */
3069 EAPI void
3070 _elm_widget_item_tooltip_unset(Elm_Widget_Item *item)
3071 {
3072    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3073    elm_object_tooltip_unset(item->view);
3074 }
3075
3076 /**
3077  * @internal
3078  *
3079  * Sets a different style for this item tooltip.
3080  *
3081  * @note before you set a style you should define a tooltip with
3082  *       elm_widget_item_tooltip_content_cb_set() or
3083  *       elm_widget_item_tooltip_text_set()
3084  *
3085  * @param item widget item with tooltip already set.
3086  * @param style the theme style to use (default, transparent, ...)
3087  *
3088  * @ingroup Widget
3089  */
3090 EAPI void
3091 _elm_widget_item_tooltip_style_set(Elm_Widget_Item *item,
3092                                    const char      *style)
3093 {
3094    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3095    elm_object_tooltip_style_set(item->view, style);
3096 }
3097
3098 EAPI Eina_Bool
3099 _elm_widget_item_tooltip_size_restrict_disable(Elm_Widget_Item *item, Eina_Bool disable)
3100 {
3101    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3102    return elm_tooltip_size_restrict_disable(item->view, disable);
3103 }
3104
3105 EAPI Eina_Bool
3106 _elm_widget_item_tooltip_size_restrict_disabled_get(const Elm_Widget_Item *item)
3107 {
3108    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3109    return elm_tooltip_size_restrict_disabled_get(item->view);
3110 }
3111
3112 /**
3113  * @internal
3114  *
3115  * Get the style for this item tooltip.
3116  *
3117  * @param item widget item with tooltip already set.
3118  * @return style the theme style in use, defaults to "default". If the
3119  *         object does not have a tooltip set, then NULL is returned.
3120  *
3121  * @ingroup Widget
3122  */
3123 EAPI const char *
3124 _elm_widget_item_tooltip_style_get(const Elm_Widget_Item *item)
3125 {
3126    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3127    return elm_object_tooltip_style_get(item->view);
3128 }
3129
3130 EAPI void
3131 _elm_widget_item_cursor_set(Elm_Widget_Item *item,
3132                             const char      *cursor)
3133 {
3134    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3135    elm_object_sub_cursor_set(item->view, item->widget, cursor);
3136 }
3137
3138 EAPI const char *
3139 _elm_widget_item_cursor_get(const Elm_Widget_Item *item)
3140 {
3141    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3142    return elm_object_cursor_get(item->view);
3143 }
3144
3145 EAPI void
3146 _elm_widget_item_cursor_unset(Elm_Widget_Item *item)
3147 {
3148    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3149    elm_object_cursor_unset(item->view);
3150 }
3151
3152 /**
3153  * @internal
3154  *
3155  * Sets a different style for this item cursor.
3156  *
3157  * @note before you set a style you should define a cursor with
3158  *       elm_widget_item_cursor_set()
3159  *
3160  * @param item widget item with cursor already set.
3161  * @param style the theme style to use (default, transparent, ...)
3162  *
3163  * @ingroup Widget
3164  */
3165 EAPI void
3166 _elm_widget_item_cursor_style_set(Elm_Widget_Item *item,
3167                                   const char      *style)
3168 {
3169    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3170    elm_object_cursor_style_set(item->view, style);
3171 }
3172
3173 /**
3174  * @internal
3175  *
3176  * Get the style for this item cursor.
3177  *
3178  * @param item widget item with cursor already set.
3179  * @return style the theme style in use, defaults to "default". If the
3180  *         object does not have a cursor set, then NULL is returned.
3181  *
3182  * @ingroup Widget
3183  */
3184 EAPI const char *
3185 _elm_widget_item_cursor_style_get(const Elm_Widget_Item *item)
3186 {
3187    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3188    return elm_object_cursor_style_get(item->view);
3189 }
3190
3191 /**
3192  * @internal
3193  *
3194  * Set if the cursor set should be searched on the theme or should use
3195  * the provided by the engine, only.
3196  *
3197  * @note before you set if should look on theme you should define a cursor
3198  * with elm_object_cursor_set(). By default it will only look for cursors
3199  * provided by the engine.
3200  *
3201  * @param item widget item with cursor already set.
3202  * @param engine_only boolean to define it cursors should be looked only
3203  * between the provided by the engine or searched on widget's theme as well.
3204  *
3205  * @ingroup Widget
3206  */
3207 EAPI void
3208 _elm_widget_item_cursor_engine_only_set(Elm_Widget_Item *item,
3209                                         Eina_Bool        engine_only)
3210 {
3211    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3212    elm_object_cursor_engine_only_set(item->view, engine_only);
3213 }
3214
3215 /**
3216  * @internal
3217  *
3218  * Get the cursor engine only usage for this item cursor.
3219  *
3220  * @param item widget item with cursor already set.
3221  * @return engine_only boolean to define it cursors should be looked only
3222  * between the provided by the engine or searched on widget's theme as well. If
3223  *         the object does not have a cursor set, then EINA_FALSE is returned.
3224  *
3225  * @ingroup Widget
3226  */
3227 EAPI Eina_Bool
3228 _elm_widget_item_cursor_engine_only_get(const Elm_Widget_Item *item)
3229 {
3230    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3231    return elm_object_cursor_engine_only_get(item->view);
3232 }
3233
3234 // smart object funcs
3235 static void
3236 _smart_reconfigure(Smart_Data *sd)
3237 {
3238    if (sd->resize_obj)
3239      {
3240         evas_object_move(sd->resize_obj, sd->x, sd->y);
3241         evas_object_resize(sd->resize_obj, sd->w, sd->h);
3242      }
3243    if (sd->hover_obj)
3244      {
3245         evas_object_move(sd->hover_obj, sd->x, sd->y);
3246         evas_object_resize(sd->hover_obj, sd->w, sd->h);
3247      }
3248 }
3249
3250 EAPI void
3251 _elm_widget_item_content_part_set(Elm_Widget_Item *item,
3252                                  const char *part,
3253                                  Evas_Object *content)
3254 {
3255    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3256    if (!item->on_content_set_func) return;
3257    item->on_content_set_func((Elm_Object_Item *) item, part, content);
3258 }
3259
3260 EAPI Evas_Object *
3261 _elm_widget_item_content_part_get(const Elm_Widget_Item *item,
3262                                   const char *part)
3263 {
3264    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3265    if (!item->on_content_get_func) return NULL;
3266    return item->on_content_get_func((Elm_Object_Item *) item, part);
3267 }
3268
3269 EAPI Evas_Object *
3270 _elm_widget_item_content_part_unset(Elm_Widget_Item *item,
3271                                     const char *part)
3272 {
3273    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3274    if (!item->on_content_unset_func) return NULL;
3275    return item->on_content_unset_func((Elm_Object_Item *) item, part);
3276 }
3277
3278 EAPI void
3279 _elm_widget_item_text_part_set(Elm_Widget_Item *item,
3280                               const char *part,
3281                               const char *label)
3282 {
3283    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3284    if (!item->on_text_set_func) return;
3285    item->on_text_set_func((Elm_Object_Item *) item, part, label);
3286 }
3287
3288 EAPI void
3289 _elm_widget_item_signal_emit(Elm_Widget_Item *item,
3290                              const char *emission,
3291                              const char *source)
3292 {
3293    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3294    if (item->on_signal_emit_func)
3295      item->on_signal_emit_func((Elm_Object_Item *) item, emission, source);
3296 }
3297
3298 EAPI const char *
3299 _elm_widget_item_text_part_get(const Elm_Widget_Item *item,
3300                                const char *part)
3301 {
3302    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3303    if (!item->on_text_get_func) return NULL;
3304    return item->on_text_get_func((Elm_Object_Item *) item, part);
3305 }
3306
3307 EAPI void
3308 _elm_widget_item_content_set_hook_set(Elm_Widget_Item *item,
3309                                       Elm_Widget_On_Content_Set_Cb func)
3310 {
3311    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3312    item->on_content_set_func = func;
3313 }
3314
3315 EAPI void
3316 _elm_widget_item_content_get_hook_set(Elm_Widget_Item *item,
3317                                       Elm_Widget_On_Content_Get_Cb func)
3318 {
3319    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3320    item->on_content_get_func = func;
3321 }
3322
3323 EAPI void
3324 _elm_widget_item_content_unset_hook_set(Elm_Widget_Item *item,
3325                                         Elm_Widget_On_Content_Unset_Cb func)
3326 {
3327    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3328    item->on_content_unset_func = func;
3329 }
3330
3331 EAPI void
3332 _elm_widget_item_text_set_hook_set(Elm_Widget_Item *item,
3333                                    Elm_Widget_On_Text_Set_Cb func)
3334 {
3335    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3336    item->on_text_set_func = func;
3337 }
3338
3339 EAPI void
3340 _elm_widget_item_text_get_hook_set(Elm_Widget_Item *item,
3341                                    Elm_Widget_On_Text_Get_Cb func)
3342 {
3343    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3344    item->on_text_get_func = func;
3345 }
3346
3347 EAPI void
3348 _elm_widget_item_signal_emit_hook_set(Elm_Widget_Item *item,
3349                                       Elm_Widget_On_Signal_Emit_Cb func)
3350 {
3351    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3352    item->on_signal_emit_func = func;
3353 }
3354
3355 EAPI void
3356 _elm_widget_item_access_info_set(Elm_Widget_Item *item, const char *txt)
3357 {
3358    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3359    if (item->access_info) eina_stringshare_del(item->access_info);
3360    if (!txt) item->access_info = NULL;
3361    else item->access_info = eina_stringshare_add(txt);
3362 }
3363
3364
3365 static void
3366 _smart_add(Evas_Object *obj)
3367 {
3368    Smart_Data *sd;
3369
3370    sd = calloc(1, sizeof(Smart_Data));
3371    if (!sd) return;
3372    sd->obj = obj;
3373    sd->x = sd->y = sd->w = sd->h = 0;
3374    sd->can_focus = 1;
3375    sd->mirrored_auto_mode = EINA_TRUE; /* will follow system locale settings */
3376    evas_object_smart_data_set(obj, sd);
3377 }
3378
3379 static Evas_Object *
3380 _newest_focus_order_get(Evas_Object  *obj,
3381                         unsigned int *newest_focus_order,
3382                         Eina_Bool     can_focus_only)
3383 {
3384    const Eina_List *l;
3385    Evas_Object *child, *ret, *best;
3386
3387    API_ENTRY return NULL;
3388
3389    if (!evas_object_visible_get(obj)
3390        || (elm_widget_disabled_get(obj))
3391        || (elm_widget_tree_unfocusable_get(obj)))
3392      return NULL;
3393
3394    best = NULL;
3395    if (*newest_focus_order < sd->focus_order)
3396      {
3397         *newest_focus_order = sd->focus_order;
3398         best = obj;
3399      }
3400    EINA_LIST_FOREACH(sd->subobjs, l, child)
3401      {
3402         ret = _newest_focus_order_get(child, newest_focus_order, can_focus_only);
3403         if (!ret) continue;
3404         best = ret;
3405      }
3406    if (can_focus_only)
3407      {
3408         if ((!best) || (!elm_widget_can_focus_get(best)))
3409           return NULL;
3410      }
3411    return best;
3412 }
3413
3414 static void
3415 _if_focused_revert(Evas_Object *obj,
3416                    Eina_Bool    can_focus_only)
3417 {
3418    Evas_Object *top;
3419    Evas_Object *newest = NULL;
3420    unsigned int newest_focus_order = 0;
3421
3422    INTERNAL_ENTRY
3423
3424    if (!sd->focused) return;
3425    if (!sd->parent_obj) return;
3426
3427    top = elm_widget_top_get(sd->parent_obj);
3428    if (top)
3429      {
3430         newest = _newest_focus_order_get(top, &newest_focus_order, can_focus_only);
3431         if (newest)
3432           {
3433              elm_object_focus_set(newest, EINA_FALSE);
3434              elm_object_focus_set(newest, EINA_TRUE);
3435           }
3436      }
3437 }
3438
3439 static void
3440 _smart_del(Evas_Object *obj)
3441 {
3442    Evas_Object *sobj;
3443    Edje_Signal_Data *esd;
3444    Elm_Translate_String_Data *ts;
3445
3446    INTERNAL_ENTRY
3447
3448    if (sd->del_pre_func) sd->del_pre_func(obj);
3449    if (sd->resize_obj)
3450      {
3451         sobj = sd->resize_obj;
3452         sd->resize_obj = NULL;
3453         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3454         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3455         evas_object_del(sobj);
3456         sd->resize_obj = NULL;
3457      }
3458    if (sd->hover_obj)
3459      {
3460         sobj = sd->hover_obj;
3461         sd->hover_obj = NULL;
3462         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3463         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3464         evas_object_del(sobj);
3465         sd->hover_obj = NULL;
3466      }
3467    EINA_LIST_FREE(sd->subobjs, sobj)
3468      {
3469         evas_object_event_callback_del_full(sobj, EVAS_CALLBACK_DEL, _sub_obj_del, sd);
3470         evas_object_smart_callback_call(sd->obj, "sub-object-del", sobj);
3471         evas_object_del(sobj);
3472      }
3473    sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */
3474    sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */
3475    EINA_LIST_FREE(sd->edje_signals, esd)
3476      {
3477         eina_stringshare_del(esd->emission);
3478         eina_stringshare_del(esd->source);
3479         free(esd);
3480      }
3481    EINA_LIST_FREE(sd->translate_strings, ts)
3482      {
3483         eina_stringshare_del(ts->id);
3484         eina_stringshare_del(ts->domain);
3485         eina_stringshare_del(ts->string);
3486         free(ts);
3487      }
3488    sd->event_cb = eina_list_free(sd->event_cb); /* should be empty anyway */
3489    if (sd->del_func) sd->del_func(obj);
3490    if (sd->style) eina_stringshare_del(sd->style);
3491    if (sd->type) eina_stringshare_del(sd->type);
3492    if (sd->theme) elm_theme_free(sd->theme);
3493    sd->data = NULL;
3494    _if_focused_revert(obj, EINA_TRUE);
3495    if (sd->access_info) eina_stringshare_del(sd->access_info);
3496    free(sd);
3497    evas_object_smart_data_set(obj, NULL);
3498 }
3499
3500 static void
3501 _smart_move(Evas_Object *obj,
3502             Evas_Coord   x,
3503             Evas_Coord   y)
3504 {
3505    INTERNAL_ENTRY
3506    sd->x = x;
3507    sd->y = y;
3508    _smart_reconfigure(sd);
3509 }
3510
3511 static void
3512 _smart_resize(Evas_Object *obj,
3513               Evas_Coord   w,
3514               Evas_Coord   h)
3515 {
3516    INTERNAL_ENTRY
3517    sd->w = w;
3518    sd->h = h;
3519    _smart_reconfigure(sd);
3520 }
3521
3522 static void
3523 _smart_show(Evas_Object *obj)
3524 {
3525    Eina_List *list;
3526    Evas_Object *o;
3527    INTERNAL_ENTRY
3528    if ((list = evas_object_smart_members_get(obj)))
3529      {
3530         EINA_LIST_FREE(list, o)
3531           {
3532              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3533              evas_object_show(o);
3534           }
3535      }
3536 }
3537
3538 static void
3539 _smart_hide(Evas_Object *obj)
3540 {
3541    Eina_List *list;
3542    Evas_Object *o;
3543    INTERNAL_ENTRY
3544
3545    list = evas_object_smart_members_get(obj);
3546    EINA_LIST_FREE(list, o)
3547      {
3548         if (evas_object_data_get(o, "_elm_leaveme")) continue;
3549         evas_object_hide(o);
3550      }
3551 }
3552
3553 static void
3554 _smart_color_set(Evas_Object *obj,
3555                  int          r,
3556                  int          g,
3557                  int          b,
3558                  int          a)
3559 {
3560    Eina_List *list;
3561    Evas_Object *o;
3562    INTERNAL_ENTRY
3563    if ((list = evas_object_smart_members_get(obj)))
3564      {
3565         EINA_LIST_FREE(list, o)
3566           {
3567              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3568              evas_object_color_set(o, r, g, b, a);
3569           }
3570      }
3571 }
3572
3573 static void
3574 _smart_clip_set(Evas_Object *obj,
3575                 Evas_Object *clip)
3576 {
3577    Eina_List *list;
3578    Evas_Object *o;
3579    INTERNAL_ENTRY
3580    if ((list = evas_object_smart_members_get(obj)))
3581      {
3582         EINA_LIST_FREE(list, o)
3583           {
3584              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3585              evas_object_clip_set(o, clip);
3586           }
3587      }
3588 }
3589
3590 static void
3591 _smart_clip_unset(Evas_Object *obj)
3592 {
3593    Eina_List *list;
3594    Evas_Object *o;
3595    INTERNAL_ENTRY
3596    if ((list = evas_object_smart_members_get(obj)))
3597      {
3598         EINA_LIST_FREE(list, o)
3599           {
3600              if (evas_object_data_get(o, "_elm_leaveme")) continue;
3601              evas_object_clip_unset(o);
3602           }
3603      }
3604 }
3605
3606 static void
3607 _smart_calculate(Evas_Object *obj)
3608 {
3609    INTERNAL_ENTRY
3610    if (sd->changed_func) sd->changed_func(obj);
3611 }
3612
3613 /* never need to touch this */
3614 static void
3615 _smart_init(void)
3616 {
3617    if (_e_smart) return;
3618      {
3619         static const Evas_Smart_Class sc =
3620           {
3621              SMART_NAME,
3622              EVAS_SMART_CLASS_VERSION,
3623              _smart_add,
3624              _smart_del,
3625              _smart_move,
3626              _smart_resize,
3627              _smart_show,
3628              _smart_hide,
3629              _smart_color_set,
3630              _smart_clip_set,
3631              _smart_clip_unset,
3632              _smart_calculate,
3633              NULL,
3634              NULL,
3635              NULL,
3636              NULL,
3637              NULL,
3638              NULL
3639           };
3640         _e_smart = evas_smart_class_new(&sc);
3641      }
3642 }
3643
3644 /* happy debug functions */
3645 #ifdef ELM_DEBUG
3646 static void
3647 _sub_obj_tree_dump(const Evas_Object *obj,
3648                    int                lvl)
3649 {
3650    int i;
3651
3652    for (i = 0; i < lvl * 3; i++)
3653      putchar(' ');
3654
3655    if (_elm_widget_is(obj))
3656      {
3657         Eina_List *l;
3658         INTERNAL_ENTRY
3659         printf("+ %s(%p)\n",
3660                sd->type,
3661                obj);
3662         if (sd->resize_obj)
3663           _sub_obj_tree_dump(sd->resize_obj, lvl + 1);
3664         EINA_LIST_FOREACH(sd->subobjs, l, obj)
3665           {
3666              if (obj != sd->resize_obj)
3667                _sub_obj_tree_dump(obj, lvl + 1);
3668           }
3669      }
3670    else
3671      printf("+ %s(%p)\n", evas_object_type_get(obj), obj);
3672 }
3673
3674 static void
3675 _sub_obj_tree_dot_dump(const Evas_Object *obj,
3676                        FILE              *output)
3677 {
3678    if (!_elm_widget_is(obj))
3679      return;
3680    INTERNAL_ENTRY
3681
3682    Eina_Bool visible = evas_object_visible_get(obj);
3683    Eina_Bool disabled = elm_widget_disabled_get(obj);
3684    Eina_Bool focused = elm_widget_focus_get(obj);
3685    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
3686
3687    if (sd->parent_obj)
3688      {
3689         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
3690
3691         if (focused)
3692           fprintf(output, ", style=bold");
3693
3694         if (!visible)
3695           fprintf(output, ", color=gray28");
3696
3697         fprintf(output, " ];\n");
3698      }
3699
3700    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
3701                    "disabled: %d|focused: %d/%d|focus order:%d}\"", obj, obj, sd->type,
3702            evas_object_name_get(obj), visible, disabled, focused, can_focus,
3703            sd->focus_order);
3704
3705    if (focused)
3706      fprintf(output, ", style=bold");
3707
3708    if (!visible)
3709      fprintf(output, ", fontcolor=gray28");
3710
3711    if ((disabled) || (!visible))
3712      fprintf(output, ", color=gray");
3713
3714    fprintf(output, " ];\n");
3715
3716    Eina_List *l;
3717    Evas_Object *o;
3718    EINA_LIST_FOREACH(sd->subobjs, l, o)
3719      _sub_obj_tree_dot_dump(o, output);
3720 }
3721 #endif
3722
3723 EAPI void
3724 elm_widget_tree_dump(const Evas_Object *top)
3725 {
3726 #ifdef ELM_DEBUG
3727    _sub_obj_tree_dump(top, 0);
3728 #else
3729    return;
3730    (void)top;
3731 #endif
3732 }
3733
3734 EAPI void
3735 elm_widget_tree_dot_dump(const Evas_Object *top,
3736                          FILE              *output)
3737 {
3738 #ifdef ELM_DEBUG
3739    if (!_elm_widget_is(top))
3740      return;
3741    fprintf(output, "graph " " { node [shape=record];\n");
3742    _sub_obj_tree_dot_dump(top, output);
3743    fprintf(output, "}\n");
3744 #else
3745    return;
3746    (void)top;
3747    (void)output;
3748 #endif
3749 }