widget/entry: Update show region geometry when entry is resized
[platform/upstream/elementary.git] / src / lib / elm_widget.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
6 #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
7 #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
8 #define ELM_WIDGET_ITEM_PROTECTED
9 #include <Elementary.h>
10
11 #include "elm_priv.h"
12 #include "elm_widget_container.h"
13 #include "elm_interface_scrollable.h"
14
15 #define MY_CLASS ELM_WIDGET_CLASS
16
17 #define MY_CLASS_NAME "Elm_Widget"
18 #define MY_CLASS_NAME_LEGACY "elm_widget"
19
20 #define ELM_WIDGET_DATA_GET(o, wd)                             \
21   Elm_Widget_Smart_Data *wd = eo_data_scope_get(o, MY_CLASS)
22
23 #define API_ENTRY                                    \
24   ELM_WIDGET_DATA_GET(obj, sd);                      \
25   if ((!sd) || (!_elm_widget_is(obj)))
26 #define INTERNAL_ENTRY                               \
27   ELM_WIDGET_DATA_GET(obj, sd);                      \
28   if (!sd) return
29
30 #define ELM_WIDGET_FOCUS_GET(obj)                                          \
31   (eo_isa(obj, ELM_WIDGET_CLASS) &&                                    \
32    ((_elm_access_auto_highlight_get()) ? (elm_widget_highlight_get(obj)) : \
33                                          (elm_widget_focus_get(obj))))
34
35 const char SIG_WIDGET_FOCUSED[] = "focused";
36 const char SIG_WIDGET_UNFOCUSED[] = "unfocused";
37 const char SIG_WIDGET_LANG_CHANGED[] = "language,changed";
38 const char SIG_WIDGET_ACCESS_CHANGED[] = "access,changed";
39
40 // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
41 const char SIG_WIDGET_ATSPI_HIGHLIGHTED[] = "atspi,highlighted";
42 const char SIG_WIDGET_ATSPI_UNHIGHLIGHTED[] = "atspi,unhighlighted";
43 //
44
45 typedef struct _Elm_Event_Cb_Data         Elm_Event_Cb_Data;
46 typedef struct _Elm_Label_Data            Elm_Label_Data;
47 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
48
49 struct _Elm_Event_Cb_Data
50 {
51    Elm_Event_Cb func;
52    const void  *data;
53 };
54
55 struct _Elm_Label_Data
56 {
57    const char *part;
58    const char *text;
59 };
60
61 struct _Elm_Translate_String_Data
62 {
63    EINA_INLIST;
64    Eina_Stringshare *id;
65    Eina_Stringshare *domain;
66    Eina_Stringshare *string;
67    Eina_Bool   preset : 1;
68 };
69
70 /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
71 static void
72 _elm_widget_evas_object_paragraph_direction_set_internal(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_BiDi_Direction dir);
73 /* END */
74
75 /* local subsystem globals */
76 static unsigned int focus_order = 0;
77
78 static inline Eina_Bool
79 _elm_widget_is(const Evas_Object *obj)
80 {
81    return eo_isa(obj, MY_CLASS);
82 }
83
84 static inline Eina_Bool
85 _is_focusable(Evas_Object *obj)
86 {
87    API_ENTRY return EINA_FALSE;
88    return sd->can_focus || (sd->child_can_focus);
89 }
90
91 static inline Eina_Bool
92 _is_focused(Evas_Object *obj)
93 {
94    API_ENTRY return EINA_FALSE;
95    return sd->focused;
96 }
97
98 static inline Eina_Bool
99 _elm_scrollable_is(const Evas_Object *obj)
100 {
101    INTERNAL_ENTRY EINA_FALSE;
102    return
103       eo_isa(obj, ELM_INTERFACE_SCROLLABLE_MIXIN);
104 }
105
106 static void
107 elm_widget_disabled_internal(Eo *obj, Eina_Bool disabled);
108 static Eina_Bool
109 _on_sub_obj_del(void *data,
110                 Eo *obj,
111                 const Eo_Event_Description *desc,
112                 void *event_info);
113 static Eina_Bool
114 _on_sub_obj_hide(void *data,
115                  Eo *obj,
116                  const Eo_Event_Description *desc,
117                  void *event_info);
118 static Eina_Bool
119 _propagate_event(void *data,
120                  Eo *obj,
121                  const Eo_Event_Description *desc,
122                  void *event_info);
123
124 EO_CALLBACKS_ARRAY_DEFINE(elm_widget_subitems_callbacks,
125                           { EVAS_OBJECT_EVENT_DEL, _on_sub_obj_del },
126                           { EVAS_OBJECT_EVENT_HIDE, _on_sub_obj_hide });
127 EO_CALLBACKS_ARRAY_DEFINE(efl_subitems_callbacks,
128                           { EVAS_OBJECT_EVENT_DEL, _on_sub_obj_del });
129 EO_CALLBACKS_ARRAY_DEFINE(focus_callbacks,
130                           { EVAS_OBJECT_EVENT_KEY_DOWN, _propagate_event },
131                           { EVAS_OBJECT_EVENT_KEY_UP, _propagate_event },
132                           { EVAS_OBJECT_EVENT_MOUSE_WHEEL, _propagate_event });
133
134 static inline void
135 _callbacks_add(Eo *widget, void *data)
136 {
137    if (_elm_widget_is(widget))
138      {
139         eo_do(widget,
140               eo_event_callback_array_add(elm_widget_subitems_callbacks(), data));
141      }
142    else
143      {
144         eo_do(widget,
145               eo_event_callback_array_add(efl_subitems_callbacks(), data));
146      }
147 }
148
149 static inline void
150 _callbacks_del(Eo *widget, void *data)
151 {
152    if (_elm_widget_is(widget))
153      {
154         eo_do(widget,
155               eo_event_callback_array_del(elm_widget_subitems_callbacks(), data));
156      }
157    else
158      {
159         eo_do(widget,
160               eo_event_callback_array_del(efl_subitems_callbacks(), data));
161      }
162 }
163
164 void
165 _elm_widget_item_highlight_in_theme(Evas_Object *obj, Elm_Object_Item *eo_it)
166 {
167    const char *str;
168
169    if (!eo_it) return;
170    if (eo_isa(eo_it, ELM_WIDGET_ITEM_CLASS))
171      {
172         Elm_Widget_Item_Data *it = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS);
173
174         if (eo_isa(it->view, ELM_LAYOUT_CLASS))
175           str = edje_object_data_get(elm_layout_edje_get(it->view), "focus_highlight");
176         else
177           str = edje_object_data_get(it->view, "focus_highlight");
178      }
179    else
180       str = edje_object_data_get(((Elm_Widget_Item_Data *)eo_it)->view, "focus_highlight");
181    if ((str) && (!strcmp(str, "on")))
182      elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
183    else
184      elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
185 }
186
187 void
188 _elm_widget_focus_highlight_start(const Evas_Object *obj)
189 {
190    Evas_Object *top = elm_widget_top_get(obj);
191
192    if (top && eo_isa(top, ELM_WIN_CLASS))
193      _elm_win_focus_highlight_start(top);
194 }
195
196 Evas_Object *
197 _elm_widget_focus_highlight_object_get(const Evas_Object *obj)
198 {
199    Evas_Object *top = elm_widget_top_get(obj);
200
201    if (top && eo_isa(top, ELM_WIN_CLASS))
202      return _elm_win_focus_highlight_object_get(top);
203    return NULL;
204 }
205
206 EAPI Eina_Bool
207 elm_widget_focus_highlight_enabled_get(const Evas_Object *obj)
208 {
209    const Evas_Object *win = elm_widget_top_get(obj);
210
211    if (win && eo_isa(win, ELM_WIN_CLASS))
212      return elm_win_focus_highlight_enabled_get(win);
213    return EINA_FALSE;
214 }
215
216 /**
217  * @internal
218  *
219  * Resets the mirrored mode from the system mirror mode for widgets that are in
220  * automatic mirroring mode. This function does not call elm_widget_theme.
221  *
222  * @param obj The widget.
223  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
224  */
225 static void
226 _elm_widget_mirrored_reload(Evas_Object *obj)
227 {
228    API_ENTRY return;
229    Eina_Bool mirrored = elm_config_mirrored_get();
230
231    if (elm_widget_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored))
232      {
233         sd->is_mirrored = mirrored;
234      }
235 }
236
237 EOLIAN static Eina_Bool
238 _elm_widget_on_focus_region(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Coord *x EINA_UNUSED, Evas_Coord *y EINA_UNUSED, Evas_Coord *w EINA_UNUSED, Evas_Coord *h EINA_UNUSED)
239 {
240    WRN("The %s widget does not implement the \"on_focus_region\" function.",
241        eo_class_name_get(eo_class_get(obj)));
242
243    return EINA_FALSE;
244 }
245
246 static void
247 _parents_focus(Evas_Object *obj)
248 {
249    for (; obj; obj = elm_widget_parent_get(obj))
250      {
251         INTERNAL_ENTRY;
252         if (sd->focused) return;
253         sd->focused = 1;
254      }
255 }
256
257 static void
258 _parents_unfocus(Evas_Object *obj)
259 {
260    for (; obj; obj = elm_widget_parent_get(obj))
261      {
262         INTERNAL_ENTRY;
263         if (!sd->focused) return;
264         sd->focused = 0;
265      }
266 }
267
268 static Eina_Bool
269 _on_sub_obj_hide(void *data EINA_UNUSED,
270                  Eo *obj,
271                  const Eo_Event_Description *desc EINA_UNUSED,
272                  void *event_info EINA_UNUSED)
273 {
274    elm_widget_focus_hide_handle(obj);
275    return EO_CALLBACK_CONTINUE;
276 }
277
278 static Eina_Bool
279 _on_sub_obj_del(void *data,
280                 Eo *obj,
281                 const Eo_Event_Description *desc EINA_UNUSED,
282                 void *event_info EINA_UNUSED)
283 {
284    ELM_WIDGET_DATA_GET(data, sd);
285
286    if (_elm_widget_is(obj))
287      {
288         if (_is_focused((Eo *)obj)) _parents_unfocus(sd->obj);
289      }
290    if (obj == sd->resize_obj)
291      {
292         /* already dels sub object */
293         elm_widget_resize_object_set(sd->obj, NULL, EINA_TRUE);
294      }
295    else if (obj == sd->hover_obj)
296      {
297         sd->hover_obj = NULL;
298      }
299    else
300      {
301         if (!elm_widget_sub_object_del(sd->obj, obj))
302           ERR("failed to remove sub object %p from %p\n", obj, sd->obj);
303      }
304
305    return EO_CALLBACK_CONTINUE;
306 }
307
308 static const Evas_Smart_Cb_Description _smart_callbacks[] =
309 {
310    {SIG_WIDGET_FOCUSED, ""},
311    {SIG_WIDGET_UNFOCUSED, ""},
312    {SIG_WIDGET_LANG_CHANGED, ""},
313    {SIG_WIDGET_ACCESS_CHANGED, ""},
314    // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
315    {SIG_WIDGET_ATSPI_HIGHLIGHTED, ""},
316    {SIG_WIDGET_ATSPI_UNHIGHLIGHTED, ""},
317    //
318    {NULL, NULL}
319 };
320
321 static void
322 _obj_mouse_down(void *data,
323                 Evas *e EINA_UNUSED,
324                 Evas_Object *obj EINA_UNUSED,
325                 void *event_info)
326 {
327    Evas_Object *top;
328
329    ELM_WIDGET_DATA_GET(data, sd);
330    Evas_Event_Mouse_Down *ev = event_info;
331    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
332
333    top = elm_widget_top_get(data);
334    if (top && eo_isa(top, ELM_WIN_CLASS)) _elm_win_focus_auto_hide(top);
335    sd->still_in = EINA_TRUE;
336 }
337
338 static void
339 _obj_mouse_move(void *data,
340                 Evas *e EINA_UNUSED,
341                 Evas_Object *obj,
342                 void *event_info)
343 {
344    ELM_WIDGET_DATA_GET(data, sd);
345    Evas_Event_Mouse_Move *ev = event_info;
346    if (!sd->still_in) return;
347
348    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
349      sd->still_in = EINA_FALSE;
350    else
351      {
352         Evas_Coord x, y, w, h;
353         evas_object_geometry_get(obj, &x, &y, &w, &h);
354         if (ELM_RECTS_POINT_OUT(x, y, w, h, ev->cur.canvas.x, ev->cur.canvas.y))
355           sd->still_in = EINA_FALSE;
356      }
357 }
358
359 static void
360 _obj_mouse_up(void *data,
361               Evas *e EINA_UNUSED,
362               Evas_Object *obj,
363               void *event_info EINA_UNUSED)
364 {
365    ELM_WIDGET_DATA_GET(data, sd);
366    if (sd->still_in &&
367        (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_CLICK))
368      elm_widget_focus_mouse_up_handle(obj);
369
370    sd->still_in = EINA_FALSE;
371 }
372
373 static void
374 _obj_mouse_in(void *data,
375               Evas *e EINA_UNUSED,
376               Evas_Object *obj,
377               void *event_info EINA_UNUSED)
378 {
379    ELM_WIDGET_DATA_GET(data, sd);
380    if (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_IN)
381      elm_widget_focus_mouse_up_handle(obj);
382 }
383
384 EOLIAN static void
385 _elm_widget_evas_object_smart_add(Eo *obj, Elm_Widget_Smart_Data *priv)
386 {
387
388    priv->obj = obj;
389    priv->mirrored_auto_mode = EINA_TRUE; /* will follow system locale
390                                           * settings */
391    priv->focus_move_policy_auto_mode = EINA_TRUE;
392    priv->focus_region_show_mode = ELM_FOCUS_REGION_SHOW_WIDGET;
393    elm_widget_can_focus_set(obj, EINA_TRUE);
394    priv->is_mirrored = elm_config_mirrored_get();
395    priv->focus_move_policy = _elm_config->focus_move_policy;
396
397    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
398                                   _obj_mouse_down, obj);
399    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
400                                   _obj_mouse_move, obj);
401    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
402                                   _obj_mouse_up, obj);
403    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_IN,
404                                   _obj_mouse_in, obj);
405    /* just a helper for inheriting classes */
406    if (priv->resize_obj)
407      {
408         Evas_Object *r_obj = priv->resize_obj;
409         priv->resize_obj = NULL;
410
411         elm_widget_resize_object_set(obj, r_obj, EINA_TRUE);
412      }
413 }
414
415 static void
416 _if_focused_revert(Evas_Object *obj,
417                    Eina_Bool can_focus_only)
418 {
419    Evas_Object *top;
420    Evas_Object *newest = NULL;
421    unsigned int newest_focus_order = 0;
422
423    INTERNAL_ENTRY;
424
425    if (!sd->focused) return;
426    if (!sd->parent_obj) return;
427
428    top = elm_widget_top_get(sd->parent_obj);
429    if (top)
430      {
431         newest = elm_widget_newest_focus_order_get
432            (top, &newest_focus_order, can_focus_only);
433         if (newest)
434           {
435              if (newest == top)
436                {
437                   ELM_WIDGET_DATA_GET(newest, sd2);
438                   if (!sd2) return;
439
440                   if (!_is_focused(newest))
441                     elm_widget_focus_steal(newest, NULL);
442                   else
443                     {
444                        if (sd2->resize_obj && _is_focused(sd2->resize_obj))
445                          elm_widget_focused_object_clear(sd2->resize_obj);
446                        else
447                          {
448                             const Eina_List *l;
449                             Evas_Object *child;
450                             EINA_LIST_FOREACH(sd2->subobjs, l, child)
451                               {
452                                  if (_is_focused(child))
453                                    {
454                                       elm_widget_focused_object_clear(child);
455                                       break;
456                                    }
457                               }
458                          }
459                     }
460                   evas_object_focus_set(newest, EINA_TRUE);
461                }
462              else
463                {
464                   elm_object_focus_set(newest, EINA_FALSE);
465                   elm_object_focus_set(newest, EINA_TRUE);
466                }
467           }
468      }
469 }
470
471 EOLIAN static void
472 _elm_widget_evas_object_smart_del(Eo *obj, Elm_Widget_Smart_Data *sd)
473 {
474    Evas_Object *sobj;
475    Elm_Translate_String_Data *ts;
476    Elm_Event_Cb_Data *ecb;
477
478    if (sd->hover_obj)
479      {
480         /* detach it from us */
481         _callbacks_del(sd->hover_obj, obj);
482         sd->hover_obj = NULL;
483      }
484
485    while (sd->subobjs)
486      {
487         sobj = eina_list_data_get(sd->subobjs);
488
489         /* let the objects clean-up themselves and get rid of this list */
490         if (!elm_widget_sub_object_del(obj, sobj))
491           {
492              ERR("failed to remove sub object %p from %p\n", sobj, obj);
493              sd->subobjs = eina_list_remove_list
494                  (sd->subobjs, sd->subobjs);
495           }
496         evas_object_del(sobj);
497      }
498    sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */
499    sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */
500    while (sd->translate_strings)
501      {
502         ts = EINA_INLIST_CONTAINER_GET(sd->translate_strings,
503                                        Elm_Translate_String_Data);
504         eina_stringshare_del(ts->id);
505         eina_stringshare_del(ts->domain);
506         eina_stringshare_del(ts->string);
507         sd->translate_strings = eina_inlist_remove(sd->translate_strings,
508                                                    sd->translate_strings);
509         free(ts);
510      }
511
512    EINA_LIST_FREE(sd->event_cb, ecb)
513       free(ecb);
514
515    eina_stringshare_del(sd->style);
516    if (sd->theme) elm_theme_free(sd->theme);
517    _if_focused_revert(obj, EINA_TRUE);
518    elm_widget_focus_custom_chain_unset(obj);
519    eina_stringshare_del(sd->access_info);
520    eina_stringshare_del(sd->accessible_name);
521    evas_object_smart_data_set(obj, NULL);
522 }
523
524 static void
525 _smart_reconfigure(Elm_Widget_Smart_Data *sd)
526 {
527    if (sd->resize_obj)
528      {
529         evas_object_move(sd->resize_obj, sd->x, sd->y);
530         evas_object_resize(sd->resize_obj, sd->w, sd->h);
531      }
532    if (sd->hover_obj)
533      {
534         evas_object_move(sd->hover_obj, sd->x, sd->y);
535         evas_object_resize(sd->hover_obj, sd->w, sd->h);
536      }
537 }
538
539 EOLIAN static void
540 _elm_widget_evas_object_smart_move(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord x, Evas_Coord y)
541 {
542    sd->x = x;
543    sd->y = y;
544
545    _smart_reconfigure(sd);
546 }
547
548 EOLIAN static void
549 _elm_widget_evas_object_smart_resize(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord w, Evas_Coord h)
550 {
551    sd->w = w;
552    sd->h = h;
553
554    _smart_reconfigure(sd);
555 }
556
557 EOLIAN static void
558 _elm_widget_evas_object_smart_show(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
559 {
560    Eina_Iterator *it;
561    Evas_Object *o;
562
563    if (_elm_atspi_enabled())
564      {
565         Eo *parent;
566         eo_do(obj, parent = elm_interface_atspi_accessible_parent_get());
567         if (parent) elm_interface_atspi_accessible_children_changed_added_signal_emit(parent, obj);
568      }
569
570    it = evas_object_smart_iterator_new(obj);
571    EINA_ITERATOR_FOREACH(it, o)
572      {
573        if (evas_object_data_get(o, "_elm_leaveme")) continue;
574        evas_object_show(o);
575      }
576    eina_iterator_free(it);
577
578    if (_elm_atspi_enabled())
579      {
580         elm_interface_atspi_accessible_added(obj);
581         if (_elm_widget_onscreen_is(obj))
582            elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_SHOWING, EINA_TRUE);
583      }
584 }
585
586 EOLIAN static void
587 _elm_widget_evas_object_smart_hide(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
588 {
589    Eina_Iterator *it;
590    Evas_Object *o;
591
592    it = evas_object_smart_iterator_new(obj);
593    EINA_ITERATOR_FOREACH(it, o)
594      {
595         if (evas_object_data_get(o, "_elm_leaveme")) continue;
596         evas_object_hide(o);
597      }
598    eina_iterator_free(it);
599
600    if (_elm_atspi_enabled())
601      elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_SHOWING, EINA_FALSE);
602 }
603
604 EOLIAN static void
605 _elm_widget_evas_object_smart_color_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, int r, int g, int b, int a)
606 {
607    Eina_Iterator *it;
608    Evas_Object *o;
609
610    it = evas_object_smart_iterator_new(obj);
611    EINA_ITERATOR_FOREACH(it, o)
612      {
613        if (evas_object_data_get(o, "_elm_leaveme")) continue;
614        evas_object_color_set(o, r, g, b, a);
615      }
616    eina_iterator_free(it);
617 }
618
619 EOLIAN static void
620 _elm_widget_evas_object_smart_clip_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *clip)
621 {
622    Eina_Iterator *it;
623    Evas_Object *o;
624
625    it = evas_object_smart_iterator_new(obj);
626    EINA_ITERATOR_FOREACH(it, o)
627      {
628        if (evas_object_data_get(o, "_elm_leaveme")) continue;
629        evas_object_clip_set(o, clip);
630      }
631    eina_iterator_free(it);
632 }
633
634 EOLIAN static void
635 _elm_widget_evas_object_smart_clip_unset(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
636 {
637    Eina_Iterator *it;
638    Evas_Object *o;
639
640    it = evas_object_smart_iterator_new(obj);
641    EINA_ITERATOR_FOREACH(it, o)
642      {
643        if (evas_object_data_get(o, "_elm_leaveme")) continue;
644        evas_object_clip_unset(o);
645      }
646    eina_iterator_free(it);
647 }
648
649 EOLIAN static void
650 _elm_widget_evas_object_smart_calculate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
651 {
652    /* a NO-OP, on the base */
653 }
654
655 EOLIAN static void
656 _elm_widget_evas_object_smart_member_add(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child)
657 {
658    int r, g, b, a;
659    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_add(child));
660
661    if (evas_object_data_get(child, "_elm_leaveme")) return;
662
663    evas_object_color_get(obj, &r, &g, &b, &a);
664    evas_object_color_set(child, r, g, b, a);
665
666    evas_object_clip_set(child, evas_object_clip_get(obj));
667
668    if (evas_object_visible_get(obj))
669      evas_object_show(child);
670    else
671      evas_object_hide(child);
672 }
673
674 EOLIAN static void
675 _elm_widget_evas_object_smart_member_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child)
676 {
677    if (!evas_object_data_get(child, "_elm_leaveme"))
678       evas_object_clip_unset(child);
679    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_del(child));
680 }
681
682 // internal funcs
683 /**
684  * @internal
685  *
686  * Check if the widget has its own focus next function.
687  *
688  * @param obj The widget.
689  * @return focus next function is implemented/unimplemented.
690  * (@c EINA_TRUE = implemented/@c EINA_FALSE = unimplemented.)
691  */
692 static inline Eina_Bool
693 _elm_widget_focus_chain_manager_is(const Evas_Object *obj)
694 {
695    ELM_WIDGET_CHECK(obj) EINA_FALSE;
696
697    Eina_Bool manager_is = EINA_FALSE;
698    eo_do((Eo *)obj, manager_is = elm_obj_widget_focus_next_manager_is());
699    return manager_is;
700 }
701
702 static inline Eina_Bool
703 _internal_elm_widget_focus_direction_manager_is(const Evas_Object *obj)
704 {
705    ELM_WIDGET_CHECK(obj) EINA_FALSE;
706
707    Eina_Bool manager_is = EINA_FALSE;
708    eo_do((Eo *)obj, manager_is = elm_obj_widget_focus_direction_manager_is());
709    return manager_is;
710 }
711
712 static void
713 _propagate_x_drag_lock(Evas_Object *obj,
714                        int dir)
715 {
716    INTERNAL_ENTRY;
717    if (sd->parent_obj)
718      {
719         ELM_WIDGET_DATA_GET(sd->parent_obj, sd2);
720         if (sd2)
721           {
722              sd2->child_drag_x_locked += dir;
723              _propagate_x_drag_lock(sd->parent_obj, dir);
724           }
725      }
726 }
727
728 static void
729 _propagate_y_drag_lock(Evas_Object *obj,
730                        int dir)
731 {
732    INTERNAL_ENTRY;
733    if (sd->parent_obj)
734      {
735         ELM_WIDGET_DATA_GET(sd->parent_obj, sd2);
736         if (sd2)
737           {
738              sd2->child_drag_y_locked += dir;
739              _propagate_y_drag_lock(sd->parent_obj, dir);
740           }
741      }
742 }
743
744 static Eina_Bool
745 _propagate_event(void *data EINA_UNUSED,
746                  Eo *obj,
747                  const Eo_Event_Description *desc,
748                  void *event_info)
749 {
750    INTERNAL_ENTRY EO_CALLBACK_CONTINUE;
751    Evas_Callback_Type type;
752    Evas_Event_Flags *event_flags = NULL;
753
754    if (desc == EVAS_OBJECT_EVENT_KEY_DOWN)
755      {
756         Evas_Event_Key_Down *ev = event_info;
757         event_flags = &(ev->event_flags);
758         type = EVAS_CALLBACK_KEY_DOWN;
759      }
760    else if (desc == EVAS_OBJECT_EVENT_KEY_UP)
761      {
762         Evas_Event_Key_Up *ev = event_info;
763         event_flags = &(ev->event_flags);
764         type = EVAS_CALLBACK_KEY_UP;
765      }
766    else if (desc == EVAS_OBJECT_EVENT_MOUSE_WHEEL)
767      {
768         Evas_Event_Mouse_Wheel *ev = event_info;
769         event_flags = &(ev->event_flags);
770         type = EVAS_CALLBACK_MOUSE_WHEEL;
771      }
772    else
773      return EO_CALLBACK_CONTINUE;
774
775    elm_widget_event_propagate(obj, type, event_info, event_flags);
776
777    return EO_CALLBACK_CONTINUE;
778 }
779
780 /**
781  * @internal
782  *
783  * If elm_widget_focus_region_get() returns EINA_FALSE, this function will
784  * ignore region show action.
785  */
786 EOLIAN static void
787 _elm_widget_focus_region_show(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
788 {
789    Evas_Coord x, y, w, h, ox, oy;
790    Evas_Object *o;
791
792    o = elm_widget_parent_get(obj);
793    if (!o) return;
794
795    if (!elm_widget_focus_region_get(obj, &x, &y, &w, &h))
796      return;
797
798    evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
799
800    while (o)
801      {
802         Evas_Coord px, py;
803         evas_object_geometry_get(o, &px, &py, NULL, NULL);
804
805         if (_elm_scrollable_is(o) && !elm_widget_disabled_get(o))
806           {
807              Evas_Coord sx, sy;
808              eo_do(o, elm_interface_scrollable_content_region_get(&sx, &sy, NULL, NULL));
809
810              // Get the object's on_focus_region position relative to the scroller.
811              Evas_Coord rx, ry;
812              rx = ox + x - px + sx;
813              ry = oy + y - py + sy;
814
815              switch (_elm_config->focus_autoscroll_mode)
816                {
817                 case ELM_FOCUS_AUTOSCROLL_MODE_SHOW:
818                    eo_do(o, elm_interface_scrollable_content_region_show(rx, ry, w, h));
819                    break;
820                 case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN:
821                    eo_do(o, elm_interface_scrollable_region_bring_in(rx, ry, w, h));
822                    break;
823                 default:
824                    break;
825                }
826
827              elm_widget_focus_region_get(o, &x, &y, &w, &h);
828              evas_object_geometry_get(o, &ox, &oy, NULL, NULL);
829           }
830         else
831           {
832              x += ox - px;
833              y += oy - py;
834              ox = px;
835              oy = py;
836           }
837         o = elm_widget_parent_get(o);
838      }
839 }
840
841 EOLIAN static Eina_Bool
842 _elm_widget_focus_highlight_style_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *style)
843 {
844    if (eina_stringshare_replace(&sd->focus_highlight_style, style)) return EINA_TRUE;
845    return EINA_FALSE;
846 }
847
848 EOLIAN static const char*
849 _elm_widget_focus_highlight_style_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
850 {
851    return sd->focus_highlight_style;
852 }
853
854 static void
855 _parent_focus(Evas_Object *obj, Elm_Object_Item *item)
856 {
857    API_ENTRY return;
858
859    if (sd->focused) return;
860
861    Evas_Object *o = elm_widget_parent_get(obj);
862    sd->focus_order_on_calc = EINA_TRUE;
863
864    if (o) _parent_focus(o, item);
865
866    if (!sd->focus_order_on_calc)
867      return;  /* we don't want to override it if by means of any of the
868                  callbacks below one gets to calculate our order
869                  first. */
870
871    focus_order++;
872    sd->focus_order = focus_order;
873    sd->focused = EINA_TRUE;
874
875    if (sd->top_win_focused)
876      eo_do(obj, elm_obj_widget_on_focus(item));
877    sd->focus_order_on_calc = EINA_FALSE;
878
879    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
880      _elm_access_highlight_set(obj);
881 }
882
883 static void
884 _elm_object_focus_chain_del_cb(void *data,
885                                Evas *e EINA_UNUSED,
886                                Evas_Object *obj,
887                                void *event_info EINA_UNUSED)
888 {
889    ELM_WIDGET_DATA_GET(data, sd);
890
891    sd->focus_chain = eina_list_remove(sd->focus_chain, obj);
892 }
893
894 EOLIAN static void
895 _elm_widget_parent_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *parent EINA_UNUSED)
896 {
897 }
898
899 EAPI Eina_Bool
900 elm_widget_api_check(int ver)
901 {
902    if (ver != ELM_INTERNAL_API_VERSION)
903      {
904         CRI("Elementary widget api versions do not match");
905         return EINA_FALSE;
906      }
907    return EINA_TRUE;
908 }
909
910 EAPI Eina_Bool
911 elm_widget_access(Evas_Object *obj,
912                   Eina_Bool is_access)
913 {
914    const Eina_List *l;
915    Evas_Object *child;
916    Eina_Bool ret = EINA_TRUE;
917
918    API_ENTRY return EINA_FALSE;
919    EINA_LIST_FOREACH(sd->subobjs, l, child)
920      {
921         if (elm_widget_is(child))
922           ret &= elm_widget_access(child, is_access);
923      }
924
925    eo_do(obj, elm_obj_widget_access(is_access));
926    eo_do(obj, eo_event_callback_call(ELM_WIDGET_EVENT_ACCESS_CHANGED, NULL));
927
928    return ret;
929 }
930
931 //TIZEN_ONLY(20160822): When atspi mode is dynamically switched on/off,
932 //register/unregister access objects accordingly.
933 EAPI Eina_Bool
934 elm_widget_atspi(Evas_Object *obj,
935                   Eina_Bool is_atspi)
936 {
937    const Eina_List *l;
938    Evas_Object *child;
939    Eina_Bool ret = EINA_TRUE;
940
941    API_ENTRY return EINA_FALSE;
942    EINA_LIST_FOREACH(sd->subobjs, l, child)
943      {
944         if (elm_widget_is(child))
945           ret &= elm_widget_atspi(child, is_atspi);
946      }
947    eo_do(obj, elm_obj_widget_atspi(is_atspi));
948
949    return ret;
950 }
951
952 EOLIAN static void
953 _elm_widget_atspi(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool is_atspi EINA_UNUSED)
954 {
955 }
956 //
957
958 EOLIAN static void
959 _elm_widget_access(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool is_access EINA_UNUSED)
960 {
961 }
962
963 EAPI Elm_Theme_Apply
964 elm_widget_theme(Evas_Object *obj)
965 {
966    const Eina_List *l;
967    Evas_Object *child;
968    Elm_Tooltip *tt;
969    Elm_Cursor *cur;
970    Elm_Theme_Apply ret = ELM_THEME_APPLY_SUCCESS;
971
972    API_ENTRY return ELM_THEME_APPLY_FAILED;
973
974    EINA_LIST_FOREACH(sd->subobjs, l, child)
975      if (_elm_widget_is(child))
976        ret &= elm_widget_theme(child);
977
978    if (sd->hover_obj) ret &= elm_widget_theme(sd->hover_obj);
979
980    EINA_LIST_FOREACH(sd->tooltips, l, tt)
981      elm_tooltip_theme(tt);
982    EINA_LIST_FOREACH(sd->cursors, l, cur)
983      elm_cursor_theme(cur);
984
985    Elm_Theme_Apply ret2 = ELM_THEME_APPLY_FAILED;
986    eo_do(obj, ret2 = elm_obj_widget_theme_apply());
987    ret &= ret2;
988
989    return ret;
990 }
991
992 EAPI void
993 elm_widget_theme_specific(Evas_Object *obj,
994                           Elm_Theme *th,
995                           Eina_Bool force)
996 {
997    const Eina_List *l;
998    Evas_Object *child;
999    Elm_Tooltip *tt;
1000    Elm_Cursor *cur;
1001    Elm_Theme *th2, *thdef;
1002
1003    API_ENTRY return;
1004
1005    thdef = elm_theme_default_get();
1006    if (!th) th = thdef;
1007    if (!force)
1008      {
1009         th2 = sd->theme;
1010         if (!th2) th2 = thdef;
1011         while (th2)
1012           {
1013              if (th2 == th)
1014                {
1015                   force = EINA_TRUE;
1016                   break;
1017                }
1018              if (th2 == thdef) break;
1019              th2 = th2->ref_theme;
1020              if (!th2) th2 = thdef;
1021           }
1022      }
1023    if (!force) return;
1024    EINA_LIST_FOREACH(sd->subobjs, l, child)
1025      {
1026         if (elm_widget_is(child))
1027           elm_widget_theme_specific(child, th, force);
1028      }
1029    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
1030    EINA_LIST_FOREACH(sd->tooltips, l, tt)
1031      elm_tooltip_theme(tt);
1032    EINA_LIST_FOREACH(sd->cursors, l, cur)
1033      elm_cursor_theme(cur);
1034    eo_do(obj, elm_obj_widget_theme_apply());
1035 }
1036
1037 EOLIAN static Elm_Theme_Apply
1038 _elm_widget_theme_apply(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
1039 {
1040    _elm_widget_mirrored_reload(obj);
1041    if (elm_widget_disabled_get(obj))
1042      elm_widget_disabled_internal(obj, elm_widget_disabled_get(obj));
1043
1044    return ELM_THEME_APPLY_SUCCESS;
1045 }
1046
1047 /**
1048  * @internal
1049  *
1050  * Returns the widget's mirrored mode.
1051  *
1052  * @param obj The widget.
1053  * @return mirrored mode of the object.
1054  *
1055  **/
1056 EOLIAN static Eina_Bool
1057 _elm_widget_mirrored_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1058 {
1059    return sd->is_mirrored;
1060 }
1061
1062 /**
1063  * @internal
1064  *
1065  * Sets the widget's mirrored mode.
1066  *
1067  * @param obj The widget.
1068  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
1069  */
1070 EOLIAN static void
1071 _elm_widget_mirrored_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool mirrored)
1072 {
1073    mirrored = !!mirrored;
1074
1075    if (sd->is_mirrored == mirrored) return;
1076
1077    sd->is_mirrored = mirrored;
1078    elm_widget_theme(obj);
1079 }
1080
1081 /**
1082  * Returns the widget's mirrored mode setting.
1083  *
1084  * @param obj The widget.
1085  * @return mirrored mode setting of the object.
1086  *
1087  **/
1088 EOLIAN static Eina_Bool
1089 _elm_widget_mirrored_automatic_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1090 {
1091    return sd->mirrored_auto_mode;
1092 }
1093
1094 /**
1095  * @internal
1096  *
1097  * Sets the widget's mirrored mode setting.
1098  * When widget in automatic mode, it follows the system mirrored mode set by
1099  * elm_mirrored_set().
1100  * @param obj The widget.
1101  * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual.
1102  */
1103 EOLIAN static void
1104 _elm_widget_mirrored_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic)
1105 {
1106    if (sd->mirrored_auto_mode != automatic)
1107      {
1108         sd->mirrored_auto_mode = automatic;
1109
1110         if (automatic)
1111           {
1112              elm_widget_mirrored_set(obj, elm_config_mirrored_get());
1113           }
1114      }
1115 }
1116
1117 EOLIAN static void
1118 _elm_widget_on_show_region_hook_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, region_hook_func_type func, void *data)
1119 {
1120    sd->on_show_region = func;
1121    sd->on_show_region_data = data;
1122 }
1123
1124 /*
1125  * @internal
1126  *
1127  * Add myself as a sub object of parent object
1128  *
1129  * @see elm_widget_sub_object_add()
1130  */
1131 EAPI Eina_Bool
1132 elm_widget_sub_object_parent_add(Evas_Object *sobj)
1133 {
1134    Eina_Bool ret = EINA_FALSE;
1135    Eo *parent = NULL;
1136
1137    eo_do(sobj, parent = eo_parent_get());
1138    if (!eo_isa(parent, ELM_WIDGET_CLASS))
1139      {
1140         ERR("You passed a wrong parent parameter (%p %s). "
1141             "Elementary widget's parent should be an elementary widget.", parent, evas_object_type_get(parent));
1142         return ret;
1143      }
1144
1145    eo_do(parent, ret = elm_obj_widget_sub_object_add(sobj));
1146
1147    return ret;
1148 }
1149
1150 /*
1151  * @internal
1152  *
1153  * Add sobj to obj's sub object.
1154  *
1155  * What does elementary sub object mean? This is unique in elementary, it
1156  * handles overall elementary policies between parent and sub objects.
1157  *   focus, access, deletion, theme, scale, mirror, scrollable child get,
1158  *   translate, name find, display mode set, orientation set, tree dump
1159  *   AUTOMATICALLY.
1160  *
1161  * @see elm_widget_sub_object_parent_add()
1162  */
1163 EOLIAN static Eina_Bool
1164 _elm_widget_sub_object_add(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1165 {
1166    Eina_Bool mirrored, pmirrored = elm_widget_mirrored_get(obj);
1167
1168    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1169
1170    if (sobj == sd->parent_obj)
1171      {
1172         /* in this case, sobj must be an elm widget, or something
1173          * very wrong is happening */
1174         if (!_elm_widget_is(sobj)) return EINA_FALSE;
1175
1176         if (!elm_widget_sub_object_del(sobj, obj)) return EINA_FALSE;
1177         WRN("You passed a parent object of obj = %p as the sub object = %p!",
1178             obj, sobj);
1179      }
1180
1181    if (_elm_widget_is(sobj))
1182      {
1183         ELM_WIDGET_DATA_GET(sobj, sdc);
1184
1185         if (sdc->parent_obj == obj) goto end;
1186         if (sdc->parent_obj)
1187           {
1188              if (!elm_widget_sub_object_del(sdc->parent_obj, sobj))
1189                return EINA_FALSE;
1190           }
1191         sdc->parent_obj = obj;
1192
1193         if (!sdc->on_create)
1194           eo_do(sobj, elm_obj_widget_orientation_set(sd->orient_mode));
1195         else
1196           sdc->orient_mode = sd->orient_mode;
1197
1198         if (!sdc->on_create)
1199           {
1200              if (!sdc->disabled && (elm_widget_disabled_get(obj)))
1201                {
1202                   elm_widget_focus_disabled_handle(sobj);
1203                   eo_do(sobj, elm_obj_widget_disable());
1204                }
1205           }
1206
1207         _elm_widget_top_win_focused_set(sobj, sd->top_win_focused);
1208
1209         /* update child focusable-ness on self and parents, now that a
1210          * focusable child got in */
1211         if (!sd->child_can_focus && (_is_focusable(sobj)))
1212           {
1213              Elm_Widget_Smart_Data *sdp = sd;
1214
1215              sdp->child_can_focus = EINA_TRUE;
1216              while (sdp->parent_obj)
1217                {
1218                   sdp = eo_data_scope_get(sdp->parent_obj, MY_CLASS);
1219
1220                   if (sdp->child_can_focus) break;
1221
1222                   sdp->child_can_focus = EINA_TRUE;
1223                }
1224           }
1225      }
1226    else
1227      {
1228         void *data = evas_object_data_get(sobj, "elm-parent");
1229
1230         if (data)
1231           {
1232              if (data == obj) goto end;
1233              if (!elm_widget_sub_object_del(data, sobj)) return EINA_FALSE;
1234           }
1235      }
1236    sd->subobjs = eina_list_append(sd->subobjs, sobj);
1237    evas_object_data_set(sobj, "elm-parent", obj);
1238
1239    _callbacks_add(sobj, obj);
1240    if (_elm_widget_is(sobj))
1241      {
1242         ELM_WIDGET_DATA_GET(sobj, sdc);
1243
1244         /* NOTE: In the following two lines, 'sobj' is correct. Do not change it.
1245          * Due to elementary's scale policy, scale and pscale can be different in
1246          * some cases. This happens when sobj's previous parent and new parent have
1247          * different scale value.
1248          * For example, if sobj's previous parent's scale is 5 and new parent's scale
1249          * is 2 while sobj's scale is 0. Then 'pscale' is 5 and 'scale' is 2. So we
1250          * need to reset sobj's scale to 5.
1251          * Note that each widget's scale is 0 by default.
1252          */
1253         double scale, pscale = elm_widget_scale_get(sobj);
1254         Elm_Theme *th, *pth = elm_widget_theme_get(sobj);
1255
1256         scale = elm_widget_scale_get(sobj);
1257         th = elm_widget_theme_get(sobj);
1258         mirrored = elm_widget_mirrored_get(sobj);
1259
1260         if (!sdc->on_create)
1261           {
1262              if ((scale != pscale) || (th != pth) || (pmirrored != mirrored))
1263                elm_widget_theme(sobj);
1264           }
1265
1266         if (_is_focused(sobj)) _parents_focus(obj);
1267
1268         elm_widget_display_mode_set(sobj,
1269               evas_object_size_hint_display_mode_get(obj));
1270         if (_elm_atspi_enabled() && !sdc->on_create)
1271           {
1272              Elm_Interface_Atspi_Accessible *aparent;
1273              eo_do(sobj, aparent = elm_interface_atspi_accessible_parent_get());
1274              if (obj == aparent)
1275                 elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, sobj);
1276           }
1277
1278         /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
1279         if (sdc->inherit_paragraph_direction &&
1280             (sdc->paragraph_direction != evas_object_paragraph_direction_get(obj)))
1281           {
1282              sdc->paragraph_direction = evas_object_paragraph_direction_get(obj);
1283              _elm_widget_evas_object_paragraph_direction_set_internal(sobj, sdc, sdc->paragraph_direction);
1284              eo_do_super(sobj, MY_CLASS, evas_obj_paragraph_direction_set(sdc->paragraph_direction));
1285           }
1286         /* END */
1287      }
1288
1289 end:
1290    return EINA_TRUE;
1291 }
1292
1293 EOLIAN static Eina_Bool
1294 _elm_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1295 {
1296    Evas_Object *sobj_parent;
1297
1298    if (!sobj) return EINA_FALSE;
1299
1300    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1301
1302    sobj_parent = evas_object_data_del(sobj, "elm-parent");
1303    if (sobj_parent && sobj_parent != obj)
1304      {
1305         static int abort_on_warn = -1;
1306
1307         ERR("removing sub object %p (%s) from parent %p (%s), "
1308             "but elm-parent is different %p (%s)!",
1309             sobj, elm_widget_type_get(sobj), obj, elm_widget_type_get(obj),
1310             sobj_parent, elm_widget_type_get(sobj_parent));
1311
1312         if (EINA_UNLIKELY(abort_on_warn == -1))
1313           {
1314              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
1315              else abort_on_warn = 0;
1316           }
1317         if (abort_on_warn == 1) abort();
1318
1319         return EINA_FALSE;
1320      }
1321
1322    if (_elm_widget_is(sobj))
1323      {
1324         if (_is_focused(sobj))
1325           {
1326              elm_widget_tree_unfocusable_set(sobj, EINA_TRUE);
1327              elm_widget_tree_unfocusable_set(sobj, EINA_FALSE);
1328           }
1329         if ((sd->child_can_focus) && (_is_focusable(sobj)))
1330           {
1331              Evas_Object *parent = obj;
1332
1333              /* update child focusable-ness on self and parents, now that a
1334               * focusable child is gone */
1335              while (parent)
1336                {
1337                   const Eina_List *l;
1338                   Evas_Object *subobj;
1339
1340                   ELM_WIDGET_DATA_GET(parent, sdp);
1341
1342                   sdp->child_can_focus = EINA_FALSE;
1343                   EINA_LIST_FOREACH(sdp->subobjs, l, subobj)
1344                     {
1345                        if ((subobj != sobj) && (_is_focusable(subobj)))
1346                          {
1347                             sdp->child_can_focus = EINA_TRUE;
1348                             break;
1349                          }
1350                     }
1351
1352                   /* break again, child_can_focus went back to
1353                    * original value */
1354                   if (sdp->child_can_focus) break;
1355                   parent = sdp->parent_obj;
1356                }
1357           }
1358         if (_elm_atspi_enabled() && !sd->on_destroy)
1359           {
1360              Elm_Interface_Atspi_Accessible *aparent;
1361              eo_do(sobj, aparent = elm_interface_atspi_accessible_parent_get());
1362              if (obj == aparent)
1363                 elm_interface_atspi_accessible_children_changed_del_signal_emit(obj, sobj);
1364           }
1365
1366         ELM_WIDGET_DATA_GET(sobj, sdc);
1367         sdc->parent_obj = NULL;
1368
1369         /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
1370         if (sdc->inherit_paragraph_direction &&
1371             (sdc->paragraph_direction != EVAS_BIDI_DIRECTION_NEUTRAL))
1372           {
1373              sdc->paragraph_direction = EVAS_BIDI_DIRECTION_NEUTRAL;
1374              _elm_widget_evas_object_paragraph_direction_set_internal(sobj, sdc, sdc->paragraph_direction);
1375              eo_do_super(sobj, MY_CLASS, evas_obj_paragraph_direction_set(EVAS_BIDI_DIRECTION_NEUTRAL));
1376           }
1377         /* END */
1378      }
1379
1380    if (sd->resize_obj == sobj) sd->resize_obj = NULL;
1381
1382    sd->subobjs = eina_list_remove(sd->subobjs, sobj);
1383
1384    _callbacks_del(sobj, obj);
1385
1386    return EINA_TRUE;
1387 }
1388
1389 /*
1390  * @internal
1391  *
1392  * a resize object is added to and deleted from the smart member and the sub object
1393  * of the parent if the third argument, Eina_Bool sub_obj, is set as EINA_TRUE.
1394  */
1395 EOLIAN static void
1396 _elm_widget_resize_object_set(Eo *obj, Elm_Widget_Smart_Data *sd,
1397                              Evas_Object *sobj,
1398                              Eina_Bool sub_obj)
1399 {
1400    Evas_Object *parent;
1401
1402    if (sd->resize_obj == sobj) return;
1403
1404    // orphan previous resize obj
1405    if (sd->resize_obj && sub_obj)
1406      {
1407         evas_object_clip_unset(sd->resize_obj);
1408         evas_object_smart_member_del(sd->resize_obj);
1409
1410         if (_elm_widget_is(sd->resize_obj))
1411           {
1412              if (_is_focused(sd->resize_obj)) _parents_unfocus(obj);
1413           }
1414         elm_widget_sub_object_del(obj, sd->resize_obj);
1415      }
1416
1417    sd->resize_obj = sobj;
1418    if (!sobj) return;
1419
1420    // orphan new resize obj
1421    parent = evas_object_data_get(sobj, "elm-parent");
1422    if (parent && parent != obj)
1423      {
1424         ELM_WIDGET_DATA_GET(parent, sdp);
1425
1426         /* should be there, just being paranoid */
1427         if (sdp)
1428           {
1429              if (sdp->resize_obj == sobj)
1430                elm_widget_resize_object_set(parent, NULL, sub_obj);
1431              else if (sub_obj)
1432                elm_widget_sub_object_del(parent, sobj);
1433           }
1434      }
1435    if (sub_obj)
1436      {
1437         elm_widget_sub_object_add(obj, sobj);
1438         evas_object_smart_member_add(sobj, obj);
1439      }
1440
1441    _smart_reconfigure(sd);
1442 }
1443
1444 /*
1445  * @internal
1446  *
1447  * WARNING: the programmer is responsible, in the scenario of
1448  * exchanging a hover object, of cleaning the old hover "target"
1449  * before
1450  */
1451 EOLIAN static void
1452 _elm_widget_hover_object_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1453 {
1454    if (sd->hover_obj)
1455      {
1456         _callbacks_del(sd->hover_obj, obj);
1457      }
1458    sd->hover_obj = sobj;
1459    if (sd->hover_obj)
1460      {
1461         _callbacks_add(sobj, obj);
1462         _smart_reconfigure(sd);
1463      }
1464 }
1465
1466 EOLIAN static void
1467 _elm_widget_can_focus_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool can_focus)
1468 {
1469    can_focus = !!can_focus;
1470
1471    if (sd->can_focus == can_focus) return;
1472    sd->can_focus = can_focus;
1473    if (sd->can_focus)
1474      {
1475         /* update child_can_focus of parents */
1476         Evas_Object *o = obj;
1477
1478         for (;;)
1479           {
1480              o = elm_widget_parent_get(o);
1481              if (!o) break;
1482              sd = eo_data_scope_get(o, MY_CLASS);
1483              if (!sd || sd->child_can_focus) break;
1484              sd->child_can_focus = EINA_TRUE;
1485           }
1486
1487         eo_do(obj, eo_event_callback_array_add(focus_callbacks(), NULL));
1488      }
1489    else
1490      {
1491         // update child_can_focus of parents */
1492         Evas_Object *parent = elm_widget_parent_get(obj);
1493         while (parent)
1494           {
1495              const Eina_List *l;
1496              Evas_Object *subobj;
1497
1498              ELM_WIDGET_DATA_GET(parent, sdp);
1499
1500              sdp->child_can_focus = EINA_FALSE;
1501              EINA_LIST_FOREACH(sdp->subobjs, l, subobj)
1502                {
1503                   if (_is_focusable(subobj))
1504                     {
1505                        sdp->child_can_focus = EINA_TRUE;
1506                        break;
1507                     }
1508                }
1509              /* break again, child_can_focus went back to
1510               * original value */
1511              if (sdp->child_can_focus) break;
1512              parent = sdp->parent_obj;
1513           }
1514         eo_do(obj, eo_event_callback_array_del(focus_callbacks(), NULL));
1515      }
1516 }
1517
1518 EOLIAN static Eina_Bool
1519 _elm_widget_can_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1520 {
1521    return sd->can_focus;
1522 }
1523
1524 EOLIAN static Eina_Bool
1525 _elm_widget_child_can_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1526 {
1527    return sd->child_can_focus;
1528 }
1529
1530 /**
1531  * @internal
1532  *
1533  * This API makes the widget object and its children to be unfocusable.
1534  *
1535  * This API can be helpful for an object to be deleted.
1536  * When an object will be deleted soon, it and its children may not
1537  * want to get focus (by focus reverting or by other focus controls).
1538  * Then, just use this API before deleting.
1539  *
1540  * @param obj The widget root of sub-tree
1541  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1542  *
1543  * @ingroup Widget
1544  */
1545 EOLIAN static void
1546 _elm_widget_tree_unfocusable_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool tree_unfocusable)
1547 {
1548    tree_unfocusable = !!tree_unfocusable;
1549    if (sd->tree_unfocusable == tree_unfocusable) return;
1550    sd->tree_unfocusable = tree_unfocusable;
1551    elm_widget_focus_tree_unfocusable_handle(obj);
1552 }
1553
1554 /**
1555  * @internal
1556  *
1557  * This returns true, if the object sub-tree is unfocusable.
1558  *
1559  * @param obj The widget root of sub-tree
1560  * @return EINA_TRUE if the object sub-tree is unfocusable
1561  *
1562  * @ingroup Widget
1563  */
1564 EOLIAN static Eina_Bool
1565 _elm_widget_tree_unfocusable_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1566 {
1567    return sd->tree_unfocusable;
1568 }
1569
1570 /**
1571  * @internal
1572  *
1573  * Get the list of focusable child objects.
1574  *
1575  * This function retruns list of child objects which can get focus.
1576  *
1577  * @param obj The parent widget
1578  * @retrun list of focusable child objects.
1579  *
1580  * @ingroup Widget
1581  */
1582 EOLIAN static Eina_List*
1583 _elm_widget_can_focus_child_list_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1584 {
1585    const Eina_List *l;
1586    Eina_List *child_list = NULL;
1587    Evas_Object *child;
1588
1589    EINA_LIST_FOREACH(sd->subobjs, l, child)
1590      {
1591         if (!_elm_widget_is(child)) continue;
1592         if ((elm_widget_can_focus_get(child)) &&
1593             (evas_object_visible_get(child)) &&
1594             (!elm_widget_disabled_get(child)))
1595           child_list = eina_list_append(child_list, child);
1596         else
1597           {
1598              Eina_List *can_focus_list;
1599              can_focus_list = elm_widget_can_focus_child_list_get(child);
1600              if (can_focus_list)
1601                child_list = eina_list_merge(child_list, can_focus_list);
1602           }
1603      }
1604
1605    return child_list;
1606 }
1607
1608 EOLIAN static void
1609 _elm_widget_highlight_ignore_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool ignore)
1610 {
1611    sd->highlight_ignore = !!ignore;
1612 }
1613
1614 EOLIAN static Eina_Bool
1615 _elm_widget_highlight_ignore_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1616 {
1617    return sd->highlight_ignore;
1618 }
1619
1620 EOLIAN static void
1621 _elm_widget_highlight_in_theme_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool highlight)
1622 {
1623    sd->highlight_in_theme = !!highlight;
1624    /* FIXME: if focused, it should switch from one mode to the other */
1625 }
1626
1627 void
1628 _elm_widget_highlight_in_theme_update(Eo *obj)
1629 {
1630    Evas_Object *top = elm_widget_top_get(obj);
1631
1632    if (top && eo_isa(top, ELM_WIN_CLASS))
1633      {
1634         _elm_win_focus_highlight_in_theme_update(
1635            top, elm_widget_highlight_in_theme_get(obj));
1636      }
1637 }
1638
1639 EOLIAN static Eina_Bool
1640 _elm_widget_highlight_in_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1641 {
1642    return sd->highlight_in_theme;
1643 }
1644
1645 EOLIAN static void
1646 _elm_widget_access_highlight_in_theme_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Bool highlight)
1647 {
1648    sd->access_highlight_in_theme = !!highlight;
1649 }
1650
1651 EOLIAN static Eina_Bool
1652 _elm_widget_access_highlight_in_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1653 {
1654    return sd->access_highlight_in_theme;
1655 }
1656
1657 EOLIAN static Eina_Bool
1658 _elm_widget_focus_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1659 {
1660    return (sd->focused && sd->top_win_focused);
1661 }
1662
1663 EOLIAN static Eina_Bool
1664 _elm_widget_highlight_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1665 {
1666    return sd->highlighted;
1667 }
1668
1669 EOLIAN static Evas_Object*
1670 _elm_widget_focused_object_get(Eo *obj, Elm_Widget_Smart_Data *sd)
1671 {
1672    const Evas_Object *subobj;
1673    const Eina_List *l;
1674
1675    if (!sd->focused || !sd->top_win_focused) return NULL;
1676    EINA_LIST_FOREACH(sd->subobjs, l, subobj)
1677      {
1678         Evas_Object *fobj;
1679         if (!_elm_widget_is(subobj)) continue;
1680         fobj = elm_widget_focused_object_get(subobj);
1681         if (fobj) return fobj;
1682      }
1683    return (Evas_Object *)obj;
1684 }
1685
1686 EOLIAN static Evas_Object*
1687 _elm_widget_top_get(Eo *obj, Elm_Widget_Smart_Data *sd)
1688 {
1689    if (sd->parent_obj)
1690      {
1691         Evas_Object *ret = NULL;
1692         if (!eo_isa(sd->parent_obj, ELM_WIDGET_CLASS)) return NULL;
1693         eo_do((Eo *) sd->parent_obj, ret = elm_obj_widget_top_get());
1694         return ret;
1695      }
1696    return (Evas_Object *)obj;
1697 }
1698
1699 EAPI Eina_Bool
1700 elm_widget_is(const Evas_Object *obj)
1701 {
1702    return _elm_widget_is(obj);
1703 }
1704
1705 EAPI Evas_Object *
1706 elm_widget_parent_widget_get(const Evas_Object *obj)
1707 {
1708    Evas_Object *parent;
1709
1710    if (_elm_widget_is(obj))
1711      {
1712         ELM_WIDGET_DATA_GET(obj, sd);
1713         if (!sd) return NULL;
1714         parent = sd->parent_obj;
1715      }
1716    else
1717      {
1718         parent = evas_object_data_get(obj, "elm-parent");
1719         if (!parent) parent = evas_object_smart_parent_get(obj);
1720      }
1721
1722    while (parent)
1723      {
1724         Evas_Object *elm_parent;
1725         if (_elm_widget_is(parent)) break;
1726         elm_parent = evas_object_data_get(parent, "elm-parent");
1727         if (elm_parent) parent = elm_parent;
1728         else parent = evas_object_smart_parent_get(parent);
1729      }
1730    return parent;
1731 }
1732
1733 EOLIAN static Evas_Object *
1734 _elm_widget_parent2_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1735 {
1736    return sd->parent2;
1737 }
1738
1739 EOLIAN static void
1740 _elm_widget_parent2_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *parent)
1741 {
1742    sd->parent2 = parent;
1743 }
1744
1745 EOLIAN static void
1746 _elm_widget_event_callback_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Event_Cb func, const void *data)
1747 {
1748    EINA_SAFETY_ON_NULL_RETURN(func);
1749
1750    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
1751    if (!ecb)
1752      {
1753         ERR("Failed to allocate memory");
1754         return;
1755      }
1756    ecb->func = func;
1757    ecb->data = data;
1758    sd->event_cb = eina_list_append(sd->event_cb, ecb);
1759 }
1760
1761 EOLIAN static void*
1762 _elm_widget_event_callback_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Event_Cb func, const void *data)
1763 {
1764    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
1765    Eina_List *l;
1766    Elm_Event_Cb_Data *ecd;
1767    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
1768      if ((ecd->func == func) && (ecd->data == data))
1769        {
1770           free(ecd);
1771           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
1772           return (void *)data;
1773        }
1774
1775    return NULL;
1776 }
1777
1778 EOLIAN static Eina_Bool
1779 _elm_widget_event_propagate(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Callback_Type type, void *event_info, Evas_Event_Flags *event_flags)
1780 {
1781    Evas_Object *parent = obj;
1782    Elm_Event_Cb_Data *ecd;
1783    Eina_List *l, *l_prev;
1784
1785    while (parent &&
1786           (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
1787      {
1788         ELM_WIDGET_CHECK(parent) EINA_FALSE;
1789         Elm_Widget_Smart_Data *sd = eo_data_scope_get(parent, MY_CLASS);
1790
1791         Eina_Bool int_ret = EINA_FALSE;
1792
1793         if (elm_widget_disabled_get(obj))
1794           {
1795              parent = sd->parent_obj;
1796              continue;
1797           }
1798
1799         eo_do(parent, int_ret = elm_obj_widget_event(obj, type, event_info));
1800         if (int_ret) return EINA_TRUE;
1801
1802         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
1803           {
1804              if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
1805                  (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
1806                 return EINA_TRUE;
1807           }
1808         parent = sd->parent_obj;
1809      }
1810
1811    return EINA_FALSE;
1812 }
1813
1814 /**
1815  * @internal
1816  *
1817  * Set custom focus chain.
1818  *
1819  * This function i set one new and overwrite any previous custom focus chain
1820  * with the list of objects. The previous list will be deleted and this list
1821  * will be managed. After setted, don't modity it.
1822  *
1823  * @note On focus cycle, only will be evaluated children of this container.
1824  *
1825  * @param obj The container widget
1826  * @param objs Chain of objects to pass focus
1827  * @ingroup Widget
1828  */
1829 EOLIAN static void
1830 _elm_widget_focus_custom_chain_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_List *objs)
1831 {
1832    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1833
1834    elm_widget_focus_custom_chain_unset(obj);
1835
1836    Eina_List *l;
1837    Evas_Object *o;
1838
1839    EINA_LIST_FOREACH(objs, l, o)
1840      {
1841         evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
1842                                        _elm_object_focus_chain_del_cb, obj);
1843      }
1844
1845    sd->focus_chain = objs;
1846 }
1847
1848 /**
1849  * @internal
1850  *
1851  * Get custom focus chain
1852  *
1853  * @param obj The container widget
1854  * @ingroup Widget
1855  */
1856 EOLIAN static const Eina_List*
1857 _elm_widget_focus_custom_chain_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1858 {
1859    return (const Eina_List *)sd->focus_chain;
1860 }
1861
1862 /**
1863  * @internal
1864  *
1865  * Unset custom focus chain
1866  *
1867  * @param obj The container widget
1868  * @ingroup Widget
1869  */
1870 EOLIAN static void
1871 _elm_widget_focus_custom_chain_unset(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1872 {
1873    Eina_List *l, *l_next;
1874    Evas_Object *o;
1875
1876    EINA_LIST_FOREACH_SAFE(sd->focus_chain, l, l_next, o)
1877      {
1878         evas_object_event_callback_del_full(o, EVAS_CALLBACK_DEL,
1879                                             _elm_object_focus_chain_del_cb, obj);
1880         sd->focus_chain = eina_list_remove_list(sd->focus_chain, l);
1881      }
1882 }
1883
1884 /**
1885  * @internal
1886  *
1887  * Append object to custom focus chain.
1888  *
1889  * @note If relative_child equal to NULL or not in custom chain, the object
1890  * will be added in end.
1891  *
1892  * @note On focus cycle, only will be evaluated children of this container.
1893  *
1894  * @param obj The container widget
1895  * @param child The child to be added in custom chain
1896  * @param relative_child The relative object to position the child
1897  * @ingroup Widget
1898  */
1899 EOLIAN static void
1900 _elm_widget_focus_custom_chain_append(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *child, Evas_Object *relative_child)
1901 {
1902    EINA_SAFETY_ON_NULL_RETURN(child);
1903
1904    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1905
1906    evas_object_event_callback_add(child, EVAS_CALLBACK_DEL,
1907                                   _elm_object_focus_chain_del_cb, obj);
1908
1909    if (!relative_child)
1910      sd->focus_chain = eina_list_append(sd->focus_chain, child);
1911    else
1912      sd->focus_chain = eina_list_append_relative(sd->focus_chain,
1913                                                  child, relative_child);
1914 }
1915
1916 /**
1917  * @internal
1918  *
1919  * Prepend object to custom focus chain.
1920  *
1921  * @note If relative_child equal to NULL or not in custom chain, the object
1922  * will be added in begin.
1923  *
1924  * @note On focus cycle, only will be evaluated children of this container.
1925  *
1926  * @param obj The container widget
1927  * @param child The child to be added in custom chain
1928  * @param relative_child The relative object to position the child
1929  * @ingroup Widget
1930  */
1931 EOLIAN static void
1932 _elm_widget_focus_custom_chain_prepend(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *child, Evas_Object *relative_child)
1933 {
1934    EINA_SAFETY_ON_NULL_RETURN(child);
1935
1936    if (!_elm_widget_focus_chain_manager_is(obj)) return;
1937
1938    evas_object_event_callback_add(child, EVAS_CALLBACK_DEL,
1939                                   _elm_object_focus_chain_del_cb, obj);
1940
1941    if (!relative_child)
1942      sd->focus_chain = eina_list_prepend(sd->focus_chain, child);
1943    else
1944      sd->focus_chain = eina_list_prepend_relative(sd->focus_chain,
1945                                                   child, relative_child);
1946 }
1947
1948 /**
1949  * @internal
1950  *
1951  * Give focus to next object in object tree.
1952  *
1953  * Give focus to next object in focus chain of one object sub-tree.
1954  * If the last object of chain already have focus, the focus will go to the
1955  * first object of chain.
1956  *
1957  * @param obj The widget root of sub-tree
1958  * @param dir Direction to cycle the focus
1959  *
1960  * @ingroup Widget
1961  */
1962 EOLIAN static void
1963 _elm_widget_focus_cycle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Elm_Focus_Direction dir)
1964 {
1965    Evas_Object *target = NULL;
1966    Elm_Object_Item *target_item = NULL;
1967    if (!_elm_widget_is(obj))
1968      return;
1969    elm_widget_focus_next_get(obj, dir, &target, &target_item);
1970    if (target)
1971      {
1972         /* access */
1973         if (_elm_config->access_mode)
1974           {
1975              /* highlight cycle does not steal a focus, only after window gets
1976                 the ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE message,
1977                 target will steal focus, or focus its own job. */
1978              if (!_elm_access_auto_highlight_get())
1979                elm_widget_focus_steal(target, target_item);
1980
1981              _elm_access_highlight_set(target);
1982              elm_widget_focus_region_show(target);
1983           }
1984         else elm_widget_focus_steal(target, target_item);
1985      }
1986 }
1987
1988 /**
1989  * @internal
1990  *
1991  * Give focus to near object(in object tree) in one direction.
1992  *
1993  * Give focus to near object(in object tree) in direction of current
1994  * focused object.  If none focusable object in given direction or
1995  * none focused object in object tree, the focus will not change.
1996  *
1997  * @param obj The reference widget
1998  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
1999  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2000  * @return EINA_TRUE if focus is moved.
2001  *
2002  * @ingroup Widget
2003  */
2004 EOLIAN static Eina_Bool
2005 _elm_widget_focus_direction_go(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, double degree)
2006 {
2007    Evas_Object *target = NULL;
2008    Elm_Object_Item *target_item = NULL;
2009    Evas_Object *current_focused = NULL;
2010    double weight = 0.0;
2011
2012    if (!_elm_widget_is(obj)) return EINA_FALSE;
2013    if (!_is_focused(obj)) return EINA_FALSE;
2014
2015    current_focused = elm_widget_focused_object_get(obj);
2016
2017    if (elm_widget_focus_direction_get
2018          (obj, current_focused, degree, &target, &target_item, &weight))
2019      {
2020         elm_widget_focus_steal(target, NULL);
2021         return EINA_TRUE;
2022      }
2023
2024    return EINA_FALSE;
2025 }
2026
2027 double
2028 _elm_widget_focus_direction_weight_get(const Evas_Object *obj1,
2029                       const Evas_Object *obj2,
2030                       double degree)
2031 {
2032    Evas_Coord obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2;
2033    double x1, yy1, x2, yy2, xx1, yyy1, xx2, yyy2;
2034    double ax, ay, cx, cy;
2035    double weight = -1.0, g = 0.0;
2036
2037    if (obj1 == obj2) return 0.0;
2038
2039    degree -= 90.0;
2040    while (degree >= 360.0)
2041      degree -= 360.0;
2042    while (degree < 0.0)
2043      degree += 360.0;
2044
2045    evas_object_geometry_get(obj1, &obj_x1, &obj_y1, &w1, &h1);
2046    cx = obj_x1 + (w1 / 2.0);
2047    cy = obj_y1 + (h1 / 2.0);
2048    evas_object_geometry_get(obj2, &obj_x2, &obj_y2, &w2, &h2);
2049
2050    /* For overlapping cases. */
2051    if (ELM_RECTS_INTERSECT(obj_x1, obj_y1, w1, h1, obj_x2, obj_y2, w2, h2))
2052      return 0.0;
2053
2054    /* Change all points to relative one. */
2055    x1 = obj_x1 - cx;
2056    xx1 = x1 + w1;
2057    yy1 = obj_y1 - cy;
2058    yyy1 = yy1 + h1;
2059    x2 = obj_x2 - cx;
2060    xx2 = x2 + w2;
2061    yy2 = obj_y2 - cy;
2062    yyy2 = yy2 + h2;
2063
2064    /* Get crossing points (ax, ay) between obj1 and a line extending
2065     * to the direction of current degree. */
2066    if (degree == 0.0)
2067      {
2068         ax = xx1;
2069         ay = 0.0;
2070      }
2071    else if (degree == 90.0)
2072      {
2073         ax = 0.0;
2074         ay = yyy1;
2075      }
2076    else if (degree == 180.0)
2077      {
2078         ax = x1;
2079         ay = 0.0;
2080      }
2081    else if (degree == 270.0)
2082      {
2083         ax = 0.0;
2084         ay = yy1;
2085      }
2086    else
2087      {
2088         g = tan(degree * (M_PI / 180.0));
2089         if ((degree > 0.0) && (degree < 90.0))
2090           {
2091              ay = g * xx1;
2092              if (ay <= yyy1) ax = xx1;
2093              else
2094                {
2095                   ax = yyy1 / g;
2096                   ay = yyy1;
2097                }
2098           }
2099         else if ((degree > 90.0) && (degree < 180.0))
2100           {
2101              ay = g * x1;
2102              if (ay <= yyy1) ax = x1;
2103              else
2104                {
2105                   ax = yyy1 / g;
2106                   ay = yyy1;
2107                }
2108           }
2109         else if ((degree > 180.0) && (degree < 270.0))
2110           {
2111              ay = g * x1;
2112              if (ay >= yy1) ax = x1;
2113              else
2114                {
2115                   ax = yy1 / g;
2116                   ay = yy1;
2117                }
2118           }
2119         else
2120           {
2121              ay = g * xx1;
2122              if (ay >= yy1) ax = xx1;
2123              else
2124                {
2125                   ax = yy1 / g;
2126                   ay = yy1;
2127                }
2128           }
2129      }
2130
2131    /* Filter obj2, if it is not in the specific derection. */
2132    int i = 0;
2133    double rx[4] = {0.0, 0.0, 0.0, 0.0}, ry[4] = {0.0, 0.0, 0.0, 0.0};
2134    double t1, t2, u1, v1, u2, v2;
2135
2136    if ((degree == 45.0) || (degree == 225.0) || (degree == 135.0) ||
2137        (degree == 315.0))
2138      {
2139         u1 = 1.0;
2140         v1 = 0.0;
2141         u2 = 0.0;
2142         v2 = 1.0;
2143      }
2144    else
2145      {
2146         double g2 = tan((degree + 45.0) * (M_PI / 180.0));
2147         u1 = (-1.0 * g2);
2148         u2 = (1.0 / g2);
2149         v1 = v2 = 1.0;
2150      }
2151    t1 = (u1 * ax) + (v1 * ay);
2152    t2 = (u2 * ax) + (v2 * ay);
2153
2154 #define _R(x) (int)((x + 0.05) * 10.0)
2155
2156    if ((_R(t1 * ((u1 * x2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * x2) +
2157                                                             (v2 * yy2))) > 0))
2158      {
2159         rx[i] = x2;
2160         ry[i++] = yy2;
2161      }
2162    if ((_R(t1 * ((u1 * x2) + (v1 * yyy2))) > 0) && (_R(t2 * ((u2 * x2) +
2163                                                              (v2 * yyy2))) > 0))
2164      {
2165         rx[i] = x2;
2166         ry[i++] = yyy2;
2167      }
2168    if ((_R(t1 * ((u1 * xx2) + (v1 * yy2))) > 0) && (_R(t2 * ((u2 * xx2) +
2169                                                              (v2 * yy2))) > 0))
2170      {
2171         rx[i] = xx2;
2172         ry[i++] = yy2;
2173      }
2174    if ((_R(t1 * ((u1 * xx2) + (v1 * yyy2))) > 0) &&
2175        (_R(t2 * ((u2 * xx2) + (v2 * yyy2))) > 0))
2176      {
2177         rx[i] = xx2;
2178         ry[i++] = yyy2;
2179      }
2180    if (i == 0)
2181      {
2182         if (degree == 0.0)
2183           {
2184              if ((_R(xx2) < 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0;
2185           }
2186         else if (degree == 90.0)
2187           {
2188              if ((_R(yyy2) < 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0;
2189           }
2190         else if (degree == 180.0)
2191           {
2192              if ((_R(x2) > 0) || (_R(yy2) > 0) || (_R(yyy2) < 0)) return 0.0;
2193           }
2194         else if (degree == 270.0)
2195           {
2196              if ((_R(yy2) > 0) || (_R(x2) > 0) || (_R(xx2) < 0)) return 0.0;
2197           }
2198         else
2199           {
2200              if ((_R(g * x2) >= _R(yy2)) && (_R((g * x2)) <= _R(yyy2)))
2201                {
2202                   if (!((_R(ax * x2) > 0) && (_R(ay * (g * x2)) > 0)))
2203                     return 0.0;
2204                }
2205              else if ((_R(g * xx2) >= _R(yy2)) && (_R((g * xx2)) <= _R(yyy2)))
2206                {
2207                   if (!((_R(ax * xx2) > 0) && (_R(ay * (g * xx2)) > 0)))
2208                     return 0.0;
2209                }
2210              else if ((_R((1.0 / g) * yy2) >= _R(xx2)) && (_R((1.0 / g) * yy2)
2211                                                            <= _R(xx2)))
2212                {
2213                   if (!((_R(ax * ((1.0 / g) * yy2)) > 0)
2214                         && (_R(ay * yy2) > 0)))
2215                     return 0.0;
2216                }
2217              else if ((_R((1.0 / g) * yyy2) >= _R(xx2)) &&
2218                       (_R((1.0 / g) * yyy2) <= _R(xx2)))
2219                {
2220                   if (!((_R(ax * ((1.0 / g) * yyy2)) > 0)
2221                         && (_R(ay * yyy2) > 0))) return 0.0;
2222                }
2223              else return 0.0;
2224           }
2225      }
2226
2227    /* Calculate the weight for obj2. */
2228    if (degree == 0.0)
2229      {
2230         if (_R(xx1) > _R(x2)) weight = -1.0;
2231         else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1)))
2232           weight = (x2 - xx1) * (x2 - xx1);
2233         else if (_R(yy2) > 0)
2234           weight = ((x2 - xx1) * (x2 - xx1)) + (yy2 * yy2);
2235         else if (_R(yyy2) < 0)
2236           weight = ((x2 - xx1) * (x2 - xx1)) + (yyy2 * yyy2);
2237         else weight = (x2 - xx1) * (x2 - xx1);
2238      }
2239    else if (degree == 90.0)
2240      {
2241         if (_R(yyy1) > _R(yy2)) weight = -1.0;
2242         else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1)))
2243           weight = (yy2 - yyy1) * (yy2 - yyy1);
2244         else if (_R(x2) > 0)
2245           weight = (x2 * x2) + ((yy2 - yyy1) * (yy2 - yyy1));
2246         else if (_R(xx2) < 0)
2247           weight = (xx2 * xx2) + ((yy2 - yyy1) * (yy2 - yyy1));
2248         else weight = (yy2 - yyy1) * (yy2 - yyy1);
2249      }
2250    else if (degree == 180.0)
2251      {
2252         if (_R(x1) < _R(xx2)) weight = -1.0;
2253         else if ((_R(yy2) >= _R(yy1)) && (_R(yyy2) <= _R(yyy1)))
2254           weight = (x1 - xx2) * (x1 - xx2);
2255         else if (_R(yy2) > 0)
2256           weight = ((x1 - xx2) * (x1 - xx2)) + (yy2 * yy2);
2257         else if (_R(yyy2) < 0)
2258           weight = ((x1 - xx2) * (x1 - xx2)) + (yyy2 * yyy2);
2259         else weight = (x1 - xx2) * (x1 - xx2);
2260      }
2261    else if (degree == 270.0)
2262      {
2263         if (_R(yy1) < _R(yyy2)) weight = -1.0;
2264         else if ((_R(x2) >= _R(x1)) && (_R(xx2) <= _R(xx1)))
2265           weight = (yy1 - yyy2) * (yy1 - yyy2);
2266         else if (_R(x2) > 0)
2267           weight = (x2 * x2) + ((yy1 - yyy2) * (yy1 - yyy2));
2268         else if (_R(xx2) < 0)
2269           weight = (xx2 * xx2) + ((yy1 - yyy2) * (yy1 - yyy2));
2270         else weight = (yy1 - yyy2) * (yy1 - yyy2);
2271      }
2272    else
2273      {
2274         int j = 0, k = 0;
2275         double sx[4] = {0.0, 0.0, 0.0, 0.0}, sy[4] = {0.0, 0.0, 0.0, 0.0};
2276         double t_weight[4] = {-1.0, -1.0, -1.0, -1.0};
2277         if ((_R(g * x2) >= _R(yy2)) && (_R(g * x2) <= _R(yyy2)))
2278           {
2279              sx[j] = x2;
2280              sy[j] = g * x2;
2281              t_weight[j++] = ((ax - x2) * (ax - x2)) +
2282                ((ay - (g * x2)) * (ay - (g * x2)));
2283           }
2284         if ((_R(g * xx2) >= _R(yy2)) && (_R(g * xx2) <= _R(yyy2)))
2285           {
2286              sx[j] = xx2;
2287              sy[j] = g * xx2;
2288              t_weight[j++] = ((ax - xx2) * (ax - xx2)) +
2289                ((ay - (g * xx2)) * (ay - (g * xx2)));
2290           }
2291         if ((_R((1.0 / g) * yy2) >= _R(x2)) && (_R((1.0 / g) * yy2) <= _R(xx2)))
2292           {
2293              sx[j] = (1.0 / g) * yy2;
2294              sy[j] = yy2;
2295              t_weight[j++] =
2296                ((ax - ((1.0 / g) * yy2)) * (ax - ((1.0 / g) * yy2))) +
2297                ((ay - yy2) * (ay - yy2));
2298           }
2299         if ((_R((1.0 / g) * yyy2) >= _R(x2)) && (_R((1.0 / g) * yyy2)
2300                                                  <= _R(xx2)))
2301           {
2302              sx[j] = (1.0 / g) * yyy2;
2303              sy[j] = yyy2;
2304              t_weight[j++] =
2305                ((ax - ((1.0 / g) * yyy2)) * (ax - ((1.0 / g) * yyy2))) +
2306                ((ay - yyy2) * (ay - yyy2));
2307           }
2308
2309         if ((j > 2) || ((j == 2) && ((_R(sx[0]) != _R(sx[1])) ||
2310                                      (_R(sy[0]) != _R(sy[1])))))
2311           {
2312              for (; k < j; k++)
2313                {
2314                   if (_R(t_weight[k]) == 0) return -1.0;
2315                   if ((1 / weight) < (1 / t_weight[k])) weight = t_weight[k];
2316                }
2317           }
2318         else
2319           {
2320              for (; k < i; k++)
2321                {
2322                   double ccx, ccy, t1_weight, x_diff, y_diff;
2323                   ccx = ((1.0 / g) * rx[k] + ry[k]) / (g + (1.0 / g));
2324                   ccy = g * ccx;
2325                   x_diff = rx[k] - ccx;
2326                   if (x_diff < 0) x_diff *= -1.0;
2327                   y_diff = ry[k] - ccy;
2328                   if (y_diff < 0) y_diff *= -1.0;
2329                   t1_weight =
2330                     (((ax - ccx) * (ax - ccx)) + ((ay - ccy) * (ay - ccy))) +
2331                     ((x_diff * x_diff * x_diff) + (y_diff * y_diff * y_diff));
2332                   if ((_R(t1_weight) != 0) && ((1 / weight) < (1 / t1_weight)))
2333                     weight = t1_weight;
2334                }
2335           }
2336      }
2337    /* Return the current object's weight. */
2338    if (weight == -1.0) return 0.0;
2339    if (_R(weight) == 0) return -1.0;
2340
2341 #undef _R
2342
2343    return 1.0 / weight;
2344 }
2345
2346 /**
2347  * @internal
2348  *
2349  * Get near object in one direction of base object.
2350  *
2351  * Get near object(in the object sub-tree) in one direction of
2352  * base object. Return the near object by reference.
2353  * By initializing weight, you can filter objects locating far
2354  * from base object. If object is in the specific direction,
2355  * weight is (1/(distance^2)). If object is not exactly in one
2356  * direction, some penalty will be added.
2357  *
2358  * @param obj The widget root of sub-tree
2359  * @param base The base object of the direction
2360  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2361  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2362  * @param direction The near object in one direction
2363  * @param weight The weight is bigger when the object is located near
2364  * @return EINA_TRUE if near object is updated.
2365  *
2366  * @ingroup Widget
2367  */
2368
2369 EOLIAN static Eina_Bool
2370 _elm_widget_focus_direction_get(const Eo *obj, Elm_Widget_Smart_Data *sd, const Evas_Object *base, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight)
2371 {
2372    double c_weight;
2373
2374    /* -1 means the best was already decided. Don't need any more searching. */
2375    if (!direction || !weight || !base || (obj == base))
2376      return EINA_FALSE;
2377
2378    /* Ignore if disabled */
2379    if ((!evas_object_visible_get(obj))
2380        || (elm_widget_disabled_get(obj))
2381        || (elm_widget_tree_unfocusable_get(obj)))
2382      return EINA_FALSE;
2383
2384    /* Try use hook */
2385    if (_internal_elm_widget_focus_direction_manager_is(obj))
2386      {
2387         Eina_Bool int_ret = EINA_FALSE;
2388         eo_do((Eo *)obj, int_ret = elm_obj_widget_focus_direction(base, degree, direction, direction_item, weight));
2389         return int_ret;
2390      }
2391
2392    if (!elm_widget_can_focus_get(obj) || _is_focused((Eo *)obj))
2393      return EINA_FALSE;
2394
2395    c_weight = _elm_widget_focus_direction_weight_get(base, obj, degree);
2396    if ((c_weight == -1.0) ||
2397        ((c_weight != 0.0) && (*weight != -1.0) &&
2398         ((int)(*weight * 1000000) <= (int)(c_weight * 1000000))))
2399      {
2400         if (*direction &&
2401             ((int)(*weight * 1000000) == (int)(c_weight * 1000000)))
2402           {
2403              ELM_WIDGET_DATA_GET(*direction, sd1);
2404              if (sd1)
2405                {
2406                   if (sd->focus_order <= sd1->focus_order)
2407                     return EINA_FALSE;
2408                }
2409           }
2410         *direction = (Evas_Object *)obj;
2411         *weight = c_weight;
2412         return EINA_TRUE;
2413      }
2414
2415    return EINA_FALSE;
2416 }
2417
2418 /**
2419  * @internal
2420  *
2421  * Get near object in one direction of base object in list.
2422  *
2423  * Get near object in one direction of base object in the specific
2424  * object list. Return the near object by reference.
2425  * By initializing weight, you can filter objects locating far
2426  * from base object. If object is in the specific direction,
2427  * weight is (1/(distance^2)). If object is not exactly in one
2428  * direction, some penalty will be added.
2429  *
2430  * @param obj The widget root of sub-tree
2431  * @param base The base object of the direction
2432  * @param items list with ordered objects
2433  * @param list_data_get function to get the object from one item of list
2434  * @param degree Degree changes clockwise. i.e. 0-degree: Up,
2435  *               90-degree: Right, 180-degree: Down, and 270-degree: Left
2436  * @param direction The near object in one direction
2437  * @param weight The weight is bigger when the object is located near
2438  * @return EINA_TRUE if near object is updated.
2439  *
2440  * @ingroup Widget
2441  */
2442 EOLIAN static Eina_Bool
2443 _elm_widget_focus_list_direction_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Evas_Object *base, const Eina_List *items, list_data_get_func_type list_data_get, double degree, Evas_Object **direction, Elm_Object_Item **direction_item, double *weight)
2444 {
2445    if (!direction || !weight || !base || !items)
2446      return EINA_FALSE;
2447
2448    const Eina_List *l = items;
2449    Evas_Object *current_best = *direction;
2450
2451    for (; l; l = eina_list_next(l))
2452      {
2453         Evas_Object *cur = list_data_get(l);
2454         if (cur && _elm_widget_is(cur))
2455           elm_widget_focus_direction_get(cur, base, degree, direction, direction_item, weight);
2456      }
2457    if (current_best != *direction) return EINA_TRUE;
2458
2459    return EINA_FALSE;
2460 }
2461
2462 /**
2463  * @internal
2464  *
2465  * Get next object in focus chain of object tree.
2466  *
2467  * Get next object in focus chain of one object sub-tree.
2468  * Return the next object by reference. If don't have any candidate to receive
2469  * focus before chain end, the first candidate will be returned.
2470  *
2471  * @param obj The widget root of sub-tree
2472  * @param dir Direction of focus chain
2473  * @param next The next object in focus chain
2474  * @return EINA_TRUE if don't need focus chain restart/loop back
2475  *         to use 'next' obj.
2476  *
2477  * @ingroup Widget
2478  */
2479 EOLIAN static Eina_Bool
2480 _elm_widget_focus_next_get(const Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
2481 {
2482    Elm_Access_Info *ac;
2483
2484    if (!next)
2485      return EINA_FALSE;
2486    *next = NULL;
2487
2488    /* Ignore if disabled */
2489    if (_elm_config->access_mode && _elm_access_auto_highlight_get())
2490      {
2491         if (!evas_object_visible_get(obj)
2492             || (elm_widget_tree_unfocusable_get(obj)))
2493           return EINA_FALSE;
2494      }
2495    else
2496      {
2497         if ((!evas_object_visible_get(obj))
2498             || (elm_widget_disabled_get(obj))
2499             || (elm_widget_tree_unfocusable_get(obj)))
2500           return EINA_FALSE;
2501      }
2502
2503    /* Try use hook */
2504    if (_elm_widget_focus_chain_manager_is(obj))
2505      {
2506         Eina_Bool int_ret = EINA_FALSE;
2507         eo_do((Eo *)obj, int_ret = elm_obj_widget_focus_next(dir, next, next_item));
2508         if (!int_ret && _is_focused((Eo *)obj))
2509           {
2510              Evas_Object *o = NULL;
2511              if (dir == ELM_FOCUS_PREVIOUS)
2512                *next_item = sd->item_focus_previous;
2513              else if (dir == ELM_FOCUS_NEXT)
2514                *next_item = sd->item_focus_next;
2515              else if (dir == ELM_FOCUS_UP)
2516                *next_item = sd->item_focus_up;
2517              else if (dir == ELM_FOCUS_DOWN)
2518                *next_item = sd->item_focus_down;
2519              else if (dir == ELM_FOCUS_RIGHT)
2520                *next_item = sd->item_focus_right;
2521              else if (dir == ELM_FOCUS_LEFT)
2522                *next_item = sd->item_focus_left;
2523              o = elm_object_item_widget_get(*next_item);
2524
2525              if (!o)
2526                {
2527                   if (dir == ELM_FOCUS_PREVIOUS)
2528                     o = sd->focus_previous;
2529                   else if (dir == ELM_FOCUS_NEXT)
2530                     o = sd->focus_next;
2531                   else if (dir == ELM_FOCUS_UP)
2532                     o = sd->focus_up;
2533                   else if (dir == ELM_FOCUS_DOWN)
2534                     o = sd->focus_down;
2535                   else if (dir == ELM_FOCUS_RIGHT)
2536                     o = sd->focus_right;
2537                   else if (dir == ELM_FOCUS_LEFT)
2538                     o = sd->focus_left;
2539                }
2540
2541              if (o)
2542                {
2543                   *next = o;
2544                   return EINA_TRUE;
2545                }
2546           }
2547         return int_ret;
2548      }
2549
2550    /* access object does not check sd->can_focus, because an object could
2551       have highlight even though the object is not focusable. */
2552    if (_elm_config->access_mode && _elm_access_auto_highlight_get())
2553      {
2554         ac = _elm_access_info_get(obj);
2555         if (!ac) return EINA_FALSE;
2556
2557         /* check whether the hover object is visible or not */
2558         if (!evas_object_visible_get(ac->hoverobj))
2559           return EINA_FALSE;
2560      }
2561    else if (!elm_widget_can_focus_get(obj))
2562      return EINA_FALSE;
2563
2564    if (_is_focused((Eo *)obj))
2565      {
2566         if (dir == ELM_FOCUS_PREVIOUS)
2567           *next_item = sd->item_focus_previous;
2568         else if (dir == ELM_FOCUS_NEXT)
2569           *next_item = sd->item_focus_next;
2570         else if (dir == ELM_FOCUS_UP)
2571           *next_item = sd->item_focus_up;
2572         else if (dir == ELM_FOCUS_DOWN)
2573           *next_item = sd->item_focus_down;
2574         else if (dir == ELM_FOCUS_RIGHT)
2575           *next_item = sd->item_focus_right;
2576         else if (dir == ELM_FOCUS_LEFT)
2577           *next_item = sd->item_focus_left;
2578         *next = elm_object_item_widget_get(*next_item);
2579
2580         if (!(*next))
2581           {
2582              if (dir == ELM_FOCUS_PREVIOUS)
2583                *next = sd->focus_previous;
2584              else if (dir == ELM_FOCUS_NEXT)
2585                *next = sd->focus_next;
2586              else if (dir == ELM_FOCUS_UP)
2587                *next = sd->focus_up;
2588              else if (dir == ELM_FOCUS_DOWN)
2589                *next = sd->focus_down;
2590              else if (dir == ELM_FOCUS_RIGHT)
2591                *next = sd->focus_right;
2592              else if (dir == ELM_FOCUS_LEFT)
2593                *next = sd->focus_left;
2594           }
2595
2596         if (*next) return EINA_TRUE;
2597      }
2598
2599    /* Return */
2600    *next = (Evas_Object *)obj;
2601    return !ELM_WIDGET_FOCUS_GET(obj);
2602 }
2603
2604 /**
2605  * @internal
2606  *
2607  * Get next object in focus chain of object tree in list.
2608  *
2609  * Get next object in focus chain of one object sub-tree ordered by one list.
2610  * Return the next object by reference. If don't have any candidate to receive
2611  * focus before list end, the first candidate will be returned.
2612  *
2613  * @param obj The widget root of sub-tree
2614  * @param items list with ordered objects
2615  * @param list_data_get function to get the object from one item of list
2616  * @param dir Direction of focus chain
2617  * @param next The next object in focus chain
2618  * @return EINA_TRUE if don't need focus chain restart/loop back
2619  *         to use 'next' obj.
2620  *
2621  * @ingroup Widget
2622  */
2623 EOLIAN static Eina_Bool
2624 _elm_widget_focus_list_next_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Eina_List *items, list_data_get_func_type list_data_get, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
2625 {
2626    Eina_List *(*list_next)(const Eina_List *list) = NULL;
2627    Evas_Object *focused_object = NULL;
2628
2629    if (!next)
2630      return EINA_FALSE;
2631    *next = NULL;
2632
2633    if (!_elm_widget_is(obj))
2634      return EINA_FALSE;
2635
2636    if (!items)
2637      return EINA_FALSE;
2638
2639    /* When Up, Down, Right, or Left, try direction_get first. */
2640    focused_object = elm_widget_focused_object_get(obj);
2641    if (focused_object)
2642      {
2643         if ((dir == ELM_FOCUS_UP)
2644            || (dir == ELM_FOCUS_DOWN)
2645            || (dir == ELM_FOCUS_RIGHT)
2646            || (dir == ELM_FOCUS_LEFT))
2647           {
2648              *next_item = elm_widget_focus_next_item_get(focused_object, dir);
2649              if (*next_item)
2650                *next = elm_object_item_widget_get(*next_item);
2651              else
2652                *next = elm_widget_focus_next_object_get(focused_object, dir);
2653              if (*next) return EINA_TRUE;
2654              else
2655                {
2656                   Evas_Object *n = NULL;
2657                   Elm_Object_Item *n_item = NULL;
2658                   double degree = 0;
2659                   double weight = 0.0;
2660
2661                   if (dir == ELM_FOCUS_UP) degree = 0.0;
2662                   else if (dir == ELM_FOCUS_DOWN) degree = 180.0;
2663                   else if (dir == ELM_FOCUS_RIGHT) degree = 90.0;
2664                   else if (dir == ELM_FOCUS_LEFT) degree = 270.0;
2665
2666                   if (elm_widget_focus_list_direction_get(obj, focused_object,
2667                                                           items, list_data_get,
2668                                                           degree, &n, &n_item,
2669                                                           &weight))
2670                     {
2671                        *next_item = n_item;
2672                        *next = n;
2673                        return EINA_TRUE;
2674                     }
2675                }
2676           }
2677      }
2678
2679    /* Direction */
2680    if (dir == ELM_FOCUS_PREVIOUS)
2681      {
2682         items = eina_list_last(items);
2683         list_next = eina_list_prev;
2684      }
2685    else if ((dir == ELM_FOCUS_NEXT)
2686             || (dir == ELM_FOCUS_UP)
2687             || (dir == ELM_FOCUS_DOWN)
2688             || (dir == ELM_FOCUS_RIGHT)
2689             || (dir == ELM_FOCUS_LEFT))
2690      list_next = eina_list_next;
2691    else
2692      return EINA_FALSE;
2693
2694    const Eina_List *l = items;
2695
2696    /* Recovery last focused sub item */
2697    if (ELM_WIDGET_FOCUS_GET(obj))
2698      {
2699         for (; l; l = list_next(l))
2700           {
2701              Evas_Object *cur = list_data_get(l);
2702              if (ELM_WIDGET_FOCUS_GET(cur)) break;
2703           }
2704
2705          /* Focused object, but no focused sub item */
2706          if (!l) l = items;
2707      }
2708
2709    const Eina_List *start = l;
2710    Evas_Object *to_focus = NULL;
2711    Elm_Object_Item *to_focus_item = NULL;
2712
2713    /* Iterate sub items */
2714    /* Go to the end of list */
2715    for (; l; l = list_next(l))
2716      {
2717         Evas_Object *tmp = NULL;
2718         Elm_Object_Item *tmp_item = NULL;
2719         Evas_Object *cur = list_data_get(l);
2720
2721         if (!cur) continue;
2722         if (!_elm_widget_is(cur)) continue;
2723         if (elm_widget_parent_get(cur) != obj)
2724           continue;
2725
2726         /* Try Focus cycle in subitem */
2727         if (elm_widget_focus_next_get(cur, dir, &tmp, &tmp_item))
2728           {
2729              *next = tmp;
2730              *next_item = tmp_item;
2731              return EINA_TRUE;
2732           }
2733         else if ((dir == ELM_FOCUS_UP)
2734                  || (dir == ELM_FOCUS_DOWN)
2735                  || (dir == ELM_FOCUS_RIGHT)
2736                  || (dir == ELM_FOCUS_LEFT))
2737           {
2738              if (tmp && _is_focused(cur))
2739                {
2740                   *next = tmp;
2741                   *next_item = tmp_item;
2742                   return EINA_FALSE;
2743                }
2744           }
2745         else if ((tmp) && (!to_focus))
2746           {
2747              to_focus = tmp;
2748              to_focus_item = tmp_item;
2749           }
2750      }
2751
2752    l = items;
2753
2754    /* Get First possible */
2755    for (; l != start; l = list_next(l))
2756      {
2757         Evas_Object *tmp = NULL;
2758         Elm_Object_Item *tmp_item = NULL;
2759         Evas_Object *cur = list_data_get(l);
2760
2761         if (elm_widget_parent_get(cur) != obj)
2762           continue;
2763
2764         /* Try Focus cycle in subitem */
2765         elm_widget_focus_next_get(cur, dir, &tmp, &tmp_item);
2766         if (tmp)
2767           {
2768              *next = tmp;
2769              *next_item = tmp_item;
2770              return EINA_FALSE;
2771           }
2772      }
2773
2774    *next = to_focus;
2775    *next_item = to_focus_item;
2776    return EINA_FALSE;
2777 }
2778
2779 /**
2780  * @internal
2781  *
2782  * Get next object which was set with specific focus direction.
2783  *
2784  * Get next object which was set by elm_widget_focus_next_object_set
2785  * with specific focus directioin.
2786  *
2787  * @param obj The widget
2788  * @param dir Direction of focus
2789  * @return Widget which was registered with sepecific focus direction.
2790  *
2791  * @ingroup Widget
2792  */
2793 EOLIAN static Evas_Object*
2794 _elm_widget_focus_next_object_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir)
2795 {
2796    Evas_Object *ret = NULL;
2797
2798    if (dir == ELM_FOCUS_PREVIOUS)
2799      ret = sd->focus_previous;
2800    else if (dir == ELM_FOCUS_NEXT)
2801      ret = sd->focus_next;
2802    else if (dir == ELM_FOCUS_UP)
2803      ret = sd->focus_up;
2804    else if (dir == ELM_FOCUS_DOWN)
2805      ret = sd->focus_down;
2806    else if (dir == ELM_FOCUS_RIGHT)
2807      ret = sd->focus_right;
2808    else if (dir == ELM_FOCUS_LEFT)
2809      ret = sd->focus_left;
2810
2811    return ret;
2812 }
2813
2814 /**
2815  * @internal
2816  *
2817  * Set next object with specific focus direction.
2818  *
2819  * When a widget is set with specific focus direction, this widget will be
2820  * the first candidate when finding the next focus object.
2821  * Focus next object can be registered with six directions that are previous,
2822  * next, up, down, right, and left.
2823  *
2824  * @param obj The widget
2825  * @param next Next focus object
2826  * @param dir Direction of focus
2827  *
2828  * @ingroup Widget
2829  */
2830 EOLIAN static void
2831 _elm_widget_focus_next_object_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Object *next, Elm_Focus_Direction dir)
2832 {
2833
2834    if (dir == ELM_FOCUS_PREVIOUS)
2835      sd->focus_previous = next;
2836    else if (dir == ELM_FOCUS_NEXT)
2837      sd->focus_next = next;
2838    else if (dir == ELM_FOCUS_UP)
2839      sd->focus_up = next;
2840    else if (dir == ELM_FOCUS_DOWN)
2841      sd->focus_down = next;
2842    else if (dir == ELM_FOCUS_RIGHT)
2843      sd->focus_right = next;
2844    else if (dir == ELM_FOCUS_LEFT)
2845      sd->focus_left = next;
2846 }
2847
2848 EOLIAN static Elm_Object_Item*
2849 _elm_widget_focus_next_item_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Direction dir)
2850 {
2851    Elm_Object_Item *ret = NULL;
2852
2853    if (dir == ELM_FOCUS_PREVIOUS)
2854      ret = sd->item_focus_previous;
2855    else if (dir == ELM_FOCUS_NEXT)
2856      ret = sd->item_focus_next;
2857    else if (dir == ELM_FOCUS_UP)
2858      ret = sd->item_focus_up;
2859    else if (dir == ELM_FOCUS_DOWN)
2860      ret = sd->item_focus_down;
2861    else if (dir == ELM_FOCUS_RIGHT)
2862      ret = sd->item_focus_right;
2863    else if (dir == ELM_FOCUS_LEFT)
2864      ret = sd->item_focus_left;
2865
2866    return ret;
2867 }
2868
2869 EOLIAN static void
2870 _elm_widget_focus_next_item_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Object_Item *next_item, Elm_Focus_Direction dir)
2871 {
2872    if (dir == ELM_FOCUS_PREVIOUS)
2873      sd->item_focus_previous = next_item;
2874    else if (dir == ELM_FOCUS_NEXT)
2875      sd->item_focus_next = next_item;
2876    else if (dir == ELM_FOCUS_UP)
2877      sd->item_focus_up = next_item;
2878    else if (dir == ELM_FOCUS_DOWN)
2879      sd->item_focus_down = next_item;
2880    else if (dir == ELM_FOCUS_RIGHT)
2881      sd->item_focus_right = next_item;
2882    else if (dir == ELM_FOCUS_LEFT)
2883      sd->item_focus_left = next_item;
2884 }
2885
2886 EOLIAN static void
2887 _elm_widget_parent_highlight_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool highlighted)
2888 {
2889    highlighted = !!highlighted;
2890
2891    Evas_Object *o = elm_widget_parent_get(obj);
2892
2893    if (o) elm_widget_parent_highlight_set(o, highlighted);
2894
2895    sd->highlighted = highlighted;
2896 }
2897
2898 EOLIAN static void
2899 _elm_widget_signal_emit(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *emission, const char *source)
2900 {
2901    if (evas_object_smart_type_check(obj, "elm_layout"))
2902      elm_layout_signal_emit(obj, emission, source);
2903    else if (evas_object_smart_type_check(obj, "elm_icon"))
2904      {
2905         WRN("Deprecated function. This functionality on icon objects"
2906             " will be dropped on a next release.");
2907         _elm_icon_signal_emit(obj, emission, source);
2908      }
2909 }
2910
2911 EOLIAN static void
2912 _elm_widget_signal_callback_add(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func, void *data)
2913 {
2914    EINA_SAFETY_ON_NULL_RETURN(func);
2915
2916    if (evas_object_smart_type_check(obj, "elm_layout"))
2917      elm_layout_signal_callback_add(obj, emission, source, func, data);
2918    else if (evas_object_smart_type_check(obj, "elm_icon"))
2919      {
2920         WRN("Deprecated function. This functionality on icon objects"
2921             " will be dropped on a next release.");
2922
2923         _elm_icon_signal_callback_add(obj, emission, source, func, data);
2924      }
2925 }
2926
2927 EOLIAN static void*
2928 _elm_widget_signal_callback_del(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *emission, const char *source, Edje_Signal_Cb func)
2929 {
2930    void *data = NULL;
2931
2932    if (evas_object_smart_type_check(obj, "elm_layout"))
2933      data = elm_layout_signal_callback_del(obj, emission, source, func);
2934    else if (evas_object_smart_type_check(obj, "elm_icon"))
2935      {
2936         WRN("Deprecated function. This functionality on icon objects"
2937             " will be dropped on a next release.");
2938
2939         data = _elm_icon_signal_callback_del(obj, emission, source, func);
2940      }
2941
2942    return data;
2943 }
2944
2945 EOLIAN static void
2946 _elm_widget_focus_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool focus)
2947 {
2948    if (!sd->focused)
2949      {
2950         focus_order++;
2951         sd->focus_order = focus_order;
2952         sd->focused = EINA_TRUE;
2953         eo_do(obj, elm_obj_widget_on_focus(NULL));
2954      }
2955
2956    if (focus)
2957      {
2958         if ((_is_focusable(sd->resize_obj)) &&
2959             (!elm_widget_disabled_get(sd->resize_obj)))
2960           {
2961              elm_widget_focus_set(sd->resize_obj, focus);
2962           }
2963         else
2964           {
2965              const Eina_List *l;
2966              Evas_Object *child;
2967
2968              EINA_LIST_FOREACH(sd->subobjs, l, child)
2969                {
2970                   if (!_elm_widget_is(child)) continue;
2971                   if ((_is_focusable(child)) &&
2972                       (!elm_widget_disabled_get(child)))
2973                     {
2974                        elm_widget_focus_set(child, focus);
2975                        break;
2976                     }
2977                }
2978           }
2979      }
2980    else
2981      {
2982         const Eina_List *l;
2983         Evas_Object *child;
2984
2985         EINA_LIST_REVERSE_FOREACH(sd->subobjs, l, child)
2986           {
2987              if (!_elm_widget_is(child)) continue;
2988              if ((_is_focusable(child)) &&
2989                  (!elm_widget_disabled_get(child)))
2990                {
2991                   elm_widget_focus_set(child, focus);
2992                   break;
2993                }
2994           }
2995      }
2996 }
2997
2998 EOLIAN static Evas_Object*
2999 _elm_widget_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3000 {
3001    return sd->parent_obj;
3002 }
3003
3004 EOLIAN static void
3005 _elm_widget_focused_object_clear(Eo *obj, Elm_Widget_Smart_Data *sd)
3006 {
3007    if (!sd->focused) return;
3008    if (sd->resize_obj && elm_widget_is(sd->resize_obj) &&
3009        _is_focused(sd->resize_obj))
3010      {
3011         eo_do(sd->resize_obj, elm_obj_widget_focused_object_clear());
3012      }
3013    else
3014      {
3015         const Eina_List *l;
3016         Evas_Object *child;
3017         EINA_LIST_FOREACH(sd->subobjs, l, child)
3018           {
3019              if (_elm_widget_is(child) && _is_focused(child))
3020                {
3021                   eo_do(child, elm_obj_widget_focused_object_clear());
3022                   break;
3023                }
3024           }
3025      }
3026    sd->focused = EINA_FALSE;
3027    if (sd->top_win_focused)
3028      eo_do(obj, elm_obj_widget_on_focus(NULL));
3029 }
3030
3031 EOLIAN static void
3032 _elm_widget_focus_steal(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Object_Item *item)
3033 {
3034    Evas_Object *parent, *parent2, *o;
3035
3036    if (sd->focused) return;
3037    if (sd->disabled) return;
3038    if (!sd->can_focus) return;
3039    if (sd->tree_unfocusable) return;
3040    parent = obj;
3041    for (;; )
3042      {
3043         o = elm_widget_parent_get(parent);
3044         if (!o) break;
3045         sd = eo_data_scope_get(o, MY_CLASS);
3046         if (sd->disabled || sd->tree_unfocusable) return;
3047         if (sd->focused) break;
3048         parent = o;
3049      }
3050    if ((!elm_widget_parent_get(parent)) &&
3051        (!elm_widget_parent2_get(parent)))
3052      eo_do(parent, elm_obj_widget_focused_object_clear());
3053    else
3054      {
3055         parent2 = elm_widget_parent_get(parent);
3056         if (!parent2) parent2 = elm_widget_parent2_get(parent);
3057         parent = parent2;
3058         sd = eo_data_scope_get(parent, MY_CLASS);
3059         if (sd)
3060           {
3061              if (sd->resize_obj && elm_widget_is(sd->resize_obj) &&
3062                    _is_focused(sd->resize_obj))
3063                {
3064                   eo_do(sd->resize_obj, elm_obj_widget_focused_object_clear());
3065                }
3066              else
3067                {
3068                   const Eina_List *l;
3069                   Evas_Object *child;
3070                   EINA_LIST_FOREACH(sd->subobjs, l, child)
3071                     {
3072                        if (_elm_widget_is(child) && _is_focused(child))
3073                          {
3074                             eo_do(child, elm_obj_widget_focused_object_clear());
3075                             break;
3076                          }
3077                     }
3078                }
3079           }
3080      }
3081    /* TIZEN_ONLY(20161212): Some winsets should know whether it's focus target or not in _on_focus */
3082    sd = eo_data_scope_get(obj, MY_CLASS);
3083    sd->is_focus_target = EINA_TRUE;
3084    //
3085    _parent_focus(obj, item);
3086    /* TIZEN_ONLY(20161212): Some winsets should know whether it's focus target or not in _on_focus */
3087    sd->is_focus_target = EINA_FALSE;
3088    //
3089    elm_widget_focus_region_show(obj);
3090    return;
3091 }
3092
3093 static void
3094 _parents_on_focus(Evas_Object *obj)
3095 {
3096    API_ENTRY return;
3097    if (!sd->focused || !sd->top_win_focused) return;
3098
3099    Evas_Object *o = elm_widget_parent_get(obj);
3100    if (o) _parents_on_focus(o);
3101    eo_do(obj, elm_obj_widget_on_focus(NULL));
3102 }
3103
3104 EOLIAN static void
3105 _elm_widget_focus_restore(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
3106 {
3107    Evas_Object *newest = NULL;
3108    unsigned int newest_focus_order = 0;
3109
3110    newest = elm_widget_newest_focus_order_get(obj, &newest_focus_order, EINA_TRUE);
3111    if (newest)
3112      _parents_on_focus(newest);
3113 }
3114
3115 void
3116 _elm_widget_focus_auto_show(Evas_Object *obj)
3117 {
3118    Evas_Object *top = elm_widget_top_get(obj);
3119    if (top && eo_isa(top, ELM_WIN_CLASS)) _elm_win_focus_auto_show(top);
3120 }
3121
3122 void
3123 _elm_widget_top_win_focused_set(Evas_Object *obj,
3124                                 Eina_Bool top_win_focused)
3125 {
3126    const Eina_List *l;
3127    Evas_Object *child;
3128    API_ENTRY return;
3129
3130    if (sd->top_win_focused == top_win_focused) return;
3131    EINA_LIST_FOREACH(sd->subobjs, l, child)
3132      {
3133         if (elm_widget_is(child))
3134           _elm_widget_top_win_focused_set(child, top_win_focused);
3135      }
3136    sd->top_win_focused = top_win_focused;
3137
3138    if (sd->focused && !sd->top_win_focused)
3139      eo_do(obj, elm_obj_widget_on_focus(NULL));
3140 }
3141
3142 Eina_Bool
3143 _elm_widget_top_win_focused_get(const Evas_Object *obj)
3144 {
3145    API_ENTRY return EINA_FALSE;
3146    return sd->top_win_focused;
3147 }
3148
3149 static void
3150 _elm_widget_disabled_eval(const Evas_Object *obj, Eina_Bool disabled)
3151 {
3152    const Eina_List *l;
3153    Evas_Object *child;
3154    ELM_WIDGET_DATA_GET(obj, sd);
3155
3156    if (disabled)
3157      {
3158         EINA_LIST_FOREACH(sd->subobjs, l, child)
3159           {
3160               if (elm_widget_is(child))
3161                 {
3162                    elm_widget_focus_disabled_handle(child);
3163                    eo_do(child, elm_obj_widget_disable());
3164                    _elm_widget_disabled_eval(child, EINA_TRUE);
3165                 }
3166           }
3167      }
3168    else
3169      {
3170         EINA_LIST_FOREACH(sd->subobjs, l, child)
3171           {
3172              ELM_WIDGET_DATA_GET(child, sdc);
3173              if (elm_widget_is(child) && !sdc->disabled)
3174                {
3175                   elm_widget_focus_disabled_handle(child);
3176                   eo_do(child, elm_obj_widget_disable());
3177                   _elm_widget_disabled_eval(child, EINA_FALSE);
3178                }
3179           }
3180      }
3181 }
3182
3183 static void
3184 elm_widget_disabled_internal(Eo *obj, Eina_Bool disabled)
3185 {
3186    Eina_Bool parent_state = EINA_FALSE;
3187
3188    if (disabled)
3189      {
3190         elm_widget_focus_disabled_handle(obj);
3191         eo_do(obj, elm_obj_widget_disable());
3192         _elm_widget_disabled_eval(obj, EINA_TRUE);
3193      }
3194    else
3195      {
3196         parent_state = elm_widget_disabled_get(elm_widget_parent_get(obj));
3197         if (parent_state) return;
3198         elm_widget_focus_disabled_handle(obj);
3199         eo_do(obj, elm_obj_widget_disable());
3200         _elm_widget_disabled_eval(obj, EINA_FALSE);
3201      }
3202 }
3203
3204 EOLIAN static void
3205 _elm_widget_disabled_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool disabled)
3206 {
3207    if (sd->disabled == disabled) return;
3208    sd->disabled = !!disabled;
3209
3210    elm_widget_disabled_internal(obj, disabled);
3211 }
3212
3213 EOLIAN static Eina_Bool
3214 _elm_widget_disabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3215 {
3216    Eina_Bool disabled = EINA_FALSE;
3217
3218    if (sd->disabled) disabled = EINA_TRUE;
3219    else disabled = elm_widget_disabled_get(elm_widget_parent_get(obj));
3220    return disabled;
3221 }
3222
3223 EOLIAN static void
3224 _elm_widget_show_region_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool forceshow)
3225 {
3226
3227    Evas_Object *parent_obj, *child_obj;
3228    Evas_Coord px, py, cx, cy, nx = 0, ny = 0;
3229
3230
3231    /* TIZEN_ONLY(20161222): Update show region geometry when entry is resized
3232       Move this code to the blow to update show region geometry properly.
3233    evas_smart_objects_calculate(evas_object_evas_get(obj));
3234     */
3235
3236    if (!forceshow && (x == sd->rx) && (y == sd->ry) &&
3237        (w == sd->rw) && (h == sd->rh)) return;
3238
3239    sd->rx = x;
3240    sd->ry = y;
3241    sd->rw = w;
3242    sd->rh = h;
3243
3244    /* TIZEN_ONLY(20161222): Update show region geometry when entry is resized */
3245    /* Block nested call for evas_smart_objects_calculate() and region showing works */
3246    if (sd->on_show_region_set) return;
3247
3248    sd->on_show_region_set = EINA_TRUE;
3249
3250    evas_smart_objects_calculate(evas_object_evas_get(obj));
3251
3252    sd->on_show_region_set = EINA_FALSE;
3253
3254    /* show_region geometry could be changed during processing elm_widget_show_region_set().
3255       evas_smart_objects_calculate() can trigger nested show_region_set calls */
3256    x = sd->rx;
3257    y = sd->ry;
3258    w = sd->rw;
3259    h = sd->rh;
3260    /* END */
3261
3262    if (sd->on_show_region)
3263      {
3264         sd->on_show_region
3265            (sd->on_show_region_data, obj);
3266
3267         if (_elm_scrollable_is(obj))
3268           {
3269              eo_do(obj, elm_interface_scrollable_content_pos_get(&nx, &ny));
3270              x -= nx;
3271              y -= ny;
3272           }
3273      }
3274
3275    do
3276      {
3277         parent_obj = sd->parent_obj;
3278         child_obj = sd->obj;
3279         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
3280         sd = eo_data_scope_get(parent_obj, MY_CLASS);
3281         if (!sd) break;
3282
3283         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
3284         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
3285
3286         x += (cx - px);
3287         y += (cy - py);
3288         sd->rx = x;
3289         sd->ry = y;
3290         sd->rw = w;
3291         sd->rh = h;
3292
3293         if (sd->on_show_region)
3294           {
3295              sd->on_show_region
3296                (sd->on_show_region_data, parent_obj);
3297           }
3298      }
3299    while (parent_obj);
3300 }
3301
3302 EOLIAN static void
3303 _elm_widget_show_region_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3304 {
3305    if (x) *x = sd->rx;
3306    if (y) *y = sd->ry;
3307    if (w) *w = sd->rw;
3308    if (h) *h = sd->rh;
3309 }
3310
3311 /**
3312  * @internal
3313  *
3314  * Get the focus region of the given widget.
3315  *
3316  * @return show region or not
3317  * (@c EINA_TRUE = show region/@c EINA_FALSE = do not show region). Default is @c EINA_FALSE.
3318  *
3319  * The focus region is the area of a widget that should brought into the
3320  * visible area when the widget is focused. Mostly used to show the part of
3321  * an entry where the cursor is, for example. The area returned is relative
3322  * to the object @p obj.
3323  *
3324  * @param obj The widget object
3325  * @param x Where to store the x coordinate of the area
3326  * @param y Where to store the y coordinate of the area
3327  * @param w Where to store the width of the area
3328  * @param h Where to store the height of the area
3329  *
3330  * @ingroup Widget
3331  */
3332 EOLIAN static Eina_Bool
3333 _elm_widget_focus_region_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3334 {
3335    Eina_Bool int_ret = EINA_FALSE;
3336    eo_do((Eo *)obj, int_ret = elm_obj_widget_on_focus_region(x, y, w, h));
3337    if (!int_ret)
3338      {
3339         evas_object_geometry_get(obj, NULL, NULL, w, h);
3340         if (x) *x = 0;
3341         if (y) *y = 0;
3342      }
3343    if ((*w <= 0) || (*h <= 0)) return EINA_FALSE;
3344    return EINA_TRUE;
3345 }
3346
3347 EOLIAN static void
3348 _elm_widget_parents_bounce_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool *horiz, Eina_Bool *vert)
3349 {
3350    Evas_Object *parent_obj = obj;
3351    Eina_Bool h = EINA_FALSE, v = EINA_FALSE;
3352
3353    *horiz = EINA_FALSE;
3354    *vert = EINA_FALSE;
3355
3356    do
3357      {
3358         parent_obj = elm_widget_parent_get(parent_obj);
3359         if ((!parent_obj) || (!_elm_widget_is(parent_obj))) break;
3360
3361         if (_elm_scrollable_is(parent_obj))
3362           {
3363              eo_do(parent_obj, elm_interface_scrollable_bounce_allow_get(&h, &v));
3364              if (h) *horiz = EINA_TRUE;
3365              if (v) *vert = EINA_TRUE;
3366           }
3367      }
3368    while (parent_obj);
3369 }
3370
3371 EOLIAN static Eina_List*
3372 _elm_widget_scrollable_children_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3373 {
3374    Eina_List *ret;
3375    ret = NULL;
3376
3377    Eina_List *l;
3378    Evas_Object *child;
3379
3380
3381    EINA_LIST_FOREACH(sd->subobjs, l, child)
3382      {
3383         if (elm_widget_is(child) && _elm_scrollable_is(child))
3384           ret = eina_list_append(ret, child);
3385      }
3386
3387    return ret;
3388 }
3389
3390 EOLIAN static void
3391 _elm_widget_scroll_hold_push(Eo *obj, Elm_Widget_Smart_Data *sd)
3392 {
3393    sd->scroll_hold++;
3394    if (sd->scroll_hold == 1)
3395      {
3396         if (_elm_scrollable_is(obj))
3397            eo_do(obj, elm_interface_scrollable_hold_set(EINA_TRUE));
3398         else
3399           {
3400              Eina_List *scr_children, *l;
3401              Evas_Object *child;
3402
3403              scr_children = elm_widget_scrollable_children_get(obj);
3404              EINA_LIST_FOREACH(scr_children, l, child)
3405                {
3406                   eo_do(child, elm_interface_scrollable_hold_set(EINA_TRUE));
3407                }
3408              eina_list_free(scr_children);
3409           }
3410      }
3411    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_hold_push());
3412    // FIXME: on delete/reparent hold pop
3413 }
3414
3415 EOLIAN static void
3416 _elm_widget_scroll_hold_pop(Eo *obj, Elm_Widget_Smart_Data *sd)
3417 {
3418    sd->scroll_hold--;
3419    if (!sd->scroll_hold)
3420      {
3421         if (_elm_scrollable_is(obj))
3422            eo_do(obj, elm_interface_scrollable_hold_set(EINA_FALSE));
3423         else
3424           {
3425              Eina_List *scr_children, *l;
3426              Evas_Object *child;
3427
3428              scr_children = elm_widget_scrollable_children_get(obj);
3429              EINA_LIST_FOREACH(scr_children, l, child)
3430                {
3431                   eo_do(child, elm_interface_scrollable_hold_set(EINA_FALSE));
3432                }
3433              eina_list_free(scr_children);
3434           }
3435      }
3436    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_hold_pop());
3437    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
3438 }
3439
3440 EOLIAN static int
3441 _elm_widget_scroll_hold_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3442 {
3443    return sd->scroll_hold;
3444 }
3445
3446 EOLIAN static void
3447 _elm_widget_scroll_freeze_push(Eo *obj, Elm_Widget_Smart_Data *sd)
3448 {
3449    sd->scroll_freeze++;
3450    if (sd->scroll_freeze == 1)
3451      {
3452         if (_elm_scrollable_is(obj))
3453            eo_do(obj, elm_interface_scrollable_freeze_set(EINA_TRUE));
3454         else
3455           {
3456              Eina_List *scr_children, *l;
3457              Evas_Object *child;
3458
3459              scr_children = elm_widget_scrollable_children_get(obj);
3460              EINA_LIST_FOREACH(scr_children, l, child)
3461                {
3462                   eo_do(child, elm_interface_scrollable_freeze_set(EINA_TRUE));
3463                }
3464              eina_list_free(scr_children);
3465           }
3466      }
3467    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_freeze_push());
3468    // FIXME: on delete/reparent freeze pop
3469 }
3470
3471 EOLIAN static void
3472 _elm_widget_scroll_freeze_pop(Eo *obj, Elm_Widget_Smart_Data *sd)
3473 {
3474    sd->scroll_freeze--;
3475    if (!sd->scroll_freeze)
3476      {
3477         if (_elm_scrollable_is(obj))
3478            eo_do(obj, elm_interface_scrollable_freeze_set(EINA_FALSE));
3479         else
3480           {
3481              Eina_List *scr_children, *l;
3482              Evas_Object *child;
3483
3484              scr_children = elm_widget_scrollable_children_get(obj);
3485              EINA_LIST_FOREACH(scr_children, l, child)
3486                {
3487                   eo_do(child, elm_interface_scrollable_freeze_set(EINA_FALSE));
3488                }
3489              eina_list_free(scr_children);
3490           }
3491      }
3492    if (sd->parent_obj) eo_do(sd->parent_obj, elm_obj_widget_scroll_freeze_pop());
3493    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
3494 }
3495
3496 EOLIAN static int
3497 _elm_widget_scroll_freeze_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3498 {
3499    return sd->scroll_freeze;
3500 }
3501
3502 // TIZEN_ONLY(20150705): Genlist item align feature
3503 EAPI void
3504 elm_widget_scroll_item_align_enabled_set(Evas_Object *obj,
3505                                         Eina_Bool scroll_item_align_enable)
3506 {
3507    API_ENTRY return;
3508    if (sd->scroll_item_align_enable == scroll_item_align_enable) return;
3509    sd->scroll_item_align_enable = scroll_item_align_enable;
3510 }
3511
3512 EAPI Eina_Bool
3513 elm_widget_scroll_item_align_enabled_get(const Evas_Object *obj)
3514 {
3515    API_ENTRY return EINA_FALSE;
3516    return sd->scroll_item_align_enable;
3517 }
3518
3519 EAPI void
3520 elm_widget_scroll_item_valign_set(Evas_Object *obj,
3521                                   const char *scroll_item_valign)
3522 {
3523    API_ENTRY return;
3524    if (sd->scroll_item_valign) eina_stringshare_del(sd->scroll_item_valign);
3525    if (!scroll_item_valign) sd->scroll_item_valign = NULL;
3526    else sd->scroll_item_valign = eina_stringshare_add(scroll_item_valign);
3527 }
3528
3529 EAPI const char*
3530 elm_widget_scroll_item_valign_get(const Evas_Object *obj)
3531 {
3532    API_ENTRY return NULL;
3533    return sd->scroll_item_valign;
3534 }
3535 //
3536
3537 EOLIAN static void
3538 _elm_widget_scale_set(Eo *obj, Elm_Widget_Smart_Data *sd, double scale)
3539 {
3540    if (scale < 0.0) scale = 0.0;
3541    if (sd->scale != scale)
3542      {
3543         sd->scale = scale;
3544         elm_widget_theme(obj);
3545      }
3546 }
3547
3548 EOLIAN static double
3549 _elm_widget_scale_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3550 {
3551    // FIXME: save walking up the tree by storing/caching parent scale
3552    if (sd->scale == 0.0)
3553      {
3554         if (sd->parent_obj && elm_widget_is(sd->parent_obj))
3555           {
3556              return elm_widget_scale_get(sd->parent_obj);
3557           }
3558         else
3559           {
3560              return 1.0;
3561           }
3562      }
3563    return sd->scale;
3564 }
3565
3566 EOLIAN static void
3567 _elm_widget_theme_set(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Theme *th)
3568 {
3569    Eina_Bool apply = EINA_FALSE;
3570    if (sd->theme != th)
3571      {
3572         if (elm_widget_theme_get(obj) != th) apply = EINA_TRUE;
3573         if (sd->theme) elm_theme_free(sd->theme);
3574         sd->theme = th;
3575         if (th) th->ref++;
3576         if (apply) elm_widget_theme(obj);
3577      }
3578 }
3579
3580 EOLIAN static void
3581 _elm_widget_part_text_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part, const char *label)
3582 {
3583    if (evas_object_smart_type_check(obj, "elm_layout"))
3584      elm_layout_text_set(obj, part, label);
3585 }
3586
3587 EOLIAN static const char*
3588 _elm_widget_part_text_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part)
3589 {
3590    if (evas_object_smart_type_check(obj, "elm_layout"))
3591      return elm_layout_text_get(obj, part);
3592
3593    return NULL;
3594 }
3595
3596 static Elm_Translate_String_Data *
3597 _translate_string_data_get(Eina_Inlist *translate_strings, const char *part)
3598 {
3599    Elm_Translate_String_Data *ts;
3600    Eina_Stringshare *str;
3601
3602    if (!translate_strings) return NULL;
3603
3604    str = eina_stringshare_add(part);
3605    EINA_INLIST_FOREACH(translate_strings, ts)
3606      {
3607         if (ts->id == str) break;
3608      }
3609
3610    eina_stringshare_del(str);
3611
3612    return ts;
3613 }
3614
3615 static Elm_Translate_String_Data *
3616 _part_text_translatable_set(Eina_Inlist **translate_strings, const char *part, Eina_Bool translatable, Eina_Bool preset)
3617 {
3618    Eina_Inlist *t;
3619    Elm_Translate_String_Data *ts;
3620    t = *translate_strings;
3621    ts = _translate_string_data_get(t, part);
3622
3623    if (translatable)
3624      {
3625         if (!ts)
3626           {
3627              ts = ELM_NEW(Elm_Translate_String_Data);
3628              if (!ts) return NULL;
3629
3630              ts->id = eina_stringshare_add(part);
3631              t = eina_inlist_append(t, (Eina_Inlist*) ts);
3632           }
3633         if (preset) ts->preset = EINA_TRUE;
3634      }
3635    //Delete this exist one if this part has been not preset.
3636    //see elm_widget_part_text_translatable_set()
3637    else if (ts && ((preset) || (!ts->preset)))
3638      {
3639         t = eina_inlist_remove(t, EINA_INLIST_GET(ts));
3640         eina_stringshare_del(ts->id);
3641         eina_stringshare_del(ts->domain);
3642         eina_stringshare_del(ts->string);
3643         ELM_SAFE_FREE(ts, free);
3644      }
3645
3646    *translate_strings = t;
3647
3648    return ts;
3649 }
3650
3651 EOLIAN static void
3652 _elm_widget_domain_translatable_part_text_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *part, const char *domain, const char *label)
3653 {
3654
3655    Elm_Translate_String_Data *ts;
3656
3657    if (!label)
3658      {
3659         _part_text_translatable_set(&sd->translate_strings, part, EINA_FALSE,
3660                                     EINA_FALSE);
3661      }
3662    else
3663      {
3664         ts = _part_text_translatable_set(&sd->translate_strings, part,
3665                                          EINA_TRUE, EINA_FALSE);
3666         if (!ts) return;
3667         if (!ts->string) ts->string = eina_stringshare_add(label);
3668         else eina_stringshare_replace(&ts->string, label);
3669         if (!ts->domain) ts->domain = eina_stringshare_add(domain);
3670         else eina_stringshare_replace(&ts->domain, domain);
3671 #ifdef HAVE_GETTEXT
3672         if (label[0]) label = dgettext(domain, label);
3673 #endif
3674      }
3675
3676    sd->on_translate = EINA_TRUE;
3677    eo_do(obj, elm_obj_widget_part_text_set(part, label));
3678    sd->on_translate = EINA_FALSE;
3679 }
3680
3681 EOLIAN static const char*
3682 _elm_widget_translatable_part_text_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *part)
3683 {
3684    Elm_Translate_String_Data *ts;
3685
3686    ts = _translate_string_data_get(sd->translate_strings, part);
3687    if (ts) return ts->string;
3688    else return NULL;
3689 }
3690
3691 EOLIAN static void
3692 _elm_widget_domain_part_text_translatable_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *part, const char *domain, Eina_Bool translatable)
3693 {
3694    Elm_Translate_String_Data *ts;
3695    const char *text = NULL;
3696
3697    ts = _part_text_translatable_set(&sd->translate_strings, part,
3698                                     translatable, EINA_TRUE);
3699    if (!ts) return;
3700    if (!ts->domain) ts->domain = eina_stringshare_add(domain);
3701    else eina_stringshare_replace(&ts->domain, domain);
3702
3703    eo_do(obj, text = elm_obj_widget_part_text_get(part));
3704    if (!text || !text[0]) return;
3705
3706    if (!ts->string) ts->string = eina_stringshare_add(text);
3707
3708 //Try to translate text since we don't know the text is already translated.
3709 #ifdef HAVE_GETTEXT
3710    text = dgettext(domain, text);
3711 #endif
3712    sd->on_translate = EINA_TRUE;
3713    eo_do(obj, elm_obj_widget_part_text_set(part, text));
3714    sd->on_translate = EINA_FALSE;
3715 }
3716
3717 EAPI void
3718 elm_widget_translate(Evas_Object *obj)
3719 {
3720    ELM_WIDGET_CHECK(obj);
3721    eo_do(obj, elm_obj_widget_translate());
3722 }
3723
3724 static const char*
3725 _part_text_translate(Eina_Inlist *translate_strings,
3726                      const char *part,
3727                      const char *text)
3728 {
3729    Elm_Translate_String_Data *ts;
3730    ts = _translate_string_data_get(translate_strings, part);
3731    if (!ts) return text;
3732
3733    if (!ts->string) ts->string = eina_stringshare_add(text);
3734    else eina_stringshare_replace(&ts->string, text);
3735 #ifdef HAVE_GETTEXT
3736    if (text && text[0])
3737      text = dgettext(ts->domain, text);
3738 #endif
3739    return text;
3740 }
3741
3742 EOLIAN static const char*
3743 _elm_widget_part_text_translate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *part, const char *text)
3744 {
3745
3746
3747    if (!sd->translate_strings || sd->on_translate) return text;
3748    return _part_text_translate(sd->translate_strings, part, text);
3749 }
3750
3751 EOLIAN static Eina_Bool
3752 _elm_widget_translate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
3753 {
3754    const Eina_List *l;
3755    Evas_Object *child;
3756    API_ENTRY return EINA_FALSE;
3757
3758    EINA_LIST_FOREACH(sd->subobjs, l, child)
3759      {
3760         if (elm_widget_is(child))
3761           elm_widget_translate(child);
3762      }
3763
3764    if (sd->hover_obj) elm_widget_translate(sd->hover_obj);
3765
3766 #ifdef HAVE_GETTEXT
3767    Elm_Translate_String_Data *ts;
3768    EINA_INLIST_FOREACH(sd->translate_strings, ts)
3769      {
3770         if (!ts->string) continue;
3771         const char *s = dgettext(ts->domain, ts->string);
3772         sd->on_translate = EINA_TRUE;
3773         eo_do(obj, elm_obj_widget_part_text_set(ts->id, s));
3774         sd->on_translate = EINA_FALSE;
3775      }
3776 #endif
3777    eo_do(obj, eo_event_callback_call(ELM_WIDGET_EVENT_LANGUAGE_CHANGED, NULL));
3778    return EINA_TRUE;
3779 }
3780
3781 /**
3782  * @internal
3783  *
3784  * Resets the focus_move_policy mode from the system one
3785  * for widgets that are in automatic mode.
3786  *
3787  * @param obj The widget.
3788  *
3789  */
3790 static void
3791 _elm_widget_focus_move_policy_reload(Evas_Object *obj)
3792 {
3793    API_ENTRY return;
3794    Elm_Focus_Move_Policy focus_move_policy = elm_config_focus_move_policy_get();
3795
3796    if (elm_widget_focus_move_policy_automatic_get(obj) &&
3797        (sd->focus_move_policy != focus_move_policy))
3798      {
3799         sd->focus_move_policy = focus_move_policy;
3800      }
3801 }
3802
3803 EOLIAN static void
3804 _elm_widget_focus_reconfigure(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
3805 {
3806    const Eina_List *l;
3807    Evas_Object *child;
3808    API_ENTRY return;
3809
3810    EINA_LIST_FOREACH(sd->subobjs, l, child)
3811      {
3812         if (elm_widget_is(child))
3813           elm_widget_focus_reconfigure(child);
3814      }
3815
3816    if (sd->hover_obj) elm_widget_focus_reconfigure(sd->hover_obj);
3817
3818    _elm_widget_focus_move_policy_reload(obj);
3819 }
3820
3821 //TIZEN_ONLY(20160726): add API elm_object_part_access_object_get
3822 EOLIAN static Evas_Object*
3823 _elm_widget_part_access_object_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *part EINA_UNUSED)
3824 {
3825    WRN("The %s widget does not implement the \"part_access_object_get\" functions.",
3826        eo_class_name_get(eo_class_get(obj)));
3827    return NULL;
3828 }
3829 //
3830
3831 EAPI void
3832 elm_widget_content_part_set(Evas_Object *obj,
3833                             const char *part,
3834                             Evas_Object *content)
3835 {
3836    ELM_WIDGET_CHECK(obj);
3837    eo_do(obj, elm_obj_container_content_set(part, content));
3838 }
3839
3840 /**
3841  * Returns the widget's focus_move_policy mode setting.
3842  *
3843  * @param obj The widget.
3844  * @return focus_move_policy mode setting of the object.
3845  *
3846  **/
3847 EOLIAN static Eina_Bool
3848 _elm_widget_focus_move_policy_automatic_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3849 {
3850    return sd->focus_move_policy_auto_mode;
3851 }
3852
3853 /**
3854  * @internal
3855  *
3856  * Sets the widget's focus_move_policy mode setting.
3857  * When widget in automatic mode, it follows the system focus_move_policy mode set by
3858  * elm_config_focus_move_policy_set().
3859  * @param obj The widget.
3860  * @param automatic EINA_TRUE for auto focus_move_policy mode. EINA_FALSE for manual.
3861  */
3862 EOLIAN static void
3863 _elm_widget_focus_move_policy_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic)
3864 {
3865    if (sd->focus_move_policy_auto_mode != automatic)
3866      {
3867         sd->focus_move_policy_auto_mode = automatic;
3868
3869         if (automatic)
3870           {
3871              elm_widget_focus_move_policy_set(obj, elm_config_focus_move_policy_get());
3872           }
3873      }
3874 }
3875
3876 EAPI Evas_Object *
3877 elm_widget_content_part_get(const Evas_Object *obj,
3878                             const char *part)
3879 {
3880    ELM_WIDGET_CHECK(obj) NULL;
3881    Evas_Object *ret = NULL;
3882    eo_do((Eo *) obj, ret = elm_obj_container_content_get(part));
3883    return ret;
3884 }
3885
3886 EAPI Evas_Object *
3887 elm_widget_content_part_unset(Evas_Object *obj,
3888                               const char *part)
3889 {
3890    ELM_WIDGET_CHECK(obj) NULL;
3891    Evas_Object *ret = NULL;
3892    eo_do(obj, ret = elm_obj_container_content_unset(part));
3893    return ret;
3894 }
3895
3896 EOLIAN static void
3897 _elm_widget_access_info_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *txt)
3898 {
3899    eina_stringshare_del(sd->access_info);
3900    if (!txt) sd->access_info = NULL;
3901    else sd->access_info = eina_stringshare_add(txt);
3902 }
3903
3904 EOLIAN static const char*
3905 _elm_widget_access_info_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3906 {
3907    return sd->access_info;
3908 }
3909
3910 EOLIAN static Elm_Theme*
3911 _elm_widget_theme_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3912 {
3913    if (!sd->theme)
3914      {
3915         if (sd->parent_obj && elm_widget_is(sd->parent_obj))
3916            return elm_widget_theme_get(sd->parent_obj);
3917         else return NULL;
3918      }
3919    return sd->theme;
3920 }
3921
3922 EOLIAN static Elm_Theme_Apply
3923 _elm_widget_style_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *style)
3924 {
3925    if (eina_stringshare_replace(&sd->style, style))
3926       return elm_widget_theme(obj);
3927
3928    return ELM_THEME_APPLY_SUCCESS;
3929 }
3930
3931 /* TIZEN_ONLY(20161223): add widget style set furnction for internal usage
3932                          this function is same with elm_widget_style_set
3933                          but it doesn't apply sub object's theme */
3934 Elm_Theme_Apply
3935 _elm_widget_style_set_internal(Evas_Object *obj, const char *style)
3936 {
3937    Elm_Theme_Apply ret = ELM_THEME_APPLY_SUCCESS;
3938
3939    API_ENTRY return ELM_THEME_APPLY_FAILED;
3940
3941    if (eina_stringshare_replace(&sd->style, style))
3942      {
3943         const Eina_List *l;
3944         Elm_Tooltip *tt;
3945         Elm_Cursor *cur;
3946
3947         if (sd->hover_obj) ret &= elm_widget_theme(sd->hover_obj);
3948
3949         EINA_LIST_FOREACH(sd->tooltips, l, tt)
3950           elm_tooltip_theme(tt);
3951         EINA_LIST_FOREACH(sd->cursors, l, cur)
3952           elm_cursor_theme(cur);
3953
3954         Elm_Theme_Apply ret2 = ELM_THEME_APPLY_FAILED;
3955         eo_do(obj, ret2 = elm_obj_widget_theme_apply());
3956         ret &= ret2;
3957      }
3958
3959    return ret;
3960 }
3961 /* END */
3962
3963 EOLIAN static const char*
3964 _elm_widget_style_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3965 {
3966    const char *ret;
3967    ret = "default";
3968    if (sd->style) ret = sd->style;
3969
3970    return ret;
3971 }
3972
3973 EOLIAN static void
3974 _elm_widget_tooltip_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Tooltip *tt)
3975 {
3976    sd->tooltips = eina_list_append(sd->tooltips, tt);
3977 }
3978
3979 EOLIAN static void
3980 _elm_widget_tooltip_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Tooltip *tt)
3981 {
3982    sd->tooltips = eina_list_remove(sd->tooltips, tt);
3983 }
3984
3985 EOLIAN static void
3986 _elm_widget_cursor_add(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Cursor *cur)
3987 {
3988    sd->cursors = eina_list_append(sd->cursors, cur);
3989 }
3990
3991 EOLIAN static void
3992 _elm_widget_cursor_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Cursor *cur)
3993 {
3994    sd->cursors = eina_list_remove(sd->cursors, cur);
3995 }
3996
3997 EOLIAN static void
3998 _elm_widget_drag_lock_x_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool lock)
3999 {
4000    if (sd->drag_x_locked == lock) return;
4001    sd->drag_x_locked = lock;
4002    if (sd->drag_x_locked) _propagate_x_drag_lock(obj, 1);
4003    else _propagate_x_drag_lock(obj, -1);
4004 }
4005
4006 EOLIAN static void
4007 _elm_widget_drag_lock_y_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool lock)
4008 {
4009    if (sd->drag_y_locked == lock) return;
4010    sd->drag_y_locked = lock;
4011    if (sd->drag_y_locked) _propagate_y_drag_lock(obj, 1);
4012    else _propagate_y_drag_lock(obj, -1);
4013 }
4014
4015 EOLIAN static Eina_Bool
4016 _elm_widget_drag_lock_x_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4017 {
4018    return sd->drag_x_locked;
4019 }
4020
4021 EOLIAN static Eina_Bool
4022 _elm_widget_drag_lock_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4023 {
4024    return sd->drag_y_locked;
4025 }
4026
4027 EOLIAN static int
4028 _elm_widget_drag_child_locked_x_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4029 {
4030    return sd->child_drag_x_locked;
4031 }
4032
4033 EOLIAN static int
4034 _elm_widget_drag_child_locked_y_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4035 {
4036    return sd->child_drag_y_locked;
4037 }
4038
4039 EOLIAN static void
4040 _elm_widget_item_loop_enabled_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED, Eina_Bool enable EINA_UNUSED)
4041 {
4042         return;
4043 }
4044
4045 EOLIAN static Eina_Bool
4046 _elm_widget_item_loop_enabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd EINA_UNUSED)
4047 {
4048         return EINA_FALSE;
4049 }
4050
4051 EOLIAN static Elm_Theme_Apply
4052 _elm_widget_theme_object_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle)
4053 {
4054    Elm_Theme_Apply ret = _elm_theme_object_set(obj, edj, wname, welement, wstyle);
4055    if (!ret)
4056      {
4057         return ELM_THEME_APPLY_FAILED;
4058      }
4059
4060    if (sd->orient_mode != -1)
4061      {
4062         char buf[128];
4063         snprintf(buf, sizeof(buf), "elm,state,orient,%d", sd->orient_mode);
4064         eo_do(obj, elm_obj_widget_signal_emit(buf, "elm"));
4065      }
4066
4067    return ret;
4068 }
4069
4070 EOLIAN static void
4071 _elm_widget_eo_base_dbg_info_get(Eo *eo_obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eo_Dbg_Info *root)
4072 {
4073    eo_do_super(eo_obj, MY_CLASS, eo_dbg_info_get(root));
4074    Eo_Dbg_Info *group = EO_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME);
4075
4076    EO_DBG_INFO_APPEND(group, "Wid-Type", EINA_VALUE_TYPE_STRING, elm_widget_type_get(eo_obj));
4077    EO_DBG_INFO_APPEND(group, "Style", EINA_VALUE_TYPE_STRING, elm_widget_style_get(eo_obj));
4078    EO_DBG_INFO_APPEND(group, "Layer", EINA_VALUE_TYPE_INT,
4079          (int) evas_object_layer_get(eo_obj));
4080    EO_DBG_INFO_APPEND(group, "Scale", EINA_VALUE_TYPE_DOUBLE,
4081          evas_object_scale_get(eo_obj));
4082    EO_DBG_INFO_APPEND(group, "Has focus", EINA_VALUE_TYPE_CHAR,
4083          elm_object_focus_get(eo_obj));
4084    EO_DBG_INFO_APPEND(group, "Disabled", EINA_VALUE_TYPE_CHAR,
4085          elm_widget_disabled_get(eo_obj));
4086    EO_DBG_INFO_APPEND(group, "Mirrored", EINA_VALUE_TYPE_CHAR,
4087          elm_widget_mirrored_get(eo_obj));
4088    EO_DBG_INFO_APPEND(group, "Automatic mirroring", EINA_VALUE_TYPE_CHAR,
4089          elm_widget_mirrored_automatic_get(eo_obj));
4090 }
4091
4092 EAPI Eina_Bool
4093 elm_widget_is_check(const Evas_Object *obj)
4094 {
4095    static int abort_on_warn = -1;
4096    if (elm_widget_is(obj))
4097      return EINA_TRUE;
4098
4099    ERR("Passing Object: %p.", obj);
4100    if (abort_on_warn == -1)
4101      {
4102         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
4103         else abort_on_warn = 0;
4104      }
4105    if (abort_on_warn == 1) abort();
4106    return EINA_FALSE;
4107 }
4108
4109 EAPI const char *
4110 elm_widget_type_get(const Evas_Object *obj)
4111 {
4112    API_ENTRY return NULL;
4113
4114    return eo_class_name_get(eo_class_get(obj));
4115 }
4116
4117 EAPI Eina_Bool
4118 elm_widget_type_check(const Evas_Object *obj,
4119                       const char *type,
4120                       const char *func)
4121 {
4122    const char *provided, *expected = "(unknown)";
4123    static int abort_on_warn = -1;
4124
4125    provided = elm_widget_type_get(obj);
4126    /* TODO: eventually migrate to check_ptr version */
4127    if (evas_object_smart_type_check(obj, type)) return EINA_TRUE;
4128    if (type) expected = type;
4129    if ((!provided) || (!provided[0]))
4130      {
4131         provided = evas_object_type_get(obj);
4132         if ((!provided) || (!provided[0]))
4133           provided = "(unknown)";
4134      }
4135    ERR("Passing Object: %p in function: %s, of type: '%s' when expecting"
4136        " type: '%s'", obj, func, provided, expected);
4137    if (abort_on_warn == -1)
4138      {
4139         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
4140         else abort_on_warn = 0;
4141      }
4142    if (abort_on_warn == 1) abort();
4143    return EINA_FALSE;
4144 }
4145
4146 static Evas_Object *
4147 _widget_name_find(const Evas_Object *obj,
4148                   const char *name,
4149                   int recurse)
4150 {
4151    Eina_List *l;
4152    Evas_Object *child;
4153    const char *s;
4154    INTERNAL_ENTRY NULL;
4155
4156    if (!_elm_widget_is(obj)) return NULL;
4157    EINA_LIST_FOREACH(sd->subobjs, l, child)
4158      {
4159         s = evas_object_name_get(child);
4160         if ((s) && (!strcmp(s, name))) return child;
4161         if ((recurse != 0) &&
4162             ((child = _widget_name_find(child, name, recurse - 1))))
4163           return child;
4164      }
4165    if (sd->hover_obj)
4166      {
4167         s = evas_object_name_get(sd->hover_obj);
4168         if ((s) && (!strcmp(s, name))) return sd->hover_obj;
4169         if ((recurse != 0) &&
4170             ((child = _widget_name_find(sd->hover_obj, name, recurse - 1))))
4171           return child;
4172      }
4173    return NULL;
4174 }
4175
4176 EOLIAN static Evas_Object*
4177 _elm_widget_name_find(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const char *name, int recurse)
4178 {
4179    if (!name) return NULL;
4180    return _widget_name_find(obj, name, recurse);
4181 }
4182
4183 /**
4184  * @internal
4185  *
4186  * Split string in words
4187  *
4188  * @param str Source string
4189  * @return List of const words
4190  *
4191  * @see elm_widget_stringlist_free()
4192  * @ingroup Widget
4193  */
4194 EAPI Eina_List *
4195 elm_widget_stringlist_get(const char *str)
4196 {
4197    Eina_List *list = NULL;
4198    const char *s, *b;
4199    if (!str) return NULL;
4200    for (b = s = str; 1; s++)
4201      {
4202         if ((*s == ' ') || (!*s))
4203           {
4204              char *t = malloc(s - b + 1);
4205              if (t)
4206                {
4207                   strncpy(t, b, s - b);
4208                   t[s - b] = 0;
4209                   list = eina_list_append(list, eina_stringshare_add(t));
4210                   free(t);
4211                }
4212              b = s + 1;
4213           }
4214         if (!*s) break;
4215      }
4216    return list;
4217 }
4218
4219 EAPI void
4220 elm_widget_stringlist_free(Eina_List *list)
4221 {
4222    const char *s;
4223    EINA_LIST_FREE(list, s)
4224      eina_stringshare_del(s);
4225 }
4226
4227 EOLIAN static void
4228 _elm_widget_focus_hide_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4229 {
4230    if (!_elm_widget_is(obj))
4231      return;
4232    _if_focused_revert(obj, EINA_TRUE);
4233 }
4234
4235 EAPI void
4236 elm_widget_focus_mouse_up_handle(Evas_Object *obj)
4237 {
4238    Evas_Object *o = obj;
4239    do
4240      {
4241         if (_elm_widget_is(o)) break;
4242         o = evas_object_smart_parent_get(o);
4243      }
4244    while (o);
4245
4246    eo_do(o, elm_obj_widget_focus_mouse_up_handle());
4247 }
4248
4249 EOLIAN static void
4250 _elm_widget_focus_mouse_up_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4251 {
4252    if (!obj) return;
4253    if (!_is_focusable(obj)) return;
4254
4255    elm_widget_focus_steal(obj, NULL);
4256 }
4257
4258 EOLIAN static void
4259 _elm_widget_focus_tree_unfocusable_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4260 {
4261    if (!elm_widget_parent_get(obj))
4262      elm_widget_focused_object_clear(obj);
4263    else
4264      _if_focused_revert(obj, EINA_TRUE);
4265 }
4266
4267 EOLIAN static void
4268 _elm_widget_focus_disabled_handle(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4269 {
4270    elm_widget_focus_tree_unfocusable_handle(obj);
4271 }
4272
4273 EOLIAN static unsigned int
4274 _elm_widget_focus_order_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4275 {
4276    return sd->focus_order;
4277 }
4278
4279 EOLIAN static Evas_Object*
4280 _elm_widget_newest_focus_order_get(const Eo *obj, Elm_Widget_Smart_Data *sd, unsigned int *newest_focus_order, Eina_Bool can_focus_only)
4281 {
4282    const Eina_List *l;
4283    Evas_Object *child, *cur, *best;
4284
4285    if (!evas_object_visible_get(obj)
4286        || (elm_widget_disabled_get(obj))
4287        || (elm_widget_tree_unfocusable_get(obj)))
4288      return NULL;
4289
4290    best = NULL;
4291    if (*newest_focus_order < sd->focus_order)
4292      {
4293         if (!can_focus_only || elm_widget_can_focus_get(obj))
4294           {
4295              *newest_focus_order = sd->focus_order;
4296              best = (Evas_Object *)obj;
4297           }
4298      }
4299    EINA_LIST_FOREACH(sd->subobjs, l, child)
4300      {
4301         if (!_elm_widget_is(child)) continue;
4302
4303         cur = elm_widget_newest_focus_order_get
4304            (child, newest_focus_order, can_focus_only);
4305         if (!cur) continue;
4306         best = cur;
4307      }
4308    return best;
4309 }
4310
4311 /*
4312  * @internal
4313  *
4314  * Get the focus highlight geometry of an widget.
4315  *
4316  * @param obj Widget object for the focus highlight
4317  * @param x Focus highlight x coordinate
4318  * @param y Focus highlight y coordinate
4319  * @param w Focus highlight object width
4320  * @param h Focus highlight object height
4321  * @param is_next @c EINA_TRUE if this request is for the new focused object,
4322  * @c EINA_FALSE if this request is for the previously focused object. This
4323  * information becomes important when the focus highlight is changed inside one
4324  * widget.
4325  *
4326  * @ingroup Widget
4327  */
4328 /*
4329  * @internal
4330  *
4331  * Get the 'focus_part' geometry if there is any
4332  *
4333  * This queries if there is a 'focus_part' request from the edc style. If edc
4334  * style offers 'focus_part' edje data item, this function requests for the
4335  * geometry of a specific part which is described in 'focus_part' edje data.
4336  *
4337  * @param obj Widget object for the focus highlight
4338  * @param x Focus highlight x coordinate
4339  * @param y Focus highlight y coordinate
4340  * @param w Focus highlight object width
4341  * @param h Focus highlight object height
4342  *
4343  * x, y, w, h already contain the object's geometry. If there is a 'focus_part'
4344  * support, these values will be updated accordingly or the values will be
4345  * remained as they were.
4346  *
4347  * @ingroup Widget
4348  */
4349 EAPI void
4350 elm_widget_focus_highlight_focus_part_geometry_get(const Evas_Object *obj,
4351                                                    Evas_Coord *x,
4352                                                    Evas_Coord *y,
4353                                                    Evas_Coord *w,
4354                                                    Evas_Coord *h)
4355 {
4356    Evas_Coord tx = 0, ty = 0, tw = 0, th = 0;
4357    const char *target_hl_part = NULL;
4358    const Evas_Object *edje_obj = NULL;
4359
4360    if (obj && eo_isa(obj, EDJE_OBJECT_CLASS))
4361      {
4362         edje_obj = obj;
4363         if (!(target_hl_part = edje_object_data_get(edje_obj, "focus_part")))
4364           return;
4365      }
4366    else if (obj && eo_isa(obj, ELM_LAYOUT_CLASS))
4367      {
4368         edje_obj = elm_layout_edje_get(obj);
4369         if (!(target_hl_part = elm_layout_data_get(obj, "focus_part")))
4370           return;
4371      }
4372    else
4373      return;
4374
4375   edje_object_part_geometry_get(edje_obj, target_hl_part,
4376                                 &tx, &ty, &tw, &th);
4377   *x += tx;
4378   *y += ty;
4379   if (tw != *w) *w = tw;
4380   if (th != *h) *h = th;
4381 }
4382
4383 EOLIAN static void
4384 _elm_widget_focus_highlight_geometry_get(const Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
4385 {
4386    Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
4387    Evas_Object *scroller = (Evas_Object *)obj;
4388
4389    evas_object_geometry_get(obj, x, y, w, h);
4390    elm_widget_focus_highlight_focus_part_geometry_get(sd->resize_obj, x, y, w, h);
4391
4392    if (_elm_config->focus_autoscroll_mode != ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN)
4393      return;
4394
4395    while (scroller)
4396      {
4397         if (_elm_scrollable_is(scroller))
4398           {
4399              eo_do(scroller,
4400                    elm_interface_scrollable_content_viewport_geometry_get(&ox, &oy, &ow, &oh));
4401
4402              if (*y < oy)
4403                *y = oy;
4404              else if ((oy + oh) < (*y + *h))
4405                *y = (oy + oh - *h);
4406              else if (*x < ox)
4407                *x = ox;
4408              else if ((ox + ow) < (*x + *w))
4409                *x = (ox + ow - *w);
4410
4411              break;
4412           }
4413         scroller = elm_widget_parent_get(scroller);
4414      }
4415 }
4416
4417 EOLIAN static Elm_Object_Item*
4418 _elm_widget_focused_item_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4419 {
4420    return NULL;
4421 }
4422
4423 EOLIAN static void
4424 _elm_widget_focus_region_show_mode_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, Elm_Focus_Region_Show_Mode mode)
4425 {
4426    _pd->focus_region_show_mode = mode;
4427 }
4428
4429 EOLIAN static Elm_Focus_Region_Show_Mode
4430 _elm_widget_focus_region_show_mode_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd)
4431 {
4432    return _pd->focus_region_show_mode;
4433 }
4434
4435 EAPI void
4436 elm_widget_activate(Evas_Object *obj, Elm_Activate act)
4437 {
4438    Evas_Object *parent;
4439    Eina_Bool ret;
4440
4441    ELM_WIDGET_CHECK(obj);
4442
4443    ret = EINA_FALSE;
4444
4445    eo_do(obj, ret = elm_obj_widget_activate(act));
4446
4447    if (ret) return;
4448
4449    parent = elm_widget_parent_get(obj);
4450    if (parent)
4451      elm_widget_activate(parent, act);
4452
4453    return;
4454 }
4455
4456 /**
4457  * @internal
4458  *
4459  * Sets the widget and child widget's Evas_Display_Mode.
4460  *
4461  * @param obj The widget.
4462  * @param dispmode Evas_Display_Mode to set widget's mode.
4463  *
4464  * Widgets are resized by several reasons.
4465  * Evas_Display_Mode can help for widgets to get one more reason of resize.
4466  * For example, elm conform widget resizes it's contents when keypad state changed.
4467  * After keypad showing, conform widget can change child's Evas_Display_Mode.
4468  * @ingroup Widget
4469  */
4470 EOLIAN static void
4471 _elm_widget_display_mode_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Display_Mode dispmode)
4472 {
4473    Evas_Display_Mode prev_dispmode;
4474    Evas_Object *child;
4475    Eina_List *l;
4476
4477    prev_dispmode = evas_object_size_hint_display_mode_get(obj);
4478
4479    if ((prev_dispmode == dispmode) ||
4480        (prev_dispmode == EVAS_DISPLAY_MODE_DONT_CHANGE)) return;
4481
4482    evas_object_size_hint_display_mode_set(obj, dispmode);
4483
4484    EINA_LIST_FOREACH (sd->subobjs, l, child)
4485      {
4486         if (elm_widget_is(child))
4487           elm_widget_display_mode_set(child, dispmode);
4488      }
4489 }
4490
4491 EOLIAN static void
4492 _elm_widget_orientation_mode_disabled_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool disabled)
4493 {
4494    int orient_mode = -1;
4495
4496    if (!disabled)
4497      {
4498         //Get current orient mode from it's parent otherwise, 0.
4499         sd->orient_mode = 0;
4500         ELM_WIDGET_DATA_GET(sd->parent_obj, sd_parent);
4501         if (!sd_parent) orient_mode = 0;
4502         else orient_mode = sd_parent->orient_mode;
4503      }
4504    eo_do(obj, elm_obj_widget_orientation_set(orient_mode));
4505 }
4506
4507 EOLIAN static Eina_Bool
4508 _elm_widget_orientation_mode_disabled_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4509 {
4510    if (sd->orient_mode == -1) return EINA_TRUE;
4511    else return EINA_FALSE;
4512 }
4513
4514 EOLIAN static void
4515 _elm_widget_orientation_set(Eo *obj, Elm_Widget_Smart_Data *sd, int orient_mode)
4516 {
4517    Evas_Object *child;
4518    Eina_List *l;
4519
4520    sd->orient_mode = orient_mode;
4521
4522    EINA_LIST_FOREACH (sd->subobjs, l, child)
4523      {
4524         if (elm_widget_is(child))
4525           eo_do(child, elm_obj_widget_orientation_set(orient_mode));
4526      }
4527
4528    if (orient_mode != -1)
4529      {
4530         char buf[128];
4531         snprintf(buf, sizeof(buf), "elm,state,orient,%d", orient_mode);
4532         eo_do(obj, elm_obj_widget_signal_emit(buf, "elm"));
4533      }
4534 }
4535
4536 /**
4537  * @internal
4538  *
4539  * Returns the widget's focus move policy.
4540  *
4541  * @param obj The widget.
4542  * @return focus move policy of the object.
4543  *
4544  **/
4545 EOLIAN static Elm_Focus_Move_Policy
4546 _elm_widget_focus_move_policy_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
4547 {
4548    return sd->focus_move_policy;
4549 }
4550
4551 /**
4552  * @internal
4553  *
4554  * Sets the widget's focus move policy.
4555  *
4556  * @param obj The widget.
4557  * @param policy Elm_Focus_Move_Policy to set object's focus move policy.
4558  */
4559
4560 EOLIAN static void
4561 _elm_widget_focus_move_policy_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Focus_Move_Policy policy)
4562 {
4563    if (sd->focus_move_policy == policy) return;
4564    sd->focus_move_policy = policy;
4565 }
4566 static void
4567 _track_obj_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
4568
4569 static void
4570 _track_obj_update(Evas_Object *track, Evas_Object *obj)
4571 {
4572    //Geometry
4573    Evas_Coord x, y, w, h;
4574    evas_object_geometry_get(obj, &x, &y, &w, &h);
4575    evas_object_move(track, x, y);
4576    evas_object_resize(track, w, h);
4577
4578    //Visibility
4579    if (evas_object_visible_get(obj)) evas_object_show(track);
4580    else evas_object_hide(track);
4581 }
4582
4583 static Eina_Bool
4584 _track_obj_view_update(void *data, Eo *obj,
4585                        const Eo_Event_Description *desc EINA_UNUSED,
4586                        void *event_info EINA_UNUSED)
4587 {
4588    Elm_Widget_Item_Data *item = data;
4589    _track_obj_update(item->track_obj, obj);
4590    return EO_CALLBACK_CONTINUE;
4591 }
4592
4593 static Eina_Bool
4594 _track_obj_view_del(void *data, Eo *obj EINA_UNUSED,
4595                     const Eo_Event_Description *desc EINA_UNUSED,
4596                     void *event_info EINA_UNUSED);
4597
4598 EO_CALLBACKS_ARRAY_DEFINE(tracker_callbacks,
4599                           { EVAS_OBJECT_EVENT_RESIZE, _track_obj_view_update },
4600                           { EVAS_OBJECT_EVENT_MOVE, _track_obj_view_update },
4601                           { EVAS_OBJECT_EVENT_SHOW, _track_obj_view_update },
4602                           { EVAS_OBJECT_EVENT_HIDE, _track_obj_view_update },
4603                           { EVAS_OBJECT_EVENT_DEL, _track_obj_view_del });
4604
4605 static Eina_Bool
4606 _track_obj_view_del(void *data, Eo *obj EINA_UNUSED,
4607                     const Eo_Event_Description *desc EINA_UNUSED,
4608                     void *event_info EINA_UNUSED)
4609 {
4610    Elm_Widget_Item_Data *item = data;
4611
4612    while (evas_object_ref_get(item->track_obj) > 0)
4613      evas_object_unref(item->track_obj);
4614
4615    evas_object_event_callback_del(item->track_obj, EVAS_CALLBACK_DEL,
4616                                   _track_obj_del);
4617    evas_object_del(item->track_obj);
4618    item->track_obj = NULL;
4619
4620    return EO_CALLBACK_CONTINUE;
4621 }
4622
4623 static void
4624 _track_obj_del(void *data, Evas *e EINA_UNUSED,
4625                     Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
4626 {
4627    Elm_Widget_Item_Data *item = data;
4628    item->track_obj = NULL;
4629
4630    if (!item->view) return;
4631
4632    eo_do(item->view, eo_event_callback_array_del(tracker_callbacks(), item));
4633 }
4634
4635 static void
4636 _elm_widget_item_signal_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission,
4637                            const char *source)
4638 {
4639    Elm_Widget_Item_Signal_Data *wisd = data;
4640    wisd->func(wisd->data, wisd->item, emission, source);
4641 }
4642
4643 static void *
4644 _elm_widget_item_signal_callback_list_get(Elm_Widget_Item_Data *item, Eina_List *position)
4645 {
4646    Elm_Widget_Item_Signal_Data *wisd = eina_list_data_get(position);
4647    void *data;
4648
4649    item->signals = eina_list_remove_list(item->signals, position);
4650    data = wisd->data;
4651
4652    if (_elm_widget_is(item->view))
4653      elm_object_signal_callback_del(item->view,
4654                                     wisd->emission, wisd->source,
4655                                     _elm_widget_item_signal_cb);
4656    else if (eo_isa(item->view, EDJE_OBJECT_CLASS))
4657      edje_object_signal_callback_del_full(item->view,
4658                                           wisd->emission, wisd->source,
4659                                           _elm_widget_item_signal_cb, wisd);
4660
4661    eina_stringshare_del(wisd->emission);
4662    eina_stringshare_del(wisd->source);
4663    free(wisd);
4664
4665    return data;
4666 }
4667
4668 #define ERR_NOT_SUPPORTED(item, method)  ERR("%s does not support %s API.", elm_widget_type_get(item->widget), method);
4669
4670 static Eina_Bool
4671 _eo_del_cb(void *data EINA_UNUSED, Eo *eo_item, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
4672 {
4673    Elm_Widget_Item_Data *item = eo_data_scope_get(eo_item, ELM_WIDGET_ITEM_CLASS);
4674    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_TRUE);
4675    if (item->del_func)
4676       item->del_func((void *) WIDGET_ITEM_DATA_GET(eo_item), item->widget, item->eo_obj);
4677    return EINA_TRUE;
4678 }
4679
4680 /**
4681  * @internal
4682  *
4683  * Allocate a new Elm_Widget_Item-derived structure.
4684  *
4685  * The goal of this structure is to provide common ground for actions
4686  * that a widget item have, such as the owner widget, callback to
4687  * notify deletion, data pointer and maybe more.
4688  *
4689  * @param widget the owner widget that holds this item, must be an elm_widget!
4690  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
4691  *        be used to allocate memory.
4692  *
4693  * @return allocated memory that is already zeroed out, or NULL on errors.
4694  *
4695  * @see elm_widget_item_new() convenience macro.
4696  * @see elm_widget_item_del() to release memory.
4697  * @ingroup Widget
4698  */
4699 EOLIAN static Eo *
4700 _elm_widget_item_eo_base_constructor(Eo *eo_item, Elm_Widget_Item_Data *item)
4701 {
4702    Evas_Object *widget;
4703    eo_do (eo_item, widget = eo_parent_get());
4704
4705    if (!_elm_widget_is(widget))
4706      {
4707         ERR("Failed");
4708         return NULL;
4709      }
4710
4711    eo_item = eo_do_super_ret(eo_item, ELM_WIDGET_ITEM_CLASS, eo_item, eo_constructor());
4712
4713    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
4714
4715    item->widget = widget;
4716    item->eo_obj = eo_item;
4717    //TIZEN_ONLY(20170717) : expose highlight information on atspi
4718    item->can_highlight = EINA_TRUE;
4719    //
4720
4721    eo_do(eo_item, eo_event_callback_add(EO_BASE_EVENT_DEL, _eo_del_cb, NULL));
4722
4723    return eo_item;
4724 }
4725
4726 EOLIAN static void
4727 _elm_widget_item_eo_base_destructor(Eo *eo_item, Elm_Widget_Item_Data *item)
4728 {
4729    Elm_Translate_String_Data *ts;
4730
4731    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4732
4733    evas_object_del(item->view);
4734
4735    eina_stringshare_del(item->access_info);
4736    eina_stringshare_del(item->accessible_name);
4737
4738    while (item->signals)
4739      _elm_widget_item_signal_callback_list_get(item, item->signals);
4740
4741    while (item->translate_strings)
4742      {
4743         ts = EINA_INLIST_CONTAINER_GET(item->translate_strings,
4744                                        Elm_Translate_String_Data);
4745         eina_stringshare_del(ts->id);
4746         eina_stringshare_del(ts->domain);
4747         eina_stringshare_del(ts->string);
4748         item->translate_strings = eina_inlist_remove(item->translate_strings,
4749                                                      item->translate_strings);
4750         free(ts);
4751      }
4752    eina_hash_free(item->labels);
4753
4754    eo_do(eo_item,
4755          elm_interface_atspi_accessible_description_set(NULL),
4756          elm_interface_atspi_accessible_name_set(NULL),
4757          //TIZEN_ONLY(20190922): add name callback, description callback.
4758          elm_interface_atspi_accessible_description_cb_set(NULL, NULL),
4759          elm_interface_atspi_accessible_name_cb_set(NULL, NULL),
4760          //
4761          elm_interface_atspi_accessible_translation_domain_set(NULL),
4762          elm_interface_atspi_accessible_relationships_clear(),
4763                  // TIZEN_ONLY(20160930) : endless recursion fix
4764          elm_interface_atspi_accessible_attributes_clear()
4765                  //
4766          );
4767
4768    if (item->name)
4769      eina_stringshare_del(item->name);
4770
4771    if (item->atspi_custom_relations)
4772      elm_atspi_relation_set_free(&item->atspi_custom_relations);
4773
4774    //TIZEN_ONLY(20150731) : add i18n support for name and description
4775    if (item->atspi_translation_domain)
4776      eina_stringshare_del(item->atspi_translation_domain);
4777    //
4778    //Tizen Only(20160728) free attribute list
4779    if (item->attr_list)
4780    {
4781       Elm_Atspi_Attribute *attr;
4782       EINA_LIST_FREE(item->attr_list, attr)
4783        {
4784           eina_stringshare_del(attr->key);
4785           eina_stringshare_del(attr->value);
4786           free(attr);
4787        }
4788    }
4789    //
4790
4791 //TIZEN_ONLY(20161013): clean up elm color class feature
4792    if (item->color_classes)
4793      ELM_SAFE_FREE(item->color_classes, eina_hash_free);
4794 //
4795
4796    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
4797
4798    eo_do_super(eo_item, ELM_WIDGET_ITEM_CLASS, eo_destructor());
4799 }
4800
4801 /**
4802  * @internal
4803  *
4804  * Releases widget item memory, calling back item_del_pre_hook() and
4805  * item_del_cb() if they exist.
4806  *
4807  * @param item a valid #Elm_Widget_Item to be deleted.
4808  *
4809  * If there is an Elm_Widget_Item::del_cb, then it will be called prior
4810  * to memory release. Note that elm_widget_item_pre_notify_del() calls
4811  * this function and then unset it, thus being useful for 2 step
4812  * cleanup whenever the del_cb may use any of the data that must be
4813  * deleted from item.
4814  *
4815  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
4816  * is presented!
4817  *
4818  * Note that if item_del_pre_hook() returns @c EINA_TRUE, item free will be
4819  * deferred, or item will be freed here if it returns @c EINA_FALSE.
4820  *
4821  * @see elm_widget_item_del() convenience macro.
4822  * @ingroup Widget
4823  */
4824 EOLIAN static void
4825 _elm_widget_item_del(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4826 {
4827    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4828    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4829    item->on_deletion = EINA_TRUE;
4830
4831    //Widget item delete callback
4832    Eina_Bool del_ok;
4833    eo_do(item->eo_obj, del_ok = elm_wdg_item_del_pre());
4834    if (del_ok)
4835       eo_del(item->eo_obj);
4836    return;
4837 }
4838
4839 EOLIAN static Eina_Bool
4840 _elm_widget_item_del_pre(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED)
4841 {
4842    return EINA_TRUE;
4843 }
4844
4845 /**
4846  * @internal
4847  *
4848  * Notify object will be deleted without actually deleting it.
4849  *
4850  * This function will callback Elm_Widget_Item::del_cb if it is set
4851  * and then unset it so it is not called twice (ie: from
4852  * elm_widget_item_del()).
4853  *
4854  * @param item a valid #Elm_Widget_Item to be notified
4855  * @see elm_widget_item_pre_notify_del() convenience macro.
4856  * @ingroup Widget
4857  */
4858 EOLIAN static void
4859 _elm_widget_item_pre_notify_del(Eo *eo_item, Elm_Widget_Item_Data *item)
4860 {
4861    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4862    if (!item->del_func) return;
4863    item->del_func((void *)WIDGET_ITEM_DATA_GET(eo_item), item->widget, item->eo_obj);
4864    item->del_func = NULL;
4865 }
4866
4867 /**
4868  * @internal
4869  *
4870  * Set the function to notify when item is being deleted.
4871  *
4872  * This function will complain if there was a callback set already,
4873  * however it will set the new one.
4874  *
4875  * The callback will be called from elm_widget_item_pre_notify_del()
4876  * or elm_widget_item_del() will be called with:
4877  *   - data: the Elm_Widget_Item::data value.
4878  *   - obj: the Elm_Widget_Item::widget evas object.
4879  *   - event_info: the item being deleted.
4880  *
4881  * @param item a valid #Elm_Widget_Item to be notified
4882  * @see elm_widget_item_del_cb_set() convenience macro.
4883  * @ingroup Widget
4884  */
4885 EOLIAN static void
4886 _elm_widget_item_del_cb_set(Eo *eo_item EINA_UNUSED,
4887                             Elm_Widget_Item_Data *item,
4888                             Evas_Smart_Cb func)
4889 {
4890    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4891    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4892
4893    if ((item->del_func) && (item->del_func != func))
4894      WRN("You're replacing a previously set del_cb %p of item %p with %p",
4895          item->del_func, item->eo_obj, func);
4896
4897    item->del_func = func;
4898 }
4899
4900 /**
4901  * @internal
4902  *
4903  * Get owner widget of this item.
4904  *
4905  * @param item a valid #Elm_Widget_Item to get data from.
4906  * @return owner widget of this item.
4907  * @ingroup Widget
4908  */
4909 EOLIAN static Evas_Object *
4910 _elm_widget_item_widget_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4911 {
4912    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4913    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4914
4915    return item->widget;
4916 }
4917
4918 EAPI Eina_Bool
4919 _elm_widget_onscreen_is(Evas_Object *widget)
4920 {
4921    Evas_Object *parent = widget;
4922    Evas_Coord x, y, w, h, wx, wy, ww, wh;
4923
4924    Evas *evas = evas_object_evas_get(widget);
4925    if (!evas) return EINA_FALSE;
4926
4927    // check if on canvas
4928    evas_output_viewport_get(evas, &x, &y, &w, &h);
4929    evas_object_geometry_get(widget, &wx, &wy, &ww, &wh);
4930    if (((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) ||
4931        ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))
4932      return EINA_FALSE;
4933
4934    // check if inside scrollable parent viewport
4935    do {
4936       parent = elm_widget_parent_get(parent);
4937       if (parent && !evas_object_visible_get(parent))
4938         return EINA_FALSE;
4939       if (parent && eo_isa(parent, ELM_INTERFACE_SCROLLABLE_MIXIN))
4940         {
4941            evas_object_geometry_get(parent, &x, &y, &w, &h);
4942            if (((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) ||
4943                ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))
4944              return EINA_FALSE;
4945         }
4946    } while (parent && (parent != elm_widget_top_get(widget)));
4947
4948    return EINA_TRUE;
4949 }
4950
4951 EAPI Eina_Bool
4952 _elm_widget_item_onscreen_is(Elm_Object_Item *item)
4953 {
4954    Evas_Coord x, y, w, h, wx, wy, ww, wh;
4955    Elm_Widget_Item_Data *id = eo_data_scope_get(item, ELM_WIDGET_ITEM_CLASS);
4956    if (!id || !id->view) return EINA_FALSE;
4957
4958    if (!evas_object_visible_get(id->view))
4959      return EINA_FALSE;
4960
4961    if (!_elm_widget_onscreen_is(id->widget))
4962      return EINA_FALSE;
4963
4964    evas_object_geometry_get(id->view, &x, &y, &w, &h);
4965    evas_object_geometry_get(id->widget, &wx, &wy, &ww, &wh);
4966    if (((wx < x) && (wx + ww < x)) || ((wx > x + w) && (wx + ww > x + w)) ||
4967        ((wy < y) && (wy + wh < y)) || ((wy > y+ h) && (wy + wh > y + h)))
4968      return EINA_FALSE;
4969
4970    return EINA_TRUE;
4971 }
4972
4973 //TIZEN_ONLY(20161107): enhance elm_atspi_accessible_can_highlight_set to set can_hihglight property to its children
4974 EAPI Eina_Bool
4975 _elm_widget_item_highlightable(Elm_Object_Item *item)
4976 {
4977    Elm_Widget_Item_Data *id = eo_data_scope_get(item, ELM_WIDGET_ITEM_CLASS);
4978    if (!id) return EINA_FALSE;
4979    if (!id->can_highlight) return EINA_FALSE;
4980    Evas_Object *widget = id->widget;
4981    Evas_Object *parent = widget;
4982    Elm_Widget_Smart_Data *wd;
4983    if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
4984      {
4985         wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
4986         if (!wd->can_highlight) return EINA_FALSE;
4987      }
4988    do
4989      {
4990         parent = elm_widget_parent_get(parent);
4991         if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
4992           {
4993              wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
4994              if (!wd->can_highlight) return EINA_FALSE;
4995           }
4996      }
4997    while (parent && (parent != elm_widget_top_get(widget)));
4998    return EINA_TRUE;
4999 }
5000 //
5001
5002 EOLIAN static Elm_Atspi_State_Set
5003 _elm_widget_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_item,
5004                                                               Elm_Widget_Item_Data *item)
5005 {
5006    Elm_Atspi_State_Set states = 0;
5007
5008    STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE);
5009
5010    if (elm_object_item_focus_get(eo_item))
5011      STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED);
5012    if (!elm_object_item_disabled_get(eo_item))
5013      {
5014         STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED);
5015         STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE);
5016         STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE);
5017      }
5018    if (_elm_widget_item_onscreen_is(eo_item))
5019      STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING);
5020
5021    //TIZEN_ONLY(20170717) : expose highlight information on atspi
5022    if (_elm_widget_item_highlightable(eo_item))
5023      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
5024    else
5025      STATE_TYPE_UNSET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
5026
5027    if (_elm_object_accessibility_currently_highlighted_get() == (void*)item->eo_obj)
5028      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTED);
5029    //
5030    return states;
5031 }
5032
5033 EOLIAN static Eo*
5034 _elm_widget_item_elm_interface_atspi_accessible_parent_get(Eo *eo_item, Elm_Widget_Item_Data *item EINA_UNUSED)
5035 {
5036    Eo *parent;
5037    eo_do(eo_item, parent = eo_parent_get());
5038    return parent;
5039 }
5040
5041 EAPI void
5042 elm_object_item_data_set(Elm_Object_Item *it, void *data)
5043 {
5044    WIDGET_ITEM_DATA_SET(it, data);
5045 }
5046
5047 EAPI void *
5048 elm_object_item_data_get(const Elm_Object_Item *it)
5049 {
5050    return (void *) WIDGET_ITEM_DATA_GET(it);
5051 }
5052
5053 EOLIAN static void
5054 _elm_widget_item_disabled_set(Eo *eo_item EINA_UNUSED,
5055                               Elm_Widget_Item_Data *item,
5056                               Eina_Bool disabled)
5057 {
5058    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5059    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5060
5061    if (item->disabled == disabled) return;
5062    item->disabled = !!disabled;
5063    eo_do(item->eo_obj, elm_wdg_item_disable());
5064 }
5065
5066 EOLIAN static Eina_Bool
5067 _elm_widget_item_disabled_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5068 {
5069    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5070    return item->disabled;
5071 }
5072
5073 EOLIAN static void
5074 _elm_widget_item_style_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *style EINA_UNUSED)
5075 {
5076    ERR_NOT_SUPPORTED(item, "elm_object_style_set()");
5077 }
5078
5079 EOLIAN static const char *
5080 _elm_widget_item_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5081 {
5082    ERR_NOT_SUPPORTED(item, "elm_object_style_get()");
5083    return NULL;
5084 }
5085
5086 EOLIAN static void
5087 _elm_widget_item_disable(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED)
5088 {
5089 }
5090
5091 EOLIAN static void
5092 _elm_widget_item_focus_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool focused EINA_UNUSED)
5093 {
5094    ERR_NOT_SUPPORTED(item, "elm_object_item_focus_set");
5095 }
5096
5097 EOLIAN static Eina_Bool
5098 _elm_widget_item_focus_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5099 {
5100    ERR_NOT_SUPPORTED(item, "elm_object_item_focus_get");
5101    return EINA_FALSE;
5102 }
5103
5104 EOLIAN static void
5105 _elm_widget_item_domain_translatable_part_text_set(Eo *eo_item EINA_UNUSED,
5106                                                    Elm_Widget_Item_Data *item,
5107                                                    const char *part,
5108                                                    const char *domain,
5109                                                    const char *label)
5110 {
5111    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5112    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5113    Elm_Translate_String_Data *ts;
5114
5115    if (!label)
5116      {
5117         _part_text_translatable_set(&item->translate_strings, part, EINA_FALSE,
5118                                     EINA_FALSE);
5119      }
5120    else
5121      {
5122         ts = _part_text_translatable_set(&item->translate_strings, part,
5123                                          EINA_TRUE, EINA_FALSE);
5124         if (!ts) return;
5125         if (!ts->string) ts->string = eina_stringshare_add(label);
5126         else eina_stringshare_replace(&ts->string, label);
5127         if (!ts->domain) ts->domain = eina_stringshare_add(domain);
5128         else eina_stringshare_replace(&ts->domain, domain);
5129 #ifdef HAVE_GETTEXT
5130         if (label[0]) label = dgettext(domain, label);
5131 #endif
5132      }
5133    item->on_translate = EINA_TRUE;
5134    eo_do(item->eo_obj, elm_wdg_item_part_text_set(part, label));
5135    item->on_translate = EINA_FALSE;
5136 }
5137
5138 EOLIAN static const char *
5139 _elm_widget_item_translatable_part_text_get(const Eo *eo_item EINA_UNUSED,
5140                                             Elm_Widget_Item_Data *item,
5141                                             const char *part)
5142 {
5143    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5144    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
5145
5146    Elm_Translate_String_Data *ts;
5147    ts = _translate_string_data_get(item->translate_strings, part);
5148    if (ts) return ts->string;
5149    return NULL;
5150 }
5151
5152 EOLIAN static void
5153 _elm_widget_item_domain_part_text_translatable_set(Eo *eo_item EINA_UNUSED,
5154                                                    Elm_Widget_Item_Data *item,
5155                                                    const char *part,
5156                                                    const char *domain,
5157                                                    Eina_Bool translatable)
5158 {
5159    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5160    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5161    Elm_Translate_String_Data *ts;
5162    const char *text;
5163
5164    ts = _part_text_translatable_set(&item->translate_strings, part,
5165                                     translatable, EINA_TRUE);
5166    if (!ts) return;
5167    if (!ts->domain) ts->domain = eina_stringshare_add(domain);
5168    else eina_stringshare_replace(&ts->domain, domain);
5169
5170    eo_do(item->eo_obj, text = elm_wdg_item_part_text_get(part));
5171
5172    if (!text || !text[0]) return;
5173
5174    if (!ts->string) ts->string = eina_stringshare_add(text);
5175
5176 //Try to translate text since we don't know the text is already translated.
5177 #ifdef HAVE_GETTEXT
5178    text = dgettext(domain, text);
5179 #endif
5180    item->on_translate = EINA_TRUE;
5181    eo_do (item->eo_obj, elm_wdg_item_part_text_set(part, text));
5182    item->on_translate = EINA_FALSE;
5183 }
5184
5185 EOLIAN static void
5186 _elm_widget_item_track_cancel(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5187 {
5188    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5189    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5190
5191    if (!item->track_obj) return;
5192
5193    while (evas_object_ref_get(item->track_obj) > 0)
5194      evas_object_unref(item->track_obj);
5195
5196    evas_object_del(item->track_obj);
5197 }
5198
5199 EOLIAN static Evas_Object *
5200 _elm_widget_item_track(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5201 {
5202    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5203    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
5204
5205    if (item->track_obj)
5206      {
5207         evas_object_ref(item->track_obj);
5208         return item->track_obj;
5209      }
5210
5211    if (!item->view)
5212      {
5213         WRN("view obj of the item(%p) is invalid. Please make sure the view obj is created!", item);
5214         return NULL;
5215      }
5216
5217    Evas_Object *track =
5218       evas_object_rectangle_add(evas_object_evas_get(item->widget));
5219    evas_object_color_set(track, 0, 0, 0, 0);
5220    evas_object_pass_events_set(track, EINA_TRUE);
5221    _track_obj_update(track, item->view);
5222    evas_object_event_callback_add(track, EVAS_CALLBACK_DEL, _track_obj_del,
5223                                   item);
5224
5225    eo_do(item->view,
5226          eo_event_callback_array_add(tracker_callbacks(), item));
5227
5228    evas_object_ref(track);
5229
5230    item->track_obj = track;
5231
5232    return track;
5233 }
5234
5235 EOLIAN static void
5236 _elm_widget_item_untrack(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5237 {
5238    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5239    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5240
5241    if (!item->track_obj) return;
5242    evas_object_unref(item->track_obj);
5243
5244    if (evas_object_ref_get(item->track_obj) == 0)
5245      evas_object_del(item->track_obj);
5246 }
5247
5248 EOLIAN static int
5249 _elm_widget_item_track_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5250 {
5251    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, 0);
5252    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, 0);
5253
5254    if (!item->track_obj) return 0;
5255    return evas_object_ref_get(item->track_obj);
5256 }
5257
5258 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
5259
5260 struct _Elm_Widget_Item_Tooltip
5261 {
5262    Elm_Widget_Item_Data       *item;
5263    Elm_Tooltip_Item_Content_Cb func;
5264    Evas_Smart_Cb               del_cb;
5265    const void                 *data;
5266 };
5267
5268 static Evas_Object *
5269 _elm_widget_item_tooltip_label_create(void *data,
5270                                       Evas_Object *obj EINA_UNUSED,
5271                                       Evas_Object *tooltip,
5272                                       void *item EINA_UNUSED)
5273 {
5274    Evas_Object *label = elm_label_add(tooltip);
5275    if (!label)
5276      return NULL;
5277    elm_object_style_set(label, "tooltip");
5278    elm_object_text_set(label, data);
5279    return label;
5280 }
5281
5282 static Evas_Object *
5283 _elm_widget_item_tooltip_trans_label_create(void *data,
5284                                             Evas_Object *obj EINA_UNUSED,
5285                                             Evas_Object *tooltip,
5286                                             void *item EINA_UNUSED)
5287 {
5288    Evas_Object *label = elm_label_add(tooltip);
5289    if (!label)
5290      return NULL;
5291    elm_object_style_set(label, "tooltip");
5292    elm_object_translatable_text_set(label, data);
5293    return label;
5294 }
5295
5296 static void
5297 _elm_widget_item_tooltip_label_del_cb(void *data,
5298                                       Evas_Object *obj EINA_UNUSED,
5299                                       void *event_info EINA_UNUSED)
5300 {
5301    eina_stringshare_del(data);
5302 }
5303
5304 /**
5305  * @internal
5306  *
5307  * Set the text to be shown in the widget item.
5308  *
5309  * @param item Target item
5310  * @param text The text to set in the content
5311  *
5312  * Setup the text as tooltip to object. The item can have only one tooltip,
5313  * so any previous tooltip data is removed.
5314  *
5315  * @ingroup Widget
5316  */
5317 EOLIAN static void
5318 _elm_widget_item_tooltip_text_set(Eo *eo_item EINA_UNUSED,
5319                                   Elm_Widget_Item_Data *item EINA_UNUSED,
5320                                   const char *text)
5321 {
5322    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5323    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5324    EINA_SAFETY_ON_NULL_RETURN(text);
5325
5326    text = eina_stringshare_add(text);
5327    eo_do(item->eo_obj, elm_wdg_item_tooltip_content_cb_set(
5328             _elm_widget_item_tooltip_label_create,
5329             text,
5330             _elm_widget_item_tooltip_label_del_cb));
5331 }
5332
5333 EOLIAN static void
5334 _elm_widget_item_tooltip_translatable_text_set(Eo *eo_item EINA_UNUSED,
5335                                                Elm_Widget_Item_Data *item EINA_UNUSED,
5336                                                const char *text)
5337 {
5338    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5339    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5340    EINA_SAFETY_ON_NULL_RETURN(text);
5341
5342    text = eina_stringshare_add(text);
5343    eo_do(item->eo_obj, elm_wdg_item_tooltip_content_cb_set(
5344             _elm_widget_item_tooltip_trans_label_create,
5345             text,
5346             _elm_widget_item_tooltip_label_del_cb));
5347 }
5348
5349 static Evas_Object *
5350 _elm_widget_item_tooltip_create(void *data,
5351                                 Evas_Object *obj,
5352                                 Evas_Object *tooltip)
5353 {
5354    Elm_Widget_Item_Tooltip *wit = data;
5355    return wit->func((void *)wit->data, obj, tooltip, wit->item->eo_obj);
5356 }
5357
5358 static void
5359 _elm_widget_item_tooltip_del_cb(void *data,
5360                                 Evas_Object *obj,
5361                                 void *event_info EINA_UNUSED)
5362 {
5363    Elm_Widget_Item_Tooltip *wit = data;
5364    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item->eo_obj);
5365    free(wit);
5366 }
5367
5368 /**
5369  * @internal
5370  *
5371  * Set the content to be shown in the tooltip item
5372  *
5373  * Setup the tooltip to item. The item can have only one tooltip,
5374  * so any previous tooltip data is removed. @p func(with @p data) will
5375  * be called every time that need show the tooltip and it should
5376  * return a valid Evas_Object. This object is then managed fully by
5377  * tooltip system and is deleted when the tooltip is gone.
5378  *
5379  * @param item the widget item being attached a tooltip.
5380  * @param func the function used to create the tooltip contents.
5381  * @param data what to provide to @a func as callback data/context.
5382  * @param del_cb called when data is not needed anymore, either when
5383  *        another callback replaces @func, the tooltip is unset with
5384  *        elm_widget_item_tooltip_unset() or the owner @a item
5385  *        dies. This callback receives as the first parameter the
5386  *        given @a data, and @c event_info is the item.
5387  *
5388  * @ingroup Widget
5389  */
5390 EOLIAN static void
5391 _elm_widget_item_tooltip_content_cb_set(Eo *eo_item EINA_UNUSED,
5392                                         Elm_Widget_Item_Data *item,
5393                                         Elm_Tooltip_Item_Content_Cb func,
5394                                         const void *data,
5395                                         Evas_Smart_Cb del_cb)
5396 {
5397    Elm_Widget_Item_Tooltip *wit;
5398
5399    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
5400    //ELM_WIDGET_ITEM_RETURN_IF_GOTO(item, error_noitem);
5401
5402    if (!func)
5403      {
5404         eo_do(item->eo_obj, elm_wdg_item_tooltip_unset());
5405         return;
5406      }
5407
5408    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
5409    if (!wit) goto error;
5410    wit->item = item;
5411    wit->func = func;
5412    wit->data = data;
5413    wit->del_cb = del_cb;
5414
5415    elm_object_sub_tooltip_content_cb_set
5416      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
5417      _elm_widget_item_tooltip_del_cb);
5418
5419    return;
5420
5421 error_noitem:
5422    if (del_cb) del_cb((void *)data, NULL, item);
5423    return;
5424 error:
5425    if (del_cb) del_cb((void *)data, item->widget, item);
5426 }
5427
5428 /**
5429  * @internal
5430  *
5431  * Unset tooltip from item
5432  *
5433  * @param item widget item to remove previously set tooltip.
5434  *
5435  * Remove tooltip from item. The callback provided as del_cb to
5436  * elm_widget_item_tooltip_content_cb_set() will be called to notify
5437  * it is not used anymore.
5438  *
5439  * @see elm_widget_item_tooltip_content_cb_set()
5440  *
5441  * @ingroup Widget
5442  */
5443 EOLIAN static void
5444 _elm_widget_item_tooltip_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5445 {
5446    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5447    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5448
5449    elm_object_tooltip_unset(item->view);
5450 }
5451
5452 /**
5453  * @internal
5454  *
5455  * Sets a different style for this item tooltip.
5456  *
5457  * @note before you set a style you should define a tooltip with
5458  *       elm_widget_item_tooltip_content_cb_set() or
5459  *       elm_widget_item_tooltip_text_set()
5460  *
5461  * @param item widget item with tooltip already set.
5462  * @param style the theme style to use (default, transparent, ...)
5463  *
5464  * @ingroup Widget
5465  */
5466 EOLIAN static void
5467 _elm_widget_item_tooltip_style_set(Eo *eo_item EINA_UNUSED,
5468                                    Elm_Widget_Item_Data *item,
5469                                    const char *style)
5470 {
5471    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5472    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5473
5474    elm_object_tooltip_style_set(item->view, style);
5475 }
5476
5477 EOLIAN static Eina_Bool
5478 _elm_widget_item_tooltip_window_mode_set(Eo *eo_item EINA_UNUSED,
5479                                          Elm_Widget_Item_Data *item,
5480                                          Eina_Bool disable)
5481 {
5482    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5483    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
5484
5485    return elm_object_tooltip_window_mode_set(item->view, disable);
5486 }
5487
5488 EOLIAN static Eina_Bool
5489 _elm_widget_item_tooltip_window_mode_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5490 {
5491    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5492    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
5493
5494    return elm_object_tooltip_window_mode_get(item->view);
5495 }
5496
5497 /**
5498  * @internal
5499  *
5500  * Get the style for this item tooltip.
5501  *
5502  * @param item widget item with tooltip already set.
5503  * @return style the theme style in use, defaults to "default". If the
5504  *         object does not have a tooltip set, then NULL is returned.
5505  *
5506  * @ingroup Widget
5507  */
5508 EOLIAN static const char *
5509 _elm_widget_item_tooltip_style_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5510 {
5511    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5512
5513    return elm_object_tooltip_style_get(item->view);
5514 }
5515
5516 EOLIAN static void
5517 _elm_widget_item_cursor_set(Eo *eo_item EINA_UNUSED,
5518                             Elm_Widget_Item_Data *item,
5519                             const char *cursor)
5520 {
5521    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5522    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5523
5524    elm_object_sub_cursor_set(item->view, item->widget, cursor);
5525 }
5526
5527 EOLIAN static const char *
5528 _elm_widget_item_cursor_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5529 {
5530    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5531    return elm_object_cursor_get(item->view);
5532 }
5533
5534 EOLIAN static void
5535 _elm_widget_item_cursor_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5536 {
5537    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5538    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5539
5540    elm_object_cursor_unset(item->view);
5541 }
5542
5543 /**
5544  * @internal
5545  *
5546  * Sets a different style for this item cursor.
5547  *
5548  * @note before you set a style you should define a cursor with
5549  *       elm_widget_item_cursor_set()
5550  *
5551  * @param item widget item with cursor already set.
5552  * @param style the theme style to use (default, transparent, ...)
5553  *
5554  * @ingroup Widget
5555  */
5556 EOLIAN static void
5557 _elm_widget_item_cursor_style_set(Eo *eo_item EINA_UNUSED,
5558                                   Elm_Widget_Item_Data *item,
5559                                   const char *style)
5560 {
5561    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5562    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5563
5564    elm_object_cursor_style_set(item->view, style);
5565 }
5566
5567 /**
5568  * @internal
5569  *
5570  * Get the style for this item cursor.
5571  *
5572  * @param item widget item with cursor already set.
5573  * @return style the theme style in use, defaults to "default". If the
5574  *         object does not have a cursor set, then NULL is returned.
5575  *
5576  * @ingroup Widget
5577  */
5578 EOLIAN static const char *
5579 _elm_widget_item_cursor_style_get(Eo *eo_item EINA_UNUSED,
5580                                   Elm_Widget_Item_Data *item)
5581 {
5582    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5583    return elm_object_cursor_style_get(item->view);
5584 }
5585
5586 /**
5587  * @internal
5588  *
5589  * Set if the cursor set should be searched on the theme or should use
5590  * the provided by the engine, only.
5591  *
5592  * @note before you set if should look on theme you should define a cursor
5593  * with elm_object_cursor_set(). By default it will only look for cursors
5594  * provided by the engine.
5595  *
5596  * @param item widget item with cursor already set.
5597  * @param engine_only boolean to define it cursors should be looked only
5598  * between the provided by the engine or searched on widget's theme as well.
5599  *
5600  * @ingroup Widget
5601  */
5602 EOLIAN static void
5603 _elm_widget_item_cursor_engine_only_set(Eo *eo_item EINA_UNUSED,
5604                                         Elm_Widget_Item_Data *item,
5605                                         Eina_Bool engine_only)
5606 {
5607    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5608    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5609
5610    elm_object_cursor_theme_search_enabled_set(item->view, !engine_only);
5611 }
5612
5613 /**
5614  * @internal
5615  *
5616  * Get the cursor engine only usage for this item cursor.
5617  *
5618  * @param item widget item with cursor already set.
5619  * @return engine_only boolean to define it cursors should be looked only
5620  * between the provided by the engine or searched on widget's theme as well. If
5621  *         the object does not have a cursor set, then EINA_FALSE is returned.
5622  *
5623  * @ingroup Widget
5624  */
5625 EOLIAN static Eina_Bool
5626 _elm_widget_item_cursor_engine_only_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5627 {
5628    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
5629    return !elm_object_cursor_theme_search_enabled_get(item->view);
5630 }
5631
5632 EOLIAN static void
5633 _elm_widget_item_part_content_set(Eo *eo_item EINA_UNUSED,
5634                                   Elm_Widget_Item_Data *item,
5635                                   const char *part EINA_UNUSED,
5636                                   Evas_Object *content EINA_UNUSED)
5637 {
5638    ERR_NOT_SUPPORTED(item, "elm_object_part_content_set()");
5639 }
5640
5641 EOLIAN static Evas_Object *
5642 _elm_widget_item_part_content_get(Eo *eo_item EINA_UNUSED,
5643                                   Elm_Widget_Item_Data *item,
5644                                   const char *part EINA_UNUSED)
5645 {
5646    ERR_NOT_SUPPORTED(item, "elm_object_part_content_get()");
5647    return NULL;
5648 }
5649
5650 EOLIAN static Evas_Object *
5651 _elm_widget_item_part_content_unset(Eo *eo_item EINA_UNUSED,
5652                                     Elm_Widget_Item_Data *item,
5653                                     const char *part EINA_UNUSED)
5654 {
5655    ERR_NOT_SUPPORTED(item, "elm_object_part_content_unset()");
5656    return NULL;
5657 }
5658
5659 EOLIAN static void
5660 _elm_widget_item_part_text_set(Eo *eo_item EINA_UNUSED,
5661                                Elm_Widget_Item_Data *item,
5662                                const char *part EINA_UNUSED,
5663                                const char *label EINA_UNUSED)
5664 {
5665    ERR_NOT_SUPPORTED(item, "elm_object_part_text_set()");
5666 }
5667
5668 EOLIAN static const char *
5669 _elm_widget_item_part_text_get(Eo *eo_item EINA_UNUSED,
5670                                Elm_Widget_Item_Data *item,
5671                                const char *part EINA_UNUSED)
5672 {
5673    ERR_NOT_SUPPORTED(item, "elm_object_part_text_get()");
5674    return NULL;
5675 }
5676
5677 static void
5678 _elm_widget_item_part_text_custom_free(void *data)
5679 {
5680    Elm_Label_Data *label;
5681    label = data;
5682    eina_stringshare_del(label->part);
5683    eina_stringshare_del(label->text);
5684    free(label);
5685 }
5686
5687 EOLIAN static void
5688 _elm_widget_item_part_text_custom_set(Eo *eo_item EINA_UNUSED,
5689                                       Elm_Widget_Item_Data *item,
5690                                       const char *part,
5691                                       const char *text)
5692 {
5693    Elm_Label_Data *label;
5694    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5695    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5696
5697    if (!item->labels)
5698      item->labels =
5699         eina_hash_stringshared_new(_elm_widget_item_part_text_custom_free);
5700    label = eina_hash_find(item->labels, part);
5701    if (!label)
5702      {
5703         label = malloc(sizeof(Elm_Label_Data));
5704         if (!label)
5705           {
5706              ERR("Failed to allocate memory");
5707              return;
5708           }
5709         label->part = eina_stringshare_add(part);
5710         label->text = eina_stringshare_add(text);
5711         eina_hash_add(item->labels, part, label);
5712      }
5713    else
5714      eina_stringshare_replace(&label->text, text);
5715 }
5716
5717 EOLIAN static const char *
5718 _elm_widget_item_part_text_custom_get(Eo *eo_item EINA_UNUSED,
5719                                       Elm_Widget_Item_Data *item,
5720                                       const char *part)
5721 {
5722    Elm_Label_Data *label;
5723    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5724    label = eina_hash_find(item->labels, part);
5725    return label ? label->text : NULL;
5726 }
5727
5728 static Eina_Bool
5729 _elm_widget_item_part_text_custom_foreach(const Eina_Hash *labels EINA_UNUSED,
5730                                           const void *key EINA_UNUSED,
5731                                           void *data,
5732                                           void *func_data)
5733 {
5734    Elm_Label_Data *label;
5735    Elm_Widget_Item_Data *item;
5736    label = data;
5737    item = func_data;
5738
5739    eo_do(item->eo_obj, elm_wdg_item_part_text_set(label->part, label->text));
5740
5741    return EINA_TRUE;
5742 }
5743
5744 EOLIAN static void
5745 _elm_widget_item_part_text_custom_update(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5746 {
5747    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5748    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5749    if (item->labels)
5750      eina_hash_foreach(item->labels,
5751                        _elm_widget_item_part_text_custom_foreach, item);
5752 }
5753
5754 EOLIAN static void
5755 _elm_widget_item_signal_emit(Eo *eo_item EINA_UNUSED,
5756                              Elm_Widget_Item_Data *item EINA_UNUSED,
5757                              const char *emission EINA_UNUSED,
5758                              const char *source EINA_UNUSED)
5759 {
5760
5761 }
5762
5763 EOLIAN static void
5764 _elm_widget_item_signal_callback_add(Eo *eo_item,
5765                                      Elm_Widget_Item_Data *item,
5766                                      const char *emission,
5767                                      const char *source,
5768                                      Elm_Object_Item_Signal_Cb func,
5769                                      void *data)
5770 {
5771    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5772    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5773    EINA_SAFETY_ON_NULL_RETURN(func);
5774
5775    Elm_Widget_Item_Signal_Data *wisd;
5776
5777    wisd = malloc(sizeof(Elm_Widget_Item_Signal_Data));
5778    if (!wisd) return;
5779
5780    wisd->item = eo_item;
5781    wisd->func = (Elm_Widget_Item_Signal_Cb)func;
5782    wisd->data = data;
5783    wisd->emission = eina_stringshare_add(emission);
5784    wisd->source = eina_stringshare_add(source);
5785
5786    if (_elm_widget_is(item->view))
5787      elm_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
5788    else if (eo_isa(item->view, EDJE_OBJECT_CLASS))
5789      edje_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
5790    else
5791      {
5792         WRN("The %s widget item doesn't support signal callback add!",
5793             eo_class_name_get(eo_class_get(item->widget)));
5794         free(wisd);
5795         return;
5796      }
5797
5798    item->signals = eina_list_append(item->signals, wisd);
5799 }
5800
5801 EOLIAN static void *
5802 _elm_widget_item_signal_callback_del(Eo *eo_item EINA_UNUSED,
5803                                      Elm_Widget_Item_Data *item,
5804                                      const char *emission,
5805                                      const char *source,
5806                                      Elm_Object_Item_Signal_Cb func)
5807 {
5808    Elm_Widget_Item_Signal_Data *wisd;
5809    Eina_List *l;
5810
5811    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
5812    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
5813    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
5814
5815    EINA_LIST_FOREACH(item->signals, l, wisd)
5816      {
5817         if ((wisd->func == (Elm_Widget_Item_Signal_Cb)func) &&
5818             !strcmp(wisd->emission, emission) &&
5819             !strcmp(wisd->source, source))
5820           return _elm_widget_item_signal_callback_list_get(item, l);
5821      }
5822
5823    return NULL;
5824 }
5825
5826 EOLIAN static void
5827 _elm_widget_item_access_info_set(Eo *eo_item EINA_UNUSED,
5828                                  Elm_Widget_Item_Data *item,
5829                                  const char *txt)
5830 {
5831    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5832    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5833
5834    eina_stringshare_del(item->access_info);
5835    if (!txt) item->access_info = NULL;
5836    else item->access_info = eina_stringshare_add(txt);
5837 }
5838
5839 EOLIAN static void
5840 _elm_widget_item_translate(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5841 {
5842    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
5843    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
5844
5845 #ifdef HAVE_GETTEXT
5846    Elm_Translate_String_Data *ts;
5847    EINA_INLIST_FOREACH(item->translate_strings, ts)
5848      {
5849         if (!ts->string) continue;
5850         const char *s = dgettext(ts->domain, ts->string);
5851         item->on_translate = EINA_TRUE;
5852         eo_do(item->eo_obj, elm_wdg_item_part_text_set(ts->id, s));
5853         item->on_translate = EINA_FALSE;
5854      }
5855 #endif
5856 }
5857
5858 EOLIAN static void
5859 _elm_widget_item_access_order_set(Eo *eo_item EINA_UNUSED,
5860                                   Elm_Widget_Item_Data *item,
5861                                   Eina_List *objs)
5862 {
5863    _elm_access_widget_item_access_order_set(item, objs);
5864 }
5865
5866 EOLIAN static const Eina_List *
5867 _elm_widget_item_access_order_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5868 {
5869    return _elm_access_widget_item_access_order_get(item);
5870 }
5871
5872 EOLIAN static void
5873 _elm_widget_item_access_order_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5874 {
5875    _elm_access_widget_item_access_order_unset(item);
5876 }
5877
5878 EOLIAN static Evas_Object*
5879 _elm_widget_item_access_register(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5880 {
5881    _elm_access_widget_item_register(item);
5882    return item->access_obj;
5883 }
5884
5885 EOLIAN static void
5886 _elm_widget_item_access_unregister(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5887 {
5888    _elm_access_widget_item_unregister(item);
5889 }
5890
5891 EOLIAN static Evas_Object*
5892 _elm_widget_item_access_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
5893 {
5894    return item->access_obj;
5895 }
5896
5897 EOLIAN static Evas_Object *
5898 _elm_widget_item_focus_next_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir)
5899 {
5900    Evas_Object *ret = NULL;
5901
5902    if (dir == ELM_FOCUS_PREVIOUS)
5903      ret = item->focus_previous;
5904    else if (dir == ELM_FOCUS_NEXT)
5905      ret = item->focus_next;
5906    else if (dir == ELM_FOCUS_UP)
5907      ret = item->focus_up;
5908    else if (dir == ELM_FOCUS_DOWN)
5909      ret = item->focus_down;
5910    else if (dir == ELM_FOCUS_RIGHT)
5911      ret = item->focus_right;
5912    else if (dir == ELM_FOCUS_LEFT)
5913      ret = item->focus_left;
5914
5915    return ret;
5916 }
5917
5918 EOLIAN static void
5919 _elm_widget_item_focus_next_object_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Evas_Object *next, Elm_Focus_Direction dir)
5920 {
5921    if (dir == ELM_FOCUS_PREVIOUS)
5922      item->focus_previous = next;
5923    else if (dir == ELM_FOCUS_NEXT)
5924      item->focus_next = next;
5925    else if (dir == ELM_FOCUS_UP)
5926      item->focus_up = next;
5927    else if (dir == ELM_FOCUS_DOWN)
5928      item->focus_down = next;
5929    else if (dir == ELM_FOCUS_RIGHT)
5930      item->focus_right = next;
5931    else if (dir == ELM_FOCUS_LEFT)
5932      item->focus_left = next;
5933 }
5934
5935 EOLIAN static Elm_Object_Item*
5936 _elm_widget_item_focus_next_item_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir)
5937 {
5938    Elm_Object_Item *ret = NULL;
5939
5940    if (dir == ELM_FOCUS_PREVIOUS)
5941      ret = item->item_focus_previous;
5942    else if (dir == ELM_FOCUS_NEXT)
5943      ret = item->item_focus_next;
5944    else if (dir == ELM_FOCUS_UP)
5945      ret = item->item_focus_up;
5946    else if (dir == ELM_FOCUS_DOWN)
5947      ret = item->item_focus_down;
5948    else if (dir == ELM_FOCUS_RIGHT)
5949      ret = item->item_focus_right;
5950    else if (dir == ELM_FOCUS_LEFT)
5951      ret = item->item_focus_left;
5952
5953    return ret;
5954 }
5955
5956 EOLIAN static void
5957 _elm_widget_item_focus_next_item_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Object_Item *next_item, Elm_Focus_Direction dir)
5958 {
5959    if (dir == ELM_FOCUS_PREVIOUS)
5960      item->item_focus_previous = next_item;
5961    else if (dir == ELM_FOCUS_NEXT)
5962      item->item_focus_next = next_item;
5963    else if (dir == ELM_FOCUS_UP)
5964      item->item_focus_up = next_item;
5965    else if (dir == ELM_FOCUS_DOWN)
5966      item->item_focus_down = next_item;
5967    else if (dir == ELM_FOCUS_RIGHT)
5968      item->item_focus_right = next_item;
5969    else if (dir == ELM_FOCUS_LEFT)
5970      item->item_focus_left = next_item;
5971 }
5972
5973 /* happy debug functions */
5974 #ifdef ELM_DEBUG
5975 static void
5976 _sub_obj_tree_dump(const Evas_Object *obj,
5977                    int lvl)
5978 {
5979    int i;
5980
5981    for (i = 0; i < lvl * 3; i++)
5982      putchar(' ');
5983
5984    if (_elm_widget_is(obj))
5985      {
5986         Eina_List *l;
5987         INTERNAL_ENTRY;
5988         DBG("+ %s(%p)\n",
5989             elm_widget_type_get(obj),
5990             obj);
5991         EINA_LIST_FOREACH(sd->subobjs, l, obj)
5992           _sub_obj_tree_dump(obj, lvl + 1);
5993      }
5994    else
5995      DBG("+ %s(%p)\n", evas_object_type_get(obj), obj);
5996 }
5997
5998 static void
5999 _sub_obj_tree_dot_dump(const Evas_Object *obj,
6000                        FILE *output)
6001 {
6002    if (!_elm_widget_is(obj))
6003      return;
6004    INTERNAL_ENTRY;
6005
6006    Eina_Bool visible = evas_object_visible_get(obj);
6007    Eina_Bool disabled = elm_widget_disabled_get(obj);
6008    Eina_Bool focused = elm_widget_focus_get(obj);
6009    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
6010
6011    if (sd->parent_obj)
6012      {
6013         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
6014
6015         if (focused)
6016           fprintf(output, ", style=bold");
6017
6018         if (!visible)
6019           fprintf(output, ", color=gray28");
6020
6021         fprintf(output, " ];\n");
6022      }
6023
6024    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
6025                    "disabled: %d|focused: %d/%d|focus order:%d}\"",
6026            obj, obj, elm_widget_type_get(obj),
6027            evas_object_name_get(obj), visible, disabled, focused, can_focus,
6028            sd->focus_order);
6029
6030    if (focused)
6031      fprintf(output, ", style=bold");
6032
6033    if (!visible)
6034      fprintf(output, ", fontcolor=gray28");
6035
6036    if ((disabled) || (!visible))
6037      fprintf(output, ", color=gray");
6038
6039    fprintf(output, " ];\n");
6040
6041    Eina_List *l;
6042    Evas_Object *o;
6043    EINA_LIST_FOREACH(sd->subobjs, l, o)
6044      _sub_obj_tree_dot_dump(o, output);
6045 }
6046
6047 #endif
6048
6049 EAPI void
6050 elm_widget_tree_dump(const Evas_Object *top)
6051 {
6052 #ifdef ELM_DEBUG
6053    if (!_elm_widget_is(top))
6054      return;
6055    _sub_obj_tree_dump(top, 0);
6056 #else
6057    (void)top;
6058    return;
6059 #endif
6060 }
6061
6062 EAPI void
6063 elm_widget_tree_dot_dump(const Evas_Object *top,
6064                          FILE *output)
6065 {
6066 #ifdef ELM_DEBUG
6067    if (!_elm_widget_is(top))
6068      return;
6069    fprintf(output, "graph " " { node [shape=record];\n");
6070    _sub_obj_tree_dot_dump(top, output);
6071    fprintf(output, "}\n");
6072 #else
6073    (void)top;
6074    (void)output;
6075    return;
6076 #endif
6077 }
6078
6079 EOLIAN static Eo *
6080 _elm_widget_eo_base_constructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED)
6081 {
6082    Eo *parent = NULL;
6083
6084    sd->on_create = EINA_TRUE;
6085    obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
6086    eo_do(obj,
6087          evas_obj_type_set(MY_CLASS_NAME_LEGACY),
6088          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
6089          parent = eo_parent_get());
6090    eo_do(obj, elm_obj_widget_parent_set(parent));
6091    sd->on_create = EINA_FALSE;
6092    //TIZEN_ONLY(20170717) : expose highlight information on atspi
6093    sd->can_highlight = EINA_TRUE;
6094    //
6095    /* TIZEN_ONLY(20160622): Override Paragraph Direction APIs */
6096    sd->inherit_paragraph_direction = EINA_TRUE;
6097    /* END */
6098
6099    eo_do(obj, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_UNKNOWN));
6100
6101    /* TIZEN_ONLY(20161117): Inherit paragraph direction from widget parent */
6102    if (sd->paragraph_direction != evas_object_paragraph_direction_get(parent))
6103      {
6104         sd->paragraph_direction = evas_object_paragraph_direction_get(parent);
6105         _elm_widget_evas_object_paragraph_direction_set_internal(obj, sd, sd->paragraph_direction);
6106         eo_do_super(obj, MY_CLASS, evas_obj_paragraph_direction_set(sd->paragraph_direction));
6107      }
6108    /* END */
6109
6110    return obj;
6111 }
6112
6113 EOLIAN static void
6114 _elm_widget_eo_base_destructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED)
6115 {
6116    sd->on_destroy = EINA_TRUE;
6117    eo_do(obj,
6118          elm_interface_atspi_accessible_description_set(NULL),
6119          elm_interface_atspi_accessible_name_set(NULL),
6120          //TIZEN_ONLY(20190922): add name callback, description callback.
6121          elm_interface_atspi_accessible_description_cb_set(NULL, NULL),
6122          elm_interface_atspi_accessible_name_cb_set(NULL, NULL),
6123          //
6124          elm_interface_atspi_accessible_translation_domain_set(NULL),
6125          elm_interface_atspi_accessible_relationships_clear(),
6126          // TIZEN_ONLY(20160930) : endless recursion fix
6127          elm_interface_atspi_accessible_attributes_clear()
6128          //
6129          );
6130    // TIZEN_ONLY(20150709) : atspi relations api
6131    if (sd->atspi_custom_relations)
6132      elm_atspi_relation_set_free(&sd->atspi_custom_relations);
6133    //
6134    //TIZEN_ONLY(20150717) add widget name setter
6135    if (sd->name)
6136      eina_stringshare_del(sd->name);
6137    //
6138
6139    //TIZEN_ONLY(20150731) : add i18n support for name and description
6140    if (sd->atspi_translation_domain)
6141      eina_stringshare_del(sd->atspi_translation_domain);
6142    //
6143    //Tizen Only(20160728) free attribute list
6144    if (sd->attr_list)
6145    {
6146       Elm_Atspi_Attribute *attr;
6147       EINA_LIST_FREE(sd->attr_list, attr)
6148        {
6149           eina_stringshare_del(attr->key);
6150           eina_stringshare_del(attr->value);
6151           free(attr);
6152        }
6153    }
6154    //
6155
6156    eo_do_super(obj, ELM_WIDGET_CLASS, eo_destructor());
6157    sd->on_destroy = EINA_FALSE;
6158
6159    elm_interface_atspi_accessible_removed(obj);
6160 }
6161
6162 EOLIAN static Eina_Bool
6163 _elm_widget_on_focus(Eo *obj, Elm_Widget_Smart_Data *sd, Elm_Object_Item *item EINA_UNUSED)
6164 {
6165    if (elm_widget_can_focus_get(obj))
6166      {
6167         if (elm_widget_focus_get(obj))
6168           {
6169              if (!sd->resize_obj)
6170                evas_object_focus_set(obj, EINA_TRUE);
6171               eo_do(obj, eo_event_callback_call
6172                (ELM_WIDGET_EVENT_FOCUSED, NULL));
6173              if (_elm_atspi_enabled() && !elm_widget_child_can_focus_get(obj))
6174                elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE);
6175           }
6176         else
6177           {
6178              if (!sd->resize_obj)
6179                evas_object_focus_set(obj, EINA_FALSE);
6180              eo_do(obj, eo_event_callback_call
6181                (ELM_WIDGET_EVENT_UNFOCUSED, NULL));
6182              if (_elm_atspi_enabled() && !elm_widget_child_can_focus_get(obj))
6183                elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE);
6184     }
6185      }
6186    else
6187      return EINA_FALSE;
6188
6189    return EINA_TRUE;
6190 }
6191
6192 EOLIAN static Eina_Bool
6193 _elm_widget_disable(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6194 {
6195    return EINA_FALSE;
6196 }
6197
6198 EOLIAN static Eina_Bool
6199 _elm_widget_event(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *source EINA_UNUSED, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
6200 {
6201    return EINA_FALSE;
6202 }
6203
6204 EOLIAN static Eina_Bool
6205 _elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6206 {
6207    WRN("The %s widget does not implement the \"focus_next/focus_next_manager_is\" functions.",
6208        eo_class_name_get(eo_class_get(obj)));
6209    return EINA_FALSE;
6210 }
6211
6212 static Eina_Bool
6213 _elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6214 {
6215    WRN("The %s widget does not implement the \"focus_direction/focus_direction_manager_is\" functions.",
6216        eo_class_name_get(eo_class_get(obj)));
6217    return EINA_FALSE;
6218 }
6219
6220 EOLIAN static Eina_Bool
6221 _elm_widget_activate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Elm_Activate act EINA_UNUSED)
6222 {
6223    WRN("The %s widget does not implement the \"activate\" functions.",
6224        eo_class_name_get(eo_class_get(obj)));
6225    return EINA_TRUE;
6226 }
6227
6228 EOLIAN static void
6229 _elm_widget_class_constructor(Eo_Class *klass)
6230 {
6231    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
6232 }
6233
6234 EOLIAN static Eina_Bool
6235 _elm_widget_elm_interface_atspi_component_focus_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6236 {
6237    if (elm_object_focus_allow_get(obj))
6238      {
6239        Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
6240        if (!ee) return EINA_FALSE;
6241        ecore_evas_activate(ee);
6242        elm_object_focus_set(obj, EINA_TRUE);
6243        return EINA_TRUE;
6244      }
6245    return EINA_FALSE;
6246 }
6247
6248 //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods (29e253e2f7ef3c632ac3a64c489bf569df407f30)
6249 EOLIAN static Eina_Bool
6250 _elm_widget_elm_interface_atspi_component_highlight_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6251 {
6252    if(!_elm_atspi_enabled())
6253       return EINA_FALSE;
6254
6255    elm_widget_focus_region_show(obj);
6256
6257    elm_object_accessibility_highlight_set(obj, EINA_TRUE);
6258    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_TRUE);
6259
6260    // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
6261    evas_object_smart_callback_call(obj, SIG_WIDGET_ATSPI_HIGHLIGHTED, NULL);
6262    //
6263    return EINA_TRUE;
6264 }
6265
6266 EOLIAN static Eina_Bool
6267 _elm_widget_elm_interface_atspi_component_highlight_clear(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6268 {
6269    if(!_elm_atspi_enabled())
6270       return EINA_FALSE;
6271    elm_object_accessibility_highlight_set(obj, EINA_FALSE);
6272    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_FALSE);
6273
6274    // TIZEN_ONLY(20161018): add highlighted/unhighlighted signal for atspi
6275    evas_object_smart_callback_call(obj, SIG_WIDGET_ATSPI_UNHIGHLIGHTED, NULL);
6276    //
6277    return EINA_TRUE;
6278 }
6279 //
6280
6281 EOLIAN static const char*
6282 _elm_widget_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd)
6283 {
6284    char *accessible_name;
6285    //TIZEN_ONLY(20190922): add name callback, description callback.
6286    const char *ret = NULL;
6287    eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_name_get());
6288    if (ret) return ret;
6289    //
6290
6291    //TIZEN_ONLY(20150717) add widget name setter
6292    if (_pd->name)
6293      {
6294 #ifdef HAVE_GETTEXT
6295         if (_pd->atspi_translation_domain)
6296           return dgettext(_pd->atspi_translation_domain, _pd->name);
6297 #endif
6298         return _pd->name;
6299      }
6300    //
6301
6302    ret = elm_object_text_get(obj);
6303    if (!ret) return NULL;
6304
6305    accessible_name = _elm_util_mkup_to_text(ret);
6306    eina_stringshare_del(_pd->accessible_name);
6307    _pd->accessible_name =  eina_stringshare_add(accessible_name);
6308    free(accessible_name);
6309    return _pd->accessible_name;
6310 }
6311 //TIZEN_ONLY(20161111) add widget/widget_item description get/set
6312 EOLIAN void
6313 _elm_widget_elm_interface_atspi_accessible_description_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data* _pd EINA_UNUSED, const char *description)
6314 {
6315    if (_pd->description)
6316      eina_stringshare_del(_pd->description);
6317
6318    _pd->description = eina_stringshare_add(description);
6319 }
6320
6321 EOLIAN static const char*
6322 _elm_widget_elm_interface_atspi_accessible_description_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
6323 {
6324    const char *ret = NULL;
6325    eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_description_get());
6326    if (ret) return ret;
6327
6328 #ifdef HAVE_GETTEXT
6329    if (_pd->atspi_translation_domain)
6330      return dgettext(_pd->atspi_translation_domain, _pd->description);
6331 #endif
6332    return _pd->description;
6333 }
6334 //
6335
6336 //TIZEN_ONLY(20150713) : add atspi name setter to widget_item
6337 EOLIAN void
6338 _elm_widget_item_elm_interface_atspi_accessible_name_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data* _pd EINA_UNUSED, const char *name)
6339 {
6340    if (_pd->name)
6341      eina_stringshare_del(_pd->name);
6342
6343    _pd->name = eina_stringshare_add(name);
6344 }
6345
6346 EOLIAN const char*
6347 _elm_widget_item_elm_interface_atspi_accessible_name_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
6348 {
6349    //TIZEN_ONLY(20190922): add name callback, description callback.
6350    const char *ret = NULL;
6351    eo_do_super(obj, ELM_WIDGET_ITEM_CLASS, ret = elm_interface_atspi_accessible_name_get());
6352    if (ret) return ret;
6353    //
6354
6355    if (_pd->name)
6356      {
6357 #ifdef HAVE_GETTEXT
6358         if (_pd->atspi_translation_domain)
6359           return dgettext(_pd->atspi_translation_domain, _pd->name);
6360 #endif
6361         return _pd->name;
6362      }
6363
6364    return NULL;
6365 }
6366 //
6367 //TIZEN_ONLY(20161111) add widget/widget_item description get/set
6368 EOLIAN void
6369 _elm_widget_item_elm_interface_atspi_accessible_description_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data* _pd EINA_UNUSED, const char *description)
6370 {
6371    if (_pd->description)
6372      eina_stringshare_del(_pd->description);
6373
6374    _pd->description = eina_stringshare_add(description);
6375 }
6376
6377 EOLIAN const char*
6378 _elm_widget_item_elm_interface_atspi_accessible_description_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
6379 {
6380    const char *ret = NULL;
6381    eo_do_super(obj, ELM_WIDGET_ITEM_CLASS, ret = elm_interface_atspi_accessible_description_get());
6382    if (ret) return ret;
6383
6384 #ifdef HAVE_GETTEXT
6385    if (_pd->atspi_translation_domain)
6386      return dgettext(_pd->atspi_translation_domain, _pd->description);
6387 #endif
6388    return _pd->description;
6389 }
6390 //
6391 //TIZEN_ONLY(20150709) : spatially sort atspi children
6392 static int _sort_vertically(const void *data1, const void *data2)
6393 {
6394    Evas_Coord y1, y2;
6395    evas_object_geometry_get(data1, NULL, &y1, NULL, NULL);
6396    evas_object_geometry_get(data2, NULL, &y2, NULL, NULL);
6397
6398    return y1 < y2 ? -1 : 1;
6399 }
6400
6401 static int _sort_horizontally(const void *data1, const void *data2)
6402 {
6403    Evas_Coord x1, x2;
6404    evas_object_geometry_get(data1, &x1, NULL, NULL, NULL);
6405    evas_object_geometry_get(data2, &x2, NULL, NULL, NULL);
6406
6407    return x1 < x2 ? -1 : 1;
6408 }
6409
6410 static Eina_List *_lines_split(Eina_List *children)
6411 {
6412    Eo *c;
6413    Eina_List *lines, *line, *l;
6414    Evas_Coord yl, y, hl, h;
6415    lines = line = NULL;
6416
6417    if (!children) return NULL;
6418
6419    EINA_LIST_FOREACH(children, l, c)
6420      {
6421         evas_object_geometry_get(c, NULL, &yl, NULL, &hl);
6422
6423         /* remove child if its height == 0 */
6424         if (hl != 0) break;
6425      }
6426
6427    EINA_LIST_FREE(children, c)
6428      {
6429         evas_object_geometry_get(c, NULL, &y, NULL, &h);
6430
6431         /* remove child if its height == 0 */
6432         if (h == 0) continue;
6433
6434         if ((yl + (int)(0.25 * hl)) >= y)
6435           {
6436              //same line
6437              line = eina_list_append(line,c);
6438           }
6439         else
6440           {
6441              // finish current line & start new
6442              lines = eina_list_append(lines, line);
6443              yl = y, hl = h;
6444              line = eina_list_append(NULL, c);
6445           }
6446      }
6447
6448    return eina_list_append(lines, line);
6449 }
6450 //
6451
6452 // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6453 static void
6454 _proxy_widget_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
6455 {
6456    Evas_Coord x, y;
6457    Eo *proxy = data;
6458
6459    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
6460    elm_atspi_bridge_utils_proxy_offset_set(proxy, x, y);
6461 }
6462 //
6463
6464 static Eina_Bool
6465 _on_widget_del(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
6466 {
6467    Eo *plug = data;
6468    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6469    evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE,
6470                                        _proxy_widget_move_cb, plug);
6471    //
6472    eo_del(plug);
6473    return EINA_TRUE;
6474 }
6475
6476 // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6477 static Eina_Bool
6478 _on_proxy_connected_cb(void *data, Eo *obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED)
6479 {
6480    Evas_Coord x, y;
6481    Evas_Object *widget = data;
6482
6483    evas_object_geometry_get(widget, &x, &y, NULL, NULL);
6484    elm_atspi_bridge_utils_proxy_offset_set(obj, x, y);
6485
6486    evas_object_event_callback_add(widget, EVAS_CALLBACK_MOVE, _proxy_widget_move_cb, obj);
6487    return EINA_TRUE;
6488 }
6489 //
6490 // TIZEN ONLY - END
6491
6492 EOLIAN static Eina_List*
6493 _elm_widget_elm_interface_atspi_accessible_children_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6494 {
6495    Eina_List *l, *accs = NULL;
6496    Elm_Widget_Smart_Data *wd;
6497    Evas_Object *widget;
6498    // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
6499    Eo *parent;
6500    //
6501
6502    wd = eo_data_scope_get(obj, ELM_WIDGET_CLASS);
6503    if (!wd) return NULL;
6504
6505    EINA_LIST_FOREACH(wd->subobjs, l, widget)
6506      {
6507         const char *type = evas_object_type_get(widget);
6508         // TIZEN ONLY
6509         // Ugly Tizen hack to integrate AT-SPI2 accessibility provided by WebKit/Chromium with elementary one.
6510         // This wrapper class should be implemented in Webkit/Chromium EFL ports
6511         if (type && (!strcmp(type, "EWebView") || !strcmp(type, "WebView"))) {
6512            elm_atspi_ewk_wrapper_a11y_init(obj, widget);
6513         }
6514      }
6515
6516    EINA_LIST_FOREACH(wd->subobjs, l, widget)
6517      {
6518         // TIZEN_ONLY(20160824): Do not append a child, if its accessible parent is different with widget parent
6519         if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN)) {
6520            eo_do(widget, parent = elm_interface_atspi_accessible_parent_get());
6521            if (parent && (parent != obj)) continue;
6522         }
6523
6524         // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6525         const char *plug_id_2;
6526         if ((plug_id_2 = evas_object_data_get(widget, "___PLUGID")) != NULL)
6527           {
6528             // TIZEN_ONLY(20160930) : endless recursion fix
6529             eo_do_super(obj, MY_CLASS, elm_interface_atspi_accessible_attribute_append("___PlugID", plug_id_2));
6530
6531              Eo *proxy;
6532              char *svcname, *svcnum;
6533
6534              proxy = evas_object_data_get(widget, "__widget_proxy");
6535              if (proxy)
6536                {
6537                   accs = eina_list_append(accs, proxy);
6538                   continue;
6539                }
6540
6541              if (_elm_atspi_bridge_plug_id_split(plug_id_2, &svcname, &svcnum))
6542                {
6543                   proxy = _elm_atspi_bridge_utils_proxy_create(obj, svcname, atoi(svcnum), ELM_ATSPI_PROXY_TYPE_PLUG);
6544                   evas_object_data_set(widget, "__widget_proxy", proxy);
6545                   eo_do(widget, eo_event_callback_add(EO_EV_DEL, _on_widget_del, proxy));
6546                   eo_do(proxy, eo_event_callback_add(ELM_ATSPI_PROXY_EVENT_CONNECTED,  _on_proxy_connected_cb, widget));
6547                   elm_atspi_bridge_utils_proxy_connect(proxy);
6548                   accs = eina_list_append(accs, proxy);
6549                   free(svcname);
6550                   free(svcnum);
6551                }
6552              continue;
6553           }
6554         //
6555         // TIZEN ONLY - END
6556         if (!elm_object_widget_check(widget)) continue;
6557         if (eo_isa(widget, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6558           accs = eina_list_append(accs, widget);
6559      }
6560    //TIZEN_ONLY(20150709) : spatially sort atspi children
6561    // sort children using its top-left coordinate
6562    accs = eina_list_sort(accs, -1, _sort_vertically);
6563    Eina_List *line, *lines = _lines_split(accs);
6564    accs = NULL;
6565    EINA_LIST_FREE(lines, line)
6566      accs = eina_list_merge(accs, eina_list_sort(line, -1, _sort_horizontally));
6567    //
6568    return accs;
6569 }
6570
6571 EOLIAN static Eo*
6572 _elm_widget_elm_interface_atspi_accessible_parent_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd)
6573 {
6574    Eo *ret;
6575    eo_do_super(obj, ELM_WIDGET_CLASS, ret = elm_interface_atspi_accessible_parent_get());
6576
6577    return ret ? ret : pd->parent_obj;
6578 }
6579
6580 //TIZEN_ONLY(20161107): enhance elm_atspi_accessible_can_highlight_set to set can_hihglight property to its children
6581 EAPI Eina_Bool
6582 _elm_widget_highlightable(Evas_Object *obj)
6583 {
6584    Elm_Widget_Smart_Data *wd = eo_data_scope_get(obj, ELM_WIDGET_CLASS);
6585    if (!wd) return EINA_FALSE;
6586    if (!wd->can_highlight) return EINA_FALSE;
6587    Evas_Object *parent = elm_widget_parent_get(obj);
6588    if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6589      {
6590         wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
6591         if (!wd->can_highlight) return EINA_FALSE;
6592      }
6593    do
6594      {
6595         parent = elm_widget_parent_get(parent);
6596         if (parent && eo_isa(parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
6597           {
6598              wd = eo_data_scope_get(parent, ELM_WIDGET_CLASS);
6599              if (!wd->can_highlight) return EINA_FALSE;
6600           }
6601      }
6602    while (parent && (parent != elm_widget_top_get(obj)));
6603    return EINA_TRUE;
6604 }
6605 //
6606
6607 EOLIAN static Elm_Atspi_State_Set
6608 _elm_widget_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Widget_Smart_Data *pd)
6609 {
6610    Elm_Atspi_State_Set states = 0;
6611
6612    eo_do_super(obj, ELM_WIDGET_CLASS, states = elm_interface_atspi_accessible_state_set_get());
6613
6614    if (evas_object_visible_get(obj))
6615      {
6616         STATE_TYPE_SET(states, ELM_ATSPI_STATE_VISIBLE);
6617         if (_elm_widget_onscreen_is(obj))
6618           STATE_TYPE_SET(states, ELM_ATSPI_STATE_SHOWING);
6619      }
6620    if (!elm_widget_child_can_focus_get(obj))
6621      {
6622         if (elm_object_focus_allow_get(obj))
6623           STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSABLE);
6624         if (elm_object_focus_get(obj))
6625           STATE_TYPE_SET(states, ELM_ATSPI_STATE_FOCUSED);
6626      }
6627    if (!elm_object_disabled_get(obj))
6628      {
6629         STATE_TYPE_SET(states, ELM_ATSPI_STATE_ENABLED);
6630         STATE_TYPE_SET(states, ELM_ATSPI_STATE_SENSITIVE);
6631      }
6632
6633    //TIZEN_ONLY(20170717) : expose highlight information on atspi
6634    if (_elm_widget_highlightable(obj))
6635      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
6636    else
6637      STATE_TYPE_UNSET(states, ELM_ATSPI_STATE_HIGHLIGHTABLE);
6638
6639    if (_elm_object_accessibility_currently_highlighted_get() == (void*)pd->obj)
6640      STATE_TYPE_SET(states, ELM_ATSPI_STATE_HIGHLIGHTED);
6641    //
6642
6643    return states;
6644 }
6645
6646 //TIZEN_ONLY(20160729): attributes_get, append APIs added/updated.
6647 EOLIAN static Eina_List*
6648 _elm_widget_elm_interface_atspi_accessible_attributes_get(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
6649 {
6650    Eina_List *attr_list = NULL;
6651    // TIZEN_ONLY(20160930) : endless recursion fix
6652    eo_do_super(obj, MY_CLASS, attr_list = elm_interface_atspi_accessible_attributes_get());
6653    //
6654    //Add type and style information in addition.
6655    Elm_Atspi_Attribute *attr = NULL;
6656    attr = calloc(1, sizeof(Elm_Atspi_Attribute));
6657    if (attr)
6658      {
6659         attr->key = eina_stringshare_add("type");
6660         attr->value = eina_stringshare_add(elm_widget_type_get(obj));
6661         attr_list = eina_list_append(attr_list, attr);
6662      }
6663
6664    attr = calloc(1, sizeof(Elm_Atspi_Attribute));
6665    if (attr)
6666      {
6667         attr->key = eina_stringshare_add("style");
6668         attr->value = eina_stringshare_add(elm_widget_style_get(obj));
6669         attr_list = eina_list_append(attr_list, attr);
6670      }
6671
6672    return attr_list;
6673 }
6674
6675 //TIZEN_ONLY(20150709) : atspi relations api
6676 EOLIAN static Elm_Atspi_Relation_Set
6677 _elm_widget_elm_interface_atspi_accessible_relation_set_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
6678 {
6679    return elm_atspi_relation_set_clone(&sd->atspi_custom_relations);
6680 }
6681
6682 EOLIAN static Elm_Atspi_Relation_Set
6683 _elm_widget_item_elm_interface_atspi_accessible_relation_set_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd)
6684 {
6685    return elm_atspi_relation_set_clone(&sd->atspi_custom_relations);
6686 }
6687 //
6688
6689 EOLIAN static void
6690 _elm_widget_item_elm_interface_atspi_component_extents_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords, int *x, int *y, int *w, int *h)
6691 {
6692    int ee_x, ee_y;
6693
6694    if (!sd->view)
6695      {
6696         if (x) *x = -1;
6697         if (y) *y = -1;
6698         if (w) *w = -1;
6699         if (h) *h = -1;
6700         return;
6701      }
6702
6703    evas_object_geometry_get(sd->view, x, y, w, h);
6704    if (screen_coords)
6705      {
6706         Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(sd->view));
6707         if (!ee) return;
6708         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
6709         if (x) *x += ee_x;
6710         if (y) *y += ee_y;
6711      }
6712 }
6713
6714 EOLIAN static Eina_Bool
6715 _elm_widget_item_elm_interface_atspi_component_extents_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
6716 {
6717    return EINA_FALSE;
6718 }
6719
6720 EOLIAN static int
6721 _elm_widget_item_elm_interface_atspi_component_layer_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED)
6722 {
6723    if (!sd->view)
6724      return -1;
6725    return evas_object_layer_get(sd->view);
6726 }
6727
6728 EOLIAN static Eina_Bool
6729 _elm_widget_item_elm_interface_atspi_component_focus_grab(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
6730 {
6731    elm_object_item_focus_set(obj, EINA_TRUE);
6732    return elm_object_item_focus_get(obj);
6733 }
6734
6735 //TIZEN_ONLY(20160329): atspi: implement HighlightGrab and HighlightClear methods
6736 EOLIAN static Eina_Bool
6737 _elm_widget_item_elm_interface_atspi_component_highlight_grab(Eo *obj, Elm_Widget_Item_Data *sd)
6738 {
6739
6740    if (!obj) return EINA_FALSE;
6741
6742    Evas_Object *o = elm_object_parent_widget_get(sd->view);
6743    if (_elm_scrollable_is(o))
6744      {
6745         Evas_Coord bx, by, bw, bh;
6746         Evas_Coord x, y, w, h;
6747         Evas_Object *w1 = elm_object_parent_widget_get(o);
6748         evas_object_geometry_get(sd->view, &x, &y, &w, &h);
6749         evas_object_geometry_get(o, &bx, &by, &bw, &bh);
6750         x -= bx;
6751         y -= by;
6752         switch (_elm_config->focus_autoscroll_mode)
6753           {
6754            case ELM_FOCUS_AUTOSCROLL_MODE_SHOW:
6755               eo_do(w1, elm_interface_scrollable_content_region_show(x, y, w, h));
6756               break;
6757            case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN:
6758               eo_do(w1, elm_interface_scrollable_region_bring_in(x, y, w, h));
6759               break;
6760            default:
6761               break;
6762           }
6763      }
6764
6765    elm_object_accessibility_highlight_set(sd->eo_obj, EINA_TRUE);
6766    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_TRUE);
6767
6768    return EINA_TRUE;
6769
6770 }
6771
6772 EOLIAN static Eina_Bool
6773 _elm_widget_item_elm_interface_atspi_component_highlight_clear(Eo *obj, Elm_Widget_Item_Data *sd)
6774 {
6775    if (!obj) return EINA_FALSE;
6776    elm_object_accessibility_highlight_set(sd->eo_obj, EINA_FALSE);
6777    elm_interface_atspi_accessible_state_changed_signal_emit(obj, ELM_ATSPI_STATE_HIGHLIGHTED, EINA_FALSE);
6778    return EINA_TRUE;
6779 }
6780 //
6781
6782 EOLIAN static double
6783 _elm_widget_item_elm_interface_atspi_component_alpha_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED)
6784 {
6785    int alpha;
6786
6787    if (!sd->view) return -1.0;
6788    evas_object_color_get(sd->view, NULL, NULL, NULL, &alpha);
6789    return (double)alpha / 255.0;
6790 }
6791
6792 //TIZEN_ONLY(20150717) add widget name setter
6793 EOLIAN void
6794 _elm_widget_elm_interface_atspi_accessible_name_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data* _pd EINA_UNUSED, const char *name)
6795 {
6796    if (_pd->name)
6797      eina_stringshare_del(_pd->name);
6798
6799    _pd->name = eina_stringshare_add(name);
6800 }
6801 //
6802
6803 //TIZEN_ONLY(20160329): widget: improve accessibile_at_point getter (a8aff0423202b9a55dbb3843205875226678fbd6)
6804 static void
6805 _coordinate_system_based_point_translate(Eo *obj, Eina_Bool screen_coords, int *x, int *y)
6806 {
6807    Ecore_Evas *ee;
6808    int ee_x = 0;
6809    int ee_y = 0;
6810
6811    if (screen_coords)
6812      {
6813         ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
6814         if (!ee) return;
6815
6816         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
6817         *x -= ee_x;
6818         *y -= ee_y;
6819      }
6820 }
6821
6822 static Evas_Object *
6823 _parent_get(Evas_Object *obj)
6824 {
6825    Evas_Object *parent;
6826
6827    parent = evas_object_smart_parent_get(obj);
6828    if (!parent)
6829      {
6830         if (strcmp("Elm_Win", eo_class_name_get(eo_class_get(obj))))
6831           parent = elm_widget_parent_get(obj);
6832      }
6833
6834    return parent;
6835 }
6836
6837 static Eina_Bool
6838 _is_inside(Evas_Object *obj, int x, int y)
6839 {
6840    Eina_Bool ret = EINA_TRUE;
6841    Evas_Coord cx = 0;
6842    Evas_Coord cy = 0;
6843    Evas_Coord cw = 0;
6844    Evas_Coord ch = 0;
6845    if (eo_isa(obj, ELM_WIDGET_ITEM_CLASS))
6846      {
6847         Elm_Widget_Item_Data *id = eo_data_scope_get(obj, ELM_WIDGET_ITEM_CLASS);
6848         evas_object_geometry_get(id->view, &cx, &cy, &cw, &ch);
6849      }
6850    else
6851      evas_object_geometry_get(obj, &cx, &cy, &cw, &ch);
6852
6853    /* check the point is out of bound */
6854    if (x < cx || x > cx + cw || y < cy || y > cy + ch)
6855      {
6856         ret = EINA_FALSE;
6857      }
6858    return ret;
6859 }
6860
6861 static Eina_Bool
6862 _is_ancestor_of(Evas_Object *smart_parent, Evas_Object *obj)
6863 {
6864    Eina_Bool ret = EINA_FALSE;
6865    Evas_Object *parent = elm_widget_parent_get(obj);
6866    while (parent)
6867      {
6868         /* No need to check more, the smart_parent is parent of obj */
6869         if (smart_parent == parent)
6870           {
6871              ret = EINA_TRUE;
6872              break;
6873           }
6874         parent = elm_widget_parent_get(parent);
6875      }
6876
6877    return ret;
6878 }
6879
6880 static Eo *
6881 _accessible_at_point_top_down_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
6882 {
6883    Eina_List *l, *l2, *children, *valid_children = NULL;
6884    Eo *child;
6885    Evas_Object *stack_item;
6886    Eo *compare_obj;
6887    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6888    Eo *proxy;
6889    Evas_Coord px, py, pw, ph;
6890    //
6891
6892    _coordinate_system_based_point_translate(obj, screen_coords, &x, &y);
6893
6894    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
6895
6896    EINA_LIST_FOREACH(children, l2, child)
6897      {
6898         if (_is_inside(child, x, y))
6899           valid_children = eina_list_append(valid_children, child);
6900      }
6901    /* Get evas_object stacked at given x,y coordinates starting from top */
6902    Eina_List *stack = evas_tree_objects_at_xy_get(evas_object_evas_get(obj), NULL, x, y);
6903    /* Foreach stacked object starting from top */
6904    EINA_LIST_FOREACH(stack, l, stack_item)
6905      {
6906         /* Foreach at-spi valid children traverse stack_item evas_objects hierarchy */
6907         EINA_LIST_FOREACH(valid_children, l2, child)
6908           {
6909              Elm_Atspi_Role role;
6910              eo_do(child, role = elm_interface_atspi_accessible_role_get());
6911              if (role == ELM_ATSPI_ROLE_REDUNDANT_OBJECT)
6912                {
6913                   /* The redundant object ignores */
6914                   continue;
6915                }
6916              /* Compare object used to compare with stacked evas objects */
6917              compare_obj = child;
6918              /* In case of widget_items compare should be different then elm_widget_ item  object */
6919              if (eo_isa(child, ELM_WIDGET_ITEM_CLASS))
6920                {
6921                   Elm_Widget_Item_Data *id = eo_data_scope_get(child, ELM_WIDGET_ITEM_CLASS);
6922                   compare_obj = id->view;
6923                }
6924              /* In case of access object compare should be 'wrapped' evas_object */
6925              if (eo_isa(child, ELM_ACCESS_CLASS))
6926                {
6927                    Elm_Access_Info *info = _elm_access_info_get(child);
6928                    if (!info) continue;
6929                    compare_obj = info->part_object;
6930                 }
6931              /* In case of widget is registerd by elm_access_object_register */
6932              Evas_Object *ao = elm_access_object_get(child);
6933              if (ao)
6934                {
6935                   eina_list_free(children);
6936                   eina_list_free(stack);
6937                   return ao;
6938                }
6939
6940              /* In case of ewk wrapper object compare with internal ewk_view evas_object */
6941              if (eo_isa(child, ELM_ATSPI_EWK_WRAPPER_CLASS))
6942                {
6943                   compare_obj = elm_atspi_ewk_wrapper_ewk_view_get(child);
6944                }
6945
6946              /* If spacial eo children do not have backing evas_object continue with search */
6947              if (!compare_obj)
6948                continue;
6949
6950              Evas_Object *smart_parent = stack_item;
6951              while (smart_parent)
6952                {
6953                    if (smart_parent == compare_obj)
6954                      {
6955                         eina_list_free(children);
6956                         eina_list_free(stack);
6957                         return child;
6958                      }
6959
6960                    // TIZEN_ONLY(20160705) - enable atspi_proxy to work
6961                    proxy = evas_object_data_get(smart_parent, "__widget_proxy");
6962                    if (proxy)
6963                      {
6964                         evas_object_geometry_get(smart_parent, &px, &py, &pw, &ph);
6965                         if (x >= px && x <= px + pw && y >= py && y <= py +ph)
6966                           {
6967                              eina_list_free(children);
6968                              eina_list_free(stack);
6969                              return proxy;
6970                           }
6971                      }
6972                    //
6973
6974                    smart_parent = _parent_get(smart_parent);
6975                    if (_is_ancestor_of(smart_parent, obj)) break;
6976                }
6977           }
6978      }
6979
6980    eina_list_free(children);
6981    eina_list_free(stack);
6982    return NULL;
6983 }
6984
6985 static int _sort_by_repeat_events(const void *data1, const void *data2)
6986 {
6987    Eina_Bool repeat1, repeat2;
6988
6989    repeat1 = evas_object_repeat_events_get(data1);
6990    repeat2 = evas_object_repeat_events_get(data2);
6991
6992    if (repeat1 != repeat2 && repeat1 == EINA_TRUE) return 1;
6993    return -1;
6994 }
6995
6996 static Eo *_item_at_point_get(Evas_Object *obj, int x, int y)
6997 {
6998    Eo *child;
6999    Eina_List *l, *children;
7000
7001    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
7002
7003    EINA_LIST_FOREACH(children, l, child)
7004      {
7005         if (_is_inside(child, x, y)) return child;
7006      }
7007
7008    ERR("No child at point (%d, %d) on object %p", x, y, obj);
7009    return NULL;
7010 }
7011
7012 EOLIAN static Eo *
7013 _elm_widget_elm_interface_atspi_component_accessible_at_point_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool screen_coords, int x, int y)
7014 {
7015    Eina_List *l;
7016    Evas_Object *stack_item;
7017
7018    if(strcmp("Elm_Win", eo_class_name_get(eo_class_get(obj))))
7019      return _accessible_at_point_top_down_get(obj, _pd, screen_coords, x, y);
7020
7021    _coordinate_system_based_point_translate(obj, screen_coords, &x, &y);
7022
7023    Eina_List *stack = evas_tree_objects_at_xy_get(evas_object_evas_get(obj), NULL, x, y);
7024    stack = eina_list_sort(stack, -1, _sort_by_repeat_events);
7025
7026    EINA_LIST_FOREACH(stack, l, stack_item)
7027      {
7028         Evas_Object *smart_parent = stack_item;
7029         while (smart_parent)
7030           {
7031              Evas_Object *ao = elm_access_object_get(smart_parent);
7032              if (ao) return ao;
7033
7034              if (eo_isa(smart_parent, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
7035                {
7036                   Eina_Bool acceptable = EINA_FALSE;
7037
7038                   Elm_Atspi_Role role;
7039                   eo_do(smart_parent, role = elm_interface_atspi_accessible_role_get());
7040                   switch (role)
7041                     {
7042                      case ELM_ATSPI_ROLE_FILLER: /* ex: View of colorselector item is layout */
7043                      case ELM_ATSPI_ROLE_ICON:
7044                      case ELM_ATSPI_ROLE_IMAGE:
7045                      case ELM_ATSPI_ROLE_REDUNDANT_OBJECT:
7046                      case ELM_ATSPI_ROLE_WINDOW:
7047                        DBG("Go for parent: %s (%p)\n", evas_object_type_get(smart_parent), smart_parent);
7048                        break;
7049
7050                      case ELM_ATSPI_ROLE_LIST:
7051                        return _item_at_point_get(smart_parent, x, y);
7052                        break;
7053
7054                      default:
7055                        acceptable = EINA_TRUE;
7056                        break;
7057                     }
7058
7059                     if (acceptable) return smart_parent;
7060                }
7061
7062              smart_parent = _parent_get(smart_parent);
7063           }
7064      }
7065    return _accessible_at_point_top_down_get(obj, _pd, screen_coords, x, y);
7066 }
7067 //
7068
7069 //TIZEN_ONLY(20150709) add relations atpi
7070 EOLIAN static Eina_Bool
7071 _elm_widget_elm_interface_atspi_accessible_relationship_append(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
7072 {
7073    return elm_atspi_relation_set_relation_append(&sd->atspi_custom_relations, type, relation_obj);
7074 }
7075
7076 EOLIAN static void
7077 _elm_widget_elm_interface_atspi_accessible_relationship_remove(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
7078 {
7079    elm_atspi_relation_set_relation_remove(&sd->atspi_custom_relations, type, relation_obj);
7080 }
7081
7082 EOLIAN static Eina_Bool
7083 _elm_widget_item_elm_interface_atspi_accessible_relationship_append(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
7084 {
7085    return elm_atspi_relation_set_relation_append(&sd->atspi_custom_relations, type, relation_obj);
7086 }
7087
7088 EOLIAN static void
7089 _elm_widget_item_elm_interface_atspi_accessible_relationship_remove(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd, Elm_Atspi_Relation_Type type, const Eo *relation_obj)
7090 {
7091    elm_atspi_relation_set_relation_remove(&sd->atspi_custom_relations, type, relation_obj);
7092 }
7093 //
7094
7095 //TIZEN_ONLY(20150731) : add i18n support for name and description
7096 EOLIAN static void
7097 _elm_widget_elm_interface_atspi_accessible_translation_domain_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, const char *domain)
7098 {
7099    eina_stringshare_replace(&_pd->atspi_translation_domain, domain);
7100 }
7101
7102 EOLIAN static const char*
7103 _elm_widget_elm_interface_atspi_accessible_translation_domain_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd)
7104 {
7105    return _pd->atspi_translation_domain;
7106 }
7107
7108 EOLIAN static void
7109 _elm_widget_item_elm_interface_atspi_accessible_translation_domain_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd, const char *domain)
7110 {
7111    eina_stringshare_replace(&_pd->atspi_translation_domain, domain);
7112 }
7113
7114 EOLIAN static const char*
7115 _elm_widget_item_elm_interface_atspi_accessible_translation_domain_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd)
7116 {
7117    return _pd->atspi_translation_domain;
7118 }
7119
7120 //TIZEN_ONLY(20160726): add API elm_atspi_accessible_can_highlight_set/get
7121 static Eina_Bool
7122 _children_highlight_check(Eo *obj)
7123 {
7124    Eina_List *children, *l;
7125    Eo *child;
7126
7127    if (_elm_object_accessibility_currently_highlighted_get() == (void *)obj)
7128      {
7129         eo_do(obj, elm_interface_atspi_component_highlight_clear());
7130         return EINA_TRUE;
7131      }
7132
7133    eo_do(obj, children = elm_interface_atspi_accessible_children_get());
7134    EINA_LIST_FOREACH(children, l, child)
7135      {
7136         if (_children_highlight_check(child)) return EINA_TRUE;
7137      }
7138
7139    return EINA_FALSE;
7140 }
7141
7142 EOLIAN static void
7143 _elm_widget_elm_interface_atspi_accessible_can_highlight_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd, Eina_Bool can_highlight)
7144 {
7145    if (!can_highlight) _children_highlight_check(obj);
7146    _pd->can_highlight = !!can_highlight;
7147 }
7148
7149 EOLIAN static Eina_Bool
7150 _elm_widget_elm_interface_atspi_accessible_can_highlight_get(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
7151 {
7152    return _elm_widget_highlightable(obj);
7153 }
7154
7155 EOLIAN static void
7156 _elm_widget_item_elm_interface_atspi_accessible_can_highlight_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd, Eina_Bool can_highlight)
7157 {
7158    if (!can_highlight) _children_highlight_check(obj);
7159    _pd->can_highlight = !!can_highlight;
7160 }
7161
7162 EOLIAN static Eina_Bool
7163 _elm_widget_item_elm_interface_atspi_accessible_can_highlight_get(Eo *obj, Elm_Widget_Item_Data *_pd EINA_UNUSED)
7164 {
7165    return _elm_widget_item_highlightable(obj);
7166 }
7167 //
7168
7169 //TIZEN_ONLY(20160622): Override Paragraph Direction APIs
7170 static void
7171 _elm_widget_evas_object_paragraph_direction_set_internal(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Evas_BiDi_Direction dir)
7172 {
7173    Evas_Object *child;
7174    Eina_List *l;
7175
7176    if (sd->on_destroy) return;
7177
7178    EINA_LIST_FOREACH(sd->subobjs, l, child)
7179      {
7180         if (_elm_widget_is(child))
7181           {
7182              Elm_Widget_Smart_Data *sdc = eo_data_scope_get(child, MY_CLASS);
7183
7184              if (sdc->inherit_paragraph_direction &&
7185                  (sdc->paragraph_direction != dir))
7186                {
7187                   sdc->paragraph_direction = dir;
7188                   _elm_widget_evas_object_paragraph_direction_set_internal(child, sdc, dir);
7189                   eo_do_super(child, MY_CLASS, evas_obj_paragraph_direction_set(dir));
7190                }
7191           }
7192
7193         /* FIXME: There is no way to handle non-widget child object.
7194          * If a non-widget child object has smart parent, it will get the direction
7195          * from the smart parent. */
7196      }
7197 }
7198
7199 EOLIAN static void
7200 _elm_widget_evas_object_paragraph_direction_set(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_BiDi_Direction dir)
7201 {
7202    if ((!(sd->inherit_paragraph_direction) && (sd->paragraph_direction == dir)) ||
7203        (sd->inherit_paragraph_direction && (dir == EVAS_BIDI_DIRECTION_INHERIT)))
7204      return;
7205
7206    if (dir == EVAS_BIDI_DIRECTION_INHERIT)
7207      {
7208         sd->inherit_paragraph_direction = EINA_TRUE;
7209         Evas_BiDi_Direction parent_dir = EVAS_BIDI_DIRECTION_NEUTRAL;
7210
7211         if (sd->parent_obj)
7212           parent_dir = evas_object_paragraph_direction_get(sd->parent_obj);
7213
7214         if (parent_dir != sd->paragraph_direction)
7215           {
7216              sd->paragraph_direction = parent_dir;
7217              _elm_widget_evas_object_paragraph_direction_set_internal(obj, sd, parent_dir);
7218           }
7219      }
7220    else
7221      {
7222         sd->inherit_paragraph_direction = EINA_FALSE;
7223         sd->paragraph_direction = dir;
7224         _elm_widget_evas_object_paragraph_direction_set_internal(obj, sd, dir);
7225      }
7226
7227    eo_do_super(obj, MY_CLASS, evas_obj_paragraph_direction_set(dir));
7228 }
7229 //
7230
7231
7232 //TIZEN_ONLY(20161013): clean up elm color class feature
7233 void
7234 _edje_color_class_free(void *data)
7235 {
7236    Edje_Color_Class *cc = data;
7237
7238    if (cc->name) eina_stringshare_del(cc->name);
7239    free(cc);
7240 }
7241
7242 Eina_Stringshare *
7243 _elm_widget_edje_class_get(const Eo_Class *klass, const char *style, const char *part)
7244 {
7245    Eina_Strbuf *buf;
7246    Eina_Stringshare *str;
7247
7248    buf = eina_strbuf_new();
7249
7250    eina_strbuf_append(buf, strchr(eo_class_name_get(klass), '_') + 1);
7251    eina_strbuf_tolower(buf);
7252
7253    if (style)
7254      {
7255         eina_strbuf_append_printf(buf, "/%s/%s", style, part);
7256      }
7257    else
7258      {
7259         eina_strbuf_append_printf(buf, "/%s", part);
7260      }
7261
7262    str = eina_stringshare_add(eina_strbuf_string_get(buf));
7263
7264    eina_strbuf_free(buf);
7265    return str;
7266 }
7267
7268 /* TIZEN_ONLY(20161025): Apply color_class parent-child relationship */
7269 Eina_Bool
7270 _elm_widget_color_class_set_internal(Evas_Object *obj, Evas_Object *edje, const char *color_class,
7271                                      int r, int g, int b, int a,
7272                                      int r2, int g2, int b2, int a2,
7273                                      int r3, int g3, int b3, int a3)
7274 {
7275    Eina_Bool int_ret = EINA_TRUE;
7276    Eina_Stringshare *buf;
7277    int temp_color[3][4] = { { r,  g,  b,  a },
7278                             { r2, g2, b2, a2 },
7279                             { r3, g3, b3, a3 } };
7280
7281    if (!color_class) return EINA_FALSE;
7282
7283    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);
7284
7285 #define TEMP_COLOR(x, y) \
7286    ((temp_color[x][y] == -1) ? &temp_color[x][y] : NULL)
7287
7288    edje_object_color_class_get(edje, buf,
7289                                TEMP_COLOR(0, 0), TEMP_COLOR(0, 1), TEMP_COLOR(0, 2), TEMP_COLOR(0, 3),
7290                                TEMP_COLOR(1, 0), TEMP_COLOR(1, 1), TEMP_COLOR(1, 2), TEMP_COLOR(1, 3),
7291                                TEMP_COLOR(2, 0), TEMP_COLOR(2, 1), TEMP_COLOR(2, 2), TEMP_COLOR(2, 3));
7292
7293 #undef TEMP_COLOR
7294
7295 #define TEMP_COLOR(x, y) \
7296    ((temp_color[x][y] == -1) ? 0 : temp_color[x][y])
7297
7298    int_ret &= edje_object_color_class_set(edje, buf,
7299                                           TEMP_COLOR(0, 0), TEMP_COLOR(0, 1), TEMP_COLOR(0, 2), TEMP_COLOR(0, 3),
7300                                           TEMP_COLOR(1, 0), TEMP_COLOR(1, 1), TEMP_COLOR(1, 2), TEMP_COLOR(1, 3),
7301                                           TEMP_COLOR(2, 0), TEMP_COLOR(2, 1), TEMP_COLOR(2, 2), TEMP_COLOR(2, 3));
7302
7303 #undef TEMP_COLOR
7304
7305    eina_stringshare_del(buf);
7306
7307    return int_ret;
7308 }
7309
7310 Eina_Bool
7311 _elm_widget_color_class_get_internal(Evas_Object *obj, Evas_Object *edje, const char *color_class,
7312                                      int *r, int *g, int *b, int *a,
7313                                      int *r2, int *g2, int *b2, int *a2,
7314                                      int *r3, int *g3, int *b3, int *a3)
7315 {
7316    Eina_Bool int_ret = EINA_TRUE;
7317    Eina_Stringshare *buf;
7318
7319    if (!color_class) return EINA_FALSE;
7320
7321    buf = _elm_widget_edje_class_get(eo_class_get(obj), elm_widget_style_get(obj), color_class);
7322
7323    int_ret &= edje_object_color_class_get(edje, buf,
7324                                           r,  g,  b,  a,
7325                                           r2, g2, b2, a2,
7326                                           r3, g3, b3, a3);
7327
7328    eina_stringshare_del(buf);
7329
7330    return int_ret;
7331 }
7332 /* END */
7333
7334 EOLIAN Eina_Bool
7335 _elm_widget_class_color_set(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int r, int g, int b, int a)
7336 {
7337    Evas_Object *edje;
7338    Eina_Bool int_ret = EINA_TRUE;
7339
7340    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7341
7342    edje = elm_layout_edje_get(obj);
7343    int_ret &= _elm_widget_color_class_set_internal(obj, edje, color_class,
7344                                                    r, g, b, a,
7345                                                    -1, -1, -1, -1,
7346                                                    -1, -1, -1, -1);
7347
7348    return int_ret;
7349 }
7350
7351 EOLIAN Eina_Bool
7352 _elm_widget_class_color_get(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int *r, int *g, int *b, int *a)
7353 {
7354    Evas_Object *edje;
7355    Eina_Bool int_ret = EINA_TRUE;
7356
7357    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7358
7359    edje = elm_layout_edje_get(obj);
7360    int_ret &= _elm_widget_color_class_get_internal(obj, edje, color_class,
7361                                                    r, g, b, a,
7362                                                    NULL, NULL, NULL, NULL,
7363                                                    NULL, NULL, NULL, NULL);
7364
7365    return int_ret;
7366 }
7367
7368 EOLIAN Eina_Bool
7369 _elm_widget_class_color2_set(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int r, int g, int b, int a)
7370 {
7371    Evas_Object *edje;
7372    Eina_Bool int_ret = EINA_TRUE;
7373
7374    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7375
7376    edje = elm_layout_edje_get(obj);
7377    int_ret &= _elm_widget_color_class_set_internal(obj, edje, color_class,
7378                                                    -1, -1, -1, -1,
7379                                                    r, g, b, a,
7380                                                    -1, -1, -1, -1);
7381
7382    return int_ret;
7383 }
7384
7385 EOLIAN Eina_Bool
7386 _elm_widget_class_color2_get(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int *r, int *g, int *b, int *a)
7387 {
7388    Evas_Object *edje;
7389    Eina_Bool int_ret = EINA_TRUE;
7390
7391    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7392
7393    edje = elm_layout_edje_get(obj);
7394    int_ret &= _elm_widget_color_class_get_internal(obj, edje, color_class,
7395                                                    NULL, NULL, NULL, NULL,
7396                                                    r, g, b, a,
7397                                                    NULL, NULL, NULL, NULL);
7398
7399    return int_ret;
7400 }
7401
7402 EOLIAN Eina_Bool
7403 _elm_widget_class_color3_set(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int r, int g, int b, int a)
7404 {
7405    Evas_Object *edje;
7406    Eina_Bool int_ret = EINA_TRUE;
7407
7408    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7409
7410    edje = elm_layout_edje_get(obj);
7411    int_ret &= _elm_widget_color_class_set_internal(obj, edje, color_class,
7412                                                    -1, -1, -1, -1,
7413                                                    -1, -1, -1, -1,
7414                                                    r, g, b, a);
7415
7416    return int_ret;
7417 }
7418
7419 EOLIAN Eina_Bool
7420 _elm_widget_class_color3_get(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, const char *color_class, int *r, int *g, int *b, int *a)
7421 {
7422    Evas_Object *edje;
7423    Eina_Bool int_ret = EINA_TRUE;
7424
7425    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return EINA_FALSE;
7426
7427    edje = elm_layout_edje_get(obj);
7428    int_ret &= _elm_widget_color_class_get_internal(obj, edje, color_class,
7429                                                    NULL, NULL, NULL, NULL,
7430                                                    NULL, NULL, NULL, NULL,
7431                                                    r, g, b, a);
7432
7433    return int_ret;
7434 }
7435
7436 EOLIAN void
7437 _elm_widget_class_color_del(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *color_class)
7438 {
7439    Eina_Stringshare *buf;
7440
7441    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return;
7442
7443    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);
7444    edje_object_color_class_del(sd->resize_obj, buf);
7445    eina_stringshare_del(buf);
7446 }
7447
7448 EOLIAN void
7449 _elm_widget_class_color_clear(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
7450 {
7451    if (!eo_isa(obj, ELM_LAYOUT_CLASS)) return;
7452    edje_object_color_class_clear(sd->resize_obj);
7453 }
7454
7455 #define ELM_COLOR_CLASS_UPDATE(obj, hash, cond)                                  \
7456    Evas_Object *edje = NULL;                                                     \
7457    Eina_Iterator *itr;                                                           \
7458    Edje_Color_Class *cc;                                                         \
7459    Eina_Bool int_ret = EINA_TRUE;                                                \
7460    if (cond) return EINA_FALSE;                                                  \
7461    if (eo_isa(obj, ELM_LAYOUT_CLASS))                                            \
7462      edje =  elm_layout_edje_get(obj);                                           \
7463    else if (eo_isa(obj, EDJE_OBJECT_CLASS))                                      \
7464      edje = obj;                                                                 \
7465    if (!edje) return EINA_FALSE;                                                 \
7466    itr = eina_hash_iterator_data_new(hash);                                      \
7467    EINA_ITERATOR_FOREACH(itr, cc)                                                \
7468      {                                                                           \
7469         int_ret &= edje_object_color_class_set(edje, cc->name,                   \
7470                                                cc->r, cc->g, cc->b, cc->a,       \
7471                                                cc->r2, cc->g2, cc->b2, cc->a2,   \
7472                                                cc->r3, cc->g3, cc->b3, cc->a3);  \
7473      }                                                                           \
7474    eina_iterator_free(itr);                                                      \
7475    return int_ret
7476
7477
7478 #define CHECK_BOUND(x)                                                           \
7479    if (x > 0xff) x = 0xff;                                                       \
7480    else if (x < 0) x = 0
7481
7482 #define ELM_COLOR_CLASS_SET_START(obj, cr, cg, cb, ca)                           \
7483    Eina_Bool int_ret = EINA_FALSE;                                               \
7484    Edje_Color_Class *cc = NULL;                                                  \
7485    Eina_Stringshare *buf;                                                        \
7486    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);       \
7487    CHECK_BOUND(r);                                                               \
7488    CHECK_BOUND(g);                                                               \
7489    CHECK_BOUND(b);                                                               \
7490    CHECK_BOUND(a);                                                               \
7491    _elm_color_unpremul(a, &r, &g, &b);                                           \
7492    if (!sd->color_classes)                                                       \
7493      sd->color_classes = eina_hash_string_small_new(_edje_color_class_free);     \
7494    else                                                                          \
7495      cc = eina_hash_find(sd->color_classes, buf);                                \
7496    if (!cc)                                                                      \
7497      {                                                                           \
7498         cc = calloc(1, sizeof(Edje_Color_Class));                                \
7499         cc->name = eina_stringshare_add(buf);                                    \
7500         if (!cc->name)                                                           \
7501           {                                                                      \
7502              free(cc);                                                           \
7503              eina_stringshare_del(buf);                                          \
7504              return EINA_FALSE;                                                  \
7505           }                                                                      \
7506         eina_hash_direct_add(sd->color_classes, cc->name, cc);                   \
7507      }                                                                           \
7508    else if ((cc->cr == r) && (cc->cg == g) &&                                    \
7509             (cc->cb == b) && (cc->ca == a))                                      \
7510      {                                                                           \
7511         eina_stringshare_del(buf);                                               \
7512         return EINA_TRUE;                                                        \
7513      }                                                                           \
7514    cc->cr = r;                                                                   \
7515    cc->cg = g;                                                                   \
7516    cc->cb = b;                                                                   \
7517    cc->ca = a;                                                                   \
7518    int_ret = EINA_TRUE
7519
7520 #define ELM_COLOR_CLASS_SET_END()                                                \
7521    eina_stringshare_del(buf);                                                    \
7522    return int_ret
7523
7524 #define ELM_COLOR_CLASS_GET(obj, cr, cg, cb, ca)                                 \
7525    Eina_Bool int_ret = EINA_FALSE;                                               \
7526    Edje_Color_Class *cc;                                                         \
7527    Eina_Stringshare *buf;                                                        \
7528    int alpha = 0;                                                                \
7529    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);       \
7530    if ((!sd->color_classes) || !(cc = eina_hash_find(sd->color_classes, buf)))   \
7531      {                                                                           \
7532         if (r) *r = 0;                                                           \
7533         if (g) *g = 0;                                                           \
7534         if (b) *b = 0;                                                           \
7535         if (a) *a = 0;                                                           \
7536         int_ret = EINA_FALSE;                                                    \
7537      }                                                                           \
7538    else                                                                          \
7539      {                                                                           \
7540         if (r) *r = cc->cr;                                                      \
7541         if (g) *g = cc->cg;                                                      \
7542         if (b) *b = cc->cb;                                                      \
7543         if (a) *a = cc->ca;                                                      \
7544         alpha = cc->ca;                                                          \
7545         int_ret = EINA_TRUE;                                                     \
7546      }                                                                           \
7547    _elm_color_premul(alpha, r, g, b);                                            \
7548    eina_stringshare_del(buf);                                                    \
7549    return int_ret
7550
7551 Eina_Bool
7552 _elm_widget_item_color_class_update(Elm_Widget_Item_Data *sd)
7553 {
7554    ELM_COLOR_CLASS_UPDATE(sd->view, sd->color_classes, (!sd) || (!sd->color_classes) || (!sd->view));
7555 }
7556
7557 EOLIAN Eina_Bool
7558 _elm_widget_item_class_color_set(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int r, int g, int b, int a)
7559 {
7560    ELM_COLOR_CLASS_SET_START(obj, r, g, b, a);
7561
7562    int_ret &= _elm_widget_item_color_class_update(sd);
7563
7564    ELM_COLOR_CLASS_SET_END();
7565 }
7566
7567 EOLIAN Eina_Bool
7568 _elm_widget_item_class_color_get(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int *r, int *g, int *b, int *a)
7569 {
7570    ELM_COLOR_CLASS_GET(obj, r, g, b, a);
7571 }
7572
7573 EOLIAN Eina_Bool
7574 _elm_widget_item_class_color2_set(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int r, int g, int b, int a)
7575 {
7576    ELM_COLOR_CLASS_SET_START(obj, r2, g2, b2, a2);
7577
7578    int_ret &= _elm_widget_item_color_class_update(sd);
7579
7580    ELM_COLOR_CLASS_SET_END();
7581 }
7582
7583 EOLIAN Eina_Bool
7584 _elm_widget_item_class_color2_get(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int *r, int *g, int *b, int *a)
7585 {
7586    ELM_COLOR_CLASS_GET(obj, r2, g2, b2, a2);
7587 }
7588
7589 EOLIAN Eina_Bool
7590 _elm_widget_item_class_color3_set(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int r, int g, int b, int a)
7591 {
7592    ELM_COLOR_CLASS_SET_START(obj, r3, g3, b3, a3);
7593
7594    int_ret &= _elm_widget_item_color_class_update(sd);
7595
7596    ELM_COLOR_CLASS_SET_END();
7597 }
7598
7599 EOLIAN Eina_Bool
7600 _elm_widget_item_class_color3_get(Eo *obj, Elm_Widget_Item_Data *sd, const char *color_class, int *r, int *g, int *b, int *a)
7601 {
7602    ELM_COLOR_CLASS_GET(obj, r3, g3, b3, a3);
7603 }
7604
7605 static Evas_Object *
7606 _elm_widget_item_edje_get(Eo *obj, Elm_Widget_Item_Data *sd)
7607 {
7608    if (!sd)
7609      sd = eo_data_scope_get(obj, ELM_WIDGET_ITEM_CLASS);
7610
7611    if (eo_isa(sd->view, ELM_LAYOUT_CLASS))
7612      return elm_layout_edje_get(sd->view);
7613    else if (eo_isa(sd->view, EDJE_OBJECT_CLASS))
7614      return sd->view;
7615
7616    return NULL;
7617 }
7618
7619 EOLIAN void
7620 _elm_widget_item_class_color_del(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd, const char *color_class)
7621 {
7622    Eina_Stringshare *buf;
7623    Evas_Object *edje;
7624    Edje_Color_Class *cc = NULL;
7625
7626    if (!color_class) return;
7627
7628    buf = _elm_widget_edje_class_get(eo_class_get(obj), NULL, color_class);
7629    eina_hash_del(sd->color_classes, buf, cc);
7630
7631    edje = _elm_widget_item_edje_get(obj, sd);
7632    if (edje)
7633      edje_object_color_class_del(edje, color_class);
7634
7635    eina_stringshare_del(buf);
7636 }
7637
7638 EOLIAN void
7639 _elm_widget_item_class_color_clear(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd)
7640 {
7641    Evas_Object *edje;
7642    ELM_SAFE_FREE(sd->color_classes, eina_hash_free);
7643
7644    edje = _elm_widget_item_edje_get(obj, sd);
7645    if (!edje) return;
7646
7647    edje_object_color_class_clear(edje);
7648 }
7649 //
7650
7651 /* TIZEN_ONLY(20161025): Apply color_class parent-child relationship */
7652 void
7653 _elm_widget_color_class_parent_set(Evas_Object *obj, Evas_Object *parent)
7654 {
7655    Evas_Object *edje = NULL, *parent_edje = NULL;
7656
7657    if (!obj || !parent) return;
7658
7659    if (eo_isa(obj, ELM_LAYOUT_CLASS))
7660      edje =  elm_layout_edje_get(obj);
7661    else if (eo_isa(obj, EDJE_OBJECT_CLASS))
7662      edje = obj;
7663
7664    if (eo_isa(parent, ELM_LAYOUT_CLASS))
7665      parent_edje =  elm_layout_edje_get(parent);
7666    else if (eo_isa(parent, EDJE_OBJECT_CLASS))
7667      parent_edje = parent;
7668
7669    if (!edje || !parent_edje) return;
7670
7671    edje_object_color_class_parent_set(edje, parent_edje);
7672 }
7673
7674 void
7675 _elm_widget_color_class_parent_unset(Evas_Object *obj)
7676 {
7677    Evas_Object *edje = NULL;
7678
7679    if (!obj) return;
7680
7681    if (eo_isa(obj, ELM_LAYOUT_CLASS))
7682      edje =  elm_layout_edje_get(obj);
7683    else if (eo_isa(obj, EDJE_OBJECT_CLASS))
7684      edje = obj;
7685
7686    if (!edje) return;
7687
7688    edje_object_color_class_parent_unset(edje);
7689 }
7690 /* END */
7691
7692 //TIZEN_ONLY(20160527): widget: add AtspiAction interface to all widgets and widget_items, add handlers for reading stopped/cancelled
7693 EOLIAN const Elm_Atspi_Action *
7694 _elm_widget_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED)
7695 {
7696    return NULL;
7697 }
7698
7699 EOLIAN const Elm_Atspi_Action *
7700 _elm_widget_item_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *pd EINA_UNUSED)
7701 {
7702    return NULL;
7703 }
7704 //
7705
7706 #include "elm_widget_item.eo.c"
7707 #include "elm_widget.eo.c"