Merge "Fixed some memory issue found by Prevent tool analysis. Issue IDs[18881, 18882...
[framework/uifw/elementary.git] / src / lib / elm_check.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5
6 struct _Widget_Data
7 {
8    Evas_Object *chk, *icon;
9    Eina_Bool state;
10    Eina_Bool *statep;
11    const char *label;
12 };
13
14 static const char *widtype = NULL;
15 static void _del_hook(Evas_Object *obj);
16 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
17 static void _theme_hook(Evas_Object *obj);
18 static void _disable_hook(Evas_Object *obj);
19 static void _sizing_eval(Evas_Object *obj);
20 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
21 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
22 static void _signal_check_off(void *data, Evas_Object *obj, const char *emission, const char *source);
23 static void _signal_check_on(void *data, Evas_Object *obj, const char *emission, const char *source);
24 static void _signal_check_toggle(void *data, Evas_Object *obj, const char *emission, const char *source);
25 static void _on_focus_hook(void *data, Evas_Object *obj);
26 static void _activate_hook(Evas_Object *obj);
27 static void _activate(Evas_Object *obj);
28 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
29                              Evas_Callback_Type type, void *event_info);
30
31 static const char SIG_CHANGED[] = "changed";
32 static const Evas_Smart_Cb_Description _signals[] = {
33        {SIG_CHANGED, ""},
34        {NULL, NULL}
35 };
36
37 static Eina_Bool
38 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
39 {
40    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
41    Evas_Event_Key_Down *ev = event_info;
42    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
43    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
44    if ((strcmp(ev->keyname, "Return")) &&
45        (strcmp(ev->keyname, "KP_Enter")) &&
46        (strcmp(ev->keyname, "space")))
47      return EINA_FALSE;
48    _activate(obj);
49    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
50    return EINA_TRUE;
51 }
52
53
54 static void
55 _del_hook(Evas_Object *obj)
56 {
57    Widget_Data *wd = elm_widget_data_get(obj);
58    if (!wd) return;
59    if (wd->label) eina_stringshare_del(wd->label);
60    free(wd);
61 }
62
63 static void
64 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
65 {
66    Widget_Data *wd = elm_widget_data_get(obj);
67    if (!wd) return;
68    if (elm_widget_focus_get(obj))
69      {
70         edje_object_signal_emit(wd->chk, "elm,action,focus", "elm");
71         evas_object_focus_set(wd->chk, EINA_TRUE);
72      }
73    else
74      {
75         edje_object_signal_emit(wd->chk, "elm,action,unfocus", "elm");
76         evas_object_focus_set(wd->chk, EINA_FALSE);
77      }
78 }
79
80 static void
81 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
82 {
83    Widget_Data *wd = elm_widget_data_get(obj);
84    if (!wd) return;
85    edje_object_mirrored_set(wd->chk, rtl);
86 }
87
88 static void
89 _theme_hook(Evas_Object *obj)
90 {
91    unsigned int counter = 0;
92    unsigned int i = 1;
93    unsigned int length = 0;
94    const char *str = NULL;
95    char labels[128] ;
96    char buffer[PATH_MAX]={'\0',};
97    char s1[PATH_MAX] = {'\0',};
98    Widget_Data *wd = elm_widget_data_get(obj);
99    if (!wd) return;
100
101    _elm_widget_mirrored_reload(obj);
102    _mirrored_set(obj, elm_widget_mirrored_get(obj));
103    _elm_theme_object_set(obj, wd->chk, "check", "base", elm_widget_style_get(obj));
104    if (wd->icon)
105      edje_object_signal_emit(wd->chk, "elm,state,icon,visible", "elm");
106    else
107      edje_object_signal_emit(wd->chk, "elm,state,icon,hidden", "elm");
108    if (wd->state)
109      edje_object_signal_emit(wd->chk, "elm,state,check,on", "elm");
110    else
111      edje_object_signal_emit(wd->chk, "elm,state,check,off", "elm");
112    if (wd->label)
113      edje_object_signal_emit(wd->chk, "elm,state,text,visible", "elm");
114    else
115      edje_object_signal_emit(wd->chk, "elm,state,text,hidden", "elm");
116    edje_object_part_text_set(wd->chk, "elm.text", wd->label);
117    if (elm_widget_disabled_get(obj))
118      edje_object_signal_emit(wd->chk, "elm,state,disabled", "elm");
119    edje_object_message_signal_process(wd->chk);
120    edje_object_scale_set(wd->chk, elm_widget_scale_get(obj) * _elm_config->scale);
121
122    //introduced internationalization of additional text parts used in style
123    while (1)
124      {
125         // s1 is  used  to store part name while buffer is used to store the part's value string
126         snprintf(labels,sizeof(labels),"label_%d",i++);
127         str = edje_object_data_get(wd->chk,labels);
128         if (!str) break;
129         length = strlen(str);
130         while ((str[counter]!= ' ') && (counter < length))
131           counter++;
132         if (counter == length)
133           continue;
134         strncpy(s1, str, counter);
135         s1[counter] = '\0';
136         strncpy(buffer, str + counter, sizeof(buffer));
137         edje_object_part_text_set(wd->chk, s1, E_(buffer));
138      }
139    _sizing_eval(obj);
140 }
141
142 static void
143 _disable_hook(Evas_Object *obj)
144 {
145    Widget_Data *wd = elm_widget_data_get(obj);
146    if (!wd) return;
147    if (elm_widget_disabled_get(obj))
148      edje_object_signal_emit(wd->chk, "elm,state,disabled", "elm");
149    else
150      edje_object_signal_emit(wd->chk, "elm,state,enabled", "elm");
151 }
152
153 static void
154 _sizing_eval(Evas_Object *obj)
155 {
156    Widget_Data *wd = elm_widget_data_get(obj);
157    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
158    if (!wd) return;
159    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
160    edje_object_size_min_restricted_calc(wd->chk, &minw, &minh, minw, minh);
161    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
162    evas_object_size_hint_min_set(obj, minw, minh);
163    evas_object_size_hint_max_set(obj, maxw, maxh);
164 }
165
166 static void
167 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
168 {
169    Widget_Data *wd = elm_widget_data_get(data);
170    if (!wd) return;
171    if (obj != wd->icon) return;
172    Evas_Coord mw, mh;
173    evas_object_size_hint_min_get(obj, &mw, &mh);
174    _sizing_eval(data);
175 }
176
177 static void
178 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
179 {
180    Widget_Data *wd = elm_widget_data_get(obj);
181    Evas_Object *sub = event_info;
182    if (!wd) return;
183    if (sub == wd->icon)
184      {
185         edje_object_signal_emit(wd->chk, "elm,state,icon,hidden", "elm");
186         evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
187                                             _changed_size_hints, obj);
188         wd->icon = NULL;
189         _sizing_eval(obj);
190         edje_object_message_signal_process(wd->chk);
191      }
192 }
193
194 static void
195 _signal_check_off(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
196 {
197    Widget_Data *wd = elm_widget_data_get(data);
198    if (!wd) return;
199    wd->state = EINA_FALSE;
200    if (wd->statep) *wd->statep = wd->state;
201    edje_object_signal_emit(wd->chk, "elm,state,check,off", "elm");
202    evas_object_smart_callback_call(data, SIG_CHANGED, NULL);
203 }
204
205 static void
206 _signal_check_on(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
207 {
208    Widget_Data *wd = elm_widget_data_get(data);
209    if (!wd) return;
210    wd->state = EINA_TRUE;
211    if (wd->statep) *wd->statep = wd->state;
212    edje_object_signal_emit(wd->chk, "elm,state,check,on", "elm");
213    evas_object_smart_callback_call(data, SIG_CHANGED, NULL);
214 }
215
216 static void
217 _signal_check_toggle(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
218 {
219    _activate(data);
220 }
221
222 static void
223 _activate_hook(Evas_Object *obj)
224 {
225    _activate(obj);
226 }
227
228 static void
229 _activate(Evas_Object *obj)
230 {
231    Widget_Data *wd = elm_widget_data_get(obj);
232    if (!wd) return;
233    wd->state = !wd->state;
234    if (wd->statep) *wd->statep = wd->state;
235    if (wd->state)
236      edje_object_signal_emit(wd->chk, "elm,state,check,on", "elm");
237    else
238      edje_object_signal_emit(wd->chk, "elm,state,check,off", "elm");
239    evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
240 }
241
242 static void
243 _elm_check_label_set(Evas_Object *obj, const char *item, const char *label)
244 {
245    ELM_CHECK_WIDTYPE(obj, widtype);
246    Widget_Data *wd = elm_widget_data_get(obj);
247    if (item && strcmp(item, "default")) return;
248    if (!wd) return;
249    eina_stringshare_replace(&wd->label, label);
250    if (label)
251      edje_object_signal_emit(wd->chk, "elm,state,text,visible", "elm");
252    else
253      edje_object_signal_emit(wd->chk, "elm,state,text,hidden", "elm");
254    edje_object_message_signal_process(wd->chk);
255    edje_object_part_text_set(wd->chk, "elm.text", label);
256    _sizing_eval(obj);
257 }
258
259 static const char *
260 _elm_check_label_get(const Evas_Object *obj, const char *item)
261 {
262    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
263    Widget_Data *wd = elm_widget_data_get(obj);
264    if (item && strcmp(item, "default")) return NULL;
265    if (!wd) return NULL;
266    return wd->label;
267 }
268
269 EAPI Evas_Object *
270 elm_check_add(Evas_Object *parent)
271 {
272    Evas_Object *obj;
273    Evas *e;
274    Widget_Data *wd;
275
276    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
277
278    ELM_SET_WIDTYPE(widtype, "check");
279    elm_widget_type_set(obj, "check");
280    elm_widget_sub_object_add(parent, obj);
281    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
282    elm_widget_data_set(obj, wd);
283    elm_widget_del_hook_set(obj, _del_hook);
284    elm_widget_theme_hook_set(obj, _theme_hook);
285    elm_widget_disable_hook_set(obj, _disable_hook);
286    elm_widget_can_focus_set(obj, EINA_TRUE);
287    elm_widget_activate_hook_set(obj, _activate_hook);
288    elm_widget_event_hook_set(obj, _event_hook);
289    elm_widget_text_set_hook_set(obj, _elm_check_label_set);
290    elm_widget_text_get_hook_set(obj, _elm_check_label_get);
291
292    wd->chk = edje_object_add(e);
293    _elm_theme_object_set(obj, wd->chk, "check", "base", "default");
294    edje_object_signal_callback_add(wd->chk, "elm,action,check,on", "",
295                                    _signal_check_on, obj);
296    edje_object_signal_callback_add(wd->chk, "elm,action,check,off", "",
297                                    _signal_check_off, obj);
298    edje_object_signal_callback_add(wd->chk, "elm,action,check,toggle", "",
299                                    _signal_check_toggle, obj);
300    elm_widget_resize_object_set(obj, wd->chk);
301
302    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
303
304    _mirrored_set(obj, elm_widget_mirrored_get(obj));
305    _sizing_eval(obj);
306
307    // TODO: convert Elementary to subclassing of Evas_Smart_Class
308    // TODO: and save some bytes, making descriptions per-class and not instance!
309    evas_object_smart_callbacks_descriptions_set(obj, _signals);
310    return obj;
311 }
312
313 EAPI void
314 elm_check_label_set(Evas_Object *obj, const char *label)
315 {
316    _elm_check_label_set(obj, NULL, label);
317 }
318
319 EAPI const char *
320 elm_check_label_get(const Evas_Object *obj)
321 {
322    return _elm_check_label_get(obj, NULL);
323 }
324
325 EAPI void
326 elm_check_icon_set(Evas_Object *obj, Evas_Object *icon)
327 {
328    ELM_CHECK_WIDTYPE(obj, widtype);
329    Widget_Data *wd = elm_widget_data_get(obj);
330    if (!wd) return;
331    if (wd->icon == icon) return;
332    if (wd->icon) evas_object_del(wd->icon);
333    wd->icon = icon;
334    if (icon)
335      {
336         elm_widget_sub_object_add(obj, icon);
337         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
338                                        _changed_size_hints, obj);
339         edje_object_part_swallow(wd->chk, "elm.swallow.content", icon);
340         edje_object_signal_emit(wd->chk, "elm,state,icon,visible", "elm");
341         edje_object_message_signal_process(wd->chk);
342      }
343    _sizing_eval(obj);
344 }
345
346 EAPI Evas_Object *
347 elm_check_icon_get(const Evas_Object *obj)
348 {
349    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
350    Widget_Data *wd = elm_widget_data_get(obj);
351    if (!wd) return NULL;
352    return wd->icon;
353 }
354
355 EAPI Evas_Object *
356 elm_check_icon_unset(Evas_Object *obj)
357 {
358    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
359    Widget_Data *wd = elm_widget_data_get(obj);
360    if (!wd) return NULL;
361    if (!wd->icon) return NULL;
362    Evas_Object *icon = wd->icon;
363    elm_widget_sub_object_del(obj, wd->icon);
364    edje_object_part_unswallow(wd->chk, wd->icon);
365    wd->icon = NULL;
366    return icon;
367 }
368
369 EAPI void
370 elm_check_state_set(Evas_Object *obj, Eina_Bool state)
371 {
372    ELM_CHECK_WIDTYPE(obj, widtype);
373    Widget_Data *wd = elm_widget_data_get(obj);
374    if (!wd) return;
375    if (state != wd->state)
376      {
377         wd->state = state;
378         if (wd->statep) *wd->statep = wd->state;
379         if (wd->state)
380           edje_object_signal_emit(wd->chk, "elm,state,check,on", "elm");
381         else
382           edje_object_signal_emit(wd->chk, "elm,state,check,off", "elm");
383      }
384    edje_object_message_signal_process(wd->chk);
385 }
386
387 EAPI Eina_Bool
388 elm_check_state_get(const Evas_Object *obj)
389 {
390    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
391    Widget_Data *wd = elm_widget_data_get(obj);
392    if (!wd) return EINA_FALSE;
393    return wd->state;
394 }
395
396 EAPI void
397 elm_check_state_pointer_set(Evas_Object *obj, Eina_Bool *statep)
398 {
399    ELM_CHECK_WIDTYPE(obj, widtype);
400    Widget_Data *wd = elm_widget_data_get(obj);
401    if (!wd) return;
402    if (statep)
403      {
404         wd->statep = statep;
405         if (*wd->statep != wd->state)
406           {
407              wd->state = *wd->statep;
408              if (wd->state)
409                edje_object_signal_emit(wd->chk, "elm,state,check,on", "elm");
410              else
411                edje_object_signal_emit(wd->chk, "elm,state,check,off", "elm");
412           }
413      }
414    else
415      wd->statep = NULL;
416 }