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