elementary - added elm_object_item_translatable_part_text_set() elm_object_item_trans...
[framework/uifw/elementary.git] / src / lib / elm_widget.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_container.h"
4 #include "elm_interface_scrollable.h"
5
6 static const char ELM_WIDGET_SMART_NAME[] = "elm_widget";
7
8 #define API_ENTRY                                               \
9   Elm_Widget_Smart_Data * sd = evas_object_smart_data_get(obj); \
10   if ((!sd) || (!_elm_widget_is(obj)))
11 #define INTERNAL_ENTRY                                          \
12   Elm_Widget_Smart_Data * sd = evas_object_smart_data_get(obj); \
13   if (!sd)                                                      \
14     return
15
16 #define ELM_WIDGET_FOCUS_GET(obj)                                    \
17   ((_elm_access_read_mode_get()) ? (elm_widget_highlight_get(obj)) : \
18                                   (elm_widget_focus_get(obj)))
19 typedef struct _Elm_Event_Cb_Data         Elm_Event_Cb_Data;
20 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
21
22 struct _Elm_Event_Cb_Data
23 {
24    Elm_Event_Cb func;
25    const void  *data;
26 };
27
28 struct _Elm_Translate_String_Data
29 {
30    const char *id;
31    const char *domain;
32    const char *string;
33 };
34
35 /* local subsystem globals */
36 static unsigned int focus_order = 0;
37
38 static inline Eina_Bool
39 _elm_widget_is(const Evas_Object *obj)
40 {
41    return evas_object_smart_type_check_ptr(obj, ELM_WIDGET_SMART_NAME);
42 }
43
44 static inline Eina_Bool
45 _is_focusable(Evas_Object *obj)
46 {
47    API_ENTRY return EINA_FALSE;
48    return sd->can_focus || (sd->child_can_focus);
49 }
50
51 static inline Eina_Bool
52 _elm_scrollable_is(const Evas_Object *obj)
53 {
54    INTERNAL_ENTRY EINA_FALSE;
55    return !!evas_object_smart_interface_get(obj, ELM_SCROLLABLE_IFACE_NAME);
56 }
57
58 /* what follows are basic (unimplemented) smart class functions */
59 #define UNIMPLEMENTED_MAKE(_prefix)                                         \
60   static Eina_Bool                                                          \
61   _elm_widget_##_prefix##_func_unimplemented(Evas_Object * obj)             \
62   {                                                                         \
63      WRN("The %s widget does not implement the \"" #_prefix "\" function.", \
64          elm_widget_type_get(obj));                                         \
65      return EINA_FALSE;                                                     \
66   }
67
68 UNIMPLEMENTED_MAKE(disable);
69 UNIMPLEMENTED_MAKE(translate);
70
71 #undef UNIMPLEMENTED_MAKE
72
73 /**
74  * @internal
75  * Resets the mirrored mode from the system mirror mode for widgets that are in
76  * automatic mirroring mode. This function does not call elm_widget_theme.
77  *
78  * @param obj The widget.
79  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
80  */
81 static void
82 _elm_widget_mirrored_reload(Evas_Object *obj)
83 {
84    API_ENTRY return;
85    Eina_Bool mirrored = elm_config_mirrored_get();
86
87    if (elm_widget_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored))
88      {
89         sd->is_mirrored = mirrored;
90      }
91 }
92
93 static Eina_Bool
94 _elm_widget_theme_func(Evas_Object *obj)
95 {
96    _elm_widget_mirrored_reload(obj);
97
98    elm_widget_disabled_set(obj, elm_widget_disabled_get(obj));
99
100    return EINA_TRUE;
101 }
102
103 static Eina_Bool
104 _elm_widget_on_focus_region_func_unimplemented(const Evas_Object *obj __UNUSED__,
105                                                Evas_Coord *x __UNUSED__,
106                                                Evas_Coord *y __UNUSED__,
107                                                Evas_Coord *w __UNUSED__,
108                                                Evas_Coord *h __UNUSED__)
109 {
110    WRN("The %s widget does not implement the \"on_focus_region\" function.",
111        elm_widget_type_get(obj));
112    return EINA_FALSE;
113 }
114
115 static Eina_Bool
116 _elm_widget_on_focus_func_unimplemented(Evas_Object *obj)
117 {
118    WRN("The %s widget does not implement the \"on_focus\" function.",
119        elm_widget_type_get(obj));
120    return EINA_FALSE;
121 }
122
123 static Eina_Bool
124 _elm_widget_event_func_unimplemented(Evas_Object *obj,
125                                      Evas_Object *source __UNUSED__,
126                                      Evas_Callback_Type type __UNUSED__,
127                                      void *event_info __UNUSED__)
128 {
129    WRN("The %s widget does not implement the \"event\" function.",
130        elm_widget_type_get(obj));
131    return EINA_FALSE;
132 }
133
134 static Eina_Bool
135 _elm_widget_focus_next_func_unimplemented(const Evas_Object *obj,
136                                           Elm_Focus_Direction dir __UNUSED__,
137                                           Evas_Object **next __UNUSED__)
138 {
139    WRN("The %s widget does not implement the \"focus_next\" function.",
140        elm_widget_type_get(obj));
141    return EINA_FALSE;
142 }
143
144 static Eina_Bool
145 _elm_widget_focus_direction_func_unimplemented(const Evas_Object *obj,
146                                                const Evas_Object *b __UNUSED__,
147                                                double degree __UNUSED__,
148                                                Evas_Object **target __UNUSED__,
149                                                double *weight __UNUSED__)
150 {
151    WRN("The %s widget does not implement the \"focus_direction\" function.",
152        elm_widget_type_get(obj));
153    return EINA_FALSE;
154 }
155
156 static void
157 _parents_focus(Evas_Object *obj)
158 {
159    for (; obj; obj = elm_widget_parent_get(obj))
160      {
161         INTERNAL_ENTRY;
162         if (sd->focused) return;
163         sd->focused = 1;
164      }
165 }
166
167 static void
168 _parents_unfocus(Evas_Object *obj)
169 {
170    for (; obj; obj = elm_widget_parent_get(obj))
171      {
172         INTERNAL_ENTRY;
173         if (!sd->focused) return;
174         sd->focused = 0;
175      }
176 }
177
178 static void
179 _on_sub_obj_hide(void *data __UNUSED__,
180               Evas *e __UNUSED__,
181               Evas_Object *obj,
182               void *event_info __UNUSED__)
183 {
184    elm_widget_focus_hide_handle(obj);
185 }
186
187 static void
188 _on_sub_obj_del(void *data,
189              Evas *e __UNUSED__,
190              Evas_Object *obj,
191              void *event_info __UNUSED__)
192 {
193    Elm_Widget_Smart_Data *sd = data;
194
195    if (_elm_widget_is(obj))
196      {
197         if (elm_widget_focus_get(obj)) _parents_unfocus(sd->obj);
198      }
199    if (obj == sd->resize_obj)
200      {
201         /* already dels sub object */
202         elm_widget_resize_object_set(sd->obj, NULL);
203         return;
204      }
205    else if (obj == sd->hover_obj)
206      {
207         sd->hover_obj = NULL;
208         return;
209      }
210    else
211      {
212         if (!elm_widget_sub_object_del(sd->obj, obj))
213           ERR("failed to remove sub object %p from %p\n", obj, sd->obj);
214      }
215 }
216
217 static Eina_Bool
218 _elm_widget_sub_object_add_func(Evas_Object *obj,
219                                 Evas_Object *sobj)
220 {
221    double scale, pscale = elm_widget_scale_get(sobj);
222    Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
223    Eina_Bool mirrored, pmirrored = elm_widget_mirrored_get(obj);
224
225    ELM_WIDGET_DATA_GET(obj, sd);
226    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
227
228    if (sobj == sd->parent_obj)
229      {
230         /* in this case, sobj must be an elm widget, or something
231          * very wrong is happening */
232         if (!_elm_widget_is(sobj)) return EINA_FALSE;
233
234         if (!elm_widget_sub_object_del(sobj, obj)) return EINA_FALSE;
235         WRN("You passed a parent object of obj = %p as the sub object = %p!",
236             obj, sobj);
237      }
238
239    if (_elm_widget_is(sobj))
240      {
241         ELM_WIDGET_DATA_GET(sobj, sdc);
242
243         if (sdc->parent_obj == obj) return EINA_TRUE;
244         if (sdc->parent_obj)
245           {
246              if (!elm_widget_sub_object_del(sdc->parent_obj, sobj))
247                return EINA_FALSE;
248           }
249         sdc->parent_obj = obj;
250         sdc->orient_mode = sd->orient_mode;
251         _elm_widget_top_win_focused_set(sobj, sd->top_win_focused);
252
253         /* update child focusable-ness on self and parents, now that a
254          * focusable child got in */
255         if (!sd->child_can_focus && (_is_focusable(sobj)))
256           {
257              Elm_Widget_Smart_Data *sdp = sd;
258
259              sdp->child_can_focus = EINA_TRUE;
260              while (sdp->parent_obj)
261                {
262                   sdp = evas_object_smart_data_get(sdp->parent_obj);
263
264                   if (sdp->child_can_focus) break;
265
266                   sdp->child_can_focus = EINA_TRUE;
267                }
268           }
269      }
270    else
271      {
272         void *data = evas_object_data_get(sobj, "elm-parent");
273
274         if (data)
275           {
276              if (data == obj) return EINA_TRUE;
277              if (!elm_widget_sub_object_del(data, sobj)) return EINA_FALSE;
278           }
279      }
280
281    sd->subobjs = eina_list_append(sd->subobjs, sobj);
282    evas_object_data_set(sobj, "elm-parent", obj);
283    evas_object_event_callback_add
284      (sobj, EVAS_CALLBACK_DEL, _on_sub_obj_del, sd);
285    if (_elm_widget_is(sobj))
286      {
287         evas_object_event_callback_add
288           (sobj, EVAS_CALLBACK_HIDE, _on_sub_obj_hide, sd);
289
290         scale = elm_widget_scale_get(sobj);
291         th = elm_widget_theme_get(sobj);
292         mirrored = elm_widget_mirrored_get(sobj);
293
294         if ((scale != pscale) || (th != pth) || (pmirrored != mirrored))
295           elm_widget_theme(sobj);
296
297         if (elm_widget_focus_get(sobj)) _parents_focus(obj);
298      }
299
300    return EINA_TRUE;
301 }
302
303 static Eina_Bool
304 _elm_widget_sub_object_del_func(Evas_Object *obj,
305                                 Evas_Object *sobj)
306 {
307    Evas_Object *sobj_parent;
308
309    if (!sobj) return EINA_FALSE;
310
311    ELM_WIDGET_DATA_GET(obj, sd);
312    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
313
314    sobj_parent = evas_object_data_del(sobj, "elm-parent");
315    if (sobj_parent != obj)
316      {
317         static int abort_on_warn = -1;
318
319         ERR("removing sub object %p (%s) from parent %p (%s), "
320             "but elm-parent is different %p (%s)!",
321             sobj, elm_widget_type_get(sobj), obj, elm_widget_type_get(obj),
322             sobj_parent, elm_widget_type_get(sobj_parent));
323
324         if (EINA_UNLIKELY(abort_on_warn == -1))
325           {
326              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
327              else abort_on_warn = 0;
328           }
329         if (abort_on_warn == 1) abort();
330
331         return EINA_FALSE;
332      }
333
334    if (_elm_widget_is(sobj))
335      {
336         if (elm_widget_focus_get(sobj))
337           {
338              elm_widget_tree_unfocusable_set(sobj, EINA_TRUE);
339              elm_widget_tree_unfocusable_set(sobj, EINA_FALSE);
340           }
341         if ((sd->child_can_focus) && (_is_focusable(sobj)))
342           {
343              Evas_Object *parent = obj;
344
345              /* update child focusable-ness on self and parents, now that a
346               * focusable child is gone */
347              while (parent)
348                {
349                   const Eina_List *l;
350                   Evas_Object *subobj;
351
352                   ELM_WIDGET_DATA_GET(parent, sdp);
353
354                   sdp->child_can_focus = EINA_FALSE;
355                   EINA_LIST_FOREACH(sdp->subobjs, l, subobj)
356                     {
357                        if ((subobj != sobj) && (_is_focusable(subobj)))
358                          {
359                             sdp->child_can_focus = EINA_TRUE;
360                             break;
361                          }
362                     }
363
364                   /* break again, child_can_focus went back to
365                    * original value */
366                   if (sdp->child_can_focus) break;
367                   parent = sdp->parent_obj;
368                }
369           }
370
371         ELM_WIDGET_DATA_GET(sobj, sdc);
372         sdc->parent_obj = NULL;
373      }
374
375    if (sd->resize_obj == sobj) sd->resize_obj = NULL;
376
377    sd->subobjs = eina_list_remove(sd->subobjs, sobj);
378
379    evas_object_event_callback_del_full
380      (sobj, EVAS_CALLBACK_DEL, _on_sub_obj_del, sd);
381    if (_elm_widget_is(sobj))
382      evas_object_event_callback_del_full
383        (sobj, EVAS_CALLBACK_HIDE, _on_sub_obj_hide, sd);
384
385    return EINA_TRUE;
386 }
387
388 static const Evas_Smart_Cb_Description _smart_callbacks[] =
389 {
390    /* FIXME: complete later */
391    {NULL, NULL}
392 };
393
394 static void
395 _smart_add(Evas_Object *obj)
396 {
397    const Evas_Smart_Class *sc;
398    const Evas_Smart *smart;
399
400    EVAS_SMART_DATA_ALLOC(obj, Elm_Widget_Smart_Data);
401
402    smart = evas_object_smart_smart_get(obj);
403    sc = evas_smart_class_get(smart);
404    priv->api = (const Elm_Widget_Smart_Class *)sc;
405    priv->obj = obj;
406    priv->x = priv->y = priv->w = priv->h = 0;
407    priv->mirrored_auto_mode = EINA_TRUE; /* will follow system locale
408                                           * settings */
409    elm_widget_can_focus_set(obj, EINA_TRUE);
410    elm_widget_mirrored_set(obj, elm_config_mirrored_get());
411
412    /* just a helper for inheriting classes */
413    if (priv->resize_obj)
414      {
415         Evas_Object *r_obj = priv->resize_obj;
416         priv->resize_obj = NULL;
417
418         elm_widget_resize_object_set(obj, r_obj);
419      }
420 }
421
422
423 static void
424 _if_focused_revert(Evas_Object *obj,
425                    Eina_Bool can_focus_only)
426 {
427    Evas_Object *top;
428    Evas_Object *newest = NULL;
429    unsigned int newest_focus_order = 0;
430
431    INTERNAL_ENTRY;
432
433    if (!sd->focused) return;
434    if (!sd->parent_obj) return;
435
436    top = elm_widget_top_get(sd->parent_obj);
437    if (top)
438      {
439         newest = elm_widget_newest_focus_order_get
440            (top, &newest_focus_order, can_focus_only);
441         if (newest)
442           {
443              elm_object_focus_set(newest, EINA_FALSE);
444              elm_object_focus_set(newest, EINA_TRUE);
445           }
446      }
447 }
448
449 static void
450 _smart_del(Evas_Object *obj)
451 {
452    Evas_Object *sobj;
453    Elm_Translate_String_Data *ts;
454    Elm_Event_Cb_Data *ecb;
455
456    ELM_WIDGET_DATA_GET(obj, sd);
457
458    if (sd->hover_obj)
459      {
460         /* detach it from us */
461         evas_object_event_callback_del_full
462           (sd->hover_obj, EVAS_CALLBACK_DEL, _on_sub_obj_del, sd);
463         sd->hover_obj = NULL;
464      }
465
466    while (sd->subobjs)
467      {
468         sobj = eina_list_data_get(sd->subobjs);
469
470         /* let the objects clean-up themselves and get rid of this list */
471         if (!elm_widget_sub_object_del(obj, sobj))
472           {
473              ERR("failed to remove sub object %p from %p\n", sobj, obj);
474              sd->subobjs = eina_list_remove_list
475                  (sd->subobjs, sd->subobjs);
476           }
477         evas_object_del(sobj);
478      }
479    sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */
480    sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */
481    EINA_LIST_FREE (sd->translate_strings, ts)
482      {
483         eina_stringshare_del(ts->id);
484         eina_stringshare_del(ts->domain);
485         eina_stringshare_del(ts->string);
486         free(ts);
487      }
488
489    EINA_LIST_FREE (sd->event_cb, ecb)
490      free(ecb);
491
492    if (sd->style) eina_stringshare_del(sd->style);
493    if (sd->theme) elm_theme_free(sd->theme);
494    _if_focused_revert(obj, EINA_TRUE);
495    if (sd->access_info) eina_stringshare_del(sd->access_info);
496    free(sd);
497    evas_object_smart_data_set(obj, NULL);
498 }
499
500 static void
501 _smart_reconfigure(Elm_Widget_Smart_Data *sd)
502 {
503    if (sd->resize_obj)
504      {
505         evas_object_move(sd->resize_obj, sd->x, sd->y);
506         evas_object_resize(sd->resize_obj, sd->w, sd->h);
507      }
508    if (sd->hover_obj)
509      {
510         evas_object_move(sd->hover_obj, sd->x, sd->y);
511         evas_object_resize(sd->hover_obj, sd->w, sd->h);
512      }
513 }
514
515 static void
516 _smart_move(Evas_Object *obj,
517             Evas_Coord x,
518             Evas_Coord y)
519 {
520    ELM_WIDGET_DATA_GET(obj, sd);
521
522    sd->x = x;
523    sd->y = y;
524
525    _smart_reconfigure(sd);
526 }
527
528 static void
529 _smart_resize(Evas_Object *obj,
530               Evas_Coord w,
531               Evas_Coord h)
532 {
533    ELM_WIDGET_DATA_GET(obj, sd);
534
535    sd->w = w;
536    sd->h = h;
537
538    _smart_reconfigure(sd);
539 }
540
541 static void
542 _smart_show(Evas_Object *obj)
543 {
544    Eina_List *list;
545    Evas_Object *o;
546
547    if ((list = evas_object_smart_members_get(obj)))
548      {
549         EINA_LIST_FREE (list, o)
550           {
551              if (evas_object_data_get(o, "_elm_leaveme")) continue;
552              evas_object_show(o);
553           }
554      }
555 }
556
557 static void
558 _smart_hide(Evas_Object *obj)
559 {
560    Eina_List *list;
561    Evas_Object *o;
562
563    list = evas_object_smart_members_get(obj);
564    EINA_LIST_FREE (list, o)
565      {
566         if (evas_object_data_get(o, "_elm_leaveme")) continue;
567         evas_object_hide(o);
568      }
569 }
570
571 static void
572 _smart_color_set(Evas_Object *obj,
573                  int r,
574                  int g,
575                  int b,
576                  int a)
577 {
578    Eina_List *list;
579    Evas_Object *o;
580
581    if ((list = evas_object_smart_members_get(obj)))
582      {
583         EINA_LIST_FREE (list, o)
584           {
585              if (evas_object_data_get(o, "_elm_leaveme")) continue;
586              evas_object_color_set(o, r, g, b, a);
587           }
588      }
589 }
590
591 static void
592 _smart_clip_set(Evas_Object *obj,
593                 Evas_Object *clip)
594 {
595    Eina_List *list;
596    Evas_Object *o;
597
598    if ((list = evas_object_smart_members_get(obj)))
599      {
600         EINA_LIST_FREE (list, o)
601           {
602              if (evas_object_data_get(o, "_elm_leaveme")) continue;
603              evas_object_clip_set(o, clip);
604           }
605      }
606 }
607
608 static void
609 _smart_clip_unset(Evas_Object *obj)
610 {
611    Eina_List *list;
612    Evas_Object *o;
613
614    if ((list = evas_object_smart_members_get(obj)))
615      {
616         EINA_LIST_FREE (list, o)
617           {
618              if (evas_object_data_get(o, "_elm_leaveme")) continue;
619              evas_object_clip_unset(o);
620           }
621      }
622 }
623
624 static void
625 _smart_calculate(Evas_Object *obj __UNUSED__)
626 {
627    /* a NO-OP, on the base */
628 }
629
630 static void
631 _smart_member_add(Evas_Object *obj,
632                   Evas_Object *child)
633 {
634    int r, g, b, a;
635
636    if (evas_object_data_get(child, "_elm_leaveme")) return;
637
638    evas_object_color_get(obj, &r, &g, &b, &a);
639    evas_object_color_set(child, r, g, b, a);
640
641    evas_object_clip_set(child, evas_object_clip_get(obj));
642
643    if (evas_object_visible_get(obj))
644      evas_object_show(child);
645    else
646      evas_object_hide(child);
647 }
648
649 static void
650 _smart_member_del(Evas_Object *obj __UNUSED__,
651                   Evas_Object *child)
652 {
653    if (evas_object_data_get(child, "_elm_leaveme")) return;
654    evas_object_clip_unset(child);
655 }
656
657 static void
658 _elm_widget_smart_set(Elm_Widget_Smart_Class *api)
659 {
660    Evas_Smart_Class *sc;
661
662    if (!(sc = (Evas_Smart_Class *)api))
663      return;
664
665    sc->add = _smart_add;
666    sc->del = _smart_del;
667    sc->move = _smart_move;
668    sc->resize = _smart_resize;
669    sc->show = _smart_show;
670    sc->hide = _smart_hide;
671    sc->color_set = _smart_color_set;
672    sc->clip_set = _smart_clip_set;
673    sc->clip_unset = _smart_clip_unset;
674    sc->calculate = _smart_calculate;
675    sc->member_add = _smart_member_add;
676    sc->member_del = _smart_member_del;
677
678 #define API_DEFAULT_SET_UNIMPLEMENTED(_prefix) \
679   api->_prefix = _elm_widget_##_prefix##_func_unimplemented;
680
681    /* NB: always remember to call these parent versions on children,
682     * except for the unimplemented ones and calculate, which is moot */
683
684 #define API_DEFAULT_SET(_prefix) \
685   api->_prefix = _elm_widget_##_prefix##_func;
686
687    /* base api */
688    API_DEFAULT_SET_UNIMPLEMENTED(on_focus);
689    API_DEFAULT_SET_UNIMPLEMENTED(disable);
690
691    API_DEFAULT_SET(theme);
692    API_DEFAULT_SET_UNIMPLEMENTED(on_focus_region);
693
694    API_DEFAULT_SET_UNIMPLEMENTED(translate);
695    API_DEFAULT_SET_UNIMPLEMENTED(event);
696    API_DEFAULT_SET_UNIMPLEMENTED(focus_next);
697    API_DEFAULT_SET_UNIMPLEMENTED(focus_direction);
698
699    /* NB: because those two weren't hooks before, translate the
700     * individual calls to them on the widgets as we bring them to the
701     * new class hierarchy. also, sub_object_{add,del} must be
702     * different than member_{add,del} here, because widget parenting
703     * on elm does not always imply parent and child will live on the
704     * same Evas layer */
705    API_DEFAULT_SET(sub_object_add);
706    API_DEFAULT_SET(sub_object_del);
707
708 #undef API_DEFAULT_SET
709 #undef API_DEFAULT_SET_UNIMPLEMENTED
710
711    sc->callbacks = _smart_callbacks;
712 }
713
714 // internal funcs
715 static inline Eina_Bool
716 _elm_widget_focus_chain_manager_is(const Evas_Object *obj)
717 {
718    API_ENTRY return EINA_FALSE;
719
720    if (!sd->api) return EINA_FALSE;
721    return sd->api->focus_next &&
722           (sd->api->focus_next != _elm_widget_focus_next_func_unimplemented);
723 }
724
725 static inline Eina_Bool
726 _elm_widget_focus_direction_manager_is(const Evas_Object *obj)
727 {
728    API_ENTRY return EINA_FALSE;
729
730    if (!sd->api) return EINA_FALSE;
731    return sd->api->focus_direction &&
732           (sd->api->focus_direction !=
733            _elm_widget_focus_direction_func_unimplemented);
734 }
735
736 static void
737 _obj_mouse_down(void *data,
738                 Evas *e __UNUSED__,
739                 Evas_Object *obj __UNUSED__,
740                 void *event_info)
741 {
742    Elm_Widget_Smart_Data *sd = data;
743    Evas_Event_Mouse_Down *ev = event_info;
744    if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD))
745      sd->still_in = EINA_TRUE;
746 }
747
748 static void
749 _obj_mouse_move(void *data,
750                 Evas *e __UNUSED__,
751                 Evas_Object *obj,
752                 void *event_info)
753 {
754    Elm_Widget_Smart_Data *sd = data;
755    Evas_Event_Mouse_Move *ev = event_info;
756    if (sd->still_in)
757      {
758         if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
759           sd->still_in = EINA_FALSE;
760         else
761           {
762              Evas_Coord x, y, w, h;
763              evas_object_geometry_get(obj, &x, &y, &w, &h);
764              if ((ev->cur.canvas.x < x) || (ev->cur.canvas.y < y) ||
765                  (ev->cur.canvas.x >= (x + w)) || (ev->cur.canvas.y >= (y + h)))
766                sd->still_in = EINA_FALSE;
767           }
768      }
769 }
770
771 static void
772 _obj_mouse_up(void *data,
773               Evas *e __UNUSED__,
774               Evas_Object *obj,
775               void *event_info __UNUSED__)
776 {
777    Elm_Widget_Smart_Data *sd = data;
778    if (sd->still_in)
779      elm_widget_focus_mouse_up_handle(obj);
780    sd->still_in = EINA_FALSE;
781 }
782
783 static void
784 _propagate_x_drag_lock(Evas_Object *obj,
785                        int dir)
786 {
787    INTERNAL_ENTRY;
788    if (sd->parent_obj)
789      {
790         Elm_Widget_Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
791         if (sd2)
792           {
793              sd2->child_drag_x_locked += dir;
794              _propagate_x_drag_lock(sd->parent_obj, dir);
795           }
796      }
797 }
798
799 static void
800 _propagate_y_drag_lock(Evas_Object *obj,
801                        int dir)
802 {
803    INTERNAL_ENTRY;
804    if (sd->parent_obj)
805      {
806         Elm_Widget_Smart_Data *sd2 = evas_object_smart_data_get(sd->parent_obj);
807         if (sd2)
808           {
809              sd2->child_drag_y_locked += dir;
810              _propagate_y_drag_lock(sd->parent_obj, dir);
811           }
812      }
813 }
814
815 static void
816 _propagate_event(void *data,
817                  Evas *e __UNUSED__,
818                  Evas_Object *obj,
819                  void *event_info)
820 {
821    INTERNAL_ENTRY;
822    Evas_Callback_Type type = (Evas_Callback_Type)(long)data;
823    Evas_Event_Flags *event_flags = NULL;
824
825    switch (type)
826      {
827       case EVAS_CALLBACK_KEY_DOWN:
828       {
829          Evas_Event_Key_Down *ev = event_info;
830          event_flags = &(ev->event_flags);
831       }
832       break;
833
834       case EVAS_CALLBACK_KEY_UP:
835       {
836          Evas_Event_Key_Up *ev = event_info;
837          event_flags = &(ev->event_flags);
838       }
839       break;
840
841       case EVAS_CALLBACK_MOUSE_WHEEL:
842       {
843          Evas_Event_Mouse_Wheel *ev = event_info;
844          event_flags = &(ev->event_flags);
845       }
846       break;
847
848       default:
849         break;
850      }
851
852    elm_widget_event_propagate(obj, type, event_info, event_flags);
853 }
854
855 /**
856  * If elm_widget_focus_region_get() returns EINA_FALSE, this function will
857  * ignore region show action.
858  */
859 static void
860 _elm_widget_focus_region_show(const Evas_Object *obj)
861 {
862    Evas_Coord x, y, ox, oy, w, h;
863    Evas_Object *o;
864
865    API_ENTRY return;
866
867    o = elm_widget_parent_get(obj);
868    if (!o) return;
869
870    if (!elm_widget_focus_region_get(obj, &x, &y, NULL, NULL))
871      return;
872
873    evas_object_geometry_get(obj, &ox, &oy, &w, &h);
874    if (w == 0 && h == 0) return;
875
876    while (o)
877      {
878         if (_elm_scrollable_is(o))
879           {
880              Evas_Coord px, py, pw, ph;
881              Evas_Coord rx, ry;
882
883              evas_object_geometry_get(o, &px, &py, &pw, &ph);
884
885              if ((px <= ox) && (px + pw) >= (ox + w) &&
886                  (py <= oy) && (py + ph) >= (oy + h))
887                {
888                   // if object is already shown
889                   o = elm_widget_parent_get(o);
890                   continue;
891                }
892              else if ((px < ox) && ((px + pw) < (ox + w)))
893                {
894                   // if object is over the viewport to the x axis.
895                   x += w - pw;
896                }
897              else if ((py < oy) && ((py + ph) < (oy + h)))
898                {
899                   // if object is over the viewport to the y axis.
900                   y += h - ph;
901                }
902
903              ELM_SCROLLABLE_IFACE_GET(o, s_iface);
904              s_iface->content_pos_get(o, &rx, &ry);
905              s_iface->content_viewport_size_get(o, &w, &h);
906
907              x += rx + ox - px;
908              y += ry + oy - py;
909
910              s_iface->content_region_show(o, x, y, w, h);
911              x = 0;
912              y = 0;
913           }
914         o = elm_widget_parent_get(o);
915      }
916 }
917
918 static void
919 _parent_focus(Evas_Object *obj)
920 {
921    API_ENTRY return;
922
923    if (sd->focused) return;
924
925    Evas_Object *o = elm_widget_parent_get(obj);
926    sd->focus_order_on_calc = EINA_TRUE;
927
928    if (o) _parent_focus(o);
929
930    if (!sd->focus_order_on_calc)
931      return;  /* we don't want to override it if by means of any of the
932                  callbacks below one gets to calculate our order
933                  first. */
934
935    focus_order++;
936    sd->focus_order = focus_order;
937    if (!sd->api) return;
938    if (sd->top_win_focused)
939      {
940         sd->focused = EINA_TRUE;
941         sd->api->on_focus(obj);
942      }
943    sd->focus_order_on_calc = EINA_FALSE;
944
945    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
946      _elm_access_highlight_set(obj);
947 }
948
949 static void
950 _elm_object_focus_chain_del_cb(void *data,
951                                Evas *e __UNUSED__,
952                                Evas_Object *obj,
953                                void *event_info __UNUSED__)
954 {
955    Elm_Widget_Smart_Data *sd = data;
956
957    sd->focus_chain = eina_list_remove(sd->focus_chain, obj);
958 }
959
960 EAPI const Elm_Widget_Smart_Class *
961 elm_widget_smart_class_get(void)
962 {
963    static Elm_Widget_Smart_Class _sc =
964      ELM_WIDGET_SMART_CLASS_INIT_NAME_VERSION(ELM_WIDGET_SMART_NAME);
965    static const Elm_Widget_Smart_Class *class = NULL;
966
967    if (class)
968      return class;
969
970    _elm_widget_smart_set(&_sc);
971    class = &_sc;
972
973    return class;
974 }
975
976 EAPI Evas_Object *
977 elm_widget_add(Evas_Smart *smart,
978                Evas_Object *parent)
979 {
980    Evas *e;
981    Evas_Object *o;
982
983    e = evas_object_evas_get(parent);
984    if (!e) return NULL;
985
986    o = evas_object_smart_add(e, smart);
987    elm_widget_parent_set(o, parent);
988
989    return o;
990 }
991
992 EAPI void
993 elm_widget_parent_set(Evas_Object *obj,
994                       Evas_Object *parent)
995 {
996    ELM_WIDGET_DATA_GET(obj, sd);
997
998    if (!sd->api->parent_set) return;
999
1000    sd->api->parent_set(obj, parent);
1001 }
1002
1003 EAPI Eina_Bool
1004 elm_widget_api_check(int ver)
1005 {
1006    if (ver != ELM_INTERNAL_API_VERSION)
1007      {
1008         CRITICAL("Elementary widget api versions do not match");
1009         return EINA_FALSE;
1010      }
1011    return EINA_TRUE;
1012 }
1013
1014 EAPI Eina_Bool
1015 elm_widget_access(Evas_Object *obj,
1016                   Eina_Bool is_access)
1017 {
1018    const Eina_List *l;
1019    Evas_Object *child;
1020    Eina_Bool ret = EINA_TRUE;
1021
1022    API_ENTRY return EINA_FALSE;
1023    EINA_LIST_FOREACH(sd->subobjs, l, child)
1024      ret &= elm_widget_access(child, is_access);
1025
1026    if (sd->api && sd->api->access)
1027      sd->api->access(obj, is_access);
1028    else
1029      return EINA_FALSE;
1030
1031    return ret;
1032 }
1033
1034 EAPI Eina_Bool
1035 elm_widget_theme(Evas_Object *obj)
1036 {
1037    const Eina_List *l;
1038    Evas_Object *child;
1039    Elm_Tooltip *tt;
1040    Elm_Cursor *cur;
1041    Eina_Bool ret = EINA_TRUE;
1042
1043    API_ENTRY return EINA_FALSE;
1044
1045    EINA_LIST_FOREACH(sd->subobjs, l, child)
1046      if (_elm_widget_is(child)) ret &= elm_widget_theme(child);
1047    if (sd->resize_obj && _elm_widget_is(sd->resize_obj))
1048      ret &= elm_widget_theme(sd->resize_obj);
1049    if (sd->hover_obj) ret &= elm_widget_theme(sd->hover_obj);
1050
1051    EINA_LIST_FOREACH(sd->tooltips, l, tt)
1052      elm_tooltip_theme(tt);
1053    EINA_LIST_FOREACH(sd->cursors, l, cur)
1054      elm_cursor_theme(cur);
1055
1056    if (!sd->api) return EINA_FALSE;
1057
1058    ret &= sd->api->theme(obj);
1059
1060    return ret;
1061 }
1062
1063 EAPI void
1064 elm_widget_theme_specific(Evas_Object *obj,
1065                           Elm_Theme *th,
1066                           Eina_Bool force)
1067 {
1068    const Eina_List *l;
1069    Evas_Object *child;
1070    Elm_Tooltip *tt;
1071    Elm_Cursor *cur;
1072    Elm_Theme *th2, *thdef;
1073
1074    API_ENTRY return;
1075
1076    thdef = elm_theme_default_get();
1077    if (!th) th = thdef;
1078    if (!force)
1079      {
1080         th2 = sd->theme;
1081         if (!th2) th2 = thdef;
1082         while (th2)
1083           {
1084              if (th2 == th)
1085                {
1086                   force = EINA_TRUE;
1087                   break;
1088                }
1089              if (th2 == thdef) break;
1090              th2 = th2->ref_theme;
1091              if (!th2) th2 = thdef;
1092           }
1093      }
1094    if (!force) return;
1095    EINA_LIST_FOREACH(sd->subobjs, l, child)
1096      elm_widget_theme_specific(child, th, force);
1097    if (sd->resize_obj) elm_widget_theme(sd->resize_obj);
1098    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
1099    EINA_LIST_FOREACH(sd->tooltips, l, tt)
1100      elm_tooltip_theme(tt);
1101    EINA_LIST_FOREACH(sd->cursors, l, cur)
1102      elm_cursor_theme(cur);
1103    if (!sd->api) return;
1104    sd->api->theme(obj);
1105 }
1106
1107 /**
1108  * Returns the widget's mirrored mode.
1109  *
1110  * @param obj The widget.
1111  * @return mirrored mode of the object.
1112  *
1113  **/
1114 EAPI Eina_Bool
1115 elm_widget_mirrored_get(const Evas_Object *obj)
1116 {
1117    API_ENTRY return EINA_FALSE;
1118    return sd->is_mirrored;
1119 }
1120
1121 /**
1122  * Sets the widget's mirrored mode.
1123  *
1124  * @param obj The widget.
1125  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
1126  */
1127 EAPI void
1128 elm_widget_mirrored_set(Evas_Object *obj,
1129                         Eina_Bool mirrored)
1130 {
1131    API_ENTRY return;
1132
1133    mirrored = !!mirrored;
1134
1135    if (sd->is_mirrored == mirrored) return;
1136
1137    sd->is_mirrored = mirrored;
1138    elm_widget_theme(obj);
1139 }
1140
1141 /**
1142  * Returns the widget's mirrored mode setting.
1143  *
1144  * @param obj The widget.
1145  * @return mirrored mode setting of the object.
1146  *
1147  **/
1148 EAPI Eina_Bool
1149 elm_widget_mirrored_automatic_get(const Evas_Object *obj)
1150 {
1151    API_ENTRY return EINA_FALSE;
1152    return sd->mirrored_auto_mode;
1153 }
1154
1155 /**
1156  * Sets the widget's mirrored mode setting.
1157  * When widget in automatic mode, it follows the system mirrored mode set by
1158  * elm_mirrored_set().
1159  * @param obj The widget.
1160  * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual.
1161  */
1162 EAPI void
1163 elm_widget_mirrored_automatic_set(Evas_Object *obj,
1164                                   Eina_Bool automatic)
1165 {
1166    API_ENTRY return;
1167    if (sd->mirrored_auto_mode != automatic)
1168      {
1169         sd->mirrored_auto_mode = automatic;
1170
1171         if (automatic)
1172           {
1173              elm_widget_mirrored_set(obj, elm_config_mirrored_get());
1174           }
1175      }
1176 }
1177
1178 EAPI void
1179 elm_widget_on_show_region_hook_set(Evas_Object *obj,
1180                                    void (*func)(void *data,
1181                                                 Evas_Object *obj),
1182                                    void *data)
1183 {
1184    API_ENTRY return;
1185
1186    sd->on_show_region = func;
1187    sd->on_show_region_data = data;
1188 }
1189
1190 EAPI Eina_Bool
1191 elm_widget_sub_object_add(Evas_Object *obj,
1192                           Evas_Object *sobj)
1193 {
1194    API_ENTRY return EINA_FALSE;
1195    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1196
1197    if (!sd->api) return EINA_FALSE;
1198    return sd->api->sub_object_add(obj, sobj);
1199 }
1200
1201 EAPI Eina_Bool
1202 elm_widget_sub_object_del(Evas_Object *obj,
1203                           Evas_Object *sobj)
1204 {
1205    API_ENTRY return EINA_FALSE;
1206    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1207
1208    if (!sobj) return EINA_FALSE;
1209
1210    if (!sd->api) return EINA_FALSE;
1211    return sd->api->sub_object_del(obj, sobj);
1212 }
1213
1214 //SHKWAK : Temp Function for Indicator Issue
1215 // THIS MUST BE REMOVED
1216
1217 EAPI const Eina_List *
1218 elm_widget_sub_object_list_get(const Evas_Object *obj)
1219 {
1220    API_ENTRY return NULL;
1221    return (const Eina_List *)sd->subobjs;
1222 }
1223
1224 //SHKWAK : END
1225
1226
1227 /* a resize object is a sub object with some more callbacks on it and
1228  * a smart member of the parent
1229  */
1230 EAPI void
1231 elm_widget_resize_object_set(Evas_Object *obj,
1232                              Evas_Object *sobj)
1233 {
1234    Evas_Object *parent;
1235
1236    API_ENTRY return;
1237
1238    if (sd->resize_obj == sobj) return;
1239
1240    // orphan previous resize obj
1241    if (sd->resize_obj)
1242      {
1243         evas_object_clip_unset(sd->resize_obj);
1244         evas_object_smart_member_del(sd->resize_obj);
1245
1246         if (_elm_widget_is(sd->resize_obj))
1247           {
1248              if (elm_widget_focus_get(sd->resize_obj)) _parents_unfocus(obj);
1249           }
1250
1251         elm_widget_sub_object_del(obj, sd->resize_obj);
1252      }
1253
1254    sd->resize_obj = sobj;
1255    if (!sobj)
1256      {
1257         evas_object_event_callback_del_full(obj,
1258                                             EVAS_CALLBACK_MOUSE_DOWN,
1259                                             _obj_mouse_down, sd);
1260         evas_object_event_callback_del_full(obj,
1261                                             EVAS_CALLBACK_MOUSE_MOVE,
1262                                             _obj_mouse_move, sd);
1263         evas_object_event_callback_del_full(obj,
1264                                             EVAS_CALLBACK_MOUSE_UP,
1265                                             _obj_mouse_up, sd);
1266         return;
1267      }
1268
1269    // orphan new resize obj
1270    parent = evas_object_data_get(sobj, "elm-parent");
1271    if (parent && parent != obj)
1272      {
1273         ELM_WIDGET_DATA_GET(parent, sdp);
1274
1275         /* should be there, just being paranoid */
1276         if (sdp)
1277           {
1278              if (sdp->resize_obj == sobj)
1279                elm_widget_resize_object_set(parent, NULL);
1280              else
1281                elm_widget_sub_object_del(parent, sobj);
1282           }
1283      }
1284
1285    elm_widget_sub_object_add(obj, sobj);
1286
1287    evas_object_smart_member_add(sobj, obj);
1288
1289    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
1290                                   _obj_mouse_down, sd);
1291    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
1292                                   _obj_mouse_move, sd);
1293    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1294                                   _obj_mouse_up, sd);
1295    _smart_reconfigure(sd);
1296 }
1297
1298 /* WARNING: the programmer is responsible, in the scenario of
1299  * exchanging a hover object, of cleaning the old hover "target"
1300  * before
1301  */
1302 EAPI void
1303 elm_widget_hover_object_set(Evas_Object *obj,
1304                             Evas_Object *sobj)
1305 {
1306    API_ENTRY return;
1307    if (sd->hover_obj)
1308      {
1309         evas_object_event_callback_del_full(sd->hover_obj, EVAS_CALLBACK_DEL,
1310                                             _on_sub_obj_del, sd);
1311      }
1312    sd->hover_obj = sobj;
1313    if (sd->hover_obj)
1314      {
1315         evas_object_event_callback_add(sobj, EVAS_CALLBACK_DEL,
1316                                        _on_sub_obj_del, sd);
1317         _smart_reconfigure(sd);
1318      }
1319 }
1320
1321 EAPI void
1322 elm_widget_can_focus_set(Evas_Object *obj,
1323                          Eina_Bool can_focus)
1324 {
1325    API_ENTRY return;
1326
1327    can_focus = !!can_focus;
1328
1329    if (sd->can_focus == can_focus) return;
1330    sd->can_focus = can_focus;
1331    if (sd->can_focus)
1332      {
1333         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
1334                                        _propagate_event,
1335                                        (void *)(long)EVAS_CALLBACK_KEY_DOWN);
1336         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP,
1337                                        _propagate_event,
1338                                        (void *)(long)EVAS_CALLBACK_KEY_UP);
1339         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1340                                        _propagate_event,
1341                                        (void *)(long)EVAS_CALLBACK_MOUSE_WHEEL);
1342      }
1343    else
1344      {
1345         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_DOWN,
1346                                        _propagate_event);
1347         evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_UP,
1348                                        _propagate_event);
1349         evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_WHEEL,
1350                                        _propagate_event);
1351      }
1352 }
1353
1354 EAPI Eina_Bool
1355 elm_widget_can_focus_get(const Evas_Object *obj)
1356 {
1357    API_ENTRY return EINA_FALSE;
1358    return sd->can_focus;
1359 }
1360
1361 EAPI Eina_Bool
1362 elm_widget_child_can_focus_get(const Evas_Object *obj)
1363 {
1364    API_ENTRY return EINA_FALSE;
1365    return sd->child_can_focus;
1366 }
1367
1368 /**
1369  * @internal
1370  *
1371  * This API makes the widget object and its children to be unfocusable.
1372  *
1373  * This API can be helpful for an object to be deleted.
1374  * When an object will be deleted soon, it and its children may not
1375  * want to get focus (by focus reverting or by other focus controls).
1376  * Then, just use this API before deleting.
1377  *
1378  * @param obj The widget root of sub-tree
1379  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1380  *
1381  * @ingroup Widget
1382  */
1383 EAPI void
1384 elm_widget_tree_unfocusable_set(Evas_Object *obj,
1385                                 Eina_Bool tree_unfocusable)
1386 {
1387    API_ENTRY return;
1388
1389    tree_unfocusable = !!tree_unfocusable;
1390    if (sd->tree_unfocusable == tree_unfocusable) return;
1391    sd->tree_unfocusable = tree_unfocusable;
1392    elm_widget_focus_tree_unfocusable_handle(obj);
1393 }
1394
1395 /**
1396  * @internal
1397  *
1398  * This returns true, if the object sub-tree is unfocusable.
1399  *
1400  * @param obj The widget root of sub-tree
1401  * @return EINA_TRUE if the object sub-tree is unfocusable
1402  *
1403  * @ingroup Widget
1404  */
1405 EAPI Eina_Bool
1406 elm_widget_tree_unfocusable_get(const Evas_Object *obj)
1407 {
1408    API_ENTRY return EINA_FALSE;
1409    return sd->tree_unfocusable;
1410 }
1411
1412 /**
1413  * @internal
1414  *
1415  * Get the list of focusable child objects.
1416  *
1417  * This function retruns list of child objects which can get focus.
1418  *
1419  * @param obj The parent widget
1420  * @retrun list of focusable child objects.
1421  *
1422  * @ingroup Widget
1423  */
1424 EAPI Eina_List *
1425 elm_widget_can_focus_child_list_get(const Evas_Object *obj)
1426 {
1427    API_ENTRY return NULL;
1428
1429    const Eina_List *l;
1430    Eina_List *child_list = NULL;
1431    Evas_Object *child;
1432
1433    if (sd->subobjs)
1434      {
1435         EINA_LIST_FOREACH(sd->subobjs, l, child)
1436           {
1437              if ((elm_widget_can_focus_get(child)) &&
1438                  (evas_object_visible_get(child)) &&
1439                  (!elm_widget_disabled_get(child)))
1440                child_list = eina_list_append(child_list, child);
1441              else if (elm_widget_is(child))
1442                {
1443                   Eina_List *can_focus_list;
1444                   can_focus_list = elm_widget_can_focus_child_list_get(child);
1445                   if (can_focus_list)
1446                     child_list = eina_list_merge(child_list, can_focus_list);
1447                }
1448           }
1449      }
1450    return child_list;
1451 }
1452
1453 EAPI void
1454 elm_widget_highlight_ignore_set(Evas_Object *obj,
1455                                 Eina_Bool ignore)
1456 {
1457    API_ENTRY return;
1458    sd->highlight_ignore = !!ignore;
1459 }
1460
1461 EAPI Eina_Bool
1462 elm_widget_highlight_ignore_get(const Evas_Object *obj)
1463 {
1464    API_ENTRY return EINA_FALSE;
1465    return sd->highlight_ignore;
1466 }
1467
1468 EAPI void
1469 elm_widget_highlight_in_theme_set(Evas_Object *obj,
1470                                   Eina_Bool highlight)
1471 {
1472    API_ENTRY return;
1473    sd->highlight_in_theme = !!highlight;
1474    /* FIXME: if focused, it should switch from one mode to the other */
1475 }
1476
1477 EAPI Eina_Bool
1478 elm_widget_highlight_in_theme_get(const Evas_Object *obj)
1479 {
1480    API_ENTRY return EINA_FALSE;
1481    return sd->highlight_in_theme;
1482 }
1483
1484 EAPI Eina_Bool
1485 elm_widget_focus_get(const Evas_Object *obj)
1486 {
1487    API_ENTRY return EINA_FALSE;
1488    return sd->focused;
1489 }
1490
1491 EAPI Evas_Object *
1492 elm_widget_focused_object_get(const Evas_Object *obj)
1493 {
1494    const Evas_Object *subobj;
1495    const Eina_List *l;
1496    API_ENTRY return NULL;
1497
1498    if (!sd->focused) return NULL;
1499    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1500      {
1501         Evas_Object *fobj = elm_widget_focused_object_get(subobj);
1502         if (fobj) return fobj;
1503      }
1504    return (Evas_Object *)obj;
1505 }
1506
1507 EAPI Evas_Object *
1508 elm_widget_top_get(const Evas_Object *obj)
1509 {
1510    API_ENTRY return NULL;
1511    if (sd->parent_obj) return elm_widget_top_get(sd->parent_obj);
1512    return (Evas_Object *)obj;
1513 }
1514
1515 EAPI Eina_Bool
1516 elm_widget_is(const Evas_Object *obj)
1517 {
1518    return _elm_widget_is(obj);
1519 }
1520
1521 EAPI Evas_Object *
1522 elm_widget_parent_widget_get(const Evas_Object *obj)
1523 {
1524    Evas_Object *parent;
1525
1526    if (_elm_widget_is(obj))
1527      {
1528         Elm_Widget_Smart_Data *sd = evas_object_smart_data_get(obj);
1529         if (!sd) return NULL;
1530         parent = sd->parent_obj;
1531      }
1532    else
1533      {
1534         parent = evas_object_data_get(obj, "elm-parent");
1535         if (!parent) parent = evas_object_smart_parent_get(obj);
1536      }
1537
1538    while (parent)
1539      {
1540         Evas_Object *elm_parent;
1541         if (_elm_widget_is(parent)) break;
1542         elm_parent = evas_object_data_get(parent, "elm-parent");
1543         if (elm_parent) parent = elm_parent;
1544         else parent = evas_object_smart_parent_get(parent);
1545      }
1546    return parent;
1547 }
1548
1549 EAPI Evas_Object *
1550 elm_widget_parent2_get(const Evas_Object *obj)
1551 {
1552    if (_elm_widget_is(obj))
1553      {
1554         Elm_Widget_Smart_Data *sd = evas_object_smart_data_get(obj);
1555         if (sd) return sd->parent2;
1556      }
1557    return NULL;
1558 }
1559
1560 EAPI void
1561 elm_widget_parent2_set(Evas_Object *obj, Evas_Object *parent)
1562 {
1563    API_ENTRY return;
1564    sd->parent2 = parent;
1565 }
1566
1567 EAPI void
1568 elm_widget_event_callback_add(Evas_Object *obj,
1569                               Elm_Event_Cb func,
1570                               const void *data)
1571 {
1572    API_ENTRY return;
1573    EINA_SAFETY_ON_NULL_RETURN(func);
1574    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
1575    ecb->func = func;
1576    ecb->data = data;
1577    sd->event_cb = eina_list_append(sd->event_cb, ecb);
1578 }
1579
1580 EAPI void *
1581 elm_widget_event_callback_del(Evas_Object *obj,
1582                               Elm_Event_Cb func,
1583                               const void *data)
1584 {
1585    API_ENTRY return NULL;
1586    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
1587    Eina_List *l;
1588    Elm_Event_Cb_Data *ecd;
1589    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
1590      if ((ecd->func == func) && (ecd->data == data))
1591        {
1592           free(ecd);
1593           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
1594           return (void *)data;
1595        }
1596    return NULL;
1597 }
1598
1599 EAPI Eina_Bool
1600 elm_widget_event_propagate(Evas_Object *obj,
1601                            Evas_Callback_Type type,
1602                            void *event_info,
1603                            Evas_Event_Flags *event_flags)
1604 {
1605    API_ENTRY return EINA_FALSE; //TODO reduce.
1606
1607    if (!_elm_widget_is(obj)) return EINA_FALSE;
1608    Evas_Object *parent = obj;
1609    Elm_Event_Cb_Data *ecd;
1610    Eina_List *l, *l_prev;
1611
1612    while (parent &&
1613           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
1614      {
1615         sd = evas_object_smart_data_get(parent);
1616         if ((!sd) || (!_elm_widget_is(obj)))
1617           return EINA_FALSE;  //Not Elm Widget
1618         if (!sd->api) return EINA_FALSE;
1619
1620         if (sd->api->event(parent, obj, type, event_info))
1621           return EINA_TRUE;
1622
1623         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1624           {
1625              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1626                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1627                return EINA_TRUE;
1628           }
1629         parent = sd->parent_obj;
1630      }
1631
1632    return EINA_FALSE;
1633 }
1634
1635 /**
1636  * @internal
1637  *
1638  * Set custom focus chain.
1639  *
1640  * This function i set one new and overwrite any previous custom focus chain
1641  * with the list of objects. The previous list will be deleted and this list
1642  * will be managed. After setted, don't modity it.
1643  *
1644  * @note On focus cycle, only will be evaluated children of this container.
1645  *
1646  * @param obj The container widget
1647  * @param objs Chain of objects to pass focus
1648  * @ingroup Widget
1649  */
1650 EAPI void
1651 elm_widget_focus_custom_chain_set(Evas_Object *obj,
1652                                   Eina_List *objs)
1653 {
1654    API_ENTRY return;
1655
1656    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1657
1658    elm_widget_focus_custom_chain_unset(obj);
1659
1660    Eina_List *l;
1661    Evas_Object *o;
1662
1663    EINA_LIST_FOREACH(objs, l, o)
1664      {
1665         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1666                                        _elm_object_focus_chain_del_cb, sd);
1667      }
1668
1669    sd->focus_chain = objs;
1670 }
1671
1672 /**
1673  * @internal
1674  *
1675  * Get custom focus chain
1676  *
1677  * @param obj The container widget
1678  * @ingroup Widget
1679  */
1680 EAPI const Eina_List *
1681 elm_widget_focus_custom_chain_get(const Evas_Object *obj)
1682 {
1683    API_ENTRY return NULL;
1684    return (const Eina_List *)sd->focus_chain;
1685 }
1686
1687 /**
1688  * @internal
1689  *
1690  * Unset custom focus chain
1691  *
1692  * @param obj The container widget
1693  * @ingroup Widget
1694  */
1695 EAPI void
1696 elm_widget_focus_custom_chain_unset(Evas_Object *obj)
1697 {
1698    API_ENTRY return;
1699    Eina_List *l, *l_next;
1700    Evas_Object *o;
1701
1702    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1703      {
1704         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1705                                             _elm_object_focus_chain_del_cb, sd);
1706         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1707      }
1708 }
1709
1710 /**
1711  * @internal
1712  *
1713  * Append object to custom focus chain.
1714  *
1715  * @note If relative_child equal to NULL or not in custom chain, the object
1716  * will be added in end.
1717  *
1718  * @note On focus cycle, only will be evaluated children of this container.
1719  *
1720  * @param obj The container widget
1721  * @param child The child to be added in custom chain
1722  * @param relative_child The relative object to position the child
1723  * @ingroup Widget
1724  */
1725 EAPI void
1726 elm_widget_focus_custom_chain_append(Evas_Object *obj,
1727                                      Evas_Object *child,
1728                                      Evas_Object *relative_child)
1729 {
1730    API_ENTRY return;
1731    EINA_SAFETY_ON_NULL_RETURN(child);
1732
1733    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1734
1735    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1736                                        _elm_object_focus_chain_del_cb, sd);
1737
1738    if (!relative_child)
1739      sd->focus_chain = eina_list_append(sd->focus_chain, child);
1740    else
1741      sd->focus_chain = eina_list_append_relative(sd->focus_chain,
1742                                                  child, relative_child);
1743 }
1744
1745 /**
1746  * @internal
1747  *
1748  * Prepend object to custom focus chain.
1749  *
1750  * @note If relative_child equal to NULL or not in custom chain, the object
1751  * will be added in begin.
1752  *
1753  * @note On focus cycle, only will be evaluated children of this container.
1754  *
1755  * @param obj The container widget
1756  * @param child The child to be added in custom chain
1757  * @param relative_child The relative object to position the child
1758  * @ingroup Widget
1759  */
1760 EAPI void
1761 elm_widget_focus_custom_chain_prepend(Evas_Object *obj,
1762                                       Evas_Object *child,
1763                                       Evas_Object *relative_child)
1764 {
1765    API_ENTRY return;
1766    EINA_SAFETY_ON_NULL_RETURN(child);
1767
1768    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1769
1770    evas_object_event_callback_del_full(child, EVAS_CALLBACK_DEL,
1771                                        _elm_object_focus_chain_del_cb, sd);
1772
1773    if (!relative_child)
1774      sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1775    else
1776      sd->focus_chain = eina_list_prepend_relative(sd->focus_chain,
1777                                                   child, relative_child);
1778 }
1779
1780 /**
1781  * @internal
1782  *
1783  * Give focus to next object in object tree.
1784  *
1785  * Give focus to next object in focus chain of one object sub-tree.
1786  * If the last object of chain already have focus, the focus will go to the
1787  * first object of chain.
1788  *
1789  * @param obj The widget root of sub-tree
1790  * @param dir Direction to cycle the focus
1791  *
1792  * @ingroup Widget
1793  */
1794 EAPI void
1795 elm_widget_focus_cycle(Evas_Object *obj,
1796                        Elm_Focus_Direction dir)
1797 {
1798    Evas_Object *target = NULL;
1799    if (!_elm_widget_is(obj))
1800      return;
1801    elm_widget_focus_next_get(obj, dir, &target);
1802    if (target)
1803      {
1804         /* access */
1805         if (_elm_config->access_mode && _elm_access_read_mode_get())
1806           {
1807              _elm_access_highlight_set(target);
1808              _elm_widget_focus_region_show(target);
1809           }
1810         else elm_widget_focus_steal(target);
1811      }
1812 }
1813
1814 /**
1815  * @internal
1816  *
1817  * Give focus to near object(in object tree) in one direction.
1818  *
1819  * Give focus to near object(in object tree) in direction of current
1820  * focused object.  If none focusable object in given direction or
1821  * none focused object in object tree, the focus will not change.
1822  *
1823  * @param obj The reference widget
1824  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
1825  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
1826  * @return EINA_TRUE if focus is moved.
1827  *
1828  * @ingroup Widget
1829  */
1830 EAPI Eina_Bool
1831 elm_widget_focus_direction_go(Evas_Object *obj,
1832                               double degree)
1833 {
1834    Evas_Object *target = NULL;
1835    Evas_Object *current_focused = NULL;
1836    double weight = 0.0;
1837
1838    if (!_elm_widget_is(obj)) return EINA_FALSE;
1839    if (!elm_widget_focus_get(obj)) return EINA_FALSE;
1840
1841    current_focused = elm_widget_focused_object_get(obj);
1842
1843    if (elm_widget_focus_direction_get
1844          (obj, current_focused, degree, &target, &weight))
1845      {
1846         elm_widget_focus_steal(target);
1847         return EINA_TRUE;
1848      }
1849    return EINA_FALSE;
1850 }
1851
1852 static double
1853 _direction_weight_get(const Evas_Object *obj1,
1854                       const Evas_Object *obj2,
1855                       double degree)
1856 {
1857    Evas_Coord obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2;
1858    double x1, yy1, x2, yy2, xx1, yyy1, xx2, yyy2;
1859    double ax, ay, cx, cy;
1860    double weight = -1.0, g = 0.0;
1861
1862    if (obj1 == obj2) return 0.0;
1863
1864    degree -= 90.0;
1865    while (degree >= 360.0)
1866      degree -= 360.0;
1867    while (degree < 0.0)
1868      degree += 360.0;
1869
1870    evas_object_geometry_get(obj1, &obj_x1, &obj_y1, &w1, &h1);
1871    cx = obj_x1 + (w1 / 2.0);
1872    cy = obj_y1 + (h1 / 2.0);
1873    evas_object_geometry_get(obj2, &obj_x2, &obj_y2, &w2, &h2);
1874
1875    /* For overlapping cases. */
1876    if (ELM_RECTS_INTERSECT(obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2))
1877      return 0.0;
1878
1879    /* Change all points to relative one. */
1880    x1 = obj_x1 - cx;
1881    xx1 = x1 + w1;
1882    yy1 = obj_y1 - cy;
1883    yyy1 = yy1 + h1;
1884    x2 = obj_x2 - cx;
1885    xx2 = x2 + w2;
1886    yy2 = obj_y2 - cy;
1887    yyy2 = yy2 + h2;
1888
1889    /* Get crossing points (ax, ay) between obj1 and a line extending
1890     * to the direction of current degree. */
1891    if (degree == 0.0)
1892      {
1893         ax = xx1;
1894         ay = 0.0;
1895      }
1896    else if (degree == 90.0)
1897      {
1898         ax = 0.0;
1899         ay = yyy1;
1900      }
1901    else if (degree == 180.0)
1902      {
1903         ax = x1;
1904         ay = 0.0;
1905      }
1906    else if (degree == 270.0)
1907      {
1908         ax = 0.0;
1909         ay = yy1;
1910      }
1911    else
1912      {
1913         g = tan(degree * (M_PI / 180.0));
1914         if ((degree > 0.0) && (degree < 90.0))
1915           {
1916              ay = g * xx1;
1917              if (ay <= yyy1) ax = xx1;
1918              else
1919                {
1920                   ax = yyy1 / g;
1921                   ay = yyy1;
1922                }
1923           }
1924         else if ((degree > 90.0) && (degree < 180.0))
1925           {
1926              ay = g * x1;
1927              if (ay <= yyy1) ax = x1;
1928              else
1929                {
1930                   ax = yyy1 / g;
1931                   ay = yyy1;
1932                }
1933           }
1934         else if ((degree > 180.0) && (degree < 270.0))
1935           {
1936              ay = g * x1;
1937              if (ay >= yy1) ax = x1;
1938              else
1939                {
1940                   ax = yy1 / g;
1941                   ay = yy1;
1942                }
1943           }
1944         else
1945           {
1946              ay = g * xx1;
1947              if (ay >= yy1) ax = xx1;
1948              else
1949                {
1950                   ax = yy1 / g;
1951                   ay = yy1;
1952                }
1953           }
1954      }
1955
1956    /* Filter obj2, if it is not in the specific derection. */
1957    int i = 0;
1958    double rx[4] = {0.0, 0.0, 0.0, 0.0}, ry[4] = {0.0, 0.0, 0.0, 0.0};
1959    double t1, t2, u1, v1, u2, v2;
1960
1961    if ((degree == 45.0) || (degree == 225.0) || (degree == 135.0) ||
1962        (degree == 315.0))
1963      {
1964         u1 = 1.0;
1965         v1 = 0.0;
1966         u2 = 0.0;
1967         v2 = 1.0;
1968      }
1969    else
1970      {
1971         double g2 = tan((degree + 45.0) * (M_PI / 180.0));
1972         u1 = (-1.0 * g2);
1973         u2 = (1.0 / g2);
1974         v1 = v2 = 1.0;
1975      }
1976    t1 = (u1 * ax) + (v1 * ay);
1977    t2 = (u2 * ax) + (v2 * ay);
1978
1979 #define _R(x) (int)((x + 0.05) * 10.0)
1980
1981    if ((_R(t1 * ((u1 * x2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * x2) +
1982                                                             (v2 * yy2))) > 0))
1983      {
1984         rx[i] = x2;
1985         ry[i++] = yy2;
1986      }
1987    if ((_R(t1 * ((u1 * x2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * x2) +
1988                                                              (v2 * yyy2))) > 0))
1989      {
1990         rx[i] = x2;
1991         ry[i++] = yyy2;
1992      }
1993    if ((_R(t1 * ((u1 * xx2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * xx2) +
1994                                                              (v2 * yy2))) > 0))
1995      {
1996         rx[i] = xx2;
1997         ry[i++] = yy2;
1998      }
1999    if ((_R(t1 * ((u1 * xx2) + (v1 * yyy2))) > 0) &&
2000        (_R(t2 * ((u2 * xx2) + (v2 * yyy2))) > 0))
2001      {
2002         rx[i] = xx2;
2003         ry[i++] = yyy2;
2004      }
2005    if (i == 0)
2006      {
2007         if (degree == 0.0)
2008           {
2009              if ((_R(xx2) < 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0;
2010           }
2011         else if (degree == 90.0)
2012           {
2013              if ((_R(yyy2) < 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0;
2014           }
2015         else if (degree == 180.0)
2016           {
2017              if ((_R(x2) > 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0;
2018           }
2019         else if (degree == 270.0)
2020           {
2021              if ((_R(yy2) > 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0;
2022           }
2023         else
2024           {
2025              if ((_R(g * x2) >= _R(yy2)) && (_R((g * x2)) <= _R(yyy2)))
2026                {
2027                   if (!((_R(ax * x2) > 0) && (_R(ay * (g * x2)) > 0)))
2028                     return 0.0;
2029                }
2030              else if ((_R(g * xx2) >= _R(yy2)) && (_R((g * xx2)) <= _R(yyy2)))
2031                {
2032                   if (!((_R(ax * xx2) > 0) && (_R(ay * (g * xx2)) > 0)))
2033                     return 0.0;
2034                }
2035              else if ((_R((1.0 / g) * yy2) >= _R(xx2)) && (_R((1.0 / g) * yy2)
2036                                                            <= _R(xx2)))
2037                {
2038                   if (!((_R(ax * ((1.0 / g) * yy2)) > 0)
2039                         && (_R(ay * yy2) > 0)))
2040                     return 0.0;
2041                }
2042              else if ((_R((1.0 / g) * yyy2) >= _R(xx2)) &&
2043                       (_R((1.0 / g) * yyy2) <= _R(xx2)))
2044                {
2045                   if (!((_R(ax * ((1.0 / g) * yyy2)) > 0)
2046                         && (_R(ay * yyy2) > 0))) return 0.0;
2047                }
2048              else return 0.0;
2049           }
2050      }
2051
2052    /* Calculate the weight for obj2. */
2053    if (degree == 0.0)
2054      {
2055         if (_R(xx1) > _R(x2)) weight = -1.0;
2056         else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1)))
2057           weight = (x2 - xx1) * (x2 - xx1);
2058         else if (_R(yy2) > 0)
2059           weight = ((x2 - xx1) * (x2 - xx1)) + (yy2 * yy2);
2060         else if (_R(yyy2) < 0)
2061           weight = ((x2 - xx1) * (x2 - xx1)) + (yyy2 * yyy2);
2062         else weight = (x2 - xx1) * (x2 - xx1);
2063      }
2064    else if (degree == 90.0)
2065      {
2066         if (_R(yyy1) > _R(yy2)) weight = -1.0;
2067         else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1)))
2068           weight = (yy2 - yyy1) * (yy2 - yyy1);
2069         else if (_R(x2) > 0)
2070           weight = (x2 * x2) + ((yy2 - yyy1) * (yy2 - yyy1));
2071         else if (_R(xx2) < 0)
2072           weight = (xx2 * xx2) + ((yy2 - yyy1) * (yy2 - yyy1));
2073         else weight = (yy2 - yyy1) * (yy2 - yyy1);
2074      }
2075    else if (degree == 180.0)
2076      {
2077         if (_R(x1) < _R(xx2)) weight = -1.0;
2078         else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1)))
2079           weight = (x1 - xx2) * (x1 - xx2);
2080         else if (_R(yy2) > 0)
2081           weight = ((x1 - xx2) * (x1 - xx2)) + (yy2 * yy2);
2082         else if (_R(yyy2) < 0)
2083           weight = ((x1 - xx2) * (x1 - xx2)) + (yyy2 * yyy2);
2084         else weight = (x1 - xx2) * (x1 - xx2);
2085      }
2086    else if (degree == 270.0)
2087      {
2088         if (_R(yy1) < _R(yyy2)) weight = -1.0;
2089         else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1)))
2090           weight = (yy1 - yyy2) * (yy1 - yyy2);
2091         else if (_R(x2) > 0)
2092           weight = (x2 * x2) + ((yy1 - yyy2) * (yy1 - yyy2));
2093         else if (_R(xx2) < 0)
2094           weight = (xx2 * xx2) + ((yy1 - yyy2) * (yy1 - yyy2));
2095         else weight = (yy1 - yyy2) * (yy1 - yyy2);
2096      }
2097    else
2098      {
2099         int j = 0, k = 0;
2100         double sx[4] = {0.0, 0.0, 0.0, 0.0}, sy[4] = {0.0, 0.0, 0.0, 0.0};
2101         double t_weight[4] = {-1.0, -1.0, -1.0, -1.0};
2102         if ((_R(g * x2) >= _R(yy2)) && (_R(g * x2) <= _R(yyy2)))
2103           {
2104              sx[j] = x2;
2105              sy[j] = g * x2;
2106              t_weight[j++] = ((ax - x2) * (ax - x2)) +
2107                ((ay - (g * x2)) * (ay - (g * x2)));
2108           }
2109         if ((_R(g * xx2) >= _R(yy2)) && (_R(g * xx2) <= _R(yyy2)))
2110           {
2111              sx[j] = xx2;
2112              sy[j] = g * xx2;
2113              t_weight[j++] = ((ax - xx2) * (ax - xx2)) +
2114                ((ay - (g * xx2)) * (ay - (g * xx2)));
2115           }
2116         if ((_R((1.0 / g) * yy2) >= _R(x2)) && (_R((1.0 / g) * yy2) <= _R(xx2)))
2117           {
2118              sx[j] = (1.0 / g) * yy2;
2119              sy[j] = yy2;
2120              t_weight[j++] =
2121                ((ax - ((1.0 / g) * yy2)) * (ax - ((1.0 / g) * yy2))) +
2122                ((ay - yy2) * (ay - yy2));
2123           }
2124         if ((_R((1.0 / g) * yyy2) >= _R(x2)) && (_R((1.0 / g) * yyy2)
2125                                                  <= _R(xx2)))
2126           {
2127              sx[j] = (1.0 / g) * yyy2;
2128              sy[j] = yyy2;
2129              t_weight[j++] =
2130                ((ax - ((1.0 / g) * yyy2)) * (ax - ((1.0 / g) * yyy2))) +
2131                ((ay - yyy2) * (ay - yyy2));
2132           }
2133
2134         if ((j > 2) || ((j == 2) && ((_R(sx[0]) != _R(sx[1])) ||
2135                                      (_R(sy[0]) != _R(sy[1])))))
2136           {
2137              for (; k < j; k++)
2138                {
2139                   if (_R(t_weight[k]) == 0) return -1.0;
2140                   if ((1 / weight) < (1 / t_weight[k])) weight = t_weight[k];
2141                }
2142           }
2143         else
2144           {
2145              for (; k < i; k++)
2146                {
2147                   double ccx, ccy, t1_weight, x_diff, y_diff;
2148                   ccx = ((1.0 / g) * rx[k] + ry[k]) / (g + (1.0 / g));
2149                   ccy = g * ccx;
2150                   x_diff = rx[k] - ccx;
2151                   if (x_diff < 0) x_diff *= -1.0;
2152                   y_diff = ry[k] - ccy;
2153                   if (y_diff < 0) y_diff *= -1.0;
2154                   t1_weight =
2155                     (((ax - ccx) * (ax - ccx)) + ((ay - ccy) * (ay - ccy))) +
2156                     ((x_diff * x_diff * x_diff) + (y_diff * y_diff * y_diff));
2157                   if ((_R(t1_weight) != 0) && ((1 / weight) < (1 / t1_weight)))
2158                     weight = t1_weight;
2159                }
2160           }
2161      }
2162    /* Return the current object's weight. */
2163    if (weight == -1.0) return 0.0;
2164    if (_R(weight) == 0) return -1.0;
2165
2166 #undef _R
2167
2168    return 1.0 / weight;
2169 }
2170
2171 /**
2172  * @internal
2173  *
2174  * Get near object in one direction of base object.
2175  *
2176  * Get near object(in the object sub-tree) in one direction of
2177  * base object. Return the near object by reference.
2178  * By initializing weight, you can filter objects locating far
2179  * from base object. If object is in the specific direction,
2180  * weight is (1/(distance^2)). If object is not exactly in one
2181  * direction, some penalty will be added.
2182  *
2183  * @param obj The widget root of sub-tree
2184  * @param base The base object of the direction
2185  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2186  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2187  * @param direction The near object in one direction
2188  * @param weight The weight is bigger when the object is located near
2189  * @return EINA_TRUE if near object is updated.
2190  *
2191  * @ingroup Widget
2192  */
2193 EAPI Eina_Bool
2194 elm_widget_focus_direction_get(const Evas_Object *obj,
2195                                const Evas_Object *base,
2196                                double degree,
2197                                Evas_Object **direction,
2198                                double *weight)
2199 {
2200    double c_weight;
2201
2202    API_ENTRY return EINA_FALSE;
2203
2204    /* -1 means the best was already decided. Don't need any more searching. */
2205    if (!direction || !weight || !base || (obj == base))
2206      return EINA_FALSE;
2207
2208    /* Ignore if disabled */
2209    if ((!evas_object_visible_get(obj))
2210        || (elm_widget_disabled_get(obj))
2211        || (elm_widget_tree_unfocusable_get(obj)))
2212      return EINA_FALSE;
2213
2214    if (!sd->api) return EINA_FALSE;
2215
2216    /* Try use hook */
2217    if (_elm_widget_focus_direction_manager_is(obj))
2218      return sd->api->focus_direction(obj, base, degree, direction, weight);
2219
2220    if (!elm_widget_can_focus_get(obj) || elm_widget_focus_get(obj))
2221      return EINA_FALSE;
2222
2223    c_weight = _direction_weight_get(base, obj, degree);
2224    if ((c_weight == -1.0) ||
2225        ((c_weight != 0.0) && (*weight != -1.0) &&
2226         ((int)(*weight * 1000000) <= (int)(c_weight * 1000000))))
2227      {
2228         if ((int)(*weight * 1000000) == (int)(c_weight * 1000000))
2229           {
2230              Elm_Widget_Smart_Data *sd1 =
2231                evas_object_smart_data_get(*direction);
2232              if (sd1)
2233                {
2234                   if (sd->focus_order <= sd1->focus_order)
2235                     return EINA_FALSE;
2236                }
2237           }
2238         *direction = (Evas_Object *)obj;
2239         *weight = c_weight;
2240         return EINA_TRUE;
2241      }
2242    return EINA_FALSE;
2243 }
2244
2245 /**
2246  * @internal
2247  *
2248  * Get near object in one direction of base object in list.
2249  *
2250  * Get near object in one direction of base object in the specific
2251  * object list. Return the near object by reference.
2252  * By initializing weight, you can filter objects locating far
2253  * from base object. If object is in the specific direction,
2254  * weight is (1/(distance^2)). If object is not exactly in one
2255  * direction, some penalty will be added.
2256  *
2257  * @param obj The widget root of sub-tree
2258  * @param base The base object of the direction
2259  * @param items list with ordered objects
2260  * @param list_data_get function to get the object from one item of list
2261  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2262  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2263  * @param direction The near object in one direction
2264  * @param weight The weight is bigger when the object is located near
2265  * @return EINA_TRUE if near object is updated.
2266  *
2267  * @ingroup Widget
2268  */
2269 EAPI Eina_Bool
2270 elm_widget_focus_list_direction_get(const Evas_Object *obj,
2271                                     const Evas_Object *base,
2272                                     const Eina_List *items,
2273                                     void *(*list_data_get)(const Eina_List *l),
2274                                     double degree,
2275                                     Evas_Object **direction,
2276                                     double *weight)
2277 {
2278    API_ENTRY return EINA_FALSE;
2279    if (!direction || !weight || !base || !items)
2280      return EINA_FALSE;
2281
2282    const Eina_List *l = items;
2283    Evas_Object *current_best = *direction;
2284
2285    for (; l; l = eina_list_next(l))
2286      {
2287         Evas_Object *cur = list_data_get(l);
2288         elm_widget_focus_direction_get(cur, base, degree, direction, weight);
2289      }
2290    if (current_best != *direction)
2291      return EINA_TRUE;
2292    else
2293      return EINA_FALSE;
2294 }
2295
2296 /**
2297  * @internal
2298  *
2299  * Get next object in focus chain of object tree.
2300  *
2301  * Get next object in focus chain of one object sub-tree.
2302  * Return the next object by reference. If don't have any candidate to receive
2303  * focus before chain end, the first candidate will be returned.
2304  *
2305  * @param obj The widget root of sub-tree
2306  * @param dir Direction os focus chain
2307  * @param next The next object in focus chain
2308  * @return EINA_TRUE if don't need focus chain restart/loop back
2309  *         to use 'next' obj.
2310  *
2311  * @ingroup Widget
2312  */
2313 EAPI Eina_Bool
2314 elm_widget_focus_next_get(const Evas_Object *obj,
2315                           Elm_Focus_Direction dir,
2316                           Evas_Object **next)
2317 {
2318    if (!next)
2319      return EINA_FALSE;
2320    *next = NULL;
2321
2322    API_ENTRY return EINA_FALSE;
2323
2324    /* Ignore if disabled */
2325    if ((!evas_object_visible_get(obj))
2326        || (elm_widget_disabled_get(obj))
2327        || (elm_widget_tree_unfocusable_get(obj)))
2328      return EINA_FALSE;
2329
2330    if (!sd->api) return EINA_FALSE;
2331
2332    /* Try use hook */
2333    if (_elm_widget_focus_chain_manager_is(obj))
2334      {
2335         Eina_Bool ret;
2336         ret = sd->api->focus_next(obj, dir, next);
2337         if (!ret && elm_widget_focus_get(obj))
2338           {
2339              Evas_Object *o = NULL;
2340              if (dir == ELM_FOCUS_PREVIOUS)
2341                o = sd->focus_previous;
2342              else if (dir == ELM_FOCUS_NEXT)
2343                o = sd->focus_next;
2344              else if (dir == ELM_FOCUS_UP)
2345                o = sd->focus_up;
2346              else if (dir == ELM_FOCUS_DOWN)
2347                o = sd->focus_down;
2348              else if (dir == ELM_FOCUS_RIGHT)
2349                o = sd->focus_right;
2350              else if (dir == ELM_FOCUS_LEFT)
2351                o = sd->focus_left;
2352
2353              if (o)
2354                {
2355                   *next = o;
2356                   return EINA_TRUE;
2357                }
2358           }
2359         else
2360           return ret;
2361      }
2362
2363    if (!elm_widget_can_focus_get(obj))
2364      return EINA_FALSE;
2365
2366    /* focusable object but does not have access info */
2367    if (_elm_config->access_mode)
2368      {
2369         if (!_elm_access_object_get(obj)) return EINA_FALSE;
2370      }
2371
2372    if (elm_widget_focus_get(obj))
2373      {
2374         if (dir == ELM_FOCUS_PREVIOUS)
2375           *next = sd->focus_previous;
2376         else if (dir == ELM_FOCUS_NEXT)
2377           *next = sd->focus_next;
2378         else if (dir == ELM_FOCUS_UP)
2379           *next = sd->focus_up;
2380         else if (dir == ELM_FOCUS_DOWN)
2381           *next = sd->focus_down;
2382         else if (dir == ELM_FOCUS_RIGHT)
2383           *next = sd->focus_right;
2384         else if (dir == ELM_FOCUS_LEFT)
2385           *next = sd->focus_left;
2386
2387         if (*next)
2388           return EINA_TRUE;
2389      }
2390    /* Return */
2391    *next = (Evas_Object *)obj;
2392    return !ELM_WIDGET_FOCUS_GET(obj);
2393 }
2394
2395 /**
2396  * @internal
2397  *
2398  * Get next object in focus chain of object tree in list.
2399  *
2400  * Get next object in focus chain of one object sub-tree ordered by one list.
2401  * Return the next object by reference. If don't have any candidate to receive
2402  * focus before list end, the first candidate will be returned.
2403  *
2404  * @param obj The widget root of sub-tree
2405  * @param dir Direction os focus chain
2406  * @param items list with ordered objects
2407  * @param list_data_get function to get the object from one item of list
2408  * @param next The next object in focus chain
2409  * @return EINA_TRUE if don't need focus chain restart/loop back
2410  *         to use 'next' obj.
2411  *
2412  * @ingroup Widget
2413  */
2414 EAPI Eina_Bool
2415 elm_widget_focus_list_next_get(const Evas_Object *obj,
2416                                const Eina_List *items,
2417                                void *(*list_data_get)(const Eina_List *list),
2418                                Elm_Focus_Direction dir,
2419                                Evas_Object **next)
2420 {
2421    Eina_List *(*list_next)(const Eina_List *list) = NULL;
2422    Evas_Object *focused_object = NULL;
2423
2424    if (!next)
2425      return EINA_FALSE;
2426    *next = NULL;
2427
2428    if (!_elm_widget_is(obj))
2429      return EINA_FALSE;
2430
2431    if (!items)
2432      return EINA_FALSE;
2433
2434    /* When Up, Down, Right, or Left, try direction_get first. */
2435    focused_object = elm_widget_focused_object_get(obj);
2436    if (focused_object)
2437      {
2438         if((dir == ELM_FOCUS_UP)
2439            || (dir == ELM_FOCUS_DOWN)
2440            || (dir == ELM_FOCUS_RIGHT)
2441            || (dir == ELM_FOCUS_LEFT))
2442           {
2443              *next = elm_widget_focus_next_object_get(focused_object, dir);
2444              if (*next)
2445                return EINA_TRUE;
2446              else
2447                {
2448                   Evas_Object *n;
2449                   double degree;
2450                   double weight;
2451
2452                   if (dir == ELM_FOCUS_UP) degree = 0.0;
2453                   else if (dir == ELM_FOCUS_DOWN) degree = 180.0;
2454                   else if (dir == ELM_FOCUS_RIGHT) degree = 90.0;
2455                   else if (dir == ELM_FOCUS_LEFT) degree = 270.0;
2456
2457                   if (elm_widget_focus_list_direction_get(obj, focused_object,
2458                                                           items, list_data_get,
2459                                                           degree, &n, &weight))
2460                     {
2461                        *next = n;
2462                        return EINA_TRUE;
2463                     }
2464                }
2465           }
2466      }
2467
2468    /* Direction */
2469    if (dir == ELM_FOCUS_PREVIOUS)
2470      {
2471         items = eina_list_last(items);
2472         list_next = eina_list_prev;
2473      }
2474    else if ((dir == ELM_FOCUS_NEXT)
2475             || (dir == ELM_FOCUS_UP)
2476             || (dir == ELM_FOCUS_DOWN)
2477             || (dir == ELM_FOCUS_RIGHT)
2478             || (dir == ELM_FOCUS_LEFT))
2479      list_next = eina_list_next;
2480    else
2481      return EINA_FALSE;
2482
2483    const Eina_List *l = items;
2484
2485    /* Recovery last focused sub item */
2486    if (ELM_WIDGET_FOCUS_GET(obj))
2487      {
2488         for (; l; l = list_next(l))
2489           {
2490              Evas_Object *cur = list_data_get(l);
2491              if (ELM_WIDGET_FOCUS_GET(cur)) break;
2492           }
2493
2494          /* Focused object, but no focused sub item */
2495          if (!l) l = items;
2496      }
2497
2498    const Eina_List *start = l;
2499    Evas_Object *to_focus = NULL;
2500
2501    /* Interate sub items */
2502    /* Go to end of list */
2503    for (; l; l = list_next(l))
2504      {
2505         Evas_Object *tmp = NULL;
2506         Evas_Object *cur = list_data_get(l);
2507
2508         if (elm_widget_parent_get(cur) != obj)
2509           continue;
2510
2511         /* Try Focus cycle in subitem */
2512         if (elm_widget_focus_next_get(cur, dir, &tmp))
2513           {
2514              *next = tmp;
2515              return EINA_TRUE;
2516           }
2517         else if ((dir == ELM_FOCUS_UP)
2518                  || (dir == ELM_FOCUS_DOWN)
2519                  || (dir == ELM_FOCUS_RIGHT)
2520                  || (dir == ELM_FOCUS_LEFT))
2521           {
2522              if (tmp && elm_widget_focus_get(cur))
2523                {
2524                   *next = tmp;
2525                   return EINA_FALSE;
2526                }
2527           }
2528         else if ((tmp) && (!to_focus))
2529           to_focus = tmp;
2530      }
2531
2532    l = items;
2533
2534    /* Get First possible */
2535    for (; l != start; l = list_next(l))
2536      {
2537         Evas_Object *tmp = NULL;
2538         Evas_Object *cur = list_data_get(l);
2539
2540         if (elm_widget_parent_get(cur) != obj)
2541           continue;
2542
2543         /* Try Focus cycle in subitem */
2544         elm_widget_focus_next_get(cur, dir, &tmp);
2545         if (tmp)
2546           {
2547              *next = tmp;
2548              return EINA_FALSE;
2549           }
2550      }
2551
2552    *next = to_focus;
2553    return EINA_FALSE;
2554 }
2555
2556
2557 /**
2558  * @internal
2559  *
2560  * Get next object which was set with specific focus direction.
2561  *
2562  * Get next object which was set by elm_widget_focus_next_object_set
2563  * with specific focus directioin.
2564  *
2565  * @param obj The widget
2566  * @param dir Direction of focus
2567  * @return Widget which was registered with sepecific focus direction.
2568  *
2569  * @ingroup Widget
2570  */
2571 EAPI Evas_Object *
2572 elm_widget_focus_next_object_get(const Evas_Object *obj, Elm_Focus_Direction dir)
2573 {
2574    API_ENTRY return NULL;
2575
2576    if (dir == ELM_FOCUS_PREVIOUS)
2577      return sd->focus_previous;
2578    else if (dir == ELM_FOCUS_NEXT)
2579      return sd->focus_next;
2580    else if (dir == ELM_FOCUS_UP)
2581      return sd->focus_up;
2582    else if (dir == ELM_FOCUS_DOWN)
2583      return sd->focus_down;
2584    else if (dir == ELM_FOCUS_RIGHT)
2585      return sd->focus_right;
2586    else if (dir == ELM_FOCUS_LEFT)
2587      return sd->focus_left;
2588
2589    return NULL;
2590 }
2591
2592 /**
2593  * @internal
2594  *
2595  * Set next object with specific focus direction.
2596  *
2597  * When a widget is set with specific focus direction, this widget will be
2598  * the first candidate when finding the next focus object.
2599  * Focus next object can be registered with six directions that are previous,
2600  * next, up, down, right, and left.
2601  *
2602  * @param obj The widget
2603  * @param next Next focus object
2604  * @param dir Direction of focus
2605  *
2606  * @ingroup Widget
2607  */
2608 EAPI void
2609 elm_widget_focus_next_object_set(Evas_Object *obj, Evas_Object *next, Elm_Focus_Direction dir)
2610 {
2611    API_ENTRY return;
2612
2613    if (dir == ELM_FOCUS_PREVIOUS)
2614      sd->focus_previous = next;
2615    else if (dir == ELM_FOCUS_NEXT)
2616      sd->focus_next = next;
2617    else if (dir == ELM_FOCUS_UP)
2618      sd->focus_up = next;
2619    else if (dir == ELM_FOCUS_DOWN)
2620      sd->focus_down = next;
2621    else if (dir == ELM_FOCUS_RIGHT)
2622      sd->focus_right = next;
2623    else if (dir == ELM_FOCUS_LEFT)
2624      sd->focus_left = next;
2625 }
2626
2627
2628 EAPI Eina_Bool
2629 elm_widget_highlight_get(const Evas_Object *obj)
2630 {
2631    API_ENTRY return EINA_FALSE;
2632    return sd->highlighted;
2633 }
2634
2635 EAPI void
2636 elm_widget_parent_highlight_set(Evas_Object *obj,
2637                                 Eina_Bool highlighted)
2638 {
2639    API_ENTRY return;
2640
2641    highlighted = !!highlighted;
2642
2643    Evas_Object *o = elm_widget_parent_get(obj);
2644
2645    if (o) elm_widget_parent_highlight_set(o, highlighted);
2646
2647    sd->highlighted = highlighted;
2648 }
2649
2650 EAPI void
2651 elm_widget_signal_emit(Evas_Object *obj,
2652                        const char *emission,
2653                        const char *source)
2654 {
2655    API_ENTRY return;
2656
2657    if (evas_object_smart_type_check(obj, "elm_layout"))
2658      elm_layout_signal_emit(obj, emission, source);
2659    else if (evas_object_smart_type_check(obj, "elm_icon"))
2660      {
2661         WRN("Deprecated function. This functionality on icon objects"
2662             " will be dropped on a next release.");
2663         _elm_icon_signal_emit(obj, emission, source);
2664      }
2665 }
2666
2667 EAPI void
2668 elm_widget_signal_callback_add(Evas_Object *obj,
2669                                const char *emission,
2670                                const char *source,
2671                                Edje_Signal_Cb func,
2672                                void *data)
2673 {
2674    API_ENTRY return;
2675
2676    EINA_SAFETY_ON_NULL_RETURN(func);
2677
2678    if (evas_object_smart_type_check(obj, "elm_layout"))
2679      elm_layout_signal_callback_add(obj, emission, source, func, data);
2680    else if (evas_object_smart_type_check(obj, "elm_icon"))
2681      {
2682         WRN("Deprecated function. This functionality on icon objects"
2683             " will be dropped on a next release.");
2684
2685         _elm_icon_signal_callback_add(obj, emission, source, func, data);
2686      }
2687 }
2688
2689 EAPI void *
2690 elm_widget_signal_callback_del(Evas_Object *obj,
2691                                const char *emission,
2692                                const char *source,
2693                                Edje_Signal_Cb func)
2694 {
2695    void *data = NULL;
2696
2697    API_ENTRY return NULL;
2698
2699    if (evas_object_smart_type_check(obj, "elm_layout"))
2700      data = elm_layout_signal_callback_del(obj, emission, source, func);
2701    else if (evas_object_smart_type_check(obj, "elm_icon"))
2702      {
2703         WRN("Deprecated function. This functionality on icon objects"
2704             " will be dropped on a next release.");
2705
2706         data = _elm_icon_signal_callback_del(obj, emission, source, func);
2707      }
2708
2709    return data;
2710 }
2711
2712 EAPI void
2713 elm_widget_focus_set(Evas_Object *obj,
2714                      int first)
2715 {
2716    API_ENTRY return;
2717
2718    if (!sd->api) return;
2719
2720    if (!sd->focused)
2721      {
2722         focus_order++;
2723         sd->focus_order = focus_order;
2724         sd->focused = EINA_TRUE;
2725         sd->api->on_focus(obj);
2726      }
2727
2728    if (first)
2729      {
2730         if ((_is_focusable(sd->resize_obj)) &&
2731             (!elm_widget_disabled_get(sd->resize_obj)))
2732           {
2733              elm_widget_focus_set(sd->resize_obj, first);
2734           }
2735         else
2736           {
2737              const Eina_List *l;
2738              Evas_Object *child;
2739
2740              EINA_LIST_FOREACH(sd->subobjs, l, child)
2741                {
2742                   if ((_is_focusable(child)) &&
2743                       (!elm_widget_disabled_get(child)))
2744                     {
2745                        elm_widget_focus_set(child, first);
2746                        break;
2747                     }
2748                }
2749           }
2750      }
2751    else
2752      {
2753         const Eina_List *l;
2754         Evas_Object *child;
2755
2756         EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
2757           {
2758              if ((_is_focusable(child)) &&
2759                  (!elm_widget_disabled_get(child)))
2760                {
2761                   elm_widget_focus_set(child, first);
2762                   break;
2763                }
2764           }
2765         if (!l)
2766           {
2767              if ((_is_focusable(sd->resize_obj)) &&
2768                  (!elm_widget_disabled_get(sd->resize_obj)))
2769                {
2770                   elm_widget_focus_set(sd->resize_obj, first);
2771                }
2772           }
2773      }
2774 }
2775
2776 EAPI Evas_Object *
2777 elm_widget_parent_get(const Evas_Object *obj)
2778 {
2779    API_ENTRY return NULL;
2780    return sd->parent_obj;
2781 }
2782
2783 EAPI void
2784 elm_widget_focused_object_clear(Evas_Object *obj)
2785 {
2786    API_ENTRY return;
2787
2788    if (!sd->api) return;
2789
2790    if (!sd->focused) return;
2791
2792    // FIXME: evas_object_ref/unref is temporary code to fix logical issue.
2793    // After Eo is applied to elementary, remove these.
2794    evas_object_ref(obj);
2795    if (sd->resize_obj && elm_widget_focus_get(sd->resize_obj))
2796      elm_widget_focused_object_clear(sd->resize_obj);
2797    else
2798      {
2799         const Eina_List *l;
2800         Evas_Object *child;
2801         EINA_LIST_FOREACH(sd->subobjs, l, child)
2802           {
2803              if (elm_widget_focus_get(child))
2804                {
2805                   elm_widget_focused_object_clear(child);
2806                   break;
2807                }
2808           }
2809      }
2810    sd->focused = EINA_FALSE;
2811    sd->api->on_focus(obj);
2812    evas_object_unref(obj);
2813 }
2814
2815 EAPI void
2816 elm_widget_focus_steal(Evas_Object *obj)
2817 {
2818    Evas_Object *parent, *parent2, *o;
2819    API_ENTRY return;
2820
2821    if (sd->focused) return;
2822    if (sd->disabled) return;
2823    if (!sd->can_focus) return;
2824    if (sd->tree_unfocusable) return;
2825    parent = obj;
2826    for (;; )
2827      {
2828         o = elm_widget_parent_get(parent);
2829         if (!o) break;
2830         sd = evas_object_smart_data_get(o);
2831         if (sd->disabled || sd->tree_unfocusable) return;
2832         if (sd->focused) break;
2833         parent = o;
2834      }
2835    if ((!elm_widget_parent_get(parent)) &&
2836        (!elm_widget_parent2_get(parent)))
2837      elm_widget_focused_object_clear(parent);
2838    else
2839      {
2840         parent2 = elm_widget_parent_get(parent);
2841         if (!parent2) parent2 = elm_widget_parent2_get(parent);
2842         parent = parent2;
2843         sd = evas_object_smart_data_get(parent);
2844         if (sd)
2845           {
2846              if ((sd->resize_obj) && (elm_widget_focus_get(sd->resize_obj)))
2847                elm_widget_focused_object_clear(sd->resize_obj);
2848              else
2849                {
2850                   const Eina_List *l;
2851                   Evas_Object *child;
2852                   EINA_LIST_FOREACH(sd->subobjs, l, child)
2853                     {
2854                        if (elm_widget_focus_get(child))
2855                          {
2856                             elm_widget_focused_object_clear(child);
2857                             break;
2858                          }
2859                     }
2860                }
2861           }
2862      }
2863    _parent_focus(obj);
2864    _elm_widget_focus_region_show(obj);
2865    return;
2866 }
2867
2868 EAPI void
2869 elm_widget_focus_restore(Evas_Object *obj)
2870 {
2871    Evas_Object *newest = NULL;
2872    unsigned int newest_focus_order = 0;
2873    API_ENTRY return;
2874
2875    newest = elm_widget_newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
2876    if (newest)
2877      {
2878         elm_object_focus_set(newest, EINA_FALSE);
2879         elm_object_focus_set(newest, EINA_TRUE);
2880      }
2881 }
2882
2883 void
2884 _elm_widget_top_win_focused_set(Evas_Object *obj,
2885                                 Eina_Bool top_win_focused)
2886 {
2887    const Eina_List *l;
2888    Evas_Object *child;
2889    API_ENTRY return;
2890
2891    if (sd->top_win_focused == top_win_focused) return;
2892    if (sd->resize_obj)
2893      _elm_widget_top_win_focused_set(sd->resize_obj, top_win_focused);
2894    EINA_LIST_FOREACH(sd->subobjs, l, child)
2895      {
2896         _elm_widget_top_win_focused_set(child, top_win_focused);
2897      }
2898    sd->top_win_focused = top_win_focused;
2899 }
2900
2901 Eina_Bool
2902 _elm_widget_top_win_focused_get(const Evas_Object *obj)
2903 {
2904    API_ENTRY return EINA_FALSE;
2905    return sd->top_win_focused;
2906 }
2907
2908 EAPI void
2909 elm_widget_disabled_set(Evas_Object *obj,
2910                         Eina_Bool disabled)
2911 {
2912    API_ENTRY return;
2913
2914    if (sd->disabled == disabled) return;
2915    sd->disabled = !!disabled;
2916    elm_widget_focus_disabled_handle(obj);
2917    if (!sd->api) return;
2918    sd->api->disable(obj);
2919 }
2920
2921 EAPI Eina_Bool
2922 elm_widget_disabled_get(const Evas_Object *obj)
2923 {
2924    API_ENTRY return 0;
2925    return sd->disabled;
2926 }
2927
2928 EAPI void
2929 elm_widget_show_region_set(Evas_Object *obj,
2930                            Evas_Coord x,
2931                            Evas_Coord y,
2932                            Evas_Coord w,
2933                            Evas_Coord h,
2934                            Eina_Bool forceshow)
2935 {
2936    Evas_Object *parent_obj, *child_obj;
2937    Evas_Coord px, py, cx, cy;
2938
2939    API_ENTRY return;
2940
2941    evas_smart_objects_calculate(evas_object_evas_get(obj));
2942    ELM_WIDGET_CHECK_OR_RETURN(obj);
2943
2944    if (!forceshow && (x == sd->rx) && (y == sd->ry) &&
2945        (w == sd->rw) && (h == sd->rh)) return;
2946
2947    sd->rx = x;
2948    sd->ry = y;
2949    sd->rw = w;
2950    sd->rh = h;
2951    if (sd->on_show_region)
2952      sd->on_show_region
2953        (sd->on_show_region_data, obj);
2954
2955    do
2956      {
2957         parent_obj = sd->parent_obj;
2958         child_obj = sd->obj;
2959         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
2960         sd = evas_object_smart_data_get(parent_obj);
2961         if (!sd) break;
2962
2963         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
2964         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
2965
2966         x += (cx - px);
2967         y += (cy - py);
2968         sd->rx = x;
2969         sd->ry = y;
2970         sd->rw = w;
2971         sd->rh = h;
2972
2973         if (sd->on_show_region)
2974           {
2975              sd->on_show_region
2976                (sd->on_show_region_data, parent_obj);
2977           }
2978      }
2979    while (parent_obj);
2980 }
2981
2982 EAPI void
2983 elm_widget_show_region_get(const Evas_Object *obj,
2984                            Evas_Coord *x,
2985                            Evas_Coord *y,
2986                            Evas_Coord *w,
2987                            Evas_Coord *h)
2988 {
2989    API_ENTRY return;
2990    if (x) *x = sd->rx;
2991    if (y) *y = sd->ry;
2992    if (w) *w = sd->rw;
2993    if (h) *h = sd->rh;
2994 }
2995
2996 /**
2997  * @internal
2998  *
2999  * Get the focus region of the given widget.
3000  *
3001  * @return show region or not
3002  * (@c EINA_TRUE = show region/@c EINA_FALSE = do not show region). Default is @c EINA_FALSE.
3003  *
3004  * The focus region is the area of a widget that should brought into the
3005  * visible area when the widget is focused. Mostly used to show the part of
3006  * an entry where the cursor is, for example. The area returned is relative
3007  * to the object @p obj.
3008  *
3009  * @param obj The widget object
3010  * @param x Where to store the x coordinate of the area
3011  * @param y Where to store the y coordinate of the area
3012  * @param w Where to store the width of the area
3013  * @param h Where to store the height of the area
3014  *
3015  * @ingroup Widget
3016  */
3017 EAPI Eina_Bool
3018 elm_widget_focus_region_get(const Evas_Object *obj,
3019                             Evas_Coord *x,
3020                             Evas_Coord *y,
3021                             Evas_Coord *w,
3022                             Evas_Coord *h)
3023 {
3024    API_ENTRY return EINA_FALSE;
3025    if (!sd->api->on_focus_region(obj, x, y, w, h))
3026      {
3027         evas_object_geometry_get(obj, NULL, NULL, w, h);
3028         if (x) *x = 0;
3029         if (y) *y = 0;
3030      }
3031    return EINA_TRUE;
3032 }
3033
3034 EAPI Eina_List *
3035 elm_widget_scrollable_children_get(Evas_Object *obj)
3036 {
3037    Eina_List *l, *ret = NULL;
3038    Evas_Object *child;
3039
3040    API_ENTRY return NULL;
3041
3042    EINA_LIST_FOREACH(sd->subobjs, l, child)
3043      {
3044         if (_elm_scrollable_is(child))
3045           ret = eina_list_append(ret, child);
3046      }
3047
3048    return ret;
3049 }
3050
3051 EAPI void
3052 elm_widget_scroll_hold_push(Evas_Object *obj)
3053 {
3054    API_ENTRY return;
3055    sd->scroll_hold++;
3056    if (sd->scroll_hold == 1)
3057      {
3058         if (_elm_scrollable_is(obj))
3059           {
3060              ELM_SCROLLABLE_IFACE_GET(obj, s_iface);
3061              s_iface->hold_set(obj, EINA_TRUE);
3062           }
3063         else
3064           {
3065              Eina_List *scr_children, *l;
3066              Evas_Object *child;
3067
3068              scr_children = elm_widget_scrollable_children_get(obj);
3069              EINA_LIST_FOREACH(scr_children, l, child)
3070                {
3071                   ELM_SCROLLABLE_IFACE_GET(child, s_iface);
3072                   s_iface->hold_set(child, EINA_TRUE);
3073                }
3074              eina_list_free(scr_children);
3075           }
3076      }
3077    if (sd->parent_obj) elm_widget_scroll_hold_push(sd->parent_obj);
3078    // FIXME: on delete/reparent hold pop
3079 }
3080
3081 EAPI void
3082 elm_widget_scroll_hold_pop(Evas_Object *obj)
3083 {
3084    API_ENTRY return;
3085    sd->scroll_hold--;
3086    if (!sd->scroll_hold)
3087      {
3088         if (_elm_scrollable_is(obj))
3089           {
3090              ELM_SCROLLABLE_IFACE_GET(obj, s_iface);
3091              s_iface->hold_set(obj, EINA_FALSE);
3092           }
3093         else
3094           {
3095              Eina_List *scr_children, *l;
3096              Evas_Object *child;
3097
3098              scr_children = elm_widget_scrollable_children_get(obj);
3099              EINA_LIST_FOREACH(scr_children, l, child)
3100                {
3101                   ELM_SCROLLABLE_IFACE_GET(child, s_iface);
3102                   s_iface->hold_set(child, EINA_FALSE);
3103                }
3104              eina_list_free(scr_children);
3105           }
3106      }
3107    if (sd->parent_obj) elm_widget_scroll_hold_pop(sd->parent_obj);
3108    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
3109 }
3110
3111 EAPI int
3112 elm_widget_scroll_hold_get(const Evas_Object *obj)
3113 {
3114    API_ENTRY return 0;
3115    return sd->scroll_hold;
3116 }
3117
3118 EAPI void
3119 elm_widget_scroll_freeze_push(Evas_Object *obj)
3120 {
3121    API_ENTRY return;
3122    sd->scroll_freeze++;
3123    if (sd->scroll_freeze == 1)
3124      {
3125         if (_elm_scrollable_is(obj))
3126           {
3127              ELM_SCROLLABLE_IFACE_GET(obj, s_iface);
3128              s_iface->freeze_set(obj, EINA_TRUE);
3129           }
3130         else
3131           {
3132              Eina_List *scr_children, *l;
3133              Evas_Object *child;
3134
3135              scr_children = elm_widget_scrollable_children_get(obj);
3136              EINA_LIST_FOREACH(scr_children, l, child)
3137                {
3138                   ELM_SCROLLABLE_IFACE_GET(child, s_iface);
3139                   s_iface->freeze_set(child, EINA_TRUE);
3140                }
3141              eina_list_free(scr_children);
3142           }
3143      }
3144    if (sd->parent_obj) elm_widget_scroll_freeze_push(sd->parent_obj);
3145    // FIXME: on delete/reparent freeze pop
3146 }
3147
3148 EAPI void
3149 elm_widget_scroll_freeze_pop(Evas_Object *obj)
3150 {
3151    API_ENTRY return;
3152    sd->scroll_freeze--;
3153    if (!sd->scroll_freeze)
3154      {
3155         if (_elm_scrollable_is(obj))
3156           {
3157              ELM_SCROLLABLE_IFACE_GET(obj, s_iface);
3158              s_iface->freeze_set(obj, EINA_FALSE);
3159           }
3160         else
3161           {
3162              Eina_List *scr_children, *l;
3163              Evas_Object *child;
3164
3165              scr_children = elm_widget_scrollable_children_get(obj);
3166              EINA_LIST_FOREACH(scr_children, l, child)
3167                {
3168                   ELM_SCROLLABLE_IFACE_GET(child, s_iface);
3169                   s_iface->freeze_set(child, EINA_FALSE);
3170                }
3171              eina_list_free(scr_children);
3172           }
3173      }
3174    if (sd->parent_obj) elm_widget_scroll_freeze_pop(sd->parent_obj);
3175    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
3176 }
3177
3178 EAPI int
3179 elm_widget_scroll_freeze_get(const Evas_Object *obj)
3180 {
3181    API_ENTRY return 0;
3182    return sd->scroll_freeze;
3183 }
3184
3185 EAPI void
3186 elm_widget_scale_set(Evas_Object *obj,
3187                      double scale)
3188 {
3189    API_ENTRY return;
3190    if (scale <= 0.0) scale = 0.0;
3191    if (sd->scale != scale)
3192      {
3193         sd->scale = scale;
3194         elm_widget_theme(obj);
3195      }
3196 }
3197
3198 EAPI double
3199 elm_widget_scale_get(const Evas_Object *obj)
3200 {
3201    API_ENTRY return 1.0;
3202    // FIXME: save walking up the tree by storing/caching parent scale
3203    if (sd->scale == 0.0)
3204      {
3205         if (sd->parent_obj)
3206           return elm_widget_scale_get(sd->parent_obj);
3207         else
3208           return 1.0;
3209      }
3210    return sd->scale;
3211 }
3212
3213 EAPI void
3214 elm_widget_theme_set(Evas_Object *obj,
3215                      Elm_Theme *th)
3216 {
3217    API_ENTRY return;
3218    if (sd->theme != th)
3219      {
3220         if (sd->theme) elm_theme_free(sd->theme);
3221         sd->theme = th;
3222         if (th) th->ref++;
3223         elm_widget_theme(obj);
3224      }
3225 }
3226
3227 EAPI void
3228 elm_widget_text_part_set(Evas_Object *obj,
3229                          const char *part,
3230                          const char *label)
3231 {
3232    API_ENTRY return;
3233
3234    if (evas_object_smart_type_check(obj, "elm_layout"))
3235      elm_layout_text_set(obj, part, label);
3236 }
3237
3238 EAPI const char *
3239 elm_widget_text_part_get(const Evas_Object *obj,
3240                          const char *part)
3241 {
3242    API_ENTRY return NULL;
3243
3244    if (evas_object_smart_type_check(obj, "elm_layout"))
3245      return elm_layout_text_get(obj, part);
3246
3247    return NULL;
3248 }
3249
3250 static Eina_Bool
3251 _translatable_part_text_set(Eina_List **translate_strings, const char *part, const char *domain, const char *label)
3252 {
3253    const char *str;
3254    Eina_List *t, *l;
3255    Elm_Translate_String_Data *ts = NULL;
3256
3257    t = *translate_strings;
3258    str = eina_stringshare_add(part);
3259    EINA_LIST_FOREACH(t, l, ts)
3260      {
3261         if (ts->id == str) break;
3262         else ts = NULL;
3263      }
3264
3265    if (!ts && !label)
3266      eina_stringshare_del(str);
3267    else if (!ts)
3268      {
3269         ts = malloc(sizeof(Elm_Translate_String_Data));
3270         if (!ts) return EINA_FALSE;
3271
3272         ts->id = str;
3273         ts->domain = eina_stringshare_add(domain);
3274         ts->string = eina_stringshare_add(label);
3275         t = eina_list_append(t, ts);
3276      }
3277    else
3278      {
3279         if (label)
3280           {
3281              eina_stringshare_replace(&ts->domain, domain);
3282              eina_stringshare_replace(&ts->string, label);
3283           }
3284         else
3285           {
3286              t = eina_list_remove_list(t, l);
3287              eina_stringshare_del(ts->id);
3288              eina_stringshare_del(ts->domain);
3289              eina_stringshare_del(ts->string);
3290              free(ts);
3291           }
3292         eina_stringshare_del(str);
3293      }
3294
3295    *translate_strings = t;
3296    return EINA_TRUE;
3297 }
3298
3299 EAPI void
3300 elm_widget_domain_translatable_part_text_set(Evas_Object *obj,
3301                                              const char *part,
3302                                              const char *domain,
3303                                              const char *label)
3304 {
3305    API_ENTRY return;
3306
3307    if (!_translatable_part_text_set(&sd->translate_strings, part, domain,
3308                                     label)) return;
3309 #ifdef HAVE_GETTEXT
3310    if (label && label[0])
3311      label = dgettext(domain, label);
3312 #endif
3313    elm_widget_text_part_set(obj, part, label);
3314 }
3315
3316 static const char *
3317 _translatable_part_text_get(Eina_List *translate_strings, const char *part)
3318 {
3319    Elm_Translate_String_Data *ts;
3320    const char*ret = NULL, *str;
3321    Eina_List *l;
3322
3323    str = eina_stringshare_add(part);
3324    EINA_LIST_FOREACH(translate_strings, l, ts)
3325      if (ts->id == str)
3326        {
3327           ret = ts->string;
3328           break;
3329        }
3330    eina_stringshare_del(str);
3331
3332    return ret;
3333 }
3334
3335 EAPI const char *
3336 elm_widget_translatable_part_text_get(const Evas_Object *obj,
3337                                       const char *part)
3338 {
3339    API_ENTRY return NULL;
3340    return _translatable_part_text_get(sd->translate_strings, part);
3341 }
3342
3343 EAPI void
3344 elm_widget_translate(Evas_Object *obj)
3345 {
3346    const Eina_List *l;
3347    Evas_Object *child;
3348 #ifdef HAVE_GETTEXT
3349    Elm_Translate_String_Data *ts;
3350 #endif
3351
3352    API_ENTRY return;
3353
3354    EINA_LIST_FOREACH(sd->subobjs, l, child)
3355      elm_widget_translate(child);
3356    if (sd->resize_obj) elm_widget_translate(sd->resize_obj);
3357    if (sd->hover_obj) elm_widget_translate(sd->hover_obj);
3358    if (!sd->api) return;
3359    sd->api->translate(obj);
3360
3361 #ifdef HAVE_GETTEXT
3362    EINA_LIST_FOREACH(sd->translate_strings, l, ts)
3363      {
3364         const char *s = dgettext(ts->domain, ts->string);
3365         elm_widget_text_part_set(obj, ts->id, s);
3366      }
3367 #endif
3368 }
3369
3370 EAPI void
3371 elm_widget_content_part_set(Evas_Object *obj,
3372                             const char *part,
3373                             Evas_Object *content)
3374 {
3375    API_ENTRY return;
3376
3377    if (!sd->api) return;
3378    if (evas_object_smart_type_check(obj, "elm_container"))
3379      ELM_CONTAINER_CLASS(sd->api)->content_set(obj, part, content);
3380 }
3381
3382 EAPI Evas_Object *
3383 elm_widget_content_part_get(const Evas_Object *obj,
3384                             const char *part)
3385 {
3386    API_ENTRY return NULL;
3387
3388    if (!sd->api) return NULL;
3389
3390    if (evas_object_smart_type_check(obj, "elm_container"))
3391      return ELM_CONTAINER_CLASS(sd->api)->content_get(obj, part);
3392
3393    return NULL;
3394 }
3395
3396 EAPI Evas_Object *
3397 elm_widget_content_part_unset(Evas_Object *obj,
3398                               const char *part)
3399 {
3400    API_ENTRY return NULL;
3401
3402    if (!sd->api) return NULL;
3403    if (evas_object_smart_type_check(obj, "elm_container"))
3404      return ELM_CONTAINER_CLASS(sd->api)->content_unset(obj, part);
3405
3406    return NULL;
3407 }
3408
3409 EAPI void
3410 elm_widget_access_info_set(Evas_Object *obj,
3411                            const char *txt)
3412 {
3413    API_ENTRY return;
3414    if (sd->access_info) eina_stringshare_del(sd->access_info);
3415    if (!txt) sd->access_info = NULL;
3416    else sd->access_info = eina_stringshare_add(txt);
3417 }
3418
3419 EAPI const char *
3420 elm_widget_access_info_get(const Evas_Object *obj)
3421 {
3422    API_ENTRY return NULL;
3423    return sd->access_info;
3424 }
3425
3426 EAPI Elm_Theme *
3427 elm_widget_theme_get(const Evas_Object *obj)
3428 {
3429    API_ENTRY return NULL;
3430    if (!sd->theme)
3431      {
3432         if (sd->parent_obj)
3433           return elm_widget_theme_get(sd->parent_obj);
3434         else
3435           return NULL;
3436      }
3437    return sd->theme;
3438 }
3439
3440 EAPI Eina_Bool
3441 elm_widget_style_set(Evas_Object *obj,
3442                      const char *style)
3443 {
3444    API_ENTRY return EINA_FALSE;
3445
3446    if (eina_stringshare_replace(&sd->style, style))
3447      return elm_widget_theme(obj);
3448
3449    return EINA_TRUE;
3450 }
3451
3452 EAPI const char *
3453 elm_widget_style_get(const Evas_Object *obj)
3454 {
3455    API_ENTRY return NULL;
3456    if (sd->style) return sd->style;
3457    return "default";
3458 }
3459
3460 EAPI void
3461 elm_widget_tooltip_add(Evas_Object *obj,
3462                        Elm_Tooltip *tt)
3463 {
3464    API_ENTRY return;
3465    sd->tooltips = eina_list_append(sd->tooltips, tt);
3466 }
3467
3468 EAPI void
3469 elm_widget_tooltip_del(Evas_Object *obj,
3470                        Elm_Tooltip *tt)
3471 {
3472    API_ENTRY return;
3473    sd->tooltips = eina_list_remove(sd->tooltips, tt);
3474 }
3475
3476 EAPI void
3477 elm_widget_cursor_add(Evas_Object *obj,
3478                       Elm_Cursor *cur)
3479 {
3480    API_ENTRY return;
3481    sd->cursors = eina_list_append(sd->cursors, cur);
3482 }
3483
3484 EAPI void
3485 elm_widget_cursor_del(Evas_Object *obj,
3486                       Elm_Cursor *cur)
3487 {
3488    API_ENTRY return;
3489    sd->cursors = eina_list_remove(sd->cursors, cur);
3490 }
3491
3492 EAPI void
3493 elm_widget_drag_lock_x_set(Evas_Object *obj,
3494                            Eina_Bool lock)
3495 {
3496    API_ENTRY return;
3497    if (sd->drag_x_locked == lock) return;
3498    sd->drag_x_locked = lock;
3499    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
3500    else _propagate_x_drag_lock(obj, -1);
3501 }
3502
3503 EAPI void
3504 elm_widget_drag_lock_y_set(Evas_Object *obj,
3505                            Eina_Bool lock)
3506 {
3507    API_ENTRY return;
3508    if (sd->drag_y_locked == lock) return;
3509    sd->drag_y_locked = lock;
3510    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
3511    else _propagate_y_drag_lock(obj, -1);
3512 }
3513
3514 EAPI Eina_Bool
3515 elm_widget_drag_lock_x_get(const Evas_Object *obj)
3516 {
3517    API_ENTRY return EINA_FALSE;
3518    return sd->drag_x_locked;
3519 }
3520
3521 EAPI Eina_Bool
3522 elm_widget_drag_lock_y_get(const Evas_Object *obj)
3523 {
3524    API_ENTRY return EINA_FALSE;
3525    return sd->drag_y_locked;
3526 }
3527
3528 EAPI int
3529 elm_widget_drag_child_locked_x_get(const Evas_Object *obj)
3530 {
3531    API_ENTRY return 0;
3532    return sd->child_drag_x_locked;
3533 }
3534
3535 EAPI int
3536 elm_widget_drag_child_locked_y_get(const Evas_Object *obj)
3537 {
3538    API_ENTRY return 0;
3539    return sd->child_drag_y_locked;
3540 }
3541
3542 EAPI Eina_Bool
3543 elm_widget_theme_object_set(Evas_Object *obj,
3544                             Evas_Object *edj,
3545                             const char *wname,
3546                             const char *welement,
3547                             const char *wstyle)
3548 {
3549    API_ENTRY return EINA_FALSE;
3550    char buf[128];
3551
3552    if (!_elm_theme_object_set(obj, edj, wname, welement, wstyle))
3553      return EINA_FALSE;
3554
3555    if (sd->orient_mode != -1)
3556      {
3557
3558         snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
3559         elm_widget_signal_emit(obj, buf, "elm");
3560
3561      }
3562    return EINA_TRUE;
3563 }
3564
3565 EAPI Eina_Bool
3566 elm_widget_is_check(const Evas_Object *obj)
3567 {
3568    static int abort_on_warn = -1;
3569    if (elm_widget_is(obj))
3570      return EINA_TRUE;
3571
3572    ERR("Passing Object: %p.", obj);
3573    if (abort_on_warn == -1)
3574      {
3575         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
3576         else abort_on_warn = 0;
3577      }
3578    if (abort_on_warn == 1) abort();
3579    return EINA_FALSE;
3580 }
3581
3582 EAPI const char *
3583 elm_widget_type_get(const Evas_Object *obj)
3584 {
3585    API_ENTRY return NULL;
3586
3587    return evas_object_type_get(obj);
3588 }
3589
3590 EAPI Eina_Bool
3591 elm_widget_type_check(const Evas_Object *obj,
3592                       const char *type,
3593                       const char *func)
3594 {
3595    const char *provided, *expected = "(unknown)";
3596    static int abort_on_warn = -1;
3597
3598    provided = elm_widget_type_get(obj);
3599    /* TODO: eventually migrate to check_ptr version */
3600    if (evas_object_smart_type_check(obj, type)) return EINA_TRUE;
3601    if (type) expected = type;
3602    if ((!provided) || (!provided[0]))
3603      {
3604         provided = evas_object_type_get(obj);
3605         if ((!provided) || (!provided[0]))
3606           provided = "(unknown)";
3607      }
3608    ERR("Passing Object: %p in function: %s, of type: '%s' when expecting"
3609        " type: '%s'", obj, func, provided, expected);
3610    if (abort_on_warn == -1)
3611      {
3612         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
3613         else abort_on_warn = 0;
3614      }
3615    if (abort_on_warn == 1) abort();
3616    return EINA_FALSE;
3617 }
3618
3619 static Evas_Object *
3620 _widget_name_find(const Evas_Object *obj,
3621                   const char *name,
3622                   int recurse)
3623 {
3624    Eina_List *l;
3625    Evas_Object *child;
3626    const char *s;
3627    INTERNAL_ENTRY NULL;
3628
3629    if (!_elm_widget_is(obj)) return NULL;
3630    if (sd->resize_obj)
3631      {
3632         s = evas_object_name_get(sd->resize_obj);
3633         if ((s) && (!strcmp(s, name))) return sd->resize_obj;
3634         if ((recurse != 0) &&
3635             ((child = _widget_name_find(sd->resize_obj, name, recurse - 1))))
3636           return child;
3637      }
3638    EINA_LIST_FOREACH(sd->subobjs, l, child)
3639      {
3640         s = evas_object_name_get(child);
3641         if ((s) && (!strcmp(s, name))) return child;
3642         if ((recurse != 0) &&
3643             ((child = _widget_name_find(child, name, recurse - 1))))
3644           return child;
3645      }
3646    if (sd->hover_obj)
3647      {
3648         s = evas_object_name_get(sd->hover_obj);
3649         if ((s) && (!strcmp(s, name))) return sd->hover_obj;
3650         if ((recurse != 0) &&
3651             ((child = _widget_name_find(sd->hover_obj, name, recurse - 1))))
3652           return child;
3653      }
3654    return NULL;
3655 }
3656
3657 EAPI Evas_Object *
3658 elm_widget_name_find(const Evas_Object *obj,
3659                      const char *name,
3660                      int recurse)
3661 {
3662    API_ENTRY return NULL;
3663    if (!name) return NULL;
3664    return _widget_name_find(obj, name, recurse);
3665 }
3666
3667 EAPI void
3668 elm_widget_orientation_mode_disabled_set(Evas_Object *obj, Eina_Bool disabled)
3669 {
3670    int orient_mode = -1;
3671
3672    API_ENTRY return;
3673
3674    if (disabled && (sd->orient_mode == -1)) return;
3675    if (!disabled && (sd->orient_mode != -1)) return;
3676
3677    if (!disabled)
3678      {
3679         //Get current orient mode from it's parent otherwise, 0.
3680         sd->orient_mode = 0;
3681         ELM_WIDGET_DATA_GET(sd->parent_obj, sd_parent);
3682         if (!sd_parent) orient_mode = 0;
3683         else orient_mode = sd_parent->orient_mode;
3684      }
3685    elm_widget_orientation_set(obj, orient_mode);
3686 }
3687
3688 EAPI Eina_Bool
3689 elm_widget_orientation_mode_disabled_get(const Evas_Object *obj)
3690 {
3691    Eina_Bool ret;
3692
3693    API_ENTRY return EINA_FALSE;
3694
3695    if (sd->orient_mode == -1) ret = EINA_TRUE;
3696    else ret = EINA_FALSE;
3697    return ret;
3698 }
3699
3700 EAPI void
3701 elm_widget_orientation_set(Evas_Object *obj, int rotation)
3702 {
3703    Evas_Object *child;
3704    Eina_List *l;
3705
3706    API_ENTRY return;
3707
3708    if ((sd->orient_mode == rotation) || (sd->orient_mode == -1)) return;
3709
3710    sd->orient_mode = rotation;
3711
3712    EINA_LIST_FOREACH (sd->subobjs, l, child)
3713      elm_widget_orientation_set(child, rotation);
3714
3715    if (rotation != -1)
3716      {
3717         char buf[128];
3718         snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
3719         elm_widget_signal_emit(obj, buf, "elm");
3720      }
3721 }
3722
3723 /**
3724  * @internal
3725  *
3726  * Split string in words
3727  *
3728  * @param str Source string
3729  * @return List of const words
3730  *
3731  * @see elm_widget_stringlist_free()
3732  * @ingroup Widget
3733  */
3734 EAPI Eina_List *
3735 elm_widget_stringlist_get(const char *str)
3736 {
3737    Eina_List *list = NULL;
3738    const char *s, *b;
3739    if (!str) return NULL;
3740    for (b = s = str; 1; s++)
3741      {
3742         if ((*s == ' ') || (!*s))
3743           {
3744              char *t = malloc(s - b + 1);
3745              if (t)
3746                {
3747                   strncpy(t, b, s - b);
3748                   t[s - b] = 0;
3749                   list = eina_list_append(list, eina_stringshare_add(t));
3750                   free(t);
3751                }
3752              b = s + 1;
3753           }
3754         if (!*s) break;
3755      }
3756    return list;
3757 }
3758
3759 EAPI void
3760 elm_widget_stringlist_free(Eina_List *list)
3761 {
3762    const char *s;
3763    EINA_LIST_FREE (list, s)
3764      eina_stringshare_del(s);
3765 }
3766
3767 EAPI void
3768 elm_widget_focus_hide_handle(Evas_Object *obj)
3769 {
3770    if (!_elm_widget_is(obj))
3771      return;
3772    _if_focused_revert(obj, EINA_TRUE);
3773 }
3774
3775 EAPI void
3776 elm_widget_focus_mouse_up_handle(Evas_Object *obj)
3777 {
3778    Evas_Object *o = obj;
3779    do
3780      {
3781         if (_elm_widget_is(o)) break;
3782         o = evas_object_smart_parent_get(o);
3783      }
3784    while (o);
3785    if (!o) return;
3786    if (!_is_focusable(o)) return;
3787    elm_widget_focus_steal(o);
3788 }
3789
3790 EAPI void
3791 elm_widget_focus_tree_unfocusable_handle(Evas_Object *obj)
3792 {
3793    API_ENTRY return;
3794
3795    //FIXME: Need to check whether the object is unfocusable or not.
3796
3797    if (!elm_widget_parent_get(obj))
3798      elm_widget_focused_object_clear(obj);
3799    else
3800      _if_focused_revert(obj, EINA_TRUE);
3801 }
3802
3803 EAPI void
3804 elm_widget_focus_disabled_handle(Evas_Object *obj)
3805 {
3806    API_ENTRY return;
3807
3808    elm_widget_focus_tree_unfocusable_handle(obj);
3809 }
3810
3811 EAPI unsigned int
3812 elm_widget_focus_order_get(const Evas_Object *obj)
3813 {
3814    API_ENTRY return 0;
3815    return sd->focus_order;
3816 }
3817
3818 EAPI Evas_Object *
3819 elm_widget_newest_focus_order_get(const Evas_Object *obj,
3820                                   unsigned int *newest_focus_order,
3821                                   Eina_Bool can_focus_only)
3822 {
3823    const Eina_List *l;
3824    Evas_Object *child, *ret, *best;
3825
3826    API_ENTRY return NULL;
3827
3828    if (!evas_object_visible_get(obj)
3829        || (elm_widget_disabled_get(obj))
3830        || (elm_widget_tree_unfocusable_get(obj)))
3831      return NULL;
3832
3833    best = NULL;
3834    if (*newest_focus_order < sd->focus_order)
3835      {
3836         *newest_focus_order = sd->focus_order;
3837         best = (Evas_Object *)obj;
3838      }
3839    EINA_LIST_FOREACH(sd->subobjs, l, child)
3840      {
3841         ret = elm_widget_newest_focus_order_get
3842            (child, newest_focus_order, can_focus_only);
3843         if (!ret) continue;
3844         best = ret;
3845      }
3846    if (can_focus_only)
3847      {
3848         if ((!best) || (!elm_widget_can_focus_get(best)))
3849           return NULL;
3850      }
3851    return best;
3852 }
3853
3854 EAPI void
3855 elm_widget_activate(Evas_Object *obj, Elm_Activate act)
3856 {
3857    Evas_Object *parent;
3858    Eina_Bool ret;
3859
3860    API_ENTRY return;
3861
3862    ret = EINA_FALSE;
3863    if (sd->api->activate)
3864      ret = sd->api->activate(obj, act);
3865
3866    if (ret) return;
3867
3868    parent = elm_widget_parent_get(obj);
3869    if (parent)
3870      elm_widget_activate(parent, act);
3871
3872    return;
3873 }
3874
3875 /**
3876  * @internal
3877  *
3878  * Returns the widget's Evas_Display_Mode
3879  *
3880  * @param obj The widget.
3881  * @return Evas_Display_Mode of the object.
3882  *
3883  * @see elm_widget_display_mode_set().
3884  * @ingroup Widget
3885  **/
3886 EAPI Evas_Display_Mode
3887 elm_widget_display_mode_get(const Evas_Object *obj)
3888 {
3889    Evas_Display_Mode new_mode;
3890    Evas_Object *parent;
3891
3892    API_ENTRY return EVAS_DISPLAY_MODE_NONE;
3893
3894    new_mode = evas_object_size_hint_display_mode_get(obj);
3895    parent = elm_widget_parent_get(obj);
3896
3897    if ((new_mode == EVAS_DISPLAY_MODE_INHERIT) && parent)
3898      return elm_widget_display_mode_get(parent);
3899    return new_mode;
3900
3901 }
3902
3903 /**
3904  * @internal
3905  *
3906  * Sets the widget and child widget's Evas_Display_Mode.
3907  *
3908  * @param obj The widget.
3909  * @param dispmode Evas_Display_Mode to set widget's mode.
3910  *
3911  * Widgets are resized by several reasons.
3912  * Evas_Display_Mode can help for widgets to get one more reason of resize.
3913  * For example, elm conform widget resizes it's contents when keypad state changed.
3914  * After keypad showing, conform widget can change child's Evas_Display_Mode.
3915  * @ingroup Widget
3916  */
3917 EAPI void
3918 elm_widget_display_mode_set(Evas_Object *obj, Evas_Display_Mode dispmode)
3919 {
3920    Evas_Display_Mode child_mode;
3921    Evas_Object *child;
3922    Eina_List *l;
3923
3924    API_ENTRY return;
3925
3926    if (elm_widget_display_mode_get(obj) == dispmode) return;
3927    evas_object_size_hint_display_mode_set(obj, dispmode);
3928
3929    //TODO: Need to deal with EVAS_DISPLAY_MODE_INHERIT efficiently.
3930    EINA_LIST_FOREACH (sd->subobjs, l, child)
3931      {
3932         child_mode = evas_object_size_hint_display_mode_get(child);
3933         if (child_mode != EVAS_DISPLAY_MODE_DONT_CHANGE)
3934           {
3935              elm_widget_display_mode_set(child, dispmode);
3936           }
3937      }
3938
3939 }
3940
3941 // temporary code. should be removed after eo is applied.
3942 EAPI void
3943 _elm_widget_orient_signal_emit(Evas_Object *obj)
3944 {
3945    ELM_WIDGET_DATA_GET(obj, sd);
3946    char buf[128];
3947    if (sd->orient_mode > 0)
3948      {
3949         snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
3950         elm_widget_signal_emit(obj, buf, "elm");
3951      }
3952 }
3953
3954 /**
3955  * @internal
3956  *
3957  * Allocate a new Elm_Widget_Item-derived structure.
3958  *
3959  * The goal of this structure is to provide common ground for actions
3960  * that a widget item have, such as the owner widget, callback to
3961  * notify deletion, data pointer and maybe more.
3962  *
3963  * @param widget the owner widget that holds this item, must be an elm_widget!
3964  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
3965  *        be used to allocate memory.
3966  *
3967  * @return allocated memory that is already zeroed out, or NULL on errors.
3968  *
3969  * @see elm_widget_item_new() convenience macro.
3970  * @see elm_widget_item_del() to release memory.
3971  * @ingroup Widget
3972  */
3973 EAPI Elm_Widget_Item *
3974 _elm_widget_item_new(Evas_Object *widget,
3975                      size_t alloc_size)
3976 {
3977    if (!_elm_widget_is(widget))
3978      return NULL;
3979
3980    Elm_Widget_Item *item;
3981
3982    EINA_SAFETY_ON_TRUE_RETURN_VAL(alloc_size < sizeof(Elm_Widget_Item), NULL);
3983    EINA_SAFETY_ON_TRUE_RETURN_VAL(!_elm_widget_is(widget), NULL);
3984
3985    item = calloc(1, alloc_size);
3986    EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
3987
3988    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
3989    item->widget = widget;
3990    return item;
3991 }
3992
3993 EAPI void
3994 _elm_widget_item_free(Elm_Widget_Item *item)
3995 {
3996    Elm_Translate_String_Data *ts;
3997    Elm_Widget_Item_Signal_Data *wisd;
3998
3999    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4000
4001    if (item->del_func)
4002      item->del_func((void *)item->data, item->widget, item);
4003
4004    if (item->view)
4005      evas_object_del(item->view);
4006
4007    if (item->access_info)
4008      eina_stringshare_del(item->access_info);
4009
4010    EINA_LIST_FREE(item->signals, wisd)
4011      {
4012         eina_stringshare_del(wisd->emission);
4013         eina_stringshare_del(wisd->source);
4014         free(wisd);
4015      }
4016
4017    EINA_LIST_FREE(item->translate_strings, ts)
4018      {
4019         eina_stringshare_del(ts->id);
4020         eina_stringshare_del(ts->domain);
4021         eina_stringshare_del(ts->string);
4022         free(ts);
4023      }
4024
4025    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
4026    free(item);
4027 }
4028
4029 /**
4030  * @internal
4031  *
4032  * Releases widget item memory, calling back del_cb() if it exists.
4033  *
4034  * If there is a Elm_Widget_Item::del_cb, then it will be called prior
4035  * to memory release. Note that elm_widget_item_pre_notify_del() calls
4036  * this function and then unset it, thus being useful for 2 step
4037  * cleanup whenever the del_cb may use any of the data that must be
4038  * deleted from item.
4039  *
4040  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
4041  * is presented!
4042  *
4043  * @param item a valid #Elm_Widget_Item to be deleted.
4044  * @see elm_widget_item_del() convenience macro.
4045  * @ingroup Widget
4046  */
4047 EAPI void
4048 _elm_widget_item_del(Elm_Widget_Item *item)
4049 {
4050    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4051    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4052    item->on_deletion = EINA_TRUE;
4053
4054    //Widget item delete callback
4055    if (item->del_pre_func)
4056      {
4057         if (item->del_pre_func((Elm_Object_Item *)item))
4058           _elm_widget_item_free(item);
4059      }
4060    else
4061      _elm_widget_item_free(item);
4062  }
4063
4064 /**
4065  * @internal
4066  *
4067  * Set the function to notify to widgets when item is being deleted by user.
4068  *
4069  * @param item a valid #Elm_Widget_Item to be notified
4070  * @see elm_widget_item_del_pre_hook_set() convenience macro.
4071  * @ingroup Widget
4072  */
4073 EAPI void
4074 _elm_widget_item_del_pre_hook_set(Elm_Widget_Item *item,
4075                                   Elm_Widget_Del_Pre_Cb func)
4076 {
4077    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4078    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4079    item->del_pre_func = func;
4080 }
4081
4082 /**
4083  * @internal
4084  *
4085  * Notify object will be deleted without actually deleting it.
4086  *
4087  * This function will callback Elm_Widget_Item::del_cb if it is set
4088  * and then unset it so it is not called twice (ie: from
4089  * elm_widget_item_del()).
4090  *
4091  * @param item a valid #Elm_Widget_Item to be notified
4092  * @see elm_widget_item_pre_notify_del() convenience macro.
4093  * @ingroup Widget
4094  */
4095 EAPI void
4096 _elm_widget_item_pre_notify_del(Elm_Widget_Item *item)
4097 {
4098    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4099    if (!item->del_func) return;
4100    item->del_func((void *)item->data, item->widget, item);
4101    item->del_func = NULL;
4102 }
4103
4104 /**
4105  * @internal
4106  *
4107  * Set the function to notify when item is being deleted.
4108  *
4109  * This function will complain if there was a callback set already,
4110  * however it will set the new one.
4111  *
4112  * The callback will be called from elm_widget_item_pre_notify_del()
4113  * or elm_widget_item_del() will be called with:
4114  *   - data: the Elm_Widget_Item::data value.
4115  *   - obj: the Elm_Widget_Item::widget evas object.
4116  *   - event_info: the item being deleted.
4117  *
4118  * @param item a valid #Elm_Widget_Item to be notified
4119  * @see elm_widget_item_del_cb_set() convenience macro.
4120  * @ingroup Widget
4121  */
4122 EAPI void
4123 _elm_widget_item_del_cb_set(Elm_Widget_Item *item,
4124                             Evas_Smart_Cb func)
4125 {
4126    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4127    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4128
4129    if ((item->del_func) && (item->del_func != func))
4130      WRN("You're replacing a previously set del_cb %p of item %p with %p",
4131          item->del_func, item, func);
4132
4133    item->del_func = func;
4134 }
4135
4136 /**
4137  * @internal
4138  *
4139  * Retrieves owner widget of this item.
4140  *
4141  * @param item a valid #Elm_Widget_Item to get data from.
4142  * @return owner widget of this item.
4143  * @ingroup Widget
4144  */
4145 EAPI Evas_Object *
4146 _elm_widget_item_widget_get(const Elm_Widget_Item *item)
4147 {
4148    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4149    return item->widget;
4150 }
4151
4152 /**
4153  * @internal
4154  *
4155  * Set user-data in this item.
4156  *
4157  * User data may be used to identify this item or just store any
4158  * application data. It is automatically given as the first parameter
4159  * of the deletion notify callback.
4160  *
4161  * @param item a valid #Elm_Widget_Item to store data in.
4162  * @param data user data to store.
4163  * @see elm_widget_item_del_cb_set() convenience macro.
4164  * @ingroup Widget
4165  */
4166 EAPI void
4167 _elm_widget_item_data_set(Elm_Widget_Item *item,
4168                           const void *data)
4169 {
4170    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4171    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4172
4173    if ((item->data) && (item->data != data))
4174      DBG("Replacing item %p data %p with %p", item, item->data, data);
4175    item->data = data;
4176 }
4177
4178 /**
4179  * @internal
4180  *
4181  * Retrieves user-data of this item.
4182  *
4183  * @param item a valid #Elm_Widget_Item to get data from.
4184  * @see elm_widget_item_data_set()
4185  * @ingroup Widget
4186  */
4187 EAPI void *
4188 _elm_widget_item_data_get(const Elm_Widget_Item *item)
4189 {
4190    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4191    return (void *)item->data;
4192 }
4193
4194 EAPI void
4195 _elm_widget_item_disabled_set(Elm_Widget_Item *item,
4196                               Eina_Bool disabled)
4197 {
4198    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4199    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4200
4201    if (item->disabled == disabled) return;
4202    item->disabled = !!disabled;
4203    if (item->disable_func) item->disable_func(item);
4204 }
4205
4206 EAPI Eina_Bool
4207 _elm_widget_item_disabled_get(const Elm_Widget_Item *item)
4208 {
4209    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4210    return item->disabled;
4211 }
4212
4213 EAPI void
4214 _elm_widget_item_disable_hook_set(Elm_Widget_Item *item,
4215                                   Elm_Widget_Disable_Cb func)
4216 {
4217    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4218    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4219
4220    item->disable_func = func;
4221 }
4222
4223 EAPI void
4224 _elm_widget_item_domain_translatable_part_text_set(Elm_Widget_Item *item,
4225                                                    const char *part,
4226                                                    const char *domain,
4227                                                    const char *label)
4228 {
4229    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4230
4231    if (!_translatable_part_text_set(&item->translate_strings, part, domain,
4232                                     label)) return;
4233 #ifdef HAVE_GETTEXT
4234    if (label && label[0])
4235      label = dgettext(domain, label);
4236 #endif
4237    _elm_widget_item_part_text_set(item, part, label);
4238 }
4239
4240 EAPI const char *
4241 _elm_widget_item_translatable_part_text_get(const Elm_Widget_Item *item,
4242                                             const char *part)
4243 {
4244    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4245    return _translatable_part_text_get(item->translate_strings, part);
4246 }
4247
4248 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
4249
4250 struct _Elm_Widget_Item_Tooltip
4251 {
4252    Elm_Widget_Item            *item;
4253    Elm_Tooltip_Item_Content_Cb func;
4254    Evas_Smart_Cb               del_cb;
4255    const void                 *data;
4256 };
4257
4258 static Evas_Object *
4259 _elm_widget_item_tooltip_label_create(void *data,
4260                                       Evas_Object *obj __UNUSED__,
4261                                       Evas_Object *tooltip,
4262                                       void *item __UNUSED__)
4263 {
4264    Evas_Object *label = elm_label_add(tooltip);
4265    if (!label)
4266      return NULL;
4267    elm_object_style_set(label, "tooltip");
4268    elm_object_text_set(label, data);
4269    return label;
4270 }
4271
4272 static Evas_Object *
4273 _elm_widget_item_tooltip_trans_label_create(void *data,
4274                                             Evas_Object *obj __UNUSED__,
4275                                             Evas_Object *tooltip,
4276                                             void *item __UNUSED__)
4277 {
4278    Evas_Object *label = elm_label_add(tooltip);
4279    if (!label)
4280      return NULL;
4281    elm_object_style_set(label, "tooltip");
4282    elm_object_translatable_text_set(label, data);
4283    return label;
4284 }
4285
4286 static void
4287 _elm_widget_item_tooltip_label_del_cb(void *data,
4288                                       Evas_Object *obj __UNUSED__,
4289                                       void *event_info __UNUSED__)
4290 {
4291    eina_stringshare_del(data);
4292 }
4293
4294 /**
4295  * @internal
4296  *
4297  * Set the text to be shown in the widget item.
4298  *
4299  * @param item Target item
4300  * @param text The text to set in the content
4301  *
4302  * Setup the text as tooltip to object. The item can have only one tooltip,
4303  * so any previous tooltip data is removed.
4304  *
4305  * @ingroup Widget
4306  */
4307 EAPI void
4308 _elm_widget_item_tooltip_text_set(Elm_Widget_Item *item,
4309                                   const char *text)
4310 {
4311    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4312    EINA_SAFETY_ON_NULL_RETURN(text);
4313    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4314
4315    text = eina_stringshare_add(text);
4316    _elm_widget_item_tooltip_content_cb_set
4317      (item, _elm_widget_item_tooltip_label_create, text,
4318      _elm_widget_item_tooltip_label_del_cb);
4319 }
4320
4321 EAPI void
4322 _elm_widget_item_tooltip_translatable_text_set(Elm_Widget_Item *item,
4323                                                const char *text)
4324 {
4325    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4326    EINA_SAFETY_ON_NULL_RETURN(text);
4327    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4328
4329    text = eina_stringshare_add(text);
4330    _elm_widget_item_tooltip_content_cb_set
4331      (item, _elm_widget_item_tooltip_trans_label_create, text,
4332      _elm_widget_item_tooltip_label_del_cb);
4333 }
4334
4335 static Evas_Object *
4336 _elm_widget_item_tooltip_create(void *data,
4337                                 Evas_Object *obj,
4338                                 Evas_Object *tooltip)
4339 {
4340    Elm_Widget_Item_Tooltip *wit = data;
4341    return wit->func((void *)wit->data, obj, tooltip, wit->item);
4342 }
4343
4344 static void
4345 _elm_widget_item_tooltip_del_cb(void *data,
4346                                 Evas_Object *obj,
4347                                 void *event_info __UNUSED__)
4348 {
4349    Elm_Widget_Item_Tooltip *wit = data;
4350    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item);
4351    free(wit);
4352 }
4353
4354 /**
4355  * @internal
4356  *
4357  * Set the content to be shown in the tooltip item
4358  *
4359  * Setup the tooltip to item. The item can have only one tooltip,
4360  * so any previous tooltip data is removed. @p func(with @p data) will
4361  * be called every time that need show the tooltip and it should
4362  * return a valid Evas_Object. This object is then managed fully by
4363  * tooltip system and is deleted when the tooltip is gone.
4364  *
4365  * @param item the widget item being attached a tooltip.
4366  * @param func the function used to create the tooltip contents.
4367  * @param data what to provide to @a func as callback data/context.
4368  * @param del_cb called when data is not needed anymore, either when
4369  *        another callback replaces @func, the tooltip is unset with
4370  *        elm_widget_item_tooltip_unset() or the owner @a item
4371  *        dies. This callback receives as the first parameter the
4372  *        given @a data, and @c event_info is the item.
4373  *
4374  * @ingroup Widget
4375  */
4376 EAPI void
4377 _elm_widget_item_tooltip_content_cb_set(Elm_Widget_Item *item,
4378                                         Elm_Tooltip_Item_Content_Cb func,
4379                                         const void *data,
4380                                         Evas_Smart_Cb del_cb)
4381 {
4382    Elm_Widget_Item_Tooltip *wit;
4383
4384    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
4385    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4386    if (!func)
4387      {
4388         _elm_widget_item_tooltip_unset(item);
4389         return;
4390      }
4391
4392    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
4393    if (!wit) goto error;
4394    wit->item = item;
4395    wit->func = func;
4396    wit->data = data;
4397    wit->del_cb = del_cb;
4398
4399    elm_object_sub_tooltip_content_cb_set
4400      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
4401      _elm_widget_item_tooltip_del_cb);
4402
4403    return;
4404
4405 error_noitem:
4406    if (del_cb) del_cb((void *)data, NULL, item);
4407    return;
4408 error:
4409    if (del_cb) del_cb((void *)data, item->widget, item);
4410 }
4411
4412 /**
4413  * @internal
4414  *
4415  * Unset tooltip from item
4416  *
4417  * @param item widget item to remove previously set tooltip.
4418  *
4419  * Remove tooltip from item. The callback provided as del_cb to
4420  * elm_widget_item_tooltip_content_cb_set() will be called to notify
4421  * it is not used anymore.
4422  *
4423  * @see elm_widget_item_tooltip_content_cb_set()
4424  *
4425  * @ingroup Widget
4426  */
4427 EAPI void
4428 _elm_widget_item_tooltip_unset(Elm_Widget_Item *item)
4429 {
4430    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4431    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4432
4433    elm_object_tooltip_unset(item->view);
4434 }
4435
4436 /**
4437  * @internal
4438  *
4439  * Sets a different style for this item tooltip.
4440  *
4441  * @note before you set a style you should define a tooltip with
4442  *       elm_widget_item_tooltip_content_cb_set() or
4443  *       elm_widget_item_tooltip_text_set()
4444  *
4445  * @param item widget item with tooltip already set.
4446  * @param style the theme style to use (default, transparent, ...)
4447  *
4448  * @ingroup Widget
4449  */
4450 EAPI void
4451 _elm_widget_item_tooltip_style_set(Elm_Widget_Item *item,
4452                                    const char *style)
4453 {
4454    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4455    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4456
4457    elm_object_tooltip_style_set(item->view, style);
4458 }
4459
4460 EAPI Eina_Bool
4461 _elm_widget_item_tooltip_window_mode_set(Elm_Widget_Item *item,
4462                                          Eina_Bool disable)
4463 {
4464    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4465    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
4466
4467    return elm_object_tooltip_window_mode_set(item->view, disable);
4468 }
4469
4470 EAPI Eina_Bool
4471 _elm_widget_item_tooltip_window_mode_get(const Elm_Widget_Item *item)
4472 {
4473    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4474    return elm_object_tooltip_window_mode_get(item->view);
4475 }
4476
4477 /**
4478  * @internal
4479  *
4480  * Get the style for this item tooltip.
4481  *
4482  * @param item widget item with tooltip already set.
4483  * @return style the theme style in use, defaults to "default". If the
4484  *         object does not have a tooltip set, then NULL is returned.
4485  *
4486  * @ingroup Widget
4487  */
4488 EAPI const char *
4489 _elm_widget_item_tooltip_style_get(const Elm_Widget_Item *item)
4490 {
4491    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4492    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4493
4494    return elm_object_tooltip_style_get(item->view);
4495 }
4496
4497 EAPI void
4498 _elm_widget_item_cursor_set(Elm_Widget_Item *item,
4499                             const char *cursor)
4500 {
4501    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4502    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4503
4504    elm_object_sub_cursor_set(item->view, item->widget, cursor);
4505 }
4506
4507 EAPI const char *
4508 _elm_widget_item_cursor_get(const Elm_Widget_Item *item)
4509 {
4510    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4511    return elm_object_cursor_get(item->view);
4512 }
4513
4514 EAPI void
4515 _elm_widget_item_cursor_unset(Elm_Widget_Item *item)
4516 {
4517    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4518    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4519
4520    elm_object_cursor_unset(item->view);
4521 }
4522
4523 /**
4524  * @internal
4525  *
4526  * Sets a different style for this item cursor.
4527  *
4528  * @note before you set a style you should define a cursor with
4529  *       elm_widget_item_cursor_set()
4530  *
4531  * @param item widget item with cursor already set.
4532  * @param style the theme style to use (default, transparent, ...)
4533  *
4534  * @ingroup Widget
4535  */
4536 EAPI void
4537 _elm_widget_item_cursor_style_set(Elm_Widget_Item *item,
4538                                   const char *style)
4539 {
4540    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4541    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4542
4543    elm_object_cursor_style_set(item->view, style);
4544 }
4545
4546 /**
4547  * @internal
4548  *
4549  * Get the style for this item cursor.
4550  *
4551  * @param item widget item with cursor already set.
4552  * @return style the theme style in use, defaults to "default". If the
4553  *         object does not have a cursor set, then NULL is returned.
4554  *
4555  * @ingroup Widget
4556  */
4557 EAPI const char *
4558 _elm_widget_item_cursor_style_get(const Elm_Widget_Item *item)
4559 {
4560    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4561    return elm_object_cursor_style_get(item->view);
4562 }
4563
4564 /**
4565  * @internal
4566  *
4567  * Set if the cursor set should be searched on the theme or should use
4568  * the provided by the engine, only.
4569  *
4570  * @note before you set if should look on theme you should define a cursor
4571  * with elm_object_cursor_set(). By default it will only look for cursors
4572  * provided by the engine.
4573  *
4574  * @param item widget item with cursor already set.
4575  * @param engine_only boolean to define it cursors should be looked only
4576  * between the provided by the engine or searched on widget's theme as well.
4577  *
4578  * @ingroup Widget
4579  */
4580 EAPI void
4581 _elm_widget_item_cursor_engine_only_set(Elm_Widget_Item *item,
4582                                         Eina_Bool engine_only)
4583 {
4584    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4585    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4586
4587    elm_object_cursor_theme_search_enabled_set(item->view, engine_only);
4588 }
4589
4590 /**
4591  * @internal
4592  *
4593  * Get the cursor engine only usage for this item cursor.
4594  *
4595  * @param item widget item with cursor already set.
4596  * @return engine_only boolean to define it cursors should be looked only
4597  * between the provided by the engine or searched on widget's theme as well. If
4598  *         the object does not have a cursor set, then EINA_FALSE is returned.
4599  *
4600  * @ingroup Widget
4601  */
4602 EAPI Eina_Bool
4603 _elm_widget_item_cursor_engine_only_get(const Elm_Widget_Item *item)
4604 {
4605    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4606    return elm_object_cursor_theme_search_enabled_get(item->view);
4607 }
4608
4609 EAPI void
4610 _elm_widget_item_part_content_set(Elm_Widget_Item *item,
4611                                   const char *part,
4612                                   Evas_Object *content)
4613 {
4614    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4615    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4616    if (!item->content_set_func)
4617      {
4618         ERR("%s does not support elm_object_item_part_content_set() API.",
4619             elm_widget_type_get(item->widget));
4620         return;
4621      }
4622    item->content_set_func((Elm_Object_Item *)item, part, content);
4623 }
4624
4625 EAPI Evas_Object *
4626 _elm_widget_item_part_content_get(const Elm_Widget_Item *item,
4627                                   const char *part)
4628 {
4629    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4630    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4631
4632    return item->content_get_func((Elm_Object_Item *)item, part);
4633 }
4634
4635 EAPI Evas_Object *
4636 _elm_widget_item_part_content_unset(Elm_Widget_Item *item,
4637                                     const char *part)
4638 {
4639    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4640    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4641    if (!item->content_unset_func)
4642      {
4643         ERR("%s does not support elm_object_item_part_content_unset() API.",
4644             elm_widget_type_get(item->widget));
4645         return NULL;
4646      }
4647
4648    return item->content_unset_func((Elm_Object_Item *)item, part);
4649 }
4650
4651 EAPI void
4652 _elm_widget_item_part_text_set(Elm_Widget_Item *item,
4653                                const char *part,
4654                                const char *label)
4655 {
4656    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4657    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4658    if (!item->text_set_func)
4659      {
4660         ERR("%s does not support elm_object_item_part_text_set() API.",
4661             elm_widget_type_get(item->widget));
4662         return;
4663      }
4664
4665    item->text_set_func((Elm_Object_Item *)item, part, label);
4666 }
4667
4668 EAPI const char *
4669 _elm_widget_item_part_text_get(const Elm_Widget_Item *item,
4670                                const char *part)
4671 {
4672    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4673    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4674    if (!item->text_get_func)
4675      {
4676         ERR("%s does not support elm_object_item_part_text_get() API.",
4677             elm_widget_type_get(item->widget));
4678         return NULL;
4679      }
4680
4681    return item->text_get_func((Elm_Object_Item *)item, part);
4682 }
4683
4684 EAPI void
4685 _elm_widget_item_content_set_hook_set(Elm_Widget_Item *item,
4686                                       Elm_Widget_Content_Set_Cb func)
4687 {
4688    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4689    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4690
4691    item->content_set_func = func;
4692 }
4693
4694 EAPI void
4695 _elm_widget_item_content_get_hook_set(Elm_Widget_Item *item,
4696                                       Elm_Widget_Content_Get_Cb func)
4697 {
4698    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4699    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4700
4701    item->content_get_func = func;
4702 }
4703
4704 EAPI void
4705 _elm_widget_item_content_unset_hook_set(Elm_Widget_Item *item,
4706                                         Elm_Widget_Content_Unset_Cb func)
4707 {
4708    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4709    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4710
4711    item->content_unset_func = func;
4712 }
4713
4714 EAPI void
4715 _elm_widget_item_text_set_hook_set(Elm_Widget_Item *item,
4716                                    Elm_Widget_Text_Set_Cb func)
4717 {
4718    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4719    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4720
4721    item->text_set_func = func;
4722 }
4723
4724 EAPI void
4725 _elm_widget_item_text_get_hook_set(Elm_Widget_Item *item,
4726                                    Elm_Widget_Text_Get_Cb func)
4727 {
4728    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4729    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4730
4731    item->text_get_func = func;
4732 }
4733
4734 EAPI void
4735 _elm_widget_item_signal_emit(Elm_Widget_Item *item,
4736                              const char *emission,
4737                              const char *source)
4738 {
4739    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4740    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4741
4742    if (item->signal_emit_func)
4743      item->signal_emit_func((Elm_Object_Item *)item, emission, source);
4744 }
4745
4746 EAPI void
4747 _elm_widget_item_signal_emit_hook_set(Elm_Widget_Item *item,
4748                                       Elm_Widget_Signal_Emit_Cb func)
4749 {
4750    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4751    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4752
4753    item->signal_emit_func = func;
4754 }
4755
4756
4757 static void
4758 _elm_widget_item_signal_cb(void *data, Evas_Object *obj __UNUSED__, const char *emission,
4759                            const char *source)
4760 {
4761    Elm_Widget_Item_Signal_Data *wisd = data;
4762    wisd->func(wisd->data, wisd->item, emission, source);
4763 }
4764
4765 EAPI void
4766 _elm_widget_item_signal_callback_add(Elm_Widget_Item *item,
4767                                      const char *emission,
4768                                      const char *source,
4769                                      Elm_Widget_Item_Signal_Cb func,
4770                                      void *data)
4771 {
4772    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4773    EINA_SAFETY_ON_NULL_RETURN(func);
4774
4775    Elm_Widget_Item_Signal_Data *wisd;
4776
4777    wisd = malloc(sizeof(Elm_Widget_Item_Signal_Data));
4778    if (!wisd) return;
4779
4780    wisd->item = item;
4781    wisd->func = func;
4782    wisd->data = data;
4783    wisd->emission = eina_stringshare_add(emission);
4784    wisd->source = eina_stringshare_add(source);
4785
4786    if (_elm_widget_is(item->view))
4787      elm_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
4788    else if (!strcmp(evas_object_type_get(item->view), "edje"))
4789      edje_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
4790    else
4791      {
4792         WRN("The %s widget item doesn't support signal callback add!",
4793             evas_object_type_get(item->widget));
4794         free(wisd);
4795         return;
4796      }
4797
4798    item->signals = eina_list_append(item->signals, wisd);
4799 }
4800
4801 EAPI void *
4802 _elm_widget_item_signal_callback_del(Elm_Widget_Item *item,
4803                                     const char *emission,
4804                                     const char *source,
4805                                     Elm_Widget_Item_Signal_Cb func)
4806 {
4807    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4808    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
4809
4810    Elm_Widget_Item_Signal_Data *wisd;
4811    Eina_List *l;
4812    void *data = NULL;
4813
4814    EINA_LIST_FOREACH(item->signals, l, wisd)
4815      {
4816         if ((wisd->func == func) && !strcmp(wisd->emission, emission) &&
4817             !strcmp(wisd->source, source))
4818           {
4819              item->signals = eina_list_remove_list(item->signals, l);
4820              eina_stringshare_del(wisd->emission);
4821              eina_stringshare_del(wisd->source);
4822              data = wisd->data;
4823
4824              if (_elm_widget_is(item->view))
4825                elm_object_signal_callback_del(item->view, emission, source,
4826                                               _elm_widget_item_signal_cb);
4827              else if (!strcmp(evas_object_type_get(item->view), "edje"))
4828                edje_object_signal_callback_del_full(item->view, emission,
4829                                                     source,
4830                                                     _elm_widget_item_signal_cb,
4831                                                     data);
4832           }
4833      }
4834
4835    return data;
4836 }
4837
4838 EAPI void
4839 _elm_widget_item_access_info_set(Elm_Widget_Item *item,
4840                                  const char *txt)
4841 {
4842    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4843    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4844
4845    if (item->access_info) eina_stringshare_del(item->access_info);
4846    if (!txt) item->access_info = NULL;
4847    else item->access_info = eina_stringshare_add(txt);
4848 }
4849
4850 /* happy debug functions */
4851 #ifdef ELM_DEBUG
4852 static void
4853 _sub_obj_tree_dump(const Evas_Object *obj,
4854                    int lvl)
4855 {
4856    int i;
4857
4858    for (i = 0; i < lvl * 3; i++)
4859      putchar(' ');
4860
4861    if (_elm_widget_is(obj))
4862      {
4863         Eina_List *l;
4864         INTERNAL_ENTRY;
4865         printf("+ %s(%p)\n",
4866                elm_widget_type_get(obj),
4867                obj);
4868         if (sd->resize_obj)
4869           _sub_obj_tree_dump(sd->resize_obj, lvl + 1);
4870         EINA_LIST_FOREACH(sd->subobjs, l, obj)
4871           {
4872              if (obj != sd->resize_obj)
4873                _sub_obj_tree_dump(obj, lvl + 1);
4874           }
4875      }
4876    else
4877      printf("+ %s(%p)\n", evas_object_type_get(obj), obj);
4878 }
4879
4880 static void
4881 _sub_obj_tree_dot_dump(const Evas_Object *obj,
4882                        FILE *output)
4883 {
4884    if (!_elm_widget_is(obj))
4885      return;
4886    INTERNAL_ENTRY;
4887
4888    Eina_Bool visible = evas_object_visible_get(obj);
4889    Eina_Bool disabled = elm_widget_disabled_get(obj);
4890    Eina_Bool focused = elm_widget_focus_get(obj);
4891    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
4892
4893    if (sd->parent_obj)
4894      {
4895         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
4896
4897         if (focused)
4898           fprintf(output, ", style=bold");
4899
4900         if (!visible)
4901           fprintf(output, ", color=gray28");
4902
4903         fprintf(output, " ];\n");
4904      }
4905
4906    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
4907                    "disabled: %d|focused: %d/%d|focus order:%d}\"",
4908            obj, obj, elm_widget_type_get(obj),
4909            evas_object_name_get(obj), visible, disabled, focused, can_focus,
4910            sd->focus_order);
4911
4912    if (focused)
4913      fprintf(output, ", style=bold");
4914
4915    if (!visible)
4916      fprintf(output, ", fontcolor=gray28");
4917
4918    if ((disabled) || (!visible))
4919      fprintf(output, ", color=gray");
4920
4921    fprintf(output, " ];\n");
4922
4923    Eina_List *l;
4924    Evas_Object *o;
4925    EINA_LIST_FOREACH(sd->subobjs, l, o)
4926      _sub_obj_tree_dot_dump(o, output);
4927 }
4928
4929 #endif
4930
4931 EAPI void
4932 elm_widget_tree_dump(const Evas_Object *top)
4933 {
4934 #ifdef ELM_DEBUG
4935    if (!_elm_widget_is(top))
4936      return;
4937    _sub_obj_tree_dump(top, 0);
4938 #else
4939    (void)top;
4940    return;
4941 #endif
4942 }
4943
4944 EAPI void
4945 elm_widget_tree_dot_dump(const Evas_Object *top,
4946                          FILE *output)
4947 {
4948 #ifdef ELM_DEBUG
4949    if (!_elm_widget_is(top))
4950      return;
4951    fprintf(output, "graph " " { node [shape=record];\n");
4952    _sub_obj_tree_dot_dump(top, output);
4953    fprintf(output, "}\n");
4954 #else
4955    (void)top;
4956    (void)output;
4957    return;
4958 #endif
4959 }