elementary - slider, scroller, progressbar, radio
[framework/uifw/elementary.git] / src / lib / elm_progressbar.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define MIN_RATIO_LVL 0.0
5 #define MAX_RATIO_LVL 1.0
6
7 typedef struct _Widget_Data Widget_Data;
8
9 struct _Widget_Data
10 {
11    Evas_Object *progressbar;
12    Evas_Object *spacer;
13    Evas_Object *icon;
14    Evas_Coord size;
15    Eina_Bool horizontal : 1;
16    Eina_Bool inverted : 1;
17    Eina_Bool pulse : 1;
18    Eina_Bool pulse_state : 1;
19    const char *units;
20    const char *label;
21    double val;
22 };
23
24 static const char *widtype = NULL;
25 static void _del_hook(Evas_Object *obj);
26 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
27 static void _theme_hook(Evas_Object *obj);
28 static void _sizing_eval(Evas_Object *obj);
29 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
30 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
31 static void _units_set(Evas_Object *obj);
32 static void _val_set(Evas_Object *obj);
33
34 static void
35 _del_hook(Evas_Object *obj)
36 {
37    Widget_Data *wd = elm_widget_data_get(obj);
38    if (!wd) return;
39    if (wd->label) eina_stringshare_del(wd->label);
40    if (wd->units) eina_stringshare_del(wd->units);
41    free(wd);
42 }
43
44 static void
45 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
46 {
47    Widget_Data *wd = elm_widget_data_get(obj);
48    if (!wd) return;
49    edje_object_mirrored_set(wd->progressbar, rtl);
50 }
51
52 static void
53 _theme_hook(Evas_Object *obj)
54 {
55    Widget_Data *wd = elm_widget_data_get(obj);
56    if (!wd) return;
57    _elm_widget_mirrored_reload(obj);
58    _mirrored_set(obj, elm_widget_mirrored_get(obj));
59    if (wd->horizontal)
60      _elm_theme_object_set(obj, wd->progressbar, "progressbar", "horizontal", elm_widget_style_get(obj));
61    else
62      _elm_theme_object_set(obj, wd->progressbar, "progressbar", "vertical", elm_widget_style_get(obj));
63
64    if (wd->icon)
65      {
66         edje_object_part_swallow(wd->progressbar, "elm.swallow.content", wd->icon);
67         edje_object_signal_emit(wd->progressbar, "elm,state,icon,visible", "elm");
68      }
69    if (wd->label)
70      {
71         edje_object_part_text_set(wd->progressbar, "elm.text", wd->label);
72         edje_object_signal_emit(wd->progressbar, "elm,state,text,visible", "elm");
73      }
74    if (wd->pulse)
75      edje_object_signal_emit(wd->progressbar, "elm,state,pulse", "elm");
76    else
77      edje_object_signal_emit(wd->progressbar, "elm,state,fraction", "elm");
78    if (wd->pulse_state)
79      edje_object_signal_emit(wd->progressbar, "elm,state,pulse,start", "elm");
80
81    if ((wd->units) && (!wd->pulse))
82      edje_object_signal_emit(wd->progressbar, "elm,state,units,visible", "elm");
83
84    if (wd->horizontal)
85      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
86    else
87      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
88
89    edje_object_part_swallow(wd->progressbar, "elm.swallow.bar", wd->spacer);
90
91    if (wd->inverted)
92      edje_object_signal_emit(wd->progressbar, "elm,state,inverted,on", "elm");
93
94    _units_set(obj);
95    edje_object_message_signal_process(wd->progressbar);
96    edje_object_scale_set(wd->progressbar, elm_widget_scale_get(obj) * _elm_config->scale);
97    _val_set(obj);
98    _sizing_eval(obj);
99 }
100
101 static void
102 _sizing_eval(Evas_Object *obj)
103 {
104    Widget_Data *wd = elm_widget_data_get(obj);
105    Evas_Coord minw = -1, minh = -1;
106    if (!wd) return;
107    edje_object_size_min_restricted_calc(wd->progressbar, &minw, &minh, minw, minh);
108    evas_object_size_hint_min_set(obj, minw, minh);
109    evas_object_size_hint_max_set(obj, -1, -1);
110 }
111
112 static void
113 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
114 {
115    Widget_Data *wd = elm_widget_data_get(data);
116    if (!wd) return;
117    if (obj != wd->icon) return;
118    _sizing_eval(data);
119 }
120
121 static void
122 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
123 {
124    Widget_Data *wd = elm_widget_data_get(obj);
125    Evas_Object *sub = event_info;
126    if (!wd) return;
127    if (sub == wd->icon)
128      {
129         edje_object_signal_emit(wd->progressbar, "elm,state,icon,hidden", "elm");
130         evas_object_event_callback_del_full
131            (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
132         wd->icon = NULL;
133         edje_object_message_signal_process(wd->progressbar);
134         _sizing_eval(obj);
135      }
136 }
137
138 static void
139 _val_set(Evas_Object *obj)
140 {
141    Widget_Data *wd = elm_widget_data_get(obj);
142    Eina_Bool rtl;
143    double pos;
144    if (!wd) return;
145    pos = wd->val;
146    rtl = elm_widget_mirrored_get(obj);
147    if ((!rtl && wd->inverted) || (rtl &&
148                                   ((!wd->horizontal && wd->inverted) ||
149                                    (wd->horizontal && !wd->inverted)))) pos = MAX_RATIO_LVL - pos;
150    edje_object_part_drag_value_set(wd->progressbar, "elm.cur.progressbar", pos, pos);
151 }
152
153 static void
154 _units_set(Evas_Object *obj)
155 {
156    Widget_Data *wd = elm_widget_data_get(obj);
157    if (!wd) return;
158    if (wd->units)
159      {
160         char buf[1024];
161         snprintf(buf, sizeof(buf), wd->units, 100 * wd->val);
162         edje_object_part_text_set(wd->progressbar, "elm.text.status", buf);
163      }
164    else
165      edje_object_part_text_set(wd->progressbar, "elm.text.status", NULL);
166 }
167
168 static void
169 _elm_progressbar_label_set(Evas_Object *obj, const char *item, const char *label)
170 {
171    ELM_CHECK_WIDTYPE(obj, widtype);
172    Widget_Data *wd = elm_widget_data_get(obj);
173    if (item && strcmp(item, "default")) return;
174    if (!wd) return;
175    eina_stringshare_replace(&wd->label, label);
176    if (label)
177      {
178         edje_object_signal_emit(wd->progressbar, "elm,state,text,visible", "elm");
179         edje_object_message_signal_process(wd->progressbar);
180      }
181    else
182      {
183         edje_object_signal_emit(wd->progressbar, "elm,state,text,hidden", "elm");
184         edje_object_message_signal_process(wd->progressbar);
185      }
186    edje_object_part_text_set(wd->progressbar, "elm.text", label);
187    _sizing_eval(obj);
188 }
189
190 static const char *
191 _elm_progressbar_label_get(const Evas_Object *obj, const char *item)
192 {
193    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
194    Widget_Data *wd = elm_widget_data_get(obj);
195    if (item && strcmp(item, "default")) return NULL;
196    if (!wd) return NULL;
197    return wd->label;
198 }
199
200 static void
201 _content_set_hook(Evas_Object *obj, const char *part __UNUSED__, Evas_Object *content)
202 {
203    ELM_CHECK_WIDTYPE(obj, widtype);
204    Widget_Data *wd = elm_widget_data_get(obj);
205    if (!wd) return;
206    if (wd->icon == content) return;
207    if (wd->icon) evas_object_del(wd->icon);
208    wd->icon = content;
209    if (content)
210      {
211         elm_widget_sub_object_add(obj, content);
212         evas_object_event_callback_add(content,
213                                        EVAS_CALLBACK_CHANGED_SIZE_HINTS,
214                                        _changed_size_hints, obj);
215         edje_object_part_swallow(wd->progressbar, "elm.swallow.content", content);
216         edje_object_signal_emit(wd->progressbar, "elm,state,icon,visible", "elm");
217         edje_object_message_signal_process(wd->progressbar);
218      }
219    _sizing_eval(obj);
220 }
221
222 static Evas_Object *
223 _content_get_hook(const Evas_Object *obj, const char *part __UNUSED__)
224 {
225    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
226    Widget_Data *wd = elm_widget_data_get(obj);
227    if (!wd) return NULL;
228    return wd->icon;
229 }
230
231 static Evas_Object *
232 _content_unset_hook(Evas_Object *obj, const char *part __UNUSED__)
233 {
234    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
235    Widget_Data *wd = elm_widget_data_get(obj);
236    if (!wd) return NULL;
237    if (!wd->icon) return NULL;
238    Evas_Object *icon = wd->icon;
239    elm_widget_sub_object_del(obj, wd->icon);
240    evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
241                                   _changed_size_hints, obj);
242    edje_object_part_unswallow(wd->progressbar, wd->icon);
243    wd->icon = NULL;
244    return icon;
245 }
246
247
248 EAPI Evas_Object *
249 elm_progressbar_add(Evas_Object *parent)
250 {
251    Evas_Object *obj;
252    Evas *e;
253    Widget_Data *wd;
254
255    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
256
257    ELM_SET_WIDTYPE(widtype, "progressbar");
258    elm_widget_type_set(obj, "progressbar");
259    elm_widget_sub_object_add(parent, obj);
260    elm_widget_data_set(obj, wd);
261    elm_widget_del_hook_set(obj, _del_hook);
262    elm_widget_theme_hook_set(obj, _theme_hook);
263    elm_widget_can_focus_set(obj, EINA_FALSE);
264    elm_widget_text_set_hook_set(obj, _elm_progressbar_label_set);
265    elm_widget_text_get_hook_set(obj, _elm_progressbar_label_get);
266    elm_widget_content_set_hook_set(obj, _content_set_hook);
267    elm_widget_content_get_hook_set(obj, _content_get_hook);
268    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
269
270    wd->horizontal = EINA_TRUE;
271    wd->inverted = EINA_FALSE;
272    wd->pulse = EINA_FALSE;
273    wd->pulse_state = EINA_FALSE;
274    wd->units = eina_stringshare_add("%.0f %%");
275    wd->val = MIN_RATIO_LVL;
276
277    wd->progressbar = edje_object_add(e);
278    _elm_theme_object_set(obj, wd->progressbar, "progressbar", "horizontal", "default");
279    elm_widget_resize_object_set(obj, wd->progressbar);
280
281    wd->spacer = evas_object_rectangle_add(e);
282    evas_object_color_set(wd->spacer, 0, 0, 0, 0);
283    evas_object_pass_events_set(wd->spacer, EINA_TRUE);
284    elm_widget_sub_object_add(obj, wd->spacer);
285    edje_object_part_swallow(wd->progressbar, "elm.swallow.bar", wd->spacer);
286
287    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
288    _units_set(obj);
289    _val_set(obj);
290    _mirrored_set(obj, elm_widget_mirrored_get(obj));
291    _sizing_eval(obj);
292    return obj;
293 }
294
295 EAPI void
296 elm_progressbar_pulse_set(Evas_Object *obj, Eina_Bool pulse)
297 {
298    ELM_CHECK_WIDTYPE(obj, widtype);
299    Widget_Data *wd = elm_widget_data_get(obj);
300    if (!wd) return;
301    pulse = !!pulse;
302    if (wd->pulse == pulse) return;
303    wd->pulse = pulse;
304    _theme_hook(obj);
305 }
306
307 EAPI Eina_Bool
308 elm_progressbar_pulse_get(const Evas_Object *obj)
309 {
310    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
311    Widget_Data *wd = elm_widget_data_get(obj);
312    if (!wd) return EINA_FALSE;
313    return wd->pulse;
314 }
315
316 EAPI void
317 elm_progressbar_pulse(Evas_Object *obj, Eina_Bool state)
318 {
319    ELM_CHECK_WIDTYPE(obj, widtype);
320    Widget_Data *wd = elm_widget_data_get(obj);
321    if (!wd) return;
322    state = !!state;
323    if ((!wd->pulse) && (wd->pulse_state == state)) return;
324    wd->pulse_state = state;
325    if (wd->pulse_state)
326      edje_object_signal_emit(wd->progressbar, "elm,state,pulse,start", "elm");
327    else
328      edje_object_signal_emit(wd->progressbar, "elm,state,pulse,stop", "elm");
329 }
330
331 EAPI void
332 elm_progressbar_value_set(Evas_Object *obj, double val)
333 {
334    ELM_CHECK_WIDTYPE(obj, widtype);
335    Widget_Data *wd = elm_widget_data_get(obj);
336    if (!wd) return;
337    if (wd->val == val) return;
338    wd->val = val;
339    if (wd->val < MIN_RATIO_LVL) wd->val = MIN_RATIO_LVL;
340    if (wd->val > MAX_RATIO_LVL) wd->val = MAX_RATIO_LVL;
341    _val_set(obj);
342    _units_set(obj);
343 }
344
345 EAPI double
346 elm_progressbar_value_get(const Evas_Object *obj)
347 {
348    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
349    Widget_Data *wd = elm_widget_data_get(obj);
350    if (!wd) return 0.0;
351    return wd->val;
352 }
353
354 EAPI void
355 elm_progressbar_label_set(Evas_Object *obj, const char *label)
356 {
357    _elm_progressbar_label_set(obj, NULL, label);
358 }
359
360 EAPI const char *
361 elm_progressbar_label_get(const Evas_Object *obj)
362 {
363    return _elm_progressbar_label_get(obj, NULL);
364 }
365
366 EAPI void
367 elm_progressbar_icon_set(Evas_Object *obj, Evas_Object *icon)
368 {
369    _content_set_hook(obj, NULL, icon);
370 }
371
372 EAPI Evas_Object *
373 elm_progressbar_icon_get(const Evas_Object *obj)
374 {
375    return _content_get_hook(obj, NULL);
376 }
377
378 EAPI Evas_Object *
379 elm_progressbar_icon_unset(Evas_Object *obj)
380 {
381    return _content_unset_hook(obj, NULL);
382 }
383
384 EAPI void
385 elm_progressbar_span_size_set(Evas_Object *obj, Evas_Coord size)
386 {
387    ELM_CHECK_WIDTYPE(obj, widtype);
388    Widget_Data *wd = elm_widget_data_get(obj);
389    if (!wd) return;
390    if (wd->size == size) return;
391    wd->size = size;
392    if (wd->horizontal)
393      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
394    else
395      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
396    edje_object_part_swallow(wd->progressbar, "elm.swallow.bar", wd->spacer);
397    _sizing_eval(obj);
398 }
399
400 EAPI Evas_Coord
401 elm_progressbar_span_size_get(const Evas_Object *obj)
402 {
403    ELM_CHECK_WIDTYPE(obj, widtype) 0;
404    Widget_Data *wd = elm_widget_data_get(obj);
405    if (!wd) return 0;
406    return wd->size;
407 }
408
409 EAPI void
410 elm_progressbar_unit_format_set(Evas_Object *obj, const char *units)
411 {
412    ELM_CHECK_WIDTYPE(obj, widtype);
413    Widget_Data *wd = elm_widget_data_get(obj);
414    if (!wd) return;
415    eina_stringshare_replace(&wd->units, units);
416    if (units)
417      {
418         edje_object_signal_emit(wd->progressbar, "elm,state,units,visible", "elm");
419         edje_object_message_signal_process(wd->progressbar);
420      }
421    else
422      {
423         edje_object_signal_emit(wd->progressbar, "elm,state,units,hidden", "elm");
424         edje_object_message_signal_process(wd->progressbar);
425      }
426    _units_set(obj);
427    _sizing_eval(obj);
428 }
429
430 EAPI const char *
431 elm_progressbar_unit_format_get(const Evas_Object *obj)
432 {
433    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
434    Widget_Data *wd = elm_widget_data_get(obj);
435    if (!wd) return NULL;
436    return wd->units;
437 }
438
439 EAPI void
440 elm_progressbar_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
441 {
442    ELM_CHECK_WIDTYPE(obj, widtype);
443    Widget_Data *wd = elm_widget_data_get(obj);
444    if (!wd) return;
445    horizontal = !!horizontal;
446    if (wd->horizontal == horizontal) return;
447    wd->horizontal = horizontal;
448    _theme_hook(obj);
449 }
450
451 EAPI Eina_Bool
452 elm_progressbar_horizontal_get(const Evas_Object *obj)
453 {
454    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
455    Widget_Data *wd = elm_widget_data_get(obj);
456    if (!wd) return EINA_FALSE;
457    return wd->horizontal;
458 }
459
460 EAPI void
461 elm_progressbar_inverted_set(Evas_Object *obj, Eina_Bool inverted)
462 {
463    ELM_CHECK_WIDTYPE(obj, widtype);
464    Widget_Data *wd = elm_widget_data_get(obj);
465    if (!wd) return;
466    inverted = !!inverted;
467    if (wd->inverted == inverted) return;
468    wd->inverted = inverted;
469    if (wd->inverted)
470      edje_object_signal_emit(wd->progressbar, "elm,state,inverted,on", "elm");
471    else
472      edje_object_signal_emit(wd->progressbar, "elm,state,inverted,off", "elm");
473    edje_object_message_signal_process(wd->progressbar);
474    _val_set(obj);
475    _units_set(obj);
476 }
477
478 EAPI Eina_Bool
479 elm_progressbar_inverted_get(const Evas_Object *obj)
480 {
481    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
482    Widget_Data *wd = elm_widget_data_get(obj);
483    if (!wd) return EINA_FALSE;
484    return wd->inverted;
485 }