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