[elementary] Docs. for the progress bar widget.
[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 EAPI Evas_Object *
201 elm_progressbar_add(Evas_Object *parent)
202 {
203    Evas_Object *obj;
204    Evas *e;
205    Widget_Data *wd;
206
207    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
208
209    ELM_SET_WIDTYPE(widtype, "progressbar");
210    elm_widget_type_set(obj, "progressbar");
211    elm_widget_sub_object_add(parent, obj);
212    elm_widget_data_set(obj, wd);
213    elm_widget_del_hook_set(obj, _del_hook);
214    elm_widget_theme_hook_set(obj, _theme_hook);
215    elm_widget_can_focus_set(obj, EINA_FALSE);
216    elm_widget_text_set_hook_set(obj, _elm_progressbar_label_set);
217    elm_widget_text_get_hook_set(obj, _elm_progressbar_label_get);
218
219    wd->horizontal = EINA_TRUE;
220    wd->inverted = EINA_FALSE;
221    wd->pulse = EINA_FALSE;
222    wd->pulse_state = EINA_FALSE;
223    wd->units = eina_stringshare_add("%.0f %%");
224    wd->val = MIN_RATIO_LVL;
225
226    wd->progressbar = edje_object_add(e);
227    _elm_theme_object_set(obj, wd->progressbar, "progressbar", "horizontal", "default");
228    elm_widget_resize_object_set(obj, wd->progressbar);
229
230    wd->spacer = evas_object_rectangle_add(e);
231    evas_object_color_set(wd->spacer, 0, 0, 0, 0);
232    evas_object_pass_events_set(wd->spacer, EINA_TRUE);
233    elm_widget_sub_object_add(obj, wd->spacer);
234    edje_object_part_swallow(wd->progressbar, "elm.swallow.bar", wd->spacer);
235
236    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
237    _units_set(obj);
238    _val_set(obj);
239    _mirrored_set(obj, elm_widget_mirrored_get(obj));
240    _sizing_eval(obj);
241    return obj;
242 }
243
244 EAPI void
245 elm_progressbar_pulse_set(Evas_Object *obj, Eina_Bool pulse)
246 {
247    ELM_CHECK_WIDTYPE(obj, widtype);
248    Widget_Data *wd = elm_widget_data_get(obj);
249    if (!wd) return;
250    pulse = !!pulse;
251    if (wd->pulse == pulse) return;
252    wd->pulse = pulse;
253    _theme_hook(obj);
254 }
255
256 EAPI Eina_Bool
257 elm_progressbar_pulse_get(const Evas_Object *obj)
258 {
259    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
260    Widget_Data *wd = elm_widget_data_get(obj);
261    if (!wd) return EINA_FALSE;
262    return wd->pulse;
263 }
264
265 EAPI void
266 elm_progressbar_pulse(Evas_Object *obj, Eina_Bool state)
267 {
268    ELM_CHECK_WIDTYPE(obj, widtype);
269    Widget_Data *wd = elm_widget_data_get(obj);
270    if (!wd) return;
271    state = !!state;
272    if ((!wd->pulse) && (wd->pulse_state == state)) return;
273    wd->pulse_state = state;
274    if (wd->pulse_state)
275      edje_object_signal_emit(wd->progressbar, "elm,state,pulse,start", "elm");
276    else
277      edje_object_signal_emit(wd->progressbar, "elm,state,pulse,stop", "elm");
278 }
279
280 EAPI void
281 elm_progressbar_value_set(Evas_Object *obj, double val)
282 {
283    ELM_CHECK_WIDTYPE(obj, widtype);
284    Widget_Data *wd = elm_widget_data_get(obj);
285    if (!wd) return;
286    if (wd->val == val) return;
287    wd->val = val;
288    if (wd->val < MIN_RATIO_LVL) wd->val = MIN_RATIO_LVL;
289    if (wd->val > MAX_RATIO_LVL) wd->val = MAX_RATIO_LVL;
290    _val_set(obj);
291    _units_set(obj);
292 }
293
294 EAPI double
295 elm_progressbar_value_get(const Evas_Object *obj)
296 {
297    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
298    Widget_Data *wd = elm_widget_data_get(obj);
299    if (!wd) return 0.0;
300    return wd->val;
301 }
302
303 EAPI void
304 elm_progressbar_label_set(Evas_Object *obj, const char *label)
305 {
306    _elm_progressbar_label_set(obj, NULL, label);
307 }
308
309 EAPI const char *
310 elm_progressbar_label_get(const Evas_Object *obj)
311 {
312    return _elm_progressbar_label_get(obj, NULL);
313 }
314
315 EAPI void
316 elm_progressbar_icon_set(Evas_Object *obj, Evas_Object *icon)
317 {
318    ELM_CHECK_WIDTYPE(obj, widtype);
319    Widget_Data *wd = elm_widget_data_get(obj);
320    if (!wd) return;
321    if (wd->icon == icon) return;
322    if (wd->icon) evas_object_del(wd->icon);
323    wd->icon = icon;
324    if (icon)
325      {
326         elm_widget_sub_object_add(obj, icon);
327         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
328                                        _changed_size_hints, obj);
329         edje_object_part_swallow(wd->progressbar, "elm.swallow.content", icon);
330         edje_object_signal_emit(wd->progressbar, "elm,state,icon,visible", "elm");
331         edje_object_message_signal_process(wd->progressbar);
332      }
333    _sizing_eval(obj);
334 }
335
336 EAPI Evas_Object *
337 elm_progressbar_icon_get(const Evas_Object *obj)
338 {
339    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
340    Widget_Data *wd = elm_widget_data_get(obj);
341    if (!wd) return NULL;
342    return wd->icon;
343 }
344
345 EAPI Evas_Object *
346 elm_progressbar_icon_unset(Evas_Object *obj)
347 {
348    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
349    Widget_Data *wd = elm_widget_data_get(obj);
350    if (!wd) return NULL;
351    if (!wd->icon) return NULL;
352    Evas_Object *icon = wd->icon;
353    elm_widget_sub_object_del(obj, wd->icon);
354    edje_object_part_unswallow(wd->progressbar, wd->icon);
355    wd->icon = NULL;
356    return icon;
357 }
358
359 EAPI void
360 elm_progressbar_span_size_set(Evas_Object *obj, Evas_Coord size)
361 {
362    ELM_CHECK_WIDTYPE(obj, widtype);
363    Widget_Data *wd = elm_widget_data_get(obj);
364    if (!wd) return;
365    if (wd->size == size) return;
366    wd->size = size;
367    if (wd->horizontal)
368      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
369    else
370      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
371    edje_object_part_swallow(wd->progressbar, "elm.swallow.bar", wd->spacer);
372    _sizing_eval(obj);
373 }
374
375 EAPI Evas_Coord
376 elm_progressbar_span_size_get(const Evas_Object *obj)
377 {
378    ELM_CHECK_WIDTYPE(obj, widtype) 0;
379    Widget_Data *wd = elm_widget_data_get(obj);
380    if (!wd) return 0;
381    return wd->size;
382 }
383
384 EAPI void
385 elm_progressbar_unit_format_set(Evas_Object *obj, const char *units)
386 {
387    ELM_CHECK_WIDTYPE(obj, widtype);
388    Widget_Data *wd = elm_widget_data_get(obj);
389    if (!wd) return;
390    eina_stringshare_replace(&wd->units, units);
391    if (units)
392      {
393         edje_object_signal_emit(wd->progressbar, "elm,state,units,visible", "elm");
394         edje_object_message_signal_process(wd->progressbar);
395      }
396    else
397      {
398         edje_object_signal_emit(wd->progressbar, "elm,state,units,hidden", "elm");
399         edje_object_message_signal_process(wd->progressbar);
400      }
401    _units_set(obj);
402    _sizing_eval(obj);
403 }
404
405 EAPI const char *
406 elm_progressbar_unit_format_get(const Evas_Object *obj)
407 {
408    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
409    Widget_Data *wd = elm_widget_data_get(obj);
410    if (!wd) return NULL;
411    return wd->units;
412 }
413
414 EAPI void
415 elm_progressbar_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
416 {
417    ELM_CHECK_WIDTYPE(obj, widtype);
418    Widget_Data *wd = elm_widget_data_get(obj);
419    if (!wd) return;
420    horizontal = !!horizontal;
421    if (wd->horizontal == horizontal) return;
422    wd->horizontal = horizontal;
423    _theme_hook(obj);
424 }
425
426 EAPI Eina_Bool
427 elm_progressbar_horizontal_get(const Evas_Object *obj)
428 {
429    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
430    Widget_Data *wd = elm_widget_data_get(obj);
431    if (!wd) return EINA_FALSE;
432    return wd->horizontal;
433 }
434
435 EAPI void
436 elm_progressbar_inverted_set(Evas_Object *obj, Eina_Bool inverted)
437 {
438    ELM_CHECK_WIDTYPE(obj, widtype);
439    Widget_Data *wd = elm_widget_data_get(obj);
440    if (!wd) return;
441    inverted = !!inverted;
442    if (wd->inverted == inverted) return;
443    wd->inverted = inverted;
444    if (wd->inverted)
445      edje_object_signal_emit(wd->progressbar, "elm,state,inverted,on", "elm");
446    else
447      edje_object_signal_emit(wd->progressbar, "elm,state,inverted,off", "elm");
448    edje_object_message_signal_process(wd->progressbar);
449    _val_set(obj);
450    _units_set(obj);
451 }
452
453 EAPI Eina_Bool
454 elm_progressbar_inverted_get(const Evas_Object *obj)
455 {
456    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
457    Widget_Data *wd = elm_widget_data_get(obj);
458    if (!wd) return EINA_FALSE;
459    return wd->inverted;
460 }