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