Elementary / genlist, slider, radio, win toolbar, thumb, toggle, scroller, slideshow...
[framework/uifw/elementary.git] / src / lib / elm_scroller.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Scroller Scroller
6  *
7  * A scroller holds a single object and "scrolls it around". This means that
8  * it allows the user to use a scrollbar (or a finger) to drag the viewable
9  * region around, allowing to move through a much larger object that is
10  * contained in the scroller. The scroiller will always have a small minimum
11  * size by default as it won't be limited by the contents of the scroller.
12  *
13  * Signals that you can add callbacks for are:
14  *
15  * "edge,left" - the left edge of the content has been reached
16  * "edge,right" - the right edge of the content has been reached
17  * "edge,top" - the top edge of the content has been reached
18  * "edge,bottom" - the bottom edge of the content has been reached
19  * "scroll" - the content has been scrolled (moved)
20  * "scroll,anim,start" - scrolling animation has started
21  * "scroll,anim,stop" - scrolling animation has stopped
22  * "scroll,drag,start" - dragging the contents around has started
23  * "scroll,drag,stop" - dragging the contents around has stopped
24  */
25 typedef struct _Widget_Data Widget_Data;
26
27 struct _Widget_Data
28 {
29    Evas_Object *scr;
30    Evas_Object *content;
31    const char *widget_name, *widget_base;
32    Eina_Bool min_w : 1;
33    Eina_Bool min_h : 1;
34    double pagerel_h, pagerel_v;
35    Evas_Coord pagesize_h, pagesize_v;
36 };
37
38 static const char *widtype = NULL;
39 static void _del_hook(Evas_Object *obj);
40 static void _theme_hook(Evas_Object *obj);
41 static void _show_region_hook(void *data, Evas_Object *obj);
42 static void _sizing_eval(Evas_Object *obj);
43 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
44 static void _on_focus_hook(void *data, Evas_Object *obj);
45 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
46                              Evas_Callback_Type type, void *event_info);
47
48
49 static const char SIG_SCROLL[] = "scroll";
50 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
51 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
52 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
53 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
54 static const char SIG_EDGE_LEFT[] = "edge,left";
55 static const char SIG_EDGE_RIGHT[] = "edge,right";
56 static const char SIG_EDGE_TOP[] = "edge,top";
57 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
58 static const Evas_Smart_Cb_Description _signals[] = {
59   {SIG_SCROLL, ""},
60   {SIG_SCROLL_ANIM_START, ""},
61   {SIG_SCROLL_ANIM_STOP, ""},
62   {SIG_SCROLL_DRAG_START, ""},
63   {SIG_SCROLL_DRAG_STOP, ""},
64   {SIG_EDGE_LEFT, ""},
65   {SIG_EDGE_RIGHT, ""},
66   {SIG_EDGE_TOP, ""},
67   {SIG_EDGE_BOTTOM, ""},
68   {NULL, NULL}
69 };
70
71 static Eina_Bool
72 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
73 {
74    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
75    Evas_Event_Key_Down *ev = event_info;
76    Widget_Data *wd = elm_widget_data_get(obj);
77    if (!wd) return EINA_FALSE;
78    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
79    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
80
81    Evas_Coord x = 0;
82    Evas_Coord y = 0;
83    Evas_Coord step_x = 0;
84    Evas_Coord step_y = 0;
85    Evas_Coord max_x = 0;
86    Evas_Coord max_y = 0;
87    Evas_Coord v_w = 0;
88    Evas_Coord v_h = 0;
89    Evas_Coord page_x = 0;
90    Evas_Coord page_y = 0;
91
92    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
93    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
94    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
95    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
96    elm_scroller_child_size_get(obj, &max_x, &max_y);
97
98    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
99      {
100         x -= step_x;
101      }
102    else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
103      {
104         x += step_x;
105      }
106    else if ((!strcmp(ev->keyname, "Up"))  || (!strcmp(ev->keyname, "KP_Up")))
107      {
108         y -= step_y;
109      }
110    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
111      {
112         y += step_y;
113      }
114    else if ((!strcmp(ev->keyname, "Home")) || (!strcmp(ev->keyname, "KP_Home")))
115      {
116         y = 0;
117      }
118    else if ((!strcmp(ev->keyname, "End")) || (!strcmp(ev->keyname, "KP_End")))
119      {
120         y = max_y - v_h;
121      }
122    else if ((!strcmp(ev->keyname, "Prior")) || (!strcmp(ev->keyname, "KP_Prior")))
123      {
124         if (page_y < 0)
125           y -= -(page_y * v_h) / 100;
126         else
127           y -= page_y;
128      }
129    else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next")))
130      {
131         if (page_y < 0)
132           y += -(page_y * v_h) / 100;
133         else
134           y += page_y;
135      }
136    else return EINA_FALSE;
137
138    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
139    elm_smart_scroller_child_pos_set(wd->scr, x, y);
140    return EINA_TRUE;
141 }
142
143 static void
144 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
145 {
146    Widget_Data *wd = elm_widget_data_get(obj);
147    if (!wd) return;
148    if (elm_widget_focus_get(obj))
149      {
150         edje_object_signal_emit(wd->scr, "elm,action,focus", "elm");
151         evas_object_focus_set(wd->scr, EINA_TRUE);
152      }
153    else
154      {
155         edje_object_signal_emit(wd->scr, "elm,action,unfocus", "elm");
156         evas_object_focus_set(wd->scr, EINA_FALSE);
157      }
158 }
159
160 static void
161 _del_hook(Evas_Object *obj)
162 {
163    Widget_Data *wd = elm_widget_data_get(obj);
164    if (!wd) return;
165    free(wd);
166 }
167
168 static void
169 _mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
170 {
171    Widget_Data *wd = elm_widget_data_get(obj);
172    if (!wd) return;
173    if (wd->scr)
174      elm_smart_scroller_mirrored_set(wd->scr, mirrored);
175 }
176
177 static void
178 _theme_hook(Evas_Object *obj)
179 {
180    Widget_Data *wd = elm_widget_data_get(obj);
181    if (!wd) return;
182    _elm_widget_mirrored_reload(obj);
183    if (wd->scr)
184      {
185         Evas_Object *edj;
186         const char *str;
187
188         _mirrored_set(obj, elm_widget_mirrored_get(obj));
189         elm_smart_scroller_object_theme_set(obj, wd->scr,
190                                             wd->widget_name, wd->widget_base,
191                                             elm_widget_style_get(obj));
192         //        edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
193         edj = elm_smart_scroller_edje_object_get(wd->scr);
194         str = edje_object_data_get(edj, "focus_highlight");
195         if ((str) && (!strcmp(str, "on")))
196           elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
197         else
198           elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
199      }
200    _sizing_eval(obj);
201 }
202
203 static Eina_Bool
204 _elm_scroller_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
205 {
206    Widget_Data *wd = elm_widget_data_get(obj);
207    Evas_Object *cur;
208
209    if ((!wd) || (!wd->content))
210      return EINA_FALSE;
211
212    cur = wd->content;
213
214    /* Try Focus cycle in subitem */
215    if ((elm_widget_can_focus_get(cur)) || (elm_widget_child_can_focus_get(cur)))
216      return elm_widget_focus_next_get(cur, dir, next);
217
218    /* Return */
219    *next = (Evas_Object *)obj;
220    return !elm_widget_focus_get(obj);
221 }
222
223 static void
224 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
225 {
226    Widget_Data *wd = elm_widget_data_get(obj);
227    if (!wd) return;
228    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
229                            emission, source);
230 }
231
232 static void
233 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
234 {
235    Widget_Data *wd = elm_widget_data_get(obj);
236    if (!wd) return;
237    edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr),
238                                    emission, source, func_cb, data);
239 }
240
241 static void
242 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
243 {
244    Widget_Data *wd = elm_widget_data_get(obj);
245    edje_object_signal_callback_del_full(
246       elm_smart_scroller_edje_object_get(wd->scr), emission, source,
247       func_cb, data);
248 }
249
250 static void
251 _show_region_hook(void *data, Evas_Object *obj)
252 {
253    Widget_Data *wd = elm_widget_data_get(data);
254    Evas_Coord x, y, w, h;
255    if (!wd) return;
256    elm_widget_show_region_get(obj, &x, &y, &w, &h);
257    if (wd->scr)
258      elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
259 }
260
261 static void
262 _focus_region_hook(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
263 {
264    Widget_Data *wd = elm_widget_data_get(obj);
265    if (wd->scr)
266      elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
267 }
268
269 static void
270 _sizing_eval(Evas_Object *obj)
271 {
272    Widget_Data *wd = elm_widget_data_get(obj);
273    Evas_Coord  vw, vh, minw = 0, minh = 0, maxw = 0, maxh = 0, w, h, vmw, vmh;
274    double xw = 0.0, yw = 0.0;
275
276    if (!wd) return;
277    if (wd->content)
278      {
279         evas_object_size_hint_min_get(wd->content, &minw, &minh);
280         evas_object_size_hint_max_get(wd->content, &maxw, &maxh);
281         evas_object_size_hint_weight_get(wd->content, &xw, &yw);
282      }
283    if (wd->scr)
284      {
285         elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
286         if (xw > 0.0)
287           {
288              if ((minw > 0) && (vw < minw)) vw = minw;
289              else if ((maxw > 0) && (vw > maxw)) vw = maxw;
290           }
291         else if (minw > 0) vw = minw;
292         if (yw > 0.0)
293           {
294              if ((minh > 0) && (vh < minh)) vh = minh;
295              else if ((maxh > 0) && (vh > maxh)) vh = maxh;
296           }
297         else if (minh > 0) vh = minh;
298         if (wd->content) evas_object_resize(wd->content, vw, vh);
299         w = -1;
300         h = -1;
301         edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
302         if (wd->min_w) w = vmw + minw;
303         if (wd->min_h) h = vmh + minh;
304         evas_object_size_hint_max_get(obj, &maxw, &maxh);
305         if ((maxw > 0) && (w > maxw)) w = maxw;
306         if ((maxh > 0) && (h > maxh)) h = maxh;
307         evas_object_size_hint_min_set(obj, w, h);
308      }
309 }
310
311 static void
312 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
313 {
314    _sizing_eval(data);
315 }
316
317 static void
318 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
319 {
320    Widget_Data *wd = elm_widget_data_get(obj);
321    Evas_Object *sub = event_info;
322
323    if (!wd) return;
324    if (sub == wd->content)
325      {
326         elm_widget_on_show_region_hook_set(wd->content, NULL, NULL);
327         evas_object_event_callback_del_full (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
328                                              _changed_size_hints, obj);
329         wd->content = NULL;
330         _sizing_eval(obj);
331      }
332    else if (sub == wd->scr)
333      wd->scr = NULL;
334 }
335
336 static void
337 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
338 {
339    Widget_Data *wd = elm_widget_data_get(obj);
340
341    if (!wd) return;
342    if (wd->scr)
343      elm_smart_scroller_hold_set(wd->scr, 1);
344 }
345
346 static void
347 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
348 {
349    Widget_Data *wd = elm_widget_data_get(obj);
350
351    if (!wd) return;
352    if (wd->scr)
353      elm_smart_scroller_hold_set(wd->scr, 0);
354 }
355
356 static void
357 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
358 {
359    Widget_Data *wd = elm_widget_data_get(obj);
360
361    if (!wd) return;
362    if (wd->scr)
363      elm_smart_scroller_freeze_set(wd->scr, 1);
364 }
365
366 static void
367 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
368 {
369    Widget_Data *wd = elm_widget_data_get(obj);
370
371    if (!wd) return;
372    if (wd->scr)
373      elm_smart_scroller_freeze_set(wd->scr, 0);
374 }
375
376 static void
377 _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
378 {
379    _sizing_eval(data);
380 }
381
382 static void
383 _edge_left(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
384 {
385    evas_object_smart_callback_call(data, SIG_EDGE_LEFT, NULL);
386 }
387
388 static void
389 _edge_right(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
390 {
391    evas_object_smart_callback_call(data, SIG_EDGE_RIGHT, NULL);
392 }
393
394 static void
395 _edge_top(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
396 {
397    evas_object_smart_callback_call(data, SIG_EDGE_TOP, NULL);
398 }
399
400 static void
401 _edge_bottom(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
402 {
403    evas_object_smart_callback_call(data, SIG_EDGE_BOTTOM, NULL);
404 }
405
406 static void
407 _scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
408 {
409    evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
410 }
411
412 static void
413 _scroll_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
414 {
415    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
416 }
417
418 static void
419 _scroll_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
420 {
421    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
422 }
423
424 static void
425 _scroll_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
426 {
427    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
428 }
429
430 static void
431 _scroll_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
432 {
433    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
434 }
435
436 /**
437  * Add a new scroller to the parent
438  *
439  * @param parent The parent object
440  * @return The new object or NULL if it cannot be created
441  *
442  * @ingroup Scroller
443  */
444 EAPI Evas_Object *
445 elm_scroller_add(Evas_Object *parent)
446 {
447    Evas_Object *obj;
448    Evas *e;
449    Widget_Data *wd;
450    Evas_Coord minw, minh;
451
452    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
453
454    ELM_SET_WIDTYPE(widtype, "scroller");
455    elm_widget_type_set(obj, "scroller");
456    elm_widget_sub_object_add(parent, obj);
457    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
458    elm_widget_data_set(obj, wd);
459    elm_widget_del_hook_set(obj, _del_hook);
460    elm_widget_theme_hook_set(obj, _theme_hook);
461    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
462    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
463    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
464    elm_widget_focus_next_hook_set(obj, _elm_scroller_focus_next_hook);
465    elm_widget_can_focus_set(obj, EINA_TRUE);
466    elm_widget_event_hook_set(obj, _event_hook);
467    elm_widget_focus_region_hook_set(obj, _focus_region_hook);
468
469    wd->widget_name = eina_stringshare_add("scroller");
470    wd->widget_base = eina_stringshare_add("base");
471
472    wd->scr = elm_smart_scroller_add(e);
473    elm_smart_scroller_widget_set(wd->scr, obj);
474    _theme_hook(obj);
475    elm_widget_resize_object_set(obj, wd->scr);
476    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
477                                   _changed_size_hints, obj);
478
479    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh);
480    evas_object_size_hint_min_set(obj, minw, minh);
481    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
482
483    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
484    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
485    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
486    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
487    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
488
489    evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj);
490    evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj);
491    evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj);
492    evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom, obj);
493    evas_object_smart_callback_add(wd->scr, "scroll", _scroll, obj);
494    evas_object_smart_callback_add(wd->scr, "animate,start", _scroll_anim_start, obj);
495    evas_object_smart_callback_add(wd->scr, "animate,stop", _scroll_anim_stop, obj);
496    evas_object_smart_callback_add(wd->scr, "drag,start", _scroll_drag_start, obj);
497    evas_object_smart_callback_add(wd->scr, "drag,stop", _scroll_drag_stop, obj);
498
499    _sizing_eval(obj);
500
501    // TODO: convert Elementary to subclassing of Evas_Smart_Class
502    // TODO: and save some bytes, making descriptions per-class and not instance!
503    evas_object_smart_callbacks_descriptions_set(obj, _signals);
504    _mirrored_set(obj, elm_widget_mirrored_get(obj));
505    return obj;
506 }
507
508 Evas_Object *
509 _elm_scroller_edje_object_get(Evas_Object *obj)
510 {
511    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
512    Widget_Data *wd = elm_widget_data_get(obj);
513    if (!wd) return NULL;
514    return elm_smart_scroller_edje_object_get(wd->scr);
515 }
516
517 /**
518  * Set the content of the scroller widget (the object to be scrolled around).
519  *
520  * Once the content object is set, a previously set one will be deleted.
521  * If you want to keep that old content object, use the
522  * elm_scroller_content_unset() function.
523  *
524  * @param obj The scroller object
525  * @param content The new content object
526  *
527  * @ingroup Scroller
528  */
529 EAPI void
530 elm_scroller_content_set(Evas_Object *obj, Evas_Object *content)
531 {
532    ELM_CHECK_WIDTYPE(obj, widtype);
533    Widget_Data *wd = elm_widget_data_get(obj);
534    if (!wd) return;
535    if (wd->content == content) return;
536    if (wd->content) evas_object_del(wd->content);
537    wd->content = content;
538    if (content)
539      {
540         elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
541         elm_widget_sub_object_add(obj, content);
542         if (wd->scr)
543           elm_smart_scroller_child_set(wd->scr, content);
544         evas_object_event_callback_add(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
545                                        _changed_size_hints, obj);
546      }
547    _sizing_eval(obj);
548 }
549
550 /**
551  * Get the content of the scroller widget
552  *
553  * Return the content object which is set for this widget
554  *
555  * @param obj The slider object
556  * @return The content that is being used
557  *
558  * @ingroup Scroller
559  */
560 EAPI Evas_Object *
561 elm_scroller_content_get(const Evas_Object *obj)
562 {
563    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
564    Widget_Data *wd = elm_widget_data_get(obj);
565    if (!wd) return NULL;
566    return wd->content;
567 }
568
569 /**
570  * Unset the content of the scroller widget
571  *
572  * Unparent and return the content object which was set for this widget
573  *
574  * @param obj The slider object
575  * @return The content that was being used
576  *
577  * @ingroup Scroller
578  */
579 EAPI Evas_Object *
580 elm_scroller_content_unset(Evas_Object *obj)
581 {
582    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
583    Widget_Data *wd = elm_widget_data_get(obj);
584    Evas_Object *content;
585    if (!wd) return NULL;
586    if (!wd->content) return NULL;
587    content = wd->content;
588    elm_widget_sub_object_del(obj, wd->content);
589    edje_object_part_unswallow(wd->scr, wd->content);
590    wd->content = NULL;
591    return content;
592 }
593
594 /**
595  * Set custom theme elements for the scroller
596  *
597  * @param obj The scroller object
598  * @param widget The widget name to use (default is "scroller")
599  * @param base The base name to use (default is "base")
600  *
601  * @ingroup Scroller
602  */
603 EAPI void
604 elm_scroller_custom_widget_base_theme_set(Evas_Object *obj, const char *widget, const char *base)
605 {
606    ELM_CHECK_WIDTYPE(obj, widtype);
607    Widget_Data *wd = elm_widget_data_get(obj);
608    if (!wd) return;
609    EINA_SAFETY_ON_NULL_RETURN(widget);
610    EINA_SAFETY_ON_NULL_RETURN(base);
611    if (eina_stringshare_replace(&wd->widget_name, widget) |
612        eina_stringshare_replace(&wd->widget_base, base))
613      _theme_hook(obj);
614 }
615
616 /**
617  * Make the scroller minimum size limited to the minimum size of the content
618  *
619  * By default the scroller will be as small as its design allows, irrespective
620  * of its content. This will make the scroller minimum size the right size
621  * horizontally and/or vertically to perfectly fit its content.
622  *
623  * @param obj The scroller object
624  * @param w Enable limiting minimum size horizontally
625  * @param h Enable limiting minimum size vertically
626  *
627  * @ingroup Scroller
628  */
629 EAPI void
630 elm_scroller_content_min_limit(Evas_Object *obj, Eina_Bool w, Eina_Bool h)
631 {
632    ELM_CHECK_WIDTYPE(obj, widtype);
633    Widget_Data *wd = elm_widget_data_get(obj);
634    if (!wd) return;
635    wd->min_w = w;
636    wd->min_h = h;
637    _sizing_eval(obj);
638 }
639
640 /**
641  * Show a specific virtual region within the scroller content object
642  *
643  * This will ensure all (or part if it does not fit) of the designated
644  * region in the virtual content object (0, 0 starting at the top-left of the
645  * virtual content object) is shown within the scroller.
646  *
647  * @param obj The scroller object
648  * @param x X coordinate of the region
649  * @param y Y coordinate of the region
650  * @param w Width of the region
651  * @param h Height of the region
652  *
653  * @ingroup Scroller
654  */
655 EAPI void
656 elm_scroller_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
657 {
658    ELM_CHECK_WIDTYPE(obj, widtype);
659    Widget_Data *wd = elm_widget_data_get(obj);
660    if ((!wd) || (!wd->scr)) return;
661    elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
662 }
663
664 /**
665  * Set the scroller scrollbar policy
666  *
667  * This sets the scrollbar visibility policy for the given scroller.
668  * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
669  * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
670  * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
671  * This applies respectively for the horizontal and vertical scrollbars.
672  *
673  * @param obj The scroller object
674  * @param policy_h Horizontal scrollbar policy
675  * @param policy_v Vertical scrollbar policy
676  *
677  * @ingroup Scroller
678  */
679 EAPI void
680 elm_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
681 {
682    ELM_CHECK_WIDTYPE(obj, widtype);
683    Widget_Data *wd = elm_widget_data_get(obj);
684    const Elm_Scroller_Policy map[3] =
685      {
686         ELM_SMART_SCROLLER_POLICY_AUTO,
687         ELM_SMART_SCROLLER_POLICY_ON,
688         ELM_SMART_SCROLLER_POLICY_OFF
689      };
690    if ((!wd) || (!wd->scr)) return;
691    if ((policy_h >= 3) || (policy_v >= 3)) return;
692    elm_smart_scroller_policy_set(wd->scr, map[policy_h], map[policy_v]);
693 }
694
695 EAPI void
696 elm_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
697 {
698    ELM_CHECK_WIDTYPE(obj, widtype);
699    Widget_Data *wd = elm_widget_data_get(obj);
700    if ((!wd) || (!wd->scr)) return;
701    elm_smart_scroller_policy_get(wd->scr,
702                                  (Elm_Smart_Scroller_Policy *) policy_h,
703                                  (Elm_Smart_Scroller_Policy *) policy_v);
704 }
705
706 /**
707  * Get the currently visible content region
708  *
709  * This gets the current region in the content object that is visible through
710  * the scroller. Also see elm_scroller_region_show(). The region co-ordinates
711  * are returned in the @p x, @p y, @p w, @p h values pointed to.
712  *
713  * @param obj The scroller object
714  * @param x X coordinate of the region
715  * @param y Y coordinate of the region
716  * @param w Width of the region
717  * @param h Height of the region
718  *
719  * @ingroup Scroller
720  */
721 EAPI void
722 elm_scroller_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
723 {
724    ELM_CHECK_WIDTYPE(obj, widtype);
725    Widget_Data *wd = elm_widget_data_get(obj);
726    if ((!wd) || (!wd->scr)) return;
727    if ((x) || (y)) elm_smart_scroller_child_pos_get(wd->scr, x, y);
728    if ((w) || (h)) elm_smart_scroller_child_viewport_size_get(wd->scr, w, h);
729 }
730
731 /**
732  * Get the size of the content child object
733  *
734  * This gets the size of the child object of the scroller. Actually the
735  * content of a scroller doesn't specifically need to be an actual object
736  * as it can be virtual and defined purely by callbacks.
737  *
738  * @param obj The scroller object
739  * @param w Width return
740  * @param h Height return
741  *
742  * @ingroup Scroller
743  */
744 EAPI void
745 elm_scroller_child_size_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
746 {
747    ELM_CHECK_WIDTYPE(obj, widtype);
748    Widget_Data *wd = elm_widget_data_get(obj);
749    if (!wd) return;
750    evas_object_geometry_get(wd->content, NULL, NULL, w, h);
751 }
752
753 /**
754  * Set bouncing behavior
755  *
756  * When scrolling, the scroller may "bounce" when reaching an edge of the child
757  * object. This is a visual way to indicate the end has been reached. This is
758  * enabled by default for both axes. This will set if it is enabled for that
759  * axis with the boolean parameters for each axis.
760  *
761  * @param obj The scroller object
762  * @param h_bounce Will the scroller bounce horizontally or not
763  * @param v_bounce Will the scroller bounce vertically or not
764  *
765  * @ingroup Scroller
766  */
767 EAPI void
768 elm_scroller_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
769 {
770    ELM_CHECK_WIDTYPE(obj, widtype);
771    Widget_Data *wd = elm_widget_data_get(obj);
772    if ((!wd) || (!wd->scr)) return;
773    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
774 }
775
776 /**
777  * Get the bounce mode
778  *
779  * @param obj The Scroller object
780  * @param h_bounce Allow bounce horizontally
781  * @param v_bounce Allow bounce vertically
782  *
783  * @ingroup Scroller
784  */
785 EAPI void
786 elm_scroller_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
787 {
788    ELM_CHECK_WIDTYPE(obj, widtype);
789    Widget_Data *wd = elm_widget_data_get(obj);
790    if (!wd) return;
791    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
792 }
793
794 /**
795  * Set scroll page size relative to viewport size.
796  *
797  * The scroller is capable of limiting scrolling by the user to "pages". That
798  * is to jump by and only show a "whole page" at a time as if the continuous
799  * area of the scroller content is split into page sized pieces. This sets
800  * the size of a page relative to the viewport of the scroller. 1.0 is "1
801  * viewport" is size (horizontally or vertically). 0.0 turns it off in that
802  * axis. This is mutually exclusive with page size
803  * (see elm_scroller_page_size_set()  for more information). Likewise 0.5
804  * is "half a viewport". Sane usable valus are normally between 0.0 and 1.0
805  * including 1.0. If you only want 1 axis to be page "limited", use 0.0 for
806  * the other axis.
807  *
808  * @param obj The scroller object
809  * @param h_pagerel The horizontal page relative size
810  * @param v_pagerel The vertical page relative size
811  *
812  * @ingroup Scroller
813  */
814 EAPI void
815 elm_scroller_page_relative_set(Evas_Object *obj, double h_pagerel, double v_pagerel)
816 {
817    ELM_CHECK_WIDTYPE(obj, widtype);
818    Widget_Data *wd = elm_widget_data_get(obj);
819    if (!wd) return;
820    wd->pagerel_h = h_pagerel;
821    wd->pagerel_v = v_pagerel;
822    if (wd->scr)
823      elm_smart_scroller_paging_set(wd->scr, wd->pagerel_h, wd->pagerel_v,
824                                    wd->pagesize_h, wd->pagesize_v);
825 }
826
827 /**
828  * Set scroll page size.
829  *
830  * See also elm_scroller_page_relative_set(). This, instead of a page size
831  * being relative to the viewport, sets it to an absolute fixed value, with
832  * 0 turning it off for that axis.
833  *
834  * @param obj The scroller object
835  * @param h_pagesize The horizontal page size
836  * @param v_pagesize The vertical page size
837  *
838  * @ingroup Scroller
839  */
840 EAPI void
841 elm_scroller_page_size_set(Evas_Object *obj, Evas_Coord h_pagesize, Evas_Coord v_pagesize)
842 {
843    ELM_CHECK_WIDTYPE(obj, widtype);
844    Widget_Data *wd = elm_widget_data_get(obj);
845    if (!wd) return;
846    wd->pagesize_h = h_pagesize;
847    wd->pagesize_v = v_pagesize;
848    if (wd->scr)
849      elm_smart_scroller_paging_set(wd->scr, wd->pagerel_h, wd->pagerel_v,
850                                    wd->pagesize_h, wd->pagesize_v);
851 }
852
853 /**
854  * Show a specific virtual region within the scroller content object.
855  *
856  * This will ensure all (or part if it does not fit) of the designated
857  * region in the virtual content object (0, 0 starting at the top-left of the
858  * virtual content object) is shown within the scroller. Unlike
859  * elm_scroller_region_show(), this allow the scroller to "smoothly slide"
860  * to this location (if configuration in general calls for transitions). It
861  * may not jump immediately to the new location and make take a while and
862  * show other content along the way.
863  *
864  * @param obj The scroller object
865  * @param x X coordinate of the region
866  * @param y Y coordinate of the region
867  * @param w Width of the region
868  * @param h Height of the region
869  *
870  * @ingroup Scroller
871  */
872 EAPI void
873 elm_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
874 {
875    ELM_CHECK_WIDTYPE(obj, widtype);
876    Widget_Data *wd = elm_widget_data_get(obj);
877    if ((!wd) || (!wd->scr)) return;
878    elm_smart_scroller_region_bring_in(wd->scr, x, y, w, h);
879 }
880
881
882 /**
883  * Set event propagation on a scroller
884  *
885  * This enables or disabled event propagation from the scroller content to
886  * the scroller and its parent. By default event propagation is disabled.
887  *
888  * @param obj The scroller object
889  * @param propagation If propagation is enabled or not
890  *
891  * @ingroup Scroller
892  */
893 EAPI void
894 elm_scroller_propagate_events_set(Evas_Object *obj, Eina_Bool propagation)
895 {
896    ELM_CHECK_WIDTYPE(obj, widtype);
897    Widget_Data *wd = elm_widget_data_get(obj);
898    if (!wd) return;
899
900    evas_object_propagate_events_set(wd->scr, propagation);
901 }
902
903 /**
904  * Get event propagation for a scroller
905  *
906  * This gets the event propagation for a scroller. See
907  * elm_scroller_propagate_events_set() for more information
908  *
909  * @param obj The scroller object
910  * @return The propagation state
911  *
912  * @ingroup Scroller
913  */
914 EAPI Eina_Bool
915 elm_scroller_propagate_events_get(const Evas_Object *obj)
916 {
917    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
918    Widget_Data *wd = elm_widget_data_get(obj);
919    if (!wd) return EINA_FALSE;
920
921    return evas_object_propagate_events_get(wd->scr);
922 }