merge with master
[framework/uifw/elementary.git] / src / lib / elm_scroller.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_scroller.h"
4 EAPI const char ELM_SCROLLER_SMART_NAME[] = "elm_scroller";
5
6 static const char SIG_SCROLL[] = "scroll";
7 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
8 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
9 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
10 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
11 static const char SIG_EDGE_LEFT[] = "edge,left";
12 static const char SIG_EDGE_RIGHT[] = "edge,right";
13 static const char SIG_EDGE_TOP[] = "edge,top";
14 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
15 static const char SIG_VBAR_DRAG[] = "vbar,drag";
16 static const char SIG_VBAR_PRESS[] = "vbar,press";
17 static const char SIG_VBAR_UNPRESS[] = "vbar,unpress";
18 static const char SIG_HBAR_DRAG[] = "hbar,drag";
19 static const char SIG_HBAR_PRESS[] = "hbar,press";
20 static const char SIG_HBAR_UNPRESS[] = "hbar,unpress";
21 static const Evas_Smart_Cb_Description _smart_callbacks[] =
22 {
23    {SIG_SCROLL, ""},
24    {SIG_SCROLL_ANIM_START, ""},
25    {SIG_SCROLL_ANIM_STOP, ""},
26    {SIG_SCROLL_DRAG_START, ""},
27    {SIG_SCROLL_DRAG_STOP, ""},
28    {SIG_EDGE_LEFT, ""},
29    {SIG_EDGE_RIGHT, ""},
30    {SIG_EDGE_TOP, ""},
31    {SIG_EDGE_BOTTOM, ""},
32    {SIG_VBAR_DRAG, ""},
33    {SIG_VBAR_PRESS, ""},
34    {SIG_VBAR_UNPRESS, ""},
35    {SIG_HBAR_DRAG, ""},
36    {SIG_HBAR_PRESS, ""},
37    {SIG_HBAR_UNPRESS, ""},
38    {NULL, NULL}
39 };
40
41 static const Evas_Smart_Interface *_smart_interfaces[] =
42 {
43    (Evas_Smart_Interface *)&ELM_SCROLLABLE_IFACE, NULL
44 };
45
46 EVAS_SMART_SUBCLASS_IFACE_NEW
47   (ELM_SCROLLER_SMART_NAME, _elm_scroller, Elm_Scroller_Smart_Class,
48   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks,
49   _smart_interfaces);
50
51 static Eina_Bool
52 _elm_scroller_smart_event(Evas_Object *obj,
53                           Evas_Object *src __UNUSED__,
54                           Evas_Callback_Type type,
55                           void *event_info)
56 {
57    Evas_Coord x = 0;
58    Evas_Coord y = 0;
59    Evas_Coord c_x = 0;
60    Evas_Coord c_y = 0;
61    Evas_Coord v_w = 0;
62    Evas_Coord v_h = 0;
63    Evas_Coord max_x = 0;
64    Evas_Coord max_y = 0;
65    Evas_Coord page_x = 0;
66    Evas_Coord page_y = 0;
67    Evas_Coord step_x = 0;
68    Evas_Coord step_y = 0;
69    Evas_Event_Key_Down *ev = event_info;
70
71    ELM_SCROLLER_DATA_GET(obj, sd);
72
73    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
74    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
75    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
76
77    sd->s_iface->content_pos_get(obj, &x, &y);
78    sd->s_iface->step_size_get(obj, &step_x, &step_y);
79    sd->s_iface->page_size_get(obj, &page_x, &page_y);
80    sd->s_iface->content_viewport_size_get(obj, &v_w, &v_h);
81    evas_object_geometry_get(sd->content, &c_x, &c_y, &max_x, &max_y);
82
83    if (((!strcmp(ev->keyname, "Left")) ||
84         (!strcmp(ev->keyname, "KP_Left")) ||
85         (!strcmp(ev->keyname, "Right")) ||
86         (!strcmp(ev->keyname, "KP_Right")) ||
87         (!strcmp(ev->keyname, "Up")) ||
88         (!strcmp(ev->keyname, "KP_Up")) ||
89         (!strcmp(ev->keyname, "Down")) ||
90         (!strcmp(ev->keyname, "KP_Down"))) && (!ev->string))
91      {
92         Evas_Object *current_focus = NULL;
93         Eina_List *can_focus_list = NULL;
94         Evas_Object *new_focus = NULL;
95         Evas_Coord f_x = 0;
96         Evas_Coord f_y = 0;
97         Evas_Coord f_w = 0;
98         Evas_Coord f_h = 0;
99
100         current_focus = elm_widget_focused_object_get(obj);
101         evas_object_geometry_get(current_focus, &f_x, &f_y, &f_w, &f_h);
102         can_focus_list = elm_widget_can_focus_child_list_get(obj);
103         if ((current_focus == obj) ||
104             (!ELM_RECTS_INTERSECT
105                (x, y, v_w, v_h, (f_x - c_x), (f_y - c_y), f_w, f_h)))
106           {
107              Eina_List *l;
108              Evas_Object *cur;
109              double weight = 0.0;
110
111              EINA_LIST_FOREACH(can_focus_list, l, cur)
112                {
113                   double cur_weight = 0.0;
114
115                   evas_object_geometry_get(cur, &f_x, &f_y, &f_w, &f_h);
116                   if (ELM_RECTS_INTERSECT
117                         (x, y, v_w, v_h, (f_x - c_x), (f_y - c_y), f_w, f_h))
118                     {
119                        if ((f_x - c_x) > x)
120                          cur_weight += ((f_x - c_x) - x) * ((f_x - c_x) - x);
121                        if ((f_y - c_y) > y)
122                          cur_weight += ((f_y - c_y) - y) * ((f_y - c_y) - y);
123                        if (cur_weight == 0.0)
124                          {
125                             elm_widget_focus_steal(cur);
126                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
127                             return EINA_TRUE;
128                          }
129                        cur_weight = 1.0 / cur_weight;
130                        if (cur_weight > weight)
131                          {
132                             new_focus = cur;
133                             weight = cur_weight;
134                          }
135                     }
136                }
137              if (new_focus)
138                {
139                   elm_widget_focus_steal(new_focus);
140                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
141                   return EINA_TRUE;
142                }
143           }
144         else
145           {
146              Evas_Object *tmp = NULL;
147              double degree = 0.0, weight = 0.0;
148              void *(*list_data_get)(const Eina_List *list);
149
150              list_data_get = eina_list_data_get;
151
152              if ((!strcmp(ev->keyname, "Left")) ||
153                  (!strcmp(ev->keyname, "KP_Left")))
154                degree = 270.0;
155              else if ((!strcmp(ev->keyname, "Right")) ||
156                       (!strcmp(ev->keyname, "KP_Right")))
157                degree = 90.0;
158              else if ((!strcmp(ev->keyname, "Up")) ||
159                       (!strcmp(ev->keyname, "KP_Up")))
160                degree = 0.0;
161              else if ((!strcmp(ev->keyname, "Down")) ||
162                       (!strcmp(ev->keyname, "KP_Down")))
163                degree = 180.0;
164
165              if (elm_widget_focus_list_direction_get
166                    (obj, current_focus, can_focus_list, list_data_get, degree,
167                    &tmp, &weight))
168                new_focus = tmp;
169
170              if (new_focus)
171                {
172                   Evas_Coord l_x = 0;
173                   Evas_Coord l_y = 0;
174                   Evas_Coord l_w = 0;
175                   Evas_Coord l_h = 0;
176
177                   evas_object_geometry_get(new_focus, &f_x, &f_y, &f_w, &f_h);
178                   l_x = f_x - c_x - step_x;
179                   l_y = f_y - c_y - step_y;
180                   l_w = f_w + (step_x * 2);
181                   l_h = f_h + (step_y * 2);
182
183                   if (ELM_RECTS_INTERSECT(x, y, v_w, v_h, l_x, l_y, l_w, l_h))
184                     {
185                        elm_widget_focus_steal(new_focus);
186                        ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
187                        return EINA_TRUE;
188                     }
189                }
190           }
191      }
192    if ((!strcmp(ev->keyname, "Left")) ||
193        ((!strcmp(ev->keyname, "KP_Left")) && (!ev->string)))
194      {
195         if (x <= 0) return EINA_FALSE;
196         x -= step_x;
197      }
198    else if ((!strcmp(ev->keyname, "Right")) ||
199             ((!strcmp(ev->keyname, "KP_Right")) && (!ev->string)))
200      {
201         if (x >= (max_x - v_w)) return EINA_FALSE;
202         x += step_x;
203      }
204    else if ((!strcmp(ev->keyname, "Up")) ||
205             ((!strcmp(ev->keyname, "KP_Up")) && (!ev->string)))
206      {
207         if (y == 0) return EINA_FALSE;
208         y -= step_y;
209      }
210    else if ((!strcmp(ev->keyname, "Down")) ||
211             ((!strcmp(ev->keyname, "KP_Down")) && (!ev->string)))
212      {
213         if (y >= (max_y - v_h)) return EINA_FALSE;
214         y += step_y;
215      }
216    else if ((!strcmp(ev->keyname, "Home")) ||
217             ((!strcmp(ev->keyname, "KP_Home")) && (!ev->string)))
218      {
219         y = 0;
220      }
221    else if ((!strcmp(ev->keyname, "End")) ||
222             ((!strcmp(ev->keyname, "KP_End")) && (!ev->string)))
223      {
224         y = max_y - v_h;
225      }
226    else if ((!strcmp(ev->keyname, "Prior")) ||
227             ((!strcmp(ev->keyname, "KP_Prior")) && (!ev->string)))
228      {
229         if (page_y < 0)
230           y -= -(page_y * v_h) / 100;
231         else
232           y -= page_y;
233      }
234    else if ((!strcmp(ev->keyname, "Next")) ||
235             ((!strcmp(ev->keyname, "KP_Next")) && (!ev->string)))
236      {
237         if (page_y < 0)
238           y += -(page_y * v_h) / 100;
239         else
240           y += page_y;
241      }
242    else return EINA_FALSE;
243
244    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
245    sd->s_iface->content_pos_set(obj, x, y, EINA_TRUE);
246
247    return EINA_TRUE;
248 }
249
250 static Eina_Bool
251 _elm_scroller_smart_activate(Evas_Object *obj, Elm_Activate act)
252 {
253    Evas_Coord x = 0;
254    Evas_Coord y = 0;
255    Evas_Coord v_w = 0;
256    Evas_Coord v_h = 0;
257    Evas_Coord page_x = 0;
258    Evas_Coord page_y = 0;
259
260    ELM_SCROLLER_DATA_GET(obj, sd);
261
262    if ((elm_widget_disabled_get(obj)) ||
263        (act == ELM_ACTIVATE_DEFAULT)) return EINA_FALSE;
264
265    sd->s_iface->content_pos_get(obj, &x, &y);
266    sd->s_iface->page_size_get(obj, &page_x, &page_y);
267    sd->s_iface->content_viewport_size_get(obj, &v_w, &v_h);
268
269    if (act == ELM_ACTIVATE_UP)
270      {
271         if (page_y < 0)
272           y -= -(page_y * v_h) / 100;
273         else
274           y -= page_y;
275      }
276    else if (act == ELM_ACTIVATE_DOWN)
277      {
278         if (page_y < 0)
279           y += -(page_y * v_h) / 100;
280         else
281           y += page_y;
282      }
283    else if (act == ELM_ACTIVATE_LEFT)
284      {
285         if (page_x < 0)
286           x -= -(page_x * v_w) / 100;
287         else
288           x -= page_x;
289      }
290    else if (act == ELM_ACTIVATE_RIGHT)
291      {
292         if (page_x < 0)
293           x += -(page_x * v_w) / 100;
294         else
295           x += page_x;
296      }
297
298    sd->s_iface->content_pos_set(obj, x, y, EINA_TRUE);
299    return EINA_TRUE;
300 }
301
302 static void
303 _elm_scroller_smart_sizing_eval(Evas_Object *obj)
304 {
305    Evas_Coord vw = 0, vh = 0, minw = 0, minh = 0, maxw = 0, maxh = 0, w, h,
306               vmw, vmh;
307    double xw = 0.0, yw = 0.0;
308
309    ELM_SCROLLER_DATA_GET(obj, sd);
310
311    /* parent class' early call */
312    if (!sd->s_iface) return;
313
314    if (sd->content)
315      {
316         evas_object_size_hint_min_get(sd->content, &minw, &minh);
317         evas_object_size_hint_max_get(sd->content, &maxw, &maxh);
318         evas_object_size_hint_weight_get(sd->content, &xw, &yw);
319      }
320
321    sd->s_iface->content_viewport_size_get(obj, &vw, &vh);
322    if (xw > 0.0)
323      {
324         if ((minw > 0) && (vw < minw))
325           vw = minw;
326         else if ((maxw > 0) && (vw > maxw))
327           vw = maxw;
328      }
329    else if (minw > 0)
330      vw = minw;
331
332    if (yw > 0.0)
333      {
334         if ((minh > 0) && (vh < minh))
335           vh = minh;
336         else if ((maxh > 0) && (vh > maxh))
337           vh = maxh;
338      }
339    else if (minh > 0)
340      vh = minh;
341
342    if (sd->content) evas_object_resize(sd->content, vw, vh);
343
344    w = -1;
345    h = -1;
346    edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &vmw, &vmh);
347
348    if (sd->min_w) w = vmw + minw;
349    if (sd->min_h) h = vmh + minh;
350
351    evas_object_size_hint_max_get(obj, &maxw, &maxh);
352    if ((maxw > 0) && (w > maxw)) w = maxw;
353    if ((maxh > 0) && (h > maxh)) h = maxh;
354
355    evas_object_size_hint_min_set(obj, w, h);
356 }
357
358 static void
359 _mirrored_set(Evas_Object *obj,
360               Eina_Bool mirrored)
361 {
362    ELM_SCROLLER_DATA_GET(obj, sd);
363
364    sd->s_iface->mirrored_set(obj, mirrored);
365 }
366
367 static Eina_Bool
368 _elm_scroller_smart_theme(Evas_Object *obj)
369 {
370    if (!ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->theme(obj))
371      return EINA_FALSE;
372
373    _mirrored_set(obj, elm_widget_mirrored_get(obj));
374
375    elm_layout_sizing_eval(obj);
376
377    return EINA_TRUE;
378 }
379
380 static Eina_Bool
381 _elm_scroller_smart_focus_next(const Evas_Object *obj,
382                                Elm_Focus_Direction dir,
383                                Evas_Object **next)
384 {
385    Evas_Object *cur;
386
387    ELM_SCROLLER_DATA_GET(obj, sd);
388
389    if (!sd->content) return EINA_FALSE;
390
391    cur = sd->content;
392
393    /* access */
394    if (_elm_config->access_mode)
395      {
396         if ((elm_widget_can_focus_get(cur)) ||
397             (elm_widget_child_can_focus_get(cur)))
398           return elm_widget_focus_next_get(cur, dir, next);
399
400         return EINA_FALSE;
401      }
402
403    /* Try focus cycle in subitem */
404    if (elm_widget_focus_get(obj))
405      {
406         if ((elm_widget_can_focus_get(cur)) ||
407             (elm_widget_child_can_focus_get(cur)))
408           return elm_widget_focus_next_get(cur, dir, next);
409      }
410
411    /* Return */
412    *next = (Evas_Object *)obj;
413
414    return !elm_widget_focus_get(obj);
415 }
416
417 static void
418 _show_region_hook(void *data,
419                   Evas_Object *content_obj)
420 {
421    Evas_Coord x, y, w, h;
422
423    ELM_SCROLLER_DATA_GET(data, sd);
424
425    elm_widget_show_region_get(content_obj, &x, &y, &w, &h);
426    sd->s_iface->content_region_show(data, x, y, w, h);
427 }
428
429 static void
430 _changed_size_hints_cb(void *data,
431                        Evas *e __UNUSED__,
432                        Evas_Object *obj __UNUSED__,
433                        void *event_info __UNUSED__)
434 {
435    elm_layout_sizing_eval(data);
436 }
437
438 static Eina_Bool
439 _elm_scroller_smart_sub_object_del(Evas_Object *obj,
440                                    Evas_Object *sobj)
441 {
442    ELM_SCROLLER_DATA_GET(obj, sd);
443
444    if (!ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->sub_object_del(obj, sobj))
445      return EINA_FALSE;
446
447    if (sobj == sd->content)
448      {
449         elm_widget_on_show_region_hook_set(sd->content, NULL, NULL);
450
451         sd->content = NULL;
452      }
453
454    return EINA_TRUE;
455 }
456
457 static void
458 _resize_cb(void *data,
459            Evas *e __UNUSED__,
460            Evas_Object *obj __UNUSED__,
461            void *event_info __UNUSED__)
462 {
463    elm_layout_sizing_eval(data);
464 }
465
466 static void
467 _edge_left_cb(Evas_Object *obj,
468               void *data __UNUSED__)
469 {
470    evas_object_smart_callback_call(obj, SIG_EDGE_LEFT, NULL);
471 }
472
473 static void
474 _edge_right_cb(Evas_Object *obj,
475                void *data __UNUSED__)
476 {
477    evas_object_smart_callback_call(obj, SIG_EDGE_RIGHT, NULL);
478 }
479
480 static void
481 _edge_top_cb(Evas_Object *obj,
482              void *data __UNUSED__)
483 {
484    evas_object_smart_callback_call(obj, SIG_EDGE_TOP, NULL);
485 }
486
487 static void
488 _edge_bottom_cb(Evas_Object *obj,
489                 void *data __UNUSED__)
490 {
491    evas_object_smart_callback_call(obj, SIG_EDGE_BOTTOM, NULL);
492 }
493
494 static void
495 _vbar_drag_cb(Evas_Object *obj,
496                 void *data __UNUSED__)
497 {
498    evas_object_smart_callback_call(obj, SIG_VBAR_DRAG, NULL);
499 }
500
501 static void
502 _vbar_press_cb(Evas_Object *obj,
503                 void *data __UNUSED__)
504 {
505    evas_object_smart_callback_call(obj, SIG_VBAR_PRESS, NULL);
506 }
507
508 static void
509 _vbar_unpress_cb(Evas_Object *obj,
510                 void *data __UNUSED__)
511 {
512    evas_object_smart_callback_call(obj, SIG_VBAR_UNPRESS, NULL);
513 }
514
515 static void
516 _hbar_drag_cb(Evas_Object *obj,
517                 void *data __UNUSED__)
518 {
519    evas_object_smart_callback_call(obj, SIG_HBAR_DRAG, NULL);
520 }
521
522 static void
523 _hbar_press_cb(Evas_Object *obj,
524                 void *data __UNUSED__)
525 {
526    evas_object_smart_callback_call(obj, SIG_HBAR_PRESS, NULL);
527 }
528
529 static void
530 _hbar_unpress_cb(Evas_Object *obj,
531                 void *data __UNUSED__)
532 {
533    evas_object_smart_callback_call(obj, SIG_HBAR_UNPRESS, NULL);
534 }
535
536 static void
537 _scroll_cb(Evas_Object *obj,
538            void *data __UNUSED__)
539 {
540    evas_object_smart_callback_call(obj, SIG_SCROLL, NULL);
541 }
542
543 static void
544 _scroll_anim_start_cb(Evas_Object *obj,
545                       void *data __UNUSED__)
546 {
547    evas_object_smart_callback_call(obj, SIG_SCROLL_ANIM_START, NULL);
548 }
549
550 static void
551 _scroll_anim_stop_cb(Evas_Object *obj,
552                      void *data __UNUSED__)
553 {
554    evas_object_smart_callback_call(obj, SIG_SCROLL_ANIM_STOP, NULL);
555 }
556
557 static void
558 _scroll_drag_start_cb(Evas_Object *obj,
559                       void *data __UNUSED__)
560 {
561    evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_START, NULL);
562 }
563
564 static void
565 _scroll_drag_stop_cb(Evas_Object *obj,
566                      void *data __UNUSED__)
567 {
568    evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_STOP, NULL);
569 }
570
571 static Eina_Bool
572 _elm_scroller_smart_content_set(Evas_Object *obj,
573                                 const char *part,
574                                 Evas_Object *content)
575 {
576    ELM_SCROLLER_DATA_GET(obj, sd);
577
578    if (part && strcmp(part, "default"))
579      return ELM_CONTAINER_CLASS
580               (_elm_scroller_parent_sc)->content_set(obj, part, content);
581
582    if (sd->content == content) return EINA_TRUE;
583
584    if (sd->content) evas_object_del(sd->content);
585    sd->content = content;
586
587    if (content)
588      {
589         elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
590         elm_widget_sub_object_add(obj, content);
591
592         sd->s_iface->content_set(obj, content);
593      }
594
595    elm_layout_sizing_eval(obj);
596
597    return EINA_TRUE;
598 }
599
600 static Evas_Object *
601 _elm_scroller_smart_content_get(const Evas_Object *obj,
602                                 const char *part)
603 {
604    ELM_SCROLLER_DATA_GET(obj, sd);
605
606    if (part && strcmp(part, "default"))
607      return ELM_CONTAINER_CLASS
608               (_elm_scroller_parent_sc)->content_get(obj, part);
609
610    return sd->content;
611 }
612
613 static Evas_Object *
614 _elm_scroller_smart_content_unset(Evas_Object *obj,
615                                   const char *part)
616 {
617    Evas_Object *content;
618
619    ELM_SCROLLER_DATA_GET(obj, sd);
620
621    if (part && strcmp(part, "default"))
622      return ELM_CONTAINER_CLASS
623               (_elm_scroller_parent_sc)->content_unset(obj, part);
624
625    if (!sd->content) return NULL;
626
627    content = sd->content;
628    elm_widget_sub_object_del(obj, sd->content);
629    sd->s_iface->content_set(obj, NULL);
630    sd->content = NULL;
631
632    return content;
633 }
634
635 static void
636 _elm_scroller_content_min_limit_cb(Evas_Object *obj,
637                                    Eina_Bool w,
638                                    Eina_Bool h)
639 {
640    ELM_SCROLLER_DATA_GET(obj, sd);
641
642    sd->min_w = !!w;
643    sd->min_h = !!h;
644
645    elm_layout_sizing_eval(obj);
646 }
647
648 static void
649 _elm_scroller_smart_add(Evas_Object *obj)
650 {
651    Evas_Coord minw, minh;
652
653    EVAS_SMART_DATA_ALLOC(obj, Elm_Scroller_Smart_Data);
654
655    ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.add(obj);
656
657    elm_widget_can_focus_set(obj, EINA_TRUE);
658
659    elm_layout_theme_set(obj, "scroller", "base", elm_widget_style_get(obj));
660
661    priv->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
662    evas_object_smart_member_add(priv->hit_rect, obj);
663    elm_widget_sub_object_add(obj, priv->hit_rect);
664
665    evas_object_color_set(priv->hit_rect, 0, 0, 0, 0);
666    evas_object_show(priv->hit_rect);
667    evas_object_repeat_events_set(priv->hit_rect, EINA_TRUE);
668
669    priv->s_iface = evas_object_smart_interface_get
670        (obj, ELM_SCROLLABLE_IFACE_NAME);
671
672    priv->s_iface->objects_set
673      (obj, ELM_WIDGET_DATA(priv)->resize_obj, priv->hit_rect);
674
675    evas_object_event_callback_add
676      (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints_cb, obj);
677
678    edje_object_size_min_calc(ELM_WIDGET_DATA(priv)->resize_obj, &minw, &minh);
679    evas_object_size_hint_min_set(obj, minw, minh);
680    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
681
682    priv->s_iface->edge_left_cb_set(obj, _edge_left_cb);
683    priv->s_iface->edge_right_cb_set(obj, _edge_right_cb);
684    priv->s_iface->edge_top_cb_set(obj, _edge_top_cb);
685    priv->s_iface->edge_bottom_cb_set(obj, _edge_bottom_cb);
686    priv->s_iface->vbar_drag_cb_set(obj, _vbar_drag_cb);
687    priv->s_iface->vbar_press_cb_set(obj, _vbar_press_cb);
688    priv->s_iface->vbar_unpress_cb_set(obj, _vbar_unpress_cb);
689    priv->s_iface->hbar_drag_cb_set(obj, _hbar_drag_cb);
690    priv->s_iface->hbar_press_cb_set(obj, _hbar_press_cb);
691    priv->s_iface->hbar_unpress_cb_set(obj, _hbar_unpress_cb);
692    priv->s_iface->scroll_cb_set(obj, _scroll_cb);
693    priv->s_iface->animate_start_cb_set(obj, _scroll_anim_start_cb);
694    priv->s_iface->animate_stop_cb_set(obj, _scroll_anim_stop_cb);
695    priv->s_iface->drag_start_cb_set(obj, _scroll_drag_start_cb);
696    priv->s_iface->drag_stop_cb_set(obj, _scroll_drag_stop_cb);
697
698    priv->s_iface->content_min_limit_cb_set
699      (obj, _elm_scroller_content_min_limit_cb);
700 }
701
702 static void
703 _elm_scroller_smart_move(Evas_Object *obj,
704                          Evas_Coord x,
705                          Evas_Coord y)
706 {
707    ELM_SCROLLER_DATA_GET(obj, sd);
708
709    ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.move(obj, x, y);
710
711    evas_object_move(sd->hit_rect, x, y);
712 }
713
714 static void
715 _elm_scroller_smart_resize(Evas_Object *obj,
716                            Evas_Coord w,
717                            Evas_Coord h)
718 {
719    ELM_SCROLLER_DATA_GET(obj, sd);
720
721    ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.resize(obj, w, h);
722
723    evas_object_resize(sd->hit_rect, w, h);
724 }
725
726 static void
727 _elm_scroller_smart_member_add(Evas_Object *obj,
728                                Evas_Object *member)
729 {
730    ELM_SCROLLER_DATA_GET(obj, sd);
731
732    ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.member_add(obj, member);
733
734    if (sd->hit_rect)
735      evas_object_raise(sd->hit_rect);
736 }
737
738 static void
739 _elm_scroller_smart_set_user(Elm_Scroller_Smart_Class *sc)
740 {
741    ELM_WIDGET_CLASS(sc)->base.add = _elm_scroller_smart_add;
742    ELM_WIDGET_CLASS(sc)->base.move = _elm_scroller_smart_move;
743    ELM_WIDGET_CLASS(sc)->base.resize = _elm_scroller_smart_resize;
744    ELM_WIDGET_CLASS(sc)->base.member_add = _elm_scroller_smart_member_add;
745
746    ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_scroller_smart_sub_object_del;
747    ELM_WIDGET_CLASS(sc)->theme = _elm_scroller_smart_theme;
748    ELM_WIDGET_CLASS(sc)->focus_next = _elm_scroller_smart_focus_next;
749    ELM_WIDGET_CLASS(sc)->event = _elm_scroller_smart_event;
750    ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
751    ELM_WIDGET_CLASS(sc)->activate = _elm_scroller_smart_activate;
752
753    ELM_CONTAINER_CLASS(sc)->content_set = _elm_scroller_smart_content_set;
754    ELM_CONTAINER_CLASS(sc)->content_get = _elm_scroller_smart_content_get;
755    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_scroller_smart_content_unset;
756
757    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_scroller_smart_sizing_eval;
758 }
759
760 EAPI const Elm_Scroller_Smart_Class *
761 elm_scroller_smart_class_get(void)
762 {
763    static Elm_Scroller_Smart_Class _sc =
764      ELM_SCROLLER_SMART_CLASS_INIT_NAME_VERSION(ELM_SCROLLER_SMART_NAME);
765    static const Elm_Scroller_Smart_Class *class = NULL;
766    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
767
768    if (class)
769      return class;
770
771    _elm_scroller_smart_set(&_sc);
772    esc->callbacks = _smart_callbacks;
773    class = &_sc;
774
775    return class;
776 }
777
778 EAPI Evas_Object *
779 elm_scroller_add(Evas_Object *parent)
780 {
781    Evas *e;
782    Evas_Object *obj;
783
784    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
785
786    e = evas_object_evas_get(parent);
787    if (!e) return NULL;
788
789    obj = evas_object_smart_add(e, _elm_scroller_smart_class_new());
790
791    if (!elm_widget_sub_object_add(parent, obj))
792      ERR("could not add %p as sub object of %p", obj, parent);
793
794    return obj;
795 }
796
797 /* deprecated */
798 EAPI void
799 elm_scroller_custom_widget_base_theme_set(Evas_Object *obj,
800                                           const char *klass,
801                                           const char *group)
802 {
803    ELM_SCROLLER_CHECK(obj);
804    ELM_SCROLLER_DATA_GET(obj, sd);
805
806    EINA_SAFETY_ON_NULL_RETURN(klass);
807    EINA_SAFETY_ON_NULL_RETURN(group);
808
809    if (eina_stringshare_replace(&(ELM_LAYOUT_DATA(sd)->klass), klass) ||
810        eina_stringshare_replace(&(ELM_LAYOUT_DATA(sd)->group), group))
811      _elm_scroller_smart_theme(obj);
812 }
813
814 EAPI void
815 elm_scroller_content_min_limit(Evas_Object *obj,
816                                Eina_Bool w,
817                                Eina_Bool h)
818 {
819    ELM_SCROLLABLE_CHECK(obj);
820
821    s_iface->content_min_limit(obj, w, h);
822 }
823
824 EAPI void
825 elm_scroller_region_show(Evas_Object *obj,
826                          Evas_Coord x,
827                          Evas_Coord y,
828                          Evas_Coord w,
829                          Evas_Coord h)
830 {
831    ELM_SCROLLABLE_CHECK(obj);
832
833    s_iface->content_region_show(obj, x, y, w, h);
834 }
835
836 EAPI void
837 elm_scroller_policy_set(Evas_Object *obj,
838                         Elm_Scroller_Policy policy_h,
839                         Elm_Scroller_Policy policy_v)
840 {
841    ELM_SCROLLABLE_CHECK(obj);
842
843    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
844        (policy_v >= ELM_SCROLLER_POLICY_LAST))
845      return;
846
847    s_iface->policy_set(obj, policy_h, policy_v);
848 }
849
850 EAPI void
851 elm_scroller_policy_get(const Evas_Object *obj,
852                         Elm_Scroller_Policy *policy_h,
853                         Elm_Scroller_Policy *policy_v)
854 {
855    ELM_SCROLLABLE_CHECK(obj);
856
857    s_iface->policy_get(obj, policy_h, policy_v);
858 }
859
860 EAPI void
861 elm_scroller_region_get(const Evas_Object *obj,
862                         Evas_Coord *x,
863                         Evas_Coord *y,
864                         Evas_Coord *w,
865                         Evas_Coord *h)
866 {
867    ELM_SCROLLABLE_CHECK(obj);
868
869    if ((x) || (y)) s_iface->content_pos_get(obj, x, y);
870    if ((w) || (h)) s_iface->content_viewport_size_get(obj, w, h);
871 }
872
873 EAPI void
874 elm_scroller_child_size_get(const Evas_Object *obj,
875                             Evas_Coord *w,
876                             Evas_Coord *h)
877 {
878    ELM_SCROLLABLE_CHECK(obj);
879
880    s_iface->content_size_get(obj, w, h);
881 }
882
883 EAPI void
884 elm_scroller_bounce_set(Evas_Object *obj,
885                         Eina_Bool h_bounce,
886                         Eina_Bool v_bounce)
887 {
888    ELM_SCROLLABLE_CHECK(obj);
889
890    s_iface->bounce_allow_set(obj, h_bounce, v_bounce);
891 }
892
893 EAPI void
894 elm_scroller_bounce_get(const Evas_Object *obj,
895                         Eina_Bool *h_bounce,
896                         Eina_Bool *v_bounce)
897 {
898    ELM_SCROLLABLE_CHECK(obj);
899
900    s_iface->bounce_allow_get(obj, h_bounce, v_bounce);
901 }
902
903 EAPI void
904 elm_scroller_page_relative_set(Evas_Object *obj,
905                                double h_pagerel,
906                                double v_pagerel)
907 {
908    Evas_Coord pagesize_h, pagesize_v;
909
910    ELM_SCROLLABLE_CHECK(obj);
911
912    s_iface->paging_get(obj, NULL, NULL, &pagesize_h, &pagesize_v);
913
914    s_iface->paging_set
915      (obj, h_pagerel, v_pagerel, pagesize_h, pagesize_v);
916 }
917
918 EAPI void
919 elm_scroller_page_relative_get(const Evas_Object *obj,
920                                double *h_pagerel,
921                                double *v_pagerel)
922 {
923    ELM_SCROLLABLE_CHECK(obj);
924
925    s_iface->paging_get(obj, h_pagerel, v_pagerel, NULL, NULL);
926 }
927
928 EAPI void
929 elm_scroller_page_size_set(Evas_Object *obj,
930                            Evas_Coord h_pagesize,
931                            Evas_Coord v_pagesize)
932 {
933    double pagerel_h, pagerel_v;
934
935    ELM_SCROLLABLE_CHECK(obj);
936
937    s_iface->paging_get(obj, &pagerel_h, &pagerel_v, NULL, NULL);
938
939    s_iface->paging_set
940      (obj, pagerel_h, pagerel_v, h_pagesize, v_pagesize);
941 }
942
943 EAPI void
944 elm_scroller_page_size_get(const Evas_Object *obj,
945                            Evas_Coord *h_pagesize,
946                            Evas_Coord *v_pagesize)
947 {
948    ELM_SCROLLABLE_CHECK(obj);
949
950    s_iface->paging_get(obj, NULL, NULL, h_pagesize, v_pagesize);
951 }
952
953 EAPI void
954 elm_scroller_current_page_get(const Evas_Object *obj,
955                               int *h_pagenumber,
956                               int *v_pagenumber)
957 {
958    ELM_SCROLLABLE_CHECK(obj);
959
960    s_iface->current_page_get(obj, h_pagenumber, v_pagenumber);
961 }
962
963 EAPI void
964 elm_scroller_last_page_get(const Evas_Object *obj,
965                            int *h_pagenumber,
966                            int *v_pagenumber)
967 {
968    ELM_SCROLLABLE_CHECK(obj);
969
970    s_iface->last_page_get(obj, h_pagenumber, v_pagenumber);
971 }
972
973 EAPI void
974 elm_scroller_page_show(Evas_Object *obj,
975                        int h_pagenumber,
976                        int v_pagenumber)
977 {
978    ELM_SCROLLABLE_CHECK(obj);
979
980    s_iface->page_show(obj, h_pagenumber, v_pagenumber);
981 }
982
983 EAPI void
984 elm_scroller_page_bring_in(Evas_Object *obj,
985                            int h_pagenumber,
986                            int v_pagenumber)
987 {
988    ELM_SCROLLABLE_CHECK(obj);
989
990    s_iface->page_bring_in(obj, h_pagenumber, v_pagenumber);
991 }
992
993 EAPI void
994 elm_scroller_region_bring_in(Evas_Object *obj,
995                              Evas_Coord x,
996                              Evas_Coord y,
997                              Evas_Coord w,
998                              Evas_Coord h)
999 {
1000    ELM_SCROLLABLE_CHECK(obj);
1001
1002    s_iface->region_bring_in(obj, x, y, w, h);
1003 }
1004
1005 EAPI void
1006 elm_scroller_gravity_set(Evas_Object *obj,
1007                          double x,
1008                          double y)
1009 {
1010    ELM_SCROLLABLE_CHECK(obj);
1011
1012    s_iface->gravity_set(obj, x, y);
1013 }
1014
1015 EAPI void
1016 elm_scroller_gravity_get(const Evas_Object *obj,
1017                          double *x,
1018                          double *y)
1019 {
1020    ELM_SCROLLABLE_CHECK(obj);
1021
1022    s_iface->gravity_get(obj, x, y);
1023 }
1024
1025 EAPI void
1026 elm_scroller_propagate_events_set(Evas_Object *obj,
1027                                   Eina_Bool propagation)
1028 {
1029    Elm_Widget_Smart_Data *sd;
1030
1031    ELM_SCROLLABLE_CHECK(obj);
1032
1033    sd = evas_object_smart_data_get(obj);
1034    if (!sd) return;  /* just being paranoid */
1035
1036    evas_object_propagate_events_set(sd->resize_obj, propagation);
1037 }
1038
1039 EAPI Eina_Bool
1040 elm_scroller_propagate_events_get(const Evas_Object *obj)
1041 {
1042    Elm_Widget_Smart_Data *sd;
1043
1044    ELM_SCROLLABLE_CHECK(obj, EINA_FALSE);
1045
1046    sd = evas_object_smart_data_get(obj);
1047    if (!sd) return EINA_FALSE;  /* just being paranoid */
1048
1049    return evas_object_propagate_events_get(sd->resize_obj);
1050 }