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