elm: Use appropriate add/del_full for evas event callbacks.
[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 EAPI Evas_Object *
498 elm_slider_add(Evas_Object *parent)
499 {
500    Evas_Object *obj;
501    Evas *e;
502    Widget_Data *wd;
503
504    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
505
506    ELM_SET_WIDTYPE(widtype, "slider");
507    elm_widget_type_set(obj, "slider");
508    elm_widget_sub_object_add(parent, obj);
509    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
510    elm_widget_data_set(obj, wd);
511    elm_widget_del_hook_set(obj, _del_hook);
512    elm_widget_theme_hook_set(obj, _theme_hook);
513    elm_widget_disable_hook_set(obj, _disable_hook);
514    elm_widget_can_focus_set(obj, EINA_TRUE);
515    elm_widget_event_hook_set(obj, _event_hook);
516    elm_widget_text_set_hook_set(obj, _elm_slider_label_set);
517    elm_widget_text_get_hook_set(obj, _elm_slider_label_get);
518
519    wd->horizontal = EINA_TRUE;
520    wd->indicator_show = EINA_TRUE;
521    wd->val = 0.0;
522    wd->val_min = 0.0;
523    wd->val_max = 1.0;
524
525    wd->slider = edje_object_add(e);
526    _elm_theme_object_set(obj, wd->slider, "slider", "horizontal", "default");
527    elm_widget_resize_object_set(obj, wd->slider);
528    edje_object_signal_callback_add(wd->slider, "drag", "*", _drag, obj);
529    edje_object_signal_callback_add(wd->slider, "drag,start", "*", _drag_start, obj);
530    edje_object_signal_callback_add(wd->slider, "drag,stop", "*", _drag_stop, obj);
531    edje_object_signal_callback_add(wd->slider, "drag,step", "*", _drag_step, obj);
532    edje_object_signal_callback_add(wd->slider, "drag,page", "*", _drag_stop, obj);
533    //   edje_object_signal_callback_add(wd->slider, "drag,set", "*", _drag_stop, obj);
534    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", 0.0, 0.0);
535
536    wd->spacer = evas_object_rectangle_add(e);
537    evas_object_color_set(wd->spacer, 0, 0, 0, 0);
538    evas_object_pass_events_set(wd->spacer, EINA_TRUE);
539    elm_widget_sub_object_add(obj, wd->spacer);
540    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
541    evas_object_event_callback_add(wd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_cb, obj);
542    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
543
544    _mirrored_set(obj, elm_widget_mirrored_get(obj));
545    _sizing_eval(obj);
546
547    // TODO: convert Elementary to subclassing of Evas_Smart_Class
548    // TODO: and save some bytes, making descriptions per-class and not instance!
549    evas_object_smart_callbacks_descriptions_set(obj, _signals);
550    return obj;
551 }
552
553 EAPI void
554 elm_slider_label_set(Evas_Object *obj, const char *label)
555 {
556    _elm_slider_label_set(obj, NULL, label);
557 }
558
559 EAPI const char *
560 elm_slider_label_get(const Evas_Object *obj)
561 {
562    return _elm_slider_label_get(obj, NULL);
563 }
564
565 EAPI void
566 elm_slider_icon_set(Evas_Object *obj, Evas_Object *icon)
567 {
568    ELM_CHECK_WIDTYPE(obj, widtype);
569    Widget_Data *wd = elm_widget_data_get(obj);
570    if (!wd) return;
571    if (wd->icon == icon) return;
572    if (wd->icon) evas_object_del(wd->icon);
573    wd->icon = icon;
574    if (icon)
575      {
576         elm_widget_sub_object_add(obj, icon);
577         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
578                                        _changed_size_hints, obj);
579         edje_object_part_swallow(wd->slider, "elm.swallow.icon", icon);
580         edje_object_signal_emit(wd->slider, "elm,state,icon,visible", "elm");
581         edje_object_message_signal_process(wd->slider);
582      }
583    _sizing_eval(obj);
584 }
585
586 EAPI Evas_Object *
587 elm_slider_icon_unset(Evas_Object *obj)
588 {
589    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
590    Widget_Data *wd = elm_widget_data_get(obj);
591    Evas_Object *ret = NULL;
592    if (!wd) return NULL;
593    if (wd->icon)
594      {
595         elm_widget_sub_object_del(obj, wd->icon);
596         evas_object_event_callback_del_full(wd->icon,
597                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
598                                             _changed_size_hints, obj);
599         ret = wd->icon;
600         edje_object_part_unswallow(wd->slider, wd->icon);
601         edje_object_signal_emit(wd->slider, "elm,state,icon,hidden", "elm");
602         wd->icon = NULL;
603         _sizing_eval(obj);
604      }
605    return ret;
606 }
607
608 EAPI Evas_Object *
609 elm_slider_icon_get(const Evas_Object *obj)
610 {
611    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
612    Widget_Data *wd = elm_widget_data_get(obj);
613    if (!wd) return NULL;
614    return wd->icon;
615 }
616
617 EAPI void
618 elm_slider_span_size_set(Evas_Object *obj, Evas_Coord size)
619 {
620    ELM_CHECK_WIDTYPE(obj, widtype);
621    Widget_Data *wd = elm_widget_data_get(obj);
622    if (!wd) return;
623    if (wd->size == size) return;
624    wd->size = size;
625    if (wd->horizontal)
626      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
627    else
628      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
629    if (wd->indicator_show)
630      edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
631    else
632      edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
633    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
634    _sizing_eval(obj);
635 }
636
637 EAPI Evas_Coord
638 elm_slider_span_size_get(const Evas_Object *obj)
639 {
640    ELM_CHECK_WIDTYPE(obj, widtype) 0;
641    Widget_Data *wd = elm_widget_data_get(obj);
642    if (!wd) return 0;
643    return wd->size;
644 }
645
646 EAPI void
647 elm_slider_unit_format_set(Evas_Object *obj, const char *units)
648 {
649    ELM_CHECK_WIDTYPE(obj, widtype);
650    Widget_Data *wd = elm_widget_data_get(obj);
651    if (!wd) return;
652    eina_stringshare_replace(&wd->units, units);
653    if (units)
654      {
655         edje_object_signal_emit(wd->slider, "elm,state,units,visible", "elm");
656         edje_object_message_signal_process(wd->slider);
657      }
658    else
659      {
660         edje_object_signal_emit(wd->slider, "elm,state,units,hidden", "elm");
661         edje_object_message_signal_process(wd->slider);
662      }
663    _units_set(obj);
664    _sizing_eval(obj);
665 }
666
667 EAPI const char *
668 elm_slider_unit_format_get(const Evas_Object *obj)
669 {
670    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
671    Widget_Data *wd = elm_widget_data_get(obj);
672    if (!wd) return NULL;
673    return wd->units;
674 }
675
676 EAPI void
677 elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator)
678 {
679    ELM_CHECK_WIDTYPE(obj, widtype);
680    Widget_Data *wd = elm_widget_data_get(obj);
681    if (!wd) return;
682    eina_stringshare_replace(&wd->indicator, indicator);
683    _indicator_set(obj);
684 }
685
686 EAPI const char *
687 elm_slider_indicator_format_get(const Evas_Object *obj)
688 {
689    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
690    Widget_Data *wd = elm_widget_data_get(obj);
691    if (!wd) return NULL;
692    return wd->indicator;
693 }
694
695 EAPI void
696 elm_slider_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
697 {
698    ELM_CHECK_WIDTYPE(obj, widtype);
699    Widget_Data *wd = elm_widget_data_get(obj);
700    if (!wd) return;
701    horizontal = !!horizontal;
702    if (wd->horizontal == horizontal) return;
703    wd->horizontal = horizontal;
704    _theme_hook(obj);
705 }
706
707 EAPI Eina_Bool
708 elm_slider_horizontal_get(const Evas_Object *obj)
709 {
710    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
711    Widget_Data *wd = elm_widget_data_get(obj);
712    if (!wd) return EINA_FALSE;
713    return wd->horizontal;
714 }
715
716 EAPI void
717 elm_slider_min_max_set(Evas_Object *obj, double min, double max)
718 {
719    ELM_CHECK_WIDTYPE(obj, widtype);
720    Widget_Data *wd = elm_widget_data_get(obj);
721    if (!wd) return;
722    if ((wd->val_min == min) && (wd->val_max == max)) return;
723    wd->val_min = min;
724    wd->val_max = max;
725    if (wd->val < wd->val_min) wd->val = wd->val_min;
726    if (wd->val > wd->val_max) wd->val = wd->val_max;
727    _val_set(obj);
728    _units_set(obj);
729    _indicator_set(obj);
730 }
731
732 EAPI void
733 elm_slider_min_max_get(const Evas_Object *obj, double *min, double *max)
734 {
735    if (min) *min = 0.0;
736    if (max) *max = 0.0;
737    ELM_CHECK_WIDTYPE(obj, widtype);
738    Widget_Data *wd = elm_widget_data_get(obj);
739    if (!wd) return;
740    if (min) *min = wd->val_min;
741    if (max) *max = wd->val_max;
742 }
743
744 EAPI void
745 elm_slider_value_set(Evas_Object *obj, double val)
746 {
747    ELM_CHECK_WIDTYPE(obj, widtype);
748    Widget_Data *wd = elm_widget_data_get(obj);
749    if (!wd) return;
750    if (wd->val == val) return;
751    wd->val = val;
752    if (wd->val < wd->val_min) wd->val = wd->val_min;
753    if (wd->val > wd->val_max) wd->val = wd->val_max;
754    _val_set(obj);
755    _units_set(obj);
756    _indicator_set(obj);
757 }
758
759 EAPI double
760 elm_slider_value_get(const Evas_Object *obj)
761 {
762    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
763    Widget_Data *wd = elm_widget_data_get(obj);
764    if (!wd) return 0.0;
765    return wd->val;
766 }
767
768 EAPI void
769 elm_slider_inverted_set(Evas_Object *obj, Eina_Bool inverted)
770 {
771    ELM_CHECK_WIDTYPE(obj, widtype);
772    Widget_Data *wd = elm_widget_data_get(obj);
773    if (!wd) return;
774    inverted = !!inverted;
775    if (wd->inverted == inverted) return;
776    wd->inverted = inverted;
777    if (wd->inverted)
778      edje_object_signal_emit(wd->slider, "elm,state,inverted,on", "elm");
779    else
780      edje_object_signal_emit(wd->slider, "elm,state,inverted,off", "elm");
781    edje_object_message_signal_process(wd->slider);
782    _val_set(obj);
783    _units_set(obj);
784    _indicator_set(obj);
785 }
786
787 EAPI Eina_Bool
788 elm_slider_inverted_get(const Evas_Object *obj)
789 {
790    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
791    Widget_Data *wd = elm_widget_data_get(obj);
792    if (!wd) return EINA_FALSE;
793    return wd->inverted;
794 }
795
796 EAPI void
797 elm_slider_indicator_format_function_set(Evas_Object *obj, const char *(*func)(double val), void (*free_func)(const char *str))
798 {
799    ELM_CHECK_WIDTYPE(obj, widtype);
800    Widget_Data *wd = elm_widget_data_get(obj);
801    if (!wd) return;
802    wd->indicator_format_func = func;
803    wd->indicator_format_free = free_func;
804    _indicator_set(obj);
805 }
806
807 EAPI void
808 elm_slider_units_format_function_set(Evas_Object *obj, const char *(*func)(double val), void (*free_func)(const char *str))
809 {
810    ELM_CHECK_WIDTYPE(obj, widtype);
811    Widget_Data *wd = elm_widget_data_get(obj);
812    if (!wd) return;
813    wd->units_format_func = func;
814    wd->units_format_free = free_func;
815    _indicator_set(obj);
816 }
817
818 EAPI void
819 elm_slider_end_set(Evas_Object *obj, Evas_Object *end)
820 {
821    ELM_CHECK_WIDTYPE(obj, widtype);
822    Widget_Data *wd = elm_widget_data_get(obj);
823    if (!wd) return;
824    if (wd->end == end) return;
825    if (wd->end) evas_object_del(wd->end);
826    wd->end = end;
827    if (end)
828      {
829         elm_widget_sub_object_add(obj, end);
830         evas_object_event_callback_add(end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
831                                        _changed_size_hints, obj);
832         edje_object_part_swallow(wd->slider, "elm.swallow.end", end);
833         edje_object_signal_emit(wd->slider, "elm,state,end,visible", "elm");
834         edje_object_message_signal_process(wd->slider);
835      }
836    _sizing_eval(obj);
837 }
838
839 EAPI Evas_Object *
840 elm_slider_end_unset(Evas_Object *obj)
841 {
842    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
843    Widget_Data *wd = elm_widget_data_get(obj);
844    Evas_Object *ret = NULL;
845    if (!wd) return NULL;
846    if (wd->end)
847      {
848         elm_widget_sub_object_del(obj, wd->end);
849         evas_object_event_callback_del_full(wd->end,
850                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
851                                             _changed_size_hints, obj);
852         ret = wd->end;
853         edje_object_part_unswallow(wd->slider, wd->end);
854         edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
855         wd->end = NULL;
856         _sizing_eval(obj);
857      }
858    return ret;
859 }
860
861 EAPI Evas_Object *
862 elm_slider_end_get(const Evas_Object *obj)
863 {
864    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
865    Widget_Data *wd = elm_widget_data_get(obj);
866    if (!wd) return NULL;
867    return wd->end;
868 }
869
870 EAPI void
871 elm_slider_indicator_show_set(Evas_Object *obj, Eina_Bool show)
872 {
873    ELM_CHECK_WIDTYPE(obj, widtype);
874    Widget_Data *wd = elm_widget_data_get(obj);
875    if (show) {
876         wd->indicator_show = EINA_TRUE;
877         edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
878    }
879    else {
880         wd->indicator_show = EINA_FALSE;
881         edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
882    }
883 }
884
885 EAPI Eina_Bool
886 elm_slider_indicator_show_get(const Evas_Object *obj)
887 {
888    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
889    Widget_Data *wd = elm_widget_data_get(obj);
890    if (!wd) return EINA_FALSE;
891    return wd->indicator_show;
892 }
893