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