elementary - modified content_set/get/unset part names to be simple names.
[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) return;
584    if (!strcmp(part, "icon"))
585      _icon_set(obj, content);
586    else if (!strcmp(part, "end"))
587      _end_set(obj, content);
588 }
589
590 static Evas_Object *
591 _content_get_hook(const Evas_Object *obj, const char *part)
592 {
593    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
594    Widget_Data *wd;
595    if (!part) return NULL;
596    wd = elm_widget_data_get(obj);
597    if (!wd) return NULL;
598    if (!strcmp(part, "icon"))
599      return wd->icon;
600    else if (!strcmp(part, "end"))
601      return wd->end;
602    return NULL;
603 }
604
605 static Evas_Object *
606 _content_unset_hook(Evas_Object *obj, const char *part)
607 {
608    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
609    if (!part) return NULL;
610    if (!strcmp(part, "icon"))
611      return _icon_unset(obj);
612    else if (!strcmp(part, "end"))
613      return _end_unset(obj);
614    return NULL;
615 }
616
617 EAPI Evas_Object *
618 elm_slider_add(Evas_Object *parent)
619 {
620    Evas_Object *obj;
621    Evas *e;
622    Widget_Data *wd;
623
624    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
625
626    ELM_SET_WIDTYPE(widtype, "slider");
627    elm_widget_type_set(obj, "slider");
628    elm_widget_sub_object_add(parent, obj);
629    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
630    elm_widget_data_set(obj, wd);
631    elm_widget_del_hook_set(obj, _del_hook);
632    elm_widget_theme_hook_set(obj, _theme_hook);
633    elm_widget_disable_hook_set(obj, _disable_hook);
634    elm_widget_can_focus_set(obj, EINA_TRUE);
635    elm_widget_event_hook_set(obj, _event_hook);
636    elm_widget_text_set_hook_set(obj, _elm_slider_label_set);
637    elm_widget_text_get_hook_set(obj, _elm_slider_label_get);
638    elm_widget_content_set_hook_set(obj, _content_set_hook);
639    elm_widget_content_get_hook_set(obj, _content_get_hook);
640    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
641
642    wd->horizontal = EINA_TRUE;
643    wd->indicator_show = EINA_TRUE;
644    wd->val = 0.0;
645    wd->val_min = 0.0;
646    wd->val_max = 1.0;
647
648    wd->slider = edje_object_add(e);
649    _elm_theme_object_set(obj, wd->slider, "slider", "horizontal", "default");
650    elm_widget_resize_object_set(obj, wd->slider);
651    edje_object_signal_callback_add(wd->slider, "drag", "*", _drag, obj);
652    edje_object_signal_callback_add(wd->slider, "drag,start", "*", _drag_start, obj);
653    edje_object_signal_callback_add(wd->slider, "drag,stop", "*", _drag_stop, obj);
654    edje_object_signal_callback_add(wd->slider, "drag,step", "*", _drag_step, obj);
655    edje_object_signal_callback_add(wd->slider, "drag,page", "*", _drag_stop, obj);
656    //   edje_object_signal_callback_add(wd->slider, "drag,set", "*", _drag_stop, obj);
657    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", 0.0, 0.0);
658
659    wd->spacer = evas_object_rectangle_add(e);
660    evas_object_color_set(wd->spacer, 0, 0, 0, 0);
661    evas_object_pass_events_set(wd->spacer, EINA_TRUE);
662    elm_widget_sub_object_add(obj, wd->spacer);
663    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
664    evas_object_event_callback_add(wd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_cb, obj);
665    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
666
667    _mirrored_set(obj, elm_widget_mirrored_get(obj));
668    _sizing_eval(obj);
669
670    // TODO: convert Elementary to subclassing of Evas_Smart_Class
671    // TODO: and save some bytes, making descriptions per-class and not instance!
672    evas_object_smart_callbacks_descriptions_set(obj, _signals);
673    return obj;
674 }
675
676 EAPI void
677 elm_slider_label_set(Evas_Object *obj, const char *label)
678 {
679    _elm_slider_label_set(obj, NULL, label);
680 }
681
682 EAPI const char *
683 elm_slider_label_get(const Evas_Object *obj)
684 {
685    return _elm_slider_label_get(obj, NULL);
686 }
687
688 EAPI void
689 elm_slider_icon_set(Evas_Object *obj, Evas_Object *icon)
690 {
691    _content_set_hook(obj, "icon", icon);
692 }
693
694 EAPI Evas_Object *
695 elm_slider_icon_unset(Evas_Object *obj)
696 {
697    return _content_unset_hook(obj, "icon");
698 }
699
700 EAPI Evas_Object *
701 elm_slider_icon_get(const Evas_Object *obj)
702 {
703    return _content_get_hook(obj, "icon");
704 }
705
706 EAPI void
707 elm_slider_span_size_set(Evas_Object *obj, Evas_Coord size)
708 {
709    ELM_CHECK_WIDTYPE(obj, widtype);
710    Widget_Data *wd = elm_widget_data_get(obj);
711    if (!wd) return;
712    if (wd->size == size) return;
713    wd->size = size;
714    if (wd->horizontal)
715      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
716    else
717      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
718    if (wd->indicator_show)
719      edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
720    else
721      edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
722    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
723    _sizing_eval(obj);
724 }
725
726 EAPI Evas_Coord
727 elm_slider_span_size_get(const Evas_Object *obj)
728 {
729    ELM_CHECK_WIDTYPE(obj, widtype) 0;
730    Widget_Data *wd = elm_widget_data_get(obj);
731    if (!wd) return 0;
732    return wd->size;
733 }
734
735 EAPI void
736 elm_slider_unit_format_set(Evas_Object *obj, const char *units)
737 {
738    ELM_CHECK_WIDTYPE(obj, widtype);
739    Widget_Data *wd = elm_widget_data_get(obj);
740    if (!wd) return;
741    eina_stringshare_replace(&wd->units, units);
742    if (units)
743      {
744         edje_object_signal_emit(wd->slider, "elm,state,units,visible", "elm");
745         edje_object_message_signal_process(wd->slider);
746      }
747    else
748      {
749         edje_object_signal_emit(wd->slider, "elm,state,units,hidden", "elm");
750         edje_object_message_signal_process(wd->slider);
751      }
752    _units_set(obj);
753    _sizing_eval(obj);
754 }
755
756 EAPI const char *
757 elm_slider_unit_format_get(const Evas_Object *obj)
758 {
759    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
760    Widget_Data *wd = elm_widget_data_get(obj);
761    if (!wd) return NULL;
762    return wd->units;
763 }
764
765 EAPI void
766 elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator)
767 {
768    ELM_CHECK_WIDTYPE(obj, widtype);
769    Widget_Data *wd = elm_widget_data_get(obj);
770    if (!wd) return;
771    eina_stringshare_replace(&wd->indicator, indicator);
772    _indicator_set(obj);
773 }
774
775 EAPI const char *
776 elm_slider_indicator_format_get(const Evas_Object *obj)
777 {
778    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
779    Widget_Data *wd = elm_widget_data_get(obj);
780    if (!wd) return NULL;
781    return wd->indicator;
782 }
783
784 EAPI void
785 elm_slider_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
786 {
787    ELM_CHECK_WIDTYPE(obj, widtype);
788    Widget_Data *wd = elm_widget_data_get(obj);
789    if (!wd) return;
790    horizontal = !!horizontal;
791    if (wd->horizontal == horizontal) return;
792    wd->horizontal = horizontal;
793    _theme_hook(obj);
794 }
795
796 EAPI Eina_Bool
797 elm_slider_horizontal_get(const Evas_Object *obj)
798 {
799    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
800    Widget_Data *wd = elm_widget_data_get(obj);
801    if (!wd) return EINA_FALSE;
802    return wd->horizontal;
803 }
804
805 EAPI void
806 elm_slider_min_max_set(Evas_Object *obj, double min, double max)
807 {
808    ELM_CHECK_WIDTYPE(obj, widtype);
809    Widget_Data *wd = elm_widget_data_get(obj);
810    if (!wd) return;
811    if ((wd->val_min == min) && (wd->val_max == max)) return;
812    wd->val_min = min;
813    wd->val_max = max;
814    if (wd->val < wd->val_min) wd->val = wd->val_min;
815    if (wd->val > wd->val_max) wd->val = wd->val_max;
816    _val_set(obj);
817    _units_set(obj);
818    _indicator_set(obj);
819 }
820
821 EAPI void
822 elm_slider_min_max_get(const Evas_Object *obj, double *min, double *max)
823 {
824    if (min) *min = 0.0;
825    if (max) *max = 0.0;
826    ELM_CHECK_WIDTYPE(obj, widtype);
827    Widget_Data *wd = elm_widget_data_get(obj);
828    if (!wd) return;
829    if (min) *min = wd->val_min;
830    if (max) *max = wd->val_max;
831 }
832
833 EAPI void
834 elm_slider_value_set(Evas_Object *obj, double val)
835 {
836    ELM_CHECK_WIDTYPE(obj, widtype);
837    Widget_Data *wd = elm_widget_data_get(obj);
838    if (!wd) return;
839    if (wd->val == val) return;
840    wd->val = val;
841    if (wd->val < wd->val_min) wd->val = wd->val_min;
842    if (wd->val > wd->val_max) wd->val = wd->val_max;
843    _val_set(obj);
844    _units_set(obj);
845    _indicator_set(obj);
846 }
847
848 EAPI double
849 elm_slider_value_get(const Evas_Object *obj)
850 {
851    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
852    Widget_Data *wd = elm_widget_data_get(obj);
853    if (!wd) return 0.0;
854    return wd->val;
855 }
856
857 EAPI void
858 elm_slider_inverted_set(Evas_Object *obj, Eina_Bool inverted)
859 {
860    ELM_CHECK_WIDTYPE(obj, widtype);
861    Widget_Data *wd = elm_widget_data_get(obj);
862    if (!wd) return;
863    inverted = !!inverted;
864    if (wd->inverted == inverted) return;
865    wd->inverted = inverted;
866    if (wd->inverted)
867      edje_object_signal_emit(wd->slider, "elm,state,inverted,on", "elm");
868    else
869      edje_object_signal_emit(wd->slider, "elm,state,inverted,off", "elm");
870    edje_object_message_signal_process(wd->slider);
871    _val_set(obj);
872    _units_set(obj);
873    _indicator_set(obj);
874 }
875
876 EAPI Eina_Bool
877 elm_slider_inverted_get(const Evas_Object *obj)
878 {
879    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
880    Widget_Data *wd = elm_widget_data_get(obj);
881    if (!wd) return EINA_FALSE;
882    return wd->inverted;
883 }
884
885 EAPI void
886 elm_slider_indicator_format_function_set(Evas_Object *obj, const char *(*func)(double val), void (*free_func)(const char *str))
887 {
888    ELM_CHECK_WIDTYPE(obj, widtype);
889    Widget_Data *wd = elm_widget_data_get(obj);
890    if (!wd) return;
891    wd->indicator_format_func = func;
892    wd->indicator_format_free = free_func;
893    _indicator_set(obj);
894 }
895
896 EAPI void
897 elm_slider_units_format_function_set(Evas_Object *obj, const char *(*func)(double val), void (*free_func)(const char *str))
898 {
899    ELM_CHECK_WIDTYPE(obj, widtype);
900    Widget_Data *wd = elm_widget_data_get(obj);
901    if (!wd) return;
902    wd->units_format_func = func;
903    wd->units_format_free = free_func;
904    _indicator_set(obj);
905 }
906
907 EAPI void
908 elm_slider_end_set(Evas_Object *obj, Evas_Object *end)
909 {
910    _content_set_hook(obj, "end", end);
911 }
912
913 EAPI Evas_Object *
914 elm_slider_end_unset(Evas_Object *obj)
915 {
916    return _content_unset_hook(obj, "end");
917 }
918
919 EAPI Evas_Object *
920 elm_slider_end_get(const Evas_Object *obj)
921 {
922    return _content_get_hook(obj, "end");
923 }
924
925 EAPI void
926 elm_slider_indicator_show_set(Evas_Object *obj, Eina_Bool show)
927 {
928    ELM_CHECK_WIDTYPE(obj, widtype);
929    Widget_Data *wd = elm_widget_data_get(obj);
930    if (show) {
931         wd->indicator_show = EINA_TRUE;
932         edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
933    }
934    else {
935         wd->indicator_show = EINA_FALSE;
936         edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
937    }
938 }
939
940 EAPI Eina_Bool
941 elm_slider_indicator_show_get(const Evas_Object *obj)
942 {
943    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
944    Widget_Data *wd = elm_widget_data_get(obj);
945    if (!wd) return EINA_FALSE;
946    return wd->indicator_show;
947 }
948