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