1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7 #define ELM_LAYOUT_PROTECTED
8 #define EFL_PART_PROTECTED
9 
10 #include <Elementary.h>
11 #include "elm_priv.h"
12 #include "efl_ui_check_private.h"
13 #include "elm_part_helper.h"
14 
15 #define MY_CLASS EFL_UI_CHECK_CLASS
16 #define MY_CLASS_PFX efl_ui_check
17 
18 #define MY_CLASS_NAME "Efl.Ui.Check"
19 
20 static const Elm_Layout_Part_Alias_Description _text_aliases[] =
21 {
22    {"default", "elm.text"},
23    {"on", "elm.ontext"},
24    {"off", "elm.offtext"},
25    {NULL, NULL}
26 };
27 
28 static const Elm_Layout_Part_Alias_Description _content_aliases[] =
29 {
30    {"icon", "elm.swallow.content"},
31    {NULL, NULL}
32 };
33 
34 static const char SIG_CHANGED[] = "changed";
35 
36 /* smart callbacks coming from elm check objects: */
37 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
38    {SIG_CHANGED, ""},
39    {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
40    {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
41    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
42    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
43    {NULL, NULL}
44 };
45 
46 static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
47 
48 static const Elm_Action key_actions[] = {
49    {"activate", _key_action_activate},
50    {NULL, NULL}
51 };
52 
53 static void
_check_legacy_event(Eo * obj)54 _check_legacy_event(Eo *obj)
55 {
56    EFL_UI_CHECK_DATA_GET(obj, pd);
57    if (pd->selected)
58      {
59         if (pd->legacy_changed_emitted_select) return;
60         pd->legacy_changed_emitted_select = EINA_TRUE;
61         pd->legacy_changed_emitted_unselect = EINA_FALSE;
62      }
63    else
64      {
65         if (pd->legacy_changed_emitted_unselect) return;
66         pd->legacy_changed_emitted_unselect = EINA_TRUE;
67         pd->legacy_changed_emitted_select = EINA_FALSE;
68      }
69    evas_object_smart_callback_call(obj, "changed", NULL);
70 }
71 
72 static void
_activate(Evas_Object * obj)73 _activate(Evas_Object *obj)
74 {
75    // state will be changed by the later call to the selected_set call
76    if (!efl_ui_selectable_selected_get(obj))
77      {
78         // FIXME: to do animation during state change , we need different signal
79         // so that we can distinguish between state change by user or state change
80         // by calling state_change() api. Keep both the signal for backward compatibility
81         // and remove "elm,state,check,on" signal emission when we can break ABI.
82         // efl_ui_selectable_selected_set below will emit "elm,state,check,*" or "efl,state,*selected"
83         if (elm_widget_is_legacy(obj))
84           {
85              elm_layout_signal_emit(obj, "elm,activate,check,on", "elm");
86           }
87         else
88           {
89              elm_layout_signal_emit(obj, "efl,state,selected", "efl");
90           }
91 
92         if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
93              _elm_access_say(E_("State: On"));
94      }
95    else
96      {
97         // FIXME: to do animation during state change , we need different signal
98         // so that we can distinguish between state change by user or state change
99         // by calling state_change() api. Keep both the signal for backward compatibility
100         // and remove "elm,state,check,off" signal emission when we can break ABI.
101         // efl_ui_selectable_selected_set below will emit "elm,state,check,*" or "efl,state,*selected"
102         if (elm_widget_is_legacy(obj))
103           {
104              elm_layout_signal_emit(obj, "elm,activate,check,off", "elm");
105           }
106         else
107           {
108              elm_layout_signal_emit(obj, "efl,state,unselected", "efl");
109           }
110 
111         if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
112              _elm_access_say(E_("State: Off"));
113      }
114    //This commit will update the theme with the correct signals
115    // "elm,state,check,on" or "elm,state,check,off" for legacy
116    // "efl,state,selected" or "efl,state,unselected" for eo-api
117    efl_ui_selectable_selected_set(obj, !efl_ui_selectable_selected_get(obj));
118    if (elm_widget_is_legacy(obj))
119      _check_legacy_event(obj);
120    if (_elm_config->atspi_mode)
121      efl_access_state_changed_signal_emit(obj,
122                                           EFL_ACCESS_STATE_TYPE_CHECKED,
123                                           efl_ui_selectable_selected_get(obj));
124 }
125 
126 EOLIAN static Efl_Access_State_Set
_efl_ui_check_efl_access_object_state_set_get(const Eo * obj,Efl_Ui_Check_Data * _pd EINA_UNUSED)127 _efl_ui_check_efl_access_object_state_set_get(const Eo *obj, Efl_Ui_Check_Data *_pd EINA_UNUSED)
128 {
129    Efl_Access_State_Set states = 0;
130 
131    states = efl_access_object_state_set_get(efl_super(obj, EFL_UI_CHECK_CLASS));
132 
133    if (elm_check_state_get(obj))
134        STATE_TYPE_SET(states, EFL_ACCESS_STATE_TYPE_CHECKED);
135 
136    return states;
137 }
138 
139 EOLIAN static Eina_Bool
_efl_ui_check_efl_ui_widget_on_access_activate(Eo * obj EINA_UNUSED,Efl_Ui_Check_Data * _pd EINA_UNUSED,Efl_Ui_Activate act)140 _efl_ui_check_efl_ui_widget_on_access_activate(Eo *obj EINA_UNUSED, Efl_Ui_Check_Data *_pd EINA_UNUSED, Efl_Ui_Activate act)
141 {
142    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
143    if (act != EFL_UI_ACTIVATE_DEFAULT) return EINA_FALSE;
144 
145    _activate(obj);
146 
147    return EINA_TRUE;
148 }
149 
150 static Eina_Bool
_key_action_activate(Evas_Object * obj,const char * params EINA_UNUSED)151 _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
152 {
153    _activate(obj);
154    return EINA_TRUE;
155 }
156 
157 EOLIAN static Eina_Error
_efl_ui_check_efl_ui_widget_theme_apply(Eo * obj,Efl_Ui_Check_Data * sd EINA_UNUSED)158 _efl_ui_check_efl_ui_widget_theme_apply(Eo *obj, Efl_Ui_Check_Data *sd EINA_UNUSED)
159 {
160    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
161 
162    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_ERROR_GENERIC);
163 
164    int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
165    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
166 
167    if (elm_widget_is_legacy(obj))
168      {
169         if (!efl_ui_selectable_selected_get(obj))
170           elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
171         else
172           elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
173      }
174    else
175      {
176         if (!efl_ui_selectable_selected_get(obj))
177           elm_layout_signal_emit(obj, "efl,state,unselected", "efl");
178         else
179           elm_layout_signal_emit(obj, "efl,state,selected", "efl");
180      }
181 
182    edje_object_message_signal_process(wd->resize_obj);
183 
184    return int_ret;
185 }
186 
187 static char *
_access_info_cb(void * data EINA_UNUSED,Evas_Object * obj)188 _access_info_cb(void *data EINA_UNUSED, Evas_Object *obj)
189 {
190    const char *txt = elm_widget_access_info_get(obj);
191 
192    if (!txt) txt = elm_layout_text_get(obj, NULL);
193    if (txt) return strdup(txt);
194 
195    return NULL;
196 }
197 
198 static char *
_access_state_cb(void * data,Evas_Object * obj)199 _access_state_cb(void *data, Evas_Object *obj)
200 {
201    const char *on_text, *off_text;
202 
203    if (elm_widget_disabled_get(obj))
204      return strdup(E_("State: Disabled"));
205    if (efl_ui_selectable_selected_get(obj))
206      {
207         on_text = elm_layout_text_get(data, "on");
208 
209         if (on_text)
210           {
211              char buf[1024];
212 
213              snprintf(buf, sizeof(buf), "%s: %s", E_("State"), on_text);
214              return strdup(buf);
215           }
216         else
217           return strdup(E_("State: On"));
218      }
219 
220    off_text = elm_layout_text_get(data, "off");
221 
222    if (off_text)
223      {
224         char buf[1024];
225 
226         snprintf(buf, sizeof(buf), "%s: %s", E_("State"), off_text);
227         return strdup(buf);
228      }
229    return strdup(E_("State: Off"));
230 }
231 
232 static void
_flush_selected(Eo * obj,Eina_Bool sel)233 _flush_selected(Eo *obj, Eina_Bool sel)
234 {
235    efl_ui_selectable_selected_set(obj, sel);
236 
237    if (_elm_config->atspi_mode)
238      efl_access_state_changed_signal_emit(obj,
239                                           EFL_ACCESS_STATE_TYPE_CHECKED,
240                                           efl_ui_selectable_selected_get(obj));
241 }
242 
243 static void
_on_check_off(void * data,Evas_Object * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)244 _on_check_off(void *data,
245               Evas_Object *o EINA_UNUSED,
246               const char *emission EINA_UNUSED,
247               const char *source EINA_UNUSED)
248 {
249    Evas_Object *obj = data;
250 
251    _flush_selected(obj, EINA_FALSE);
252    if (elm_widget_is_legacy(obj))
253      _check_legacy_event(obj);
254 }
255 
256 static void
_on_check_on(void * data,Evas_Object * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)257 _on_check_on(void *data,
258              Evas_Object *o EINA_UNUSED,
259              const char *emission EINA_UNUSED,
260              const char *source EINA_UNUSED)
261 {
262    Evas_Object *obj = data;
263 
264    _flush_selected(obj, EINA_TRUE);
265    if (elm_widget_is_legacy(obj))
266      _check_legacy_event(obj);
267 }
268 
269 static void
_on_check_toggle(void * data,Evas_Object * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)270 _on_check_toggle(void *data,
271                  Evas_Object *o EINA_UNUSED,
272                  const char *emission EINA_UNUSED,
273                  const char *source EINA_UNUSED)
274 {
275    _activate(data);
276 }
277 
278 static void
_clicked_cb(void * data,const Efl_Event * ev EINA_UNUSED)279 _clicked_cb(void *data, const Efl_Event *ev EINA_UNUSED)
280 {
281    _activate(data);
282 }
283 
284 EOLIAN static Eina_Bool
_efl_ui_check_efl_ui_selectable_selected_get(const Eo * obj EINA_UNUSED,Efl_Ui_Check_Data * pd EINA_UNUSED)285 _efl_ui_check_efl_ui_selectable_selected_get(const Eo *obj EINA_UNUSED, Efl_Ui_Check_Data *pd EINA_UNUSED)
286 {
287    return pd->selected;
288 }
289 
290 EOLIAN static void
_efl_ui_check_efl_ui_selectable_selected_set(Eo * obj,Efl_Ui_Check_Data * pd,Eina_Bool value)291 _efl_ui_check_efl_ui_selectable_selected_set(Eo *obj, Efl_Ui_Check_Data *pd, Eina_Bool value)
292 {
293    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
294 
295    if (pd->selected == value) return;
296 
297    if (elm_widget_is_legacy(obj))
298      {
299         if (pd->statep)
300           *pd->statep = value;
301      }
302 
303    if (elm_widget_is_legacy(obj))
304      {
305         if (value == 1)
306           elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
307         else
308           elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
309      }
310    else
311      {
312         if (value == 1)
313           elm_layout_signal_emit(obj, "efl,state,selected", "efl");
314         else
315           elm_layout_signal_emit(obj, "efl,state,unselected", "efl");
316      }
317 
318    edje_object_message_signal_process(wd->resize_obj);
319 
320    pd->selected = value;
321 
322    pd->legacy_changed_emitted_select = !pd->selected;
323    pd->legacy_changed_emitted_unselect = pd->selected;
324 
325    if (!elm_widget_is_legacy(obj))
326      efl_event_callback_call(obj, EFL_UI_EVENT_SELECTED_CHANGED, &pd->selected);
327 }
328 
329 EOLIAN static Eo *
_efl_ui_check_efl_object_constructor(Eo * obj,Efl_Ui_Check_Data * pd EINA_UNUSED)330 _efl_ui_check_efl_object_constructor(Eo *obj, Efl_Ui_Check_Data *pd EINA_UNUSED)
331 {
332    if (!elm_widget_theme_klass_get(obj))
333      elm_widget_theme_klass_set(obj, "check");
334    obj = efl_constructor(efl_super(obj, MY_CLASS));
335    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
336 
337    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
338    efl_ui_action_connector_bind_clickable_to_theme(wd->resize_obj, obj);
339    if (elm_widget_is_legacy(obj))
340      {
341         efl_layout_signal_callback_add
342           (wd->resize_obj, "elm,action,check,on", "*", obj, _on_check_on, NULL);
343         efl_layout_signal_callback_add
344           (wd->resize_obj, "elm,action,check,off", "*", obj, _on_check_off, NULL);
345         efl_layout_signal_callback_add
346           (wd->resize_obj, "elm,action,check,toggle", "*", obj, _on_check_toggle, NULL);
347      }
348    else
349      {
350         efl_layout_signal_callback_add
351           (wd->resize_obj, "efl,action,select", "*", obj, _on_check_on, NULL);
352         efl_layout_signal_callback_add
353           (wd->resize_obj, "efl,action,unselect", "*", obj, _on_check_off, NULL);
354         efl_event_callback_add(obj, EFL_INPUT_EVENT_CLICKED, _clicked_cb, obj);
355      }
356 
357    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_CHECK_BOX);
358    _elm_access_object_register(obj, wd->resize_obj);
359    _elm_access_text_set
360      (_elm_access_info_get(obj), ELM_ACCESS_TYPE, E_("Check"));
361    _elm_access_callback_set
362      (_elm_access_info_get(obj), ELM_ACCESS_INFO, _access_info_cb, obj);
363    _elm_access_callback_set
364      (_elm_access_info_get(obj), ELM_ACCESS_STATE, _access_state_cb, obj);
365 
366    elm_widget_can_focus_set(obj, EINA_TRUE);
367 
368    return obj;
369 }
370 
371 EAPI void
elm_check_state_set(Evas_Object * obj,Eina_Bool state)372 elm_check_state_set(Evas_Object *obj, Eina_Bool state)
373 {
374    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
375    EFL_UI_CHECK_DATA_GET_OR_RETURN(obj, sd);
376 
377    efl_ui_selectable_selected_set(obj, state);
378 }
379 
380 EAPI Eina_Bool
elm_check_state_get(const Evas_Object * obj)381 elm_check_state_get(const Evas_Object *obj)
382 {
383    return !!efl_ui_selectable_selected_get(obj);
384 }
385 
386 EAPI void
elm_check_state_pointer_set(Eo * obj,Eina_Bool * statep)387 elm_check_state_pointer_set(Eo *obj, Eina_Bool *statep)
388 {
389    EFL_UI_CHECK_DATA_GET_OR_RETURN(obj, sd);
390 
391    if (!statep)
392      {
393         sd->statep = NULL;
394         return;
395      }
396 
397    sd->statep = statep;
398    if (*sd->statep != sd->selected)
399      {
400         efl_ui_selectable_selected_set(obj, *sd->statep);
401      }
402 }
403 
404 EOLIAN const Efl_Access_Action_Data *
_efl_ui_check_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Efl_Ui_Check_Data * pd EINA_UNUSED)405 _efl_ui_check_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Efl_Ui_Check_Data *pd EINA_UNUSED)
406 {
407    static Efl_Access_Action_Data atspi_action[] = {
408           { "activate", "activate", NULL, _key_action_activate },
409           { NULL, NULL, NULL, NULL }
410    };
411    return &atspi_action[0];
412 }
413 
414 /* Standard widget overrides */
415 
ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_check,Efl_Ui_Check_Data)416 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_check, Efl_Ui_Check_Data)
417 ELM_PART_TEXT_DEFAULT_IMPLEMENT(efl_ui_check, Efl_Ui_Check_Data)
418 ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_check, Efl_Ui_Check_Data)
419 EFL_UI_LAYOUT_CONTENT_ALIASES_IMPLEMENT(MY_CLASS_PFX)
420 
421 /* Internal EO APIs and hidden overrides */
422 
423 EFL_UI_LAYOUT_TEXT_ALIASES_IMPLEMENT(MY_CLASS_PFX)
424 
425 #define EFL_UI_CHECK_EXTRA_OPS \
426    EFL_UI_LAYOUT_CONTENT_ALIASES_OPS(MY_CLASS_PFX), \
427    EFL_UI_LAYOUT_TEXT_ALIASES_OPS(MY_CLASS_PFX)
428 
429 
430 #include "efl_ui_check.eo.c"
431 #include "efl_ui_check_eo.legacy.c"
432 
433 #include "efl_ui_check_legacy_eo.h"
434 #include "efl_ui_check_legacy_part.eo.h"
435 
436 #define MY_CLASS_NAME_LEGACY "elm_check"
437 
438 static void
439 _efl_ui_check_legacy_class_constructor(Efl_Class *klass)
440 {
441    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
442 }
443 
444 EOLIAN static Eo *
_efl_ui_check_legacy_efl_object_constructor(Eo * obj,void * pd EINA_UNUSED)445 _efl_ui_check_legacy_efl_object_constructor(Eo *obj, void *pd EINA_UNUSED)
446 {
447    obj = efl_constructor(efl_super(obj, EFL_UI_CHECK_LEGACY_CLASS));
448    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
449    legacy_object_focus_handle(obj);
450    return obj;
451 }
452 
453 /* FIXME: replicated from elm_layout just because check's icon spot
454  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
455  * can changed the theme API */
456 EOLIAN static Eina_Error
_efl_ui_check_legacy_efl_ui_widget_theme_apply(Eo * obj,void * _pd EINA_UNUSED)457 _efl_ui_check_legacy_efl_ui_widget_theme_apply(Eo *obj, void *_pd EINA_UNUSED)
458 {
459    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
460 
461    int_ret = efl_ui_widget_theme_apply(efl_super(obj, EFL_UI_CHECK_LEGACY_CLASS));
462    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
463 
464    if (efl_finalized_get(obj)) _elm_layout_legacy_icon_signal_emit(obj);
465 
466    return int_ret;
467 }
468 
469 /* FIXME: replicated from elm_layout just because check's icon spot
470  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
471  * can changed the theme API */
472 EOLIAN static Eina_Bool
_efl_ui_check_legacy_efl_ui_widget_widget_sub_object_del(Eo * obj,void * _pd EINA_UNUSED,Evas_Object * sobj)473 _efl_ui_check_legacy_efl_ui_widget_widget_sub_object_del(Eo *obj, void *_pd EINA_UNUSED, Evas_Object *sobj)
474 {
475    Eina_Bool int_ret = EINA_FALSE;
476 
477    int_ret = elm_widget_sub_object_del(efl_super(obj, EFL_UI_CHECK_LEGACY_CLASS), sobj);
478    if (!int_ret) return EINA_FALSE;
479 
480    _elm_layout_legacy_icon_signal_emit(obj);
481 
482    return EINA_TRUE;
483 }
484 
485 /* FIXME: replicated from elm_layout just because check's icon spot
486  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
487  * can changed the theme API */
488 static Eina_Bool
_efl_ui_check_legacy_content_set(Eo * obj,void * _pd EINA_UNUSED,const char * part,Evas_Object * content)489 _efl_ui_check_legacy_content_set(Eo *obj, void *_pd EINA_UNUSED, const char *part, Evas_Object *content)
490 {
491    Eina_Bool int_ret = EINA_FALSE;
492 
493    int_ret = efl_content_set(efl_part(efl_super(obj, EFL_UI_CHECK_LEGACY_CLASS), part), content);
494    if (!int_ret) return EINA_FALSE;
495 
496    _elm_layout_legacy_icon_signal_emit(obj);
497 
498    return EINA_TRUE;
499 }
500 
501 /* Efl.Part begin */
502 
503 static Eina_Bool
_part_is_efl_ui_check_legacy_part(const Eo * obj EINA_UNUSED,const char * part)504 _part_is_efl_ui_check_legacy_part(const Eo *obj EINA_UNUSED, const char *part)
505 {
506    return eina_streq(part, "elm.swallow.content");
507 }
508 
ELM_PART_OVERRIDE_PARTIAL(efl_ui_check_legacy,EFL_UI_CHECK_LEGACY,void,_part_is_efl_ui_check_legacy_part)509 ELM_PART_OVERRIDE_PARTIAL(efl_ui_check_legacy, EFL_UI_CHECK_LEGACY, void, _part_is_efl_ui_check_legacy_part)
510 ELM_PART_OVERRIDE_CONTENT_SET_NO_SD(efl_ui_check_legacy)
511 #include "efl_ui_check_legacy_part.eo.c"
512 
513 /* Efl.Part end */
514 
515 EAPI Evas_Object *
516 elm_check_add(Evas_Object *parent)
517 {
518    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
519    return elm_legacy_add(EFL_UI_CHECK_LEGACY_CLASS, parent);
520 }
521 
522 #include "efl_ui_check_legacy_eo.c"
523