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