elementary - slider, scroller, progressbar, radio
[framework/uifw/elementary.git] / src / lib / elm_slider.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 *slider;
9    Evas_Object *icon;
10    Evas_Object *end;
11    Evas_Object *spacer;
12
13    Ecore_Timer *delay;
14
15    const char *label;
16    const char *units;
17    const char *indicator;
18
19    const char *(*indicator_format_func)(double val);
20    void (*indicator_format_free)(const char *str);
21
22    const char *(*units_format_func)(double val);
23    void (*units_format_free)(const char *str);
24
25    double val, val_min, val_max;
26    Evas_Coord size;
27
28    Eina_Bool horizontal : 1;
29    Eina_Bool inverted : 1;
30    Eina_Bool indicator_show : 1;
31 };
32
33 #define ELM_SLIDER_INVERTED_FACTOR (-1.0)
34
35 static const char *widtype = NULL;
36 static void _del_hook(Evas_Object *obj);
37 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
38 static void _theme_hook(Evas_Object *obj);
39 static void _disable_hook(Evas_Object *obj);
40 static void _sizing_eval(Evas_Object *obj);
41 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
42 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
43 static void _units_set(Evas_Object *obj);
44 static void _val_set(Evas_Object *obj);
45 static void _indicator_set(Evas_Object *obj);
46 static void _on_focus_hook(void *data, Evas_Object *obj);
47 static void _drag_up(void *data, Evas_Object *obj,
48                     const char *emission, const char *source);
49 static void _drag_down(void *data, Evas_Object *obj,
50                     const char *emission, const char *source);
51 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
52                              Evas_Callback_Type type, void *event_info);
53 static void _spacer_cb(void *data, Evas * e, Evas_Object * obj, void *event_info);
54
55 static const char SIG_CHANGED[] = "changed";
56 static const char SIG_DELAY_CHANGED[] = "delay,changed";
57 static const char SIG_DRAG_START[] = "slider,drag,start";
58 static const char SIG_DRAG_STOP[] = "slider,drag,stop";
59 static const Evas_Smart_Cb_Description _signals[] = {
60   {SIG_CHANGED, ""},
61   {SIG_DELAY_CHANGED, ""},
62   {SIG_DRAG_START, ""},
63   {SIG_DRAG_STOP, ""},
64   {NULL, NULL}
65 };
66
67 static Eina_Bool
68 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
69 {
70    Evas_Event_Mouse_Wheel *mev;
71    Evas_Event_Key_Down *ev;
72    Widget_Data *wd;
73
74    wd = elm_widget_data_get(obj);
75    if (!wd) return EINA_FALSE;
76
77    if (type == EVAS_CALLBACK_KEY_DOWN) goto key_down;
78    else if (type != EVAS_CALLBACK_MOUSE_WHEEL) return EINA_FALSE;
79
80    mev = event_info;
81    if (mev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
82    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
83
84    if (mev->z < 0) _drag_up(obj, NULL, NULL, NULL);
85    else _drag_down(obj, NULL, NULL, NULL);
86    mev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
87    return EINA_TRUE;
88
89   key_down:
90    ev = event_info;
91    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
92    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
93    if ((!strcmp(ev->keyname, "Left"))
94        || (!strcmp(ev->keyname, "KP_Left")))
95      {
96         if (!wd->horizontal) return EINA_FALSE;
97         if (!wd->inverted) _drag_down(obj, NULL, NULL, NULL);
98         else _drag_up(obj, NULL, NULL, NULL);
99         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
100         return EINA_TRUE;
101      }
102    else if ((!strcmp(ev->keyname, "Right"))
103             || (!strcmp(ev->keyname, "KP_Right")))
104      {
105         if (!wd->horizontal) return EINA_FALSE;
106         if (!wd->inverted) _drag_up(obj, NULL, NULL, NULL);
107         else _drag_down(obj, NULL, NULL, NULL);
108         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
109         return EINA_TRUE;
110      }
111    else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")))
112      {
113         if (wd->horizontal) return EINA_FALSE;
114         if (wd->inverted) _drag_up(obj, NULL, NULL, NULL);
115         else _drag_down(obj, NULL, NULL, NULL);
116         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
117         return EINA_TRUE;
118      }
119    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
120      {
121         if (wd->horizontal) return EINA_FALSE;
122         if (wd->inverted) _drag_down(obj, NULL, NULL, NULL);
123         else _drag_up(obj, NULL, NULL, NULL);
124         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
125         return EINA_TRUE;
126      }
127    else return EINA_FALSE;
128 }
129
130 static void
131 _del_hook(Evas_Object *obj)
132 {
133    Widget_Data *wd = elm_widget_data_get(obj);
134    if (!wd) return;
135    if (wd->label) eina_stringshare_del(wd->label);
136    if (wd->indicator) eina_stringshare_del(wd->units);
137    if (wd->delay) ecore_timer_del(wd->delay);
138    free(wd);
139 }
140
141 static void
142 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
143 {
144    Widget_Data *wd = elm_widget_data_get(obj);
145    if (!wd) return;
146    if (elm_widget_focus_get(obj))
147      {
148         edje_object_signal_emit(wd->slider, "elm,action,focus", "elm");
149         evas_object_focus_set(wd->slider, EINA_TRUE);
150      }
151    else
152      {
153         edje_object_signal_emit(wd->slider, "elm,action,unfocus", "elm");
154         evas_object_focus_set(wd->slider, EINA_FALSE);
155      }
156 }
157
158 static void
159 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
160 {
161    Widget_Data *wd = elm_widget_data_get(obj);
162    if (!wd) return;
163    edje_object_mirrored_set(wd->slider, rtl);
164 }
165
166 static void
167 _theme_hook(Evas_Object *obj)
168 {
169    Widget_Data *wd = elm_widget_data_get(obj);
170    if (!wd) return;
171    _elm_widget_mirrored_reload(obj);
172    _mirrored_set(obj, elm_widget_mirrored_get(obj));
173    if (wd->horizontal)
174      _elm_theme_object_set(obj, wd->slider, "slider", "horizontal", elm_widget_style_get(obj));
175    else
176      _elm_theme_object_set(obj, wd->slider, "slider", "vertical", elm_widget_style_get(obj));
177    if (wd->icon)
178      {
179         edje_object_part_swallow(wd->slider, "elm.swallow.content", wd->icon);
180         edje_object_signal_emit(wd->slider, "elm,state,icon,visible", "elm");
181      }
182    if (wd->end)
183      edje_object_signal_emit(wd->slider, "elm,state,end,visible", "elm");
184    else
185      edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
186    if (wd->label)
187      {
188         edje_object_part_text_set(wd->slider, "elm.text", wd->label);
189         edje_object_signal_emit(wd->slider, "elm,state,text,visible", "elm");
190      }
191
192    if (wd->units)
193      edje_object_signal_emit(wd->slider, "elm,state,units,visible", "elm");
194
195    if (wd->horizontal)
196      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
197    else
198      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
199
200    if (wd->inverted)
201      edje_object_signal_emit(wd->slider, "elm,state,inverted,on", "elm");
202
203    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
204    _units_set(obj);
205    _indicator_set(obj);
206    edje_object_message_signal_process(wd->slider);
207    edje_object_scale_set(wd->slider, elm_widget_scale_get(obj) * _elm_config->scale);
208    _val_set(obj);
209    _sizing_eval(obj);
210 }
211
212 static void
213 _disable_hook(Evas_Object *obj)
214 {
215    Widget_Data *wd = elm_widget_data_get(obj);
216    if (!wd) return;
217    if (elm_widget_disabled_get(obj))
218      edje_object_signal_emit(wd->slider, "elm,state,disabled", "elm");
219    else
220      edje_object_signal_emit(wd->slider, "elm,state,enabled", "elm");
221 }
222
223 static void
224 _sizing_eval(Evas_Object *obj)
225 {
226    Widget_Data *wd = elm_widget_data_get(obj);
227    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
228    if (!wd) return;
229    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
230    edje_object_size_min_restricted_calc(wd->slider, &minw, &minh, minw, minh);
231    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
232    evas_object_size_hint_min_set(obj, minw, minh);
233    evas_object_size_hint_max_set(obj, maxw, maxh);
234 }
235
236 static void
237 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
238 {
239    Widget_Data *wd = elm_widget_data_get(data);
240    if (!wd) return;
241    if ((obj != wd->icon) && (obj != wd->end)) return;
242    _sizing_eval(data);
243 }
244
245 static void
246 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
247 {
248    Widget_Data *wd = elm_widget_data_get(obj);
249    Evas_Object *sub = event_info;
250    if (!wd) return;
251    if (sub == wd->icon)
252      {
253         edje_object_signal_emit(wd->slider, "elm,state,icon,hidden", "elm");
254         evas_object_event_callback_del_full
255            (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
256         wd->icon = NULL;
257         edje_object_message_signal_process(wd->slider);
258         _sizing_eval(obj);
259      }
260    if (sub == wd->end)
261      {
262         edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
263         evas_object_event_callback_del_full(sub,
264                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
265                                             _changed_size_hints, obj);
266         wd->end = NULL;
267         edje_object_message_signal_process(wd->slider);
268         _sizing_eval(obj);
269      }
270 }
271
272 static Eina_Bool
273 _delay_change(void *data)
274 {
275    Widget_Data *wd = elm_widget_data_get(data);
276    if (!wd) return ECORE_CALLBACK_CANCEL;
277    wd->delay = NULL;
278    evas_object_smart_callback_call(data, SIG_DELAY_CHANGED, NULL);
279    return ECORE_CALLBACK_CANCEL;
280 }
281
282 static void
283 _val_fetch(Evas_Object *obj)
284 {
285    Eina_Bool rtl;
286    Widget_Data *wd = elm_widget_data_get(obj);
287    double posx = 0.0, posy = 0.0, pos = 0.0, val;
288    if (!wd) return;
289    edje_object_part_drag_value_get(wd->slider, "elm.dragable.slider",
290                                    &posx, &posy);
291    if (wd->horizontal) pos = posx;
292    else pos = posy;
293
294    rtl = elm_widget_mirrored_get(obj);
295    if ((!rtl && wd->inverted) || (rtl &&
296                                   ((!wd->horizontal && wd->inverted) ||
297                                    (wd->horizontal && !wd->inverted)))) pos = 1.0 - pos;
298    val = (pos * (wd->val_max - wd->val_min)) + wd->val_min;
299    if (val != wd->val)
300      {
301         wd->val = val;
302         evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
303         if (wd->delay) ecore_timer_del(wd->delay);
304         wd->delay = ecore_timer_add(0.2, _delay_change, obj);
305      }
306 }
307
308 static void
309 _val_set(Evas_Object *obj)
310 {
311    Eina_Bool rtl;
312    Widget_Data *wd = elm_widget_data_get(obj);
313    double pos;
314    if (!wd) return;
315    if (wd->val_max > wd->val_min)
316      pos = (wd->val - wd->val_min) / (wd->val_max - wd->val_min);
317    else
318      pos = 0.0;
319    if (pos < 0.0) pos = 0.0;
320    else if (pos > 1.0) pos = 1.0;
321
322    rtl = elm_widget_mirrored_get(obj);
323    if ((!rtl && wd->inverted) || (rtl &&
324                                   ((!wd->horizontal && wd->inverted) ||
325                                    (wd->horizontal && !wd->inverted)))) pos = 1.0 - pos;
326    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", pos, pos);
327 }
328
329 static void
330 _units_set(Evas_Object *obj)
331 {
332    Widget_Data *wd = elm_widget_data_get(obj);
333    if (!wd) return;
334    if (wd->units_format_func)
335      {
336         const char *buf;
337         buf = wd->units_format_func(wd->val);
338         edje_object_part_text_set(wd->slider, "elm.units", buf);
339         if (wd->units_format_free) wd->units_format_free(buf);
340      }
341    else if (wd->units)
342      {
343         char buf[1024];
344
345         snprintf(buf, sizeof(buf), wd->units, wd->val);
346         edje_object_part_text_set(wd->slider, "elm.units", buf);
347      }
348    else
349      edje_object_part_text_set(wd->slider, "elm.units", NULL);
350 }
351
352 static void
353 _indicator_set(Evas_Object *obj)
354 {
355    Widget_Data *wd = elm_widget_data_get(obj);
356    if (!wd) return;
357    if (wd->indicator_format_func)
358      {
359         const char *buf;
360         buf = wd->indicator_format_func(wd->val);
361         edje_object_part_text_set(wd->slider, "elm.dragable.slider:elm.indicator", buf);
362         if (wd->indicator_format_free) wd->indicator_format_free(buf);
363      }
364    else if (wd->indicator)
365      {
366         char buf[1024];
367         snprintf(buf, sizeof(buf), wd->indicator, wd->val);
368         edje_object_part_text_set(wd->slider, "elm.dragable.slider:elm.indicator", buf);
369      }
370    else
371      edje_object_part_text_set(wd->slider, "elm.dragable.slider:elm.indicator", NULL);
372 }
373
374 static void
375 _drag(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
376 {
377    _val_fetch(data);
378    _units_set(data);
379    _indicator_set(data);
380 }
381
382 static void
383 _drag_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
384 {
385    _val_fetch(data);
386    evas_object_smart_callback_call(data, SIG_DRAG_START, NULL);
387    _units_set(data);
388    _indicator_set(data);
389    elm_widget_scroll_freeze_push(data);
390 }
391
392 static void
393 _drag_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
394 {
395    _val_fetch(data);
396    evas_object_smart_callback_call(data, SIG_DRAG_STOP, NULL);
397    _units_set(data);
398    _indicator_set(data);
399    elm_widget_scroll_freeze_pop(data);
400 }
401
402 static void
403 _drag_step(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
404 {
405    _val_fetch(data);
406    _units_set(data);
407    _indicator_set(data);
408 }
409
410 static void
411 _drag_up(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
412 {
413    double step;
414    Widget_Data *wd;
415
416    wd = elm_widget_data_get(data);
417    step = 0.05;
418
419    if (wd->inverted) step *= ELM_SLIDER_INVERTED_FACTOR;
420
421    edje_object_part_drag_step(wd->slider, "elm.dragable.slider", step, step);
422 }
423
424 static void
425 _drag_down(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
426 {
427    double step;
428    Widget_Data *wd;
429
430    wd = elm_widget_data_get(data);
431    step = -0.05;
432
433    if (wd->inverted) step *= ELM_SLIDER_INVERTED_FACTOR;
434
435    edje_object_part_drag_step(wd->slider, "elm.dragable.slider", step, step);
436 }
437
438 static void
439 _spacer_cb(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
440 {
441    Widget_Data *wd = elm_widget_data_get(data);
442    Evas_Event_Mouse_Down *ev = event_info;
443    Evas_Coord x, y, w, h;
444    double button_x, button_y;
445
446    evas_object_geometry_get(wd->spacer, &x, &y, &w, &h);
447    edje_object_part_drag_value_get(wd->slider, "elm.dragable.slider", &button_x, &button_y);
448    if (wd->horizontal)
449      {
450         button_x = ((double)ev->canvas.x - (double)x) / (double)w;
451         if (button_x > 1) button_x = 1;
452         if (button_x < 0) button_x = 0;
453      }
454    else
455      {
456         button_y = ((double)ev->canvas.y - (double)y) / (double)h;
457         if (button_y > 1) button_y = 1;
458         if (button_y < 0) button_y = 0;
459      }
460    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", button_x, button_y);
461    evas_event_feed_mouse_cancel(e, 0, NULL);
462    evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, 0, NULL);
463 }
464
465 static void
466 _elm_slider_label_set(Evas_Object *obj, const char *item, const char *label)
467 {
468    ELM_CHECK_WIDTYPE(obj, widtype);
469    Widget_Data *wd = elm_widget_data_get(obj);
470    if (item && strcmp(item, "default")) return;
471    if (!wd) return;
472    eina_stringshare_replace(&wd->label, label);
473    if (label)
474      {
475         edje_object_signal_emit(wd->slider, "elm,state,text,visible", "elm");
476         edje_object_message_signal_process(wd->slider);
477      }
478    else
479      {
480         edje_object_signal_emit(wd->slider, "elm,state,text,hidden", "elm");
481         edje_object_message_signal_process(wd->slider);
482      }
483    edje_object_part_text_set(wd->slider, "elm.text", label);
484    _sizing_eval(obj);
485 }
486
487 static const char *
488 _elm_slider_label_get(const Evas_Object *obj, const char *item)
489 {
490    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
491    Widget_Data *wd = elm_widget_data_get(obj);
492    if (item && strcmp(item, "default")) return NULL;
493    if (!wd) return NULL;
494    return wd->label;
495 }
496
497 static void
498 _icon_set(Evas_Object *obj, Evas_Object *icon)
499 {
500    Widget_Data *wd = elm_widget_data_get(obj);
501    if (!wd) return;
502    if (wd->icon == icon) return;
503    if (wd->icon) evas_object_del(wd->icon);
504    wd->icon = icon;
505    if (icon)
506      {
507         elm_widget_sub_object_add(obj, icon);
508         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
509                                        _changed_size_hints, obj);
510         edje_object_part_swallow(wd->slider, "elm.swallow.icon", icon);
511         edje_object_signal_emit(wd->slider, "elm,state,icon,visible", "elm");
512         edje_object_message_signal_process(wd->slider);
513      }
514    _sizing_eval(obj);
515 }
516
517 static Evas_Object *
518 _icon_unset(Evas_Object *obj)
519 {
520    Widget_Data *wd = elm_widget_data_get(obj);
521    Evas_Object *ret = NULL;
522    if (!wd) return NULL;
523    if (wd->icon)
524      {
525         elm_widget_sub_object_del(obj, wd->icon);
526         evas_object_event_callback_del_full(wd->icon,
527                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
528                                             _changed_size_hints, obj);
529         ret = wd->icon;
530         edje_object_part_unswallow(wd->slider, wd->icon);
531         edje_object_signal_emit(wd->slider, "elm,state,icon,hidden", "elm");
532         wd->icon = NULL;
533         _sizing_eval(obj);
534      }
535    return ret;
536 }
537
538 static void
539 _end_set(Evas_Object *obj, Evas_Object *end)
540 {
541    Widget_Data *wd = elm_widget_data_get(obj);
542    if (!wd) return;
543    if (wd->end == end) return;
544    if (wd->end) evas_object_del(wd->end);
545    wd->end = end;
546    if (end)
547      {
548         elm_widget_sub_object_add(obj, end);
549         evas_object_event_callback_add(end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
550                                        _changed_size_hints, obj);
551         edje_object_part_swallow(wd->slider, "elm.swallow.end", end);
552         edje_object_signal_emit(wd->slider, "elm,state,end,visible", "elm");
553         edje_object_message_signal_process(wd->slider);
554      }
555    _sizing_eval(obj);
556 }
557
558 static Evas_Object *
559 _end_unset(Evas_Object *obj)
560 {
561    Widget_Data *wd = elm_widget_data_get(obj);
562    Evas_Object *ret = NULL;
563    if (!wd) return NULL;
564    if (wd->end)
565      {
566         elm_widget_sub_object_del(obj, wd->end);
567         evas_object_event_callback_del_full(wd->end,
568                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
569                                             _changed_size_hints, obj);
570         ret = wd->end;
571         edje_object_part_unswallow(wd->slider, wd->end);
572         edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
573         wd->end = NULL;
574         _sizing_eval(obj);
575      }
576    return ret;
577 }
578
579 static void
580 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
581 {
582    ELM_CHECK_WIDTYPE(obj, widtype);
583    if ((!part) || (!strcmp(part, "elm.swallow.icon")))
584      _icon_set(obj, content);
585    else if (!strcmp(part, "elm.swallow.end"))
586      _end_set(obj, content);
587 }
588
589 static Evas_Object *
590 _content_get_hook(const Evas_Object *obj, const char *part __UNUSED__)
591 {
592    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
593    Widget_Data *wd = elm_widget_data_get(obj);
594    if (!wd) return NULL;
595    if ((!part) || (!strcmp(part, "elm.swallow.icon")))
596      return wd->icon;
597    else if (!strcmp(part, "elm.swallow.end"))
598      return wd->end;
599    return NULL;
600 }
601
602 static Evas_Object *
603 _content_unset_hook(Evas_Object *obj, const char *part __UNUSED__)
604 {
605    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
606    if ((!part) || (!strcmp(part, "elm.swallow.icon")))
607      return _icon_unset(obj);
608    else if (!strcmp(part, "elm.swallow.end"))
609      return _end_unset(obj);
610    return NULL;
611 }
612
613 EAPI Evas_Object *
614 elm_slider_add(Evas_Object *parent)
615 {
616    Evas_Object *obj;
617    Evas *e;
618    Widget_Data *wd;
619
620    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
621
622    ELM_SET_WIDTYPE(widtype, "slider");
623    elm_widget_type_set(obj, "slider");
624    elm_widget_sub_object_add(parent, obj);
625    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
626    elm_widget_data_set(obj, wd);
627    elm_widget_del_hook_set(obj, _del_hook);
628    elm_widget_theme_hook_set(obj, _theme_hook);
629    elm_widget_disable_hook_set(obj, _disable_hook);
630    elm_widget_can_focus_set(obj, EINA_TRUE);
631    elm_widget_event_hook_set(obj, _event_hook);
632    elm_widget_text_set_hook_set(obj, _elm_slider_label_set);
633    elm_widget_text_get_hook_set(obj, _elm_slider_label_get);
634    elm_widget_content_set_hook_set(obj, _content_set_hook);
635    elm_widget_content_get_hook_set(obj, _content_get_hook);
636    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
637
638    wd->horizontal = EINA_TRUE;
639    wd->indicator_show = EINA_TRUE;
640    wd->val = 0.0;
641    wd->val_min = 0.0;
642    wd->val_max = 1.0;
643
644    wd->slider = edje_object_add(e);
645    _elm_theme_object_set(obj, wd->slider, "slider", "horizontal", "default");
646    elm_widget_resize_object_set(obj, wd->slider);
647    edje_object_signal_callback_add(wd->slider, "drag", "*", _drag, obj);
648    edje_object_signal_callback_add(wd->slider, "drag,start", "*", _drag_start, obj);
649    edje_object_signal_callback_add(wd->slider, "drag,stop", "*", _drag_stop, obj);
650    edje_object_signal_callback_add(wd->slider, "drag,step", "*", _drag_step, obj);
651    edje_object_signal_callback_add(wd->slider, "drag,page", "*", _drag_stop, obj);
652    //   edje_object_signal_callback_add(wd->slider, "drag,set", "*", _drag_stop, obj);
653    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", 0.0, 0.0);
654
655    wd->spacer = evas_object_rectangle_add(e);
656    evas_object_color_set(wd->spacer, 0, 0, 0, 0);
657    evas_object_pass_events_set(wd->spacer, EINA_TRUE);
658    elm_widget_sub_object_add(obj, wd->spacer);
659    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
660    evas_object_event_callback_add(wd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_cb, obj);
661    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
662
663    _mirrored_set(obj, elm_widget_mirrored_get(obj));
664    _sizing_eval(obj);
665
666    // TODO: convert Elementary to subclassing of Evas_Smart_Class
667    // TODO: and save some bytes, making descriptions per-class and not instance!
668    evas_object_smart_callbacks_descriptions_set(obj, _signals);
669    return obj;
670 }
671
672 EAPI void
673 elm_slider_label_set(Evas_Object *obj, const char *label)
674 {
675    _elm_slider_label_set(obj, NULL, label);
676 }
677
678 EAPI const char *
679 elm_slider_label_get(const Evas_Object *obj)
680 {
681    return _elm_slider_label_get(obj, NULL);
682 }
683
684 EAPI void
685 elm_slider_icon_set(Evas_Object *obj, Evas_Object *icon)
686 {
687    _content_set_hook(obj, NULL, icon);
688 }
689
690 EAPI Evas_Object *
691 elm_slider_icon_unset(Evas_Object *obj)
692 {
693    return _content_unset_hook(obj, NULL);
694 }
695
696 EAPI Evas_Object *
697 elm_slider_icon_get(const Evas_Object *obj)
698 {
699    return _content_get_hook(obj, NULL);
700 }
701
702 EAPI void
703 elm_slider_span_size_set(Evas_Object *obj, Evas_Coord size)
704 {
705    ELM_CHECK_WIDTYPE(obj, widtype);
706    Widget_Data *wd = elm_widget_data_get(obj);
707    if (!wd) return;
708    if (wd->size == size) return;
709    wd->size = size;
710    if (wd->horizontal)
711      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
712    else
713      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
714    if (wd->indicator_show)
715      edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
716    else
717      edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
718    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
719    _sizing_eval(obj);
720 }
721
722 EAPI Evas_Coord
723 elm_slider_span_size_get(const Evas_Object *obj)
724 {
725    ELM_CHECK_WIDTYPE(obj, widtype) 0;
726    Widget_Data *wd = elm_widget_data_get(obj);
727    if (!wd) return 0;
728    return wd->size;
729 }
730
731 EAPI void
732 elm_slider_unit_format_set(Evas_Object *obj, const char *units)
733 {
734    ELM_CHECK_WIDTYPE(obj, widtype);
735    Widget_Data *wd = elm_widget_data_get(obj);
736    if (!wd) return;
737    eina_stringshare_replace(&wd->units, units);
738    if (units)
739      {
740         edje_object_signal_emit(wd->slider, "elm,state,units,visible", "elm");
741         edje_object_message_signal_process(wd->slider);
742      }
743    else
744      {
745         edje_object_signal_emit(wd->slider, "elm,state,units,hidden", "elm");
746         edje_object_message_signal_process(wd->slider);
747      }
748    _units_set(obj);
749    _sizing_eval(obj);
750 }
751
752 EAPI const char *
753 elm_slider_unit_format_get(const Evas_Object *obj)
754 {
755    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
756    Widget_Data *wd = elm_widget_data_get(obj);
757    if (!wd) return NULL;
758    return wd->units;
759 }
760
761 EAPI void
762 elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator)
763 {
764    ELM_CHECK_WIDTYPE(obj, widtype);
765    Widget_Data *wd = elm_widget_data_get(obj);
766    if (!wd) return;
767    eina_stringshare_replace(&wd->indicator, indicator);
768    _indicator_set(obj);
769 }
770
771 EAPI const char *
772 elm_slider_indicator_format_get(const Evas_Object *obj)
773 {
774    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
775    Widget_Data *wd = elm_widget_data_get(obj);
776    if (!wd) return NULL;
777    return wd->indicator;
778 }
779
780 EAPI void
781 elm_slider_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
782 {
783    ELM_CHECK_WIDTYPE(obj, widtype);
784    Widget_Data *wd = elm_widget_data_get(obj);
785    if (!wd) return;
786    horizontal = !!horizontal;
787    if (wd->horizontal == horizontal) return;
788    wd->horizontal = horizontal;
789    _theme_hook(obj);
790 }
791
792 EAPI Eina_Bool
793 elm_slider_horizontal_get(const Evas_Object *obj)
794 {
795    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
796    Widget_Data *wd = elm_widget_data_get(obj);
797    if (!wd) return EINA_FALSE;
798    return wd->horizontal;
799 }
800
801 EAPI void
802 elm_slider_min_max_set(Evas_Object *obj, double min, double max)
803 {
804    ELM_CHECK_WIDTYPE(obj, widtype);
805    Widget_Data *wd = elm_widget_data_get(obj);
806    if (!wd) return;
807    if ((wd->val_min == min) && (wd->val_max == max)) return;
808    wd->val_min = min;
809    wd->val_max = max;
810    if (wd->val < wd->val_min) wd->val = wd->val_min;
811    if (wd->val > wd->val_max) wd->val = wd->val_max;
812    _val_set(obj);
813    _units_set(obj);
814    _indicator_set(obj);
815 }
816
817 EAPI void
818 elm_slider_min_max_get(const Evas_Object *obj, double *min, double *max)
819 {
820    if (min) *min = 0.0;
821    if (max) *max = 0.0;
822    ELM_CHECK_WIDTYPE(obj, widtype);
823    Widget_Data *wd = elm_widget_data_get(obj);
824    if (!wd) return;
825    if (min) *min = wd->val_min;
826    if (max) *max = wd->val_max;
827 }
828
829 EAPI void
830 elm_slider_value_set(Evas_Object *obj, double val)
831 {
832    ELM_CHECK_WIDTYPE(obj, widtype);
833    Widget_Data *wd = elm_widget_data_get(obj);
834    if (!wd) return;
835    if (wd->val == val) return;
836    wd->val = val;
837    if (wd->val < wd->val_min) wd->val = wd->val_min;
838    if (wd->val > wd->val_max) wd->val = wd->val_max;
839    _val_set(obj);
840    _units_set(obj);
841    _indicator_set(obj);
842 }
843
844 EAPI double
845 elm_slider_value_get(const Evas_Object *obj)
846 {
847    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
848    Widget_Data *wd = elm_widget_data_get(obj);
849    if (!wd) return 0.0;
850    return wd->val;
851 }
852
853 EAPI void
854 elm_slider_inverted_set(Evas_Object *obj, Eina_Bool inverted)
855 {
856    ELM_CHECK_WIDTYPE(obj, widtype);
857    Widget_Data *wd = elm_widget_data_get(obj);
858    if (!wd) return;
859    inverted = !!inverted;
860    if (wd->inverted == inverted) return;
861    wd->inverted = inverted;
862    if (wd->inverted)
863      edje_object_signal_emit(wd->slider, "elm,state,inverted,on", "elm");
864    else
865      edje_object_signal_emit(wd->slider, "elm,state,inverted,off", "elm");
866    edje_object_message_signal_process(wd->slider);
867    _val_set(obj);
868    _units_set(obj);
869    _indicator_set(obj);
870 }
871
872 EAPI Eina_Bool
873 elm_slider_inverted_get(const Evas_Object *obj)
874 {
875    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
876    Widget_Data *wd = elm_widget_data_get(obj);
877    if (!wd) return EINA_FALSE;
878    return wd->inverted;
879 }
880
881 EAPI void
882 elm_slider_indicator_format_function_set(Evas_Object *obj, const char *(*func)(double val), void (*free_func)(const char *str))
883 {
884    ELM_CHECK_WIDTYPE(obj, widtype);
885    Widget_Data *wd = elm_widget_data_get(obj);
886    if (!wd) return;
887    wd->indicator_format_func = func;
888    wd->indicator_format_free = free_func;
889    _indicator_set(obj);
890 }
891
892 EAPI void
893 elm_slider_units_format_function_set(Evas_Object *obj, const char *(*func)(double val), void (*free_func)(const char *str))
894 {
895    ELM_CHECK_WIDTYPE(obj, widtype);
896    Widget_Data *wd = elm_widget_data_get(obj);
897    if (!wd) return;
898    wd->units_format_func = func;
899    wd->units_format_free = free_func;
900    _indicator_set(obj);
901 }
902
903 EAPI void
904 elm_slider_end_set(Evas_Object *obj, Evas_Object *end)
905 {
906    _content_set_hook(obj, "elm.swallow.end", end);
907 }
908
909 EAPI Evas_Object *
910 elm_slider_end_unset(Evas_Object *obj)
911 {
912    return _content_unset_hook(obj, "elm.swallow.end");
913 }
914
915 EAPI Evas_Object *
916 elm_slider_end_get(const Evas_Object *obj)
917 {
918    return _content_get_hook(obj, "elm.swallow.end");
919 }
920
921 EAPI void
922 elm_slider_indicator_show_set(Evas_Object *obj, Eina_Bool show)
923 {
924    ELM_CHECK_WIDTYPE(obj, widtype);
925    Widget_Data *wd = elm_widget_data_get(obj);
926    if (show) {
927         wd->indicator_show = EINA_TRUE;
928         edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
929    }
930    else {
931         wd->indicator_show = EINA_FALSE;
932         edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
933    }
934 }
935
936 EAPI Eina_Bool
937 elm_slider_indicator_show_get(const Evas_Object *obj)
938 {
939    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
940    Widget_Data *wd = elm_widget_data_get(obj);
941    if (!wd) return EINA_FALSE;
942    return wd->indicator_show;
943 }
944