96371f0ae6cd4c4e81785ef0cd1d1012e0382540
[framework/uifw/elementary.git] / src / lib / elm_check.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_check.h"
4
5 EAPI const char ELM_CHECK_SMART_NAME[] = "elm_check";
6
7 static const Elm_Layout_Part_Alias_Description _content_aliases[] =
8 {
9    {"icon", "elm.swallow.content"},
10    {NULL, NULL}
11 };
12
13 static const Elm_Layout_Part_Alias_Description _text_aliases[] =
14 {
15    {"default", "elm.text"},
16    {"on", "elm.ontext"},
17    {"off", "elm.offtext"},
18    {NULL, NULL}
19 };
20
21 static const char SIG_CHANGED[] = "changed";
22
23 /* smart callbacks coming from elm check objects: */
24 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
25    {SIG_CHANGED, ""},
26    {NULL, NULL}
27 };
28
29 EVAS_SMART_SUBCLASS_NEW
30   (ELM_CHECK_SMART_NAME, _elm_check, Elm_Check_Smart_Class,
31   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
32
33 static void
34 _activate(Evas_Object *obj)
35 {
36    ELM_CHECK_DATA_GET(obj, sd);
37
38    sd->state = !sd->state;
39    if (sd->statep) *sd->statep = sd->state;
40    if (sd->state)
41      {
42         elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
43         if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
44              _elm_access_say(E_("State: On"));
45      }
46    else
47      {
48         elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
49         if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
50              _elm_access_say(E_("State: Off"));
51      }
52
53    evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
54 }
55
56 /* FIXME: replicated from elm_layout just because check's icon spot
57  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
58  * can changed the theme API */
59 static void
60 _icon_signal_emit(Evas_Object *obj)
61 {
62    char buf[64];
63
64    snprintf(buf, sizeof(buf), "elm,state,icon,%s",
65             elm_layout_content_get(obj, "icon") ? "visible" : "hidden");
66
67    elm_layout_signal_emit(obj, buf, "elm");
68 }
69
70 /* FIXME: replicated from elm_layout just because check's icon spot
71  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
72  * can changed the theme API */
73 static Eina_Bool
74 _elm_check_smart_sub_object_del(Evas_Object *obj,
75                                  Evas_Object *sobj)
76 {
77    if (!ELM_WIDGET_CLASS(_elm_check_parent_sc)->sub_object_del(obj, sobj))
78      return EINA_FALSE;
79
80    _icon_signal_emit(obj);
81
82    return EINA_TRUE;
83 }
84
85 static Eina_Bool
86 _elm_check_smart_activate(Evas_Object *obj, Elm_Activate act)
87 {
88    if (act != ELM_ACTIVATE_DEFAULT) return EINA_FALSE;
89
90    _activate(obj);
91
92    return EINA_TRUE;
93 }
94
95 /* FIXME: replicated from elm_layout just because check's icon spot
96  * is elm.swallow.content, not elm.swallow.icon. Fix that whenever we
97  * can changed the theme API */
98 static Eina_Bool
99 _elm_check_smart_content_set(Evas_Object *obj,
100                               const char *part,
101                               Evas_Object *content)
102 {
103    if (!ELM_CONTAINER_CLASS(_elm_check_parent_sc)->content_set
104          (obj, part, content))
105      return EINA_FALSE;
106
107    _icon_signal_emit(obj);
108
109    return EINA_TRUE;
110 }
111
112 static void
113 _elm_check_smart_sizing_eval(Evas_Object *obj)
114 {
115    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
116
117    ELM_CHECK_DATA_GET(obj, sd);
118
119    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
120    edje_object_size_min_restricted_calc
121      (ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh, minw, minh);
122    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
123    evas_object_size_hint_min_set(obj, minw, minh);
124    evas_object_size_hint_max_set(obj, maxw, maxh);
125 }
126
127 static Eina_Bool
128 _elm_check_smart_event(Evas_Object *obj,
129                        Evas_Object *src __UNUSED__,
130                        Evas_Callback_Type type,
131                        void *event_info)
132 {
133    Evas_Event_Key_Down *ev = event_info;
134
135    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
136
137    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
138
139    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
140
141    if ((strcmp(ev->keyname, "Return")) &&
142        (strcmp(ev->keyname, "KP_Enter")) &&
143        (strcmp(ev->keyname, "space")))
144      return EINA_FALSE;
145
146    _activate(obj);
147    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
148
149    return EINA_TRUE;
150 }
151
152 static Eina_Bool
153 _elm_check_smart_theme(Evas_Object *obj)
154 {
155    ELM_CHECK_DATA_GET(obj, sd);
156
157    if (!ELM_WIDGET_CLASS(_elm_check_parent_sc)->theme(obj)) return EINA_FALSE;
158
159    if (!sd->state) elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
160    else elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
161
162    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
163
164    /* FIXME: replicated from elm_layout just because check's icon spot
165     * is elm.swallow.content, not elm.swallow.icon. Fix that whenever
166     * we can changed the theme API */
167    _icon_signal_emit(obj);
168
169    elm_layout_sizing_eval(obj);
170
171    return EINA_TRUE;
172 }
173
174 static char *
175 _access_info_cb(void *data __UNUSED__, Evas_Object *obj)
176 {
177    const char *txt = elm_widget_access_info_get(obj);
178
179    if (!txt) txt = elm_layout_text_get(obj, NULL);
180    if (txt) return strdup(txt);
181
182    return NULL;
183 }
184
185 static char *
186 _access_state_cb(void *data, Evas_Object *obj)
187 {
188    Elm_Check_Smart_Data *sd = data;
189    const char *on_text, *off_text;
190
191    if (elm_widget_disabled_get(obj))
192      return strdup(E_("State: Disabled"));
193    if (sd->state)
194      {
195         on_text = elm_layout_text_get(ELM_WIDGET_DATA(sd)->obj, "on");
196
197         if (on_text)
198           {
199              char buf[1024];
200
201              snprintf(buf, sizeof(buf), "%s: %s", E_("State"), on_text);
202              return strdup(buf);
203           }
204         else
205           return strdup(E_("State: On"));
206      }
207
208    off_text = elm_layout_text_get(ELM_WIDGET_DATA(sd)->obj, "off");
209
210    if (off_text)
211      {
212         char buf[1024];
213
214         snprintf(buf, sizeof(buf), "%s: %s", E_("State"), off_text);
215         return strdup(buf);
216      }
217    return strdup(E_("State: Off"));
218 }
219
220 static void
221 _on_check_off(void *data,
222               Evas_Object *o __UNUSED__,
223               const char *emission __UNUSED__,
224               const char *source __UNUSED__)
225 {
226    Evas_Object *obj = data;
227
228    ELM_CHECK_DATA_GET(obj, sd);
229
230    sd->state = EINA_FALSE;
231    if (sd->statep) *sd->statep = sd->state;
232
233    elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
234    evas_object_smart_callback_call(data, SIG_CHANGED, NULL);
235 }
236
237 static void
238 _on_check_on(void *data,
239              Evas_Object *o __UNUSED__,
240              const char *emission __UNUSED__,
241              const char *source __UNUSED__)
242 {
243    Evas_Object *obj = data;
244
245    ELM_CHECK_DATA_GET(obj, sd);
246
247    sd->state = EINA_TRUE;
248    if (sd->statep) *sd->statep = sd->state;
249    elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
250    evas_object_smart_callback_call(data, SIG_CHANGED, NULL);
251 }
252
253 static void
254 _on_check_toggle(void *data,
255                  Evas_Object *o __UNUSED__,
256                  const char *emission __UNUSED__,
257                  const char *source __UNUSED__)
258 {
259    _activate(data);
260 }
261
262 static void
263 _elm_check_smart_add(Evas_Object *obj)
264 {
265    EVAS_SMART_DATA_ALLOC(obj, Elm_Check_Smart_Data);
266
267    ELM_WIDGET_CLASS(_elm_check_parent_sc)->base.add(obj);
268
269    edje_object_signal_callback_add
270      (ELM_WIDGET_DATA(priv)->resize_obj, "elm,action,check,on", "",
271      _on_check_on, obj);
272    edje_object_signal_callback_add
273      (ELM_WIDGET_DATA(priv)->resize_obj, "elm,action,check,off", "",
274      _on_check_off, obj);
275    edje_object_signal_callback_add
276      (ELM_WIDGET_DATA(priv)->resize_obj, "elm,action,check,toggle", "",
277      _on_check_toggle, obj);
278
279    _elm_access_object_register(obj, ELM_WIDGET_DATA(priv)->resize_obj);
280    _elm_access_text_set
281      (_elm_access_object_get(obj), ELM_ACCESS_TYPE, E_("Check"));
282    _elm_access_callback_set
283      (_elm_access_object_get(obj), ELM_ACCESS_INFO, _access_info_cb, priv);
284    _elm_access_callback_set
285      (_elm_access_object_get(obj), ELM_ACCESS_STATE, _access_state_cb, priv);
286
287    elm_widget_can_focus_set(obj, EINA_TRUE);
288
289    elm_layout_theme_set(obj, "check", "base", elm_widget_style_get(obj));
290    elm_layout_sizing_eval(obj);
291 }
292
293 static void
294 _elm_check_smart_set_user(Elm_Check_Smart_Class *sc)
295 {
296    ELM_WIDGET_CLASS(sc)->base.add = _elm_check_smart_add;
297
298    ELM_WIDGET_CLASS(sc)->theme = _elm_check_smart_theme;
299    ELM_WIDGET_CLASS(sc)->event = _elm_check_smart_event;
300    ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_check_smart_sub_object_del;
301    ELM_WIDGET_CLASS(sc)->activate = _elm_check_smart_activate;
302
303    /* not a 'focus chain manager' */
304    ELM_WIDGET_CLASS(sc)->focus_next = NULL;
305    ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
306
307    ELM_CONTAINER_CLASS(sc)->content_set = _elm_check_smart_content_set;
308
309    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_check_smart_sizing_eval;
310
311    ELM_LAYOUT_CLASS(sc)->content_aliases = _content_aliases;
312    ELM_LAYOUT_CLASS(sc)->text_aliases = _text_aliases;
313 }
314
315 EAPI const Elm_Check_Smart_Class *
316 elm_check_smart_class_get(void)
317 {
318    static Elm_Check_Smart_Class _sc =
319      ELM_CHECK_SMART_CLASS_INIT_NAME_VERSION(ELM_CHECK_SMART_NAME);
320    static const Elm_Check_Smart_Class *class = NULL;
321    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
322
323    if (class)
324      return class;
325
326    _elm_check_smart_set(&_sc);
327    esc->callbacks = _smart_callbacks;
328    class = &_sc;
329
330    return class;
331 }
332
333 EAPI Evas_Object *
334 elm_check_add(Evas_Object *parent)
335 {
336    Evas_Object *obj;
337
338    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
339
340    obj = elm_widget_add(_elm_check_smart_class_new(), parent);
341    if (!obj) return NULL;
342
343    if (!elm_widget_sub_object_add(parent, obj))
344      ERR("could not add %p as sub object of %p", obj, parent);
345
346    return obj;
347 }
348
349 EAPI void
350 elm_check_state_set(Evas_Object *obj,
351                     Eina_Bool state)
352 {
353    ELM_CHECK_CHECK(obj);
354    ELM_CHECK_DATA_GET(obj, sd);
355
356    if (state != sd->state)
357      {
358         sd->state = state;
359         if (sd->statep) *sd->statep = sd->state;
360         if (sd->state)
361           elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
362         else
363           elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
364      }
365
366    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
367 }
368
369 EAPI Eina_Bool
370 elm_check_state_get(const Evas_Object *obj)
371 {
372    ELM_CHECK_CHECK(obj) EINA_FALSE;
373    ELM_CHECK_DATA_GET(obj, sd);
374
375    return sd->state;
376 }
377
378 EAPI void
379 elm_check_state_pointer_set(Evas_Object *obj,
380                             Eina_Bool *statep)
381 {
382    ELM_CHECK_CHECK(obj);
383    ELM_CHECK_DATA_GET(obj, sd);
384
385    if (statep)
386      {
387         sd->statep = statep;
388         if (*sd->statep != sd->state)
389           {
390              sd->state = *sd->statep;
391              if (sd->state)
392                elm_layout_signal_emit(obj, "elm,state,check,on", "elm");
393              else
394                elm_layout_signal_emit(obj, "elm,state,check,off", "elm");
395           }
396      }
397    else
398      sd->statep = NULL;
399 }