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