Scroller: Add step size set API
[platform/upstream/elementary.git] / src / lib / elm_scroller.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
6 #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
7
8 #include <Elementary.h>
9
10 #include "elm_priv.h"
11 #include "elm_interface_scrollable.h"
12 #include "elm_widget_layout.h"
13 #include "elm_widget_scroller.h"
14
15 #define MY_CLASS ELM_SCROLLER_CLASS
16
17 #define MY_CLASS_NAME "Elm_Scroller"
18 #define MY_CLASS_NAME_LEGACY "elm_scroller"
19
20 #define ELM_PRIV_SCROLLER_SIGNALS(cmd) \
21    cmd(SIG_SCROLL, "scroll", "") \
22    cmd(SIG_SCROLL_LEFT, "scroll,left", "") \
23    cmd(SIG_SCROLL_RIGHT, "scroll,right", "") \
24    cmd(SIG_SCROLL_UP, "scroll,up", "") \
25    cmd(SIG_SCROLL_DOWN, "scroll,down", "") \
26    cmd(SIG_SCROLL_ANIM_START, "scroll,anim,start", "") \
27    cmd(SIG_SCROLL_ANIM_STOP, "scroll,anim,stop", "") \
28    cmd(SIG_SCROLL_DRAG_START, "scroll,drag,start", "") \
29    cmd(SIG_SCROLL_DRAG_STOP, "scroll,drag,stop", "") \
30    cmd(SIG_EDGE_LEFT, "edge,left", "") \
31    cmd(SIG_EDGE_RIGHT, "edge,right", "") \
32    cmd(SIG_EDGE_TOP, "edge,top", "") \
33    cmd(SIG_EDGE_BOTTOM, "edge,bottom", "") \
34    cmd(SIG_VBAR_DRAG, "vbar,drag", "") \
35    cmd(SIG_VBAR_PRESS, "vbar,press", "") \
36    cmd(SIG_VBAR_UNPRESS, "vbar,unpress", "") \
37    cmd(SIG_HBAR_DRAG, "hbar,drag", "") \
38    cmd(SIG_HBAR_PRESS, "hbar,press", "") \
39    cmd(SIG_HBAR_UNPRESS, "hbar,unpress", "") \
40    cmd(SIG_SCROLL_PAGE_CHANGE, "scroll,page,changed", "") \
41
42 ELM_PRIV_SCROLLER_SIGNALS(ELM_PRIV_STATIC_VARIABLE_DECLARE);
43
44 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
45    ELM_PRIV_SCROLLER_SIGNALS(ELM_PRIV_SMART_CALLBACKS_DESC)
46    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
47    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
48    {NULL, NULL}
49 };
50 #undef ELM_PRIV_SCROLLER_SIGNALS
51
52 static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
53
54 static const Elm_Action key_actions[] = {
55    {"move", _key_action_move},
56    {NULL, NULL}
57 };
58
59 static Eina_Bool
60 _key_action_move(Evas_Object *obj, const char *params)
61 {
62    ELM_SCROLLER_DATA_GET(obj, sd);
63    const char *dir = params;
64    Evas_Coord x = 0;
65    Evas_Coord y = 0;
66    Evas_Coord c_x = 0;
67    Evas_Coord c_y = 0;
68    Evas_Coord v_w = 0;
69    Evas_Coord v_h = 0;
70    Evas_Coord max_x = 0;
71    Evas_Coord max_y = 0;
72    Evas_Coord page_x = 0;
73    Evas_Coord page_y = 0;
74    Evas_Coord step_x = 0;
75    Evas_Coord step_y = 0;
76    Evas_Object *current_focus = NULL;
77    Eina_List *can_focus_list = NULL;
78    Evas_Object *new_focus = NULL;
79    Evas_Coord f_x = 0;
80    Evas_Coord f_y = 0;
81    Evas_Coord f_w = 0;
82    Evas_Coord f_h = 0;
83
84    eo_do(obj,
85          elm_interface_scrollable_content_pos_get(&x, &y),
86          elm_interface_scrollable_step_size_get(&step_x, &step_y),
87          elm_interface_scrollable_page_size_get(&page_x, &page_y),
88          elm_interface_scrollable_content_viewport_geometry_get
89          (NULL, NULL, &v_w, &v_h));
90    eo_do(sd->content,
91          evas_obj_position_get(&c_x, &c_y),
92          evas_obj_size_get(&max_x, &max_y));
93
94    current_focus = elm_widget_focused_object_get(obj);
95    evas_object_geometry_get(current_focus, &f_x, &f_y, &f_w, &f_h);
96    can_focus_list = elm_widget_can_focus_child_list_get(obj);
97
98    if ((current_focus == obj) ||
99        (!ELM_RECTS_INTERSECT
100         (x, y, v_w, v_h, (f_x - c_x), (f_y - c_y), f_w, f_h)))
101      {
102         Eina_List *l;
103         Evas_Object *cur;
104         double weight = 0.0;
105
106         EINA_LIST_FOREACH(can_focus_list, l, cur)
107           {
108              double cur_weight = 0.0;
109
110              evas_object_geometry_get(cur, &f_x, &f_y, &f_w, &f_h);
111              if (ELM_RECTS_INTERSECT
112                  (x, y, v_w, v_h, (f_x - c_x), (f_y - c_y), f_w, f_h))
113                {
114                   if ((f_x - c_x) > x)
115                     cur_weight += ((f_x - c_x) - x) * ((f_x - c_x) - x);
116                   if ((f_y - c_y) > y)
117                     cur_weight += ((f_y - c_y) - y) * ((f_y - c_y) - y);
118                   if (cur_weight == 0.0)
119                     {
120                        elm_widget_focus_steal(cur);
121                        return EINA_TRUE;
122                     }
123                   cur_weight = 1.0 / cur_weight;
124                   if (cur_weight > weight)
125                     {
126                        new_focus = cur;
127                        weight = cur_weight;
128                     }
129                }
130           }
131         if (new_focus)
132           {
133              elm_widget_focus_steal(new_focus);
134              return EINA_TRUE;
135           }
136      }
137    else
138      {
139         Eina_Bool r = EINA_FALSE;
140
141         if (!strcmp(dir, "left"))
142           r = elm_widget_focus_next_get(obj, ELM_FOCUS_LEFT, &new_focus);
143         else if (!strcmp(dir, "right"))
144           r = elm_widget_focus_next_get(obj, ELM_FOCUS_RIGHT, &new_focus);
145         else if (!strcmp(dir, "up"))
146           r = elm_widget_focus_next_get(obj, ELM_FOCUS_UP, &new_focus);
147         else if (!strcmp(dir, "down"))
148           r = elm_widget_focus_next_get(obj, ELM_FOCUS_DOWN, &new_focus);
149
150         if (r && new_focus)
151           {
152              Evas_Coord l_x = 0;
153              Evas_Coord l_y = 0;
154              Evas_Coord l_w = 0;
155              Evas_Coord l_h = 0;
156
157              evas_object_geometry_get(new_focus, &f_x, &f_y, &f_w, &f_h);
158              l_x = f_x - c_x - step_x;
159              l_y = f_y - c_y - step_y;
160              l_w = f_w + (step_x * 2);
161              l_h = f_h + (step_y * 2);
162
163              if (ELM_RECTS_INTERSECT(x, y, v_w, v_h, l_x, l_y, l_w, l_h))
164                {
165                   elm_widget_focus_steal(new_focus);
166                   return EINA_TRUE;
167                }
168           }
169      }
170    if (!strcmp(dir, "left"))
171      {
172         if (x <= 0) return EINA_FALSE;
173         x -= step_x;
174      }
175    else if (!strcmp(dir, "right"))
176      {
177         if (x >= (max_x - v_w)) return EINA_FALSE;
178         x += step_x;
179      }
180    else if (!strcmp(dir, "up"))
181      {
182         if (y == 0) return EINA_FALSE;
183         y -= step_y;
184      }
185    else if (!strcmp(dir, "down"))
186      {
187         if (y >= (max_y - v_h)) return EINA_FALSE;
188         y += step_y;
189      }
190    else if (!strcmp(dir, "first"))
191      {
192         y = 0;
193      }
194    else if (!strcmp(dir, "last"))
195      {
196         y = max_y - v_h;
197      }
198    else if (!strcmp(dir, "prior"))
199      {
200         if (page_y < 0)
201           y -= -(page_y * v_h) / 100;
202         else
203           y -= page_y;
204      }
205    else if (!strcmp(dir, "next"))
206      {
207         if (page_y < 0)
208           y += -(page_y * v_h) / 100;
209         else
210           y += page_y;
211      }
212    else return EINA_FALSE;
213
214    eo_do(obj, elm_interface_scrollable_content_pos_set(x, y, EINA_TRUE));
215    return EINA_TRUE;
216 }
217
218 EOLIAN static Eina_Bool
219 _elm_scroller_elm_widget_event(Eo *obj, Elm_Scroller_Data *sd EINA_UNUSED, Evas_Object *src, Evas_Callback_Type type, void *event_info)
220 {
221    (void) src;
222    Evas_Event_Key_Down *ev = event_info;
223
224    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
225    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
226
227    if (!_elm_config_key_binding_call(obj, ev, key_actions))
228      return EINA_FALSE;
229
230    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
231    return EINA_TRUE;
232 }
233
234 EOLIAN static Eina_Bool
235 _elm_scroller_elm_widget_activate(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED, Elm_Activate act)
236 {
237    Evas_Coord x = 0;
238    Evas_Coord y = 0;
239    Evas_Coord v_w = 0;
240    Evas_Coord v_h = 0;
241    Evas_Coord page_x = 0;
242    Evas_Coord page_y = 0;
243
244    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
245    if (act == ELM_ACTIVATE_DEFAULT) return EINA_FALSE;
246
247    eo_do(obj,
248          elm_interface_scrollable_content_pos_get(&x, &y),
249          elm_interface_scrollable_page_size_get(&page_x, &page_y),
250          elm_interface_scrollable_content_viewport_geometry_get
251          (NULL, NULL, &v_w, &v_h));
252
253    if (act == ELM_ACTIVATE_UP)
254      {
255         if (page_y < 0)
256           y -= -(page_y * v_h) / 100;
257         else
258           y -= page_y;
259      }
260    else if (act == ELM_ACTIVATE_DOWN)
261      {
262         if (page_y < 0)
263           y += -(page_y * v_h) / 100;
264         else
265           y += page_y;
266      }
267    else if (act == ELM_ACTIVATE_LEFT)
268      {
269         if (page_x < 0)
270           x -= -(page_x * v_w) / 100;
271         else
272           x -= page_x;
273      }
274    else if (act == ELM_ACTIVATE_RIGHT)
275      {
276         if (page_x < 0)
277           x += -(page_x * v_w) / 100;
278         else
279           x += page_x;
280      }
281
282    eo_do(obj, elm_interface_scrollable_content_pos_set(x, y, EINA_TRUE));
283
284    return EINA_TRUE;
285 }
286
287 EOLIAN static void
288 _elm_scroller_elm_layout_sizing_eval(Eo *obj, Elm_Scroller_Data *sd)
289 {
290    Evas_Coord vw = 0, vh = 0, minw = 0, minh = 0, maxw = 0, maxh = 0, w, h,
291               vmw, vmh;
292    double xw = 0.0, yw = 0.0;
293
294    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
295
296    if (sd->content)
297      {
298         evas_object_size_hint_min_get(sd->content, &minw, &minh);
299         evas_object_size_hint_max_get(sd->content, &maxw, &maxh);
300         evas_object_size_hint_weight_get(sd->content, &xw, &yw);
301      }
302
303    eo_do(obj, elm_interface_scrollable_content_viewport_geometry_get
304          (NULL, NULL, &vw, &vh));
305    if (xw > 0.0)
306      {
307         if ((minw > 0) && (vw < minw))
308           vw = minw;
309         else if ((maxw > 0) && (vw > maxw))
310           vw = maxw;
311      }
312    else if (minw > 0)
313      vw = minw;
314
315    if (yw > 0.0)
316      {
317         if ((minh > 0) && (vh < minh))
318           vh = minh;
319         else if ((maxh > 0) && (vh > maxh))
320           vh = maxh;
321      }
322    else if (minh > 0)
323      vh = minh;
324
325    if (sd->content) evas_object_resize(sd->content, vw, vh);
326
327    w = -1;
328    h = -1;
329    vmw = vmh = 0;
330    edje_object_size_min_calc(wd->resize_obj, &vmw, &vmh);
331
332    if (sd->min_w) w = vmw + minw;
333    if (sd->min_h) h = vmh + minh;
334
335    evas_object_size_hint_max_get(obj, &maxw, &maxh);
336    if ((maxw > 0) && (w > maxw)) w = maxw;
337    if ((maxh > 0) && (h > maxh)) h = maxh;
338
339    evas_object_size_hint_min_set(obj, w, h);
340 }
341
342 static void
343 _mirrored_set(Evas_Object *obj,
344               Eina_Bool mirrored)
345 {
346    eo_do(obj, elm_interface_scrollable_mirrored_set(mirrored));
347 }
348
349 EOLIAN static Eina_Bool
350 _elm_scroller_elm_widget_theme_apply(Eo *obj, Elm_Scroller_Data *sd EINA_UNUSED)
351 {
352    Eina_Bool int_ret = EINA_FALSE;
353    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_theme_apply());
354    if (!int_ret) return EINA_FALSE;
355
356    _mirrored_set(obj, elm_widget_mirrored_get(obj));
357
358    elm_layout_sizing_eval(obj);
359
360    return EINA_TRUE;
361 }
362
363 EOLIAN static Eina_Bool
364 _elm_scroller_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Scroller_Data *_pd EINA_UNUSED)
365 {
366    return EINA_TRUE;
367 }
368
369 EOLIAN static Eina_Bool
370 _elm_scroller_elm_widget_focus_next(Eo *obj EINA_UNUSED, Elm_Scroller_Data *sd, Elm_Focus_Direction dir, Evas_Object **next)
371 {
372    Evas_Object *cur;
373
374    if (!sd->content) return EINA_FALSE;
375
376    cur = sd->content;
377
378    /* access */
379    if (_elm_config->access_mode)
380      {
381         if ((elm_widget_can_focus_get(cur)) ||
382             (elm_widget_child_can_focus_get(cur)))
383           {
384              return elm_widget_focus_next_get(cur, dir, next);
385           }
386
387         return EINA_FALSE;
388      }
389
390    /* Try focus cycle in subitem */
391    if (elm_widget_focus_get(obj))
392      {
393         if ((elm_widget_can_focus_get(cur)) ||
394             (elm_widget_child_can_focus_get(cur)))
395           {
396              return elm_widget_focus_next_get(cur, dir, next);
397           }
398      }
399
400    /* Return */
401    *next = (Evas_Object *)obj;
402
403    return !elm_widget_focus_get(obj);
404 }
405
406 EOLIAN static Eina_Bool
407 _elm_scroller_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_Scroller_Data *_pd EINA_UNUSED)
408 {
409    return EINA_FALSE;
410 }
411
412 static void
413 _show_region_hook(void *data,
414                   Evas_Object *content_obj)
415 {
416    Evas_Coord x, y, w, h;
417
418    elm_widget_show_region_get(content_obj, &x, &y, &w, &h);
419    eo_do(data, elm_interface_scrollable_content_region_show(x, y, w, h));
420 }
421
422 static void
423 _changed_size_hints_cb(void *data,
424                        Evas *e EINA_UNUSED,
425                        Evas_Object *obj EINA_UNUSED,
426                        void *event_info EINA_UNUSED)
427 {
428    elm_layout_sizing_eval(data);
429 }
430
431 EOLIAN static Eina_Bool
432 _elm_scroller_elm_widget_sub_object_del(Eo *obj, Elm_Scroller_Data *sd, Evas_Object *sobj)
433 {
434    Eina_Bool int_ret = EINA_FALSE;
435    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_sub_object_del(sobj));
436    if (!int_ret) return EINA_FALSE;
437
438    if (sobj == sd->content)
439      {
440         if (elm_widget_is(sobj))
441           elm_widget_on_show_region_hook_set(sd->content, NULL, NULL);
442
443         sd->content = NULL;
444      }
445
446    return EINA_TRUE;
447 }
448
449 static void
450 _resize_cb(void *data,
451            Evas *e EINA_UNUSED,
452            Evas_Object *obj EINA_UNUSED,
453            void *event_info EINA_UNUSED)
454 {
455    elm_layout_sizing_eval(data);
456 }
457
458 static void
459 _edge_left_cb(Evas_Object *obj,
460               void *data EINA_UNUSED)
461 {
462    evas_object_smart_callback_call(obj, SIG_EDGE_LEFT, NULL);
463 }
464
465 static void
466 _edge_right_cb(Evas_Object *obj,
467                void *data EINA_UNUSED)
468 {
469    evas_object_smart_callback_call(obj, SIG_EDGE_RIGHT, NULL);
470 }
471
472 static void
473 _edge_top_cb(Evas_Object *obj,
474              void *data EINA_UNUSED)
475 {
476    evas_object_smart_callback_call(obj, SIG_EDGE_TOP, NULL);
477 }
478
479 static void
480 _edge_bottom_cb(Evas_Object *obj,
481                 void *data EINA_UNUSED)
482 {
483    evas_object_smart_callback_call(obj, SIG_EDGE_BOTTOM, NULL);
484 }
485
486 static void
487 _scroll_cb(Evas_Object *obj,
488            void *data EINA_UNUSED)
489 {
490    evas_object_smart_callback_call(obj, SIG_SCROLL, NULL);
491 }
492
493 static void
494 _scroll_left_cb(Evas_Object *obj,
495            void *data EINA_UNUSED)
496 {
497    evas_object_smart_callback_call(obj, SIG_SCROLL_LEFT, NULL);
498 }
499
500 static void
501 _scroll_right_cb(Evas_Object *obj,
502            void *data EINA_UNUSED)
503 {
504    evas_object_smart_callback_call(obj, SIG_SCROLL_RIGHT, NULL);
505 }
506
507 static void
508 _scroll_up_cb(Evas_Object *obj,
509            void *data EINA_UNUSED)
510 {
511    evas_object_smart_callback_call(obj, SIG_SCROLL_UP, NULL);
512 }
513
514 static void
515 _scroll_down_cb(Evas_Object *obj,
516            void *data EINA_UNUSED)
517 {
518    evas_object_smart_callback_call(obj, SIG_SCROLL_DOWN, NULL);
519 }
520
521 static void
522 _scroll_anim_start_cb(Evas_Object *obj,
523                       void *data EINA_UNUSED)
524 {
525    evas_object_smart_callback_call(obj, SIG_SCROLL_ANIM_START, NULL);
526 }
527
528 static void
529 _scroll_anim_stop_cb(Evas_Object *obj,
530                      void *data EINA_UNUSED)
531 {
532    evas_object_smart_callback_call(obj, SIG_SCROLL_ANIM_STOP, NULL);
533 }
534
535 static void
536 _scroll_drag_start_cb(Evas_Object *obj,
537                       void *data EINA_UNUSED)
538 {
539    evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_START, NULL);
540 }
541
542 static void
543 _scroll_drag_stop_cb(Evas_Object *obj,
544                      void *data EINA_UNUSED)
545 {
546    evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_STOP, NULL);
547 }
548
549 static void
550 _vbar_drag_cb(Evas_Object *obj,
551                 void *data EINA_UNUSED)
552 {
553    evas_object_smart_callback_call(obj, SIG_VBAR_DRAG, NULL);
554 }
555
556 static void
557 _vbar_press_cb(Evas_Object *obj,
558                 void *data EINA_UNUSED)
559 {
560    evas_object_smart_callback_call(obj, SIG_VBAR_PRESS, NULL);
561 }
562
563 static void
564 _vbar_unpress_cb(Evas_Object *obj,
565                 void *data EINA_UNUSED)
566 {
567    evas_object_smart_callback_call(obj, SIG_VBAR_UNPRESS, NULL);
568 }
569
570 static void
571 _hbar_drag_cb(Evas_Object *obj,
572                 void *data EINA_UNUSED)
573 {
574    evas_object_smart_callback_call(obj, SIG_HBAR_DRAG, NULL);
575 }
576
577 static void
578 _hbar_press_cb(Evas_Object *obj,
579                 void *data EINA_UNUSED)
580 {
581    evas_object_smart_callback_call(obj, SIG_HBAR_PRESS, NULL);
582 }
583
584 static void
585 _hbar_unpress_cb(Evas_Object *obj,
586                 void *data EINA_UNUSED)
587 {
588    evas_object_smart_callback_call(obj, SIG_HBAR_UNPRESS, NULL);
589 }
590
591 static void
592 _page_change_cb(Evas_Object *obj,
593                 void *data EINA_UNUSED)
594 {
595    evas_object_smart_callback_call(obj, SIG_SCROLL_PAGE_CHANGE, NULL);
596 }
597
598 EOLIAN static Eina_Bool
599 _elm_scroller_elm_container_content_set(Eo *obj, Elm_Scroller_Data *sd, const char *part, Evas_Object *content)
600 {
601    if (part && strcmp(part, "default"))
602      {
603         Eina_Bool int_ret = EINA_FALSE;
604         eo_do_super(obj, MY_CLASS, int_ret = elm_obj_container_content_set(part, content));
605         return int_ret;
606      }
607
608    if (sd->content == content) return EINA_TRUE;
609
610    evas_object_del(sd->content);
611    sd->content = content;
612
613    if (content)
614      {
615         if (elm_widget_is(content))
616           elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
617         elm_widget_sub_object_add(obj, content);
618
619         eo_do(obj, elm_interface_scrollable_content_set(content));
620      }
621
622    elm_layout_sizing_eval(obj);
623
624    return EINA_TRUE;
625 }
626
627 EOLIAN static Evas_Object*
628 _elm_scroller_elm_container_content_get(Eo *obj, Elm_Scroller_Data *sd, const char *part)
629 {
630    if (part && strcmp(part, "default"))
631      {
632         Evas_Object *ret = NULL;
633         eo_do_super(obj, MY_CLASS, ret = elm_obj_container_content_get(part));
634         return ret;
635      }
636
637    return sd->content;
638 }
639
640 EOLIAN static Evas_Object*
641 _elm_scroller_elm_container_content_unset(Eo *obj, Elm_Scroller_Data *sd, const char *part)
642 {
643    Evas_Object *ret = NULL;
644    if (part && strcmp(part, "default"))
645      {
646         eo_do_super(obj, MY_CLASS, ret = elm_obj_container_content_unset(part));
647         return ret;
648      }
649
650    if (!sd->content) return NULL;
651
652    ret = sd->content;
653    elm_widget_sub_object_del(obj, sd->content);
654    eo_do(obj, elm_interface_scrollable_content_set(NULL));
655    sd->content = NULL;
656
657    return ret;
658 }
659
660 static void
661 _elm_scroller_content_min_limit_cb(Evas_Object *obj,
662                                    Eina_Bool w,
663                                    Eina_Bool h)
664 {
665    ELM_SCROLLER_DATA_GET(obj, sd);
666
667    sd->min_w = !!w;
668    sd->min_h = !!h;
669
670    elm_layout_sizing_eval(obj);
671 }
672
673 static void
674 _elm_scroller_content_viewport_resize_cb(Evas_Object *obj,
675                                    Evas_Coord w EINA_UNUSED,
676                                    Evas_Coord h EINA_UNUSED)
677 {
678    elm_layout_sizing_eval(obj);
679 }
680
681 EOLIAN static void
682 _elm_scroller_evas_object_smart_add(Eo *obj, Elm_Scroller_Data *priv)
683 {
684    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
685    Evas_Coord minw, minh;
686
687    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
688    elm_widget_sub_object_parent_add(obj);
689    elm_widget_can_focus_set(obj, EINA_TRUE);
690
691    if (!elm_layout_theme_set
692        (obj, "scroller", "base", elm_widget_style_get(obj)))
693      CRI("Failed to set layout!");
694
695    priv->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
696    evas_object_smart_member_add(priv->hit_rect, obj);
697    elm_widget_sub_object_add(obj, priv->hit_rect);
698
699    evas_object_color_set(priv->hit_rect, 0, 0, 0, 0);
700    evas_object_show(priv->hit_rect);
701    evas_object_repeat_events_set(priv->hit_rect, EINA_TRUE);
702
703    eo_do(obj, elm_interface_scrollable_objects_set(wd->resize_obj, priv->hit_rect));
704
705    evas_object_event_callback_add
706      (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints_cb, obj);
707
708    edje_object_size_min_calc(wd->resize_obj, &minw, &minh);
709    evas_object_size_hint_min_set(obj, minw, minh);
710    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
711
712    eo_do(obj,
713          elm_interface_scrollable_edge_left_cb_set(_edge_left_cb),
714          elm_interface_scrollable_edge_right_cb_set(_edge_right_cb),
715          elm_interface_scrollable_edge_top_cb_set(_edge_top_cb),
716          elm_interface_scrollable_edge_bottom_cb_set(_edge_bottom_cb),
717          elm_interface_scrollable_scroll_cb_set(_scroll_cb),
718          elm_interface_scrollable_scroll_left_cb_set(_scroll_left_cb),
719          elm_interface_scrollable_scroll_right_cb_set(_scroll_right_cb),
720          elm_interface_scrollable_scroll_up_cb_set(_scroll_up_cb),
721          elm_interface_scrollable_scroll_down_cb_set(_scroll_down_cb),
722          elm_interface_scrollable_animate_start_cb_set(_scroll_anim_start_cb),
723          elm_interface_scrollable_animate_stop_cb_set(_scroll_anim_stop_cb),
724          elm_interface_scrollable_drag_start_cb_set(_scroll_drag_start_cb),
725          elm_interface_scrollable_drag_stop_cb_set(_scroll_drag_stop_cb),
726          elm_interface_scrollable_vbar_drag_cb_set(_vbar_drag_cb),
727          elm_interface_scrollable_vbar_press_cb_set(_vbar_press_cb),
728          elm_interface_scrollable_vbar_unpress_cb_set(_vbar_unpress_cb),
729          elm_interface_scrollable_hbar_drag_cb_set(_hbar_drag_cb),
730          elm_interface_scrollable_hbar_press_cb_set(_hbar_press_cb),
731          elm_interface_scrollable_hbar_unpress_cb_set(_hbar_unpress_cb),
732          elm_interface_scrollable_page_change_cb_set(_page_change_cb),
733          elm_interface_scrollable_content_min_limit_cb_set
734          (_elm_scroller_content_min_limit_cb),
735          elm_interface_scrollable_content_viewport_resize_cb_set
736          (_elm_scroller_content_viewport_resize_cb));
737 }
738
739 EOLIAN static void
740 _elm_scroller_evas_object_smart_move(Eo *obj, Elm_Scroller_Data *sd, Evas_Coord x, Evas_Coord y)
741 {
742    eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
743
744    evas_object_move(sd->hit_rect, x, y);
745 }
746
747 EOLIAN static void
748 _elm_scroller_evas_object_smart_resize(Eo *obj, Elm_Scroller_Data *sd, Evas_Coord w, Evas_Coord h)
749 {
750    eo_do_super(obj, MY_CLASS, evas_obj_smart_resize(w, h));
751
752    evas_object_resize(sd->hit_rect, w, h);
753 }
754
755 EOLIAN static void
756 _elm_scroller_evas_object_smart_member_add(Eo *obj, Elm_Scroller_Data *sd, Evas_Object *member)
757 {
758    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_add(member));
759
760    if (sd->hit_rect)
761      evas_object_raise(sd->hit_rect);
762 }
763
764 EAPI Evas_Object *
765 elm_scroller_add(Evas_Object *parent)
766 {
767    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
768    Evas_Object *obj = eo_add(MY_CLASS, parent);
769    return obj;
770 }
771
772 EOLIAN static void
773 _elm_scroller_eo_base_constructor(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED)
774 {
775    eo_do_super(obj, MY_CLASS, eo_constructor());
776    eo_do(obj,
777          evas_obj_type_set(MY_CLASS_NAME_LEGACY),
778          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
779          elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_SCROLL_PANE));
780 }
781
782 /* deprecated */
783 EOLIAN static void
784 _elm_scroller_custom_widget_base_theme_set(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED, const char *klass, const char *group)
785 {
786    ELM_LAYOUT_DATA_GET(obj, ld);
787
788    EINA_SAFETY_ON_NULL_RETURN(klass);
789    EINA_SAFETY_ON_NULL_RETURN(group);
790
791    if (eina_stringshare_replace(&(ld->klass), klass) ||
792        eina_stringshare_replace(&(ld->group), group))
793       eo_do(obj, elm_obj_widget_theme_apply());
794 }
795
796 EAPI void
797 elm_scroller_content_min_limit(Evas_Object *obj,
798                                Eina_Bool w,
799                                Eina_Bool h)
800 {
801    ELM_SCROLLABLE_CHECK(obj);
802
803    eo_do(obj, elm_interface_scrollable_content_min_limit(w, h));
804 }
805
806 EAPI void
807 elm_scroller_region_show(Evas_Object *obj,
808                          Evas_Coord x,
809                          Evas_Coord y,
810                          Evas_Coord w,
811                          Evas_Coord h)
812 {
813    ELM_SCROLLABLE_CHECK(obj);
814
815    eo_do(obj, elm_interface_scrollable_content_region_show(x, y, w, h));
816 }
817
818 EAPI void
819 elm_scroller_policy_set(Evas_Object *obj,
820                         Elm_Scroller_Policy policy_h,
821                         Elm_Scroller_Policy policy_v)
822 {
823    ELM_SCROLLABLE_CHECK(obj);
824    eo_do(obj, elm_interface_scrollable_policy_set(policy_h, policy_v));
825 }
826
827 EOLIAN static void
828 _elm_scroller_elm_interface_scrollable_policy_set(Eo *obj, Elm_Scroller_Data *sd EINA_UNUSED, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
829 {
830    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
831        (policy_v >= ELM_SCROLLER_POLICY_LAST))
832      return;
833
834    eo_do_super(obj, MY_CLASS, elm_interface_scrollable_policy_set(policy_h, policy_v));
835 }
836
837 EAPI void
838 elm_scroller_policy_get(const Evas_Object *obj,
839                         Elm_Scroller_Policy *policy_h,
840                         Elm_Scroller_Policy *policy_v)
841 {
842    ELM_SCROLLABLE_CHECK(obj);
843
844    eo_do((Eo *) obj, elm_interface_scrollable_policy_get(policy_h, policy_v));
845 }
846
847 EAPI void
848 elm_scroller_single_direction_set(Evas_Object *obj,
849                                   Elm_Scroller_Single_Direction single_dir)
850 {
851    ELM_SCROLLABLE_CHECK(obj);
852    eo_do(obj, elm_interface_scrollable_single_direction_set(single_dir));
853 }
854
855 EOLIAN static void
856 _elm_scroller_elm_interface_scrollable_single_direction_set(Eo *obj, Elm_Scroller_Data *sd EINA_UNUSED, Elm_Scroller_Single_Direction single_dir)
857 {
858    if (single_dir >= ELM_SCROLLER_SINGLE_DIRECTION_LAST)
859      return;
860
861    eo_do_super(obj, MY_CLASS,
862                elm_interface_scrollable_single_direction_set(single_dir));
863 }
864
865 EAPI Elm_Scroller_Single_Direction
866 elm_scroller_single_direction_get(const Evas_Object *obj)
867 {
868    ELM_SCROLLABLE_CHECK(obj, ELM_SCROLLER_SINGLE_DIRECTION_NONE);
869    Elm_Scroller_Single_Direction single_dir = ELM_SCROLLER_SINGLE_DIRECTION_NONE;
870
871    eo_do((Eo *) obj, single_dir = elm_interface_scrollable_single_direction_get());
872    return single_dir;
873 }
874
875 EOLIAN static Elm_Scroller_Single_Direction
876 _elm_scroller_elm_interface_scrollable_single_direction_get(Eo *obj, Elm_Scroller_Data *sd EINA_UNUSED)
877 {
878    Elm_Scroller_Single_Direction ret = ELM_SCROLLER_SINGLE_DIRECTION_NONE;
879    eo_do_super(obj, MY_CLASS,
880                ret = elm_interface_scrollable_single_direction_get());
881    return ret;
882 }
883
884 EAPI void
885 elm_scroller_region_get(const Evas_Object *obj,
886                         Evas_Coord *x,
887                         Evas_Coord *y,
888                         Evas_Coord *w,
889                         Evas_Coord *h)
890 {
891    ELM_SCROLLABLE_CHECK(obj);
892    eo_do((Eo *) obj, elm_interface_scrollable_content_region_get(x, y, w, h));
893 }
894
895 EAPI void
896 elm_scroller_child_size_get(const Evas_Object *obj,
897                             Evas_Coord *w,
898                             Evas_Coord *h)
899 {
900    ELM_SCROLLABLE_CHECK(obj);
901
902    eo_do((Eo *) obj, elm_interface_scrollable_content_size_get(w, h));
903 }
904
905 EAPI void
906 elm_scroller_page_snap_set(Evas_Object *obj,
907                              Eina_Bool page_snap_h,
908                              Eina_Bool page_snap_v)
909 {
910    ELM_SCROLLABLE_CHECK(obj);
911
912    eo_do(obj, elm_interface_scrollable_page_snap_allow_set
913          (page_snap_h, page_snap_v));
914 }
915
916 EAPI void
917 elm_scroller_page_snap_get(const Evas_Object *obj,
918                              Eina_Bool *page_snap_h,
919                              Eina_Bool *page_snap_v)
920 {
921    ELM_SCROLLABLE_CHECK(obj);
922
923    eo_do((Eo *) obj, elm_interface_scrollable_page_snap_allow_get
924          (page_snap_h, page_snap_v));
925 }
926
927 EAPI void
928 elm_scroller_bounce_set(Evas_Object *obj,
929                         Eina_Bool h_bounce,
930                         Eina_Bool v_bounce)
931 {
932    ELM_SCROLLABLE_CHECK(obj);
933
934    eo_do(obj, elm_interface_scrollable_bounce_allow_set(h_bounce, v_bounce));
935 }
936
937 EAPI void
938 elm_scroller_bounce_get(const Evas_Object *obj,
939                         Eina_Bool *h_bounce,
940                         Eina_Bool *v_bounce)
941 {
942    ELM_SCROLLABLE_CHECK(obj);
943
944    eo_do((Eo *) obj, elm_interface_scrollable_bounce_allow_get(h_bounce, v_bounce));
945 }
946
947 EAPI void
948 elm_scroller_page_relative_set(Evas_Object *obj,
949                                double h_pagerel,
950                                double v_pagerel)
951 {
952    ELM_SCROLLABLE_CHECK(obj);
953
954    eo_do((Eo *)obj, elm_interface_scrollable_page_relative_set(h_pagerel, v_pagerel));
955 }
956
957 EAPI void
958 elm_scroller_page_relative_get(const Evas_Object *obj,
959                                double *h_pagerel,
960                                double *v_pagerel)
961 {
962    ELM_SCROLLABLE_CHECK(obj);
963
964    eo_do((Eo *)obj, elm_interface_scrollable_paging_get(h_pagerel, v_pagerel, NULL, NULL));
965 }
966
967 EAPI void
968 elm_scroller_page_size_set(Evas_Object *obj,
969                            Evas_Coord h_pagesize,
970                            Evas_Coord v_pagesize)
971 {
972    ELM_SCROLLABLE_CHECK(obj);
973    eo_do(obj, elm_interface_scrollable_page_size_set(h_pagesize, v_pagesize));
974 }
975
976 EOLIAN static void
977 _elm_scroller_elm_interface_scrollable_page_size_set(Eo *obj, Elm_Scroller_Data *sd EINA_UNUSED, Evas_Coord h_pagesize, Evas_Coord v_pagesize)
978 {
979    double pagerel_h = 0.0, pagerel_v = 0.0;
980
981    eo_do(obj, elm_interface_scrollable_paging_get(&pagerel_h, &pagerel_v, NULL, NULL));
982
983    eo_do(obj, elm_interface_scrollable_paging_set(pagerel_h, pagerel_v, h_pagesize, v_pagesize));
984 }
985
986 EAPI void
987 elm_scroller_page_size_get(const Evas_Object *obj,
988                            Evas_Coord *h_pagesize,
989                            Evas_Coord *v_pagesize)
990 {
991    ELM_SCROLLABLE_CHECK(obj);
992
993    eo_do((Eo *)obj, elm_interface_scrollable_paging_get(NULL, NULL, h_pagesize, v_pagesize));
994 }
995
996 EOLIAN static void
997 _elm_scroller_page_scroll_limit_set(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED, int page_limit_h, int page_limit_v)
998 {
999    if (page_limit_h < 1)
1000      page_limit_h = 9999;
1001    if (page_limit_v < 1)
1002      page_limit_v = 9999;
1003
1004    eo_do(obj, elm_interface_scrollable_page_scroll_limit_set
1005          (page_limit_h, page_limit_v));
1006 }
1007
1008 EOLIAN static void
1009 _elm_scroller_page_scroll_limit_get(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED, int *page_limit_h, int *page_limit_v)
1010 {
1011    eo_do(obj, elm_interface_scrollable_page_scroll_limit_get
1012          (page_limit_h, page_limit_v));
1013 }
1014
1015 EAPI void
1016 elm_scroller_current_page_get(const Evas_Object *obj,
1017                               int *h_pagenumber,
1018                               int *v_pagenumber)
1019 {
1020    ELM_SCROLLABLE_CHECK(obj);
1021
1022    eo_do((Eo *) obj, elm_interface_scrollable_current_page_get(h_pagenumber, v_pagenumber));
1023 }
1024
1025 EAPI void
1026 elm_scroller_last_page_get(const Evas_Object *obj,
1027                            int *h_pagenumber,
1028                            int *v_pagenumber)
1029 {
1030    ELM_SCROLLABLE_CHECK(obj);
1031
1032    eo_do((Eo *) obj, elm_interface_scrollable_last_page_get(h_pagenumber, v_pagenumber));
1033 }
1034
1035 EAPI void
1036 elm_scroller_page_show(Evas_Object *obj,
1037                        int h_pagenumber,
1038                        int v_pagenumber)
1039 {
1040    ELM_SCROLLABLE_CHECK(obj);
1041
1042    eo_do(obj, elm_interface_scrollable_page_show(h_pagenumber, v_pagenumber));
1043 }
1044
1045 EAPI void
1046 elm_scroller_page_bring_in(Evas_Object *obj,
1047                            int h_pagenumber,
1048                            int v_pagenumber)
1049 {
1050    ELM_SCROLLABLE_CHECK(obj);
1051
1052    eo_do(obj, elm_interface_scrollable_page_bring_in(h_pagenumber, v_pagenumber));
1053 }
1054
1055 EAPI void
1056 elm_scroller_region_bring_in(Evas_Object *obj,
1057                              Evas_Coord x,
1058                              Evas_Coord y,
1059                              Evas_Coord w,
1060                              Evas_Coord h)
1061 {
1062    ELM_SCROLLABLE_CHECK(obj);
1063
1064    eo_do(obj, elm_interface_scrollable_region_bring_in(x, y, w, h));
1065 }
1066
1067 EAPI void
1068 elm_scroller_gravity_set(Evas_Object *obj,
1069                          double x,
1070                          double y)
1071 {
1072    ELM_SCROLLABLE_CHECK(obj);
1073
1074    eo_do(obj, elm_interface_scrollable_gravity_set(x, y));
1075 }
1076
1077 EAPI void
1078 elm_scroller_gravity_get(const Evas_Object *obj,
1079                          double *x,
1080                          double *y)
1081 {
1082    ELM_SCROLLABLE_CHECK(obj);
1083
1084    eo_do((Eo *) obj, elm_interface_scrollable_gravity_get(x, y));
1085 }
1086
1087 EAPI void
1088 elm_scroller_movement_block_set(Evas_Object *obj,
1089                                 Elm_Scroller_Movement_Block block)
1090 {
1091    ELM_SCROLLABLE_CHECK(obj);
1092
1093    eo_do(obj, elm_interface_scrollable_movement_block_set(block));
1094 }
1095
1096 EAPI Elm_Scroller_Movement_Block
1097 elm_scroller_movement_block_get(const Evas_Object *obj)
1098 {
1099    Elm_Scroller_Movement_Block block = ELM_SCROLLER_MOVEMENT_NO_BLOCK;
1100
1101    ELM_SCROLLABLE_CHECK(obj, ELM_SCROLLER_MOVEMENT_NO_BLOCK);
1102
1103    eo_do((Eo *) obj, block = elm_interface_scrollable_movement_block_get());
1104
1105    return block;
1106 }
1107
1108 EAPI void
1109 elm_scroller_step_size_set(Evas_Object *obj,
1110                            Evas_Coord x,
1111                            Evas_Coord y)
1112 {
1113    ELM_SCROLLABLE_CHECK(obj);
1114
1115    eo_do(obj, elm_interface_scrollable_step_size_set(x, y));
1116 }
1117
1118 EAPI void
1119 elm_scroller_step_size_get(const Evas_Object *obj,
1120                            Evas_Coord *x,
1121                            Evas_Coord *y)
1122 {
1123    ELM_SCROLLABLE_CHECK(obj);
1124
1125    eo_do((Eo *) obj, elm_interface_scrollable_step_size_get(x, y));
1126 }
1127
1128 EOLIAN static void
1129 _elm_scroller_propagate_events_set(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED, Eina_Bool propagation)
1130 {
1131    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1132
1133    evas_object_propagate_events_set(wd->resize_obj, propagation);
1134 }
1135
1136 EOLIAN static Eina_Bool
1137 _elm_scroller_propagate_events_get(Eo *obj, Elm_Scroller_Data *_pd EINA_UNUSED)
1138 {
1139    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
1140    return evas_object_propagate_events_get(wd->resize_obj);
1141 }
1142
1143 static void
1144 _elm_scroller_class_constructor(Eo_Class *klass)
1145 {
1146    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1147 }
1148
1149 EOLIAN const Elm_Atspi_Action *
1150 _elm_scroller_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Scroller_Data *pd EINA_UNUSED)
1151 {
1152    static Elm_Atspi_Action atspi_actions[] = {
1153           { "move,prior", "move", "prior", _key_action_move},
1154           { "move,next", "move", "next", _key_action_move},
1155           { "move,left", "move", "left", _key_action_move},
1156           { "move,right", "move", "right", _key_action_move},
1157           { "move,up", "move", "up", _key_action_move},
1158           { "move,down", "move", "down", _key_action_move},
1159           { "move,first", "move", "first", _key_action_move},
1160           { "move,last", "move", "last", _key_action_move},
1161           { NULL, NULL, NULL, NULL }
1162    };
1163    return &atspi_actions[0];
1164 }
1165
1166 #include "elm_scroller.eo.c"