Merge "[elm_entry] anchor clicked bug - fixed"
[framework/uifw/elementary.git] / src / lib / elm_slider.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Slider Slider
6  * @ingroup Elementary
7  *
8  * The slider adds a dragable “slider” widget for selecting the value of
9  * something within a range.
10  *
11  * Signals that you can add callbacks for are:
12  *
13  * changed - Whenever the slider value is changed by the user.
14  *
15  * delay,changed - A short time after the value is changed by the user.
16  * This will be called only when the user stops dragging for a very short
17  * period or when they release their finger/mouse, so it avoids possibly
18  * expensive reactions to the value change.
19  *
20  * slider,drag,start - dragging the slider indicator around has started
21  *
22  * slider,drag,stop - dragging the slider indicator around has stopped
23  *
24  * A slider can be horizontal or vertical. It can contain an Icon and has a
25  * primary label as well as a units label (that is formatted with floating
26  * point values and thus accepts a printf-style format string, like
27  * “%1.2f units”. There is also an indicator string that may be somewhere
28  * else (like on the slider itself) that also accepts a format string like
29  * units. Label, Icon Unit and Indicator strings/objects are optional.
30  *
31  * A slider may be inverted which means values invert, with high vales being
32  * on the left or top and low values on the right or bottom (as opposed to
33  * normally being low on the left or top and high on the bottom and right).
34  *
35  * The slider should have its minimum and maximum values set by the
36  * application with  elm_slider_min_max_set() and value should also be set by
37  * the application before use with  elm_slider_value_set(). The span of the
38  * slider is its length (horizontally or vertically). This will be scaled by
39  * the object or applications scaling factor. At any point code can query the
40  * slider for its value with elm_slider_value_get().
41  */
42
43 typedef struct _Widget_Data Widget_Data;
44
45 struct _Widget_Data
46 {
47    Evas_Object *slider;
48    Evas_Object *icon;
49    Evas_Object *end;
50    Evas_Object *spacer;
51    const char *label;
52    const char *units;
53    const char *indicator;
54    const char *(*indicator_format_func)(double val);
55    Eina_Bool horizontal : 1;
56    Eina_Bool inverted : 1;
57    Eina_Bool indicator_show : 1;
58    int feed_cnt;
59    double val, val_min, val_max;
60    Ecore_Timer *delay;
61    Evas_Coord size;
62 };
63
64 #define ELM_SLIDER_INVERTED_FACTOR (-1.0)
65
66 static const char *widtype = NULL;
67 static void _del_hook(Evas_Object *obj);
68 static void _theme_hook(Evas_Object *obj);
69 static void _disable_hook(Evas_Object *obj);
70 static void _sizing_eval(Evas_Object *obj);
71 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
72 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
73 static void _units_set(Evas_Object *obj);
74 static void _val_set(Evas_Object *obj);
75 static void _indicator_set(Evas_Object *obj);
76 static void _on_focus_hook(void *data, Evas_Object *obj);
77 static void _drag_up(void *data, Evas_Object *obj,
78                     const char *emission, const char *source);
79 static void _drag_down(void *data, Evas_Object *obj,
80                     const char *emission, const char *source);
81 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
82                              Evas_Callback_Type type, void *event_info);
83 static void _spacer_cb(void *data, Evas * e, Evas_Object * obj, void *event_info);
84
85 static const char SIG_CHANGED[] = "changed";
86 static const char SIG_DELAY_CHANGED[] = "delay,changed";
87 static const char SIG_DRAG_START[] = "slider,drag,start";
88 static const char SIG_DRAG_STOP[] = "slider,drag,stop";
89 static const Evas_Smart_Cb_Description _signals[] = {
90   {SIG_CHANGED, ""},
91   {SIG_DELAY_CHANGED, ""},
92   {SIG_DRAG_START, ""},
93   {SIG_DRAG_STOP, ""},
94   {NULL, NULL}
95 };
96
97 static Eina_Bool
98 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
99 {
100    Evas_Event_Mouse_Wheel *mev;
101    Evas_Event_Key_Down *ev;
102    Widget_Data *wd;
103
104    wd = elm_widget_data_get(obj);
105    if (!wd) return EINA_FALSE;
106    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
107
108    if (type == EVAS_CALLBACK_KEY_DOWN) goto key_down;
109    else if (type != EVAS_CALLBACK_MOUSE_WHEEL) return EINA_FALSE;
110
111    mev = event_info;
112    if (mev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
113    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
114
115    if (mev->z < 0) _drag_up(obj, NULL, NULL, NULL);
116    else _drag_down(obj, NULL, NULL, NULL);
117    mev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
118    return EINA_TRUE;
119
120   key_down:
121    ev = event_info;
122    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
123    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
124    if ((!strcmp(ev->keyname, "Left"))
125        || (!strcmp(ev->keyname, "KP_Left")))
126      {
127         if (!wd->horizontal) return EINA_FALSE;
128         if (!wd->inverted) _drag_down(obj, NULL, NULL, NULL);
129         else _drag_up(obj, NULL, NULL, NULL);
130         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
131         return EINA_TRUE;
132      }
133    else if ((!strcmp(ev->keyname, "Right"))
134             || (!strcmp(ev->keyname, "KP_Right")))
135      {
136         if (!wd->horizontal) return EINA_FALSE;
137         if (!wd->inverted) _drag_up(obj, NULL, NULL, NULL);
138         else _drag_down(obj, NULL, NULL, NULL);
139         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
140         return EINA_TRUE;
141      }
142    else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")))
143      {
144         if (wd->horizontal) return EINA_FALSE;
145         if (wd->inverted) _drag_up(obj, NULL, NULL, NULL);
146         else _drag_down(obj, NULL, NULL, NULL);
147         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
148         return EINA_TRUE;
149      }
150    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
151      {
152         if (wd->horizontal) return EINA_FALSE;
153         if (wd->inverted) _drag_down(obj, NULL, NULL, NULL);
154         else _drag_up(obj, NULL, NULL, NULL);
155         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
156         return EINA_TRUE;
157      }
158    else return EINA_FALSE;
159 }
160
161 static void
162 _del_hook(Evas_Object *obj)
163 {
164    Widget_Data *wd = elm_widget_data_get(obj);
165    if (!wd) return;
166    if (wd->label) eina_stringshare_del(wd->label);
167    if (wd->indicator) eina_stringshare_del(wd->units);
168    if (wd->delay) ecore_timer_del(wd->delay);
169    free(wd);
170 }
171
172 static void
173 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
174 {
175    Widget_Data *wd = elm_widget_data_get(obj);
176    if (!wd) return;
177    if (elm_widget_focus_get(obj))
178      {
179         edje_object_signal_emit(wd->slider, "elm,action,focus", "elm");
180         evas_object_focus_set(wd->slider, EINA_TRUE);
181      }
182    else
183      {
184         edje_object_signal_emit(wd->slider, "elm,action,unfocus", "elm");
185         evas_object_focus_set(wd->slider, EINA_FALSE);
186      }
187 }
188
189 static void
190 _theme_hook(Evas_Object *obj)
191 {
192    Widget_Data *wd = elm_widget_data_get(obj);
193    if (!wd) return;
194    if (wd->horizontal)
195      _elm_theme_object_set(obj, wd->slider, "slider", "horizontal", elm_widget_style_get(obj));
196    else
197      _elm_theme_object_set(obj, wd->slider, "slider", "vertical", elm_widget_style_get(obj));
198    if (elm_widget_disabled_get(obj))
199      edje_object_signal_emit(wd->slider, "elm,state,disabled", "elm");
200    else
201      edje_object_signal_emit(wd->slider, "elm,state,enabled", "elm");
202    if (wd->icon)
203      {
204         edje_object_part_swallow(wd->slider, "elm.swallow.content", wd->icon);
205         edje_object_signal_emit(wd->slider, "elm,state,icon,visible", "elm");
206      }
207    if (wd->end)
208      edje_object_signal_emit(wd->slider, "elm,state,end,visible", "elm");
209    else
210      edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
211    if (wd->label)
212      {
213         edje_object_part_text_set(wd->slider, "elm.text", wd->label);
214         edje_object_signal_emit(wd->slider, "elm,state,text,visible", "elm");
215      }
216    
217    if (wd->units)
218      edje_object_signal_emit(wd->slider, "elm,state,units,visible", "elm");
219    
220    if (wd->horizontal)
221      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
222    else
223      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
224    
225    if (wd->inverted)
226       edje_object_signal_emit(wd->slider, "elm,state,inverted,on", "elm");
227    
228    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
229    _units_set(obj);
230    _indicator_set(obj);
231    edje_object_message_signal_process(wd->slider);
232    edje_object_scale_set(wd->slider, elm_widget_scale_get(obj) * _elm_config->scale);
233    _val_set(obj);
234    _sizing_eval(obj);
235 }
236
237 static void
238 _disable_hook(Evas_Object *obj)
239 {
240    Widget_Data *wd = elm_widget_data_get(obj);
241    if (!wd) return;
242    if (elm_widget_disabled_get(obj))
243       edje_object_signal_emit(wd->slider, "elm,state,disabled", "elm");
244    else
245       edje_object_signal_emit(wd->slider, "elm,state,enabled", "elm");
246 }
247
248 static void
249 _sizing_eval(Evas_Object *obj)
250 {   
251    Widget_Data *wd = elm_widget_data_get(obj);
252    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
253    if (!wd) return;
254    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
255    edje_object_size_min_restricted_calc(wd->slider, &minw, &minh, minw, minh);
256    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
257    evas_object_size_hint_min_set(obj, minw, minh);
258    evas_object_size_hint_max_set(obj, maxw, maxh);
259 }
260
261 static void
262 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
263 {
264    Widget_Data *wd = elm_widget_data_get(data);
265    if (!wd) return;
266    if ((obj != wd->icon) && (obj != wd->end)) return;
267    _sizing_eval(data);
268 }
269
270 static void
271 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
272 {
273    Widget_Data *wd = elm_widget_data_get(obj);
274    Evas_Object *sub = event_info;
275    if (!wd) return;
276    if (sub == wd->icon)
277      {
278         edje_object_signal_emit(wd->slider, "elm,state,icon,hidden", "elm");
279         evas_object_event_callback_del_full (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints, obj);
280         wd->icon = NULL;
281         edje_object_message_signal_process(wd->slider);
282         _sizing_eval(obj);
283      }
284    if (sub == wd->end)
285      {
286         edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
287         evas_object_event_callback_del_full(sub,
288                                             EVAS_CALLBACK_CHANGED_SIZE_HINTS,
289                                             _changed_size_hints, obj);
290         wd->end = NULL;
291         edje_object_message_signal_process(wd->slider);
292         _sizing_eval(obj);
293      }
294 }
295
296 static Eina_Bool
297 _delay_change(void *data)
298 {
299    Widget_Data *wd = elm_widget_data_get(data);
300    if (!wd) return ECORE_CALLBACK_CANCEL;
301    wd->delay = NULL;
302    evas_object_smart_callback_call(data, SIG_DELAY_CHANGED, NULL);
303    return ECORE_CALLBACK_CANCEL;
304 }
305
306 static void
307 _val_fetch(Evas_Object *obj)
308 {
309    Widget_Data *wd = elm_widget_data_get(obj);
310    double posx = 0.0, posy = 0.0, pos = 0.0, val;
311    if (!wd) return;
312    edje_object_part_drag_value_get(wd->slider, "elm.dragable.slider",&posx, &posy);
313    if (wd->horizontal) pos = posx;
314    else pos = posy;
315    if (wd->inverted) pos = 1.0 - pos;
316    val = (pos * (wd->val_max - wd->val_min)) + wd->val_min;
317    if (val != wd->val)
318      {
319         wd->val = val;
320         evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
321         if (wd->delay) ecore_timer_del(wd->delay);
322         wd->delay = ecore_timer_add(0.2, _delay_change, obj);
323      }
324 }
325
326 static void
327 _val_set(Evas_Object *obj)
328 {
329    Widget_Data *wd = elm_widget_data_get(obj);
330    double pos;
331    if (!wd) return;
332    if (wd->val_max > wd->val_min)
333      pos = (wd->val - wd->val_min) / (wd->val_max - wd->val_min);
334    else
335      pos = 0.0;
336    if (pos < 0.0) pos = 0.0;
337    else if (pos > 1.0) pos = 1.0;
338    if (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)
348      {
349         char buf[1024];
350
351         snprintf(buf, sizeof(buf), wd->units, wd->val);
352         edje_object_part_text_set(wd->slider, "elm.units", buf);
353      }
354    else
355      edje_object_part_text_set(wd->slider, "elm.units", NULL);
356 }
357
358 static void
359 _indicator_set(Evas_Object *obj)
360 {
361    Widget_Data *wd = elm_widget_data_get(obj);
362    if (!wd) return;
363    if (wd->indicator_format_func)
364      {
365         const char *buf;
366         buf = wd->indicator_format_func(wd->val);
367         edje_object_part_text_set(wd->slider, "elm.indicator", buf);
368      }
369    else if (wd->indicator)
370      {
371         char buf[1024];
372         snprintf(buf, sizeof(buf), wd->indicator, wd->val);
373         edje_object_part_text_set(wd->slider, "elm.indicator", buf);
374      }
375    else
376      edje_object_part_text_set(wd->slider, "elm.indicator", NULL);
377 }
378
379 static void
380 _drag(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
381 {
382    Widget_Data *wd = elm_widget_data_get((Evas_Object*)data);
383    if (elm_widget_disabled_get(data)) return;
384    edje_object_signal_emit(wd->slider, "elm,state,drag", "elm");
385    edje_object_message_signal_process(wd->slider);
386    _val_fetch(data);
387    _units_set(data);
388    _indicator_set(data);
389 }
390
391 static void
392 _drag_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
393 {
394    Widget_Data *wd = elm_widget_data_get((Evas_Object*)data);
395    if (elm_widget_disabled_get(data)) return;
396    _val_fetch(data);
397    evas_object_smart_callback_call(data, SIG_DRAG_START, NULL);
398    edje_object_signal_emit(wd->slider, "elm,state,drag", "elm");
399    edje_object_message_signal_process(wd->slider); 
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    if (elm_widget_disabled_get(data)) return;
409    _val_fetch(data);
410    evas_object_smart_callback_call(data, SIG_DRAG_STOP, NULL);
411    _units_set(data);
412    _indicator_set(data);
413    elm_widget_scroll_freeze_pop(data);
414 }
415
416 static void
417 _drag_step(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
418 {
419    if (elm_widget_disabled_get(data)) return;
420    _val_fetch(data);
421    _units_set(data);
422    _indicator_set(data);
423 }
424
425 static void
426 _drag_up(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
427 {
428    double step;
429    Widget_Data *wd;
430    if (elm_widget_disabled_get(data)) return;
431
432    wd = elm_widget_data_get(data);
433    step = 0.05;
434
435    if (wd->inverted) step *= ELM_SLIDER_INVERTED_FACTOR;
436
437    edje_object_part_drag_step(wd->slider, "elm.dragable.slider", step, step);
438 }
439
440 static void
441 _drag_down(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
442 {
443    double step;
444    Widget_Data *wd;
445    if (elm_widget_disabled_get(data)) return;
446
447    wd = elm_widget_data_get(data);
448    step = -0.05;
449
450    if (wd->inverted) step *= ELM_SLIDER_INVERTED_FACTOR;
451
452    edje_object_part_drag_step(wd->slider, "elm.dragable.slider", step, step);
453 }
454
455 static void
456 _spacer_cb(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
457 {
458    Widget_Data *wd = elm_widget_data_get(data);
459    Evas_Event_Mouse_Down *ev = event_info;
460    Evas_Coord x, y, w, h;
461    double button_x, button_y;   
462    if (elm_widget_disabled_get(data)) return;
463
464    evas_object_geometry_get(wd->spacer, &x, &y, &w, &h);
465    edje_object_part_drag_value_get(wd->slider, "elm.dragable.slider", &button_x, &button_y);
466    if (wd->horizontal)
467      {
468         button_x = ((double)ev->output.x - (double)x) / (double)w;
469         if (button_x > 1) button_x = 1;
470         if (button_x < 0) button_x = 0;
471      }
472    else 
473      {
474         button_y = ((double)ev->output.y - (double)y) / (double)h;
475         if (button_y > 1) button_y = 1;
476         if (button_y < 0) button_y = 0;
477      }
478    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", button_x, button_y);
479    evas_event_feed_mouse_cancel(e, 0, NULL);
480    wd->feed_cnt ++;
481    if(wd->feed_cnt < 3)
482      evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, 0, NULL);  
483    wd->feed_cnt = 0;
484 }
485
486 /**
487  * Add a new slider to the parent
488  *
489  * @param parent The parent object
490  * @return The new object or NULL if it cannot be created
491  *
492  * @ingroup Slider
493  */
494 EAPI Evas_Object *
495 elm_slider_add(Evas_Object *parent)
496 {
497    Evas_Object *obj;
498    Evas *e;
499    Widget_Data *wd;
500
501    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
502
503    wd = ELM_NEW(Widget_Data);
504    e = evas_object_evas_get(parent);
505    if (!e) return NULL;
506    obj = elm_widget_add(e);
507    ELM_SET_WIDTYPE(widtype, "slider");
508    elm_widget_type_set(obj, "slider");
509    elm_widget_sub_object_add(parent, obj);
510    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
511    elm_widget_data_set(obj, wd);
512    elm_widget_del_hook_set(obj, _del_hook);
513    elm_widget_theme_hook_set(obj, _theme_hook);
514    elm_widget_disable_hook_set(obj, _disable_hook);
515    elm_widget_can_focus_set(obj, EINA_TRUE);
516    elm_widget_event_hook_set(obj, _event_hook);
517
518    wd->horizontal = EINA_TRUE;
519    wd->indicator_show = EINA_TRUE;
520    wd->feed_cnt = 0;
521    wd->val = 0.0;
522    wd->val_min = 0.0;
523    wd->val_max = 1.0;
524
525    wd->slider = edje_object_add(e);
526    _elm_theme_object_set(obj, wd->slider, "slider", "horizontal", "default");
527    elm_widget_resize_object_set(obj, wd->slider);
528    edje_object_signal_callback_add(wd->slider, "drag", "*", _drag, obj);
529    edje_object_signal_callback_add(wd->slider, "drag,start", "*", _drag_start, obj);
530    edje_object_signal_callback_add(wd->slider, "drag,stop", "*", _drag_stop, obj);
531    edje_object_signal_callback_add(wd->slider, "drag,step", "*", _drag_step, obj);
532    edje_object_signal_callback_add(wd->slider, "drag,page", "*", _drag_stop, obj);
533 //   edje_object_signal_callback_add(wd->slider, "drag,set", "*", _drag_stop, obj);
534    edje_object_part_drag_value_set(wd->slider, "elm.dragable.slider", 0.0, 0.0);
535
536    wd->spacer = evas_object_rectangle_add(e);
537    evas_object_color_set(wd->spacer, 0, 0, 0, 0);
538    evas_object_pass_events_set(wd->spacer, EINA_TRUE);
539    elm_widget_sub_object_add(obj, wd->spacer);
540    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
541    evas_object_event_callback_add(wd->spacer, EVAS_CALLBACK_MOUSE_DOWN, _spacer_cb, obj);
542    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
543
544    _sizing_eval(obj);
545
546    // TODO: convert Elementary to subclassing of Evas_Smart_Class
547    // TODO: and save some bytes, making descriptions per-class and not instance!
548    evas_object_smart_callbacks_descriptions_set(obj, _signals);
549    return obj;
550 }
551
552 /**
553  * Set the label of the slider
554  *
555  * @param obj The slider object
556  * @param label The text label string in UTF-8
557  *
558  * @ingroup Slider
559  */
560 EAPI void
561 elm_slider_label_set(Evas_Object *obj, const char *label)
562 {
563    ELM_CHECK_WIDTYPE(obj, widtype);
564    Widget_Data *wd = elm_widget_data_get(obj);
565    if (!wd) return;
566    eina_stringshare_replace(&wd->label, label);
567    if (label)
568      {
569         edje_object_signal_emit(wd->slider, "elm,state,text,visible", "elm");
570         edje_object_message_signal_process(wd->slider);
571      }
572    else
573      {
574         edje_object_signal_emit(wd->slider, "elm,state,text,hidden", "elm");
575         edje_object_message_signal_process(wd->slider);
576      }
577    edje_object_part_text_set(wd->slider, "elm.text", label);
578    _sizing_eval(obj);
579 }
580
581 /**
582  * Get the label of the slider
583  *
584  * @param obj The slider object
585  * @return The text label string in UTF-8
586  *
587  * @ingroup Slider
588  */
589 EAPI const char *
590 elm_slider_label_get(const Evas_Object *obj)
591 {
592    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
593    Widget_Data *wd = elm_widget_data_get(obj);
594    if (!wd) return NULL;
595    return wd->label;
596 }
597
598 /**
599  * Set the icon object (leftmost widget) of the slider object.
600  *
601  * Once the icon object is set, a previously set one will be deleted.
602  * If you want to keep that old content object, use the
603  * elm_slider_icon_unset() function.
604  *
605  * @param obj The slider object
606  * @param icon The icon object
607  *
608  * @note If the object being set does not have minimum size hints set,
609  * it won't get properly displayed.
610  *
611  * @ingroup Slider
612  */
613 EAPI void
614 elm_slider_icon_set(Evas_Object *obj, Evas_Object *icon)
615 {
616    ELM_CHECK_WIDTYPE(obj, widtype);
617    Widget_Data *wd = elm_widget_data_get(obj);
618    if (!wd) return;
619    if (wd->icon == icon) return;
620    if (wd->icon) evas_object_del(wd->icon);
621    wd->icon = icon;
622    if (icon)
623      {
624         elm_widget_sub_object_add(obj, icon);
625         evas_object_event_callback_add(icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
626                                        _changed_size_hints, obj);
627         edje_object_part_swallow(wd->slider, "elm.swallow.icon", icon);
628         edje_object_signal_emit(wd->slider, "elm,state,icon,visible", "elm");
629         edje_object_message_signal_process(wd->slider);
630      }
631    _sizing_eval(obj);
632 }
633
634 /**
635  * Unset the leftmost widget of the slider, unparenting and
636  * returning it.
637  *
638  * @param obj The slider object
639  * @return the previously set icon sub-object of this slider, on
640  * success.
641  *
642  * @see elm_slider_icon_set()
643  *
644  * @ingroup Slider
645  */
646 EAPI Evas_Object *
647 elm_slider_icon_unset(Evas_Object *obj)
648 {
649    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
650    Widget_Data *wd = elm_widget_data_get(obj);
651    Evas_Object *ret = NULL;
652    if (!wd) return NULL;
653    if (wd->icon)
654      {
655         elm_widget_sub_object_del(obj, wd->icon);
656         ret = wd->icon;
657         edje_object_part_unswallow(wd->slider, wd->icon);
658         edje_object_signal_emit(wd->slider, "elm,state,icon,hidden", "elm");
659         wd->icon = NULL;
660         _sizing_eval(obj);
661      }
662    return ret;
663 }
664
665 /**
666  * Get the icon object of the slider object. This object is owned by
667  * the scrolled entry and should not be modified.
668  *
669  * @param obj The slider object
670  * @return The icon object
671  *
672  * @ingroup Slider
673  */
674 EAPI Evas_Object *
675 elm_slider_icon_get(const Evas_Object *obj)
676 {
677    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
678    Widget_Data *wd = elm_widget_data_get(obj);
679    if (!wd) return NULL;
680    return wd->icon;
681 }
682
683 /**
684  * Set the length of the dragable region of the slider
685  *
686  * This sets the minimum width or height (depending on orientation) of the
687  * area of the slider that allows the slider to be dragged around. This in
688  * turn affects the objects minimum size (along with icon label and unit
689  * text). Note that this will also get multiplied by the scale factor.
690  *
691  * @param obj The slider object
692  * @param size The length of the slider area
693  *
694  * @ingroup Slider
695  */
696 EAPI void
697 elm_slider_span_size_set(Evas_Object *obj, Evas_Coord size)
698 {
699    ELM_CHECK_WIDTYPE(obj, widtype);
700    Widget_Data *wd = elm_widget_data_get(obj);
701    if (!wd) return;
702    if (wd->size == size) return;
703    wd->size = size;
704    if (wd->horizontal)
705      evas_object_size_hint_min_set(wd->spacer, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale, 1);
706    else
707      evas_object_size_hint_min_set(wd->spacer, 1, (double)wd->size * elm_widget_scale_get(obj) * _elm_config->scale);
708    if (wd->indicator_show)
709        edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
710    else
711        edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
712    edje_object_part_swallow(wd->slider, "elm.swallow.bar", wd->spacer);
713    _sizing_eval(obj);
714 }
715
716 /**
717  * Get the length of the dragable region of the slider
718  *
719  * This gets the minimum width or height (depending on orientation) of
720  * the area of the slider that allows the slider to be dragged
721  * around. Note that this will also get multiplied by the scale
722  * factor.
723  *
724  * @param obj The slider object
725  * @return The length of the slider area
726  *
727  * @ingroup Slider
728  */
729 EAPI Evas_Coord
730 elm_slider_span_size_get(const Evas_Object *obj)
731 {
732    ELM_CHECK_WIDTYPE(obj, widtype) 0;
733    Widget_Data *wd = elm_widget_data_get(obj);
734    if (!wd) return 0;
735    return wd->size;
736 }
737
738 /**
739  * Set the format string of the unit area
740  *
741  * If NULL, this disabls the unit area display. If not it sets the format
742  * string for the unit text. The unit text is provided a floating point
743  * value, so the unit text can display up to 1 floating point value. Note that
744  * this is optional. Use a format string such as "%1.2f meters" for example.
745  *
746  * @param obj The slider object
747  * @param units The format string for the units display
748  *
749  * @ingroup Slider
750  */
751 EAPI void
752 elm_slider_unit_format_set(Evas_Object *obj, const char *units)
753 {
754    ELM_CHECK_WIDTYPE(obj, widtype);
755    Widget_Data *wd = elm_widget_data_get(obj);
756    if (!wd) return;
757    eina_stringshare_replace(&wd->units, units);
758    if (units)
759      {
760         edje_object_signal_emit(wd->slider, "elm,state,units,visible", "elm");
761         edje_object_message_signal_process(wd->slider);
762      }
763    else
764      {
765         edje_object_signal_emit(wd->slider, "elm,state,units,hidden", "elm");
766         edje_object_message_signal_process(wd->slider);
767      }
768    _units_set(obj);
769    _sizing_eval(obj);
770 }
771
772 /**
773  * Get the format string for the unit area
774  *
775  * The slider may also display a value (the value of the slider) somewhere
776  * (for example above the slider knob that is dragged around). This sets the
777  * format string for this. See elm_slider_unit_format_set() for more
778  * information on how this works.
779  *
780  * @param obj The slider object
781  * @return The format string for the unit display.
782  *
783  * @ingroup Slider
784  */
785 EAPI const char *
786 elm_slider_unit_format_get(const Evas_Object *obj)
787 {
788    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
789    Widget_Data *wd = elm_widget_data_get(obj);
790    if (!wd) return NULL;
791    return wd->units;
792 }
793
794 /**
795  * Set the format string for the indicator area
796  *
797  * The slider may also display a value (the value of the slider) somewhere
798  * (for example above the slider knob that is dragged around). This sets the
799  * format string for this. See elm_slider_unit_format_set() for more
800  * information on how this works.
801  *
802  * @param obj The slider object
803  * @param indicator The format string for the indicator display
804  *
805  * @ingroup Slider
806  */
807 EAPI void
808 elm_slider_indicator_format_set(Evas_Object *obj, const char *indicator)
809 {
810    ELM_CHECK_WIDTYPE(obj, widtype);
811    Widget_Data *wd = elm_widget_data_get(obj);
812    if (!wd) return;
813    eina_stringshare_replace(&wd->indicator, indicator);
814    _indicator_set(obj);
815 }
816
817 /**
818  * Get the format string for the indicator area
819  *
820  * The slider may also display a value (the value of the slider) somewhere
821  * (for example above the slider knob that is dragged around). This sets the
822  * format string for this. See elm_slider_indicator_format_set() for more
823  * information on how this works.
824  *
825  * @param obj The slider object
826  * @return The format string for the indicator display.
827  *
828  * @ingroup Slider
829  */
830 EAPI const char *
831 elm_slider_indicator_format_get(const Evas_Object *obj)
832 {
833    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
834    Widget_Data *wd = elm_widget_data_get(obj);
835    if (!wd) return NULL;
836    return wd->indicator;
837 }
838
839 /**
840  * Set orientation of the slider
841  *
842  * @param obj The slider object
843  * @param horizontal If set, the slider will be horizontal
844  *
845  * @ingroup Slider
846  */
847 EAPI void
848 elm_slider_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
849 {
850    ELM_CHECK_WIDTYPE(obj, widtype);
851    Widget_Data *wd = elm_widget_data_get(obj);
852    if (!wd) return;
853    horizontal = !!horizontal;
854    if (wd->horizontal == horizontal) return;
855    wd->horizontal = horizontal;
856    _theme_hook(obj);
857 }
858
859 /**
860  * Get orientation of the slider
861  *
862  * @param obj The slider object
863  * @return If @c EINA_TRUE the slider will be horizontal, else it is
864  *         vertical.
865  * @ingroup Slider
866  */
867 EAPI Eina_Bool
868 elm_slider_horizontal_get(const Evas_Object *obj)
869 {
870    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
871    Widget_Data *wd = elm_widget_data_get(obj);
872    if (!wd) return EINA_FALSE;
873    return wd->horizontal;
874 }
875
876 /**
877  * Set the minimum and maximum values for the slider
878  *
879  * Maximum mut be greater than minimum.
880  *
881  * @param obj The slider object
882  * @param min The minimum value
883  * @param max The maximum value
884  *
885  * @ingroup Slider
886  */
887 EAPI void
888 elm_slider_min_max_set(Evas_Object *obj, double min, double max)
889 {
890    ELM_CHECK_WIDTYPE(obj, widtype);
891    Widget_Data *wd = elm_widget_data_get(obj);
892    if (!wd) return;
893    if ((wd->val_min == min) && (wd->val_max == max)) return;
894    wd->val_min = min;
895    wd->val_max = max;
896    if (wd->val < wd->val_min) wd->val = wd->val_min;
897    if (wd->val > wd->val_max) wd->val = wd->val_max;
898    _val_set(obj);
899    _units_set(obj);
900    _indicator_set(obj);
901 }
902
903 /**
904  * Get the minimum and maximum values for the slider
905  *
906  * @param obj The slider object
907  * @param min The pointer to store minimum value, may be @c NULL.
908  * @param max The pointer to store maximum value, may be @c NULL.
909  *
910  * @ingroup Slider
911  */
912 EAPI void
913 elm_slider_min_max_get(const Evas_Object *obj, double *min, double *max)
914 {
915    if (min) *min = 0.0;
916    if (max) *max = 0.0;
917    ELM_CHECK_WIDTYPE(obj, widtype);
918    Widget_Data *wd = elm_widget_data_get(obj);
919    if (!wd) return;
920    if (min) *min = wd->val_min;
921    if (max) *max = wd->val_max;
922 }
923
924 /**
925  * Set the value the slider indicates
926  *
927  * @param obj The slider object
928  * @param val The value (must be between min and max for the slider)
929  *
930  * @ingroup Slider
931  */
932 EAPI void
933 elm_slider_value_set(Evas_Object *obj, double val)
934 {
935    ELM_CHECK_WIDTYPE(obj, widtype);
936    Widget_Data *wd = elm_widget_data_get(obj);
937    if (!wd) return;
938    if (wd->val == val) return;
939    wd->val = val;
940    if (wd->val < wd->val_min) wd->val = wd->val_min;
941    if (wd->val > wd->val_max) wd->val = wd->val_max;
942    edje_object_signal_emit(wd->slider, "elm,state,drag", "elm");
943    _val_set(obj);
944    _units_set(obj);
945    _indicator_set(obj);
946 }
947
948 /**
949  * Get the value the slider has
950  *
951  * @param obj The slider object
952  * @return The value of the slider
953  *
954  * @ingroup Slider
955  */
956 EAPI double
957 elm_slider_value_get(const Evas_Object *obj)
958 {
959    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
960    Widget_Data *wd = elm_widget_data_get(obj);
961    if (!wd) return 0.0;
962    return wd->val;
963 }
964
965 /**
966  * Invert the slider display
967  *
968  * Normally the slider will display and interpret values from low to high
969  * and when horizontal that is left to right. When vertical that is top
970  * to bottom. This inverts this (so from right to left or bottom to top) if
971  * inverted is set to 1.
972  *
973  * @param obj The slider object
974  * @param inverted The inverted flag. 1 == inverted, 0 == normal
975  *
976  * @ingroup Slider
977  */
978 EAPI void
979 elm_slider_inverted_set(Evas_Object *obj, Eina_Bool inverted)
980 {
981    ELM_CHECK_WIDTYPE(obj, widtype);
982    Widget_Data *wd = elm_widget_data_get(obj);
983    if (!wd) return;
984    inverted = !!inverted;
985    if (wd->inverted == inverted) return;
986    wd->inverted = inverted;
987    if (wd->inverted)
988      edje_object_signal_emit(wd->slider, "elm,state,inverted,on", "elm");
989    else
990      edje_object_signal_emit(wd->slider, "elm,state,inverted,off", "elm");
991    edje_object_message_signal_process(wd->slider);
992    _val_set(obj);
993    _units_set(obj);
994    _indicator_set(obj);
995 }
996
997 /**
998  * Get if the slider display is inverted (backwards)
999  *
1000  * @param obj The slider object
1001  * @return If @c EINA_TRUE the slider will be inverted.
1002  * @ingroup Slider
1003  */
1004 EAPI Eina_Bool
1005 elm_slider_inverted_get(const Evas_Object *obj)
1006 {
1007    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1008    Widget_Data *wd = elm_widget_data_get(obj);
1009    if (!wd) return EINA_FALSE;
1010    return wd->inverted;
1011 }
1012
1013 /**
1014  * Set the format function pointer for the inducator area
1015  *
1016  * Set the callback function to format the indicator string.
1017  * See elm_slider_indicator_format_set() for more info on how this works.
1018  *
1019  * @param obj The slider object
1020  * @param indicator The format string for the indicator display
1021  * @param func The indicator format function
1022  *
1023  * @ingroup Slider
1024  */
1025 EAPI void
1026 elm_slider_indicator_format_function_set(Evas_Object *obj, const char *(*func)(double val))
1027 {
1028    ELM_CHECK_WIDTYPE(obj, widtype);
1029    Widget_Data *wd = elm_widget_data_get(obj);
1030    if (!wd) return;
1031    wd->indicator_format_func = func;
1032    _indicator_set(obj);
1033 }
1034
1035 /**
1036  * Set the end object (rightmost widget) of the slider object.
1037  *
1038  * Once the end object is set, a previously set one will be deleted.
1039  * If you want to keep that old content object, use the
1040  * elm_button_end_unset() function.
1041  *
1042  * @param obj The slider object
1043  * @param end The end object
1044  *
1045  * @note If the object being set does not have minimum size hints set,
1046  * it won't get properly displayed.
1047  *
1048  * @ingroup Slider
1049  */
1050 EAPI void
1051 elm_slider_end_set(Evas_Object *obj, Evas_Object *end)
1052 {
1053    ELM_CHECK_WIDTYPE(obj, widtype);
1054    Widget_Data *wd = elm_widget_data_get(obj);
1055    if (!wd) return;
1056    if (wd->end == end) return;
1057    if (wd->end) evas_object_del(wd->end);
1058    wd->end = end;
1059    if (end)
1060      {
1061         elm_widget_sub_object_add(obj, end);
1062         evas_object_event_callback_add(end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1063                                        _changed_size_hints, obj);
1064         edje_object_part_swallow(wd->slider, "elm.swallow.end", end);
1065         edje_object_signal_emit(wd->slider, "elm,state,end,visible", "elm");
1066         edje_object_message_signal_process(wd->slider);
1067      }
1068    _sizing_eval(obj);
1069 }
1070
1071 /**
1072  * Unset the rightmost widget of the slider, unparenting and
1073  * returning it.
1074  *
1075  * @param obj The slider object
1076  * @return the previously set end sub-object of this slider, on
1077  * success.
1078  *
1079  * @see elm_slider_end_set()
1080  *
1081  * @ingroup Slider
1082  */
1083 EAPI Evas_Object *
1084 elm_slider_end_unset(Evas_Object *obj)
1085 {
1086    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1087    Widget_Data *wd = elm_widget_data_get(obj);
1088    Evas_Object *ret = NULL;
1089    if (!wd) return NULL;
1090    if (wd->end)
1091      {
1092         elm_widget_sub_object_del(obj, wd->end);
1093         ret = wd->end;
1094         edje_object_part_unswallow(wd->slider, wd->end);
1095         edje_object_signal_emit(wd->slider, "elm,state,end,hidden", "elm");
1096         wd->end = NULL;
1097         _sizing_eval(obj);
1098      }
1099    return ret;
1100 }
1101
1102 /**
1103  * Get the end icon object of the slider object. This object is owned
1104  * by the scrolled entry and should not be modified.
1105  *
1106  * @param obj The slider object
1107  * @return The end icon object
1108  *
1109  * @ingroup Slider
1110  */
1111 EAPI Evas_Object *
1112 elm_slider_end_get(const Evas_Object *obj)
1113 {
1114    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1115    Widget_Data *wd = elm_widget_data_get(obj);
1116    if (!wd) return NULL;
1117    return wd->end;
1118 }
1119
1120 /**
1121  * Set whether to the slider indicator (augmented knob) at all.
1122  *
1123  * @param obj The slider object
1124  * @param show @c EINA_TRUE will make it show it, @c EINA_FALSE will
1125  * let the knob alwayes at default size.
1126  *
1127  * @note It will conflict with elm_slider_indicator_format_set(), if
1128  * you wanted those effects.
1129  *
1130  * @ingroup Slider
1131  */
1132 EAPI void
1133 elm_slider_indicator_show_set(Evas_Object *obj, Eina_Bool show)
1134 {
1135    ELM_CHECK_WIDTYPE(obj, widtype);
1136    Widget_Data *wd = elm_widget_data_get(obj);
1137    if (show) {
1138       wd->indicator_show = EINA_TRUE;
1139       edje_object_signal_emit(wd->slider, "elm,state,val,show", "elm");
1140    }
1141    else {
1142       wd->indicator_show = EINA_FALSE;
1143       edje_object_signal_emit(wd->slider, "elm,state,val,hide", "elm");
1144    }
1145 }
1146
1147 /**
1148  * Get the state of indicator in the slider (if it's being shown or
1149  * not).
1150  *
1151  * @param obj The slider object
1152  * @return @c EINA_TRUE if the indicator is being shown, @c EINA_FALSE
1153  * otherwise.
1154  *
1155  *  @ingroup Slider
1156  */
1157 EAPI Eina_Bool
1158 elm_slider_indicator_show_get(const Evas_Object *obj)
1159 {
1160    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1161    Widget_Data *wd = elm_widget_data_get(obj);
1162    if (!wd) return EINA_FALSE;
1163    return wd->indicator_show;
1164 }