1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
6 #define EFL_ACCESS_OBJECT_PROTECTED
7 #define ELM_LAYOUT_PROTECTED
8 #define EFL_PART_PROTECTED
9 #define EFL_INPUT_CLICKABLE_PROTECTED
10 
11 #include <Elementary.h>
12 #include "elm_priv.h"
13 #include "efl_ui_button_private.h"
14 #include "elm_widget_layout.h"
15 #include "elm_part_helper.h"
16 
17 #define MY_CLASS EFL_UI_BUTTON_CLASS
18 #define MY_CLASS_PFX efl_ui_button
19 
20 #define MY_CLASS_NAME "Efl.Ui.Button"
21 
22 static const char SIG_CLICKED[] = "clicked";
23 static const char SIG_REPEATED[] = "repeated";
24 static const char SIG_PRESSED[] = "pressed";
25 static const char SIG_UNPRESSED[] = "unpressed";
26 
27 /* smart callbacks coming from elm button objects (besides the ones
28  * coming from elm layout): */
29 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
30    {SIG_CLICKED, ""},
31    {SIG_REPEATED, ""},
32    {SIG_PRESSED, ""},
33    {SIG_UNPRESSED, ""},
34    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
35    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
36    {NULL, NULL}
37 };
38 
39 static const Elm_Layout_Part_Alias_Description _content_aliases[] =
40 {
41    {"icon", "elm.swallow.content"},
42    {NULL, NULL}
43 };
44 
45 static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
46 
47 static const Elm_Action key_actions[] = {
48    {"activate", _key_action_activate},
49    {NULL, NULL}
50 };
51 
52 #define MY_CLASS_NAME_LEGACY "elm_button"
53 
54 static void
_efl_ui_button_class_constructor(Efl_Class * klass)55 _efl_ui_button_class_constructor(Efl_Class *klass)
56 {
57    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
58 }
59 
60 static void
_activate(Evas_Object * obj)61 _activate(Evas_Object *obj)
62 {
63    ELM_BUTTON_DATA_GET_OR_RETURN(obj, sd);
64 
65    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
66    sd->repeating = EINA_FALSE;
67 
68    if ((_elm_config->access_mode == ELM_ACCESS_MODE_OFF) ||
69        (_elm_access_2nd_click_timeout(obj)))
70      {
71         if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
72           _elm_access_say(E_("Clicked"));
73         if (!elm_widget_disabled_get(obj) &&
74             !evas_object_freeze_events_get(obj))
75           {
76              if (elm_widget_is_legacy(obj))
77                evas_object_smart_callback_call(obj, "clicked", NULL);
78              else
79                {
80                   efl_input_clickable_press(obj, 1);
81                   efl_input_clickable_unpress(obj, 1);
82                }
83           }
84      }
85 }
86 
87 EOLIAN static Eina_Bool
_efl_ui_button_efl_ui_widget_on_access_activate(Eo * obj,Efl_Ui_Button_Data * _pd EINA_UNUSED,Efl_Ui_Activate act)88 _efl_ui_button_efl_ui_widget_on_access_activate(Eo *obj, Efl_Ui_Button_Data *_pd EINA_UNUSED, Efl_Ui_Activate act)
89 {
90    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
91    if (act != EFL_UI_ACTIVATE_DEFAULT) return EINA_FALSE;
92    if (evas_object_freeze_events_get(obj)) return EINA_FALSE;
93 
94    if (elm_widget_is_legacy(obj))
95      evas_object_smart_callback_call(obj, "clicked", NULL);
96    else
97      {
98         efl_input_clickable_press(obj, 1);
99         efl_input_clickable_unpress(obj, 1);
100      }
101 
102    if (elm_widget_is_legacy(obj))
103      elm_layout_signal_emit(obj, "elm,anim,activate", "elm");
104    else
105      elm_layout_signal_emit(obj, "efl,state,animation,activated", "efl");
106 
107    return EINA_TRUE;
108 }
109 
110 static Eina_Bool
_key_action_activate(Evas_Object * obj,const char * params EINA_UNUSED)111 _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
112 {
113    if (elm_widget_is_legacy(obj))
114      elm_layout_signal_emit(obj, "elm,anim,activate", "elm");
115    else
116      elm_layout_signal_emit(obj, "efl,state,animation,activated", "efl");
117    _activate(obj);
118    return EINA_TRUE;
119 }
120 
121 static void
_on_clicked_signal(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)122 _on_clicked_signal(void *data,
123                    Evas_Object *obj EINA_UNUSED,
124                    const char *emission EINA_UNUSED,
125                    const char *source EINA_UNUSED)
126 {
127    _activate(data);
128 }
129 
130 static Eina_Bool
_autorepeat_send(void * data)131 _autorepeat_send(void *data)
132 {
133    ELM_BUTTON_DATA_GET_OR_RETURN_VAL(data, sd, ECORE_CALLBACK_CANCEL);
134 
135    if (elm_widget_is_legacy(data))
136      evas_object_smart_callback_call(data, "repeated", NULL);
137    else
138      efl_event_callback_call(data, EFL_UI_AUTOREPEAT_EVENT_REPEATED, NULL);
139 
140    if (!sd->repeating)
141      {
142         sd->timer = NULL;
143         return ECORE_CALLBACK_CANCEL;
144      }
145 
146    return ECORE_CALLBACK_RENEW;
147 }
148 
149 static Eina_Bool
_autorepeat_initial_send(void * data)150 _autorepeat_initial_send(void *data)
151 {
152    ELM_BUTTON_DATA_GET_OR_RETURN_VAL(data, sd, ECORE_CALLBACK_CANCEL);
153 
154    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
155    sd->repeating = EINA_TRUE;
156    _autorepeat_send(data);
157    sd->timer = ecore_timer_add(sd->ar_gap_timeout, _autorepeat_send, data);
158 
159    return ECORE_CALLBACK_CANCEL;
160 }
161 
162 static void
_on_pressed_signal(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)163 _on_pressed_signal(void *data,
164                    Evas_Object *obj EINA_UNUSED,
165                    const char *emission EINA_UNUSED,
166                    const char *source EINA_UNUSED)
167 {
168    ELM_BUTTON_DATA_GET_OR_RETURN(data, sd);
169 
170    if ((sd->autorepeat) && (!sd->repeating))
171      {
172         if (sd->ar_initial_timeout <= 0.0)
173           _autorepeat_initial_send(data);  /* call immediately */
174         else
175           sd->timer = ecore_timer_add
176               (sd->ar_initial_timeout, _autorepeat_initial_send, data);
177      }
178 
179    if (elm_widget_is_legacy(data))
180      evas_object_smart_callback_call
181         (data, "pressed", NULL);
182 
183 }
184 
185 static void
_on_unpressed_signal(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)186 _on_unpressed_signal(void *data,
187                      Evas_Object *obj EINA_UNUSED,
188                      const char *emission EINA_UNUSED,
189                      const char *source EINA_UNUSED)
190 {
191    ELM_BUTTON_DATA_GET_OR_RETURN(data, sd);
192 
193    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
194    sd->repeating = EINA_FALSE;
195 
196    if (elm_widget_is_legacy(data))
197      evas_object_smart_callback_call
198         (data, "unpressed", NULL);
199 }
200 
201 static char *
_access_info_cb(void * data EINA_UNUSED,Evas_Object * obj)202 _access_info_cb(void *data EINA_UNUSED, Evas_Object *obj)
203 {
204    const char *txt = elm_widget_access_info_get(obj);
205 
206    if (!txt) txt = elm_layout_text_get(obj, NULL);
207    if (txt) return strdup(txt);
208 
209    return NULL;
210 }
211 
212 static char *
_access_state_cb(void * data EINA_UNUSED,Evas_Object * obj)213 _access_state_cb(void *data EINA_UNUSED, Evas_Object *obj)
214 {
215    if (elm_widget_disabled_get(obj))
216      return strdup(E_("State: Disabled"));
217 
218    return NULL;
219 }
220 
221 EOLIAN static void
_efl_ui_button_efl_canvas_group_group_add(Eo * obj,Efl_Ui_Button_Data * _pd EINA_UNUSED)222 _efl_ui_button_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Button_Data *_pd EINA_UNUSED)
223 {
224    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
225 
226    if (!elm_widget_theme_klass_get(obj))
227      elm_widget_theme_klass_set(obj, "button");
228    efl_canvas_group_add(efl_super(obj, MY_CLASS));
229 
230    if (elm_widget_is_legacy(obj))
231      {
232         edje_object_signal_callback_add
233            (wd->resize_obj, "elm,action,click", "*",
234             _on_clicked_signal, obj);
235         edje_object_signal_callback_add
236            (wd->resize_obj, "elm,action,press", "*",
237             _on_pressed_signal, obj);
238         edje_object_signal_callback_add
239            (wd->resize_obj, "elm,action,unpress", "*",
240             _on_unpressed_signal, obj);
241      }
242    else
243      {
244         edje_object_signal_callback_add
245            (wd->resize_obj, "efl,action,press", "*",
246             _on_pressed_signal, obj);
247         edje_object_signal_callback_add
248            (wd->resize_obj, "efl,action,unpress", "*",
249             _on_unpressed_signal, obj);
250         efl_ui_action_connector_bind_clickable_to_theme(wd->resize_obj, obj);
251      }
252 
253    _elm_access_object_register(obj, wd->resize_obj);
254    _elm_access_text_set
255      (_elm_access_info_get(obj), ELM_ACCESS_TYPE, E_("Button"));
256    _elm_access_callback_set
257      (_elm_access_info_get(obj), ELM_ACCESS_INFO, _access_info_cb, NULL);
258    _elm_access_callback_set
259      (_elm_access_info_get(obj), ELM_ACCESS_STATE, _access_state_cb, obj);
260 
261    elm_widget_can_focus_set(obj, EINA_TRUE);
262 
263    if (elm_widget_theme_object_set(obj, wd->resize_obj,
264                                        elm_widget_theme_klass_get(obj),
265                                        elm_widget_theme_element_get(obj),
266                                        elm_widget_theme_style_get(obj)) == EFL_UI_THEME_APPLY_ERROR_GENERIC)
267      CRI("Failed to set layout!");
268 }
269 
270 EOLIAN static Eo *
_efl_ui_button_efl_object_constructor(Eo * obj,Efl_Ui_Button_Data * _pd EINA_UNUSED)271 _efl_ui_button_efl_object_constructor(Eo *obj, Efl_Ui_Button_Data *_pd EINA_UNUSED)
272 {
273    obj = efl_constructor(efl_super(obj, MY_CLASS));
274    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
275    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_PUSH_BUTTON);
276 
277    return obj;
278 }
279 
280 EOLIAN static void
_efl_ui_button_efl_ui_autorepeat_autorepeat_enabled_set(Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * sd,Eina_Bool on)281 _efl_ui_button_efl_ui_autorepeat_autorepeat_enabled_set(Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *sd, Eina_Bool on)
282 {
283    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
284    sd->autorepeat = on;
285    sd->repeating = EINA_FALSE;
286 }
287 
288 EOLIAN static Eina_Bool
_efl_ui_button_efl_ui_autorepeat_autorepeat_enabled_get(const Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * sd)289 _efl_ui_button_efl_ui_autorepeat_autorepeat_enabled_get(const Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *sd)
290 {
291    return (sd->autorepeat);
292 }
293 
294 EOLIAN static void
_efl_ui_button_efl_ui_autorepeat_autorepeat_initial_timeout_set(Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * sd,double t)295 _efl_ui_button_efl_ui_autorepeat_autorepeat_initial_timeout_set(Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *sd, double t)
296 {
297    if (EINA_DBL_EQ(sd->ar_initial_timeout, t)) return;
298    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
299    sd->ar_initial_timeout = t;
300 }
301 
302 EOLIAN static double
_efl_ui_button_efl_ui_autorepeat_autorepeat_initial_timeout_get(const Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * sd)303 _efl_ui_button_efl_ui_autorepeat_autorepeat_initial_timeout_get(const Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *sd)
304 {
305    return sd->ar_initial_timeout;
306 }
307 
308 EOLIAN static void
_efl_ui_button_efl_ui_autorepeat_autorepeat_gap_timeout_set(Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * sd,double t)309 _efl_ui_button_efl_ui_autorepeat_autorepeat_gap_timeout_set(Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *sd, double t)
310 {
311    if (EINA_DBL_EQ(sd->ar_gap_timeout, t)) return;
312 
313    sd->ar_gap_timeout = t;
314    if ((sd->repeating) && (sd->timer)) ecore_timer_interval_set(sd->timer, t);
315 }
316 
317 EOLIAN static double
_efl_ui_button_efl_ui_autorepeat_autorepeat_gap_timeout_get(const Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * sd)318 _efl_ui_button_efl_ui_autorepeat_autorepeat_gap_timeout_get(const Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *sd)
319 {
320    return sd->ar_gap_timeout;
321 }
322 
323 EOLIAN const Efl_Access_Action_Data *
_efl_ui_button_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Efl_Ui_Button_Data * pd EINA_UNUSED)324 _efl_ui_button_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Efl_Ui_Button_Data *pd EINA_UNUSED)
325 {
326    static Efl_Access_Action_Data atspi_actions[] = {
327           { "activate", "activate", NULL, _key_action_activate },
328           { NULL, NULL, NULL, NULL}
329    };
330    return &atspi_actions[0];
331 }
332 
333 /* Standard widget overrides */
334 
ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_button,Efl_Ui_Button_Data)335 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_button, Efl_Ui_Button_Data)
336 ELM_PART_TEXT_DEFAULT_IMPLEMENT(efl_ui_button, Efl_Ui_Button_Data)
337 ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_button, Efl_Ui_Button_Data)
338 
339 EAPI void
340 elm_button_autorepeat_initial_timeout_set(Evas_Object *obj, double t)
341 {
342    efl_ui_autorepeat_initial_timeout_set(obj, t);
343 }
344 
345 EAPI double
elm_button_autorepeat_initial_timeout_get(const Evas_Object * obj)346 elm_button_autorepeat_initial_timeout_get(const Evas_Object *obj)
347 {
348    return efl_ui_autorepeat_initial_timeout_get(obj);
349 }
350 
351 EAPI void
elm_button_autorepeat_gap_timeout_set(Evas_Object * obj,double t)352 elm_button_autorepeat_gap_timeout_set(Evas_Object *obj, double t)
353 {
354    efl_ui_autorepeat_gap_timeout_set(obj, t);
355 }
356 
357 EAPI double
elm_button_autorepeat_gap_timeout_get(const Evas_Object * obj)358 elm_button_autorepeat_gap_timeout_get(const Evas_Object *obj)
359 {
360    return efl_ui_autorepeat_gap_timeout_get(obj);
361 }
362 
363 EAPI void
elm_button_autorepeat_set(Evas_Object * obj,Eina_Bool on)364 elm_button_autorepeat_set(Evas_Object *obj, Eina_Bool on)
365 {
366    efl_ui_autorepeat_enabled_set(obj, on);
367 }
368 
369 EAPI Eina_Bool
elm_button_autorepeat_get(const Evas_Object * obj)370 elm_button_autorepeat_get(const Evas_Object *obj)
371 {
372    return efl_ui_autorepeat_enabled_get(obj);
373 }
374 
375 /* Internal EO APIs and hidden overrides */
376 
EFL_UI_LAYOUT_CONTENT_ALIASES_IMPLEMENT(MY_CLASS_PFX)377 EFL_UI_LAYOUT_CONTENT_ALIASES_IMPLEMENT(MY_CLASS_PFX)
378 
379 #define EFL_UI_BUTTON_EXTRA_OPS \
380    EFL_UI_LAYOUT_CONTENT_ALIASES_OPS(MY_CLASS_PFX), \
381    EFL_CANVAS_GROUP_ADD_OPS(efl_ui_button)
382 
383 #include "efl_ui_button.eo.c"
384 
385 #include "efl_ui_button_legacy_eo.h"
386 #include "efl_ui_button_legacy_part.eo.h"
387 
388 EOLIAN static Eo *
389 _efl_ui_button_legacy_efl_object_constructor(Eo *obj, void *_pd EINA_UNUSED)
390 {
391    obj = efl_constructor(efl_super(obj, EFL_UI_BUTTON_LEGACY_CLASS));
392    legacy_object_focus_handle(obj);
393    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
394    return obj;
395 }
396 
397 /* FIXME: replicated from elm_layout just because button's icon spot
398  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
399  * can changed the theme API */
400 EOLIAN static Eina_Error
_efl_ui_button_legacy_efl_ui_widget_theme_apply(Eo * obj,void * _pd EINA_UNUSED)401 _efl_ui_button_legacy_efl_ui_widget_theme_apply(Eo *obj, void *_pd EINA_UNUSED)
402 {
403    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
404 
405    int_ret = efl_ui_widget_theme_apply(efl_super(obj, EFL_UI_BUTTON_LEGACY_CLASS));
406    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
407    if (efl_finalized_get(obj)) _elm_layout_legacy_icon_signal_emit(obj);
408 
409    return int_ret;
410 }
411 
412 /* FIXME: replicated from elm_layout just because button's icon spot
413  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
414  * can changed the theme API */
415 EOLIAN static Eina_Bool
_efl_ui_button_legacy_efl_ui_widget_widget_sub_object_del(Eo * obj,void * _pd EINA_UNUSED,Evas_Object * sobj)416 _efl_ui_button_legacy_efl_ui_widget_widget_sub_object_del(Eo *obj, void *_pd EINA_UNUSED, Evas_Object *sobj)
417 {
418    Eina_Bool int_ret = EINA_FALSE;
419 
420    int_ret = elm_widget_sub_object_del(efl_super(obj, EFL_UI_BUTTON_LEGACY_CLASS), sobj);
421    if (!int_ret) return EINA_FALSE;
422 
423    _elm_layout_legacy_icon_signal_emit(obj);
424 
425    return EINA_TRUE;
426 }
427 
428 /* FIXME: replicated from elm_layout just because button's icon spot
429  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
430  * can changed the theme API */
431 static Eina_Bool
_efl_ui_button_legacy_content_set(Eo * obj,void * _pd EINA_UNUSED,const char * part,Evas_Object * content)432 _efl_ui_button_legacy_content_set(Eo *obj, void *_pd EINA_UNUSED, const char *part, Evas_Object *content)
433 {
434    Eina_Bool int_ret = EINA_FALSE;
435 
436    int_ret = efl_content_set(efl_part(efl_super(obj, EFL_UI_BUTTON_LEGACY_CLASS), part), content);
437    if (!int_ret) return EINA_FALSE;
438 
439    _elm_layout_legacy_icon_signal_emit(obj);
440 
441    return EINA_TRUE;
442 }
443 
444 /* Efl.Part begin */
445 
446 static Eina_Bool
_part_is_efl_ui_button_legacy_part(const Eo * obj EINA_UNUSED,const char * part)447 _part_is_efl_ui_button_legacy_part(const Eo *obj EINA_UNUSED, const char *part)
448 {
449    return eina_streq(part, "elm.swallow.content");
450 }
451 
ELM_PART_OVERRIDE_PARTIAL(efl_ui_button_legacy,EFL_UI_BUTTON_LEGACY,void,_part_is_efl_ui_button_legacy_part)452 ELM_PART_OVERRIDE_PARTIAL(efl_ui_button_legacy, EFL_UI_BUTTON_LEGACY, void, _part_is_efl_ui_button_legacy_part)
453 ELM_PART_OVERRIDE_CONTENT_SET_NO_SD(efl_ui_button_legacy)
454 #include "efl_ui_button_legacy_part.eo.c"
455 
456 /* Efl.Part end */
457 
458 EAPI Evas_Object *
459 elm_button_add(Evas_Object *parent)
460 {
461    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
462    return elm_legacy_add(EFL_UI_BUTTON_LEGACY_CLASS, parent);
463 }
464 
465 #include "efl_ui_button_legacy_eo.c"
466