1 #include <Elementary.h>
5 * @defgroup Button Button
8 * This is a push-button. Press it and run some function. It can contain
9 * a simple label and icon object.
12 typedef struct _Widget_Data Widget_Data;
24 Evas_Object *btn, *icon;
31 const char *statelabel[4];
35 static const char *widtype = NULL;
36 static void _del_hook(Evas_Object *obj);
37 static void _theme_hook(Evas_Object *obj);
38 static void _disable_hook(Evas_Object *obj);
39 static void _sizing_eval(Evas_Object *obj);
40 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
41 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
42 static void _signal_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
43 static void _signal_pressed(void *data, Evas_Object *obj, const char *emission, const char *source);
44 static void _signal_unpressed(void *data, Evas_Object *obj, const char *emission, const char *source);
45 static void _on_focus_hook(void *data, Evas_Object *obj);
46 static void _activate(Evas_Object *obj);
47 static void _activate_hook(Evas_Object *obj);
48 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
49 Evas_Callback_Type type, void *event_info);
51 static void _set_label(Evas_Object *obj, const char *label);
52 static void _signal_default_text_set(void *data, Evas_Object *obj, const char *emission, const char *source);
54 static const char SIG_CLICKED[] = "clicked";
55 static const char SIG_REPEATED[] = "repeated";
56 static const char SIG_UNPRESSED[] = "unpressed";
57 static const Evas_Smart_Cb_Description _signals[] = {
65 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
67 if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
68 Evas_Event_Key_Down *ev = event_info;
69 Widget_Data *wd = elm_widget_data_get(obj);
70 if (!wd) return EINA_FALSE;
71 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
72 if (elm_widget_disabled_get(obj)) return EINA_FALSE;
73 if ((strcmp(ev->keyname, "Return")) &&
74 (strcmp(ev->keyname, "KP_Enter")) &&
75 (strcmp(ev->keyname, "space")))
78 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
79 edje_object_signal_emit(wd->btn, "elm,anim,activate", "elm");
84 _del_hook(Evas_Object *obj)
86 Widget_Data *wd = elm_widget_data_get(obj);
88 if (wd->label) eina_stringshare_del(wd->label);
89 if (wd->statelabel[DEFAULT]) eina_stringshare_del(wd->statelabel[DEFAULT]);
90 if (wd->statelabel[HIGHLIGHTED]) eina_stringshare_del(wd->statelabel[HIGHLIGHTED]);
91 if (wd->statelabel[FOCUSED]) eina_stringshare_del(wd->statelabel[FOCUSED]);
92 if (wd->statelabel[DISABLED]) eina_stringshare_del(wd->statelabel[DISABLED]);
97 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
99 Widget_Data *wd = elm_widget_data_get(obj);
101 if (elm_widget_focus_get(obj))
103 if (wd->statelabel[FOCUSED])
105 _set_label(obj, wd->statelabel[FOCUSED]);
107 edje_object_signal_emit(wd->btn, "elm,action,focus", "elm");
108 evas_object_focus_set(wd->btn, EINA_TRUE);
112 if (wd->statelabel[DEFAULT])
113 _set_label(obj, wd->statelabel[DEFAULT]);
116 _set_label(obj, wd->label);
118 edje_object_signal_emit(wd->btn, "elm,action,unfocus", "elm");
119 evas_object_focus_set(wd->btn, EINA_FALSE);
124 _theme_hook(Evas_Object *obj)
126 Widget_Data *wd = elm_widget_data_get(obj);
129 _elm_theme_object_set(obj, wd->btn, "button", "base", elm_widget_style_get(obj));
131 edje_object_part_swallow(wd->btn, "elm.swallow.content", wd->icon);
133 edje_object_signal_emit(wd->btn, "elm,state,text,visible", "elm");
135 edje_object_signal_emit(wd->btn, "elm,state,text,hidden", "elm");
137 edje_object_signal_emit(wd->btn, "elm,state,icon,visible", "elm");
139 edje_object_signal_emit(wd->btn, "elm,state,icon,hidden", "elm");
140 edje_object_part_text_set(wd->btn, "elm.text", wd->label);
141 if (elm_object_disabled_get(obj))
142 edje_object_signal_emit(wd->btn, "elm,state,disabled", "elm");
143 edje_object_message_signal_process(wd->btn);
144 edje_object_scale_set(wd->btn, elm_widget_scale_get(obj) * _elm_config->scale);
145 str = edje_object_data_get(wd->btn, "focus_highlight");
146 if ((str) && (!strcmp(str, "on")))
147 elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
149 elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
154 _disable_hook(Evas_Object *obj)
156 Widget_Data *wd = elm_widget_data_get(obj);
158 if (elm_widget_disabled_get(obj))
160 if (wd->statelabel[DISABLED] )
162 _set_label(obj, wd->statelabel[DISABLED]);
164 edje_object_signal_emit(wd->btn, "elm,state,disabled", "elm");
168 if (wd->statelabel[DEFAULT])
169 _set_label(obj, wd->statelabel[DEFAULT]);
172 _set_label(obj, wd->label);
174 edje_object_signal_emit(wd->btn, "elm,state,enabled", "elm");
179 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
181 Widget_Data *wd = elm_widget_data_get(obj);
183 edje_object_signal_emit(wd->btn, emission, source);
187 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
189 Widget_Data *wd = elm_widget_data_get(obj);
191 edje_object_signal_callback_add(wd->btn, emission, source, func_cb, data);
195 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
197 Widget_Data *wd = elm_widget_data_get(obj);
198 edje_object_signal_callback_del_full(wd->btn, emission, source, func_cb,
203 _sizing_eval(Evas_Object *obj)
205 Widget_Data *wd = elm_widget_data_get(obj);
206 Evas_Coord minw = -1, minh = -1;
210 elm_coords_finger_size_adjust(1, &minw, 1, &minh);
211 edje_object_size_min_restricted_calc(wd->btn, &minw, &minh, minw, minh);
212 elm_coords_finger_size_adjust(1, &minw, 1, &minh);
213 //Commenting to sync with open source and able to resize based on text change
214 evas_object_size_hint_min_get(obj, &w, &h);
215 //if (w > minw) minw = w;
216 if (h > minh) minh = h;
218 evas_object_size_hint_min_set(obj, minw, minh);
222 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
224 Widget_Data *wd = elm_widget_data_get(data);
226 if (obj != wd->icon) return;
231 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
233 Widget_Data *wd = elm_widget_data_get(obj);
234 Evas_Object *sub = event_info;
238 edje_object_signal_emit(wd->btn, "elm,state,icon,hidden", "elm");
239 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
240 _changed_size_hints, obj);
242 edje_object_message_signal_process(wd->btn);
248 _activate(Evas_Object *obj)
250 Widget_Data *wd = elm_widget_data_get(obj);
254 ecore_timer_del(wd->timer);
257 wd->repeating = EINA_FALSE;
258 evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
262 _activate_hook(Evas_Object *obj)
268 _signal_clicked(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
274 _autorepeat_send(void *data)
276 Widget_Data *wd = elm_widget_data_get(data);
277 if (!wd) return ECORE_CALLBACK_CANCEL;
279 evas_object_smart_callback_call(data, SIG_REPEATED, NULL);
283 return ECORE_CALLBACK_CANCEL;
286 return ECORE_CALLBACK_RENEW;
290 _autorepeat_initial_send(void *data)
292 Widget_Data *wd = elm_widget_data_get(data);
293 if (!wd) return ECORE_CALLBACK_CANCEL;
295 if (wd->timer) ecore_timer_del(wd->timer);
296 wd->repeating = EINA_TRUE;
297 _autorepeat_send(data);
298 wd->timer = ecore_timer_add(wd->ar_interval, _autorepeat_send, data);
300 return ECORE_CALLBACK_CANCEL;
304 _signal_pressed(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
306 Widget_Data *wd = elm_widget_data_get(data);
309 if (wd->statelabel[HIGHLIGHTED])
311 _set_label(data, wd->statelabel[HIGHLIGHTED]);
313 if ((wd->autorepeat) && (!wd->repeating))
315 if (wd->ar_threshold <= 0.0)
316 _autorepeat_initial_send(data); /* call immediately */
318 wd->timer = ecore_timer_add(wd->ar_threshold, _autorepeat_initial_send, data);
323 _signal_default_text_set(void *data, Evas_Object *obj, const char *emission, const char *source)
325 Widget_Data *wd = elm_widget_data_get(data);
327 if (wd->statelabel[DEFAULT])
328 _set_label(data, wd->statelabel[DEFAULT]);
331 _set_label(data, wd->label);
337 _signal_unpressed(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
339 Widget_Data *wd = elm_widget_data_get(data);
341 if (wd->statelabel[DEFAULT])
342 _set_label(data, wd->statelabel[DEFAULT]);
345 _set_label(data, wd->label);
350 ecore_timer_del(wd->timer);
353 wd->repeating = EINA_FALSE;
354 evas_object_smart_callback_call(data, SIG_UNPRESSED, NULL);
358 * Add a new button to the parent
359 * @param[in] parent The parent object
360 * @return The new object or NULL if it cannot be created
365 elm_button_add(Evas_Object *parent)
371 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
373 wd = ELM_NEW(Widget_Data);
374 e = evas_object_evas_get(parent);
376 obj = elm_widget_add(e);
377 ELM_SET_WIDTYPE(widtype, "button");
378 elm_widget_type_set(obj, "button");
379 elm_widget_sub_object_add(parent, obj);
380 elm_widget_on_focus_hook_set( obj, _on_focus_hook, NULL );
381 elm_widget_data_set(obj, wd);
382 elm_widget_del_hook_set(obj, _del_hook);
383 elm_widget_theme_hook_set(obj, _theme_hook);
384 elm_widget_disable_hook_set(obj, _disable_hook);
385 elm_widget_can_focus_set(obj, EINA_TRUE);
386 elm_widget_activate_hook_set(obj, _activate_hook);
387 elm_widget_event_hook_set(obj, _event_hook);
388 elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
389 elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
390 elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
392 wd->btn = edje_object_add(e);
393 _elm_theme_object_set(obj, wd->btn, "button", "base", "default");
394 wd->statetype[DEFAULT] = 0;
395 wd->statetype[HIGHLIGHTED] = 0;
396 wd->statetype[FOCUSED] = 0;
397 wd->statetype[DISABLED] = 0;
398 wd->statelabel[DEFAULT] = 0;
399 wd->statelabel[HIGHLIGHTED] = 0;
400 wd->statelabel[FOCUSED] = 0;
401 wd->statelabel[DISABLED] = 0;
402 edje_object_signal_callback_add(wd->btn, "elm,action,click", "",
403 _signal_clicked, obj);
404 edje_object_signal_callback_add(wd->btn, "elm,action,press", "",
405 _signal_pressed, obj);
406 edje_object_signal_callback_add(wd->btn, "elm,action,unpress", "",
407 _signal_unpressed, obj);
408 edje_object_signal_callback_add(wd->btn, "elm,action,default,text,set", "",
409 _signal_default_text_set, obj);
410 elm_widget_resize_object_set(obj, wd->btn);
412 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
416 // TODO: convert Elementary to subclassing of Evas_Smart_Class
417 // TODO: and save some bytes, making descriptions per-class and not instance!
418 evas_object_smart_callbacks_descriptions_set(obj, _signals);
423 * Set the label used in the button
425 * @param[in] obj The button object
426 * @param[in] label The text will be written on the button
431 elm_button_label_set(Evas_Object *obj, const char *label)
433 ELM_CHECK_WIDTYPE(obj, widtype);
434 Widget_Data *wd = elm_widget_data_get(obj);
436 eina_stringshare_replace(&wd->label, label);
438 edje_object_signal_emit(wd->btn, "elm,state,text,visible", "elm");
440 edje_object_signal_emit(wd->btn, "elm,state,text,hidden", "elm");
441 edje_object_message_signal_process(wd->btn);
442 edje_object_part_text_set(wd->btn, "elm.text", label);
447 _set_label(Evas_Object *obj, const char *label)
449 Widget_Data *wd = elm_widget_data_get(obj);
451 edje_object_part_text_set(wd->btn, "elm.text", label);
455 * Set the label for each state of button
457 * @param[in] obj The button object
458 * @param[in] label The text will be written on the button
459 * @param[in] state The state of button
464 elm_button_label_set_for_state(Evas_Object *obj, const char *label, UIControlState state)
466 Widget_Data *wd = elm_widget_data_get(obj);
469 if (label == NULL) return;
471 if (state == UIControlStateDefault)
473 wd->statetype[DEFAULT] = UIControlStateDefault;
474 eina_stringshare_replace(&wd->statelabel[DEFAULT], label);
477 if (state == UIControlStateHighlighted)
479 wd->statetype[HIGHLIGHTED] = UIControlStateHighlighted;
480 eina_stringshare_replace(&wd->statelabel[HIGHLIGHTED], label);
483 if (state == UIControlStateFocused)
485 wd->statetype[FOCUSED] = UIControlStateFocused;
486 eina_stringshare_replace(&wd->statelabel[FOCUSED], label);
489 if (state == UIControlStateDisabled)
491 wd->statetype[DISABLED] = UIControlStateDisabled;
492 eina_stringshare_replace(&wd->statelabel[DISABLED], label);
498 * Get the label of button
500 * @param[in] obj The button object
501 * @return The title of button
506 elm_button_label_get(const Evas_Object *obj)
508 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
509 Widget_Data *wd = elm_widget_data_get(obj);
510 if (!wd) return NULL;
514 * Get the label of button for each state
516 * @param[in] obj The button object
517 * @param[in] state The state of button
518 * @return The title of button for state
523 elm_button_label_get_for_state(const Evas_Object *obj, UIControlState state)
525 Widget_Data *wd = elm_widget_data_get(obj);
526 if (!wd) return NULL;
528 if (state == UIControlStateDefault)
529 return wd->statelabel[DEFAULT];
530 else if (state == UIControlStateHighlighted)
531 return wd->statelabel[HIGHLIGHTED];
532 else if (state == UIControlStateFocused)
533 return wd->statelabel[FOCUSED];
534 else if (state == UIControlStateDisabled)
535 return wd->statelabel[DISABLED];
541 * Set the icon used for the button
543 * Once the icon object is set, a previously set one will be deleted
544 * If you want to keep that old content object, use the
545 * elm_button_icon_unset() function.
547 * @param[in] obj The button object
548 * @param[in] icon The image for the button
553 elm_button_icon_set(Evas_Object *obj, Evas_Object *icon)
555 ELM_CHECK_WIDTYPE(obj, widtype);
556 Widget_Data *wd = elm_widget_data_get(obj);
558 if (wd->icon == icon) return;
559 if (wd->icon) evas_object_del(wd->icon);
563 elm_widget_sub_object_add(obj, icon);
564 evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
565 _changed_size_hints, obj);
566 edje_object_part_swallow(wd->btn, "elm.swallow.content", icon);
567 edje_object_signal_emit(wd->btn, "elm,state,icon,visible", "elm");
568 edje_object_message_signal_process(wd->btn);
574 * Get the icon used for the button
576 * Return the icon object which is set for this widget.
577 * @param[in] obj The button object
578 * @return The icon object that is being used
583 elm_button_icon_get(const Evas_Object *obj)
585 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
586 Widget_Data *wd = elm_widget_data_get(obj);
587 if (!wd) return NULL;
592 * Unset the icon used for the button
594 * Unparent and return the icon object which was set for this widget.
596 * @param[in] obj The button object
597 * @return The icon object that was being used
602 elm_button_icon_unset(Evas_Object *obj)
604 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
605 Widget_Data *wd = elm_widget_data_get(obj);
606 if (!wd) return NULL;
607 if (!wd->icon) return NULL;
608 Evas_Object *icon = wd->icon;
609 elm_widget_sub_object_del(obj, wd->icon);
610 edje_object_part_unswallow(wd->btn, wd->icon);
616 * Turn on/off the autorepeat event generated when the user keeps pressing on the button
618 * @param[in] obj The button object
619 * @param[in] on A bool to turn on/off the event
624 elm_button_autorepeat_set(Evas_Object *obj, Eina_Bool on)
626 ELM_CHECK_WIDTYPE(obj, widtype);
627 Widget_Data *wd = elm_widget_data_get(obj);
631 ecore_timer_del(wd->timer);
635 wd->repeating = EINA_FALSE;
639 * Get if autorepeat event is on
641 * @param obj The button object
642 * @return If autorepeat is on
647 elm_button_autorepeat_get(const Evas_Object *obj)
649 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
650 Widget_Data *wd = elm_widget_data_get(obj);
651 if (!wd) return EINA_FALSE;
652 return wd->autorepeat;
656 * Set the initial timeout before the autorepeat event is generated
658 * @param[in] obj The button object
659 * @param[in] t Timeout
664 elm_button_autorepeat_initial_timeout_set(Evas_Object *obj, double t)
666 ELM_CHECK_WIDTYPE(obj, widtype);
667 Widget_Data *wd = elm_widget_data_get(obj);
669 if (wd->ar_threshold == t) return;
672 ecore_timer_del(wd->timer);
675 wd->ar_threshold = t;
679 * Get the initial timeout before the autorepeat event is generated
681 * @param[in] obj The button object
687 elm_button_autorepeat_initial_timeout_get(const Evas_Object *obj)
689 ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
690 Widget_Data *wd = elm_widget_data_get(obj);
692 return wd->ar_threshold;
696 * Set the interval between each generated autorepeat event
698 * @param[in] obj The button object
699 * @param[in] t Interval
704 elm_button_autorepeat_gap_timeout_set(Evas_Object *obj, double t)
706 ELM_CHECK_WIDTYPE(obj, widtype);
707 Widget_Data *wd = elm_widget_data_get(obj);
709 if (wd->ar_interval == t) return;
712 if ((wd->repeating) && (wd->timer)) ecore_timer_interval_set(wd->timer, t);
716 * Get the interval between each generated autorepeat event
718 * @param[in] obj The button object
724 elm_button_autorepeat_gap_timeout_get(const Evas_Object *obj)
726 ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
727 Widget_Data *wd = elm_widget_data_get(obj);
729 return wd->ar_interval;