1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_COMPONENT_PROTECTED
7 #define ELM_WIDGET_PROTECTED
8 #define ELM_WIDGET_ITEM_PROTECTED
9 #define EFL_INPUT_EVENT_PROTECTED
10 #define EFL_UI_L10N_PROTECTED
11 #define EFL_UI_FOCUS_OBJECT_PROTECTED
12 #define EFL_UI_WIDGET_PART_BG_PROTECTED
13 #define EFL_PART_PROTECTED
14 
15 #include <Elementary.h>
16 
17 #include "elm_priv.h"
18 #include "elm_widget_container.h"
19 #include "elm_interface_scrollable.h"
20 #include "elm_pan_eo.h"
21 #include "elm_part_helper.h"
22 #include "elm_widget_combobox.h"
23 
24 #define MY_CLASS EFL_UI_WIDGET_CLASS
25 
26 #define MY_CLASS_NAME "Efl_Ui_Widget"
27 #define MY_CLASS_NAME_LEGACY "elm_widget"
28 
29 #define API_ENTRY                                    \
30   Elm_Widget_Smart_Data *sd = NULL;                  \
31   if (!_elm_widget_is(obj) ||                        \
32       (!(sd = efl_data_scope_get(obj, MY_CLASS))))
33 
34 #define INTERNAL_ENTRY                               \
35   ELM_WIDGET_DATA_GET(obj, sd);                      \
36   if (!sd) return
37 
38 #define ELM_WIDGET_FOCUS_GET(obj)                                          \
39   (efl_isa(obj, EFL_UI_WIDGET_CLASS) &&                                    \
40    ((_elm_access_auto_highlight_get()) ? (elm_widget_highlight_get(obj)) : \
41                                          (efl_ui_focus_object_focus_get(obj))))
42 
43 const char SIG_WIDGET_FOCUSED[] = "focused";
44 const char SIG_WIDGET_UNFOCUSED[] = "unfocused";
45 const char SIG_WIDGET_LANG_CHANGED[] = "language,changed";
46 const char SIG_WIDGET_ACCESS_CHANGED[] = "access,changed";
47 
48 typedef struct _Elm_Event_Cb_Data         Elm_Event_Cb_Data;
49 typedef struct _Elm_Label_Data            Elm_Label_Data;
50 typedef struct _Elm_Translate_String_Data Elm_Translate_String_Data;
51 
52 static Eina_Error _efl_ui_property_bind(Eo *widget, Eo *target, Efl_Ui_Widget_Data *pd,
53                                         const char *part,
54                                         const char *key, const char *property);
55 
56 struct _Elm_Event_Cb_Data
57 {
58    Elm_Event_Cb func;
59    const void  *data;
60 };
61 
62 struct _Elm_Label_Data
63 {
64    const char *part;
65    const char *text;
66 };
67 
68 struct _Elm_Translate_String_Data
69 {
70    EINA_INLIST;
71    Eina_Stringshare *id;
72    Eina_Stringshare *domain;
73    Eina_Stringshare *string;
74    Eina_Bool   preset : 1;
75 };
76 
77 /* For keeping backward compatibility (EFL 1.18 or older versions).
78  * Since EFL 1.19 which starts to use eolian_gen2, it does not convert
79  * "." to "_" among the class name. */
80 static const char *legacy_type_table[][2] =
81 {
82      { "Efl.Ui.Bg_Legacy", "Elm_Bg" },
83      { "Efl.Ui.Button_Legacy", "Elm_Button" },
84      { "Efl.Ui.Check_Legacy", "Elm_Check" },
85      { "Efl.Ui.Clock_Legacy", "Elm_Datetime" },
86      { "Efl.Ui.Flip_Legacy", "Elm_Flip" },
87      { "Efl.Ui.Frame_Legacy", "Elm_Frame" },
88      { "Efl.Ui.Image_Legacy", "Elm_Image" },
89      { "Efl.Ui.Image_Zoomable_Legacy", "Elm_Photocam" },
90      { "Efl.Ui.Layout_Legacy", "Elm_Layout" },
91      { "Efl.Ui.Panes_Legacy", "Elm_Panes" },
92      { "Efl.Ui.Progressbar_Legacy", "Elm_Progressbar" },
93      { "Efl.Ui.Radio_Legacy", "Elm_Radio" },
94      { "Efl.Ui.Video_Legacy", "Elm_Video" },
95      { "Efl.Ui.Win_Legacy", "Elm_Win" },
96      { "Efl.Ui.Win_Socket_Legacy", "Elm_Win" },
97      { "Efl.Ui.Win_Inlined_Legacy", "Elm_Win" },
98      { "Elm.Code_Widget_Legacy", "Elm_Code_Widget" },
99      { "Elm.Ctxpopup", "Elm_Ctxpopup" },
100      { "Elm.Entry", "Elm_Entry" },
101      { "Elm.Colorselector", "Elm_Colorselector" },
102      { "Elm.List", "Elm_List" },
103      { "Elm.Photo", "Elm_Photo" },
104      { "Elm.Actionslider", "Elm_Actionslider" },
105      { "Elm.Box", "Elm_Box" },
106      { "Elm.Table", "Elm_Table" },
107      { "Elm.Thumb", "Elm_Thumb" },
108      { "Elm.Menu", "Elm_Menu" },
109      { "Elm.Icon", "Elm_Icon" },
110      { "Elm.Prefs", "Elm_Prefs" },
111      { "Elm.Map", "Elm_Map" },
112      { "Elm.Glview", "Elm_Glview" },
113      { "Elm.Web", "Elm_Web" },
114      { "Elm.Toolbar", "Elm_Toolbar" },
115      { "Elm.Grid", "Elm_Grid" },
116      { "Elm.Diskselector", "Elm_Diskselector" },
117      { "Elm.Notify", "Elm_Notify" },
118      { "Elm.Mapbuf", "Elm_Mapbuf" },
119      { "Elm.Separator", "Elm_Separator" },
120      { "Elm.Calendar", "Elm_Calendar" },
121      { "Elm.Inwin", "Elm_Inwin" },
122      { "Elm.Gengrid", "Elm_Gengrid" },
123      { "Elm.Scroller", "Elm_Scroller" },
124      { "Elm.Player", "Elm_Player" },
125      { "Elm.Segment_Control", "Elm_Segment_Control" },
126      { "Elm.Fileselector", "Elm_Fileselector" },
127      { "Elm.Fileselector_Button", "Elm_Fileselector_Button" },
128      { "Elm.Fileselector_Entry", "Elm_Fileselector_Entry" },
129      { "Elm.Flipselector", "Elm_Flipselector" },
130      { "Elm.Hoversel", "Elm_Hoversel" },
131      { "Elm.Naviframe", "Elm_Naviframe" },
132      { "Elm.Popup", "Elm_Popup" },
133      { "Elm.Bubble", "Elm_Bubble" },
134      { "Elm.Clock", "Elm_Clock" },
135      { "Elm.Conformant", "Elm_Conformant" },
136      { "Elm.Dayselector", "Elm_Dayselector" },
137      { "Elm.Genlist", "Elm_Genlist" },
138      { "Elm.Hover", "Elm_Hover" },
139      { "Elm.Index", "Elm_Index" },
140      { "Elm.Label", "Elm_Label" },
141      { "Elm.Panel", "Elm_Panel" },
142      { "Elm.Slider", "Elm_Slider" },
143      { "Elm.Slideshow", "Elm_Slideshow" },
144      { "Elm.Spinner", "Elm_Spinner" },
145      { "Elm.Plug", "Elm_Plug" },
146      { "Elm.Web.None", "Elm_Web" },
147      { "Elm.Multibuttonentry", "Elm_Multibuttonentry" },
148      { NULL, NULL }
149 };
150 
151 /* local subsystem globals */
152 static inline Eina_Bool
_elm_widget_is(const Evas_Object * obj)153 _elm_widget_is(const Evas_Object *obj)
154 {
155    return efl_isa(obj, MY_CLASS);
156 }
157 
158 static inline Eina_Bool
_is_focusable(Evas_Object * obj)159 _is_focusable(Evas_Object *obj)
160 {
161    API_ENTRY return EINA_FALSE;
162    return sd->can_focus || (sd->logical.child_count > 0);
163 }
164 
165 static inline Eina_Bool
_is_focused(Evas_Object * obj)166 _is_focused(Evas_Object *obj)
167 {
168    API_ENTRY return EINA_FALSE;
169    return sd->focused;
170 }
171 
172 static inline Eina_Bool
_elm_scrollable_is(const Evas_Object * obj)173 _elm_scrollable_is(const Evas_Object *obj)
174 {
175    INTERNAL_ENTRY EINA_FALSE;
176    if (elm_widget_is_legacy(obj))
177      return
178         efl_isa(obj, ELM_INTERFACE_SCROLLABLE_MIXIN);
179    else
180      return
181         efl_isa(obj, EFL_UI_SCROLLABLE_INTERFACE);
182 }
183 
184 static void
185 _on_sub_obj_del(void *data, const Efl_Event *event);
186 static void _propagate_event(void *data, const Efl_Event *eo_event);
187 static void _elm_widget_shadow_update(Efl_Ui_Widget *obj);
188 
189 EFL_CALLBACKS_ARRAY_DEFINE(efl_subitems_callbacks,
190                           { EFL_EVENT_DEL, _on_sub_obj_del });
191 EFL_CALLBACKS_ARRAY_DEFINE(focus_callbacks,
192                           { EFL_EVENT_KEY_DOWN, _propagate_event },
193                           { EFL_EVENT_KEY_UP, _propagate_event },
194                           { EFL_EVENT_POINTER_WHEEL, _propagate_event });
195 
196 static inline void
_callbacks_add(Eo * widget,void * data)197 _callbacks_add(Eo *widget, void *data)
198 {
199     efl_event_callback_array_add(widget, efl_subitems_callbacks(), data);
200 }
201 
202 static inline void
_callbacks_del(Eo * widget,void * data)203 _callbacks_del(Eo *widget, void *data)
204 {
205     efl_event_callback_array_del(widget, efl_subitems_callbacks(), data);
206 }
207 
208 void
_elm_widget_item_highlight_in_theme(Evas_Object * obj,Elm_Object_Item * eo_it)209 _elm_widget_item_highlight_in_theme(Evas_Object *obj, Elm_Object_Item *eo_it)
210 {
211    const char *str;
212 
213    if (!eo_it) return;
214    if (efl_isa(eo_it, ELM_WIDGET_ITEM_CLASS))
215      {
216         Elm_Widget_Item_Data *it = efl_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS);
217 
218         if (efl_isa(it->view, EFL_UI_LAYOUT_BASE_CLASS))
219           str = edje_object_data_get(elm_layout_edje_get(it->view), "focus_highlight");
220         else
221           str = edje_object_data_get(it->view, "focus_highlight");
222      }
223    else
224       str = edje_object_data_get(((Elm_Widget_Item_Data *)eo_it)->view, "focus_highlight");
225    if ((str) && (!strcmp(str, "on")))
226      elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
227    else
228      elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
229 }
230 
231 void
_elm_widget_focus_highlight_start(const Evas_Object * obj)232 _elm_widget_focus_highlight_start(const Evas_Object *obj)
233 {
234    Evas_Object *top = efl_provider_find(obj, EFL_UI_WIN_CLASS);
235 
236    EINA_SAFETY_ON_FALSE_RETURN(efl_isa(top, EFL_UI_WIN_CLASS));
237 
238    _elm_win_focus_highlight_start(top);
239 }
240 
241 Evas_Object *
_efl_ui_widget_focus_highlight_object_get(const Evas_Object * obj)242 _efl_ui_widget_focus_highlight_object_get(const Evas_Object *obj)
243 {
244    Evas_Object *top = efl_provider_find(obj, EFL_UI_WIN_CLASS);
245 
246    EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(top, EFL_UI_WIN_CLASS), NULL);
247 
248    return _elm_win_focus_highlight_object_get(top);
249 }
250 
251 static Eina_Bool
_legacy_focus_eval(Eo * obj)252 _legacy_focus_eval(Eo *obj)
253 {
254    Eina_List *lst;
255    Efl_Ui_Widget *wid = obj, *top;
256    Elm_Widget_Smart_Data *wid_pd;
257 
258    wid_pd = efl_data_scope_get(wid, MY_CLASS);
259    do {
260 
261      top = wid;
262 
263      wid = elm_widget_parent_get(wid);
264      if (!wid) break;
265      wid_pd = efl_data_scope_get(wid, MY_CLASS);
266 
267      lst = wid_pd->legacy_focus.custom_chain;
268      if (lst)
269        {
270           if (!eina_list_data_find(lst, top))
271             {
272                WRN("Widget %p disabled due to custom chain of %p", top, wid);
273                return EINA_TRUE;
274             }
275        }
276 
277    } while (1);
278 
279    return !efl_isa(top, EFL_UI_WIN_CLASS);
280 }
281 
282 static void _full_eval(Eo *obj, Elm_Widget_Smart_Data *pd);
283 
284 static Efl_Ui_Focus_Object*
_focus_manager_eval(Eo * obj,Elm_Widget_Smart_Data * pd)285 _focus_manager_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
286 {
287    Evas_Object *provider = NULL;
288    Evas_Object *parent;
289    Efl_Ui_Focus_Manager *new = NULL, *old = NULL;
290 
291    parent = elm_widget_parent_get(obj);
292    if (efl_isa(parent, EFL_UI_FOCUS_MANAGER_INTERFACE))
293      {
294         new = parent;
295      }
296    else if (parent)
297      {
298         new = efl_ui_focus_object_focus_manager_get(parent);
299         provider = parent;
300      }
301 
302    if (new != pd->manager.manager)
303      {
304         old = pd->manager.manager;
305 
306         pd->manager.manager = new;
307         pd->manager.provider = provider;
308      }
309 
310    return old;
311 }
312 
313 EOLIAN static Eina_Bool
_efl_ui_widget_focus_state_apply(Eo * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED,Efl_Ui_Widget_Focus_State current_state,Efl_Ui_Widget_Focus_State * configured_state,Efl_Ui_Widget * redirect)314 _efl_ui_widget_focus_state_apply(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED, Efl_Ui_Widget_Focus_State current_state, Efl_Ui_Widget_Focus_State *configured_state, Efl_Ui_Widget *redirect)
315 {
316    Eina_Bool registered = EINA_TRUE;
317 
318    //shortcut for having the same configurations
319    if (current_state.manager == configured_state->manager && !current_state.manager)
320      return !!current_state.manager;
321 
322    if (configured_state->logical == current_state.logical &&
323        configured_state->manager == current_state.manager &&
324        configured_state->parent == current_state.parent)
325      return !!current_state.manager;
326 
327    //this thing doesnt want to be registered, but it is ...
328    if (!configured_state->manager && current_state.manager)
329      {
330         efl_ui_focus_manager_calc_unregister(current_state.manager, obj);
331         return EINA_FALSE;
332      }
333    //by that point we have always a configured manager
334 
335    if (!current_state.manager) registered = EINA_FALSE;
336 
337    if ((//check if we have changed the manager
338         (current_state.manager != configured_state->manager) ||
339         //check if we are already registered but in a different state
340         (current_state.logical != configured_state->logical))
341        && registered)
342      {
343         //we need to unregister here
344         efl_ui_focus_manager_calc_unregister(current_state.manager, obj);
345         registered = EINA_FALSE;
346      }
347 
348    //the parent may has changed
349    if (current_state.parent != configured_state->parent && registered)
350      {
351         return efl_ui_focus_manager_calc_update_parent(current_state.manager, obj, configured_state->parent);
352      }
353 
354    if (!registered)
355      {
356         if (configured_state->logical)
357           return efl_ui_focus_manager_calc_register_logical(configured_state->manager, obj, configured_state->parent, redirect);
358         else
359           return efl_ui_focus_manager_calc_register(configured_state->manager, obj, configured_state->parent, redirect);
360      }
361    ERR("Uncaught focus state consider this as unregistered (%d) \n (%p,%p,%d) \n (%p,%p,%d) ", registered,
362      configured_state->manager, configured_state->parent, configured_state->logical,
363      current_state.manager, current_state.parent, current_state.logical
364    );
365    return EINA_FALSE;
366 }
367 static void
_eval_registration_candidate(Eo * obj,Elm_Widget_Smart_Data * pd,Eina_Bool * should,Eina_Bool * want_full)368 _eval_registration_candidate(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool *should, Eina_Bool *want_full)
369 {
370    *should = *want_full = EINA_FALSE;
371 
372     //can focus can be overridden by the following properties
373     if ((!pd->parent_obj) ||
374         (!evas_object_visible_get(obj)) ||
375         pd->disabled > 0 ||
376         pd->tree_unfocusable > 0)
377       return;
378 
379     if (!pd->shared_win_data || ((Efl_Ui_Shared_Win_Data*)pd->shared_win_data)->legacy_focus_api_used)
380       {
381          if (_legacy_focus_eval(obj))
382            return;
383       }
384 
385     if (pd->can_focus)
386       {
387          *should = *want_full = EINA_TRUE;
388       }
389     else if (pd->logical.child_count > 0)
390       {
391          *should = EINA_TRUE;
392       }
393 }
394 
395 static void
_focus_state_eval(Eo * obj,Elm_Widget_Smart_Data * pd,Eina_Bool should,Eina_Bool want_full)396 _focus_state_eval(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool should, Eina_Bool want_full)
397 {
398    Efl_Ui_Widget_Focus_State configuration;
399 
400    //this would mean we are registering again the root, we dont want that
401    if (pd->manager.manager == obj) return;
402 
403    //there are two reasons to be registered, the child count is bigger than 0, or the widget is flagged to be able to handle focus
404    if (should)
405      {
406         configuration.parent = pd->logical.parent;
407         configuration.manager = pd->manager.manager;
408         configuration.logical = !want_full;
409      }
410    else
411      {
412         configuration.parent = NULL;
413         configuration.manager = NULL;
414         configuration.logical = EINA_FALSE;
415      }
416 
417    if (!efl_ui_widget_focus_state_apply(obj, pd->focus, &configuration, NULL))
418      {
419         //things went wrong or this thing is unregistered. Purge the current configuration.
420         pd->focus.manager = NULL;
421         pd->focus.parent = NULL;
422         pd->focus.logical = EINA_FALSE;
423      }
424    else
425      {
426         pd->focus.parent = configuration.parent;
427         pd->focus.manager = configuration.manager;
428         pd->focus.logical = configuration.logical;
429      }
430 
431 }
432 
433 static Efl_Ui_Focus_Object*
_logical_parent_eval(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * pd,Eina_Bool should,Eina_Bool * state_change_to_parent)434 _logical_parent_eval(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd, Eina_Bool should, Eina_Bool *state_change_to_parent)
435 {
436    Efl_Ui_Widget *parent;
437    Efl_Ui_Focus_Parent_Provider *provider;
438 
439    if (!pd->shared_win_data || ((Efl_Ui_Shared_Win_Data*)pd->shared_win_data)->custom_parent_provider)
440      {
441         if (should)
442           {
443              provider = efl_provider_find(obj, EFL_UI_FOCUS_PARENT_PROVIDER_INTERFACE);
444              EINA_SAFETY_ON_NULL_RETURN_VAL(provider, NULL);
445              parent = efl_ui_focus_parent_provider_find_logical_parent(provider, obj);
446           }
447         else
448           parent = NULL;
449      }
450    else
451      {
452         parent = efl_ui_widget_parent_get(obj);
453      }
454 
455 
456    if (pd->logical.parent != parent)
457      {
458         Efl_Ui_Focus_Object *old = NULL;
459 
460         //update old logical parent;
461         if (pd->logical.parent)
462           {
463              if (efl_isa(pd->logical.parent, EFL_UI_WIDGET_CLASS))
464                {
465                   ELM_WIDGET_DATA_GET_OR_RETURN(pd->logical.parent, logical_wd, NULL);
466                   logical_wd->logical.child_count --;
467                   if (logical_wd->logical.child_count == 0)
468                     {
469                       *state_change_to_parent = EINA_TRUE;
470                     }
471                }
472              old = pd->logical.parent;
473              efl_weak_unref(&pd->logical.parent);
474              pd->logical.parent = NULL;
475           }
476         if (parent)
477           {
478              if (efl_isa(parent, EFL_UI_WIDGET_CLASS))
479                {
480                   ELM_WIDGET_DATA_GET_OR_RETURN(parent, parent_wd, NULL);
481                   parent_wd->logical.child_count ++;
482                   if (parent_wd->logical.child_count == 1)
483                     {
484                       *state_change_to_parent = EINA_TRUE;
485                     }
486                }
487              pd->logical.parent = parent;
488              efl_weak_ref(&pd->logical.parent);
489           }
490         return old;
491      }
492    return NULL;
493 }
494 
495 static void
_full_eval(Eo * obj,Elm_Widget_Smart_Data * pd)496 _full_eval(Eo *obj, Elm_Widget_Smart_Data *pd)
497 {
498    Efl_Ui_Focus_Object *old_parent;
499    Efl_Ui_Focus_Object *old_registered_parent, *old_registered_manager;
500    Eina_Bool should, want_full, state_change_to_parent = EINA_FALSE;
501 
502    _eval_registration_candidate(obj, pd, &should, &want_full);
503 
504    old_parent = _logical_parent_eval(obj, pd, should, &state_change_to_parent);
505 
506    if (state_change_to_parent)
507      {
508         if (efl_isa(old_parent, EFL_UI_WIDGET_CLASS))
509           {
510              //emit signal and focus eval old and new
511              ELM_WIDGET_DATA_GET(old_parent, old_pd);
512              if (old_pd) _full_eval(old_parent, old_pd);
513           }
514 
515         if (efl_isa(pd->logical.parent, EFL_UI_WIDGET_CLASS))
516           {
517              ELM_WIDGET_DATA_GET(pd->logical.parent, new_pd);
518              if (new_pd) _full_eval(pd->logical.parent, new_pd);
519           }
520      }
521 
522 
523    _focus_manager_eval(obj, pd);
524 
525    old_registered_parent = pd->focus.parent;
526    old_registered_manager = pd->focus.manager;
527 
528    _focus_state_eval(obj, pd, should, want_full);
529 
530    if (old_registered_parent != pd->focus.parent)
531      {
532         efl_event_callback_call(obj,
533              EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_PARENT_CHANGED, old_registered_parent);
534      }
535 
536    if (old_registered_manager != pd->focus.manager)
537      {
538         _elm_widget_full_eval_children(obj, pd);
539         efl_event_callback_call(obj,
540              EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_MANAGER_CHANGED, old_registered_manager);
541      }
542 
543 }
544 
545 void
_elm_widget_full_eval(Eo * obj)546 _elm_widget_full_eval(Eo *obj)
547 {
548    ELM_WIDGET_DATA_GET(obj, pd);
549    if (pd) _full_eval(obj, pd);
550 }
551 
552 /**
553  * @internal
554  *
555  * Resets the mirrored mode from the system mirror mode for widgets that are in
556  * automatic mirroring mode. This function does not call elm_widget_theme.
557  *
558  * @param obj The widget.
559  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
560  */
561 static void
_elm_widget_mirrored_reload(Evas_Object * obj)562 _elm_widget_mirrored_reload(Evas_Object *obj)
563 {
564    API_ENTRY return;
565    Eina_Bool mirrored = elm_config_mirrored_get();
566 
567    if (efl_ui_mirrored_automatic_get(obj) && (sd->is_mirrored != mirrored))
568      {
569         sd->is_mirrored = mirrored;
570      }
571 }
572 
573 static void
_parents_focus(Evas_Object * obj)574 _parents_focus(Evas_Object *obj)
575 {
576    for (; obj; obj = elm_widget_parent_get(obj))
577      {
578         INTERNAL_ENTRY;
579         if (sd->focused) return;
580         sd->focused = 1;
581      }
582 }
583 
584 static void
_parents_unfocus(Evas_Object * obj)585 _parents_unfocus(Evas_Object *obj)
586 {
587    for (; obj; obj = elm_widget_parent_get(obj))
588      {
589         INTERNAL_ENTRY;
590         if (!sd->focused) return;
591         sd->focused = 0;
592      }
593 }
594 
595 static void
_on_sub_obj_del(void * data,const Efl_Event * event)596 _on_sub_obj_del(void *data, const Efl_Event *event)
597 {
598    ELM_WIDGET_DATA_GET_OR_RETURN(data, sd);
599 
600    if (_elm_widget_is(event->object))
601      {
602         if (_is_focused(event->object)) _parents_unfocus(data);
603      }
604    if (event->object == sd->resize_obj)
605      {
606         /* already dels sub object */
607         elm_widget_resize_object_set(data, NULL);
608      }
609    else if (event->object == sd->hover_obj)
610      {
611         sd->hover_obj = NULL;
612      }
613    else
614      {
615         if (!elm_widget_sub_object_del(data, event->object))
616           ERR("failed to remove sub object %p from %p\n", event->object, data);
617      }
618 }
619 
620 static const Evas_Smart_Cb_Description _smart_callbacks[] =
621 {
622    {SIG_WIDGET_FOCUSED, ""},
623    {SIG_WIDGET_UNFOCUSED, ""},
624    {SIG_WIDGET_LANG_CHANGED, ""},
625    {SIG_WIDGET_ACCESS_CHANGED, ""},
626    {NULL, NULL}
627 };
628 
629 static void
_obj_mouse_down(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)630 _obj_mouse_down(void *data,
631                 Evas *e EINA_UNUSED,
632                 Evas_Object *obj EINA_UNUSED,
633                 void *event_info)
634 {
635    Evas_Object *top;
636 
637    ELM_WIDGET_DATA_GET(data, sd);
638    if (!sd) return;
639    Evas_Event_Mouse_Down *ev = event_info;
640    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
641 
642    top = elm_widget_top_get(data);
643    if (top && efl_isa(top, EFL_UI_WIN_CLASS)) _elm_win_focus_auto_hide(top);
644    sd->still_in = EINA_TRUE;
645 }
646 
647 static void
_obj_mouse_move(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)648 _obj_mouse_move(void *data,
649                 Evas *e EINA_UNUSED,
650                 Evas_Object *obj,
651                 void *event_info)
652 {
653    ELM_WIDGET_DATA_GET(data, sd);
654    if (!sd) return;
655    Evas_Event_Mouse_Move *ev = event_info;
656    if (!sd->still_in) return;
657 
658    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
659      sd->still_in = EINA_FALSE;
660    else
661      {
662         Evas_Coord x, y, w, h;
663         evas_object_geometry_get(obj, &x, &y, &w, &h);
664         if (ELM_RECTS_POINT_OUT(x, y, w, h, ev->cur.canvas.x, ev->cur.canvas.y))
665           sd->still_in = EINA_FALSE;
666      }
667 }
668 
669 static void
_obj_mouse_up(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)670 _obj_mouse_up(void *data,
671               Evas *e EINA_UNUSED,
672               Evas_Object *obj,
673               void *event_info)
674 {
675    ELM_WIDGET_DATA_GET(data, sd);
676    if (!sd) return;
677    Evas_Event_Mouse_Up *ev = event_info;
678 
679    if (sd->still_in && (ev->flags == EVAS_BUTTON_NONE) &&
680        (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_CLICK) &&
681        !efl_invalidated_get(data))
682      elm_widget_focus_mouse_up_handle(evas_object_widget_parent_find(obj));
683 
684    sd->still_in = EINA_FALSE;
685 }
686 
687 static void
_obj_mouse_in(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)688 _obj_mouse_in(void *data,
689               Evas *e EINA_UNUSED,
690               Evas_Object *obj,
691               void *event_info EINA_UNUSED)
692 {
693    ELM_WIDGET_DATA_GET(data, sd);
694    if (!sd) return;
695    if (sd->focus_move_policy == ELM_FOCUS_MOVE_POLICY_IN &&
696        !efl_invalidated_get(data))
697      elm_widget_focus_mouse_up_handle(evas_object_widget_parent_find(obj));
698 }
699 
700 EOLIAN static void
_efl_ui_widget_efl_canvas_group_group_add(Eo * obj,Elm_Widget_Smart_Data * priv)701 _efl_ui_widget_efl_canvas_group_group_add(Eo *obj, Elm_Widget_Smart_Data *priv)
702 {
703    priv->mirrored_auto_mode = EINA_TRUE; /* will follow system locale
704                                           * settings */
705    priv->focus_move_policy_auto_mode = EINA_TRUE;
706    priv->focus_region_show_mode = ELM_FOCUS_REGION_SHOW_WIDGET;
707    elm_widget_can_focus_set(obj, EINA_TRUE);
708    priv->is_mirrored = elm_config_mirrored_get();
709    priv->focus_move_policy = _elm_config->focus_move_policy;
710 
711    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
712                                   _obj_mouse_down, obj);
713    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
714                                   _obj_mouse_move, obj);
715    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
716                                   _obj_mouse_up, obj);
717    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_IN,
718                                   _obj_mouse_in, obj);
719 }
720 
721 static Eina_Bool
_keep(void * data,void * gdata)722 _keep(void *data, void *gdata)
723 {
724    if (data == gdata)
725      return EINA_FALSE;
726    return EINA_TRUE;
727 }
728 
729 EOLIAN static void
_efl_ui_widget_efl_canvas_group_group_del(Eo * obj,Elm_Widget_Smart_Data * sd)730 _efl_ui_widget_efl_canvas_group_group_del(Eo *obj, Elm_Widget_Smart_Data *sd)
731 {
732    Evas_Object *sobj;
733    Elm_Translate_String_Data *ts;
734    Elm_Event_Cb_Data *ecb;
735 
736    if (sd->hover_obj)
737      {
738         /* detach it from us */
739         _callbacks_del(sd->hover_obj, obj);
740         sd->hover_obj = NULL;
741      }
742    while(eina_array_count(sd->children))
743      {
744         sobj = eina_array_data_get(sd->children, 0);
745 
746         if (!elm_widget_sub_object_del(obj, sobj))
747           {
748              ERR("failed to remove sub object %p from %p\n", sobj, obj);
749              eina_array_remove(sd->children, _keep, sobj);
750           }
751         // FIXME: is that a legacy or a new object ?
752         evas_object_del(sobj);
753         EINA_SAFETY_ON_TRUE_RETURN(eina_array_count(sd->children) && sobj == eina_array_data_get(sd->children, 0));
754      }
755    sd->tooltips = eina_list_free(sd->tooltips); /* should be empty anyway */
756    sd->cursors = eina_list_free(sd->cursors); /* should be empty anyway */
757    while (sd->translate_strings)
758      {
759         ts = EINA_INLIST_CONTAINER_GET(sd->translate_strings,
760                                        Elm_Translate_String_Data);
761         eina_stringshare_del(ts->id);
762         eina_stringshare_del(ts->domain);
763         eina_stringshare_del(ts->string);
764         sd->translate_strings = eina_inlist_remove(sd->translate_strings,
765                                                    sd->translate_strings);
766         free(ts);
767      }
768 
769    EINA_LIST_FREE(sd->event_cb, ecb)
770       free(ecb);
771 
772    eina_stringshare_del(sd->klass);
773    eina_stringshare_del(sd->group);
774    eina_stringshare_del(sd->style);
775    if (sd->theme) elm_theme_free(sd->theme);
776    eina_stringshare_del(sd->access_info);
777    eina_stringshare_del(sd->accessible_name);
778    evas_object_smart_data_set(obj, NULL);
779    efl_canvas_group_del(efl_super(obj, MY_CLASS));
780 }
781 
782 static void
_smart_reconfigure(Eo * obj,Elm_Widget_Smart_Data * sd)783 _smart_reconfigure(Eo *obj, Elm_Widget_Smart_Data *sd)
784 {
785    Eina_Rect geom = efl_gfx_entity_geometry_get(obj);
786 
787    if (sd->resize_obj)
788      {
789         efl_gfx_entity_geometry_set(sd->resize_obj, geom);
790      }
791    if (sd->hover_obj)
792      {
793         efl_gfx_entity_geometry_set(sd->hover_obj, geom);
794      }
795    if (sd->bg)
796      {
797         efl_gfx_entity_geometry_set(sd->bg, geom);
798      }
799    if (sd->has_shadow)
800      _elm_widget_shadow_update(obj);
801 }
802 
803 EOLIAN static void
_efl_ui_widget_efl_gfx_entity_position_set(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd,Eina_Position2D pos)804 _efl_ui_widget_efl_gfx_entity_position_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Position2D pos)
805 {
806    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
807      return;
808 
809    if (sd->resize_obj)
810      efl_gfx_entity_position_set(sd->resize_obj, pos);
811    if (sd->hover_obj)
812      efl_gfx_entity_position_set(sd->hover_obj, pos);
813    if (sd->bg)
814      efl_gfx_entity_position_set(sd->bg, pos);
815 
816    if (sd->has_shadow)
817      _elm_widget_shadow_update(obj);
818 
819    efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos);
820 }
821 
822 EOLIAN static void
_efl_ui_widget_efl_gfx_entity_size_set(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd,Eina_Size2D sz)823 _efl_ui_widget_efl_gfx_entity_size_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Eina_Size2D sz)
824 {
825    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
826      return;
827 
828    if (sd->resize_obj)
829      efl_gfx_entity_size_set(sd->resize_obj, sz);
830    if (sd->hover_obj)
831      efl_gfx_entity_size_set(sd->hover_obj, sz);
832    if (sd->bg)
833      efl_gfx_entity_size_set(sd->bg, sz);
834 
835    if (sd->has_shadow)
836      _elm_widget_shadow_update(obj);
837 
838    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz);
839 }
840 
841 void
_elm_widget_full_eval_children(Eo * obj,Elm_Widget_Smart_Data * sd)842 _elm_widget_full_eval_children(Eo *obj, Elm_Widget_Smart_Data *sd)
843 {
844    Eo *child;
845 
846    _full_eval(obj, sd);
847 
848    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
849      {
850         Elm_Widget_Smart_Data *sd_child;
851         child = eina_array_data_get(sd->children, i);
852 
853         if (!efl_isa(child, EFL_UI_WIDGET_CLASS)) continue;
854 
855         sd_child = efl_data_scope_get(child, EFL_UI_WIDGET_CLASS);
856         _elm_widget_full_eval_children(child, sd_child);
857      }
858 }
859 
860 EOLIAN static void
_efl_ui_widget_efl_gfx_entity_visible_set(Eo * obj,Elm_Widget_Smart_Data * pd,Eina_Bool vis)861 _efl_ui_widget_efl_gfx_entity_visible_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool vis)
862 {
863    Eina_Iterator *it;
864    Evas_Object *o;
865 
866    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
867      {
868         _elm_widget_full_eval_children(obj, pd);
869         return;
870      }
871 
872    efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), vis);
873 
874    _elm_widget_full_eval_children(obj, pd);
875 
876 
877    it = evas_object_smart_iterator_new(obj);
878    EINA_ITERATOR_FOREACH(it, o)
879      {
880        if (evas_object_data_get(o, "_elm_leaveme")) continue;
881        efl_gfx_entity_visible_set(o, vis);
882      }
883    eina_iterator_free(it);
884 
885    if (!_elm_config->atspi_mode || pd->on_destroy)
886      return;
887 
888    if (vis)
889      {
890         efl_access_added(obj);
891         if (_elm_widget_onscreen_is(obj))
892           efl_access_state_changed_signal_emit(obj, EFL_ACCESS_STATE_TYPE_SHOWING, EINA_TRUE);
893      }
894    else
895      {
896         efl_access_state_changed_signal_emit(obj, EFL_ACCESS_STATE_TYPE_SHOWING, EINA_FALSE);
897      }
898 }
899 
900 EOLIAN static void
_efl_ui_widget_efl_gfx_color_color_set(Eo * obj,Elm_Widget_Smart_Data * pd,int r,int g,int b,int a)901 _efl_ui_widget_efl_gfx_color_color_set(Eo *obj, Elm_Widget_Smart_Data *pd, int r, int g, int b, int a)
902 {
903    Eina_Iterator *it;
904    Evas_Object *o;
905 
906    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_COLOR_SET, 0, r, g, b, a))
907      return;
908 
909    efl_gfx_color_set(efl_super(obj, MY_CLASS), r, g, b, a);
910 
911    it = evas_object_smart_iterator_new(obj);
912    EINA_ITERATOR_FOREACH(it, o)
913      {
914        if (pd->bg == o) continue;
915        if (evas_object_data_get(o, "_elm_leaveme")) continue;
916        evas_object_color_set(o, r, g, b, a);
917      }
918    eina_iterator_free(it);
919 }
920 
921 EOLIAN static void
_efl_ui_widget_efl_canvas_object_no_render_set(Eo * obj,Elm_Widget_Smart_Data * _pd EINA_UNUSED,Eina_Bool hide)922 _efl_ui_widget_efl_canvas_object_no_render_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool hide)
923 {
924    Eina_Iterator *it;
925    Evas_Object *o;
926 
927    hide = !!hide;
928    if (efl_canvas_object_no_render_get(obj) == hide)
929      return;
930 
931    it = evas_object_smart_iterator_new(obj);
932    EINA_ITERATOR_FOREACH(it, o)
933      {
934        if (evas_object_data_get(o, "_elm_leaveme")) continue;
935        efl_canvas_object_no_render_set(o, hide);
936      }
937    eina_iterator_free(it);
938 
939    // bypass implementation in Efl.Canvas.Group
940    efl_canvas_object_no_render_set(efl_super(obj, EFL_CANVAS_GROUP_CLASS), hide);
941 }
942 
943 EOLIAN static void
_efl_ui_widget_efl_canvas_object_is_frame_object_set(Eo * obj,Elm_Widget_Smart_Data * pd,Eina_Bool frame)944 _efl_ui_widget_efl_canvas_object_is_frame_object_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool frame)
945 {
946    Evas_Object *o;
947 
948    frame = !!frame;
949    efl_canvas_object_is_frame_object_set(efl_super(obj, MY_CLASS), frame);
950    for (unsigned int i = 0; i < eina_array_count(pd->children); ++i)
951      {
952         o = eina_array_data_get(pd->children, i);
953 
954        if (evas_object_data_get(o, "_elm_leaveme")) continue;
955        efl_canvas_object_is_frame_object_set(o, frame);
956      }
957 }
958 
959 EOLIAN static void
_efl_ui_widget_efl_canvas_object_clipper_set(Eo * obj,Elm_Widget_Smart_Data * _pd EINA_UNUSED,Evas_Object * clip)960 _efl_ui_widget_efl_canvas_object_clipper_set(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *clip)
961 {
962    Eina_Iterator *it;
963    Evas_Object *o;
964 
965    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_CLIP_SET, 0, clip))
966      return;
967 
968    efl_canvas_object_clipper_set(efl_super(obj, MY_CLASS), clip);
969 
970    it = evas_object_smart_iterator_new(obj);
971    EINA_ITERATOR_FOREACH(it, o)
972      {
973        if (evas_object_data_get(o, "_elm_leaveme")) continue;
974        evas_object_clip_set(o, clip);
975      }
976    eina_iterator_free(it);
977 }
978 
979 EOLIAN static void
_efl_ui_widget_efl_canvas_group_group_calculate(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * _pd EINA_UNUSED)980 _efl_ui_widget_efl_canvas_group_group_calculate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
981 {
982    /* a NO-OP, on the base */
983    efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
984 }
985 
986 EOLIAN static void
_efl_ui_widget_efl_canvas_group_group_member_add(Eo * obj,Elm_Widget_Smart_Data * pd,Evas_Object * child)987 _efl_ui_widget_efl_canvas_group_group_member_add(Eo *obj, Elm_Widget_Smart_Data *pd, Evas_Object *child)
988 {
989    int r, g, b, a;
990    efl_canvas_group_member_add(efl_super(obj, MY_CLASS), child);
991 
992    if (evas_object_data_get(child, "_elm_leaveme")) return;
993 
994    if (pd->bg != child)
995      {
996         evas_object_color_get(obj, &r, &g, &b, &a);
997         evas_object_color_set(child, r, g, b, a);
998      }
999 
1000    efl_canvas_object_no_render_set(child, efl_canvas_object_no_render_get(obj));
1001    evas_object_clip_set(child, evas_object_clip_get(obj));
1002 
1003    if (evas_object_visible_get(obj))
1004      evas_object_show(child);
1005    else
1006      evas_object_hide(child);
1007 }
1008 
1009 EOLIAN static void
_efl_ui_widget_efl_canvas_group_group_member_remove(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * _pd EINA_UNUSED,Evas_Object * child)1010 _efl_ui_widget_efl_canvas_group_group_member_remove(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Evas_Object *child)
1011 {
1012    if (!evas_object_data_get(child, "_elm_leaveme"))
1013       evas_object_clip_unset(child);
1014    efl_canvas_group_member_remove(efl_super(obj, MY_CLASS), child);
1015 }
1016 
1017 // internal funcs
1018 static void
_propagate_x_drag_lock(Evas_Object * obj,int dir)1019 _propagate_x_drag_lock(Evas_Object *obj,
1020                        int dir)
1021 {
1022    INTERNAL_ENTRY;
1023    if (sd->parent_obj)
1024      {
1025         ELM_WIDGET_DATA_GET(sd->parent_obj, sd2);
1026         if (sd2)
1027           {
1028              sd2->child_drag_x_locked += dir;
1029              _propagate_x_drag_lock(sd->parent_obj, dir);
1030           }
1031      }
1032 }
1033 
1034 static void
_propagate_y_drag_lock(Evas_Object * obj,int dir)1035 _propagate_y_drag_lock(Evas_Object *obj,
1036                        int dir)
1037 {
1038    INTERNAL_ENTRY;
1039    if (sd->parent_obj)
1040      {
1041         ELM_WIDGET_DATA_GET(sd->parent_obj, sd2);
1042         if (sd2)
1043           {
1044              sd2->child_drag_y_locked += dir;
1045              _propagate_y_drag_lock(sd->parent_obj, dir);
1046           }
1047      }
1048 }
1049 
1050 static Eina_Bool
_propagate_event_legacy(Eo * parent,const Efl_Event * event,Eo * obj,Elm_Event_Cb_Data * ecd)1051 _propagate_event_legacy(Eo *parent, const Efl_Event *event, Eo *obj, Elm_Event_Cb_Data *ecd)
1052 {
1053    Evas_Callback_Type type;
1054    Evas_Event_Flags *event_flags, prev_flags;
1055    union {
1056       Evas_Event_Key_Down    *down;
1057       Evas_Event_Key_Up      *up;
1058       Evas_Event_Mouse_Wheel *wheel;
1059       void                   *any;
1060    } event_info;
1061 
1062    if (event->desc == EFL_EVENT_KEY_DOWN)
1063      {
1064         event_info.down = efl_input_legacy_info_get(event->info);
1065         EINA_SAFETY_ON_NULL_RETURN_VAL(event_info.down, EINA_FALSE);
1066         type = EVAS_CALLBACK_KEY_DOWN;
1067         event_flags = &event_info.down->event_flags;
1068      }
1069    else if (event->desc == EFL_EVENT_KEY_UP)
1070      {
1071         event_info.up = efl_input_legacy_info_get(event->info);
1072         EINA_SAFETY_ON_NULL_RETURN_VAL(event_info.up, EINA_FALSE);
1073         type = EVAS_CALLBACK_KEY_UP;
1074         event_flags = &event_info.up->event_flags;
1075      }
1076    else if (event->desc == EFL_EVENT_POINTER_WHEEL)
1077      {
1078         event_info.wheel = efl_input_legacy_info_get(event->info);
1079         EINA_SAFETY_ON_NULL_RETURN_VAL(event_info.wheel, EINA_FALSE);
1080         type = EVAS_CALLBACK_MOUSE_WHEEL;
1081         event_flags = &event_info.wheel->event_flags;
1082      }
1083    else
1084      return EINA_FALSE;
1085 
1086    prev_flags = *event_flags;
1087    if (ecd->func((void *)ecd->data, parent, obj, type, event_info.any) ||
1088        ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))
1089      {
1090         if (prev_flags != *event_flags)
1091           efl_input_event_flags_set(event->info, (Efl_Input_Flags)*event_flags);
1092         return EINA_TRUE;
1093      }
1094 
1095    return EINA_FALSE;
1096 }
1097 
1098 /**
1099  * @internal
1100  *
1101  * If elm_widget_focus_region_get() returns an empty rect (w or h <= 0),
1102  * this function will ignore region show action.
1103  */
1104 EAPI void
elm_widget_focus_region_show(Eo * obj)1105 elm_widget_focus_region_show(Eo *obj)
1106 {
1107    Evas_Coord ox, oy;
1108    Eina_Rect r;
1109    Evas_Object *o;
1110 
1111    o = elm_widget_parent_get(obj);
1112    if (!o) return;
1113 
1114    r = elm_widget_focus_region_get(obj);
1115    if (eina_rectangle_is_empty(&r.rect)) return;
1116 
1117    evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
1118 
1119    while (o)
1120      {
1121         Evas_Coord px, py;
1122         evas_object_geometry_get(o, &px, &py, NULL, NULL);
1123 
1124         if (_elm_scrollable_is(o) && !elm_widget_disabled_get(o))
1125           {
1126              Evas_Coord sx, sy;
1127              Evas_Coord vx, vy;
1128 
1129              elm_interface_scrollable_content_region_get(o, &sx, &sy, NULL, NULL);
1130              elm_interface_scrollable_content_viewport_geometry_get(o, &vx, &vy, NULL, NULL);
1131 
1132              // Get the object's on_focus_region position relative to the pan in the scroller.
1133              Evas_Coord rx, ry;
1134              rx = ox + r.x - vx + sx;
1135              ry = oy + r.y - vy + sy;
1136 
1137              switch (_elm_config->focus_autoscroll_mode)
1138                {
1139                 case ELM_FOCUS_AUTOSCROLL_MODE_SHOW:
1140                    elm_interface_scrollable_content_region_show(o, rx, ry, r.w, r.h);
1141                    break;
1142                 case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN:
1143                    elm_interface_scrollable_region_bring_in(o, rx, ry, r.w, r.h);
1144                    break;
1145                 default:
1146                    break;
1147                }
1148 
1149              r = elm_widget_focus_region_get(o);
1150              evas_object_geometry_get(o, &ox, &oy, NULL, NULL);
1151           }
1152         else
1153           {
1154              r.x += ox - px;
1155              r.y += oy - py;
1156              ox = px;
1157              oy = py;
1158           }
1159         o = elm_widget_parent_get(o);
1160      }
1161 }
1162 
1163 
1164 EAPI Eina_Bool
elm_widget_api_check(int ver)1165 elm_widget_api_check(int ver)
1166 {
1167    if (ver != ELM_INTERNAL_API_VERSION)
1168      {
1169         CRI("Elementary widget api versions do not match");
1170         return EINA_FALSE;
1171      }
1172    return EINA_TRUE;
1173 }
1174 
1175 EAPI Eina_Bool
elm_widget_access(Evas_Object * obj,Eina_Bool is_access)1176 elm_widget_access(Evas_Object *obj,
1177                   Eina_Bool is_access)
1178 {
1179    Evas_Object *child;
1180    Eina_Bool ret = EINA_TRUE;
1181 
1182    API_ENTRY return EINA_FALSE;
1183    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
1184      {
1185         child = eina_array_data_get(sd->children, i);
1186 
1187         if (elm_widget_is(child))
1188           ret &= elm_widget_access(child, is_access);
1189      }
1190 
1191    efl_ui_widget_on_access_update(obj, is_access);
1192    efl_event_callback_legacy_call(obj, EFL_UI_WIDGET_EVENT_ACCESS_CHANGED, NULL);
1193 
1194    return ret;
1195 }
1196 
1197 EOLIAN static void
_efl_ui_widget_on_access_update(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * _pd EINA_UNUSED,Eina_Bool is_access EINA_UNUSED)1198 _efl_ui_widget_on_access_update(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Eina_Bool is_access EINA_UNUSED)
1199 {
1200 }
1201 
1202 static void
_elm_widget_theme_helper(Eina_Error err,Eina_Bool * err_default,Eina_Bool * err_generic)1203 _elm_widget_theme_helper(Eina_Error err, Eina_Bool *err_default, Eina_Bool *err_generic)
1204 {
1205    if (err == EFL_UI_THEME_APPLY_ERROR_DEFAULT)
1206      *err_default = EINA_TRUE;
1207    else if (err == EFL_UI_THEME_APPLY_ERROR_GENERIC)
1208      *err_generic = EINA_TRUE;
1209 }
1210 
1211 EAPI Eina_Error
elm_widget_theme(Evas_Object * obj)1212 elm_widget_theme(Evas_Object *obj)
1213 {
1214    const Eina_List *l;
1215    Evas_Object *child;
1216    Elm_Tooltip *tt;
1217    Elm_Cursor *cur;
1218    Eina_Bool err_default = EINA_FALSE;
1219    Eina_Bool err_generic = EINA_FALSE;
1220 
1221    API_ENTRY return EFL_UI_THEME_APPLY_ERROR_GENERIC;
1222    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
1223      {
1224         child = eina_array_data_get(sd->children, i);
1225         if (_elm_widget_is(child))
1226           _elm_widget_theme_helper(elm_widget_theme(child), &err_default, &err_generic);
1227      }
1228 
1229    if (sd->hover_obj)
1230      _elm_widget_theme_helper(elm_widget_theme(sd->hover_obj), &err_default, &err_generic);
1231 
1232    EINA_LIST_FOREACH(sd->tooltips, l, tt)
1233      elm_tooltip_theme(tt);
1234    EINA_LIST_FOREACH(sd->cursors, l, cur)
1235      elm_cursor_theme(cur);
1236 
1237    _elm_widget_theme_helper(efl_ui_widget_theme_apply(obj), &err_default, &err_generic);
1238    if (err_generic) return EFL_UI_THEME_APPLY_ERROR_GENERIC;
1239    if (err_default) return EFL_UI_THEME_APPLY_ERROR_DEFAULT;
1240    return EFL_UI_THEME_APPLY_ERROR_NONE;
1241 }
1242 
1243 EAPI void
elm_widget_theme_specific(Evas_Object * obj,Elm_Theme * th,Eina_Bool force)1244 elm_widget_theme_specific(Evas_Object *obj,
1245                           Elm_Theme *th,
1246                           Eina_Bool force)
1247 {
1248    const Eina_List *l;
1249    Evas_Object *child;
1250    Elm_Tooltip *tt;
1251    Elm_Cursor *cur;
1252    Elm_Theme *th2, *thdef;
1253 
1254    API_ENTRY return;
1255 
1256    thdef = elm_theme_default_get();
1257    if (!th) th = thdef;
1258    if (!force)
1259      {
1260         th2 = sd->theme;
1261         if (!th2) th2 = thdef;
1262         while (th2)
1263           {
1264              if (th2 == th)
1265                {
1266                   force = EINA_TRUE;
1267                   break;
1268                }
1269              if (th2 == thdef) break;
1270              th2 = th2->ref_theme;
1271              if (!th2) th2 = thdef;
1272           }
1273      }
1274    if (!force) return;
1275    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
1276      {
1277         child = eina_array_data_get(sd->children, i);
1278         if (elm_widget_is(child))
1279           elm_widget_theme_specific(child, th, force);
1280      }
1281    if (sd->hover_obj) elm_widget_theme(sd->hover_obj);
1282    EINA_LIST_FOREACH(sd->tooltips, l, tt)
1283      elm_tooltip_theme(tt);
1284    EINA_LIST_FOREACH(sd->cursors, l, cur)
1285      elm_cursor_theme(cur);
1286    efl_ui_widget_theme_apply(obj);
1287 }
1288 
1289 EOLIAN static Eina_Error
_efl_ui_widget_theme_apply(Eo * obj,Elm_Widget_Smart_Data * _pd EINA_UNUSED)1290 _efl_ui_widget_theme_apply(Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
1291 {
1292    _elm_widget_mirrored_reload(obj);
1293 
1294    return EFL_UI_THEME_APPLY_ERROR_NONE;
1295 }
1296 
1297 /**
1298  * @internal
1299  *
1300  * Returns the widget's mirrored mode.
1301  *
1302  * @param obj The widget.
1303  * @return mirrored mode of the object.
1304  *
1305  **/
1306 EOLIAN static Eina_Bool
_efl_ui_widget_efl_ui_i18n_mirrored_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)1307 _efl_ui_widget_efl_ui_i18n_mirrored_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1308 {
1309    return sd->is_mirrored;
1310 }
1311 
1312 /**
1313  * @internal
1314  *
1315  * Sets the widget's mirrored mode.
1316  *
1317  * @param obj The widget.
1318  * @param mirrored EINA_TRUE to set mirrored mode. EINA_FALSE to unset.
1319  */
1320 EOLIAN static void
_efl_ui_widget_efl_ui_i18n_mirrored_set(Eo * obj,Elm_Widget_Smart_Data * sd,Eina_Bool mirrored)1321 _efl_ui_widget_efl_ui_i18n_mirrored_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool mirrored)
1322 {
1323    mirrored = !!mirrored;
1324 
1325    if (sd->is_mirrored == mirrored) return;
1326 
1327    sd->is_mirrored = mirrored;
1328    elm_widget_theme(obj);
1329 }
1330 
1331 /**
1332  * Returns the widget's mirrored mode setting.
1333  *
1334  * @param obj The widget.
1335  * @return mirrored mode setting of the object.
1336  *
1337  **/
1338 EOLIAN static Eina_Bool
_efl_ui_widget_efl_ui_i18n_mirrored_automatic_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)1339 _efl_ui_widget_efl_ui_i18n_mirrored_automatic_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1340 {
1341    return sd->mirrored_auto_mode;
1342 }
1343 
1344 /**
1345  * @internal
1346  *
1347  * Sets the widget's mirrored mode setting.
1348  * When widget in automatic mode, it follows the system mirrored mode set by
1349  * elm_mirrored_set().
1350  * @param obj The widget.
1351  * @param automatic EINA_TRUE for auto mirrored mode. EINA_FALSE for manual.
1352  */
1353 EOLIAN static void
_efl_ui_widget_efl_ui_i18n_mirrored_automatic_set(Eo * obj,Elm_Widget_Smart_Data * sd,Eina_Bool automatic)1354 _efl_ui_widget_efl_ui_i18n_mirrored_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic)
1355 {
1356    if (sd->mirrored_auto_mode != automatic)
1357      {
1358         sd->mirrored_auto_mode = automatic;
1359 
1360         if (automatic)
1361           {
1362              efl_ui_mirrored_set(obj, elm_config_mirrored_get());
1363           }
1364      }
1365 }
1366 
1367 /*
1368  * @internal
1369  *
1370  * Add myself as a sub object of parent object
1371  *
1372  * @see elm_widget_sub_object_add()
1373  */
1374 EAPI Eina_Bool
elm_widget_sub_object_parent_add(Evas_Object * sobj)1375 elm_widget_sub_object_parent_add(Evas_Object *sobj)
1376 {
1377    Eo *parent = NULL;
1378 
1379    parent = efl_parent_get(sobj);
1380    if (!efl_isa(parent, EFL_UI_WIDGET_CLASS))
1381      {
1382         ERR("You passed a wrong parent parameter (%p %s). "
1383             "Elementary widget's parent should be an elementary widget.", parent, evas_object_type_get(parent));
1384         return EINA_FALSE;
1385      }
1386 
1387    return elm_widget_sub_object_add(parent, sobj);
1388 }
1389 
1390 static int
_disabled_counter_get(Eo * widget)1391 _disabled_counter_get(Eo *widget)
1392 {
1393    ELM_WIDGET_DATA_GET_OR_RETURN(widget, pd, -1);
1394 
1395    return pd->disabled;
1396 }
1397 
1398 static void
_mirror_disabled_state(Eo * obj,Elm_Widget_Smart_Data * pd,int disabled_delta)1399 _mirror_disabled_state(Eo *obj, Elm_Widget_Smart_Data *pd, int disabled_delta)
1400 {
1401    int prev_disabled = pd->disabled;
1402 
1403    pd->disabled = (pd->parent_obj ? _disabled_counter_get(pd->parent_obj) : 0) + disabled_delta;
1404 
1405    //The current disabled state is the same as the parent
1406    //when the parent is assigned or changed, no further action is required.
1407    if (((prev_disabled > 0 && pd->disabled > 0)) ||
1408        ((prev_disabled <= 0 && pd->disabled <= 0)))
1409      return;
1410 
1411    //we should not call disabled_set when things are invalidated
1412    //otherwise we will unleashe an amount of errors in efl_ui_layout
1413    if (efl_invalidated_get(obj)) return;
1414 
1415    if (pd->disabled > 0)
1416      {
1417         pd->disabled --;
1418         efl_ui_widget_disabled_set(obj, EINA_TRUE);
1419      }
1420    else
1421      {
1422         pd->disabled ++;
1423         efl_ui_widget_disabled_set(obj, EINA_FALSE);
1424      }
1425 }
1426 
1427 EOLIAN static void
_efl_ui_widget_widget_parent_set(Eo * obj,Elm_Widget_Smart_Data * pd,Efl_Ui_Widget * parent)1428 _efl_ui_widget_widget_parent_set(Eo *obj, Elm_Widget_Smart_Data *pd, Efl_Ui_Widget *parent)
1429 {
1430    Efl_Ui_Widget *old_parent;
1431    //check if we are in the subobject list of parents
1432    if (parent)
1433      {
1434         ELM_WIDGET_DATA_GET_OR_RETURN(parent, ppd);
1435         EINA_SAFETY_ON_FALSE_RETURN(eina_array_find(ppd->children, obj, NULL));
1436         if (ppd->parent_obj == parent)
1437           {
1438              CRI("ATTEMPTING TO SET CHILD OF PARENT AS PARENT OF ITS OWN PARENT. THIS IS A BUG.");
1439              return;
1440           }
1441      }
1442 
1443    /* NOTE: In the following two lines, 'obj' is correct. Do not change it.
1444     * Due to elementary's scale policy, scale and prev_scale can be different in
1445     * some cases. This happens when obj's previous parent and new parent have
1446     * different scale value.
1447     * For example, if obj's previous parent's scale is 5 and new parent's scale
1448     * is 2 while obj's scale is 0. Then 'prev_pscale' is 5 and 'scale' is 2. So
1449     * we need to reset obj's scale to 5.
1450     * Note that each widget's scale is 1.0 by default.
1451     */
1452    double scale, prev_scale = efl_gfx_entity_scale_get(obj);
1453    Elm_Theme *th, *prev_th = elm_widget_theme_get(obj);
1454    int disabled_delta = pd->disabled - (pd->parent_obj ? _disabled_counter_get(pd->parent_obj) : 0);
1455 
1456    old_parent = pd->parent_obj;
1457    pd->parent_obj = parent;
1458 
1459    // now lets sync up all states
1460    if (pd->parent_obj)
1461      {
1462         Eina_Bool mirrored, pmirrored = efl_ui_mirrored_get(pd->parent_obj);
1463         scale = efl_gfx_entity_scale_get(obj);
1464         th = elm_widget_theme_get(obj);
1465         mirrored = efl_ui_mirrored_get(obj);
1466 
1467         if (!pd->on_create)
1468           {
1469              if (!EINA_DBL_EQ(scale, prev_scale) || (th != prev_th) ||
1470                  (pmirrored != mirrored))
1471                elm_widget_theme(obj);
1472           }
1473         if (_is_focused(obj)) _parents_focus(parent);
1474         elm_widget_display_mode_set(obj, evas_object_size_hint_display_mode_get(parent));
1475         _elm_widget_top_win_focused_set(obj, _elm_widget_top_win_focused_get(parent));
1476      }
1477    _mirror_disabled_state(obj, pd, disabled_delta);
1478    _full_eval(obj, pd);
1479 
1480    if (!efl_alive_get(obj)) return;
1481    if (old_parent && _elm_config->atspi_mode)
1482      {
1483         Efl_Access_Object *aparent;
1484         aparent = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
1485         if (aparent)
1486            efl_access_children_changed_del_signal_emit(aparent, obj);
1487      }
1488 
1489    if (pd->parent_obj && _elm_config->atspi_mode && efl_finalized_get(parent))
1490      {
1491         Efl_Access_Object *aparent;
1492         aparent = efl_provider_find(efl_parent_get(obj), EFL_ACCESS_OBJECT_MIXIN);
1493         if (aparent)
1494            efl_access_children_changed_added_signal_emit(aparent, obj);
1495      }
1496 }
1497 
1498 static void
_widget_add_sub(Eo * obj,Elm_Widget_Smart_Data * sd,Evas_Object * sobj)1499 _widget_add_sub(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1500 {
1501    if (!sd->children) sd->children = eina_array_new(1);
1502    eina_array_push(sd->children, sobj);
1503    evas_object_data_set(sobj, "elm-parent", obj);
1504    _callbacks_add(sobj, obj);
1505 }
1506 
1507 static void
_widget_del_sub(Eo * obj,Elm_Widget_Smart_Data * sd,Evas_Object * sobj)1508 _widget_del_sub(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1509 {
1510    eina_array_remove(sd->children, _keep, sobj);
1511    evas_object_data_del(sobj, "elm-parent");
1512    _callbacks_del(sobj, obj);
1513 }
1514 
1515 EOLIAN static Eina_Bool
_efl_ui_widget_widget_sub_object_add(Eo * obj,Elm_Widget_Smart_Data * sd,Evas_Object * sobj)1516 _efl_ui_widget_widget_sub_object_add(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1517 {
1518    Efl_Ui_Widget *parent;
1519    Eina_Bool is_widget;
1520 
1521    EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(sobj, EFL_GFX_ENTITY_INTERFACE), EINA_FALSE);
1522    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1523 
1524    is_widget = elm_widget_is(sobj);
1525    //first make sure that we unregister the sobj from the parent
1526    if (is_widget)
1527      parent = efl_ui_widget_parent_get(sobj);
1528    else
1529      parent = evas_object_data_get(sobj, "elm-parent");
1530    if (parent == obj) return EINA_TRUE;
1531    if (parent)
1532      {
1533         if (sd->parent_obj == sobj)
1534           {
1535              CRI("ATTEMPTING TO SET CHILD OF PARENT AS PARENT OF ITS OWN PARENT. THIS IS A BUG.");
1536              return EINA_FALSE;
1537           }
1538 
1539         if (!efl_ui_widget_sub_object_del(parent, sobj))
1540           return EINA_FALSE;
1541      }
1542 
1543    //sobj does not have a parent here
1544    //first add it to our own children list
1545    _widget_add_sub(obj, sd, sobj);
1546 
1547    //and if it is a widget, please set the correct parent on the widget itself
1548    //the parent set method will take care of the property syncing etc.
1549    if (is_widget)
1550      efl_ui_widget_parent_set(sobj, obj);
1551 
1552    return EINA_TRUE;
1553 }
1554 
1555 EOLIAN static Eina_Bool
_efl_ui_widget_widget_sub_object_del(Eo * obj,Elm_Widget_Smart_Data * sd,Evas_Object * sobj)1556 _efl_ui_widget_widget_sub_object_del(Eo *obj, Elm_Widget_Smart_Data *sd, Evas_Object *sobj)
1557 {
1558    Evas_Object *sobj_parent = NULL;
1559    Eina_Bool is_widget;
1560 
1561    if (!sobj) return EINA_FALSE;
1562 
1563    EINA_SAFETY_ON_TRUE_RETURN_VAL(obj == sobj, EINA_FALSE);
1564 
1565    is_widget = _elm_widget_is(sobj);
1566 
1567    if (!is_widget) sobj_parent = evas_object_data_del(sobj, "elm-parent");
1568 
1569    if (sobj_parent && sobj_parent != obj)
1570      {
1571         static int abort_on_warn = -1;
1572 
1573         ERR("removing sub object %p (%s) from parent %p (%s), "
1574             "but elm-parent is different %p (%s)!",
1575             sobj, elm_widget_type_get(sobj), obj, elm_widget_type_get(obj),
1576             sobj_parent, elm_widget_type_get(sobj_parent));
1577 
1578         if (EINA_UNLIKELY(abort_on_warn == -1))
1579           {
1580              if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
1581              else abort_on_warn = 0;
1582           }
1583         if (abort_on_warn == 1) abort();
1584 
1585         return EINA_FALSE;
1586      }
1587 
1588    if (is_widget)
1589      {
1590 	if (efl_ui_widget_parent_get(sobj) != obj)
1591           return EINA_FALSE;
1592         if (_is_focused(sobj))
1593           {
1594              elm_widget_tree_unfocusable_set(sobj, EINA_TRUE);
1595              elm_widget_tree_unfocusable_set(sobj, EINA_FALSE);
1596           }
1597 
1598         efl_ui_widget_parent_set(sobj, NULL);
1599      }
1600 
1601    if (sd->resize_obj == sobj) sd->resize_obj = NULL;
1602 
1603    _widget_del_sub(obj, sd, sobj);
1604 
1605    return EINA_TRUE;
1606 }
1607 
1608 /* protected function - for widget developers only */
1609 EOLIAN static void
_efl_ui_widget_resize_object_set(Eo * obj,Elm_Widget_Smart_Data * sd,Eo * sobj)1610 _efl_ui_widget_resize_object_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eo *sobj)
1611 {
1612    Evas_Object *parent;
1613 
1614    if (sd->resize_obj == sobj) return;
1615    EINA_SAFETY_ON_TRUE_RETURN(sobj && !efl_isa(sobj, EFL_CANVAS_OBJECT_CLASS));
1616 
1617    // orphan previous resize obj
1618    if (sd->resize_obj)
1619      {
1620         evas_object_clip_unset(sd->resize_obj);
1621         evas_object_smart_member_del(sd->resize_obj);
1622 
1623         if (_elm_widget_is(sd->resize_obj))
1624           {
1625              if (_is_focused(sd->resize_obj)) _parents_unfocus(obj);
1626           }
1627         elm_widget_sub_object_del(obj, sd->resize_obj);
1628      }
1629 
1630    sd->resize_obj = sobj;
1631    if (!sobj) return;
1632 
1633    // orphan new resize obj
1634    parent = evas_object_data_get(sobj, "elm-parent");
1635    if (parent && parent != obj)
1636      {
1637         ELM_WIDGET_DATA_GET(parent, sdp);
1638 
1639         /* should be there, just being paranoid */
1640         if (sdp)
1641           {
1642              if (sdp->resize_obj == sobj)
1643                elm_widget_resize_object_set(parent, NULL);
1644              else
1645                elm_widget_sub_object_del(parent, sobj);
1646           }
1647      }
1648 
1649    elm_widget_sub_object_add(obj, sobj);
1650    evas_object_smart_member_add(sobj, obj);
1651    _smart_reconfigure(obj, sd);
1652 }
1653 
1654 /*
1655  * @internal
1656  *
1657  * WARNING: the programmer is responsible, in the scenario of
1658  * exchanging a hover object, of cleaning the old hover "target"
1659  * before
1660  */
1661 EAPI void
elm_widget_hover_object_set(Eo * obj,Evas_Object * sobj)1662 elm_widget_hover_object_set(Eo *obj, Evas_Object *sobj)
1663 {
1664    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1665    if (!sd) return;
1666 
1667    if (sd->hover_obj)
1668      {
1669         _callbacks_del(sd->hover_obj, obj);
1670      }
1671    sd->hover_obj = sobj;
1672    if (sd->hover_obj)
1673      {
1674         _callbacks_add(sobj, obj);
1675         _smart_reconfigure(obj, sd);
1676      }
1677 }
1678 
1679 EOLIAN static void
_efl_ui_widget_focus_allow_set(Eo * obj,Elm_Widget_Smart_Data * sd,Eina_Bool can_focus)1680 _efl_ui_widget_focus_allow_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool can_focus)
1681 {
1682    can_focus = !!can_focus;
1683 
1684    if (sd->can_focus == can_focus) return;
1685    sd->can_focus = can_focus;
1686    if (sd->can_focus)
1687      {
1688         efl_event_callback_array_add(obj, focus_callbacks(), NULL);
1689      }
1690    else
1691      {
1692         efl_event_callback_array_del(obj, focus_callbacks(), NULL);
1693      }
1694      if (efl_finalized_get(obj))
1695        _full_eval(obj, sd);
1696 }
1697 
1698 EOLIAN static Eina_Bool
_efl_ui_widget_focus_allow_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)1699 _efl_ui_widget_focus_allow_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
1700 {
1701    return sd->can_focus;
1702 }
1703 
1704 EAPI Eina_Bool
elm_widget_child_can_focus_get(const Eo * obj)1705 elm_widget_child_can_focus_get(const Eo *obj)
1706 {
1707    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1708    if (!sd) return EINA_FALSE;
1709 
1710    return sd->logical.child_count > 0;
1711 }
1712 
1713 
1714 static int
_tree_unfocusable_counter_get(Eo * widget)1715 _tree_unfocusable_counter_get(Eo *widget)
1716 {
1717    ELM_WIDGET_DATA_GET_OR_RETURN(widget, pd, -1);
1718 
1719    return pd->tree_unfocusable;
1720 }
1721 
1722 /**
1723  * Evalulate tree number.
1724  *
1725  * This is here to support properties which are propagating through the widget tree. If this property is set to true,
1726  * every widget in the subtree, will also be automatically true.
1727  * When one of the widgets in the subtree then seperatly will be set to true, the unsetting on the original widget will not unset the flag automatically in this tree.
1728  *
1729  * The basic idea here is:
1730  * - The numeric number beeing bigger than 0, means that the property is true
1731  * - The difference between the number of the parent, and the number of the object, represents the boolean flag
1732  *   (0 means that the flag is equal to the one of the parent, 1 means that if the parent is false, this child is true).
1733  */
1734 static int
_calculate_tree_number(int self_counter,int parent_counter,Eina_Bool flag)1735 _calculate_tree_number(int self_counter, int parent_counter, Eina_Bool flag)
1736 {
1737    int distance = self_counter - parent_counter;
1738 
1739    if (flag)
1740      self_counter ++;
1741    else
1742      self_counter --;
1743 
1744    distance = self_counter - parent_counter;
1745 
1746    if ((distance < 0) || (distance > 1))
1747      {
1748         distance = MAX(MIN(flag, 1), 0);
1749         self_counter = parent_counter + distance;
1750      }
1751 
1752    return self_counter;
1753 }
1754 
1755 static void
_propagate_bool_property(Elm_Widget_Smart_Data * pd,Eina_Bool flag,void (* property_setting)(Eo * obj,Eina_Bool flag))1756 _propagate_bool_property(Elm_Widget_Smart_Data *pd, Eina_Bool flag, void (*property_setting)(Eo *obj, Eina_Bool flag))
1757 {
1758    Efl_Ui_Widget *subs;
1759    for (unsigned int i = 0; i < eina_array_count(pd->children); ++i)
1760      {
1761         subs = eina_array_data_get(pd->children, i);
1762         if (efl_isa(subs, EFL_UI_WIDGET_CLASS))
1763           property_setting(subs, flag);
1764      }
1765 }
1766 
1767 /**
1768  * @internal
1769  *
1770  * This API makes the widget object and its children to be unfocusable.
1771  *
1772  * This API can be helpful for an object to be deleted.
1773  * When an object will be deleted soon, it and its children may not
1774  * want to get focus (by focus reverting or by other focus controls).
1775  * Then, just use this API before deleting.
1776  *
1777  * @param obj The widget root of sub-tree
1778  * @param tree_unfocusable If true, set the object sub-tree as unfocusable
1779  *
1780  * @ingroup Widget
1781  */
1782 EAPI void
elm_widget_tree_unfocusable_set(Eo * obj,Eina_Bool tree_unfocusable)1783 elm_widget_tree_unfocusable_set(Eo *obj, Eina_Bool tree_unfocusable)
1784 {
1785    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
1786    EINA_SAFETY_ON_NULL_RETURN(pd);
1787    int old_tree_unfocusable;
1788 
1789    old_tree_unfocusable = pd->tree_unfocusable;
1790 
1791    pd->tree_unfocusable = _calculate_tree_number(pd->tree_unfocusable,
1792                                                 (pd->parent_obj ? _tree_unfocusable_counter_get(pd->parent_obj) : 0),
1793                                                 tree_unfocusable);
1794 
1795    if (old_tree_unfocusable != pd->tree_unfocusable)
1796      {
1797         _full_eval(obj, pd);
1798         _propagate_bool_property(pd, tree_unfocusable, elm_widget_tree_unfocusable_set);
1799      }
1800 }
1801 
1802 /**
1803  * @internal
1804  *
1805  * This returns true, if the object sub-tree is unfocusable.
1806  *
1807  * @param obj The widget root of sub-tree
1808  * @return EINA_TRUE if the object sub-tree is unfocusable
1809  *
1810  * @ingroup Widget
1811  */
1812 EAPI Eina_Bool
elm_widget_tree_unfocusable_get(const Eo * obj)1813 elm_widget_tree_unfocusable_get(const Eo *obj)
1814 {
1815    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1816    EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_FALSE);
1817 
1818    return !!sd->tree_unfocusable;
1819 }
1820 
1821 /**
1822  * @internal
1823  *
1824  * Get the list of focusable child objects.
1825  *
1826  * This function returns list of child objects which can get focus.
1827  *
1828  * @param obj The parent widget
1829  * @return list of focusable child objects.
1830  *
1831  * @ingroup Widget
1832  */
1833 EAPI Eina_List*
elm_widget_can_focus_child_list_get(const Eo * obj)1834 elm_widget_can_focus_child_list_get(const Eo *obj)
1835 {
1836    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1837    Eina_List *child_list = NULL;
1838    Evas_Object *child;
1839 
1840    if (!sd) return NULL;
1841    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
1842      {
1843         child = eina_array_data_get(sd->children, i);
1844         if (!_elm_widget_is(child)) continue;
1845         if ((elm_widget_can_focus_get(child)) &&
1846             (evas_object_visible_get(child)) &&
1847             (!elm_widget_disabled_get(child)))
1848           child_list = eina_list_append(child_list, child);
1849         else
1850           {
1851              Eina_List *can_focus_list;
1852              can_focus_list = elm_widget_can_focus_child_list_get(child);
1853              if (can_focus_list)
1854                child_list = eina_list_merge(child_list, can_focus_list);
1855           }
1856      }
1857 
1858    return child_list;
1859 }
1860 
1861 /** @internal */
1862 EAPI void
elm_widget_highlight_ignore_set(Eo * obj,Eina_Bool ignore)1863 elm_widget_highlight_ignore_set(Eo *obj, Eina_Bool ignore)
1864 {
1865    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1866    if (!sd) return;
1867 
1868    sd->highlight_ignore = !!ignore;
1869 }
1870 
1871 /** @internal */
1872 EAPI Eina_Bool
elm_widget_highlight_ignore_get(const Eo * obj)1873 elm_widget_highlight_ignore_get(const Eo *obj)
1874 {
1875    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1876    if (!sd) return EINA_FALSE;
1877 
1878    return sd->highlight_ignore;
1879 }
1880 
1881 /** @internal */
1882 EAPI void
elm_widget_highlight_in_theme_set(Eo * obj,Eina_Bool highlight)1883 elm_widget_highlight_in_theme_set(Eo *obj, Eina_Bool highlight)
1884 {
1885    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1886    if (!sd) return;
1887 
1888    sd->highlight_in_theme = !!highlight;
1889    /* FIXME: if focused, it should switch from one mode to the other */
1890 }
1891 
1892 void
_elm_widget_highlight_in_theme_update(Eo * obj)1893 _elm_widget_highlight_in_theme_update(Eo *obj)
1894 {
1895    Evas_Object *top = elm_widget_top_get(obj);
1896 
1897    if (top && efl_isa(top, EFL_UI_WIN_CLASS))
1898      {
1899         _elm_win_focus_highlight_in_theme_update(
1900            top, elm_widget_highlight_in_theme_get(obj));
1901      }
1902 }
1903 
1904 /** @internal */
1905 EAPI Eina_Bool
elm_widget_highlight_in_theme_get(const Eo * obj)1906 elm_widget_highlight_in_theme_get(const Eo *obj)
1907 {
1908    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1909    if (!sd) return EINA_FALSE;
1910 
1911    return sd->highlight_in_theme;
1912 }
1913 
1914 /** @internal */
1915 EAPI void
elm_widget_access_highlight_in_theme_set(Eo * obj,Eina_Bool highlight)1916 elm_widget_access_highlight_in_theme_set(Eo *obj, Eina_Bool highlight)
1917 {
1918    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1919    if (!sd) return;
1920 
1921    sd->access_highlight_in_theme = !!highlight;
1922 }
1923 
1924 /** @internal */
1925 EAPI Eina_Bool
elm_widget_access_highlight_in_theme_get(const Eo * obj)1926 elm_widget_access_highlight_in_theme_get(const Eo *obj)
1927 {
1928    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1929    if (!sd) return EINA_FALSE;
1930 
1931    return sd->access_highlight_in_theme;
1932 }
1933 
1934 /** @internal */
1935 EAPI Eina_Bool
elm_widget_highlight_get(const Eo * obj)1936 elm_widget_highlight_get(const Eo *obj)
1937 {
1938    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
1939    if (!sd) return EINA_FALSE;
1940 
1941    return sd->highlighted;
1942 }
1943 
1944 EAPI Eina_Bool
elm_widget_is(const Evas_Object * obj)1945 elm_widget_is(const Evas_Object *obj)
1946 {
1947    return _elm_widget_is(obj);
1948 }
1949 
1950 EAPI void
elm_widget_access_info_set(Efl_Ui_Widget * obj,const char * txt)1951 elm_widget_access_info_set(Efl_Ui_Widget *obj, const char *txt)
1952 {
1953    efl_ui_widget_access_info_set(obj, txt);
1954 }
1955 
1956 EAPI const char *
elm_widget_access_info_get(const Efl_Ui_Widget * obj)1957 elm_widget_access_info_get(const Efl_Ui_Widget *obj)
1958 {
1959    return efl_ui_widget_access_info_get(obj);
1960 }
1961 
1962 EAPI Eo *
elm_widget_top_get(const Eo * obj)1963 elm_widget_top_get(const Eo *obj)
1964 {
1965    Efl_Ui_Widget *parent = elm_widget_parent_get(obj);
1966    if (parent)
1967      {
1968         if (!efl_isa(parent, EFL_UI_WIDGET_CLASS)) return NULL;
1969         return elm_widget_top_get(parent);
1970      }
1971    /* XXX const */
1972    return (Evas_Object *)obj;
1973 }
1974 
1975 EAPI Evas_Object *
elm_widget_parent_widget_get(const Evas_Object * obj)1976 elm_widget_parent_widget_get(const Evas_Object *obj)
1977 {
1978    Evas_Object *parent;
1979 
1980    if (_elm_widget_is(obj))
1981      {
1982         ELM_WIDGET_DATA_GET(obj, sd);
1983         if (!sd) return NULL;
1984         parent = sd->parent_obj;
1985      }
1986    else
1987      {
1988         parent = evas_object_data_get(obj, "elm-parent");
1989         if (!parent) parent = evas_object_smart_parent_get(obj);
1990      }
1991 
1992    while (parent)
1993      {
1994         Evas_Object *elm_parent;
1995         if (_elm_widget_is(parent)) break;
1996         elm_parent = evas_object_data_get(parent, "elm-parent");
1997         if (elm_parent) parent = elm_parent;
1998         else parent = evas_object_smart_parent_get(parent);
1999      }
2000    return parent;
2001 }
2002 
2003 EAPI void
elm_widget_event_callback_add(Eo * obj,Elm_Event_Cb func,const void * data)2004 elm_widget_event_callback_add(Eo *obj, Elm_Event_Cb func, const void *data)
2005 {
2006    API_ENTRY return;
2007    EINA_SAFETY_ON_NULL_RETURN(func);
2008 
2009    Elm_Event_Cb_Data *ecb = ELM_NEW(Elm_Event_Cb_Data);
2010    if (!ecb)
2011      {
2012         ERR("Failed to allocate memory");
2013         return;
2014      }
2015    ecb->func = func;
2016    ecb->data = data;
2017    sd->event_cb = eina_list_append(sd->event_cb, ecb);
2018 }
2019 
2020 EAPI void *
elm_widget_event_callback_del(Eo * obj,Elm_Event_Cb func,const void * data)2021 elm_widget_event_callback_del(Eo *obj, Elm_Event_Cb func, const void *data)
2022 {
2023    API_ENTRY return NULL;
2024    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
2025    Eina_List *l;
2026    Elm_Event_Cb_Data *ecd;
2027 
2028    EINA_LIST_FOREACH(sd->event_cb, l, ecd)
2029      if ((ecd->func == func) && (ecd->data == data))
2030        {
2031           free(ecd);
2032           sd->event_cb = eina_list_remove_list(sd->event_cb, l);
2033           return (void *)data;
2034        }
2035 
2036    return NULL;
2037 }
2038 
2039 static void
_propagate_event(void * data EINA_UNUSED,const Efl_Event * eo_event)2040 _propagate_event(void *data EINA_UNUSED, const Efl_Event *eo_event)
2041 {
2042    Evas_Object *obj = eo_event->object;
2043    Evas_Object *parent = obj;
2044    Elm_Event_Cb_Data *ecd;
2045    Eina_List *l, *l_prev;
2046 
2047    if ((evas_focus_get(evas_object_evas_get(obj)) != elm_widget_top_get(obj)) &&
2048        efl_isa(obj, EFL_UI_WIN_CLASS))
2049      return;
2050 
2051    while (parent && !efl_input_processed_get(eo_event->info))
2052      {
2053         Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(parent, MY_CLASS);
2054         if (!sd) return;
2055 
2056         if (elm_widget_disabled_get(obj))
2057           {
2058              parent = sd->parent_obj;
2059              continue;
2060           }
2061 
2062         if (efl_ui_widget_input_event_handler(parent, eo_event, obj))
2063           return;
2064 
2065         EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
2066           {
2067              if (_propagate_event_legacy(parent, eo_event, obj, ecd))
2068                return;
2069           }
2070 
2071         parent = sd->parent_obj;
2072      }
2073 }
2074 
2075 /** @internal */
2076 EAPI void
elm_widget_parent_highlight_set(Eo * obj,Eina_Bool highlighted)2077 elm_widget_parent_highlight_set(Eo *obj, Eina_Bool highlighted)
2078 {
2079    Elm_Widget_Smart_Data *sd =efl_data_scope_safe_get(obj, MY_CLASS);
2080    if (!sd) return;
2081 
2082    highlighted = !!highlighted;
2083 
2084    Evas_Object *o = elm_widget_parent_get(obj);
2085 
2086    if (o) elm_widget_parent_highlight_set(o, highlighted);
2087 
2088    sd->highlighted = highlighted;
2089 }
2090 
2091 EOLIAN static Evas_Object*
_efl_ui_widget_widget_parent_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)2092 _efl_ui_widget_widget_parent_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
2093 {
2094    return sd->parent_obj;
2095 }
2096 
2097 void
_elm_widget_focus_auto_show(Evas_Object * obj)2098 _elm_widget_focus_auto_show(Evas_Object *obj)
2099 {
2100    Evas_Object *top = elm_widget_top_get(obj);
2101    if (top && efl_isa(top, EFL_UI_WIN_CLASS)) _elm_win_focus_auto_show(top);
2102 }
2103 
2104 void
_elm_widget_top_win_focused_set(Evas_Object * obj,Eina_Bool top_win_focused)2105 _elm_widget_top_win_focused_set(Evas_Object *obj,
2106                                 Eina_Bool top_win_focused)
2107 {
2108    Evas_Object *child;
2109    API_ENTRY return;
2110 
2111    if (sd->top_win_focused == top_win_focused) return;
2112    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2113      {
2114         child = eina_array_data_get(sd->children, i);
2115         if (elm_widget_is(child))
2116           _elm_widget_top_win_focused_set(child, top_win_focused);
2117      }
2118    sd->top_win_focused = top_win_focused;
2119 
2120    if (sd->focused && !sd->top_win_focused)
2121      efl_ui_focus_object_on_focus_update(obj);
2122 }
2123 
2124 Eina_Bool
_elm_widget_top_win_focused_get(const Evas_Object * obj)2125 _elm_widget_top_win_focused_get(const Evas_Object *obj)
2126 {
2127    API_ENTRY return EINA_FALSE;
2128    return sd->top_win_focused;
2129 }
2130 
2131 EOLIAN static void
_efl_ui_widget_disabled_set(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * pd,Eina_Bool disabled)2132 _efl_ui_widget_disabled_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd, Eina_Bool disabled)
2133 {
2134    int old_state;
2135 
2136    old_state = pd->disabled;
2137 
2138    pd->disabled = _calculate_tree_number(pd->disabled, (pd->parent_obj ? _disabled_counter_get(pd->parent_obj) : 0), disabled);
2139    if (old_state != pd->disabled)
2140      {
2141         if (efl_finalized_get(obj))
2142           _full_eval(obj, pd);
2143         _propagate_bool_property(pd, disabled, efl_ui_widget_disabled_set);
2144      }
2145 }
2146 
2147 EOLIAN static Eina_Bool
_efl_ui_widget_disabled_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * pd)2148 _efl_ui_widget_disabled_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd)
2149 {
2150    return pd->disabled > 0;
2151 }
2152 
2153 /**
2154  * @internal
2155  *
2156  * Get the focus region of the given widget.
2157  *
2158  * @return The region to show. If it's not a valid rectangle it will not show.
2159  *
2160  * The focus region is the area of a widget that should brought into the
2161  * visible area when the widget is focused. Mostly used to show the part of
2162  * an entry where the cursor is, for example. The area returned is relative
2163  * to the object @p obj.
2164  *
2165  * @param obj The widget object
2166  * @return The region to show, in relative coordinates. If it's not a valid
2167  *         rectangle (i.e. w or h <= 0) it will be ignored.
2168  *
2169  * @ingroup Widget
2170  */
2171 EOLIAN static Eina_Rect
_efl_ui_widget_interest_region_get(const Eo * obj,Elm_Widget_Smart_Data * _pd EINA_UNUSED)2172 _efl_ui_widget_interest_region_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
2173 {
2174    Eina_Rect r = {};
2175    r.size = efl_gfx_entity_size_get(obj);
2176    return r;
2177 }
2178 
2179 EOLIAN static void
_efl_ui_widget_scroll_hold_push(Eo * obj,Elm_Widget_Smart_Data * sd)2180 _efl_ui_widget_scroll_hold_push(Eo *obj, Elm_Widget_Smart_Data *sd)
2181 {
2182    sd->scroll_hold++;
2183    if (sd->scroll_hold == 1)
2184      {
2185         if (_elm_scrollable_is(obj))
2186           {
2187              if (elm_widget_is_legacy(obj))
2188                elm_interface_scrollable_hold_set(obj, EINA_TRUE);
2189              else
2190                efl_ui_scrollable_scroll_hold_set(obj, EINA_TRUE);
2191           }
2192         else
2193           {
2194              Evas_Object *child;
2195 
2196              for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2197                {
2198                   child = eina_array_data_get(sd->children, i);
2199                   if (elm_widget_is(child) && _elm_scrollable_is(child))
2200                     {
2201                        if (elm_widget_is_legacy(child))
2202                          elm_interface_scrollable_hold_set(child, EINA_TRUE);
2203                        else
2204                          efl_ui_scrollable_scroll_hold_set(child, EINA_TRUE);
2205                     }
2206                }
2207           }
2208      }
2209    if (sd->parent_obj) efl_ui_widget_scroll_hold_push(sd->parent_obj);
2210    // FIXME: on delete/reparent hold pop
2211 }
2212 
2213 EOLIAN static void
_efl_ui_widget_scroll_hold_pop(Eo * obj,Elm_Widget_Smart_Data * sd)2214 _efl_ui_widget_scroll_hold_pop(Eo *obj, Elm_Widget_Smart_Data *sd)
2215 {
2216    sd->scroll_hold--;
2217    if (!sd->scroll_hold)
2218      {
2219         if (_elm_scrollable_is(obj))
2220           {
2221              if (elm_widget_is_legacy(obj))
2222                elm_interface_scrollable_hold_set(obj, EINA_FALSE);
2223              else
2224                efl_ui_scrollable_scroll_hold_set(obj, EINA_FALSE);
2225           }
2226         else
2227           {
2228              Evas_Object *child;
2229 
2230              for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2231                {
2232                   child = eina_array_data_get(sd->children, i);
2233                   if (elm_widget_is(child) && _elm_scrollable_is(child))
2234                     {
2235                        if (elm_widget_is_legacy(child))
2236                          elm_interface_scrollable_hold_set(child, EINA_FALSE);
2237                        else
2238                          efl_ui_scrollable_scroll_hold_set(child, EINA_FALSE);
2239                      }
2240                }
2241           }
2242      }
2243    if (sd->parent_obj) efl_ui_widget_scroll_hold_pop(sd->parent_obj);
2244    if (sd->scroll_hold < 0) sd->scroll_hold = 0;
2245 }
2246 
2247 EAPI int
elm_widget_scroll_hold_get(const Eo * obj)2248 elm_widget_scroll_hold_get(const Eo *obj)
2249 {
2250    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2251 
2252    if (!sd) return 0;
2253    return sd->scroll_hold;
2254 }
2255 
2256 EOLIAN static void
_efl_ui_widget_scroll_freeze_push(Eo * obj,Elm_Widget_Smart_Data * sd)2257 _efl_ui_widget_scroll_freeze_push(Eo *obj, Elm_Widget_Smart_Data *sd)
2258 {
2259    sd->scroll_freeze++;
2260    if (sd->scroll_freeze == 1)
2261      {
2262         if (_elm_scrollable_is(obj))
2263           {
2264              if (elm_widget_is_legacy(obj))
2265                elm_interface_scrollable_freeze_set(obj, EINA_TRUE);
2266              else
2267                efl_ui_scrollable_scroll_freeze_set(obj, EINA_TRUE);
2268           }
2269         else
2270           {
2271              Evas_Object *child;
2272 
2273              for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2274                {
2275                   child = eina_array_data_get(sd->children, i);
2276                   if (elm_widget_is(child) && _elm_scrollable_is(child))
2277                     {
2278                        if (elm_widget_is_legacy(child))
2279                          elm_interface_scrollable_freeze_set(child, EINA_TRUE);
2280                        else
2281                          efl_ui_scrollable_scroll_freeze_set(child, EINA_TRUE);
2282                     }
2283                }
2284           }
2285      }
2286    if (sd->parent_obj) efl_ui_widget_scroll_freeze_push(sd->parent_obj);
2287    // FIXME: on delete/reparent freeze pop
2288 }
2289 
2290 EOLIAN static void
_efl_ui_widget_scroll_freeze_pop(Eo * obj,Elm_Widget_Smart_Data * sd)2291 _efl_ui_widget_scroll_freeze_pop(Eo *obj, Elm_Widget_Smart_Data *sd)
2292 {
2293    sd->scroll_freeze--;
2294    if (!sd->scroll_freeze)
2295      {
2296         if (_elm_scrollable_is(obj))
2297           {
2298              if (elm_widget_is_legacy(obj))
2299                elm_interface_scrollable_freeze_set(obj, EINA_FALSE);
2300              else
2301                efl_ui_scrollable_scroll_freeze_set(obj, EINA_FALSE);
2302           }
2303         else
2304           {
2305              Evas_Object *child;
2306 
2307              for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2308                {
2309                   child = eina_array_data_get(sd->children, i);
2310 
2311                   if (elm_widget_is(child) && _elm_scrollable_is(child))
2312                     {
2313                        if (elm_widget_is_legacy(child))
2314                          elm_interface_scrollable_freeze_set(child, EINA_FALSE);
2315                        else
2316                          efl_ui_scrollable_scroll_freeze_set(child, EINA_FALSE);
2317                     }
2318                }
2319           }
2320      }
2321    if (sd->parent_obj) efl_ui_widget_scroll_freeze_pop(sd->parent_obj);
2322    if (sd->scroll_freeze < 0) sd->scroll_freeze = 0;
2323 }
2324 
2325 EAPI int
elm_widget_scroll_freeze_get(const Eo * obj)2326 elm_widget_scroll_freeze_get(const Eo *obj)
2327 {
2328    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2329 
2330    if (!sd) return 0;
2331    return sd->scroll_freeze;
2332 }
2333 
2334 EOLIAN static void
_efl_ui_widget_efl_gfx_entity_scale_set(Eo * obj,Elm_Widget_Smart_Data * sd,double scale)2335 _efl_ui_widget_efl_gfx_entity_scale_set(Eo *obj, Elm_Widget_Smart_Data *sd, double scale)
2336 {
2337    if (scale < 0.0) scale = 0.0;
2338    if (!EINA_DBL_EQ(sd->scale, scale))
2339      {
2340         sd->scale = scale;
2341         elm_widget_theme(obj);
2342      }
2343 }
2344 
2345 EOLIAN static double
_efl_ui_widget_efl_gfx_entity_scale_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)2346 _efl_ui_widget_efl_gfx_entity_scale_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
2347 {
2348    // FIXME: save walking up the tree by storing/caching parent scale
2349    if (EINA_DBL_EQ(sd->scale, 0.0))
2350      {
2351         if (sd->parent_obj)
2352           {
2353              return efl_gfx_entity_scale_get(sd->parent_obj);
2354           }
2355         else
2356           {
2357              return 1.0;
2358           }
2359      }
2360    return sd->scale;
2361 }
2362 
2363 EAPI void
elm_widget_theme_set(Evas_Object * obj,Elm_Theme * th)2364 elm_widget_theme_set(Evas_Object *obj, Elm_Theme *th)
2365 {
2366    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2367    if (!sd) return;
2368 
2369    Eina_Bool apply = EINA_FALSE;
2370    if (sd->theme != th)
2371      {
2372         if (elm_widget_theme_get(obj) != th) apply = EINA_TRUE;
2373         if (sd->theme) elm_theme_free(sd->theme);
2374         sd->theme = th;
2375         if (th) efl_ref(th->eo_theme);
2376         if (apply) elm_widget_theme(obj);
2377      }
2378 }
2379 
2380 EAPI void
elm_widget_part_text_set(Eo * obj,const char * part,const char * label)2381 elm_widget_part_text_set(Eo *obj, const char *part, const char *label)
2382 {
2383    /* legacy support: combobox was special (internal entry is text object). */
2384    if (efl_isa(obj, ELM_COMBOBOX_CLASS))
2385      _elm_combobox_part_text_set(obj, part, label);
2386    else if (efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
2387      elm_layout_text_set(obj, part, label);
2388 }
2389 
2390 EAPI const char*
elm_widget_part_text_get(const Eo * obj,const char * part)2391 elm_widget_part_text_get(const Eo *obj, const char *part)
2392 {
2393    /* legacy support: combobox was special (internal entry is text object). */
2394    if (efl_isa(obj, ELM_COMBOBOX_CLASS))
2395      return _elm_combobox_part_text_get(obj, part);
2396    else if (efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
2397      return elm_layout_text_get(obj, part);
2398 
2399    return NULL;
2400 }
2401 
2402 static Elm_Translate_String_Data *
_translate_string_data_get(Eina_Inlist * translate_strings,const char * part)2403 _translate_string_data_get(Eina_Inlist *translate_strings, const char *part)
2404 {
2405    Elm_Translate_String_Data *ts;
2406    Eina_Stringshare *str;
2407 
2408    if (!translate_strings) return NULL;
2409 
2410    str = eina_stringshare_add(part);
2411    EINA_INLIST_FOREACH(translate_strings, ts)
2412      {
2413         if (ts->id == str) break;
2414      }
2415 
2416    eina_stringshare_del(str);
2417 
2418    return ts;
2419 }
2420 
2421 static Elm_Translate_String_Data *
_part_text_translatable_set(Eina_Inlist ** translate_strings,const char * part,Eina_Bool translatable,Eina_Bool preset)2422 _part_text_translatable_set(Eina_Inlist **translate_strings, const char *part, Eina_Bool translatable, Eina_Bool preset)
2423 {
2424    Eina_Inlist *t;
2425    Elm_Translate_String_Data *ts;
2426    t = *translate_strings;
2427    ts = _translate_string_data_get(t, part);
2428 
2429    if (translatable)
2430      {
2431         if (!ts)
2432           {
2433              ts = ELM_NEW(Elm_Translate_String_Data);
2434              if (!ts) return NULL;
2435 
2436              ts->id = eina_stringshare_add(part);
2437              t = eina_inlist_append(t, (Eina_Inlist*) ts);
2438           }
2439         if (preset) ts->preset = EINA_TRUE;
2440      }
2441    //Delete this exist one if this part has been not preset.
2442    //see elm_widget_part_text_translatable_set()
2443    else if (ts && ((preset) || (!ts->preset)))
2444      {
2445         t = eina_inlist_remove(t, EINA_INLIST_GET(ts));
2446         eina_stringshare_del(ts->id);
2447         eina_stringshare_del(ts->domain);
2448         eina_stringshare_del(ts->string);
2449         ELM_SAFE_FREE(ts, free);
2450      }
2451 
2452    *translate_strings = t;
2453 
2454    return ts;
2455 }
2456 
2457 /* internal */
2458 void
elm_widget_part_translatable_text_set(Eo * obj,const char * part,const char * label,const char * domain)2459 elm_widget_part_translatable_text_set(Eo *obj, const char *part, const char *label, const char *domain)
2460 {
2461    Elm_Translate_String_Data *ts;
2462    Elm_Widget_Smart_Data *sd;
2463 
2464    sd = efl_data_scope_safe_get(obj, MY_CLASS);
2465    if (!sd) return;
2466 
2467    if (!label)
2468      {
2469         _part_text_translatable_set(&sd->translate_strings, part, EINA_FALSE,
2470                                     EINA_FALSE);
2471      }
2472    else
2473      {
2474         ts = _part_text_translatable_set(&sd->translate_strings, part,
2475                                          EINA_TRUE, EINA_FALSE);
2476         if (!ts) return;
2477         if (!ts->string) ts->string = eina_stringshare_add(label);
2478         else eina_stringshare_replace(&ts->string, label);
2479         if (!ts->domain) ts->domain = eina_stringshare_add(domain);
2480         else eina_stringshare_replace(&ts->domain, domain);
2481 #ifdef HAVE_GETTEXT
2482         if (label[0]) label = dgettext(domain, label);
2483 #endif
2484      }
2485 
2486    sd->on_translate = EINA_TRUE;
2487    elm_widget_part_text_set(obj, part, label);
2488    sd->on_translate = EINA_FALSE;
2489 }
2490 
2491 /* legacy only */
2492 EAPI void
elm_widget_domain_part_text_translatable_set(Eo * obj,const char * part,const char * domain,Eina_Bool translatable)2493 elm_widget_domain_part_text_translatable_set(Eo *obj, const char *part, const char *domain, Eina_Bool translatable)
2494 {
2495    Elm_Translate_String_Data *ts;
2496    Elm_Widget_Smart_Data *sd;
2497    const char *text = NULL;
2498 
2499    sd = efl_data_scope_safe_get(obj, MY_CLASS);
2500    if (!sd) return;
2501 
2502    ts = _part_text_translatable_set(&sd->translate_strings, part,
2503                                     translatable, EINA_TRUE);
2504    if (!ts) return;
2505    if (!ts->domain) ts->domain = eina_stringshare_add(domain);
2506    else eina_stringshare_replace(&ts->domain, domain);
2507 
2508    text = elm_widget_part_text_get(obj, part);
2509    if (!text || !text[0]) return;
2510 
2511    if (!ts->string) ts->string = eina_stringshare_add(text);
2512 
2513 //Try to translate text since we don't know the text is already translated.
2514 #ifdef HAVE_GETTEXT
2515    text = dgettext(domain, text);
2516 #endif
2517    sd->on_translate = EINA_TRUE;
2518    elm_widget_part_text_set(obj, part, text);
2519    sd->on_translate = EINA_FALSE;
2520 }
2521 
2522 /* internal */
2523 const char *
elm_widget_part_translatable_text_get(const Eo * obj,const char * part,const char ** domain)2524 elm_widget_part_translatable_text_get(const Eo *obj, const char *part, const char **domain)
2525 {
2526    Elm_Widget_Smart_Data *sd;
2527    Elm_Translate_String_Data *ts;
2528 
2529    if (domain) *domain = NULL;
2530 
2531    sd = efl_data_scope_safe_get(obj, MY_CLASS);
2532    if (!sd) return NULL;
2533 
2534    ts = _translate_string_data_get(sd->translate_strings, part);
2535    if (!ts) return NULL;
2536 
2537    if (domain) *domain = ts->domain;
2538    return ts->string;
2539 }
2540 
2541 EOLIAN static void
_efl_ui_widget_efl_ui_l10n_translation_update(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)2542 _efl_ui_widget_efl_ui_l10n_translation_update(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
2543 {
2544    Evas_Object *child;
2545 
2546    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2547      {
2548         child = eina_array_data_get(sd->children, i);
2549         if (elm_widget_is(child))
2550           efl_ui_l10n_translation_update(child);
2551 
2552      }
2553 
2554    if (sd->hover_obj) efl_ui_l10n_translation_update(sd->hover_obj);
2555 
2556 #ifdef HAVE_GETTEXT
2557    Elm_Translate_String_Data *ts;
2558    EINA_INLIST_FOREACH(sd->translate_strings, ts)
2559      {
2560         if (!ts->string) continue;
2561         const char *s = dgettext(ts->domain, ts->string);
2562         sd->on_translate = EINA_TRUE;
2563         elm_widget_part_text_set(obj, ts->id, s);
2564         sd->on_translate = EINA_FALSE;
2565      }
2566 #endif
2567    efl_event_callback_legacy_call(obj, EFL_UI_WIDGET_EVENT_LANGUAGE_CHANGED, NULL);
2568 }
2569 
2570 EOLIAN static void
_efl_ui_widget_access_info_set(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd,const char * txt)2571 _efl_ui_widget_access_info_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, const char *txt)
2572 {
2573    eina_stringshare_replace(&sd->access_info, txt);
2574 }
2575 
2576 EOLIAN static const char*
_efl_ui_widget_access_info_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)2577 _efl_ui_widget_access_info_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
2578 {
2579    return sd->access_info;
2580 }
2581 
2582 
2583 EAPI void
elm_widget_scroll_hold_push(Efl_Ui_Widget * obj)2584 elm_widget_scroll_hold_push(Efl_Ui_Widget *obj)
2585 {
2586    efl_ui_widget_scroll_hold_push(obj);
2587 }
2588 
2589 EAPI void
elm_widget_scroll_hold_pop(Efl_Ui_Widget * obj)2590 elm_widget_scroll_hold_pop(Efl_Ui_Widget *obj)
2591 {
2592    efl_ui_widget_scroll_hold_pop(obj);
2593 }
2594 
2595 EAPI void
elm_widget_scroll_freeze_push(Efl_Ui_Widget * obj)2596 elm_widget_scroll_freeze_push(Efl_Ui_Widget *obj)
2597 {
2598    efl_ui_widget_scroll_freeze_push(obj);
2599 }
2600 
2601 EAPI void
elm_widget_scroll_freeze_pop(Efl_Ui_Widget * obj)2602 elm_widget_scroll_freeze_pop(Efl_Ui_Widget *obj)
2603 {
2604    efl_ui_widget_scroll_freeze_pop(obj);
2605 }
2606 
2607 
2608 EAPI Elm_Theme *
elm_widget_theme_get(const Evas_Object * obj)2609 elm_widget_theme_get(const Evas_Object *obj)
2610 {
2611    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2612    if (!sd) return NULL;
2613 
2614    if (!sd->theme)
2615      {
2616         if (sd->parent_obj)
2617            return elm_widget_theme_get(sd->parent_obj);
2618         else return NULL;
2619      }
2620    return sd->theme;
2621 }
2622 
2623 EOLIAN static Eina_Error
_efl_ui_widget_style_set(Eo * obj,Elm_Widget_Smart_Data * sd,const char * style)2624 _efl_ui_widget_style_set(Eo *obj, Elm_Widget_Smart_Data *sd, const char *style)
2625 {
2626    if (!elm_widget_is_legacy(obj) && efl_finalized_get(obj))
2627      {
2628         ERR("Efl.Ui.Widget.style can only be set before finalize!");
2629         return EFL_UI_THEME_APPLY_ERROR_GENERIC;
2630      }
2631 
2632    if (eina_stringshare_replace(&sd->style, style))
2633       return elm_widget_theme(obj);
2634 
2635    return EFL_UI_THEME_APPLY_ERROR_NONE;
2636 }
2637 
2638 EOLIAN static const char*
_efl_ui_widget_style_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)2639 _efl_ui_widget_style_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
2640 {
2641    const char *ret;
2642    ret = "default";
2643    if (sd->style) ret = sd->style;
2644 
2645    return ret;
2646 }
2647 
2648 EAPI void
elm_widget_tooltip_add(Eo * obj,Elm_Tooltip * tt)2649 elm_widget_tooltip_add(Eo *obj, Elm_Tooltip *tt)
2650 {
2651    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2652    if (!sd) return;
2653 
2654    sd->tooltips = eina_list_append(sd->tooltips, tt);
2655 }
2656 
2657 EAPI void
elm_widget_tooltip_del(Eo * obj,Elm_Tooltip * tt)2658 elm_widget_tooltip_del(Eo *obj, Elm_Tooltip *tt)
2659 {
2660    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2661    if (!sd) return;
2662 
2663    sd->tooltips = eina_list_remove(sd->tooltips, tt);
2664 }
2665 
2666 EAPI void
elm_widget_cursor_add(Eo * obj,Elm_Cursor * cur)2667 elm_widget_cursor_add(Eo *obj, Elm_Cursor *cur)
2668 {
2669    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2670    if (!sd) return;
2671 
2672    sd->cursors = eina_list_append(sd->cursors, cur);
2673 }
2674 
2675 EAPI void
elm_widget_cursor_del(Eo * obj,Elm_Cursor * cur)2676 elm_widget_cursor_del(Eo *obj, Elm_Cursor *cur)
2677 {
2678    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2679    if (!sd) return;
2680 
2681    sd->cursors = eina_list_remove(sd->cursors, cur);
2682 }
2683 
2684 EAPI void
elm_widget_scroll_lock_set(Eo * obj,Efl_Ui_Layout_Orientation block)2685 elm_widget_scroll_lock_set(Eo *obj, Efl_Ui_Layout_Orientation block)
2686 {
2687    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2688    Eina_Bool lx, ly;
2689 
2690    if (!sd) return;
2691    lx = !!(block & EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
2692    ly = !!(block & EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
2693    if (sd->scroll_x_locked != lx)
2694      {
2695         sd->scroll_x_locked = lx;
2696         _propagate_x_drag_lock(obj, lx ? 1 : -1);
2697      }
2698    if (sd->scroll_y_locked != ly)
2699      {
2700         sd->scroll_y_locked = ly;
2701         _propagate_y_drag_lock(obj, ly ? 1 : -1);
2702      }
2703 }
2704 
2705 EAPI Efl_Ui_Layout_Orientation
elm_widget_scroll_lock_get(const Eo * obj)2706 elm_widget_scroll_lock_get(const Eo *obj)
2707 {
2708    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2709    Efl_Ui_Layout_Orientation block = EFL_UI_LAYOUT_ORIENTATION_DEFAULT;
2710 
2711    if (!sd) return block;
2712    if (sd->scroll_x_locked) block |= EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL;
2713    if (sd->scroll_y_locked) block |= EFL_UI_LAYOUT_ORIENTATION_VERTICAL;
2714 
2715    return block;
2716 }
2717 
2718 EAPI int
elm_widget_scroll_child_locked_x_get(const Eo * obj)2719 elm_widget_scroll_child_locked_x_get(const Eo *obj)
2720 {
2721    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2722    if (!sd) return EINA_FALSE;
2723    return sd->child_drag_x_locked;
2724 }
2725 
2726 EAPI int
elm_widget_scroll_child_locked_y_get(const Eo * obj)2727 elm_widget_scroll_child_locked_y_get(const Eo *obj)
2728 {
2729    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2730    if (!sd) return EINA_FALSE;
2731    return sd->child_drag_y_locked;
2732 }
2733 
2734 EAPI Eina_Error
elm_widget_theme_object_set(Evas_Object * obj,Evas_Object * edj,const char * wname,const char * welement,const char * wstyle)2735 elm_widget_theme_object_set(Evas_Object *obj, Evas_Object *edj, const char *wname, const char *welement, const char *wstyle)
2736 {
2737    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(obj, MY_CLASS);
2738    if (!sd) return EFL_UI_THEME_APPLY_ERROR_GENERIC;
2739 
2740    if (eina_streq(welement, "base"))
2741      welement = NULL;
2742    if (eina_streq(wstyle, "default"))
2743      wstyle = NULL;
2744    return _elm_theme_object_set(obj, edj, wname, welement, wstyle);
2745 }
2746 
2747 static void
_convert(Efl_Dbg_Info * info,Eina_Iterator * ptr_list)2748 _convert(Efl_Dbg_Info *info, Eina_Iterator *ptr_list)
2749 {
2750    void *p;
2751    int i = 0;
2752 
2753    EINA_ITERATOR_FOREACH(ptr_list, p)
2754      {
2755         char name[100];
2756 
2757         snprintf(name, sizeof(name), "Candidate %d", i);
2758 
2759         EFL_DBG_INFO_APPEND(info, name, EINA_VALUE_TYPE_UINT64, p);
2760         i++;
2761      }
2762 
2763    eina_iterator_free(ptr_list);
2764 }
2765 
2766 EOLIAN static void
_efl_ui_widget_efl_object_dbg_info_get(Eo * eo_obj,Elm_Widget_Smart_Data * _pd EINA_UNUSED,Efl_Dbg_Info * root)2767 _efl_ui_widget_efl_object_dbg_info_get(Eo *eo_obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Efl_Dbg_Info *root)
2768 {
2769    efl_dbg_info_get(efl_super(eo_obj, MY_CLASS), root);
2770    Efl_Ui_Focus_Relations *rel = NULL;
2771    Efl_Dbg_Info *focus, *group = EFL_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME);
2772 
2773    EFL_DBG_INFO_APPEND(group, "Wid-Type", EINA_VALUE_TYPE_STRING, elm_widget_type_get(eo_obj));
2774    EFL_DBG_INFO_APPEND(group, "Style", EINA_VALUE_TYPE_STRING, elm_widget_style_get(eo_obj));
2775    EFL_DBG_INFO_APPEND(group, "Layer", EINA_VALUE_TYPE_INT,
2776          (int) evas_object_layer_get(eo_obj));
2777    EFL_DBG_INFO_APPEND(group, "Scale", EINA_VALUE_TYPE_DOUBLE,
2778          evas_object_scale_get(eo_obj));
2779    EFL_DBG_INFO_APPEND(group, "Has focus", EINA_VALUE_TYPE_CHAR,
2780          elm_object_focus_get(eo_obj));
2781    EFL_DBG_INFO_APPEND(group, "Can focus", EINA_VALUE_TYPE_CHAR,
2782          elm_widget_can_focus_get(eo_obj));
2783    EFL_DBG_INFO_APPEND(group, "Disabled", EINA_VALUE_TYPE_CHAR,
2784          elm_widget_disabled_get(eo_obj));
2785    EFL_DBG_INFO_APPEND(group, "Mirrored", EINA_VALUE_TYPE_CHAR,
2786          efl_ui_mirrored_get(eo_obj));
2787    EFL_DBG_INFO_APPEND(group, "Tree Unfocusable", EINA_VALUE_TYPE_CHAR,
2788          elm_widget_tree_unfocusable_get(eo_obj));
2789    EFL_DBG_INFO_APPEND(group, "Automatic mirroring", EINA_VALUE_TYPE_CHAR,
2790          efl_ui_mirrored_automatic_get(eo_obj));
2791 
2792    rel = efl_ui_focus_manager_fetch(_pd->focus.manager, eo_obj);
2793    if (rel)
2794      {
2795         focus = EFL_DBG_INFO_LIST_APPEND(group, "Focus");
2796 
2797         EFL_DBG_INFO_APPEND(focus, "logical", EINA_VALUE_TYPE_CHAR, rel->logical );
2798         EFL_DBG_INFO_APPEND(focus, "manager", EINA_VALUE_TYPE_UINT64, _pd->focus.manager);
2799         EFL_DBG_INFO_APPEND(focus, "parent", EINA_VALUE_TYPE_UINT64, rel->parent);
2800         EFL_DBG_INFO_APPEND(focus, "next", EINA_VALUE_TYPE_UINT64 , rel->next);
2801         EFL_DBG_INFO_APPEND(focus, "prev", EINA_VALUE_TYPE_UINT64 , rel->prev);
2802 
2803         EFL_DBG_INFO_APPEND(focus, "redirect", EINA_VALUE_TYPE_UINT64 , rel->redirect);
2804 
2805 #define ADD_PTR_LIST(name) \
2806         Efl_Dbg_Info* name = EFL_DBG_INFO_LIST_APPEND(focus, ""#name""); \
2807         _convert(name, rel->name);
2808 
2809         ADD_PTR_LIST(top)
2810         ADD_PTR_LIST(down)
2811         ADD_PTR_LIST(right)
2812         ADD_PTR_LIST(left)
2813 
2814 #undef ADD_PTR_LIST
2815 
2816      }
2817 
2818    //if that's a focus manager, give useful information like the border elements
2819    if (efl_isa(eo_obj, EFL_UI_FOCUS_MANAGER_INTERFACE))
2820      {
2821         Efl_Dbg_Info *border;
2822 
2823         focus = EFL_DBG_INFO_LIST_APPEND(group, "Focus Manager");
2824         border = EFL_DBG_INFO_LIST_APPEND(focus, "Border Elements");
2825 
2826         _convert(border,
2827           efl_ui_focus_manager_border_elements_get(eo_obj)
2828         );
2829 
2830         EFL_DBG_INFO_APPEND(focus, "redirect", EINA_VALUE_TYPE_UINT64,
2831           efl_ui_focus_manager_redirect_get(eo_obj));
2832      }
2833 }
2834 
2835 EAPI Eina_Bool
elm_widget_is_check(const Evas_Object * obj)2836 elm_widget_is_check(const Evas_Object *obj)
2837 {
2838    static int abort_on_warn = -1;
2839    if (elm_widget_is(obj))
2840      return EINA_TRUE;
2841 
2842    ERR("Passing Object: %p.", obj);
2843    if (abort_on_warn == -1)
2844      {
2845         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2846         else abort_on_warn = 0;
2847      }
2848    if (abort_on_warn == 1) abort();
2849    return EINA_FALSE;
2850 }
2851 
2852 /* If you changed a legacy widget's class name,
2853  * please update the "legacy_type_table". */
2854 EAPI const char *
elm_widget_type_get(const Evas_Object * obj)2855 elm_widget_type_get(const Evas_Object *obj)
2856 {
2857    const char *ret;
2858    int i;
2859 
2860    API_ENTRY return NULL;
2861 
2862    ret = efl_class_name_get(efl_class_get(obj));
2863 
2864    /* If the given widget is created for legacy,
2865     * convert type name to legacy. */
2866    if (elm_widget_is_legacy(obj))
2867      {
2868         for (i = 0; legacy_type_table[i][0] ; i++)
2869           {
2870              if (eina_streq(ret, legacy_type_table[i][0]))
2871                return legacy_type_table[i][1];
2872           }
2873      }
2874 
2875    return ret;
2876 }
2877 
2878 EAPI Eina_Bool
elm_widget_type_check(const Evas_Object * obj,const char * type,const char * func)2879 elm_widget_type_check(const Evas_Object *obj,
2880                       const char *type,
2881                       const char *func)
2882 {
2883    const char *provided, *expected = "(unknown)";
2884    static int abort_on_warn = -1;
2885 
2886    provided = elm_widget_type_get(obj);
2887    /* TODO: eventually migrate to check_ptr version */
2888    if (evas_object_smart_type_check(obj, type)) return EINA_TRUE;
2889    if (type) expected = type;
2890    if ((!provided) || (!provided[0]))
2891      {
2892         provided = evas_object_type_get(obj);
2893         if ((!provided) || (!provided[0]))
2894           provided = "(unknown)";
2895      }
2896    ERR("Passing Object: %p in function: %s, of type: '%s' when expecting"
2897        " type: '%s'", obj, func, provided, expected);
2898    if (abort_on_warn == -1)
2899      {
2900         if (getenv("ELM_ERROR_ABORT")) abort_on_warn = 1;
2901         else abort_on_warn = 0;
2902      }
2903    if (abort_on_warn == 1) abort();
2904    return EINA_FALSE;
2905 }
2906 
2907 /** @internal */
2908 EAPI Evas_Object *
elm_widget_name_find(const Eo * obj,const char * name,int recurse)2909 elm_widget_name_find(const Eo *obj, const char *name, int recurse)
2910 {
2911    Evas_Object *child;
2912    const char *s;
2913    INTERNAL_ENTRY NULL;
2914 
2915    if (!name) return NULL;
2916    if (!_elm_widget_is(obj)) return NULL;
2917 
2918    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
2919      {
2920         child = eina_array_data_get(sd->children, i);
2921         s = evas_object_name_get(child);
2922         if ((s) && (!strcmp(s, name))) return child;
2923         if ((recurse != 0) &&
2924             ((child = elm_widget_name_find(child, name, recurse - 1))))
2925           return child;
2926      }
2927    if (sd->hover_obj)
2928      {
2929         s = evas_object_name_get(sd->hover_obj);
2930         if ((s) && (!strcmp(s, name))) return sd->hover_obj;
2931         if ((recurse != 0) &&
2932             ((child = elm_widget_name_find(sd->hover_obj, name, recurse - 1))))
2933           return child;
2934      }
2935    return NULL;
2936 }
2937 
2938 /**
2939  * @internal
2940  *
2941  * Split string in words
2942  *
2943  * @param str Source string
2944  * @return List of const words
2945  *
2946  * @see elm_widget_stringlist_free()
2947  * @ingroup Widget
2948  */
2949 EAPI Eina_List *
elm_widget_stringlist_get(const char * str)2950 elm_widget_stringlist_get(const char *str)
2951 {
2952    Eina_List *list = NULL;
2953    const char *s, *b;
2954    if (!str) return NULL;
2955    for (b = s = str; 1; s++)
2956      {
2957         if ((*s == ' ') || (!*s))
2958           {
2959              char *t = malloc(s - b + 1);
2960              if (t)
2961                {
2962                   strncpy(t, b, s - b);
2963                   t[s - b] = 0;
2964                   list = eina_list_append(list, eina_stringshare_add(t));
2965                   free(t);
2966                }
2967              b = s + 1;
2968           }
2969         if (!*s) break;
2970      }
2971    return list;
2972 }
2973 
2974 EAPI void
elm_widget_stringlist_free(Eina_List * list)2975 elm_widget_stringlist_free(Eina_List *list)
2976 {
2977    const char *s;
2978    EINA_LIST_FREE(list, s)
2979      eina_stringshare_del(s);
2980 }
2981 
2982 /* internal */
2983 EAPI void
elm_widget_focus_mouse_up_handle(Eo * obj)2984 elm_widget_focus_mouse_up_handle(Eo *obj)
2985 {
2986    Elm_Widget_Smart_Data *pd = efl_data_scope_get(obj, MY_CLASS);
2987 
2988    if (!_is_focusable(obj)) return;
2989 
2990    if (pd->focus.manager && !pd->focus.logical)
2991      {
2992         efl_ui_focus_util_focus(obj);
2993      }
2994 }
2995 
2996 /*
2997  * @internal
2998  *
2999  * Get the focus highlight geometry of a widget.
3000  *
3001  * @param obj Widget object for the focus highlight
3002  * @param x Focus highlight x coordinate
3003  * @param y Focus highlight y coordinate
3004  * @param w Focus highlight object width
3005  * @param h Focus highlight object height
3006  * @param is_next @c EINA_TRUE if this request is for the new focused object,
3007  * @c EINA_FALSE if this request is for the previously focused object. This
3008  * information becomes important when the focus highlight is changed inside one
3009  * widget.
3010  *
3011  * @ingroup Widget
3012  */
3013 /*
3014  * @internal
3015  *
3016  * Get the 'focus_part' geometry if there is any
3017  *
3018  * This queries if there is a 'focus_part' request from the edc style. If edc
3019  * style offers 'focus_part' edje data item, this function requests for the
3020  * geometry of a specific part which is described in 'focus_part' edje data.
3021  *
3022  * @param obj Widget object for the focus highlight
3023  * @param x Focus highlight x coordinate
3024  * @param y Focus highlight y coordinate
3025  * @param w Focus highlight object width
3026  * @param h Focus highlight object height
3027  *
3028  * x, y, w, h already contain the object's geometry. If there is a 'focus_part'
3029  * support, these values will be updated accordingly or the values will be
3030  * remained as they were.
3031  *
3032  * @ingroup Widget
3033  */
3034 EAPI void
elm_widget_focus_highlight_focus_part_geometry_get(const Evas_Object * obj,Evas_Coord * x,Evas_Coord * y,Evas_Coord * w,Evas_Coord * h)3035 elm_widget_focus_highlight_focus_part_geometry_get(const Evas_Object *obj,
3036                                                    Evas_Coord *x,
3037                                                    Evas_Coord *y,
3038                                                    Evas_Coord *w,
3039                                                    Evas_Coord *h)
3040 {
3041    Evas_Coord tx = 0, ty = 0, tw = 0, th = 0;
3042    const char *target_hl_part = NULL;
3043    const Evas_Object *edje_obj = NULL;
3044 
3045    if (obj && efl_isa(obj, EFL_CANVAS_LAYOUT_CLASS))
3046      {
3047         edje_obj = obj;
3048         if (!(target_hl_part = edje_object_data_get(edje_obj, "focus_part")))
3049           return;
3050      }
3051    else if (obj && efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
3052      {
3053         edje_obj = elm_layout_edje_get(obj);
3054         if (!(target_hl_part = elm_layout_data_get(obj, "focus_part")))
3055           return;
3056      }
3057    else
3058      return;
3059 
3060   edje_object_part_geometry_get(edje_obj, target_hl_part,
3061                                 &tx, &ty, &tw, &th);
3062   *x += tx;
3063   *y += ty;
3064   if (tw != *w) *w = tw;
3065   if (th != *h) *h = th;
3066 }
3067 
3068 EOLIAN static Eina_Rect
_efl_ui_widget_focus_highlight_geometry_get(const Eo * obj,Elm_Widget_Smart_Data * sd)3069 _efl_ui_widget_focus_highlight_geometry_get(const Eo *obj, Elm_Widget_Smart_Data *sd)
3070 {
3071    Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
3072    Evas_Object *scroller = (Evas_Object *)obj;
3073    Eina_Rect r = {};
3074 
3075    evas_object_geometry_get(obj, &r.x, &r.y, &r.w, &r.h);
3076    elm_widget_focus_highlight_focus_part_geometry_get(sd->resize_obj, &r.x, &r.y, &r.w, &r.h);
3077 
3078    if (_elm_config->focus_autoscroll_mode != ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN)
3079      return r;
3080 
3081    while (scroller)
3082      {
3083         if (_elm_scrollable_is(scroller))
3084           {
3085              elm_interface_scrollable_content_viewport_geometry_get(scroller, &ox, &oy, &ow, &oh);
3086 
3087              if (r.y < oy)
3088                r.y = oy;
3089              else if ((oy + oh) < (r.y + r.h))
3090                r.y = (oy + oh - r.h);
3091              else if (r.x < ox)
3092                r.x = ox;
3093              else if ((ox + ow) < (r.x + r.w))
3094                r.x = (ox + ow - r.w);
3095 
3096              break;
3097           }
3098         scroller = elm_widget_parent_get(scroller);
3099      }
3100 
3101    return r;
3102 }
3103 
3104 EAPI void
elm_widget_activate(Evas_Object * obj,Efl_Ui_Activate act)3105 elm_widget_activate(Evas_Object *obj, Efl_Ui_Activate act)
3106 {
3107    Evas_Object *parent;
3108    Eina_Bool ret;
3109 
3110    ELM_WIDGET_CHECK(obj);
3111 
3112    ret = EINA_FALSE;
3113 
3114    ret = efl_ui_widget_on_access_activate(obj, act);
3115 
3116    if (ret) return;
3117 
3118    parent = elm_widget_parent_get(obj);
3119    if (parent)
3120      elm_widget_activate(parent, act);
3121 
3122    return;
3123 }
3124 
3125 /**
3126  * @internal
3127  *
3128  * Sets the widget and child widget's Evas_Display_Mode.
3129  *
3130  * @param obj The widget.
3131  * @param dispmode Evas_Display_Mode to set widget's mode.
3132  *
3133  * Widgets are resized by several reasons.
3134  * Evas_Display_Mode can help for widgets to get one more reason of resize.
3135  * For example, elm conform widget resizes it's contents when keypad state changed.
3136  * After keypad showing, conform widget can change child's Evas_Display_Mode.
3137  * @ingroup Widget
3138  */
3139 /* Legacy only */
3140 EAPI void
elm_widget_display_mode_set(Evas_Object * obj,Evas_Display_Mode dispmode)3141 elm_widget_display_mode_set(Evas_Object *obj, Evas_Display_Mode dispmode)
3142 {
3143    Evas_Display_Mode prev_dispmode;
3144    Evas_Object *child;
3145 
3146    API_ENTRY return;
3147    prev_dispmode = evas_object_size_hint_display_mode_get(obj);
3148 
3149    if ((prev_dispmode == dispmode) ||
3150        (prev_dispmode == EVAS_DISPLAY_MODE_DONT_CHANGE)) return;
3151 
3152    evas_object_size_hint_display_mode_set(obj, dispmode);
3153 
3154    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
3155      {
3156         child = eina_array_data_get(sd->children, i);
3157         if (elm_widget_is(child))
3158           elm_widget_display_mode_set(child, dispmode);
3159      }
3160 }
3161 
3162 /**
3163  * @internal
3164  *
3165  * Returns the widget's focus move policy.
3166  *
3167  * @param obj The widget.
3168  * @return focus move policy of the object.
3169  *
3170  **/
3171 EOLIAN static Efl_Ui_Focus_Move_Policy
_efl_ui_widget_focus_move_policy_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)3172 _efl_ui_widget_focus_move_policy_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3173 {
3174    return (Efl_Ui_Focus_Move_Policy)sd->focus_move_policy;
3175 }
3176 
3177 /**
3178  * @internal
3179  *
3180  * Sets the widget's focus move policy.
3181  *
3182  * @param obj The widget.
3183  * @param policy Elm_Focus_Move_Policy to set object's focus move policy.
3184  */
3185 
3186 EOLIAN static void
_efl_ui_widget_focus_move_policy_set(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd,Efl_Ui_Focus_Move_Policy policy)3187 _efl_ui_widget_focus_move_policy_set(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd, Efl_Ui_Focus_Move_Policy policy)
3188 {
3189    if (sd->focus_move_policy == (Elm_Focus_Move_Policy)policy) return;
3190    sd->focus_move_policy = (Elm_Focus_Move_Policy)policy;
3191 }
3192 
3193 /**
3194  * Returns the widget's focus_move_policy mode setting.
3195  *
3196  * @param obj The widget.
3197  * @return focus_move_policy mode setting of the object.
3198  *
3199  **/
3200 EOLIAN static Eina_Bool
_efl_ui_widget_focus_move_policy_automatic_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * sd)3201 _efl_ui_widget_focus_move_policy_automatic_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *sd)
3202 {
3203    return sd->focus_move_policy_auto_mode;
3204 }
3205 
3206 /**
3207  * @internal
3208  *
3209  * Sets the widget's focus_move_policy mode setting.
3210  * When widget in automatic mode, it follows the system focus_move_policy mode set by
3211  * elm_config_focus_move_policy_set().
3212  * @param obj The widget.
3213  * @param automatic EINA_TRUE for auto focus_move_policy mode. EINA_FALSE for manual.
3214  */
3215 EOLIAN static void
_efl_ui_widget_focus_move_policy_automatic_set(Eo * obj,Elm_Widget_Smart_Data * sd,Eina_Bool automatic)3216 _efl_ui_widget_focus_move_policy_automatic_set(Eo *obj, Elm_Widget_Smart_Data *sd, Eina_Bool automatic)
3217 {
3218    if (sd->focus_move_policy_auto_mode != automatic)
3219      {
3220         sd->focus_move_policy_auto_mode = automatic;
3221 
3222         if (automatic)
3223           {
3224              efl_ui_widget_focus_move_policy_set
3225                (obj, (Efl_Ui_Focus_Move_Policy)elm_config_focus_move_policy_get());
3226           }
3227      }
3228 }
3229 
3230 /**
3231  * @internal
3232  *
3233  * Sets the klass name of a widget.
3234  * @param obj The widget.
3235  * @param name Name of the klass to use.
3236  * @return Whether the name was different and thus replaced.
3237  */
3238 EAPI Eina_Bool
elm_widget_theme_klass_set(Evas_Object * obj,const char * name)3239 elm_widget_theme_klass_set(Evas_Object *obj, const char *name)
3240 {
3241    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
3242    if (!pd) return EINA_FALSE;
3243 
3244    return eina_stringshare_replace(&(pd->klass), name);
3245 }
3246 
3247 /**
3248  * @internal
3249  *
3250  * Gets the klass name of a widget.
3251  * @param obj The widget.
3252  * @return The current klass name of internal canvas object.
3253  */
3254 EAPI const char *
elm_widget_theme_klass_get(const Evas_Object * obj)3255 elm_widget_theme_klass_get(const Evas_Object *obj)
3256 {
3257    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
3258    if (!pd) return NULL;
3259 
3260    return (const char *)pd->klass;
3261 }
3262 
3263 /**
3264  * @internal
3265  *
3266  * Sets the element name of a widget.
3267  *
3268  * @param obj The widget.
3269  * @param name Name of the element to use.
3270  * @return Whether the name was different and thus replaced.
3271  */
3272 EAPI Eina_Bool
elm_widget_theme_element_set(Evas_Object * obj,const char * name)3273 elm_widget_theme_element_set(Evas_Object *obj, const char *name)
3274 {
3275    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
3276    if (!pd) return EINA_FALSE;
3277 
3278    if (eina_streq(name, "base"))
3279      name = NULL;
3280 
3281    return eina_stringshare_replace(&(pd->group), name);
3282 }
3283 
3284 /**
3285  * @internal
3286  *
3287  * Gets the element name of a widget.
3288  * @param obj The widget.
3289  * @return The current element name of internal canvas object.
3290  */
3291 EAPI const char *
elm_widget_theme_element_get(const Evas_Object * obj)3292 elm_widget_theme_element_get(const Evas_Object *obj)
3293 {
3294    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
3295    if (!pd) return NULL;
3296 
3297    return (const char *)pd->group;
3298 }
3299 
3300 /**
3301  * @internal
3302  *
3303  * Sets the style name of a widget.
3304  *
3305  * @param obj The widget.
3306  * @param name Name of the style to use.
3307  * @return Whether the name was different and thus replaced.
3308  */
3309 EAPI Eina_Bool
elm_widget_theme_style_set(Evas_Object * obj,const char * name)3310 elm_widget_theme_style_set(Evas_Object *obj, const char *name)
3311 {
3312    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
3313    if (!pd) return EINA_FALSE;
3314 
3315    if (eina_streq(name, "default"))
3316      name = NULL;
3317 
3318    return eina_stringshare_replace(&(pd->style), name);
3319 }
3320 
3321 /**
3322  * @internal
3323  *
3324  * Gets the style name of a widget.
3325  * @param obj The widget.
3326  * @return The current style name of internal canvas object.
3327  */
3328 EAPI const char *
elm_widget_theme_style_get(const Evas_Object * obj)3329 elm_widget_theme_style_get(const Evas_Object *obj)
3330 {
3331    Elm_Widget_Smart_Data *pd = efl_data_scope_safe_get(obj, MY_CLASS);
3332    if (!pd) return NULL;
3333 
3334    return (const char *)pd->style;
3335 }
3336 
3337 /**
3338  * @internal
3339  *
3340  * Register sub object as a group of a widget and re-apply its theme.
3341  * @param obj The widget.
3342  * @param component A sub object to be added as an element of the widget.
3343  * @param name An element name of sub object.
3344  * @return Whether the style was successfully applied or not.
3345  */
3346 EAPI Eina_Error
elm_widget_element_update(Evas_Object * obj,Evas_Object * component,const char * name)3347 elm_widget_element_update(Evas_Object *obj, Evas_Object *component, const char *name)
3348 {
3349    Eina_Error ret = EFL_UI_THEME_APPLY_ERROR_NONE;
3350    Eina_Bool changed = EINA_FALSE;
3351    const char *obj_group;
3352    Eina_Stringshare *group;
3353 
3354    obj_group = elm_widget_theme_element_get(obj);
3355    if (!obj_group)
3356      group = eina_stringshare_add(name);
3357    else
3358      group = eina_stringshare_printf("%s/%s", elm_widget_theme_element_get(obj), name);
3359    if (efl_isa(component, EFL_UI_WIDGET_CLASS))
3360      {
3361         changed |= elm_widget_theme_klass_set(component, elm_widget_theme_klass_get(obj));
3362         changed |= elm_widget_theme_element_set(component, (const char *)group);
3363         changed |= elm_widget_theme_style_set(component, elm_widget_theme_style_get(obj));
3364         if (changed)
3365           ret = efl_ui_widget_theme_apply(component);
3366      }
3367    else
3368      {
3369         ret = elm_widget_theme_object_set(obj, component,
3370                                    elm_widget_theme_klass_get(obj),
3371                                    (const char *)group,
3372                                    elm_widget_theme_style_get(obj));
3373      }
3374    eina_stringshare_del(group);
3375 
3376    return ret;
3377 }
3378 
3379 static void
3380 _track_obj_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
3381 
3382 static void
_track_obj_update(Evas_Object * track,Evas_Object * obj)3383 _track_obj_update(Evas_Object *track, Evas_Object *obj)
3384 {
3385    //Geometry
3386    Evas_Coord x, y, w, h;
3387    evas_object_geometry_get(obj, &x, &y, &w, &h);
3388    evas_object_geometry_set(track, x, y, w, h);
3389 
3390    //Visibility
3391    if (evas_object_visible_get(obj)) evas_object_show(track);
3392    else evas_object_hide(track);
3393 }
3394 
3395 static void
_track_obj_view_update(void * data,const Efl_Event * event)3396 _track_obj_view_update(void *data, const Efl_Event *event)
3397 {
3398    Elm_Widget_Item_Data *item = data;
3399    _track_obj_update(item->track_obj, event->object);
3400 }
3401 
3402 static void
3403 _track_obj_view_del(void *data, const Efl_Event *event);
3404 
3405 EFL_CALLBACKS_ARRAY_DEFINE(tracker_callbacks,
3406                           { EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _track_obj_view_update },
3407                           { EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _track_obj_view_update },
3408                           { EFL_GFX_ENTITY_EVENT_VISIBILITY_CHANGED, _track_obj_view_update },
3409                           { EFL_EVENT_DEL, _track_obj_view_del });
3410 
3411 static void
_track_obj_view_del(void * data,const Efl_Event * event EINA_UNUSED)3412 _track_obj_view_del(void *data, const Efl_Event *event EINA_UNUSED)
3413 {
3414    Elm_Widget_Item_Data *item = data;
3415 
3416    while (evas_object_ref_get(item->track_obj) > 0)
3417      evas_object_unref(item->track_obj);
3418 
3419    evas_object_event_callback_del(item->track_obj, EVAS_CALLBACK_DEL,
3420                                   _track_obj_del);
3421    evas_object_del(item->track_obj);
3422    item->track_obj = NULL;
3423 }
3424 
3425 static void
_track_obj_del(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)3426 _track_obj_del(void *data, Evas *e EINA_UNUSED,
3427                     Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
3428 {
3429    Elm_Widget_Item_Data *item = data;
3430    item->track_obj = NULL;
3431 
3432    if (!item->view) return;
3433 
3434    efl_event_callback_array_del(item->view, tracker_callbacks(), item);
3435 }
3436 
3437 static void
_elm_widget_item_signal_cb(void * data,Evas_Object * obj EINA_UNUSED,const char * emission,const char * source)3438 _elm_widget_item_signal_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission,
3439                            const char *source)
3440 {
3441    Elm_Widget_Item_Signal_Data *wisd = data;
3442    wisd->func(wisd->data, wisd->item, emission, source);
3443 }
3444 
3445 static void *
_elm_widget_item_signal_callback_list_get(Elm_Widget_Item_Data * item,Eina_List * position)3446 _elm_widget_item_signal_callback_list_get(Elm_Widget_Item_Data *item, Eina_List *position)
3447 {
3448    Elm_Widget_Item_Signal_Data *wisd = eina_list_data_get(position);
3449    void *data;
3450 
3451    item->signals = eina_list_remove_list(item->signals, position);
3452    data = wisd->data;
3453 
3454    if (_elm_widget_is(item->view))
3455      elm_object_signal_callback_del(item->view,
3456                                     wisd->emission, wisd->source,
3457                                     _elm_widget_item_signal_cb);
3458    else if (efl_isa(item->view, EFL_CANVAS_LAYOUT_CLASS))
3459      edje_object_signal_callback_del_full(item->view,
3460                                           wisd->emission, wisd->source,
3461                                           _elm_widget_item_signal_cb, wisd);
3462 
3463    eina_stringshare_del(wisd->emission);
3464    eina_stringshare_del(wisd->source);
3465    free(wisd);
3466 
3467    return data;
3468 }
3469 
3470 #define ERR_NOT_SUPPORTED(item, method)  ERR("%s does not support %s API.", elm_widget_type_get(item->widget), method);
3471 
3472 static void
_efl_del_cb(void * data EINA_UNUSED,const Efl_Event * event)3473 _efl_del_cb(void *data EINA_UNUSED, const Efl_Event *event)
3474 {
3475    Elm_Widget_Item_Data *item = efl_data_scope_get(event->object, ELM_WIDGET_ITEM_CLASS);
3476    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3477    if (item->del_func)
3478       item->del_func((void *) WIDGET_ITEM_DATA_GET(event->object), item->widget, item->eo_obj);
3479 }
3480 
3481 /**
3482  * @internal
3483  *
3484  * Allocate a new Elm_Widget_Item-derived structure.
3485  *
3486  * The goal of this structure is to provide common ground for actions
3487  * that a widget item have, such as the owner widget, callback to
3488  * notify deletion, data pointer and maybe more.
3489  *
3490  * @param widget the owner widget that holds this item, must be an elm_widget!
3491  * @param alloc_size any number greater than sizeof(Elm_Widget_Item) that will
3492  *        be used to allocate memory.
3493  *
3494  * @return allocated memory that is already zeroed out, or NULL on errors.
3495  *
3496  * @see elm_widget_item_new() convenience macro.
3497  * @see elm_widget_item_del() to release memory.
3498  * @ingroup Widget
3499  */
3500 EOLIAN static Eo *
_elm_widget_item_efl_object_constructor(Eo * eo_item,Elm_Widget_Item_Data * item)3501 _elm_widget_item_efl_object_constructor(Eo *eo_item, Elm_Widget_Item_Data *item)
3502 {
3503    Evas_Object *widget;
3504    widget = efl_parent_get(eo_item);
3505 
3506    if (!_elm_widget_is(widget))
3507      {
3508         ERR("Failed");
3509         return NULL;
3510      }
3511 
3512    eo_item = efl_constructor(efl_super(eo_item, ELM_WIDGET_ITEM_CLASS));
3513 
3514    EINA_MAGIC_SET(item, ELM_WIDGET_ITEM_MAGIC);
3515 
3516    item->widget = widget;
3517    item->eo_obj = eo_item;
3518    efl_event_callback_add(eo_item, EFL_EVENT_DEL, _efl_del_cb, NULL);
3519 
3520    return eo_item;
3521 }
3522 
3523 EOLIAN static void
_elm_widget_item_efl_object_destructor(Eo * eo_item,Elm_Widget_Item_Data * item)3524 _elm_widget_item_efl_object_destructor(Eo *eo_item, Elm_Widget_Item_Data *item)
3525 {
3526    Elm_Translate_String_Data *ts;
3527 
3528    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3529 
3530    eina_stringshare_del(item->style);
3531    eina_stringshare_del(item->access_info);
3532    eina_stringshare_del(item->accessible_name);
3533 
3534    while (item->signals)
3535      _elm_widget_item_signal_callback_list_get(item, item->signals);
3536 
3537    while (item->translate_strings)
3538      {
3539         ts = EINA_INLIST_CONTAINER_GET(item->translate_strings,
3540                                        Elm_Translate_String_Data);
3541         eina_stringshare_del(ts->id);
3542         eina_stringshare_del(ts->domain);
3543         eina_stringshare_del(ts->string);
3544         item->translate_strings = eina_inlist_remove(item->translate_strings,
3545                                                      item->translate_strings);
3546         free(ts);
3547      }
3548    eina_hash_free(item->labels);
3549 
3550    efl_access_object_attributes_clear(eo_item);
3551    efl_access_removed(eo_item);
3552 
3553    EINA_MAGIC_SET(item, EINA_MAGIC_NONE);
3554 
3555    efl_destructor(efl_super(eo_item, ELM_WIDGET_ITEM_CLASS));
3556 }
3557 
3558 /**
3559  * @internal
3560  *
3561  * Releases widget item memory, calling back item_del_pre_hook() and
3562  * item_del_cb() if they exist.
3563  *
3564  * @param item a valid #Elm_Widget_Item to be deleted.
3565  *
3566  * If there is an Elm_Widget_Item::del_cb, then it will be called prior
3567  * to memory release. Note that elm_widget_item_pre_notify_del() calls
3568  * this function and then unset it, thus being useful for 2 step
3569  * cleanup whenever the del_cb may use any of the data that must be
3570  * deleted from item.
3571  *
3572  * The Elm_Widget_Item::view will be deleted (evas_object_del()) if it
3573  * is presented!
3574  *
3575  * Note that if item_del_pre_hook() returns @c EINA_TRUE, item free will be
3576  * deferred, or item will be freed here if it returns @c EINA_FALSE.
3577  *
3578  * @see elm_widget_item_del() convenience macro.
3579  * @ingroup Widget
3580  */
3581 EOLIAN static void
_elm_widget_item_efl_object_invalidate(Eo * eo_item,Elm_Widget_Item_Data * item)3582 _elm_widget_item_efl_object_invalidate(Eo *eo_item, Elm_Widget_Item_Data *item)
3583 {
3584    Evas_Object *view;
3585 
3586    //Widget item delete callback
3587    elm_wdg_item_del_pre(item->eo_obj);
3588 
3589    view = item->view;
3590    if (item->view) efl_wref_del(item->view, &item->view);
3591    // FIXME: Is view an Efl.Ui or a legacy object ?
3592    evas_object_del(view);
3593    item->view = NULL;
3594 
3595    efl_invalidate(efl_super(eo_item, ELM_WIDGET_ITEM_CLASS));
3596 }
3597 
3598 EOLIAN static void
_elm_widget_item_del_pre(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item EINA_UNUSED)3599 _elm_widget_item_del_pre(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED)
3600 {
3601 }
3602 
3603 /**
3604  * @internal
3605  *
3606  * Notify object will be deleted without actually deleting it.
3607  *
3608  * This function will callback Elm_Widget_Item::del_cb if it is set
3609  * and then unset it so it is not called twice (ie: from
3610  * elm_widget_item_del()).
3611  *
3612  * @param item a valid #Elm_Widget_Item to be notified
3613  * @see elm_widget_item_pre_notify_del() convenience macro.
3614  * @ingroup Widget
3615  */
3616 EOLIAN static void
_elm_widget_item_pre_notify_del(Eo * eo_item,Elm_Widget_Item_Data * item)3617 _elm_widget_item_pre_notify_del(Eo *eo_item, Elm_Widget_Item_Data *item)
3618 {
3619    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3620    if (!item->del_func) return;
3621    item->del_func((void *)WIDGET_ITEM_DATA_GET(eo_item), item->widget, item->eo_obj);
3622    item->del_func = NULL;
3623 }
3624 
3625 /**
3626  * @internal
3627  *
3628  * Set the function to notify when item is being deleted.
3629  *
3630  * This function will complain if there was a callback set already,
3631  * however it will set the new one.
3632  *
3633  * The callback will be called from elm_widget_item_pre_notify_del()
3634  * or elm_widget_item_del() will be called with:
3635  *   - data: the Elm_Widget_Item::data value.
3636  *   - obj: the Elm_Widget_Item::widget evas object.
3637  *   - event_info: the item being deleted.
3638  *
3639  * @param item a valid #Elm_Widget_Item to be notified
3640  * @see elm_widget_item_del_cb_set() convenience macro.
3641  * @ingroup Widget
3642  */
3643 EOLIAN static void
_elm_widget_item_del_cb_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Evas_Smart_Cb func)3644 _elm_widget_item_del_cb_set(Eo *eo_item EINA_UNUSED,
3645                             Elm_Widget_Item_Data *item,
3646                             Evas_Smart_Cb func)
3647 {
3648    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3649    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
3650 
3651    if ((item->del_func) && (item->del_func != func))
3652      WRN("You're replacing a previously set del_cb %p of item %p with %p",
3653          item->del_func, item->eo_obj, func);
3654 
3655    item->del_func = func;
3656 }
3657 
3658 /**
3659  * @internal
3660  *
3661  * Get owner widget of this item.
3662  *
3663  * @param item a valid #Elm_Widget_Item to get data from.
3664  * @return owner widget of this item.
3665  * @ingroup Widget
3666  */
3667 EOLIAN static Evas_Object *
_elm_widget_item_widget_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3668 _elm_widget_item_widget_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3669 {
3670    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3671    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
3672 
3673    return item->widget;
3674 }
3675 
3676 EAPI Eina_Bool
_elm_widget_onscreen_is(const Evas_Object * widget)3677 _elm_widget_onscreen_is(const Evas_Object *widget)
3678 {
3679    Evas_Object *parent = (Evas_Object *)widget;
3680    Eina_Rectangle r1, r2;
3681 
3682    Evas *evas = evas_object_evas_get(widget);
3683    if (!evas) return EINA_FALSE;
3684 
3685    evas_object_geometry_get(widget, &r1.x, &r1.y, &r1.w, &r1.h);
3686    if (eina_rectangle_is_empty(&r1))
3687      return EINA_FALSE;
3688 
3689    // window does not have to check viewport and geometry
3690    if (efl_isa(widget, EFL_UI_WIN_CLASS))
3691       return EINA_TRUE;
3692 
3693    // check if on canvas
3694    evas_output_viewport_get(evas, &r2.x, &r2.y, &r2.w, &r2.h);
3695    if (!eina_rectangles_intersect(&r1, &r2))
3696      return EINA_FALSE;
3697 
3698    // check if inside scrollable parent viewport
3699    do {
3700       parent = elm_widget_parent_get(parent);
3701       if (parent && !evas_object_visible_get(parent))
3702         return EINA_FALSE;
3703       if (parent && efl_isa(parent, ELM_INTERFACE_SCROLLABLE_MIXIN))
3704         {
3705            evas_object_geometry_get(parent, &r2.x, &r2.y, &r2.w, &r2.h);
3706            if (!eina_rectangles_intersect(&r1, &r2))
3707              return EINA_FALSE;
3708         }
3709    } while (parent && (parent != elm_widget_top_get(widget)));
3710 
3711    return EINA_TRUE;
3712 }
3713 
3714 EAPI Eina_Bool
_elm_widget_item_onscreen_is(const Elm_Object_Item * item)3715 _elm_widget_item_onscreen_is(const Elm_Object_Item *item)
3716 {
3717    Eina_Rectangle r1, r2;
3718    Elm_Widget_Item_Data *id = efl_data_scope_get(item, ELM_WIDGET_ITEM_CLASS);
3719    if (!id || !id->view) return EINA_FALSE;
3720 
3721    if (!evas_object_visible_get(id->view))
3722      return EINA_FALSE;
3723 
3724    if (!_elm_widget_onscreen_is(id->widget))
3725      return EINA_FALSE;
3726 
3727    evas_object_geometry_get(id->view, &r1.x, &r1.y, &r1.w, &r1.h);
3728    if (eina_rectangle_is_empty(&r1))
3729      return EINA_FALSE;
3730 
3731    evas_object_geometry_get(id->widget, &r2.x, &r2.y, &r2.w, &r2.h);
3732    if (!eina_rectangles_intersect(&r1, &r2))
3733      return EINA_FALSE;
3734 
3735    return EINA_TRUE;
3736 }
3737 
3738 const char*
_elm_widget_accessible_plain_name_get(const Evas_Object * obj,const char * name)3739 _elm_widget_accessible_plain_name_get(const Evas_Object *obj, const char* name)
3740 {
3741    char *accessible_plain_name;
3742 
3743    API_ENTRY return NULL;
3744 
3745    accessible_plain_name = _elm_util_mkup_to_text(name);
3746    eina_stringshare_del(sd->accessible_name);
3747    sd->accessible_name =  eina_stringshare_add(accessible_plain_name);
3748    free(accessible_plain_name);
3749    return sd->accessible_name;
3750 }
3751 
3752 const char*
_elm_widget_item_accessible_plain_name_get(const Elm_Object_Item * item,const char * name)3753 _elm_widget_item_accessible_plain_name_get(const Elm_Object_Item *item, const char* name)
3754 {
3755    char *accessible_plain_name;
3756 
3757    Elm_Widget_Item_Data *id = efl_data_scope_get(item, ELM_WIDGET_ITEM_CLASS);
3758    if (!id) return NULL;
3759 
3760    accessible_plain_name = _elm_util_mkup_to_text(name);
3761    eina_stringshare_del(id->accessible_name);
3762    id->accessible_name =  eina_stringshare_add(accessible_plain_name);
3763    free(accessible_plain_name);
3764    return id->accessible_name;
3765 }
3766 
3767 EOLIAN static Efl_Access_State_Set
_elm_widget_item_efl_access_object_state_set_get(const Eo * eo_item,Elm_Widget_Item_Data * item EINA_UNUSED)3768 _elm_widget_item_efl_access_object_state_set_get(const Eo *eo_item,
3769                                                  Elm_Widget_Item_Data *item EINA_UNUSED)
3770 {
3771    Efl_Access_State_Set states = 0;
3772 
3773    STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_FOCUSABLE);
3774 
3775    if (elm_object_item_focus_get(eo_item))
3776      STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_FOCUSED);
3777    if (!elm_object_item_disabled_get(eo_item))
3778      {
3779         STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_ENABLED);
3780         STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_SENSITIVE);
3781         STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_VISIBLE);
3782      }
3783    if (_elm_widget_item_onscreen_is(eo_item))
3784      STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_SHOWING);
3785 
3786    return states;
3787 }
3788 
3789 EAPI void
elm_object_item_data_set(Elm_Object_Item * it,void * data)3790 elm_object_item_data_set(Elm_Object_Item *it, void *data)
3791 {
3792    WIDGET_ITEM_DATA_SET(it, data);
3793 }
3794 
3795 EAPI void *
elm_object_item_data_get(const Elm_Object_Item * it)3796 elm_object_item_data_get(const Elm_Object_Item *it)
3797 {
3798    return (void *) WIDGET_ITEM_DATA_GET(it);
3799 }
3800 
3801 EOLIAN static void
_elm_widget_item_disabled_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Eina_Bool disabled)3802 _elm_widget_item_disabled_set(Eo *eo_item EINA_UNUSED,
3803                               Elm_Widget_Item_Data *item,
3804                               Eina_Bool disabled)
3805 {
3806    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3807    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
3808 
3809    if (item->disabled == disabled) return;
3810    item->disabled = !!disabled;
3811    elm_wdg_item_disable(item->eo_obj);
3812 }
3813 
3814 EOLIAN static Eina_Bool
_elm_widget_item_disabled_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3815 _elm_widget_item_disabled_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3816 {
3817    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
3818    return item->disabled;
3819 }
3820 
3821 EOLIAN static void
_elm_widget_item_style_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * style)3822 _elm_widget_item_style_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, const char *style)
3823 {
3824    eina_stringshare_replace(&item->style, style);
3825 }
3826 
3827 EOLIAN static const char *
_elm_widget_item_style_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3828 _elm_widget_item_style_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3829 {
3830    return item->style;
3831 }
3832 
3833 EOLIAN static void
_elm_widget_item_disable(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item EINA_UNUSED)3834 _elm_widget_item_disable(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item EINA_UNUSED)
3835 {
3836 }
3837 
3838 EOLIAN static void
_elm_widget_item_item_focus_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Eina_Bool focused EINA_UNUSED)3839 _elm_widget_item_item_focus_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Eina_Bool focused EINA_UNUSED)
3840 {
3841    ERR_NOT_SUPPORTED(item, "elm_object_item_focus_set");
3842 }
3843 
3844 EOLIAN static Eina_Bool
_elm_widget_item_item_focus_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3845 _elm_widget_item_item_focus_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3846 {
3847    ERR_NOT_SUPPORTED(item, "elm_object_item_focus_get");
3848    return EINA_FALSE;
3849 }
3850 
3851 EOLIAN static void
_elm_widget_item_domain_translatable_part_text_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part,const char * domain,const char * label)3852 _elm_widget_item_domain_translatable_part_text_set(Eo *eo_item EINA_UNUSED,
3853                                                    Elm_Widget_Item_Data *item,
3854                                                    const char *part,
3855                                                    const char *domain,
3856                                                    const char *label)
3857 {
3858    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3859    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
3860    Elm_Translate_String_Data *ts;
3861 
3862    if (!label)
3863      {
3864         _part_text_translatable_set(&item->translate_strings, part, EINA_FALSE,
3865                                     EINA_FALSE);
3866      }
3867    else
3868      {
3869         ts = _part_text_translatable_set(&item->translate_strings, part,
3870                                          EINA_TRUE, EINA_FALSE);
3871         if (!ts) return;
3872         if (!ts->string) ts->string = eina_stringshare_add(label);
3873         else eina_stringshare_replace(&ts->string, label);
3874         if (!ts->domain) ts->domain = eina_stringshare_add(domain);
3875         else eina_stringshare_replace(&ts->domain, domain);
3876 #ifdef HAVE_GETTEXT
3877         if (label[0]) label = dgettext(domain, label);
3878 #endif
3879      }
3880    item->on_translate = EINA_TRUE;
3881    elm_wdg_item_part_text_set(item->eo_obj, part, label);
3882    item->on_translate = EINA_FALSE;
3883 }
3884 
3885 EOLIAN static const char *
_elm_widget_item_translatable_part_text_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part)3886 _elm_widget_item_translatable_part_text_get(const Eo *eo_item EINA_UNUSED,
3887                                             Elm_Widget_Item_Data *item,
3888                                             const char *part)
3889 {
3890    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3891    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
3892 
3893    Elm_Translate_String_Data *ts;
3894    ts = _translate_string_data_get(item->translate_strings, part);
3895    if (ts) return ts->string;
3896    return NULL;
3897 }
3898 
3899 EOLIAN static void
_elm_widget_item_domain_part_text_translatable_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part,const char * domain,Eina_Bool translatable)3900 _elm_widget_item_domain_part_text_translatable_set(Eo *eo_item EINA_UNUSED,
3901                                                    Elm_Widget_Item_Data *item,
3902                                                    const char *part,
3903                                                    const char *domain,
3904                                                    Eina_Bool translatable)
3905 {
3906    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3907    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
3908    Elm_Translate_String_Data *ts;
3909    const char *text;
3910 
3911    ts = _part_text_translatable_set(&item->translate_strings, part,
3912                                     translatable, EINA_TRUE);
3913    if (!ts) return;
3914    if (!ts->domain) ts->domain = eina_stringshare_add(domain);
3915    else eina_stringshare_replace(&ts->domain, domain);
3916 
3917    text = elm_wdg_item_part_text_get(item->eo_obj, part);
3918 
3919    if (!text || !text[0]) return;
3920 
3921    if (!ts->string) ts->string = eina_stringshare_add(text);
3922 
3923 //Try to translate text since we don't know the text is already translated.
3924 #ifdef HAVE_GETTEXT
3925    text = dgettext(domain, text);
3926 #endif
3927    item->on_translate = EINA_TRUE;
3928    elm_wdg_item_part_text_set(item->eo_obj, part, text);
3929    item->on_translate = EINA_FALSE;
3930 }
3931 
3932 EOLIAN static void
_elm_widget_item_track_cancel(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3933 _elm_widget_item_track_cancel(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3934 {
3935    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3936    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
3937 
3938    if (!item->track_obj) return;
3939 
3940    while (evas_object_ref_get(item->track_obj) > 0)
3941      evas_object_unref(item->track_obj);
3942 
3943    evas_object_del(item->track_obj);
3944 }
3945 
3946 EOLIAN static Evas_Object *
_elm_widget_item_track(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3947 _elm_widget_item_track(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3948 {
3949    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
3950    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
3951 
3952    if (item->track_obj)
3953      {
3954         evas_object_ref(item->track_obj);
3955         return item->track_obj;
3956      }
3957 
3958    if (!item->view)
3959      {
3960         WRN("view obj of the item(%p) is invalid. Please make sure the view obj is created!", item);
3961         return NULL;
3962      }
3963 
3964    Evas_Object *track =
3965       evas_object_rectangle_add(evas_object_evas_get(item->widget));
3966    evas_object_color_set(track, 0, 0, 0, 0);
3967    evas_object_pass_events_set(track, EINA_TRUE);
3968    _track_obj_update(track, item->view);
3969    evas_object_event_callback_add(track, EVAS_CALLBACK_DEL, _track_obj_del,
3970                                   item);
3971 
3972    efl_event_callback_array_add(item->view, tracker_callbacks(), item);
3973 
3974    evas_object_ref(track);
3975 
3976    item->track_obj = track;
3977 
3978    return track;
3979 }
3980 
3981 EOLIAN static void
_elm_widget_item_untrack(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3982 _elm_widget_item_untrack(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3983 {
3984    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
3985    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
3986 
3987    if (!item->track_obj) return;
3988    evas_object_unref(item->track_obj);
3989 
3990    if (evas_object_ref_get(item->track_obj) == 0)
3991      evas_object_del(item->track_obj);
3992 }
3993 
3994 EOLIAN static int
_elm_widget_item_track_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)3995 _elm_widget_item_track_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
3996 {
3997    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, 0);
3998    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, 0);
3999 
4000    if (!item->track_obj) return 0;
4001    return evas_object_ref_get(item->track_obj);
4002 }
4003 
4004 typedef struct _Elm_Widget_Item_Tooltip Elm_Widget_Item_Tooltip;
4005 
4006 struct _Elm_Widget_Item_Tooltip
4007 {
4008    Elm_Widget_Item_Data       *item;
4009    Elm_Tooltip_Item_Content_Cb func;
4010    Evas_Smart_Cb               del_cb;
4011    const void                 *data;
4012 };
4013 
4014 static Evas_Object *
_elm_widget_item_tooltip_label_create(void * data,Evas_Object * obj EINA_UNUSED,Evas_Object * tooltip,void * item EINA_UNUSED)4015 _elm_widget_item_tooltip_label_create(void *data,
4016                                       Evas_Object *obj EINA_UNUSED,
4017                                       Evas_Object *tooltip,
4018                                       void *item EINA_UNUSED)
4019 {
4020    Evas_Object *label = elm_label_add(tooltip);
4021    if (!label)
4022      return NULL;
4023    elm_object_style_set(label, "tooltip");
4024    elm_object_text_set(label, data);
4025    return label;
4026 }
4027 
4028 static Evas_Object *
_elm_widget_item_tooltip_trans_label_create(void * data,Evas_Object * obj EINA_UNUSED,Evas_Object * tooltip,void * item EINA_UNUSED)4029 _elm_widget_item_tooltip_trans_label_create(void *data,
4030                                             Evas_Object *obj EINA_UNUSED,
4031                                             Evas_Object *tooltip,
4032                                             void *item EINA_UNUSED)
4033 {
4034    Evas_Object *label = elm_label_add(tooltip);
4035    if (!label)
4036      return NULL;
4037    elm_object_style_set(label, "tooltip");
4038    elm_object_translatable_text_set(label, data);
4039    return label;
4040 }
4041 
4042 static void
_elm_widget_item_tooltip_label_del_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)4043 _elm_widget_item_tooltip_label_del_cb(void *data,
4044                                       Evas_Object *obj EINA_UNUSED,
4045                                       void *event_info EINA_UNUSED)
4046 {
4047    eina_stringshare_del(data);
4048 }
4049 
4050 /**
4051  * @internal
4052  *
4053  * Set the text to be shown in the widget item.
4054  *
4055  * @param item Target item
4056  * @param text The text to set in the content
4057  *
4058  * Setup the text as tooltip to object. The item can have only one tooltip,
4059  * so any previous tooltip data is removed.
4060  *
4061  * @ingroup Widget
4062  */
4063 EOLIAN static void
_elm_widget_item_tooltip_text_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item EINA_UNUSED,const char * text)4064 _elm_widget_item_tooltip_text_set(Eo *eo_item EINA_UNUSED,
4065                                   Elm_Widget_Item_Data *item EINA_UNUSED,
4066                                   const char *text)
4067 {
4068    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4069    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4070    EINA_SAFETY_ON_NULL_RETURN(text);
4071 
4072    text = eina_stringshare_add(text);
4073    elm_wdg_item_tooltip_content_cb_set(item->eo_obj, _elm_widget_item_tooltip_label_create, text, _elm_widget_item_tooltip_label_del_cb);
4074 }
4075 
4076 EOLIAN static void
_elm_widget_item_tooltip_translatable_text_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item EINA_UNUSED,const char * text)4077 _elm_widget_item_tooltip_translatable_text_set(Eo *eo_item EINA_UNUSED,
4078                                                Elm_Widget_Item_Data *item EINA_UNUSED,
4079                                                const char *text)
4080 {
4081    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4082    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4083    EINA_SAFETY_ON_NULL_RETURN(text);
4084 
4085    text = eina_stringshare_add(text);
4086    elm_wdg_item_tooltip_content_cb_set(item->eo_obj, _elm_widget_item_tooltip_trans_label_create, text, _elm_widget_item_tooltip_label_del_cb);
4087 }
4088 
4089 static Evas_Object *
_elm_widget_item_tooltip_create(void * data,Evas_Object * obj,Evas_Object * tooltip)4090 _elm_widget_item_tooltip_create(void *data,
4091                                 Evas_Object *obj,
4092                                 Evas_Object *tooltip)
4093 {
4094    Elm_Widget_Item_Tooltip *wit = data;
4095    return wit->func((void *)wit->data, obj, tooltip, wit->item->eo_obj);
4096 }
4097 
4098 static void
_elm_widget_item_tooltip_del_cb(void * data,Evas_Object * obj,void * event_info EINA_UNUSED)4099 _elm_widget_item_tooltip_del_cb(void *data,
4100                                 Evas_Object *obj,
4101                                 void *event_info EINA_UNUSED)
4102 {
4103    Elm_Widget_Item_Tooltip *wit = data;
4104    if (wit->del_cb) wit->del_cb((void *)wit->data, obj, wit->item->eo_obj);
4105    free(wit);
4106 }
4107 
4108 /**
4109  * @internal
4110  *
4111  * Set the content to be shown in the tooltip item
4112  *
4113  * Setup the tooltip to item. The item can have only one tooltip,
4114  * so any previous tooltip data is removed. @p func(with @p data) will
4115  * be called every time that need show the tooltip and it should
4116  * return a valid Evas_Object. This object is then managed fully by
4117  * tooltip system and is deleted when the tooltip is gone.
4118  *
4119  * @param item the widget item being attached a tooltip.
4120  * @param func the function used to create the tooltip contents.
4121  * @param data what to provide to @a func as callback data/context.
4122  * @param del_cb called when data is not needed anymore, either when
4123  *        another callback replaces @func, the tooltip is unset with
4124  *        elm_widget_item_tooltip_unset() or the owner @a item
4125  *        dies. This callback receives as the first parameter the
4126  *        given @a data, and @c event_info is the item.
4127  *
4128  * @ingroup Widget
4129  */
4130 EOLIAN static void
_elm_widget_item_tooltip_content_cb_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Elm_Tooltip_Item_Content_Cb func,const void * data,Evas_Smart_Cb del_cb)4131 _elm_widget_item_tooltip_content_cb_set(Eo *eo_item EINA_UNUSED,
4132                                         Elm_Widget_Item_Data *item,
4133                                         Elm_Tooltip_Item_Content_Cb func,
4134                                         const void *data,
4135                                         Evas_Smart_Cb del_cb)
4136 {
4137    Elm_Widget_Item_Tooltip *wit;
4138 
4139    ELM_WIDGET_ITEM_CHECK_OR_GOTO(item, error_noitem);
4140    //ELM_WIDGET_ITEM_RETURN_IF_GOTO(item, error_noitem);
4141 
4142    if (!func)
4143      {
4144         elm_wdg_item_tooltip_unset(item->eo_obj);
4145         return;
4146      }
4147 
4148    wit = ELM_NEW(Elm_Widget_Item_Tooltip);
4149    if (!wit) goto error;
4150    wit->item = item;
4151    wit->func = func;
4152    wit->data = data;
4153    wit->del_cb = del_cb;
4154 
4155    elm_object_sub_tooltip_content_cb_set
4156      (item->view, item->widget, _elm_widget_item_tooltip_create, wit,
4157      _elm_widget_item_tooltip_del_cb);
4158 
4159    return;
4160 
4161 error_noitem:
4162    if (del_cb) del_cb((void *)data, NULL, item);
4163    return;
4164 error:
4165    if (del_cb) del_cb((void *)data, item->widget, item);
4166 }
4167 
4168 /**
4169  * @internal
4170  *
4171  * Unset tooltip from item
4172  *
4173  * @param item widget item to remove previously set tooltip.
4174  *
4175  * Remove tooltip from item. The callback provided as del_cb to
4176  * elm_widget_item_tooltip_content_cb_set() will be called to notify
4177  * it is not used anymore.
4178  *
4179  * @see elm_widget_item_tooltip_content_cb_set()
4180  *
4181  * @ingroup Widget
4182  */
4183 EOLIAN static void
_elm_widget_item_tooltip_unset(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4184 _elm_widget_item_tooltip_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4185 {
4186    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4187    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4188 
4189    elm_object_tooltip_unset(item->view);
4190 }
4191 
4192 /**
4193  * @internal
4194  *
4195  * Sets a different style for this item tooltip.
4196  *
4197  * @note before you set a style you should define a tooltip with
4198  *       elm_widget_item_tooltip_content_cb_set() or
4199  *       elm_widget_item_tooltip_text_set()
4200  *
4201  * @param item widget item with tooltip already set.
4202  * @param style the theme style to use (default, transparent, ...)
4203  *
4204  * @ingroup Widget
4205  */
4206 EOLIAN static void
_elm_widget_item_tooltip_style_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * style)4207 _elm_widget_item_tooltip_style_set(Eo *eo_item EINA_UNUSED,
4208                                    Elm_Widget_Item_Data *item,
4209                                    const char *style)
4210 {
4211    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4212    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4213 
4214    elm_object_tooltip_style_set(item->view, style);
4215 }
4216 
4217 EOLIAN static Eina_Bool
_elm_widget_item_tooltip_window_mode_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Eina_Bool disable)4218 _elm_widget_item_tooltip_window_mode_set(Eo *eo_item EINA_UNUSED,
4219                                          Elm_Widget_Item_Data *item,
4220                                          Eina_Bool disable)
4221 {
4222    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4223    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
4224 
4225    return elm_object_tooltip_window_mode_set(item->view, disable);
4226 }
4227 
4228 EOLIAN static Eina_Bool
_elm_widget_item_tooltip_window_mode_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4229 _elm_widget_item_tooltip_window_mode_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4230 {
4231    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4232    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, EINA_FALSE);
4233 
4234    return elm_object_tooltip_window_mode_get(item->view);
4235 }
4236 
4237 /**
4238  * @internal
4239  *
4240  * Get the style for this item tooltip.
4241  *
4242  * @param item widget item with tooltip already set.
4243  * @return style the theme style in use, defaults to "default". If the
4244  *         object does not have a tooltip set, then NULL is returned.
4245  *
4246  * @ingroup Widget
4247  */
4248 EOLIAN static const char *
_elm_widget_item_tooltip_style_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4249 _elm_widget_item_tooltip_style_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4250 {
4251    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4252 
4253    return elm_object_tooltip_style_get(item->view);
4254 }
4255 
4256 EOLIAN static void
_elm_widget_item_cursor_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * cursor)4257 _elm_widget_item_cursor_set(Eo *eo_item EINA_UNUSED,
4258                             Elm_Widget_Item_Data *item,
4259                             const char *cursor)
4260 {
4261    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4262    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4263 
4264    elm_object_sub_cursor_set(item->view, item->widget, cursor);
4265 }
4266 
4267 EOLIAN static const char *
_elm_widget_item_cursor_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4268 _elm_widget_item_cursor_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4269 {
4270    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4271    return elm_object_sub_cursor_get(item->view);
4272 }
4273 
4274 EOLIAN static void
_elm_widget_item_cursor_unset(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4275 _elm_widget_item_cursor_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4276 {
4277    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4278    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4279 
4280    elm_object_cursor_unset(item->view);
4281 }
4282 
4283 /**
4284  * @internal
4285  *
4286  * Sets a different style for this item cursor.
4287  *
4288  * @note before you set a style you should define a cursor with
4289  *       elm_widget_item_cursor_set()
4290  *
4291  * @param item widget item with cursor already set.
4292  * @param style the theme style to use (default, transparent, ...)
4293  *
4294  * @ingroup Widget
4295  */
4296 EOLIAN static void
_elm_widget_item_cursor_style_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * style)4297 _elm_widget_item_cursor_style_set(Eo *eo_item EINA_UNUSED,
4298                                   Elm_Widget_Item_Data *item,
4299                                   const char *style)
4300 {
4301    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4302    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4303 
4304    elm_object_sub_cursor_style_set(item->view, style);
4305 }
4306 
4307 /**
4308  * @internal
4309  *
4310  * Get the style for this item cursor.
4311  *
4312  * @param item widget item with cursor already set.
4313  * @return style the theme style in use, defaults to "default". If the
4314  *         object does not have a cursor set, then NULL is returned.
4315  *
4316  * @ingroup Widget
4317  */
4318 EOLIAN static const char *
_elm_widget_item_cursor_style_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4319 _elm_widget_item_cursor_style_get(const Eo *eo_item EINA_UNUSED,
4320                                   Elm_Widget_Item_Data *item)
4321 {
4322    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4323    return elm_object_sub_cursor_style_get(item->view);
4324 }
4325 
4326 /**
4327  * @internal
4328  *
4329  * Set if the cursor set should be searched on the theme or should use
4330  * the provided by the engine, only.
4331  *
4332  * @note before you set if should look on theme you should define a cursor
4333  * with elm_object_cursor_set(). By default it will only look for cursors
4334  * provided by the engine.
4335  *
4336  * @param item widget item with cursor already set.
4337  * @param engine_only boolean to define it cursors should be looked only
4338  * between the provided by the engine or searched on widget's theme as well.
4339  *
4340  * @ingroup Widget
4341  */
4342 EOLIAN static void
_elm_widget_item_cursor_engine_only_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Eina_Bool engine_only)4343 _elm_widget_item_cursor_engine_only_set(Eo *eo_item EINA_UNUSED,
4344                                         Elm_Widget_Item_Data *item,
4345                                         Eina_Bool engine_only)
4346 {
4347    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4348    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4349 
4350    elm_object_sub_cursor_theme_search_enabled_set(item->view, !engine_only);
4351 }
4352 
4353 /**
4354  * @internal
4355  *
4356  * Get the cursor engine only usage for this item cursor.
4357  *
4358  * @param item widget item with cursor already set.
4359  * @return engine_only boolean to define it cursors should be looked only
4360  * between the provided by the engine or searched on widget's theme as well. If
4361  *         the object does not have a cursor set, then EINA_FALSE is returned.
4362  *
4363  * @ingroup Widget
4364  */
4365 EOLIAN static Eina_Bool
_elm_widget_item_cursor_engine_only_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4366 _elm_widget_item_cursor_engine_only_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4367 {
4368    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
4369    return !elm_object_sub_cursor_theme_search_enabled_get(item->view);
4370 }
4371 
4372 EOLIAN static void
_elm_widget_item_part_content_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part EINA_UNUSED,Evas_Object * content EINA_UNUSED)4373 _elm_widget_item_part_content_set(Eo *eo_item EINA_UNUSED,
4374                                   Elm_Widget_Item_Data *item,
4375                                   const char *part EINA_UNUSED,
4376                                   Evas_Object *content EINA_UNUSED)
4377 {
4378    ERR_NOT_SUPPORTED(item, "elm_object_part_content_set()");
4379 }
4380 
4381 EOLIAN static Evas_Object *
_elm_widget_item_part_content_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part EINA_UNUSED)4382 _elm_widget_item_part_content_get(const Eo *eo_item EINA_UNUSED,
4383                                   Elm_Widget_Item_Data *item,
4384                                   const char *part EINA_UNUSED)
4385 {
4386    ERR_NOT_SUPPORTED(item, "elm_object_part_content_get()");
4387    return NULL;
4388 }
4389 
4390 EOLIAN static Evas_Object *
_elm_widget_item_part_content_unset(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part EINA_UNUSED)4391 _elm_widget_item_part_content_unset(Eo *eo_item EINA_UNUSED,
4392                                     Elm_Widget_Item_Data *item,
4393                                     const char *part EINA_UNUSED)
4394 {
4395    ERR_NOT_SUPPORTED(item, "elm_object_part_content_unset()");
4396    return NULL;
4397 }
4398 
4399 EOLIAN static void
_elm_widget_item_part_text_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part EINA_UNUSED,const char * label EINA_UNUSED)4400 _elm_widget_item_part_text_set(Eo *eo_item EINA_UNUSED,
4401                                Elm_Widget_Item_Data *item,
4402                                const char *part EINA_UNUSED,
4403                                const char *label EINA_UNUSED)
4404 {
4405    ERR_NOT_SUPPORTED(item, "elm_object_part_text_set()");
4406 }
4407 
4408 EOLIAN static const char *
_elm_widget_item_part_text_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part EINA_UNUSED)4409 _elm_widget_item_part_text_get(const Eo *eo_item EINA_UNUSED,
4410                                Elm_Widget_Item_Data *item,
4411                                const char *part EINA_UNUSED)
4412 {
4413    ERR_NOT_SUPPORTED(item, "elm_object_part_text_get()");
4414    return NULL;
4415 }
4416 
4417 static void
_elm_widget_item_part_text_custom_free(void * data)4418 _elm_widget_item_part_text_custom_free(void *data)
4419 {
4420    Elm_Label_Data *label;
4421    label = data;
4422    eina_stringshare_del(label->part);
4423    eina_stringshare_del(label->text);
4424    free(label);
4425 }
4426 
4427 EOLIAN static void
_elm_widget_item_part_text_custom_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part,const char * text)4428 _elm_widget_item_part_text_custom_set(Eo *eo_item EINA_UNUSED,
4429                                       Elm_Widget_Item_Data *item,
4430                                       const char *part,
4431                                       const char *text)
4432 {
4433    Elm_Label_Data *label;
4434    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4435    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4436 
4437    if (!item->labels)
4438      item->labels =
4439         eina_hash_stringshared_new(_elm_widget_item_part_text_custom_free);
4440    label = eina_hash_find(item->labels, part);
4441    if (!label)
4442      {
4443         label = malloc(sizeof(Elm_Label_Data));
4444         if (!label)
4445           {
4446              ERR("Failed to allocate memory");
4447              return;
4448           }
4449         label->part = eina_stringshare_add(part);
4450         label->text = eina_stringshare_add(text);
4451         eina_hash_add(item->labels, part, label);
4452      }
4453    else
4454      eina_stringshare_replace(&label->text, text);
4455 }
4456 
4457 EOLIAN static const char *
_elm_widget_item_part_text_custom_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * part)4458 _elm_widget_item_part_text_custom_get(const Eo *eo_item EINA_UNUSED,
4459                                       Elm_Widget_Item_Data *item,
4460                                       const char *part)
4461 {
4462    Elm_Label_Data *label;
4463    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4464    label = eina_hash_find(item->labels, part);
4465    return label ? label->text : NULL;
4466 }
4467 
4468 static Eina_Bool
_elm_widget_item_part_text_custom_foreach(const Eina_Hash * labels EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * func_data)4469 _elm_widget_item_part_text_custom_foreach(const Eina_Hash *labels EINA_UNUSED,
4470                                           const void *key EINA_UNUSED,
4471                                           void *data,
4472                                           void *func_data)
4473 {
4474    Elm_Label_Data *label;
4475    Elm_Widget_Item_Data *item;
4476    label = data;
4477    item = func_data;
4478 
4479    elm_wdg_item_part_text_set(item->eo_obj, label->part, label->text);
4480 
4481    return EINA_TRUE;
4482 }
4483 
4484 EOLIAN static void
_elm_widget_item_part_text_custom_update(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4485 _elm_widget_item_part_text_custom_update(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4486 {
4487    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4488    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4489    if (item->labels)
4490      eina_hash_foreach(item->labels,
4491                        _elm_widget_item_part_text_custom_foreach, item);
4492 }
4493 
4494 EOLIAN static void
_elm_widget_item_signal_emit(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)4495 _elm_widget_item_signal_emit(Eo *eo_item EINA_UNUSED,
4496                              Elm_Widget_Item_Data *item EINA_UNUSED,
4497                              const char *emission EINA_UNUSED,
4498                              const char *source EINA_UNUSED)
4499 {
4500 
4501 }
4502 
4503 EOLIAN static void
_elm_widget_item_signal_callback_add(Eo * eo_item,Elm_Widget_Item_Data * item,const char * emission,const char * source,Elm_Object_Item_Signal_Cb func,void * data)4504 _elm_widget_item_signal_callback_add(Eo *eo_item,
4505                                      Elm_Widget_Item_Data *item,
4506                                      const char *emission,
4507                                      const char *source,
4508                                      Elm_Object_Item_Signal_Cb func,
4509                                      void *data)
4510 {
4511    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4512    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4513    EINA_SAFETY_ON_NULL_RETURN(func);
4514 
4515    Elm_Widget_Item_Signal_Data *wisd;
4516 
4517    wisd = malloc(sizeof(Elm_Widget_Item_Signal_Data));
4518    if (!wisd) return;
4519 
4520    wisd->item = eo_item;
4521    wisd->func = (Elm_Widget_Item_Signal_Cb)func;
4522    wisd->data = data;
4523    wisd->emission = eina_stringshare_add(emission);
4524    wisd->source = eina_stringshare_add(source);
4525 
4526    if (_elm_widget_is(item->view))
4527      elm_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
4528    else if (efl_isa(item->view, EFL_CANVAS_LAYOUT_CLASS))
4529      edje_object_signal_callback_add(item->view, emission, source, _elm_widget_item_signal_cb, wisd);
4530    else
4531      {
4532         WRN("The %s widget item doesn't support signal callback add!",
4533             efl_class_name_get(efl_class_get(item->widget)));
4534         free(wisd);
4535         return;
4536      }
4537 
4538    item->signals = eina_list_append(item->signals, wisd);
4539 }
4540 
4541 EOLIAN static void *
_elm_widget_item_signal_callback_del(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * emission,const char * source,Elm_Object_Item_Signal_Cb func)4542 _elm_widget_item_signal_callback_del(Eo *eo_item EINA_UNUSED,
4543                                      Elm_Widget_Item_Data *item,
4544                                      const char *emission,
4545                                      const char *source,
4546                                      Elm_Object_Item_Signal_Cb func)
4547 {
4548    Elm_Widget_Item_Signal_Data *wisd;
4549    Eina_List *l;
4550 
4551    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item, NULL);
4552    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item, NULL);
4553    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
4554 
4555    EINA_LIST_FOREACH(item->signals, l, wisd)
4556      {
4557         if ((wisd->func == (Elm_Widget_Item_Signal_Cb)func) &&
4558             !strcmp(wisd->emission, emission) &&
4559             !strcmp(wisd->source, source))
4560           return _elm_widget_item_signal_callback_list_get(item, l);
4561      }
4562 
4563    return NULL;
4564 }
4565 
4566 EOLIAN static void
_elm_widget_item_access_info_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,const char * txt)4567 _elm_widget_item_access_info_set(Eo *eo_item EINA_UNUSED,
4568                                  Elm_Widget_Item_Data *item,
4569                                  const char *txt)
4570 {
4571    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4572    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4573 
4574    eina_stringshare_del(item->access_info);
4575    if (!txt) item->access_info = NULL;
4576    else item->access_info = eina_stringshare_add(txt);
4577 }
4578 
4579 EOLIAN static void
_elm_widget_item_translate(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4580 _elm_widget_item_translate(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4581 {
4582    ELM_WIDGET_ITEM_CHECK_OR_RETURN(item);
4583    ELM_WIDGET_ITEM_RETURN_IF_ONDEL(item);
4584 
4585 #ifdef HAVE_GETTEXT
4586    Elm_Translate_String_Data *ts;
4587    EINA_INLIST_FOREACH(item->translate_strings, ts)
4588      {
4589         if (!ts->string) continue;
4590         const char *s = dgettext(ts->domain, ts->string);
4591         item->on_translate = EINA_TRUE;
4592         elm_wdg_item_part_text_set(item->eo_obj, ts->id, s);
4593         item->on_translate = EINA_FALSE;
4594      }
4595 #endif
4596 }
4597 
4598 EOLIAN static void
_elm_widget_item_access_order_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Eina_List * objs)4599 _elm_widget_item_access_order_set(Eo *eo_item EINA_UNUSED,
4600                                   Elm_Widget_Item_Data *item,
4601                                   Eina_List *objs)
4602 {
4603    _elm_access_widget_item_access_order_set(item, objs);
4604 }
4605 
4606 EOLIAN static const Eina_List *
_elm_widget_item_access_order_get(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4607 _elm_widget_item_access_order_get(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4608 {
4609    return _elm_access_widget_item_access_order_get(item);
4610 }
4611 
4612 EOLIAN static void
_elm_widget_item_access_order_unset(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4613 _elm_widget_item_access_order_unset(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4614 {
4615    _elm_access_widget_item_access_order_unset(item);
4616 }
4617 
4618 EOLIAN static Evas_Object*
_elm_widget_item_access_register(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4619 _elm_widget_item_access_register(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4620 {
4621    _elm_access_widget_item_register(item);
4622    return item->access_obj;
4623 }
4624 
4625 EOLIAN static void
_elm_widget_item_access_unregister(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4626 _elm_widget_item_access_unregister(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4627 {
4628    _elm_access_widget_item_unregister(item);
4629 }
4630 
4631 EOLIAN static Evas_Object*
_elm_widget_item_access_object_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item)4632 _elm_widget_item_access_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item)
4633 {
4634    return item->access_obj;
4635 }
4636 
4637 EOLIAN static Evas_Object *
_elm_widget_item_focus_next_object_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Elm_Focus_Direction dir)4638 _elm_widget_item_focus_next_object_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir)
4639 {
4640    Evas_Object *ret = NULL;
4641 
4642    if (dir == ELM_FOCUS_PREVIOUS)
4643      ret = item->focus_previous;
4644    else if (dir == ELM_FOCUS_NEXT)
4645      ret = item->focus_next;
4646    else if (dir == ELM_FOCUS_UP)
4647      ret = item->focus_up;
4648    else if (dir == ELM_FOCUS_DOWN)
4649      ret = item->focus_down;
4650    else if (dir == ELM_FOCUS_RIGHT)
4651      ret = item->focus_right;
4652    else if (dir == ELM_FOCUS_LEFT)
4653      ret = item->focus_left;
4654 
4655    return ret;
4656 }
4657 
4658 EOLIAN static void
_elm_widget_item_focus_next_object_set(Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Evas_Object * next,Elm_Focus_Direction dir)4659 _elm_widget_item_focus_next_object_set(Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Evas_Object *next, Elm_Focus_Direction dir)
4660 {
4661    if (dir == ELM_FOCUS_PREVIOUS)
4662      item->focus_previous = next;
4663    else if (dir == ELM_FOCUS_NEXT)
4664      item->focus_next = next;
4665    else if (dir == ELM_FOCUS_UP)
4666      item->focus_up = next;
4667    else if (dir == ELM_FOCUS_DOWN)
4668      item->focus_down = next;
4669    else if (dir == ELM_FOCUS_RIGHT)
4670      item->focus_right = next;
4671    else if (dir == ELM_FOCUS_LEFT)
4672      item->focus_left = next;
4673 }
4674 
4675 EOLIAN static Elm_Object_Item*
_elm_widget_item_focus_next_item_get(const Eo * eo_item EINA_UNUSED,Elm_Widget_Item_Data * item,Elm_Focus_Direction dir)4676 _elm_widget_item_focus_next_item_get(const Eo *eo_item EINA_UNUSED, Elm_Widget_Item_Data *item, Elm_Focus_Direction dir)
4677 {
4678    Elm_Object_Item *ret = NULL;
4679 
4680    if (dir == ELM_FOCUS_PREVIOUS)
4681      ret = item->item_focus_previous;
4682    else if (dir == ELM_FOCUS_NEXT)
4683      ret = item->item_focus_next;
4684    else if (dir == ELM_FOCUS_UP)
4685      ret = item->item_focus_up;
4686    else if (dir == ELM_FOCUS_DOWN)
4687      ret = item->item_focus_down;
4688    else if (dir == ELM_FOCUS_RIGHT)
4689      ret = item->item_focus_right;
4690    else if (dir == ELM_FOCUS_LEFT)
4691      ret = item->item_focus_left;
4692 
4693    return ret;
4694 }
4695 
4696 EOLIAN static void
_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)4697 _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)
4698 {
4699    if (dir == ELM_FOCUS_PREVIOUS)
4700      item->item_focus_previous = next_item;
4701    else if (dir == ELM_FOCUS_NEXT)
4702      item->item_focus_next = next_item;
4703    else if (dir == ELM_FOCUS_UP)
4704      item->item_focus_up = next_item;
4705    else if (dir == ELM_FOCUS_DOWN)
4706      item->item_focus_down = next_item;
4707    else if (dir == ELM_FOCUS_RIGHT)
4708      item->item_focus_right = next_item;
4709    else if (dir == ELM_FOCUS_LEFT)
4710      item->item_focus_left = next_item;
4711 }
4712 
4713 /* happy debug functions */
4714 #ifdef ELM_DEBUG
4715 static void
_sub_obj_tree_dump(const Evas_Object * obj,int lvl)4716 _sub_obj_tree_dump(const Evas_Object *obj,
4717                    int lvl)
4718 {
4719    int i;
4720 
4721    for (i = 0; i < lvl * 3; i++)
4722      putchar(' ');
4723 
4724    if (_elm_widget_is(obj))
4725      {
4726         Eina_List *l;
4727         INTERNAL_ENTRY;
4728         DBG("+ %s(%p)\n",
4729             elm_widget_type_get(obj),
4730             obj);
4731        for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
4732          {
4733             obj = eina_array_data_get(sd->children, i);
4734           _sub_obj_tree_dump(obj, lvl + 1);
4735          }
4736      }
4737    else
4738      DBG("+ %s(%p)\n", evas_object_type_get(obj), obj);
4739 }
4740 
4741 static void
_sub_obj_tree_dot_dump(const Evas_Object * obj,FILE * output)4742 _sub_obj_tree_dot_dump(const Evas_Object *obj,
4743                        FILE *output)
4744 {
4745    if (!_elm_widget_is(obj))
4746      return;
4747    INTERNAL_ENTRY;
4748 
4749    Eina_Bool visible = evas_object_visible_get(obj);
4750    Eina_Bool disabled = elm_widget_disabled_get(obj);
4751    Eina_Bool focused = efl_ui_focus_object_focus_get(obj);
4752    Eina_Bool can_focus = elm_widget_can_focus_get(obj);
4753 
4754    if (sd->parent_obj)
4755      {
4756         fprintf(output, "\"%p\" -- \"%p\" [ color=black", sd->parent_obj, obj);
4757 
4758         if (focused)
4759           fprintf(output, ", style=bold");
4760 
4761         if (!visible)
4762           fprintf(output, ", color=gray28");
4763 
4764         fprintf(output, " ];\n");
4765      }
4766 
4767    fprintf(output, "\"%p\" [ label = \"{%p|%s|%s|visible: %d|"
4768                    "disabled: %d|focused: %d/%d|focus order:%d}\"",
4769            obj, obj, elm_widget_type_get(obj),
4770            evas_object_name_get(obj), visible, disabled, focused, can_focus,
4771            sd->focus_order);
4772 
4773    if (focused)
4774      fprintf(output, ", style=bold");
4775 
4776    if (!visible)
4777      fprintf(output, ", fontcolor=gray28");
4778 
4779    if ((disabled) || (!visible))
4780      fprintf(output, ", color=gray");
4781 
4782    fprintf(output, " ];\n");
4783 
4784    Eina_List *l;
4785    Evas_Object *o;
4786 
4787    for (unsigned int i = 0; i < eina_array_count(sd->children); ++i)
4788      {
4789         o = eina_array_data_get(sd->children, i);
4790         _sub_obj_tree_dot_dump(o, output);
4791      }
4792 }
4793 
4794 #endif
4795 
4796 EAPI void
elm_widget_tree_dump(const Evas_Object * top)4797 elm_widget_tree_dump(const Evas_Object *top)
4798 {
4799 #ifdef ELM_DEBUG
4800    if (!_elm_widget_is(top))
4801      return;
4802    _sub_obj_tree_dump(top, 0);
4803 #else
4804    (void)top;
4805    return;
4806 #endif
4807 }
4808 
4809 EAPI void
elm_widget_tree_dot_dump(const Evas_Object * top,FILE * output)4810 elm_widget_tree_dot_dump(const Evas_Object *top,
4811                          FILE *output)
4812 {
4813 #ifdef ELM_DEBUG
4814    if (!_elm_widget_is(top))
4815      return;
4816    fprintf(output, "graph " " { node [shape=record];\n");
4817    _sub_obj_tree_dot_dump(top, output);
4818    fprintf(output, "}\n");
4819 #else
4820    (void)top;
4821    (void)output;
4822    return;
4823 #endif
4824 }
4825 
4826 EOLIAN static Eo *
_efl_ui_widget_efl_object_constructor(Eo * obj,Elm_Widget_Smart_Data * sd EINA_UNUSED)4827 _efl_ui_widget_efl_object_constructor(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED)
4828 {
4829    Eo *parent = efl_parent_get(obj);
4830    sd->on_create = EINA_TRUE;
4831 
4832    sd->window = efl_provider_find(efl_parent_get(obj), EFL_UI_WIN_CLASS);
4833    if (!efl_isa(obj, EFL_UI_WIN_CLASS))
4834      {
4835         if (!efl_isa(parent, EFL_UI_WIDGET_CLASS))
4836           {
4837              ERR("You passed a wrong parent parameter (%p %s). "
4838                  "Elementary widget's parent should be an elementary widget.",
4839                  parent, evas_object_type_get(parent));
4840           }
4841         else
4842           {
4843              ELM_WIDGET_DATA_GET(parent, parent_sd);
4844              if (parent_sd)
4845                sd->shared_win_data = parent_sd->shared_win_data;
4846           }
4847      }
4848    else
4849      {
4850         sd->shared_win_data = efl_ui_win_shared_data_get(obj);
4851      }
4852 
4853    _efl_ui_focus_event_redirector(obj, obj);
4854    efl_canvas_group_clipped_set(obj, EINA_FALSE);
4855    obj = efl_constructor(efl_super(obj, MY_CLASS));
4856    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
4857    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
4858 
4859    if (!efl_isa(obj, EFL_UI_WIN_CLASS) && efl_isa(parent, EFL_UI_WIDGET_CLASS))
4860      efl_ui_widget_sub_object_add(parent, obj);
4861 
4862    sd->on_create = EINA_FALSE;
4863 
4864    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_UNKNOWN);
4865 
4866    if (!elm_widget_is_legacy(obj))
4867      EINA_SAFETY_ON_NULL_RETURN_VAL(sd->shared_win_data, NULL);
4868 
4869    return obj;
4870 }
4871 
4872 EOLIAN static Efl_Object*
_efl_ui_widget_efl_object_finalize(Eo * obj,Elm_Widget_Smart_Data * pd)4873 _efl_ui_widget_efl_object_finalize(Eo *obj, Elm_Widget_Smart_Data *pd)
4874 {
4875   Eo *eo;
4876 
4877   eo = efl_finalize(efl_super(obj, MY_CLASS));
4878 
4879   _full_eval(obj, pd);
4880 
4881   return eo;
4882 }
4883 
4884 
4885 EOLIAN static void
_efl_ui_widget_efl_object_destructor(Eo * obj,Elm_Widget_Smart_Data * sd)4886 _efl_ui_widget_efl_object_destructor(Eo *obj, Elm_Widget_Smart_Data *sd)
4887 {
4888    if (sd->manager.provider)
4889      {
4890         sd->manager.provider = NULL;
4891      }
4892    efl_access_object_attributes_clear(obj);
4893    efl_access_removed(obj);
4894    if (sd->logical.parent)
4895      {
4896         efl_weak_unref(&sd->logical.parent);
4897         sd->logical.parent = NULL;
4898      }
4899    if (sd->children)
4900      {
4901         eina_array_free(sd->children);
4902         sd->children = NULL;
4903      }
4904 
4905    sd->on_destroy = EINA_TRUE;
4906    efl_destructor(efl_super(obj, EFL_UI_WIDGET_CLASS));
4907    sd->on_destroy = EINA_FALSE;
4908 }
4909 
4910 /* internal eo */
4911 
4912 EOLIAN static void
_efl_ui_widget_efl_object_debug_name_override(Eo * obj,Elm_Widget_Smart_Data * sd EINA_UNUSED,Eina_Strbuf * sb)4913 _efl_ui_widget_efl_object_debug_name_override(Eo *obj, Elm_Widget_Smart_Data *sd EINA_UNUSED, Eina_Strbuf *sb)
4914 {
4915    const char *focus = "";
4916 
4917    if (efl_ui_focus_object_focus_get(obj)) focus = ":focused";
4918    efl_debug_name_override(efl_super(obj, MY_CLASS), sb);
4919    eina_strbuf_append_printf(sb, "%s", focus);
4920 }
4921 
4922 EOLIAN static Eina_Bool
_efl_ui_widget_efl_ui_focus_object_on_focus_update(Eo * obj,Elm_Widget_Smart_Data * sd)4923 _efl_ui_widget_efl_ui_focus_object_on_focus_update(Eo *obj, Elm_Widget_Smart_Data *sd)
4924 {
4925    Eina_Bool focused;
4926 
4927    if (!elm_widget_can_focus_get(obj))
4928      return EINA_FALSE;
4929 
4930    focused = efl_ui_focus_object_focus_get(obj);
4931 
4932    if (!sd->resize_obj)
4933      evas_object_focus_set(obj, focused);
4934 
4935    if (_elm_config->atspi_mode && !elm_widget_child_can_focus_get(obj))
4936      efl_access_state_changed_signal_emit(obj, EFL_ACCESS_STATE_TYPE_FOCUSED, focused);
4937 
4938    return EINA_TRUE;
4939 }
4940 
4941 EOLIAN static Eina_Bool
_efl_ui_widget_widget_input_event_handler(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * _pd EINA_UNUSED,const Efl_Event * eo_event EINA_UNUSED,Evas_Object * source EINA_UNUSED)4942 _efl_ui_widget_widget_input_event_handler(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, const Efl_Event *eo_event EINA_UNUSED, Evas_Object *source EINA_UNUSED)
4943 {
4944    return EINA_FALSE;
4945 }
4946 
4947 EOLIAN static Eina_Bool
_efl_ui_widget_on_access_activate(Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * _pd EINA_UNUSED,Efl_Ui_Activate act EINA_UNUSED)4948 _efl_ui_widget_on_access_activate(Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *_pd EINA_UNUSED, Efl_Ui_Activate act EINA_UNUSED)
4949 {
4950    WRN("The %s widget does not implement the \"activate\" functions.",
4951        efl_class_name_get(efl_class_get(obj)));
4952    return EINA_TRUE;
4953 }
4954 
4955 EOLIAN static void
_efl_ui_widget_class_constructor(Efl_Class * klass)4956 _efl_ui_widget_class_constructor(Efl_Class *klass)
4957 {
4958    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
4959 }
4960 
4961 EOLIAN static Eina_Bool
_efl_ui_widget_efl_access_component_focus_grab(Eo * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)4962 _efl_ui_widget_efl_access_component_focus_grab(Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
4963 {
4964    if (elm_object_focus_allow_get(obj))
4965      {
4966        Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
4967        if (!ee) return EINA_FALSE;
4968        ecore_evas_activate(ee);
4969        elm_object_focus_set(obj, EINA_TRUE);
4970        return EINA_TRUE;
4971      }
4972    return EINA_FALSE;
4973 }
4974 
4975 EOLIAN static const char*
_efl_ui_widget_efl_access_object_i18n_name_get(const Eo * obj,Elm_Widget_Smart_Data * _pd EINA_UNUSED)4976 _efl_ui_widget_efl_access_object_i18n_name_get(const Eo *obj, Elm_Widget_Smart_Data *_pd EINA_UNUSED)
4977 {
4978    const char *ret, *name;
4979    name = efl_access_object_i18n_name_get(efl_super(obj, EFL_UI_WIDGET_CLASS));
4980 
4981    if (name) return name;
4982 
4983    ret = elm_object_text_get(obj);
4984    if (!ret) return NULL;
4985 
4986    return _elm_widget_accessible_plain_name_get(obj, ret);
4987 }
4988 
4989 EOLIAN static Eina_List*
_efl_ui_widget_efl_access_object_access_children_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * pd)4990 _efl_ui_widget_efl_access_object_access_children_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd)
4991 {
4992    Eina_List *accs = NULL;
4993    Evas_Object *widget;
4994    Efl_Access_Type type;
4995 
4996    for (unsigned int i = 0; i < eina_array_count(pd->children); ++i)
4997      {
4998         widget = eina_array_data_get(pd->children, i);
4999 
5000         if (!elm_object_widget_check(widget)) continue;
5001         if (!efl_isa(widget, EFL_ACCESS_OBJECT_MIXIN)) continue;
5002         type = efl_access_object_access_type_get(widget);
5003         if (type == EFL_ACCESS_TYPE_DISABLED) continue;
5004         if (type == EFL_ACCESS_TYPE_SKIPPED)
5005           {
5006              Eina_List *children;
5007              children = efl_access_object_access_children_get(widget);
5008              accs = eina_list_merge(accs, children);
5009              continue;
5010           }
5011         accs = eina_list_append(accs, widget);
5012      }
5013    return accs;
5014 }
5015 
5016 EOLIAN static Efl_Access_State_Set
_efl_ui_widget_efl_access_object_state_set_get(const Eo * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)5017 _efl_ui_widget_efl_access_object_state_set_get(const Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
5018 {
5019    Efl_Access_State_Set states = 0;
5020 
5021    states = efl_access_object_state_set_get(efl_super(obj, EFL_UI_WIDGET_CLASS));
5022 
5023    if (evas_object_visible_get(obj))
5024      {
5025         STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_VISIBLE);
5026         if (_elm_widget_onscreen_is(obj))
5027           STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_SHOWING);
5028      }
5029    if (!elm_widget_child_can_focus_get(obj))
5030      {
5031         if (elm_object_focus_allow_get(obj))
5032           STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_FOCUSABLE);
5033         if (elm_object_focus_get(obj))
5034           STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_FOCUSED);
5035      }
5036    if (!elm_object_disabled_get(obj))
5037      {
5038         STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_ENABLED);
5039         STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_SENSITIVE);
5040      }
5041 
5042    return states;
5043 }
5044 
5045 EOLIAN static Eina_List*
_efl_ui_widget_efl_access_object_attributes_get(const Eo * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)5046 _efl_ui_widget_efl_access_object_attributes_get(const Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
5047 {
5048    const char *type = NULL;
5049    const char *style = NULL;
5050    Eina_List *attr_list = NULL;
5051    Efl_Access_Attribute *attr = NULL;
5052 
5053    attr_list = efl_access_object_attributes_get(efl_super(obj, EFL_UI_WIDGET_CLASS));
5054 
5055    //Add type and style information in addition.
5056    type = elm_widget_type_get(obj);
5057    if (type)
5058      {
5059         attr = calloc(1, sizeof(Efl_Access_Attribute));
5060         if (attr)
5061           {
5062              attr->key = eina_stringshare_add("type");
5063              attr->value = eina_stringshare_add(type);
5064              attr_list = eina_list_append(attr_list, attr);
5065            }
5066      }
5067 
5068    style = elm_widget_style_get(obj);
5069    if (style)
5070      {
5071         attr = calloc(1, sizeof(Efl_Access_Attribute));
5072         if (attr)
5073           {
5074              attr->key = eina_stringshare_add("style");
5075              attr->value = eina_stringshare_add(style);
5076              attr_list = eina_list_append(attr_list, attr);
5077           }
5078      }
5079 
5080    return attr_list;
5081 }
5082 
5083 EOLIAN static Eina_List *
_elm_widget_item_efl_access_object_attributes_get(const Eo * eo_item,Elm_Widget_Item_Data * pd EINA_UNUSED)5084 _elm_widget_item_efl_access_object_attributes_get(const Eo *eo_item, Elm_Widget_Item_Data *pd  EINA_UNUSED)
5085 {
5086    const char *style = NULL;
5087    Eina_List *attr_list = NULL;
5088    Efl_Access_Attribute *attr = NULL;
5089 
5090    attr_list = efl_access_object_attributes_get(efl_super(eo_item, ELM_WIDGET_ITEM_CLASS));
5091 
5092    style = elm_object_item_style_get(eo_item);
5093    if (style)
5094      {
5095         attr = calloc(1, sizeof(Efl_Access_Attribute));
5096         if (attr)
5097           {
5098              attr->key = eina_stringshare_add("style");
5099              attr->value = eina_stringshare_add(style);
5100              attr_list = eina_list_append(attr_list, attr);
5101           }
5102      }
5103    return attr_list;
5104 }
5105 
5106 EOLIAN static Eina_Rect
_elm_widget_item_efl_access_component_extents_get(const Eo * obj EINA_UNUSED,Elm_Widget_Item_Data * sd EINA_UNUSED,Eina_Bool screen_coords)5107 _elm_widget_item_efl_access_component_extents_get(const Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords)
5108 {
5109    Eina_Rect r = EINA_RECT(-1, -1, -1, -1);
5110    int ee_x, ee_y;
5111 
5112    if (!sd->view) return r;
5113 
5114    r = efl_gfx_entity_geometry_get(sd->view);
5115    if (screen_coords)
5116      {
5117         Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(sd->view));
5118         if (ee)
5119           {
5120              ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
5121              r.x += ee_x;
5122              r.y += ee_y;
5123           }
5124      }
5125    return r;
5126 }
5127 
5128 EOLIAN static Eina_Bool
_elm_widget_item_efl_access_component_extents_set(Eo * obj EINA_UNUSED,Elm_Widget_Item_Data * sd EINA_UNUSED,Eina_Bool screen_coords EINA_UNUSED,Eina_Rect r EINA_UNUSED)5129 _elm_widget_item_efl_access_component_extents_set(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *sd EINA_UNUSED, Eina_Bool screen_coords EINA_UNUSED, Eina_Rect r EINA_UNUSED)
5130 {
5131    return EINA_FALSE;
5132 }
5133 
5134 EOLIAN static Eina_Bool
_elm_widget_item_efl_access_component_focus_grab(Eo * obj EINA_UNUSED,Elm_Widget_Item_Data * _pd EINA_UNUSED)5135 _elm_widget_item_efl_access_component_focus_grab(Eo *obj EINA_UNUSED, Elm_Widget_Item_Data *_pd EINA_UNUSED)
5136 {
5137    elm_object_item_focus_set(obj, EINA_TRUE);
5138    return elm_object_item_focus_get(obj);
5139 }
5140 
5141 EOLIAN static Efl_Object *
_efl_ui_widget_efl_object_provider_find(const Eo * obj,Elm_Widget_Smart_Data * pd,const Efl_Object * klass)5142 _efl_ui_widget_efl_object_provider_find(const Eo *obj, Elm_Widget_Smart_Data *pd, const Efl_Object *klass)
5143 {
5144    Efl_Object *lookup = NULL;
5145 
5146    if ((klass == EFL_CONFIG_INTERFACE) || (klass == EFL_CONFIG_GLOBAL_CLASS))
5147      return _efl_config_obj;
5148 
5149    if (klass == EFL_UI_WIN_CLASS)
5150      {
5151         if (pd->window)
5152           return pd->window;
5153         //let the parent_obj lookup handle this
5154      }
5155 
5156    if (klass == EFL_ACCESS_OBJECT_MIXIN)
5157      {
5158         Efl_Access_Type type = efl_access_object_access_type_get(obj);
5159         if (type != EFL_ACCESS_TYPE_SKIPPED)
5160           return (Eo*)obj;
5161      }
5162 
5163    if (pd->provider_lookup) return NULL;
5164    pd->provider_lookup = EINA_TRUE;
5165 
5166    lookup = efl_provider_find(efl_super(obj, MY_CLASS), klass);
5167    if (!lookup && pd->parent_obj) lookup = efl_provider_find(pd->parent_obj, klass);
5168 
5169    pd->provider_lookup = EINA_FALSE;
5170 
5171    return lookup;
5172 }
5173 
5174 EOLIAN static Efl_Ui_Focus_Manager*
_efl_ui_widget_efl_ui_focus_object_focus_parent_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * pd EINA_UNUSED)5175 _efl_ui_widget_efl_ui_focus_object_focus_parent_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED)
5176 {
5177    return pd->focus.parent;
5178 }
5179 
5180 EOLIAN static Efl_Ui_Focus_Manager*
_efl_ui_widget_efl_ui_focus_object_focus_manager_get(const Eo * obj EINA_UNUSED,Elm_Widget_Smart_Data * pd EINA_UNUSED)5181 _efl_ui_widget_efl_ui_focus_object_focus_manager_get(const Eo *obj EINA_UNUSED, Elm_Widget_Smart_Data *pd EINA_UNUSED)
5182 {
5183    return pd->focus.manager;
5184 }
5185 
5186 EOLIAN static Eina_Rect
_efl_ui_widget_efl_ui_focus_object_focus_geometry_get(const Eo * obj,Elm_Widget_Smart_Data * pd EINA_UNUSED)5187 _efl_ui_widget_efl_ui_focus_object_focus_geometry_get(const Eo *obj, Elm_Widget_Smart_Data *pd EINA_UNUSED)
5188 {
5189    return efl_gfx_entity_geometry_get(obj);
5190 }
5191 
5192 EOLIAN static void
_efl_ui_widget_efl_ui_focus_object_focus_set(Eo * obj,Elm_Widget_Smart_Data * pd,Eina_Bool focus)5193 _efl_ui_widget_efl_ui_focus_object_focus_set(Eo *obj, Elm_Widget_Smart_Data *pd, Eina_Bool focus)
5194 {
5195    pd->focused = focus;
5196 
5197    efl_ui_focus_object_focus_set(efl_super(obj, MY_CLASS), focus);
5198 
5199    efl_ui_focus_object_on_focus_update(obj);
5200 }
5201 
5202 /* Legacy APIs */
5203 
5204 EAPI void
elm_widget_on_show_region_hook_set(Eo * obj,void * data,Elm_Widget_On_Show_Region_Cb func,Eina_Free_Cb func_free_cb)5205 elm_widget_on_show_region_hook_set(Eo *obj, void *data, Elm_Widget_On_Show_Region_Cb func, Eina_Free_Cb func_free_cb)
5206 {
5207    ELM_WIDGET_DATA_GET(obj, sd);
5208 
5209    if (!sd) return;
5210    if ((sd->on_show_region_data == data) && (sd->on_show_region == func))
5211      return;
5212 
5213    if (sd->on_show_region_data && sd->on_show_region_data_free)
5214      sd->on_show_region_data_free(sd->on_show_region_data);
5215 
5216    sd->on_show_region = func;
5217    sd->on_show_region_data = data;
5218    sd->on_show_region_data_free = func_free_cb;
5219 }
5220 
5221 EAPI void
elm_widget_show_region_set(Eo * obj,Eina_Rect sr,Eina_Bool forceshow)5222 elm_widget_show_region_set(Eo *obj, Eina_Rect sr, Eina_Bool forceshow)
5223 {
5224    Evas_Object *parent_obj, *child_obj;
5225    Evas_Coord px, py, cx, cy, nx = 0, ny = 0;
5226 
5227    ELM_WIDGET_DATA_GET_OR_RETURN(obj, sd);
5228 
5229    evas_smart_objects_calculate(evas_object_evas_get(obj));
5230 
5231    if (!forceshow && eina_rectangle_equal(&sr.rect, &sd->show_region.rect)) return;
5232 
5233    sd->show_region = sr;
5234    if (sd->on_show_region)
5235      {
5236         sd->on_show_region(sd->on_show_region_data, obj, sr);
5237 
5238         if (_elm_scrollable_is(obj))
5239           {
5240              if (elm_widget_is_legacy(obj))
5241                {
5242                   elm_interface_scrollable_content_pos_get(obj, &nx, &ny);
5243                   sr.x -= nx;
5244                   sr.y -= ny;
5245                }
5246              else
5247                {
5248                   Eina_Position2D pos;
5249                   pos = efl_ui_scrollable_content_pos_get(obj);
5250                   sr.x -= pos.x;
5251                   sr.y -= pos.y;
5252                }
5253           }
5254      }
5255    child_obj = obj;
5256    do
5257      {
5258         parent_obj = sd->parent_obj;
5259         if ((!parent_obj)) break;
5260         sd = efl_data_scope_get(parent_obj, MY_CLASS);
5261         if (!sd) break;
5262 
5263         evas_object_geometry_get(parent_obj, &px, &py, NULL, NULL);
5264         evas_object_geometry_get(child_obj, &cx, &cy, NULL, NULL);
5265 
5266         sr.x += (cx - px);
5267         sr.y += (cy - py);
5268         sd->show_region = sr;
5269 
5270         if (sd->on_show_region)
5271           sd->on_show_region(sd->on_show_region_data, parent_obj, sr);
5272         child_obj = parent_obj;
5273      }
5274    while (parent_obj);
5275 }
5276 
5277 EAPI Eina_Rect
elm_widget_show_region_get(const Eo * obj)5278 elm_widget_show_region_get(const Eo *obj)
5279 {
5280    ELM_WIDGET_DATA_GET_OR_RETURN(obj, sd, EINA_RECT_EMPTY());
5281    return (Eina_Rect) sd->show_region;
5282 }
5283 /* elm_object_content_xxx APIs are supposed to work on all objects for which
5284  * elm_object_widget_check() returns true. The below checks avoid printing out
5285  * undesired ERR messages. */
5286 EAPI void
elm_widget_content_part_set(Evas_Object * obj,const char * part,Evas_Object * content)5287 elm_widget_content_part_set(Evas_Object *obj, const char *part, Evas_Object *content)
5288 {
5289    ELM_WIDGET_CHECK(obj);
5290    if (efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
5291      {
5292         elm_layout_content_set(obj, part, content);
5293         return;
5294      }
5295    if (!efl_isa(obj, EFL_PART_INTERFACE)) return;
5296    if (!part)
5297      {
5298         part = efl_ui_widget_default_content_part_get(obj);
5299         if (!part) return;
5300      }
5301    efl_content_set(efl_part(obj, part), content);
5302 }
5303 
5304 EAPI Evas_Object *
elm_widget_content_part_get(const Evas_Object * obj,const char * part)5305 elm_widget_content_part_get(const Evas_Object *obj, const char *part)
5306 {
5307    ELM_WIDGET_CHECK(obj) NULL;
5308    if (efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
5309      return elm_layout_content_get(obj, part);
5310    if (!efl_isa(obj, EFL_PART_INTERFACE)) return NULL;
5311    if (!part)
5312      {
5313         part = efl_ui_widget_default_content_part_get(obj);
5314         if (!part) return NULL;
5315      }
5316    return efl_content_get(efl_part(obj, part));
5317 }
5318 
5319 EAPI Evas_Object *
elm_widget_content_part_unset(Evas_Object * obj,const char * part)5320 elm_widget_content_part_unset(Evas_Object *obj, const char *part)
5321 {
5322    ELM_WIDGET_CHECK(obj) NULL;
5323    if (efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
5324      return elm_layout_content_unset(obj, part);
5325    if (!efl_isa(obj, EFL_PART_INTERFACE)) return NULL;
5326    if (!part)
5327      {
5328         part = efl_ui_widget_default_content_part_get(obj);
5329         if (!part) return NULL;
5330      }
5331    return efl_content_unset(efl_part(obj, part));
5332 }
5333 
5334 EAPI void
elm_widget_signal_emit(Eo * obj,const char * emission,const char * source)5335 elm_widget_signal_emit(Eo *obj, const char *emission, const char *source)
5336 {
5337    ELM_WIDGET_CHECK(obj);
5338 
5339    if (efl_isa(obj, EFL_UI_LAYOUT_BASE_CLASS))
5340      elm_layout_signal_emit(obj, emission, source);
5341    else if (evas_object_smart_type_check(obj, "elm_icon"))
5342      {
5343         WRN("Deprecated function. This functionality on icon objects"
5344             " will be dropped on a next release.");
5345         _elm_icon_signal_emit(obj, emission, source);
5346      }
5347 }
5348 
5349 EAPI void
elm_widget_signal_callback_add(Eo * obj,const char * emission,const char * source,Edje_Signal_Cb func,void * data)5350 elm_widget_signal_callback_add(Eo *obj, const char *emission, const char *source, Edje_Signal_Cb func, void *data)
5351 {
5352    ELM_WIDGET_CHECK(obj);
5353    EINA_SAFETY_ON_NULL_RETURN(func);
5354    if (evas_object_smart_type_check(obj, "elm_layout"))
5355      elm_layout_signal_callback_add(obj, emission, source, func, data);
5356    else if (evas_object_smart_type_check(obj, "elm_icon"))
5357      {
5358         WRN("Deprecated function. This functionality on icon objects"
5359             " will be dropped on a next release.");
5360 
5361         _elm_icon_signal_callback_add(obj, emission, source, func, data);
5362      }
5363 }
5364 
5365 EAPI void *
elm_widget_signal_callback_del(Eo * obj,const char * emission,const char * source,Edje_Signal_Cb func)5366 elm_widget_signal_callback_del(Eo *obj, const char *emission, const char *source, Edje_Signal_Cb func)
5367 {
5368    void *data = NULL;
5369 
5370    ELM_WIDGET_CHECK(obj) NULL;
5371    EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
5372    if (evas_object_smart_type_check(obj, "elm_layout"))
5373      data = elm_layout_signal_callback_del(obj, emission, source, func);
5374    else if (evas_object_smart_type_check(obj, "elm_icon"))
5375      {
5376         WRN("Deprecated function. This functionality on icon objects"
5377             " will be dropped on a next release.");
5378 
5379         data = _elm_icon_signal_callback_del(obj, emission, source, func);
5380      }
5381 
5382    return data;
5383 }
5384 
5385 
5386 /* Widget Shadow Begin */
5387 
5388 typedef struct _Widget_Shadow
5389 {
5390    Eo *widget;
5391    Eo *surface;
5392    struct {
5393       double rx, ry, ox, oy, grow;
5394       int r, g, b, a;
5395    } props;
5396    Eina_Stringshare *code, *name;
5397 } Widget_Shadow;
5398 
5399 static void _widget_shadow_update(Widget_Shadow *shadow);
5400 
5401 static void
_widget_shadow_del_cb(void * data,const Efl_Event * ev EINA_UNUSED)5402 _widget_shadow_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
5403 {
5404    Widget_Shadow *shadow = data;
5405 
5406    efl_del(shadow->surface);
5407    free(shadow);
5408 }
5409 
5410 static void
_widget_shadow_event_cb(void * data,const Efl_Event * ev EINA_UNUSED)5411 _widget_shadow_event_cb(void *data, const Efl_Event *ev EINA_UNUSED)
5412 {
5413    Widget_Shadow *shadow = data;
5414    _widget_shadow_update(shadow);
5415 }
5416 
5417 EFL_CALLBACKS_ARRAY_DEFINE(widget_shadow_cb,
5418 { EFL_EVENT_DEL, _widget_shadow_del_cb },
5419 { EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _widget_shadow_event_cb },
5420 { EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _widget_shadow_event_cb },
5421 { EFL_GFX_ENTITY_EVENT_STACKING_CHANGED, _widget_shadow_event_cb },
5422 { EFL_GFX_ENTITY_EVENT_VISIBILITY_CHANGED, _widget_shadow_event_cb });
5423 
5424 static Widget_Shadow *
_widget_shadow_part_get(const Eo * part_obj)5425 _widget_shadow_part_get(const Eo *part_obj)
5426 {
5427    Elm_Part_Data *pd = efl_data_scope_get(part_obj, EFL_UI_WIDGET_PART_CLASS);
5428    Widget_Shadow *shadow;
5429    Eo *widget = pd->obj;
5430 
5431    shadow = efl_key_data_get(widget, "__elm_shadow");
5432    if (!shadow)
5433      {
5434         shadow = calloc(1, sizeof(*shadow));
5435         if (!shadow) return NULL;
5436         shadow->widget = pd->obj;
5437         efl_key_data_set(widget, "__elm_shadow", shadow);
5438         efl_event_callback_array_add(widget, widget_shadow_cb(), shadow);
5439      }
5440    return shadow;
5441 }
5442 
5443 static void
_widget_shadow_update(Widget_Shadow * ws)5444 _widget_shadow_update(Widget_Shadow *ws)
5445 {
5446    int l = 0, r = 0, t = 0, b = 0;
5447    Eina_Rect srect, wrect;
5448    char filter[1024];
5449 
5450 #define FILTER_FMT \
5451    "a = buffer { 'alpha' }" \
5452    "grow { %f, dst = a, alphaonly = true }" \
5453    "blur { src = a, rx = %f, ry = %f, color = color(%d,%d,%d,%d) }"
5454 
5455    if (!ws->surface)
5456      {
5457         ws->surface = efl_add(EFL_CANVAS_PROXY_CLASS, ws->widget);
5458         efl_gfx_fill_auto_set(ws->surface, 1);
5459         efl_canvas_proxy_source_clip_set(ws->surface, EINA_FALSE);
5460         efl_canvas_proxy_source_events_set(ws->surface, EINA_FALSE);
5461         efl_canvas_proxy_source_set(ws->surface, ws->widget);
5462      }
5463 
5464    if (!ws->code)
5465      {
5466         snprintf(filter, sizeof(filter), FILTER_FMT,
5467                  ws->props.grow, ws->props.rx, ws->props.ry,
5468                  ws->props.r, ws->props.g, ws->props.b, ws->props.a);
5469      }
5470 
5471    efl_gfx_filter_program_set(ws->surface,
5472                               ws->code ? ws->code : filter,
5473                               ws->name ? ws->name : "shadow");
5474    efl_gfx_filter_padding_get(ws->surface, &l, &r, &t, &b);
5475 
5476    wrect = efl_gfx_entity_geometry_get(ws->widget);
5477    srect.x = wrect.x + (int) (-l + ws->props.ox);
5478    srect.y = wrect.y + (int) (-t + ws->props.oy);
5479    srect.w = wrect.w + (int) (l + r);
5480    srect.h = wrect.h + (int) (t + b);
5481 
5482    if ((!ws->props.a && !ws->code) ||
5483        !efl_gfx_entity_visible_get(ws->widget))
5484      {
5485         efl_gfx_entity_visible_set(ws->surface, EINA_FALSE);
5486         return;
5487      }
5488 
5489    efl_canvas_object_clipper_set(ws->surface, efl_canvas_object_clipper_get(ws->widget));
5490    efl_canvas_group_member_add(efl_canvas_object_render_parent_get(ws->widget), ws->surface);
5491    efl_gfx_entity_geometry_set(ws->surface, srect);
5492    efl_gfx_stack_below(ws->surface, ws->widget);
5493    efl_gfx_entity_visible_set(ws->surface, EINA_TRUE);
5494 }
5495 
5496 static void
_elm_widget_shadow_update(Efl_Ui_Widget * obj)5497 _elm_widget_shadow_update(Efl_Ui_Widget *obj)
5498 {
5499    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5500    _widget_shadow_update(shadow);
5501 }
5502 
5503 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_blur_offset_set(Eo * obj,void * _pd EINA_UNUSED,double ox,double oy)5504 _efl_ui_widget_part_shadow_efl_gfx_blur_offset_set(Eo *obj, void *_pd EINA_UNUSED, double ox, double oy)
5505 {
5506    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5507    shadow->props.ox = ox;
5508    shadow->props.oy = oy;
5509    _widget_shadow_update(shadow);
5510 }
5511 
5512 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_blur_offset_get(const Eo * obj,void * _pd EINA_UNUSED,double * ox,double * oy)5513 _efl_ui_widget_part_shadow_efl_gfx_blur_offset_get(const Eo *obj, void *_pd EINA_UNUSED, double *ox, double *oy)
5514 {
5515    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5516    if (ox) *ox = shadow->props.ox;
5517    if (oy) *oy = shadow->props.oy;
5518 }
5519 
5520 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_blur_radius_set(Eo * obj,void * _pd EINA_UNUSED,double rx,double ry)5521 _efl_ui_widget_part_shadow_efl_gfx_blur_radius_set(Eo *obj, void *_pd EINA_UNUSED, double rx, double ry)
5522 {
5523    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5524    shadow->props.rx = rx;
5525    shadow->props.ry = ry;
5526    _widget_shadow_update(shadow);
5527 }
5528 
5529 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_blur_radius_get(const Eo * obj,void * _pd EINA_UNUSED,double * rx,double * ry)5530 _efl_ui_widget_part_shadow_efl_gfx_blur_radius_get(const Eo *obj, void *_pd EINA_UNUSED, double *rx, double *ry)
5531 {
5532    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5533    if (rx) *rx = shadow->props.rx;
5534    if (ry) *ry = shadow->props.ry;
5535 }
5536 
5537 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_color_color_set(Eo * obj,void * _pd EINA_UNUSED,int r,int g,int b,int a)5538 _efl_ui_widget_part_shadow_efl_gfx_color_color_set(Eo *obj, void *_pd EINA_UNUSED, int r, int g, int b, int a)
5539 {
5540    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5541    shadow->props.r = r;
5542    shadow->props.g = g;
5543    shadow->props.b = b;
5544    shadow->props.a = a;
5545    _widget_shadow_update(shadow);
5546 }
5547 
5548 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_color_color_get(const Eo * obj,void * _pd EINA_UNUSED,int * r,int * g,int * b,int * a)5549 _efl_ui_widget_part_shadow_efl_gfx_color_color_get(const Eo *obj, void *_pd EINA_UNUSED, int *r, int *g, int *b, int *a)
5550 {
5551    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5552    if (r) *r = shadow->props.r;
5553    if (g) *g = shadow->props.g;
5554    if (b) *b = shadow->props.b;
5555    if (a) *a = shadow->props.a;
5556 }
5557 
5558 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_blur_grow_set(Eo * obj,void * _pd EINA_UNUSED,double radius)5559 _efl_ui_widget_part_shadow_efl_gfx_blur_grow_set(Eo *obj, void *_pd EINA_UNUSED, double radius)
5560 {
5561    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5562    shadow->props.grow = radius;
5563    _widget_shadow_update(shadow);
5564 }
5565 
5566 EOLIAN static double
_efl_ui_widget_part_shadow_efl_gfx_blur_grow_get(const Eo * obj,void * _pd EINA_UNUSED)5567 _efl_ui_widget_part_shadow_efl_gfx_blur_grow_get(const Eo *obj, void *_pd EINA_UNUSED)
5568 {
5569    Widget_Shadow *shadow = _widget_shadow_part_get(obj);
5570    return shadow->props.grow;
5571 }
5572 
5573 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_program_set(Eo * obj,void * _pd EINA_UNUSED,const char * code,const char * name)5574 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_program_set(Eo *obj, void *_pd EINA_UNUSED, const char *code, const char *name)
5575 {
5576    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5577    eina_stringshare_replace(&ws->code, code);
5578    eina_stringshare_replace(&ws->name, name);
5579    _widget_shadow_update(ws);
5580 }
5581 
5582 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_program_get(const Eo * obj,void * _pd EINA_UNUSED,const char ** code,const char ** name)5583 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_program_get(const Eo *obj, void *_pd EINA_UNUSED, const char **code, const char **name)
5584 {
5585    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5586    efl_gfx_filter_program_get(ws->surface, code, name);
5587 }
5588 
5589 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_source_set(Eo * obj,void * _pd EINA_UNUSED,const char * name,Efl_Gfx_Entity * source)5590 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_source_set(Eo *obj, void *_pd EINA_UNUSED, const char *name, Efl_Gfx_Entity *source)
5591 {
5592    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5593    _widget_shadow_update(ws);
5594    efl_gfx_filter_source_set(ws->surface, name, source);
5595 }
5596 
5597 EOLIAN static Efl_Gfx_Entity *
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_source_get(const Eo * obj,void * _pd EINA_UNUSED,const char * name)5598 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_source_get(const Eo *obj, void *_pd EINA_UNUSED, const char *name)
5599 {
5600    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5601    return efl_gfx_filter_source_get(ws->surface, name);
5602 }
5603 
5604 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_data_set(Eo * obj,void * _pd EINA_UNUSED,const char * name,const char * value,Eina_Bool execute)5605 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_data_set(Eo *obj, void *_pd EINA_UNUSED, const char *name, const char *value, Eina_Bool execute)
5606 {
5607    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5608    _widget_shadow_update(ws);
5609    efl_gfx_filter_data_set(ws->surface, name, value, execute);
5610 }
5611 
5612 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_data_get(const Eo * obj,void * _pd EINA_UNUSED,const char * name,const char ** value,Eina_Bool * execute)5613 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_data_get(const Eo *obj, void *_pd EINA_UNUSED, const char *name, const char **value, Eina_Bool *execute)
5614 {
5615    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5616    efl_gfx_filter_data_get(ws->surface, name, value, execute);
5617 }
5618 
5619 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_padding_get(const Eo * obj,void * _pd EINA_UNUSED,int * l,int * r,int * t,int * b)5620 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_padding_get(const Eo *obj, void *_pd EINA_UNUSED, int *l, int *r, int *t, int *b)
5621 {
5622    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5623    efl_gfx_filter_padding_get(ws->surface, l, r, t, b);
5624 }
5625 
5626 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_state_set(Eo * obj,void * _pd EINA_UNUSED,const char * cur_state,double cur_val,const char * next_state,double next_val,double pos)5627 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_state_set(Eo *obj, void *_pd EINA_UNUSED, const char *cur_state, double cur_val, const char *next_state, double next_val, double pos)
5628 {
5629    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5630    efl_gfx_filter_state_set(ws->surface, cur_state, cur_val, next_state, next_val, pos);
5631 }
5632 
5633 EOLIAN static void
_efl_ui_widget_part_shadow_efl_gfx_filter_filter_state_get(const Eo * obj,void * _pd EINA_UNUSED,const char ** cur_state,double * cur_val,const char ** next_state,double * next_val,double * pos)5634 _efl_ui_widget_part_shadow_efl_gfx_filter_filter_state_get(const Eo *obj, void *_pd EINA_UNUSED, const char **cur_state, double *cur_val, const char **next_state, double *next_val, double *pos)
5635 {
5636    Widget_Shadow *ws = _widget_shadow_part_get(obj);
5637    efl_gfx_filter_state_get(ws->surface, cur_state, cur_val, next_state, next_val, pos);
5638 }
5639 
5640 #include "efl_ui_widget_part_shadow.eo.c"
5641 
5642 /* Widget Shadow End */
5643 
5644 
5645 /* Efl.Part implementation */
5646 
5647 EOLIAN static Efl_Object *
_efl_ui_widget_efl_part_part_get(const Eo * obj,Elm_Widget_Smart_Data * wd EINA_UNUSED,const char * part)5648 _efl_ui_widget_efl_part_part_get(const Eo *obj, Elm_Widget_Smart_Data *wd EINA_UNUSED, const char *part)
5649 {
5650    if (eina_streq(part, "background"))
5651      return ELM_PART_IMPLEMENT(EFL_UI_WIDGET_PART_BG_CLASS, obj, part);
5652    else if (eina_streq(part, "shadow"))
5653      return ELM_PART_IMPLEMENT(EFL_UI_WIDGET_PART_SHADOW_CLASS, obj, part);
5654    return ELM_PART_IMPLEMENT(EFL_UI_WIDGET_PART_CLASS, obj, part);
5655 }
5656 
5657 EOLIAN static void \
_efl_ui_widget_part_efl_object_destructor(Eo * obj,Elm_Part_Data * pd)5658 _efl_ui_widget_part_efl_object_destructor(Eo *obj, Elm_Part_Data *pd)
5659 {
5660    ELM_PART_HOOK;
5661    eina_tmpstr_del(pd->part);
5662    efl_destructor(efl_super(obj, EFL_UI_WIDGET_PART_CLASS));
5663 }
5664 
5665 static Efl_Canvas_Layout_Part_Type
_efl_ui_widget_part_efl_canvas_layout_part_type_provider_part_type_get(const Eo * obj EINA_UNUSED,Elm_Part_Data * pd)5666 _efl_ui_widget_part_efl_canvas_layout_part_type_provider_part_type_get(const Eo *obj EINA_UNUSED, Elm_Part_Data *pd)
5667 {
5668    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(pd->obj, MY_CLASS);
5669    EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EFL_CANVAS_LAYOUT_PART_TYPE_NONE);
5670    return efl_canvas_layout_part_type_get(efl_part(sd->resize_obj, pd->part));
5671 }
5672 
5673 static Eina_Rect
_efl_ui_widget_part_efl_gfx_entity_geometry_get(const Eo * obj EINA_UNUSED,Elm_Part_Data * pd)5674 _efl_ui_widget_part_efl_gfx_entity_geometry_get(const Eo *obj EINA_UNUSED, Elm_Part_Data *pd)
5675 {
5676    Elm_Widget_Smart_Data *sd = efl_data_scope_safe_get(pd->obj, MY_CLASS);
5677    EINA_SAFETY_ON_NULL_RETURN_VAL(sd, EINA_RECT_EMPTY());
5678    return efl_gfx_entity_geometry_get(efl_part(sd->resize_obj, pd->part));
5679 }
5680 
5681 static Eina_Error
_efl_ui_widget_part_efl_ui_property_bind_property_bind(Eo * obj,Elm_Part_Data * ppd,const char * key,const char * property)5682 _efl_ui_widget_part_efl_ui_property_bind_property_bind(Eo *obj, Elm_Part_Data *ppd,
5683                                                        const char *key, const char *property)
5684 {
5685    Efl_Ui_Widget_Data *pd;
5686    Eo *widget;
5687 
5688    widget = efl_parent_get(obj);
5689    pd = efl_data_scope_get(widget, EFL_UI_WIDGET_CLASS);
5690 
5691    return _efl_ui_property_bind(widget, obj, pd, ppd->part, key, property);
5692 }
5693 
5694 #include "efl_ui_widget_part.eo.c"
5695 
5696 /* Efl.Part end */
5697 
5698 /* Efl.Part Bg implementation */
5699 
5700 Efl_Canvas_Object *
_efl_ui_widget_bg_get(const Efl_Ui_Widget * obj)5701 _efl_ui_widget_bg_get(const Efl_Ui_Widget *obj)
5702 {
5703    Elm_Widget_Smart_Data *sd = efl_data_scope_get(obj, MY_CLASS);
5704    Evas_Object *bg_obj = sd->bg;
5705 
5706    if (!bg_obj)
5707      {
5708         /* XXX const */
5709         bg_obj = efl_add(EFL_UI_BG_CLASS, (Eo *)obj);
5710         EINA_SAFETY_ON_NULL_RETURN_VAL(bg_obj, NULL);
5711         sd->bg = bg_obj;
5712         efl_canvas_group_member_add((Eo *)obj, sd->bg);
5713         evas_object_stack_below(sd->bg, sd->resize_obj);
5714         _smart_reconfigure((Eo*)obj, sd);
5715      }
5716 
5717    return bg_obj;
5718 }
5719 
5720 static inline Efl_Canvas_Object *
efl_ui_widget_part_bg_get(const Eo * part_obj)5721 efl_ui_widget_part_bg_get(const Eo *part_obj)
5722 {
5723    Elm_Part_Data *pd = efl_data_scope_get(part_obj, EFL_UI_WIDGET_PART_CLASS);
5724    return _efl_ui_widget_bg_get(pd->obj);
5725 }
5726 
5727 EOLIAN static Eina_Error
_efl_ui_widget_part_bg_efl_file_load(Eo * obj,void * pd EINA_UNUSED)5728 _efl_ui_widget_part_bg_efl_file_load(Eo *obj, void *pd EINA_UNUSED)
5729 {
5730    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5731 
5732    return efl_file_load(bg_obj);
5733 }
5734 
5735 EOLIAN static void
_efl_ui_widget_part_bg_efl_file_unload(Eo * obj,void * pd EINA_UNUSED)5736 _efl_ui_widget_part_bg_efl_file_unload(Eo *obj, void *pd EINA_UNUSED)
5737 {
5738    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5739 
5740    efl_file_unload(bg_obj);
5741 }
5742 
5743 EOLIAN static const char *
_efl_ui_widget_part_bg_efl_file_file_get(const Eo * obj,void * pd EINA_UNUSED)5744 _efl_ui_widget_part_bg_efl_file_file_get(const Eo *obj, void *pd EINA_UNUSED)
5745 {
5746    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5747 
5748    return efl_file_get(bg_obj);
5749 }
5750 
5751 EOLIAN static Eina_Error
_efl_ui_widget_part_bg_efl_file_file_set(Eo * obj,void * pd EINA_UNUSED,const char * file)5752 _efl_ui_widget_part_bg_efl_file_file_set(Eo *obj, void *pd EINA_UNUSED, const char *file)
5753 {
5754    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5755 
5756    return efl_file_set(bg_obj, file);
5757 }
5758 
5759 EOLIAN static const char *
_efl_ui_widget_part_bg_efl_file_key_get(const Eo * obj,void * pd EINA_UNUSED)5760 _efl_ui_widget_part_bg_efl_file_key_get(const Eo *obj, void *pd EINA_UNUSED)
5761 {
5762    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5763 
5764    return efl_file_key_get(bg_obj);
5765 }
5766 
5767 EOLIAN static void
_efl_ui_widget_part_bg_efl_file_key_set(Eo * obj,void * pd EINA_UNUSED,const char * key)5768 _efl_ui_widget_part_bg_efl_file_key_set(Eo *obj, void *pd EINA_UNUSED, const char *key)
5769 {
5770    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5771 
5772    efl_file_key_set(bg_obj, key);
5773 }
5774 
5775 EOLIAN static const Eina_File *
_efl_ui_widget_part_bg_efl_file_mmap_get(const Eo * obj,void * pd EINA_UNUSED)5776 _efl_ui_widget_part_bg_efl_file_mmap_get(const Eo *obj, void *pd EINA_UNUSED)
5777 {
5778    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5779 
5780    return efl_file_mmap_get(bg_obj);
5781 }
5782 
5783 EOLIAN static Eina_Error
_efl_ui_widget_part_bg_efl_file_mmap_set(Eo * obj,void * pd EINA_UNUSED,const Eina_File * file)5784 _efl_ui_widget_part_bg_efl_file_mmap_set(Eo *obj, void *pd EINA_UNUSED, const Eina_File *file)
5785 {
5786    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5787 
5788    return efl_file_mmap_set(bg_obj, file);
5789 }
5790 
5791 EOLIAN static void
_efl_ui_widget_part_bg_efl_gfx_color_color_set(Eo * obj,void * pd EINA_UNUSED,int r,int g,int b,int a)5792 _efl_ui_widget_part_bg_efl_gfx_color_color_set(Eo *obj, void *pd EINA_UNUSED, int r, int g, int b, int a)
5793 {
5794    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5795 
5796    efl_gfx_color_set(bg_obj, r, g, b, a);
5797 }
5798 
5799 EOLIAN static void
_efl_ui_widget_part_bg_efl_gfx_color_color_get(const Eo * obj,void * pd EINA_UNUSED,int * r,int * g,int * b,int * a)5800 _efl_ui_widget_part_bg_efl_gfx_color_color_get(const Eo *obj, void *pd EINA_UNUSED, int *r, int *g, int *b, int *a)
5801 {
5802    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5803 
5804    efl_gfx_color_get(bg_obj, r, g, b, a);
5805 }
5806 
5807 EOLIAN static Efl_Object*
_efl_ui_widget_part_bg_efl_object_finalize(Eo * obj,void * pd EINA_UNUSED)5808 _efl_ui_widget_part_bg_efl_object_finalize(Eo *obj, void *pd EINA_UNUSED)
5809 {
5810    Evas_Object *bg_obj = efl_ui_widget_part_bg_get(obj);
5811 
5812    efl_composite_attach(obj, bg_obj);
5813 
5814    return efl_finalize(efl_super(obj, EFL_UI_WIDGET_PART_BG_CLASS));
5815 }
5816 
5817 
5818 typedef struct _Efl_Ui_Property_Bound Efl_Ui_Property_Bound;
5819 struct _Efl_Ui_Property_Bound
5820 {
5821    Eina_Stringshare *part; // Optional part to apply the property on
5822    Eina_Stringshare *key; // Local object property
5823    Eina_Stringshare *property; // Model property
5824    Eina_Future *f;
5825 };
5826 
5827 static void
_efl_ui_property_bind_free(void * data)5828 _efl_ui_property_bind_free(void *data)
5829 {
5830    Efl_Ui_Property_Bound *prop = data;
5831 
5832    eina_stringshare_del(prop->part);
5833    eina_stringshare_del(prop->key);
5834    eina_stringshare_del(prop->property);
5835    free(prop);
5836 }
5837 
5838 static void
_efl_ui_property_bind_clean(Eo * obj EINA_UNUSED,void * data,const Eina_Future * f EINA_UNUSED)5839 _efl_ui_property_bind_clean(Eo *obj EINA_UNUSED,
5840                             void *data,
5841                             const Eina_Future *f EINA_UNUSED)
5842 {
5843    Efl_Ui_Property_Bound *prop = data;
5844 
5845    prop->f = NULL;
5846 }
5847 
5848 static void
_efl_ui_property_bind_get(Eo * obj,Efl_Ui_Widget_Data * pd,Efl_Ui_Property_Bound * prop)5849 _efl_ui_property_bind_get(Eo *obj, Efl_Ui_Widget_Data *pd, Efl_Ui_Property_Bound *prop)
5850 {
5851    Eina_Value *value;
5852    Eina_Future *f;
5853    Eina_Error err;
5854    Eo *target;
5855 
5856    // If there is no model set yet, no need to try anything
5857    if (!pd->properties.model) return ;
5858 
5859    value = efl_model_property_get(pd->properties.model, prop->property);
5860    target = prop->part ? efl_part(obj, prop->part) : obj;
5861 
5862    err = efl_property_reflection_set(target, prop->key, eina_value_reference_copy(value));
5863    eina_value_free(value);
5864 
5865    if (!err) return ;
5866 
5867    // Report back the error to the model
5868    if (prop->f) eina_future_cancel(prop->f);
5869    f = efl_model_property_set(pd->properties.model, prop->property,
5870                               eina_value_error_new(err));
5871    prop->f = efl_future_then(obj, f, .free = _efl_ui_property_bind_clean, .data = prop);
5872 }
5873 
5874 static void
_efl_ui_property_bind_set(Eo * obj,Efl_Ui_Widget_Data * pd,Efl_Ui_Property_Bound * prop)5875 _efl_ui_property_bind_set(Eo *obj, Efl_Ui_Widget_Data *pd, Efl_Ui_Property_Bound *prop)
5876 {
5877    Eina_Value value;
5878    Eina_Future *f;
5879    Eo *target;
5880 
5881    target = prop->part ? efl_part(obj, prop->part) : obj;
5882    value = efl_property_reflection_get(target, prop->key);
5883 
5884    if (prop->f) eina_future_cancel(prop->f);
5885    f = efl_model_property_set(pd->properties.model, prop->property, eina_value_dup(&value));
5886    prop->f = efl_future_then(obj, f, .free = _efl_ui_property_bind_clean, .data = prop);
5887    eina_value_flush(&value);
5888 }
5889 
5890 static void
_efl_ui_model_property_bind_changed(void * data,const Efl_Event * event)5891 _efl_ui_model_property_bind_changed(void *data, const Efl_Event *event)
5892 {
5893    Efl_Model_Property_Event *evt = event->info;
5894    ELM_WIDGET_DATA_GET(data, pd);
5895    Eina_Array_Iterator it;
5896    const char *prop;
5897    unsigned int i;
5898 
5899    if (!pd) return;
5900    EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it)
5901      {
5902         Efl_Ui_Property_Bound *lookup;
5903 
5904         lookup = eina_hash_find(pd->properties.model_lookup, prop);
5905         if (lookup) _efl_ui_property_bind_get(data, pd, lookup);
5906      }
5907 }
5908 
5909 static void
_efl_ui_view_property_bind_changed(void * data,const Efl_Event * event)5910 _efl_ui_view_property_bind_changed(void *data, const Efl_Event *event)
5911 {
5912    Efl_Ui_Property_Event *evt = event->info;
5913    ELM_WIDGET_DATA_GET(data, pd);
5914    Eina_Array_Iterator it;
5915    Eina_Stringshare *prop;
5916    unsigned int i;
5917 
5918    if (!pd) return;
5919    EINA_ARRAY_ITER_NEXT(evt->changed_properties, i, prop, it)
5920      {
5921         Efl_Ui_Property_Bound *lookup;
5922 
5923         lookup = eina_hash_find(pd->properties.view_lookup, prop);
5924         if (lookup) _efl_ui_property_bind_set(data, pd, lookup);
5925      }
5926 }
5927 
5928 static void
_efl_ui_widget_model_update(Eo * obj,Efl_Ui_Widget_Data * pd)5929 _efl_ui_widget_model_update(Eo *obj, Efl_Ui_Widget_Data *pd)
5930 {
5931    Efl_Ui_Property_Bound *property;
5932    Eina_Iterator *it;
5933 
5934    it = eina_hash_iterator_data_new(pd->properties.model_lookup);
5935    EINA_ITERATOR_FOREACH(it, property)
5936      _efl_ui_property_bind_get(obj, pd, property);
5937    eina_iterator_free(it);
5938 }
5939 
5940 static void _efl_ui_widget_model_provider_model_change(void *data, const Efl_Event *event EINA_UNUSED);
5941 static void _efl_ui_widget_model_provider_invalidate(void *data, const Efl_Event *event EINA_UNUSED);
5942 
5943 EFL_CALLBACKS_ARRAY_DEFINE(efl_ui_widget_model_provider_callbacks,
5944                            { EFL_EVENT_INVALIDATE, _efl_ui_widget_model_provider_invalidate },
5945                            { EFL_UI_VIEW_EVENT_MODEL_CHANGED, _efl_ui_widget_model_provider_model_change });
5946 
5947 static void
_efl_ui_widget_model_provider_model_change(void * data,const Efl_Event * event)5948 _efl_ui_widget_model_provider_model_change(void *data, const Efl_Event *event)
5949 {
5950    ELM_WIDGET_DATA_GET(data, pd);
5951 
5952    if (!pd) return;
5953    efl_replace(&pd->properties.model,
5954                efl_ui_view_model_get(pd->properties.provider));
5955    _efl_ui_widget_model_update(data, pd);
5956 
5957    efl_event_callback_call(data, EFL_UI_VIEW_EVENT_MODEL_CHANGED, event->info);
5958 }
5959 
5960 static void
_efl_ui_widget_model_provider_invalidate(void * data,const Efl_Event * event EINA_UNUSED)5961 _efl_ui_widget_model_provider_invalidate(void *data, const Efl_Event *event EINA_UNUSED)
5962 {
5963    ELM_WIDGET_DATA_GET(data, pd);
5964 
5965    if (!pd) return;
5966    efl_event_callback_array_del(pd->properties.provider,
5967                                 efl_ui_widget_model_provider_callbacks(),
5968                                 data);
5969    efl_replace(&pd->properties.provider, NULL);
5970    efl_replace(&pd->properties.model, NULL);
5971    pd->properties.callback_to_provider = EINA_FALSE;
5972 }
5973 
5974 static void
_efl_ui_widget_model_register(Eo * obj,Efl_Ui_Widget_Data * pd)5975 _efl_ui_widget_model_register(Eo *obj, Efl_Ui_Widget_Data *pd)
5976 {
5977    if (pd->properties.registered) return ;
5978 
5979    if (!pd->properties.model)
5980      {
5981         Efl_Model_Changed_Event ev;
5982 
5983         efl_replace(&pd->properties.provider,
5984                     efl_provider_find(obj, EFL_MODEL_PROVIDER_CLASS));
5985         if (!pd->properties.provider) return ;
5986         if (!pd->properties.callback_to_provider)
5987           efl_event_callback_array_add(pd->properties.provider,
5988                                        efl_ui_widget_model_provider_callbacks(),
5989                                        obj);
5990         pd->properties.callback_to_provider = EINA_TRUE;
5991         efl_replace(&pd->properties.model,
5992                     efl_ui_view_model_get(pd->properties.provider));
5993 
5994         if (!pd->properties.model) return ;
5995 
5996         ev.current = pd->properties.model;
5997         ev.previous = NULL;
5998         efl_event_callback_call(obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, &ev);
5999      }
6000 
6001    if (!pd->properties.model) return ;
6002    if (!pd->properties.model_lookup) return ;
6003 
6004    efl_event_callback_add(pd->properties.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED,
6005                           _efl_ui_model_property_bind_changed, obj);
6006    efl_event_callback_add(obj, EFL_UI_PROPERTY_BIND_EVENT_PROPERTIES_CHANGED,
6007                           _efl_ui_view_property_bind_changed, obj);
6008    pd->properties.registered = EINA_TRUE;
6009 }
6010 
6011 static void
_efl_ui_widget_model_unregister(Eo * obj,Efl_Ui_Widget_Data * pd)6012 _efl_ui_widget_model_unregister(Eo *obj, Efl_Ui_Widget_Data *pd)
6013 {
6014    if (pd->properties.registered)
6015      {
6016         // Remove any existing handler that might exist for any reason
6017         efl_event_callback_del(pd->properties.model, EFL_MODEL_EVENT_PROPERTIES_CHANGED,
6018                                _efl_ui_model_property_bind_changed, obj);
6019         efl_event_callback_del(obj, EFL_UI_PROPERTY_BIND_EVENT_PROPERTIES_CHANGED,
6020                                _efl_ui_view_property_bind_changed, obj);
6021 
6022         pd->properties.registered = EINA_FALSE;
6023      }
6024    // Invalidate must be called before setting a new model and even if no model is registered
6025    if (pd->properties.provider)
6026      _efl_ui_widget_model_provider_invalidate(obj, NULL);
6027 }
6028 
6029 static Eina_Error
_efl_ui_property_bind(Eo * widget,Eo * target,Efl_Ui_Widget_Data * pd,const char * part,const char * key,const char * property)6030 _efl_ui_property_bind(Eo *widget, Eo *target, Efl_Ui_Widget_Data *pd,
6031                       const char *part, const char *key, const char *property)
6032 {
6033    Efl_Ui_Property_Bound *prop;
6034 
6035    // Always check for a model and fetch a provider in case a bound property
6036    // is provided by a class down the hierarchy, but they still need to be notified
6037    // when a model change
6038    _efl_ui_widget_model_register(widget, pd);
6039 
6040    // Check if the property is available from the reflection table of the object.
6041    if (!efl_property_reflection_exist(target, key)) return EFL_PROPERTY_ERROR_INVALID_KEY;
6042 
6043    if (!pd->properties.model_lookup)
6044      {
6045         pd->properties.model_lookup = eina_hash_stringshared_new(_efl_ui_property_bind_free);
6046         pd->properties.view_lookup = eina_hash_stringshared_new(NULL);
6047      }
6048 
6049    prop = calloc(1, sizeof (Efl_Ui_Property_Bound));
6050    if (!prop) return ENOMEM;
6051    prop->part = eina_stringshare_add(part);
6052    prop->key = eina_stringshare_add(key);
6053    prop->property = eina_stringshare_add(property);
6054 
6055    eina_hash_direct_add(pd->properties.model_lookup, prop->property, prop);
6056    eina_hash_direct_add(pd->properties.view_lookup, prop->key, prop);
6057 
6058    _efl_ui_property_bind_get(widget, pd, prop);
6059 
6060    efl_event_callback_call(widget, EFL_UI_PROPERTY_BIND_EVENT_PROPERTY_BOUND, (void*) prop->key);
6061    // In case of part, we emit it also on the part so that the part too can act on it
6062    if (target)
6063      efl_event_callback_call(target, EFL_UI_PROPERTY_BIND_EVENT_PROPERTY_BOUND, (void*) prop->key);
6064 
6065    return 0;
6066 }
6067 
6068 static Eina_Error
_efl_ui_widget_efl_ui_property_bind_property_bind(Eo * obj,Efl_Ui_Widget_Data * pd,const char * key,const char * property)6069 _efl_ui_widget_efl_ui_property_bind_property_bind(Eo *obj, Efl_Ui_Widget_Data *pd,
6070                                                   const char *key, const char *property)
6071 {
6072    return _efl_ui_property_bind(obj, obj, pd, NULL, key, property);
6073 }
6074 
6075 static void
_efl_ui_widget_efl_ui_view_model_set(Eo * obj,Efl_Ui_Widget_Data * pd,Efl_Model * model)6076 _efl_ui_widget_efl_ui_view_model_set(Eo *obj,
6077                                      Efl_Ui_Widget_Data *pd,
6078                                      Efl_Model *model)
6079 {
6080    Efl_Model_Changed_Event ev;
6081 
6082    ev.current = efl_ref(model);
6083    ev.previous = efl_ref(pd->properties.model);
6084 
6085    _efl_ui_widget_model_unregister(obj, pd);
6086 
6087    efl_replace(&pd->properties.model, model);
6088 
6089    // Set the properties handler just in case
6090    _efl_ui_widget_model_register(obj, pd);
6091 
6092    // In case the model set was NULL, but we did found a model provider
6093    // we shouldn't emit a second event. Otherwise we should.
6094    if (ev.current == pd->properties.model)
6095      efl_event_callback_call(obj, EFL_UI_VIEW_EVENT_MODEL_CHANGED, &ev);
6096 
6097    if (pd->properties.model) _efl_ui_widget_model_update(obj, pd);
6098 
6099    efl_unref(ev.current);
6100    efl_unref(ev.previous);
6101 }
6102 
6103 static Efl_Model *
_efl_ui_widget_efl_ui_view_model_get(const Eo * obj EINA_UNUSED,Efl_Ui_Widget_Data * pd)6104 _efl_ui_widget_efl_ui_view_model_get(const Eo *obj EINA_UNUSED, Efl_Ui_Widget_Data *pd)
6105 {
6106    return pd->properties.model;
6107 }
6108 
6109 static void
_efl_ui_widget_efl_object_invalidate(Eo * obj,Efl_Ui_Widget_Data * pd)6110 _efl_ui_widget_efl_object_invalidate(Eo *obj, Efl_Ui_Widget_Data *pd)
6111 {
6112    efl_invalidate(efl_super(obj, EFL_UI_WIDGET_CLASS));
6113 
6114    _efl_ui_widget_model_unregister(obj, pd);
6115    efl_replace(&pd->properties.model, NULL);
6116 
6117    if (pd->properties.view_lookup) eina_hash_free(pd->properties.view_lookup);
6118    pd->properties.view_lookup = NULL;
6119    if (pd->properties.model_lookup) eina_hash_free(pd->properties.model_lookup);
6120    pd->properties.model_lookup = NULL;
6121 }
6122 
6123 #include "efl_ui_widget_part_bg.eo.c"
6124 
6125 EAPI void
efl_ui_widget_internal_set(Eo * obj,Eina_Bool b)6126 efl_ui_widget_internal_set(Eo *obj, Eina_Bool b)
6127 {
6128    ELM_WIDGET_DATA_GET(obj, pd);
6129    EINA_SAFETY_ON_NULL_RETURN(pd);
6130 
6131    pd->internal = b;
6132 }
6133 
6134 EAPI Eina_Bool
efl_ui_widget_internal_get(Eo * obj)6135 efl_ui_widget_internal_get(Eo *obj)
6136 {
6137    ELM_WIDGET_DATA_GET(obj, pd);
6138    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
6139 
6140    return pd->internal;
6141 }
6142 
6143 /* Efl.Part Bg end */
6144 
6145 
6146 /* Internal EO APIs and hidden overrides */
6147 
6148 EFL_FUNC_BODY_CONST(efl_ui_widget_default_content_part_get, const char *, NULL)
6149 EFL_FUNC_BODY_CONST(efl_ui_widget_default_text_part_get, const char *, NULL)
6150 
6151 ELM_PART_CONTENT_DEFAULT_GET(efl_ui_widget, NULL)
6152 ELM_PART_TEXT_DEFAULT_GET(efl_ui_widget, NULL)
6153 
6154 #define EFL_UI_WIDGET_EXTRA_OPS \
6155    EFL_CANVAS_GROUP_ADD_DEL_OPS(efl_ui_widget), \
6156    ELM_PART_CONTENT_DEFAULT_OPS(efl_ui_widget), \
6157    ELM_PART_TEXT_DEFAULT_OPS(efl_ui_widget), \
6158    EFL_OBJECT_OP_FUNC(efl_canvas_object_is_frame_object_set, _efl_ui_widget_efl_canvas_object_is_frame_object_set), \
6159    EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_ui_widget_efl_object_dbg_info_get)
6160 
6161 #include "elm_widget_item_eo.c"
6162 #include "elm_widget_item_container_eo.c"
6163 #include "efl_ui_widget.eo.c"
6164 #include "efl_ui_widget_eo.legacy.c"
6165 
6166 /* Others */
6167 #include "efl_ui_l10n.eo.c"
6168