efl/legacy/elementary/src/lib/elm_button.c

512 lines
15 KiB
C
Raw Normal View History

#include <Elementary.h>
#include "elm_priv.h"
/**
* @defgroup Button Button
*
* This is a push-button. Press it and run some function. It can contain
* a simple label and icon object.
*/
typedef struct _Widget_Data Widget_Data;
struct _Widget_Data
{
2009-09-26 10:39:29 -07:00
Evas_Object *btn, *icon;
const char *label;
Eina_Bool autorepeat;
Eina_Bool repeating;
double ar_threshold;
double ar_interval;
Ecore_Timer *timer;
};
static const char *widtype = NULL;
static void _del_hook(Evas_Object *obj);
static void _theme_hook(Evas_Object *obj);
static void _disable_hook(Evas_Object *obj);
static void _sizing_eval(Evas_Object *obj);
static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _sub_del(void *data, Evas_Object *obj, void *event_info);
static void _signal_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _signal_pressed(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _signal_unpressed(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _on_focus_hook(void *data, Evas_Object *obj);
static void _activate(Evas_Object *obj);
static void _activate_hook(Evas_Object *obj);
static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
Evas_Callback_Type type, void *event_info);
static const char SIG_CLICKED[] = "clicked";
static const char SIG_REPEATED[] = "repeated";
static const char SIG_UNPRESSED[] = "unpressed";
static const Evas_Smart_Cb_Description _signals[] = {
{SIG_CLICKED, ""},
{SIG_REPEATED, ""},
{SIG_UNPRESSED, ""},
{NULL, NULL}
};
static Eina_Bool
_event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
{
if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
Evas_Event_Key_Down *ev = event_info;
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return EINA_FALSE;
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
if (elm_widget_disabled_get(obj)) return EINA_FALSE;
2010-10-22 14:41:22 -07:00
if ((strcmp(ev->keyname, "Return")) && (strcmp(ev->keyname, "space")))
return EINA_FALSE;
_activate(obj);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
edje_object_signal_emit(wd->btn, "elm,anim,activate", "elm");
return EINA_TRUE;
}
static void
_del_hook(Evas_Object *obj)
{
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
if (wd->label) eina_stringshare_del(wd->label);
free(wd);
}
static void
_on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
{
Widget_Data *wd = elm_widget_data_get(obj);
2010-03-08 23:30:48 -08:00
if (!wd) return;
if (elm_widget_focus_get(obj))
{
edje_object_signal_emit(wd->btn, "elm,action,focus", "elm");
evas_object_focus_set(wd->btn, EINA_TRUE);
}
else
{
edje_object_signal_emit(wd->btn, "elm,action,unfocus", "elm");
evas_object_focus_set(wd->btn, EINA_FALSE);
}
}
static void
_theme_hook(Evas_Object *obj)
{
Widget_Data *wd = elm_widget_data_get(obj);
const char *str;
if (!wd) return;
_elm_theme_object_set(obj, wd->btn, "button", "base", elm_widget_style_get(obj));
if (wd->icon)
edje_object_part_swallow(wd->btn, "elm.swallow.content", wd->icon);
if (wd->label)
edje_object_signal_emit(wd->btn, "elm,state,text,visible", "elm");
else
edje_object_signal_emit(wd->btn, "elm,state,text,hidden", "elm");
if (wd->icon)
edje_object_signal_emit(wd->btn, "elm,state,icon,visible", "elm");
else
edje_object_signal_emit(wd->btn, "elm,state,icon,hidden", "elm");
edje_object_part_text_set(wd->btn, "elm.text", wd->label);
From: RAJEEV RANJAN <rajeev.r@samsung.com> Subject: Patch to address some focus and disabling issue in elementary widgets We have observed some generic issues in Elementary widgets. 1. Widgets not getting disabled if we call elm_object_disabled_set(ob, EINA_TRUE) followed by elm_object_style_set(obj, <style_name>); This works fine if we disable the widget after changing the style(call to theme_hook happens here). It happens because we are not sending the edje signal in theme_hook of the widgets, if the widget is already in disabled state. I have added this code in theme_hook of elm_button as an example and we will need to apply the similar stuff in all other widgets if needed. 2. The widget gets focused in a particular scenario even though we call elm_object_focus_allow_set(obj, EINA_FALSE). The code snippet to explain the scenario which we observed was like this: Evas_Object *button = NULL, *icon = NULL; button = elm_button_add(parent); elm_object_focus_allow_set(button, EINA_FALSE); icon = elm_icon_add(button); elm_icon_file_set(icon, EDJE_PATH, "test.icon"); elm_button_icon_set(button, icon); An icon object does not take focus by default. But still whenever the focus returned to the parent(layout in this case) after closing some popup, the button gets focused though we had disabled it explicitly. The reason is in this case, when we call elm_icon_add(button), icon gets added to button as a sub-object and in this call, we set sd->child_can_focus for button(the parent) as true because till now, the focus property for icon has not been set to false which by default is true. This was set later in the function elm_icon_add() as follows: elm_widget_can_focus_set(obj, EINA_FALSE); Actually this should be set before adding icon as sub-object of the parent which in this case is a button. I have done the required modification in the function elm_icon_add(). Attached to this mail is the patch file for these two issues.The revision from which I have created this patch file is 53129. We may need to do similar changes in other widgets if required. SVN revision: 53137
2010-10-07 00:31:24 -07:00
if (elm_object_disabled_get(obj))
edje_object_signal_emit(wd->btn, "elm,state,disabled", "elm");
edje_object_message_signal_process(wd->btn);
edje_object_scale_set(wd->btn, elm_widget_scale_get(obj) * _elm_config->scale);
str = edje_object_data_get(wd->btn, "focus_highlight");
2010-10-22 14:41:22 -07:00
if ((str) && (!strcmp(str, "on")))
elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
else
elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
_sizing_eval(obj);
}
static void
_disable_hook(Evas_Object *obj)
{
Widget_Data *wd = elm_widget_data_get(obj);
2010-03-08 23:30:48 -08:00
if (!wd) return;
if (elm_widget_disabled_get(obj))
edje_object_signal_emit(wd->btn, "elm,state,disabled", "elm");
else
edje_object_signal_emit(wd->btn, "elm,state,enabled", "elm");
}
static void
_signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
{
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
edje_object_signal_emit(wd->btn, emission, source);
}
static void
_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)
{
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
edje_object_signal_callback_add(wd->btn, emission, source, func_cb, data);
}
static void *
_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))
{
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return NULL;
return edje_object_signal_callback_del(wd->btn, emission, source,
func_cb);
}
static void
_sizing_eval(Evas_Object *obj)
{
Widget_Data *wd = elm_widget_data_get(obj);
Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
2009-09-26 10:39:29 -07:00
if (!wd) return;
elm_coords_finger_size_adjust(1, &minw, 1, &minh);
edje_object_size_min_restricted_calc(wd->btn, &minw, &minh, minw, minh);
elm_coords_finger_size_adjust(1, &minw, 1, &minh);
evas_object_size_hint_min_set(obj, minw, minh);
evas_object_size_hint_max_set(obj, maxw, maxh);
}
static void
_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
Widget_Data *wd = elm_widget_data_get(data);
if (!wd) return;
if (obj != wd->icon) return;
_sizing_eval(data);
}
static void
_sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
{
Widget_Data *wd = elm_widget_data_get(obj);
Evas_Object *sub = event_info;
2009-09-26 10:39:29 -07:00
if (!wd) return;
if (sub == wd->icon)
{
edje_object_signal_emit(wd->btn, "elm,state,icon,hidden", "elm");
evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
_changed_size_hints, obj);
wd->icon = NULL;
edje_object_message_signal_process(wd->btn);
_sizing_eval(obj);
}
}
static void
_activate(Evas_Object *obj)
{
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
if (wd->timer)
{
ecore_timer_del(wd->timer);
wd->timer = NULL;
}
wd->repeating = EINA_FALSE;
evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
_signal_unpressed(obj, wd->btn, NULL, NULL); /* safe guard when the theme does not emit the 'unpress' signal */
}
static void
_activate_hook(Evas_Object *obj)
{
_activate(obj);
}
static void
_signal_clicked(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
{
_activate(data);
}
static Eina_Bool
_autorepeat_send(void *data)
{
Widget_Data *wd = elm_widget_data_get(data);
if (!wd) return ECORE_CALLBACK_CANCEL;
evas_object_smart_callback_call(data, SIG_REPEATED, NULL);
if (!wd->repeating)
{
wd->timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_autorepeat_initial_send(void *data)
{
Widget_Data *wd = elm_widget_data_get(data);
if (!wd) return ECORE_CALLBACK_CANCEL;
if (wd->timer) ecore_timer_del(wd->timer);
wd->repeating = EINA_TRUE;
_autorepeat_send(data);
wd->timer = ecore_timer_add(wd->ar_interval, _autorepeat_send, data);
return ECORE_CALLBACK_CANCEL;
}
static void
_signal_pressed(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
{
Widget_Data *wd = elm_widget_data_get(data);
if (!wd) return;
2010-10-22 14:41:22 -07:00
if ((wd->autorepeat) && (!wd->repeating))
{
if (wd->ar_threshold <= 0.0)
_autorepeat_initial_send(data); /* call immediately */
else
wd->timer = ecore_timer_add(wd->ar_threshold, _autorepeat_initial_send, data);
}
}
static void
_signal_unpressed(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
{
Widget_Data *wd = elm_widget_data_get(data);
if (!wd) return;
if (wd->timer)
{
ecore_timer_del(wd->timer);
wd->timer = NULL;
}
wd->repeating = EINA_FALSE;
evas_object_smart_callback_call(data, SIG_UNPRESSED, NULL);
}
/**
* Add a new button to the parent
* @param parent The parent object
* @return The new object or NULL if it cannot be created
*
* @ingroup Button
*/
EAPI Evas_Object *
elm_button_add(Evas_Object *parent)
{
Evas_Object *obj;
Evas *e;
Widget_Data *wd;
wd = ELM_NEW(Widget_Data);
e = evas_object_evas_get(parent);
obj = elm_widget_add(e);
ELM_SET_WIDTYPE(widtype, "button");
elm_widget_type_set(obj, "button");
elm_widget_sub_object_add(parent, obj);
elm_widget_on_focus_hook_set( obj, _on_focus_hook, NULL );
elm_widget_data_set(obj, wd);
elm_widget_del_hook_set(obj, _del_hook);
elm_widget_theme_hook_set(obj, _theme_hook);
elm_widget_disable_hook_set(obj, _disable_hook);
elm_widget_can_focus_set(obj, EINA_TRUE);
elm_widget_activate_hook_set(obj, _activate_hook);
elm_widget_event_hook_set(obj, _event_hook);
elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
wd->btn = edje_object_add(e);
_elm_theme_object_set(obj, wd->btn, "button", "base", "default");
edje_object_signal_callback_add(wd->btn, "elm,action,click", "",
2009-09-26 10:39:29 -07:00
_signal_clicked, obj);
edje_object_signal_callback_add(wd->btn, "elm,action,press", "",
_signal_pressed, obj);
edje_object_signal_callback_add(wd->btn, "elm,action,unpress", "",
_signal_unpressed, obj);
elm_widget_resize_object_set(obj, wd->btn);
evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
_theme_hook(obj);
// TODO: convert Elementary to subclassing of Evas_Smart_Class
// TODO: and save some bytes, making descriptions per-class and not instance!
evas_object_smart_callbacks_descriptions_set(obj, _signals);
return obj;
}
/**
* Set the label used in the button
*
* @param obj The button object
* @param label The text will be written on the button
*
* @ingroup Button
*/
EAPI void
elm_button_label_set(Evas_Object *obj, const char *label)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
2009-09-26 10:39:29 -07:00
if (!wd) return;
eina_stringshare_replace(&wd->label, label);
if (label)
edje_object_signal_emit(wd->btn, "elm,state,text,visible", "elm");
else
edje_object_signal_emit(wd->btn, "elm,state,text,hidden", "elm");
2009-09-26 10:39:29 -07:00
edje_object_message_signal_process(wd->btn);
edje_object_part_text_set(wd->btn, "elm.text", label);
_sizing_eval(obj);
}
2010-03-08 23:30:48 -08:00
EAPI const char *
elm_button_label_get(const Evas_Object *obj)
{
2010-03-08 23:30:48 -08:00
ELM_CHECK_WIDTYPE(obj, widtype) NULL;
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return NULL;
return wd->label;
}
/**
* Set the icon used for the button
*
* Once the icon object is set, a previously set one will be deleted
* If you want to keep that old content object, use the
* elm_button_icon_unset() function.
*
* @param obj The button object
* @param icon The icon object for the button
*
* @ingroup Button
*/
EAPI void
elm_button_icon_set(Evas_Object *obj, Evas_Object *icon)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
if (wd->icon == icon) return;
if (wd->icon) evas_object_del(wd->icon);
wd->icon = icon;
if (icon)
{
elm_widget_sub_object_add(obj, icon);
evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
_changed_size_hints, obj);
edje_object_part_swallow(wd->btn, "elm.swallow.content", icon);
edje_object_signal_emit(wd->btn, "elm,state,icon,visible", "elm");
edje_object_message_signal_process(wd->btn);
}
_sizing_eval(obj);
}
2010-03-08 23:30:48 -08:00
/**
* Get the icon used for the button
*
* Return the icon object which is set for this widget.
*
2010-03-08 23:30:48 -08:00
* @param obj The button object
* @return The icon object that is being used
2010-03-08 23:30:48 -08:00
*
* @ingroup Button
*/
EAPI Evas_Object *
elm_button_icon_get(const Evas_Object *obj)
{
2010-03-08 23:30:48 -08:00
ELM_CHECK_WIDTYPE(obj, widtype) NULL;
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return NULL;
return wd->icon;
}
/**
* Unset the icon used for the button
*
* Unparent and return the icon object which was set for this widget.
*
* @param obj The button object
* @return The icon object that was being used
*
* @ingroup Button
*/
EAPI Evas_Object *
elm_button_icon_unset(Evas_Object *obj)
{
ELM_CHECK_WIDTYPE(obj, widtype) NULL;
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return NULL;
if (!wd->icon) return NULL;
Evas_Object *icon = wd->icon;
elm_widget_sub_object_del(obj, wd->icon);
edje_object_part_unswallow(wd->btn, wd->icon);
wd->icon = NULL;
return icon;
}
/**
* Turn on/off the autorepeat event generated when the user keeps pressing on the button
*
* @param obj The button object
* @param on A bool to turn on/off the event
*
* @ingroup Button
*/
EAPI void
elm_button_autorepeat_set(Evas_Object *obj, Eina_Bool on)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
2010-03-08 23:30:48 -08:00
if (wd->timer)
{
ecore_timer_del(wd->timer);
wd->timer = NULL;
}
wd->autorepeat = on;
wd->repeating = EINA_FALSE;
}
/**
* Set the initial timeout before the autorepeat event is generated
*
* @param obj The button object
* @param t Timeout
*
* @ingroup Button
*/
EAPI void
elm_button_autorepeat_initial_timeout_set(Evas_Object *obj, double t)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
2010-03-08 23:30:48 -08:00
if (wd->ar_threshold == t) return;
if (wd->timer)
{
ecore_timer_del(wd->timer);
wd->timer = NULL;
}
wd->ar_threshold = t;
}
/**
* Set the interval between each generated autorepeat event
*
* @param obj The button object
* @param t Interval
*
* @ingroup Button
*/
EAPI void
elm_button_autorepeat_gap_timeout_set(Evas_Object *obj, double t)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
2010-03-08 23:30:48 -08:00
if (wd->ar_interval == t) return;
wd->ar_interval = t;
2010-10-22 14:41:22 -07:00
if ((wd->repeating) && (wd->timer)) ecore_timer_interval_set(wd->timer, t);
}