0365eedd30fd7dc079ac2187c3717e63314bbe3e
[framework/uifw/elementary.git] / src / lib / elm_interface_scrollable.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_interface_scrollable.h"
4
5 static const char PAN_SMART_NAME[] = "elm_pan";
6
7 #define ELM_PAN_DATA_GET_OR_RETURN(o, ptr)                      \
8   Elm_Pan_Smart_Data *ptr = evas_object_smart_data_get(o);      \
9   if (!ptr)                                                     \
10     {                                                           \
11        CRITICAL("No smart data for object %p (%s)",             \
12                 o, evas_object_type_get(o));                    \
13        return;                                                  \
14     }
15
16 #define ELM_PAN_DATA_GET_OR_RETURN_VAL(o, ptr, val)             \
17   Elm_Pan_Smart_Data *ptr = evas_object_smart_data_get(o);      \
18   if (!ptr)                                                     \
19     {                                                           \
20        CRITICAL("No smart data for object %p (%s)",             \
21                 o, evas_object_type_get(o));                    \
22        return val;                                              \
23     }
24
25 static const char SIG_CHANGED[] = "changed";
26 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
27    {SIG_CHANGED, ""},
28    {NULL, NULL}
29 };
30
31 ELM_INTERNAL_SMART_SUBCLASS_NEW
32   (PAN_SMART_NAME, _elm_pan, Elm_Pan_Smart_Class, Evas_Smart_Class,
33   evas_object_smart_clipped_class_get, _smart_callbacks);
34
35 static void _elm_pan_content_set(Evas_Object *, Evas_Object *);
36
37 EAPI const Elm_Pan_Smart_Class *
38 elm_pan_smart_class_get(void)
39 {
40    static Elm_Pan_Smart_Class _sc =
41      ELM_PAN_SMART_CLASS_INIT_NAME_VERSION(PAN_SMART_NAME);
42    static const Elm_Pan_Smart_Class *class = NULL;
43    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
44
45    if (class)
46      return class;
47
48    _elm_pan_smart_set(&_sc);
49    esc->callbacks = _smart_callbacks;
50    class = &_sc;
51
52    return class;
53 }
54
55 static void
56 _elm_pan_update(Elm_Pan_Smart_Data *psd)
57 {
58    if (!psd->gravity_x && !psd->gravity_y)
59      {
60         evas_object_move(psd->content, psd->x - psd->px, psd->y - psd->py);
61         return;
62      }
63
64    if ((!psd->px) && (!psd->py))
65      {
66         psd->px = psd->delta_posx * psd->gravity_x;
67         psd->py = psd->delta_posy * psd->gravity_y;
68      }
69    psd->delta_posx += psd->content_w - psd->prev_cw;
70    psd->prev_cw = psd->content_w;
71    psd->delta_posy += psd->content_h - psd->prev_ch;
72    psd->prev_ch = psd->content_h;
73
74    evas_object_move(psd->content, psd->x - psd->px, psd->y - psd->py);
75    psd->px = psd->delta_posx * psd->gravity_x;
76    psd->py = psd->delta_posy * psd->gravity_y;
77 }
78
79 static void
80 _elm_pan_smart_add(Evas_Object *obj)
81 {
82    const Evas_Smart_Class *sc;
83    const Evas_Smart *smart;
84
85    EVAS_SMART_DATA_ALLOC(obj, Elm_Pan_Smart_Data);
86
87    _elm_pan_parent_sc->add(obj);
88
89    priv->self = obj;
90
91    priv->x = 0;
92    priv->y = 0;
93    priv->w = 0;
94    priv->h = 0;
95    priv->gravity_x = 0.0;
96    priv->gravity_y = 0.0;
97
98    smart = evas_object_smart_smart_get(obj);
99    sc = evas_smart_class_get(smart);
100    priv->api = (const Elm_Pan_Smart_Class *)sc;
101 }
102
103 static void
104 _elm_pan_smart_del(Evas_Object *obj)
105 {
106    _elm_pan_content_set(obj, NULL);
107
108    _elm_pan_parent_sc->del(obj);
109 }
110
111 static void
112 _elm_pan_smart_move(Evas_Object *obj,
113                     Evas_Coord x,
114                     Evas_Coord y)
115 {
116    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
117
118    /* we don't want the clipped smart object version here */
119
120    psd->x = x;
121    psd->y = y;
122
123    _elm_pan_update(psd);
124 }
125
126 static void
127 _elm_pan_smart_resize(Evas_Object *obj,
128                       Evas_Coord w,
129                       Evas_Coord h)
130 {
131    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
132
133    psd->w = w;
134    psd->h = h;
135
136    _elm_pan_update(psd);
137    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
138 }
139
140 static void
141 _elm_pan_smart_show(Evas_Object *obj)
142 {
143    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
144
145    _elm_pan_parent_sc->show(obj);
146
147    if (psd->content)
148      evas_object_show(psd->content);
149 }
150
151 static void
152 _elm_pan_smart_hide(Evas_Object *obj)
153 {
154    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
155
156    _elm_pan_parent_sc->hide(obj);
157
158    if (psd->content)
159      evas_object_hide(psd->content);
160 }
161
162 static void
163 _elm_pan_pos_set(Evas_Object *obj,
164                  Evas_Coord x,
165                  Evas_Coord y)
166 {
167    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
168
169    if ((x == psd->px) && (y == psd->py)) return;
170    psd->px = x;
171    psd->py = y;
172
173    _elm_pan_update(psd);
174    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
175 }
176
177 static void
178 _elm_pan_pos_get(const Evas_Object *obj,
179                  Evas_Coord *x,
180                  Evas_Coord *y)
181 {
182    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
183
184    if (x) *x = psd->px;
185    if (y) *y = psd->py;
186 }
187
188 static void
189 _elm_pan_pos_max_get(const Evas_Object *obj,
190                      Evas_Coord *x,
191                      Evas_Coord *y)
192 {
193    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
194
195    if (x)
196      {
197         if (psd->w < psd->content_w) *x = psd->content_w - psd->w;
198         else *x = 0;
199      }
200    if (y)
201      {
202         if (psd->h < psd->content_h) *y = psd->content_h - psd->h;
203         else *y = 0;
204      }
205 }
206
207 static void
208 _elm_pan_pos_min_get(const Evas_Object *obj __UNUSED__,
209                      Evas_Coord *x,
210                      Evas_Coord *y)
211 {
212    if (x)
213      *x = 0;
214    if (y)
215      *y = 0;
216 }
217
218 static void
219 _elm_pan_content_size_get(const Evas_Object *obj,
220                           Evas_Coord *w,
221                           Evas_Coord *h)
222 {
223    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
224
225    if (w) *w = psd->content_w;
226    if (h) *h = psd->content_h;
227 }
228
229 static void
230 _elm_pan_gravity_set(Evas_Object *obj,
231                      double x,
232                      double y)
233 {
234    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
235
236    psd->gravity_x = x;
237    psd->gravity_y = y;
238    psd->prev_cw = psd->content_w;
239    psd->prev_ch = psd->content_h;
240    psd->delta_posx = 0;
241    psd->delta_posy = 0;
242 }
243
244 static void
245 _elm_pan_gravity_get(const Evas_Object *obj,
246                      double *x,
247                      double *y)
248 {
249    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
250
251    if (x) *x = psd->gravity_x;
252    if (y) *y = psd->gravity_y;
253 }
254
255 static void
256 _elm_pan_smart_set_user(Elm_Pan_Smart_Class *sc)
257 {
258    sc->base.add = _elm_pan_smart_add;
259    sc->base.del = _elm_pan_smart_del;
260    sc->base.move = _elm_pan_smart_move;
261    sc->base.resize = _elm_pan_smart_resize;
262    sc->base.show = _elm_pan_smart_show;
263    sc->base.hide = _elm_pan_smart_hide;
264
265    sc->pos_set = _elm_pan_pos_set;
266    sc->pos_get = _elm_pan_pos_get;
267    sc->pos_max_get = _elm_pan_pos_max_get;
268    sc->pos_min_get = _elm_pan_pos_min_get;
269    sc->content_size_get = _elm_pan_content_size_get;
270    sc->gravity_set = _elm_pan_gravity_set;
271    sc->gravity_get = _elm_pan_gravity_get;
272 }
273
274 static Evas_Object *
275 _elm_pan_add(Evas *evas)
276 {
277    return evas_object_smart_add(evas, _elm_pan_smart_class_new());
278 }
279
280 static void
281 _elm_pan_content_del_cb(void *data,
282                         Evas *e __UNUSED__,
283                         Evas_Object *obj __UNUSED__,
284                         void *event_info __UNUSED__)
285 {
286    Elm_Pan_Smart_Data *psd;
287
288    psd = data;
289    psd->content = NULL;
290    psd->content_w = psd->content_h = psd->px = psd->py =
291            psd->prev_cw = psd->prev_ch = psd->delta_posx = psd->delta_posy = 0;
292    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
293 }
294
295 static void
296 _elm_pan_content_resize_cb(void *data,
297                            Evas *e __UNUSED__,
298                            Evas_Object *obj __UNUSED__,
299                            void *event_info __UNUSED__)
300 {
301    Elm_Pan_Smart_Data *psd;
302    Evas_Coord w, h;
303
304    psd = data;
305    evas_object_geometry_get(psd->content, NULL, NULL, &w, &h);
306    if ((w != psd->content_w) || (h != psd->content_h))
307      {
308         psd->content_w = w;
309         psd->content_h = h;
310         _elm_pan_update(psd);
311      }
312    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
313 }
314
315 static void
316 _elm_pan_content_set(Evas_Object *obj,
317                      Evas_Object *content)
318 {
319    Evas_Coord w, h;
320
321    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
322
323    if (content == psd->content) return;
324    if (psd->content)
325      {
326         evas_object_smart_member_del(psd->content);
327         evas_object_event_callback_del_full
328           (psd->content, EVAS_CALLBACK_DEL, _elm_pan_content_del_cb, psd);
329         evas_object_event_callback_del_full
330           (psd->content, EVAS_CALLBACK_RESIZE, _elm_pan_content_resize_cb,
331           psd);
332         psd->content = NULL;
333      }
334    if (!content) goto end;
335
336    psd->content = content;
337    evas_object_smart_member_add(psd->content, psd->self);
338    evas_object_geometry_get(psd->content, NULL, NULL, &w, &h);
339    psd->content_w = w;
340    psd->content_h = h;
341    evas_object_event_callback_add
342      (content, EVAS_CALLBACK_DEL, _elm_pan_content_del_cb, psd);
343    evas_object_event_callback_add
344      (content, EVAS_CALLBACK_RESIZE, _elm_pan_content_resize_cb, psd);
345
346    if (evas_object_visible_get(psd->self))
347      evas_object_show(psd->content);
348    else
349      evas_object_hide(psd->content);
350
351    _elm_pan_update(psd);
352
353 end:
354    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
355 }
356
357 /* pan smart object on top, scroller interface on bottom */
358 /* ============================================================ */
359
360 static const char SCROLL_SMART_NAME[] = "elm_scroll";
361
362 #define ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(o, ptr)                     \
363   Elm_Scrollable_Smart_Interface_Data *ptr =                            \
364     evas_object_smart_interface_data_get(o, &(ELM_SCROLLABLE_IFACE.base)); \
365   if (!ptr)                                                             \
366     {                                                                   \
367        CRITICAL("No interface data for object %p (%s)",                 \
368                 o, evas_object_type_get(o));                            \
369        return;                                                          \
370     }
371
372 #define ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(o, ptr, val)            \
373   Elm_Scrollable_Smart_Interface_Data *ptr =                            \
374     evas_object_smart_interface_data_get(o, &(ELM_SCROLLABLE_IFACE.base)); \
375   if (!ptr)                                                             \
376     {                                                                   \
377        CRITICAL("No interface data for object %p (%s)",                 \
378                 o, evas_object_type_get(o));                            \
379        return val;                                                      \
380     }
381
382 static void _elm_scroll_scroll_bar_size_adjust(
383   Elm_Scrollable_Smart_Interface_Data *);
384 static void _elm_scroll_wanted_region_set(Evas_Object *);
385 static void _elm_scroll_content_pos_get(const Evas_Object *,
386                                         Evas_Coord *,
387                                         Evas_Coord *);
388 static void _elm_scroll_content_pos_set(Evas_Object *,
389                                         Evas_Coord,
390                                         Evas_Coord,
391                                         Eina_Bool);
392
393 #define LEFT               0
394 #define RIGHT              1
395 #define UP                 2
396 #define DOWN               3
397 #define EVTIME             1
398
399 static void
400 _elm_direction_arrows_eval(Elm_Scrollable_Smart_Interface_Data *sid)
401 {
402    Eina_Bool go_left = EINA_TRUE, go_right = EINA_TRUE;
403    Eina_Bool go_up = EINA_TRUE, go_down = EINA_TRUE;
404    Evas_Coord x = 0, y = 0, mx = 0, my = 0, minx = 0, miny = 0;
405    
406    if (!sid->edje_obj || !sid->pan_obj) return;
407    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
408    
409    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
410    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
411    psd->api->pos_get(sid->pan_obj, &x, &y);
412
413    if (x == minx) go_left = EINA_FALSE;
414    if (x == (mx + minx)) go_right = EINA_FALSE;
415    if (y == miny) go_up = EINA_FALSE;
416    if (y == (my + miny)) go_down = EINA_FALSE;
417    if (go_left != sid->go_left)
418      {
419         if (go_left)
420           edje_object_signal_emit(sid->edje_obj, "elm,action,show,left", "elm");
421         else
422           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,left", "elm");
423         sid->go_left = go_left;
424      }
425    if (go_right != sid->go_right)
426      {
427         if (go_right)
428           edje_object_signal_emit(sid->edje_obj, "elm,action,show,right", "elm");
429         else
430           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,right", "elm");
431         sid->go_right= go_right;
432      }
433    if (go_up != sid->go_up)
434      {
435         if (go_up)
436           edje_object_signal_emit(sid->edje_obj, "elm,action,show,up", "elm");
437         else
438           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,up", "elm");
439         sid->go_up = go_up;
440      }
441    if (go_down != sid->go_down)
442      {
443         if (go_down)
444           edje_object_signal_emit(sid->edje_obj, "elm,action,show,down", "elm");
445         else
446           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,down", "elm");
447         sid->go_down= go_down;
448      }
449 }
450
451 static int
452 _elm_scroll_scroll_bar_h_visibility_adjust(
453   Elm_Scrollable_Smart_Interface_Data *sid)
454 {
455    int scroll_h_vis_change = 0;
456    Evas_Coord w, vw = 0, vh = 0;
457
458    if (!sid->edje_obj) return 0;
459
460    w = sid->content_info.w;
461    if (sid->pan_obj)
462      evas_object_geometry_get(sid->pan_obj, NULL, NULL, &vw, &vh);
463    if (sid->hbar_visible)
464      {
465         if (sid->min_w)
466           {
467              scroll_h_vis_change = 1;
468              sid->hbar_visible = EINA_FALSE;
469           }
470         else
471           {
472              if (sid->hbar_flags == ELM_SCROLLER_POLICY_AUTO)
473                {
474                   if ((sid->content) || (sid->extern_pan))
475                     {
476                        if (w <= vw)
477                          {
478                             scroll_h_vis_change = 1;
479                             sid->hbar_visible = EINA_FALSE;
480                          }
481                     }
482                   else
483                     {
484                        scroll_h_vis_change = 1;
485                        sid->hbar_visible = EINA_FALSE;
486                     }
487                }
488              else if (sid->hbar_flags == ELM_SCROLLER_POLICY_OFF)
489                {
490                   scroll_h_vis_change = 1;
491                   sid->hbar_visible = EINA_FALSE;
492                }
493           }
494      }
495    else
496      {
497         if (!sid->min_w)
498           {
499              if (sid->hbar_flags == ELM_SCROLLER_POLICY_AUTO)
500                {
501                   if ((sid->content) || (sid->extern_pan))
502                     {
503                        if (w > vw)
504                          {
505                             scroll_h_vis_change = 1;
506                             sid->hbar_visible = EINA_TRUE;
507                          }
508                     }
509                }
510              else if (sid->hbar_flags == ELM_SCROLLER_POLICY_ON)
511                {
512                   scroll_h_vis_change = 1;
513                   sid->hbar_visible = EINA_TRUE;
514                }
515           }
516      }
517    if (scroll_h_vis_change)
518      {
519         if (sid->hbar_flags != ELM_SCROLLER_POLICY_OFF)
520           {
521              if (sid->hbar_visible)
522                edje_object_signal_emit
523                  (sid->edje_obj, "elm,action,show,hbar", "elm");
524              else
525                edje_object_signal_emit
526                  (sid->edje_obj, "elm,action,hide,hbar", "elm");
527           }
528         else
529           edje_object_signal_emit
530             (sid->edje_obj, "elm,action,hide,hbar", "elm");
531         edje_object_message_signal_process(sid->edje_obj);
532         _elm_scroll_scroll_bar_size_adjust(sid);
533         if (sid->cb_func.content_min_limit)
534           sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
535      }
536    
537    _elm_direction_arrows_eval(sid);
538    return scroll_h_vis_change;
539 }
540
541 static int
542 _elm_scroll_scroll_bar_v_visibility_adjust(
543   Elm_Scrollable_Smart_Interface_Data *sid)
544 {
545    int scroll_v_vis_change = 0;
546    Evas_Coord h, vw = 0, vh = 0;
547
548    if (!sid->edje_obj) return 0;
549
550    h = sid->content_info.h;
551    if (sid->pan_obj)
552      evas_object_geometry_get(sid->pan_obj, NULL, NULL, &vw, &vh);
553    if (sid->vbar_visible)
554      {
555         if (sid->min_h)
556           {
557              scroll_v_vis_change = 1;
558              sid->vbar_visible = EINA_FALSE;
559           }
560         else
561           {
562              if (sid->vbar_flags == ELM_SCROLLER_POLICY_AUTO)
563                {
564                   if ((sid->content) || (sid->extern_pan))
565                     {
566                        if (h <= vh)
567                          {
568                             scroll_v_vis_change = 1;
569                             sid->vbar_visible = EINA_FALSE;
570                          }
571                     }
572                   else
573                     {
574                        scroll_v_vis_change = 1;
575                        sid->vbar_visible = EINA_FALSE;
576                     }
577                }
578              else if (sid->vbar_flags == ELM_SCROLLER_POLICY_OFF)
579                {
580                   scroll_v_vis_change = 1;
581                   sid->vbar_visible = EINA_FALSE;
582                }
583           }
584      }
585    else
586      {
587         if (!sid->min_h)
588           {
589              if (sid->vbar_flags == ELM_SCROLLER_POLICY_AUTO)
590                {
591                   if ((sid->content) || (sid->extern_pan))
592                     {
593                        if (h > vh)
594                          {
595                             scroll_v_vis_change = 1;
596                             sid->vbar_visible = EINA_TRUE;
597                          }
598                     }
599                }
600              else if (sid->vbar_flags == ELM_SCROLLER_POLICY_ON)
601                {
602                   scroll_v_vis_change = 1;
603                   sid->vbar_visible = EINA_TRUE;
604                }
605           }
606      }
607    if (scroll_v_vis_change)
608      {
609         if (sid->vbar_flags != ELM_SCROLLER_POLICY_OFF)
610           {
611              if (sid->vbar_visible)
612                edje_object_signal_emit
613                  (sid->edje_obj, "elm,action,show,vbar", "elm");
614              else
615                edje_object_signal_emit
616                  (sid->edje_obj, "elm,action,hide,vbar", "elm");
617           }
618         else
619           edje_object_signal_emit
620             (sid->edje_obj, "elm,action,hide,vbar", "elm");
621         edje_object_message_signal_process(sid->edje_obj);
622         _elm_scroll_scroll_bar_size_adjust(sid);
623         if (sid->cb_func.content_min_limit)
624           sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
625      }
626
627    _elm_direction_arrows_eval(sid);
628    return scroll_v_vis_change;
629 }
630
631 static void
632 _elm_scroll_scroll_bar_visibility_adjust(
633   Elm_Scrollable_Smart_Interface_Data *sid)
634 {
635    int changed = 0;
636
637    changed |= _elm_scroll_scroll_bar_h_visibility_adjust(sid);
638    changed |= _elm_scroll_scroll_bar_v_visibility_adjust(sid);
639
640    if (changed)
641      {
642         _elm_scroll_scroll_bar_h_visibility_adjust(sid);
643         _elm_scroll_scroll_bar_v_visibility_adjust(sid);
644      }
645 }
646
647 static void
648 _elm_scroll_scroll_bar_size_adjust(Elm_Scrollable_Smart_Interface_Data *sid)
649 {
650    if (!sid->pan_obj || !sid->edje_obj) return;
651
652    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
653
654    if ((sid->content) || (sid->extern_pan))
655      {
656         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py,
657                    minx = 0, miny = 0;
658         double vx, vy, size;
659
660         edje_object_part_geometry_get
661           (sid->edje_obj, "elm.swallow.content", NULL, NULL, &vw, &vh);
662         w = sid->content_info.w;
663         if (w < 1) w = 1;
664         size = (double)vw / (double)w;
665
666         if (size > 1.0)
667           {
668              size = 1.0;
669              edje_object_part_drag_value_set
670                (sid->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
671           }
672         edje_object_part_drag_size_set
673           (sid->edje_obj, "elm.dragable.hbar", size, 1.0);
674
675         h = sid->content_info.h;
676         if (h < 1) h = 1;
677         size = (double)vh / (double)h;
678         if (size > 1.0)
679           {
680              size = 1.0;
681              edje_object_part_drag_value_set
682                (sid->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
683           }
684         edje_object_part_drag_size_set
685           (sid->edje_obj, "elm.dragable.vbar", 1.0, size);
686
687         edje_object_part_drag_value_get
688           (sid->edje_obj, "elm.dragable.hbar", &vx, NULL);
689         edje_object_part_drag_value_get
690           (sid->edje_obj, "elm.dragable.vbar", NULL, &vy);
691
692         psd->api->pos_max_get(sid->pan_obj, &mx, &my);
693         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
694         x = vx * mx + minx;
695         y = vy * my + miny;
696
697         edje_object_part_drag_step_set
698           (sid->edje_obj, "elm.dragable.hbar", (double)sid->step.x /
699           (double)w, 0.0);
700         edje_object_part_drag_step_set
701           (sid->edje_obj, "elm.dragable.vbar", 0.0, (double)sid->step.y /
702           (double)h);
703         if (sid->page.x > 0)
704           edje_object_part_drag_page_set
705             (sid->edje_obj, "elm.dragable.hbar", (double)sid->page.x /
706             (double)w, 0.0);
707         else
708           edje_object_part_drag_page_set
709             (sid->edje_obj, "elm.dragable.hbar",
710             -((double)sid->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
711         if (sid->page.y > 0)
712           edje_object_part_drag_page_set
713             (sid->edje_obj, "elm.dragable.vbar", 0.0,
714             (double)sid->page.y / (double)h);
715         else
716           edje_object_part_drag_page_set
717             (sid->edje_obj, "elm.dragable.vbar", 0.0,
718             -((double)sid->page.y * ((double)vh / (double)h)) / 100.0);
719
720         psd->api->pos_get(sid->pan_obj, &px, &py);
721         if (vx != mx) x = px;
722         if (vy != my) y = py;
723         psd->api->pos_set(sid->pan_obj, x, y);
724      }
725    else
726      {
727         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
728
729         edje_object_part_drag_size_set
730           (sid->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
731         edje_object_part_drag_size_set
732           (sid->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
733         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
734         psd->api->pos_get(sid->pan_obj, &px, &py);
735         psd->api->pos_set(sid->pan_obj, minx, miny);
736         if ((px != minx) || (py != miny))
737           edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
738      }
739    _elm_scroll_scroll_bar_visibility_adjust(sid);
740 }
741
742 static void
743 _elm_scroll_scroll_bar_read_and_update(
744   Elm_Scrollable_Smart_Interface_Data *sid)
745 {
746    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
747    double vx, vy;
748
749    if (!sid->edje_obj || !sid->pan_obj) return;
750
751    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
752
753    if ((sid->down.dragged) || (sid->down.bounce_x_animator)
754        || (sid->down.bounce_y_animator) || (sid->down.momentum_animator)
755        || (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
756      return;
757    edje_object_part_drag_value_get
758      (sid->edje_obj, "elm.dragable.vbar", NULL, &vy);
759    edje_object_part_drag_value_get
760      (sid->edje_obj, "elm.dragable.hbar", &vx, NULL);
761    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
762    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
763    x = vx * (double)mx + minx;
764    y = vy * (double)my + miny;
765    psd->api->pos_get(sid->pan_obj, &px, &py);
766    psd->api->pos_set(sid->pan_obj, x, y);
767    if ((px != x) || (py != y))
768      {
769         edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
770      }
771 }
772
773 static void
774 _elm_scroll_drag_start(Elm_Scrollable_Smart_Interface_Data *sid)
775 {
776    if (sid->cb_func.drag_start)
777      sid->cb_func.drag_start(sid->obj, NULL);
778 }
779
780 static void
781 _elm_scroll_drag_stop(Elm_Scrollable_Smart_Interface_Data *sid)
782 {
783    if (sid->cb_func.drag_stop)
784      sid->cb_func.drag_stop(sid->obj, NULL);
785 }
786
787 static void
788 _elm_scroll_anim_start(Elm_Scrollable_Smart_Interface_Data *sid)
789 {
790    if (sid->cb_func.animate_start)
791      sid->cb_func.animate_start(sid->obj, NULL);
792 }
793
794 static void
795 _elm_scroll_anim_stop(Elm_Scrollable_Smart_Interface_Data *sid)
796 {
797    if (sid->cb_func.animate_stop)
798      sid->cb_func.animate_stop(sid->obj, NULL);
799 }
800
801 static void
802 _elm_scroll_vbar_drag_cb(void *data,
803                            Evas_Object *obj __UNUSED__,
804                            const char *emission __UNUSED__,
805                            const char *source __UNUSED__)
806 {
807    Elm_Scrollable_Smart_Interface_Data *sid = data;
808
809    if (sid->cb_func.vbar_drag)
810      sid->cb_func.vbar_drag(sid->obj, NULL);
811
812    _elm_scroll_scroll_bar_read_and_update(sid);
813 }
814
815 static void
816 _elm_scroll_vbar_press_cb(void *data,
817                            Evas_Object *obj __UNUSED__,
818                            const char *emission __UNUSED__,
819                            const char *source __UNUSED__)
820 {
821    Elm_Scrollable_Smart_Interface_Data *sid = data;
822
823    if (sid->cb_func.vbar_press)
824      sid->cb_func.vbar_press(sid->obj, NULL);
825 }
826
827 static void
828 _elm_scroll_vbar_unpress_cb(void *data,
829                            Evas_Object *obj __UNUSED__,
830                            const char *emission __UNUSED__,
831                            const char *source __UNUSED__)
832 {
833    Elm_Scrollable_Smart_Interface_Data *sid = data;
834
835    if (sid->cb_func.vbar_unpress)
836      sid->cb_func.vbar_unpress(sid->obj, NULL);
837 }
838
839 static void
840 _elm_scroll_edje_drag_v_start_cb(void *data,
841                                  Evas_Object *obj __UNUSED__,
842                                  const char *emission __UNUSED__,
843                                  const char *source __UNUSED__)
844 {
845    Elm_Scrollable_Smart_Interface_Data *sid = data;
846
847    _elm_scroll_scroll_bar_read_and_update(sid);
848    _elm_scroll_drag_start(sid);
849    sid->freeze = EINA_TRUE;
850 }
851
852 static void
853 _elm_scroll_edje_drag_v_stop_cb(void *data,
854                                 Evas_Object *obj __UNUSED__,
855                                 const char *emission __UNUSED__,
856                                 const char *source __UNUSED__)
857 {
858    Elm_Scrollable_Smart_Interface_Data *sid = data;
859
860    _elm_scroll_scroll_bar_read_and_update(sid);
861    _elm_scroll_drag_stop(sid);
862    sid->freeze = EINA_FALSE;
863 }
864
865 static void
866 _elm_scroll_edje_drag_v_cb(void *data,
867                            Evas_Object *obj __UNUSED__,
868                            const char *emission __UNUSED__,
869                            const char *source __UNUSED__)
870 {
871    Elm_Scrollable_Smart_Interface_Data *sid = data;
872
873    _elm_scroll_scroll_bar_read_and_update(sid);
874 }
875
876 static void
877 _elm_scroll_hbar_drag_cb(void *data,
878                            Evas_Object *obj __UNUSED__,
879                            const char *emission __UNUSED__,
880                            const char *source __UNUSED__)
881 {
882    Elm_Scrollable_Smart_Interface_Data *sid = data;
883
884    if (sid->cb_func.hbar_drag)
885      sid->cb_func.hbar_drag(sid->obj, NULL);
886
887    _elm_scroll_scroll_bar_read_and_update(sid);
888 }
889
890 static void
891 _elm_scroll_hbar_press_cb(void *data,
892                            Evas_Object *obj __UNUSED__,
893                            const char *emission __UNUSED__,
894                            const char *source __UNUSED__)
895 {
896    Elm_Scrollable_Smart_Interface_Data *sid = data;
897
898    if (sid->cb_func.hbar_press)
899      sid->cb_func.hbar_press(sid->obj, NULL);
900 }
901
902 static void
903 _elm_scroll_hbar_unpress_cb(void *data,
904                            Evas_Object *obj __UNUSED__,
905                            const char *emission __UNUSED__,
906                            const char *source __UNUSED__)
907 {
908    Elm_Scrollable_Smart_Interface_Data *sid = data;
909
910    if (sid->cb_func.hbar_unpress)
911      sid->cb_func.hbar_unpress(sid->obj, NULL);
912 }
913
914 static void
915 _elm_scroll_edje_drag_h_start_cb(void *data,
916                                  Evas_Object *obj __UNUSED__,
917                                  const char *emission __UNUSED__,
918                                  const char *source __UNUSED__)
919 {
920    Elm_Scrollable_Smart_Interface_Data *sid = data;
921
922    _elm_scroll_scroll_bar_read_and_update(sid);
923    _elm_scroll_drag_start(sid);
924    sid->freeze = EINA_TRUE;
925 }
926
927 static void
928 _elm_scroll_edje_drag_h_stop_cb(void *data,
929                                 Evas_Object *obj __UNUSED__,
930                                 const char *emission __UNUSED__,
931                                 const char *source __UNUSED__)
932 {
933    Elm_Scrollable_Smart_Interface_Data *sid = data;
934
935    _elm_scroll_scroll_bar_read_and_update(sid);
936    _elm_scroll_drag_stop(sid);
937    sid->freeze = EINA_FALSE;
938 }
939
940 static void
941 _elm_scroll_edje_drag_h_cb(void *data,
942                            Evas_Object *obj __UNUSED__,
943                            const char *emission __UNUSED__,
944                            const char *source __UNUSED__)
945 {
946    Elm_Scrollable_Smart_Interface_Data *sid = data;
947
948    _elm_scroll_scroll_bar_read_and_update(sid);
949 }
950
951 static void
952 _elm_scroll_content_size_get(const Evas_Object *obj,
953                              Evas_Coord *w,
954                              Evas_Coord *h)
955 {
956    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
957
958    if (!sid->content) return;
959
960    evas_object_geometry_get(sid->content, NULL, NULL, w, h);
961 }
962
963 static void
964 _elm_scroll_content_viewport_size_get(const Evas_Object *obj,
965                                       Evas_Coord *w,
966                                       Evas_Coord *h)
967 {
968    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
969
970    if (!sid->pan_obj || !sid->edje_obj) return;
971
972    edje_object_calc_force(sid->edje_obj);
973    evas_object_geometry_get(sid->pan_obj, NULL, NULL, w, h);
974 }
975
976 static void
977 _elm_scroll_content_min_limit(Evas_Object *obj,
978                               Eina_Bool w,
979                               Eina_Bool h)
980 {
981    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
982
983    if (!sid->edje_obj) return;
984
985    if (!sid->cb_func.content_min_limit)
986      {
987         ERR("Content minimim size limiting is unimplemented -- you "
988             "must provide it yourself\n");
989         return;
990      }
991
992    sid->min_w = !!w;
993    sid->min_h = !!h;
994    sid->cb_func.content_min_limit(sid->obj, w, h);
995 }
996
997 static Evas_Coord
998 _elm_scroll_x_mirrored_get(const Evas_Object *obj,
999                            Evas_Coord x)
1000 {
1001    Evas_Coord cw, ch, w, ret;
1002
1003    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, x);
1004
1005    if (!sid->pan_obj) return 0;
1006
1007    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
1008
1009    _elm_scroll_content_viewport_size_get(obj, &w, NULL);
1010    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1011    ret = (cw - (x + w));
1012
1013    return (ret >= 0) ? ret : 0;
1014 }
1015
1016 /* Update the wanted coordinates according to the x, y passed
1017  * widget directionality, content size and etc. */
1018 static void
1019 _elm_scroll_wanted_coordinates_update(Elm_Scrollable_Smart_Interface_Data *sid,
1020                                       Evas_Coord x,
1021                                       Evas_Coord y)
1022 {
1023    Evas_Coord cw, ch;
1024
1025    if (!sid->pan_obj) return;
1026
1027    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1028
1029    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1030
1031    /* Update wx/y/w/h - and if the requested positions aren't legal
1032     * adjust a bit. */
1033    _elm_scroll_content_viewport_size_get(sid->obj, &sid->ww, &sid->wh);
1034    if (x < 0)
1035      sid->wx = 0;
1036    else if ((x + sid->ww) > cw)
1037      sid->wx = cw - sid->ww;
1038    else if (sid->is_mirrored)
1039      sid->wx = _elm_scroll_x_mirrored_get(sid->obj, x);
1040    else
1041      sid->wx = x;
1042    if (y < 0) sid->wy = 0;
1043    else if ((y + sid->wh) > ch)
1044      sid->wy = ch - sid->wh;
1045    else sid->wy = y;
1046 }
1047
1048 static void
1049 _elm_scroll_momentum_end(Elm_Scrollable_Smart_Interface_Data *sid)
1050 {
1051    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator)) return;
1052    if (sid->down.momentum_animator)
1053      {
1054         Evas_Coord px, py;
1055         _elm_scroll_content_pos_get(sid->obj, &px, &py);
1056         _elm_scroll_wanted_coordinates_update(sid, px, py);
1057
1058         ecore_animator_del(sid->down.momentum_animator);
1059         sid->down.momentum_animator = NULL;
1060         sid->down.bounce_x_hold = EINA_FALSE;
1061         sid->down.bounce_y_hold = EINA_FALSE;
1062         sid->down.ax = 0;
1063         sid->down.ay = 0;
1064         sid->down.dx = 0;
1065         sid->down.dy = 0;
1066         sid->down.pdx = 0;
1067         sid->down.pdy = 0;
1068         if (sid->content_info.resized)
1069           _elm_scroll_wanted_region_set(sid->obj);
1070      }
1071 }
1072
1073 static Eina_Bool
1074 _elm_scroll_bounce_x_animator(void *data)
1075 {
1076    Elm_Scrollable_Smart_Interface_Data *sid;
1077    Evas_Coord x, y, dx, w, odx, ed, md;
1078    double t, p, dt, pd, r;
1079
1080    sid = data;
1081    t = ecore_loop_time_get();
1082    dt = t - sid->down.anim_start2;
1083    if (dt >= 0.0)
1084      {
1085         dt = dt / _elm_config->thumbscroll_bounce_friction;
1086         odx = sid->down.b2x - sid->down.bx;
1087         _elm_scroll_content_viewport_size_get(sid->obj, &w, NULL);
1088         if (!sid->down.momentum_animator && (w > abs(odx)))
1089           {
1090              pd = (double)odx / (double)w;
1091              pd = (pd > 0) ? pd : -pd;
1092              pd = 1.0 - ((1.0 - pd) * (1.0 - pd));
1093              dt = dt / pd;
1094           }
1095         if (dt > 1.0) dt = 1.0;
1096         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
1097         _elm_scroll_content_pos_get(sid->obj, &x, &y);
1098         dx = (odx * p);
1099         r = 1.0;
1100         if (sid->down.momentum_animator)
1101           {
1102              ed = abs(sid->down.dx * (_elm_config->thumbscroll_friction +
1103                                       sid->down.extra_time) - sid->down.b0x);
1104              md = abs(_elm_config->thumbscroll_friction * 5 * w);
1105              if (ed > md) r = (double)(md) / (double)ed;
1106           }
1107         x = sid->down.b2x + (int)((double)(dx - odx) * r);
1108         if (!sid->down.cancelled)
1109           _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1110         if (dt >= 1.0)
1111           {
1112              if (sid->down.momentum_animator)
1113                sid->down.bounce_x_hold = EINA_TRUE;
1114              if ((!sid->down.bounce_y_animator) &&
1115                  (!sid->scrollto.y.animator))
1116                _elm_scroll_anim_stop(sid);
1117              sid->down.bounce_x_animator = NULL;
1118              sid->down.pdx = 0;
1119              sid->bouncemex = EINA_FALSE;
1120              _elm_scroll_momentum_end(sid);
1121              if (sid->content_info.resized)
1122                _elm_scroll_wanted_region_set(sid->obj);
1123              return ECORE_CALLBACK_CANCEL;
1124           }
1125      }
1126    return ECORE_CALLBACK_RENEW;
1127 }
1128
1129 static Eina_Bool
1130 _elm_scroll_bounce_y_animator(void *data)
1131 {
1132    Elm_Scrollable_Smart_Interface_Data *sid;
1133    Evas_Coord x, y, dy, h, ody, ed, md;
1134    double t, p, dt, pd, r;
1135
1136    sid = data;
1137    t = ecore_loop_time_get();
1138    dt = t - sid->down.anim_start3;
1139    if (dt >= 0.0)
1140      {
1141         dt = dt / _elm_config->thumbscroll_bounce_friction;
1142         ody = sid->down.b2y - sid->down.by;
1143         _elm_scroll_content_viewport_size_get(sid->obj, NULL, &h);
1144         if (!sid->down.momentum_animator && (h > abs(ody)))
1145           {
1146              pd = (double)ody / (double)h;
1147              pd = (pd > 0) ? pd : -pd;
1148              pd = 1.0 - ((1.0 - pd) * (1.0 - pd));
1149              dt = dt / pd;
1150           }
1151         if (dt > 1.0) dt = 1.0;
1152         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
1153         _elm_scroll_content_pos_get(sid->obj, &x, &y);
1154         dy = (ody * p);
1155         r = 1.0;
1156         if (sid->down.momentum_animator)
1157           {
1158              ed = abs(sid->down.dy * (_elm_config->thumbscroll_friction +
1159                                       sid->down.extra_time) - sid->down.b0y);
1160              md = abs(_elm_config->thumbscroll_friction * 5 * h);
1161              if (ed > md) r = (double)(md) / (double)ed;
1162           }
1163         y = sid->down.b2y + (int)((double)(dy - ody) * r);
1164         if (!sid->down.cancelled)
1165           _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1166         if (dt >= 1.0)
1167           {
1168              if (sid->down.momentum_animator)
1169                sid->down.bounce_y_hold = EINA_TRUE;
1170              if ((!sid->down.bounce_x_animator) &&
1171                  (!sid->scrollto.y.animator))
1172                _elm_scroll_anim_stop(sid);
1173              sid->down.bounce_y_animator = NULL;
1174              sid->down.pdy = 0;
1175              sid->bouncemey = EINA_FALSE;
1176              _elm_scroll_momentum_end(sid);
1177              if (sid->content_info.resized)
1178                _elm_scroll_wanted_region_set(sid->obj);
1179              return ECORE_CALLBACK_CANCEL;
1180           }
1181      }
1182
1183    return ECORE_CALLBACK_RENEW;
1184 }
1185
1186 static void
1187 _elm_scroll_bounce_eval(Elm_Scrollable_Smart_Interface_Data *sid)
1188 {
1189    Evas_Coord mx, my, px, py, bx, by, b2x, b2y, minx = 0, miny = 0;
1190
1191    if (!sid->pan_obj) return;
1192
1193    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1194
1195    if (sid->freeze) return;
1196    if ((!sid->bouncemex) && (!sid->bouncemey)) return;
1197    if (sid->down.now) return;  // down bounce while still held down
1198    if (sid->down.onhold_animator)
1199      {
1200         ecore_animator_del(sid->down.onhold_animator);
1201         sid->down.onhold_animator = NULL;
1202         if (sid->content_info.resized)
1203           _elm_scroll_wanted_region_set(sid->obj);
1204      }
1205    if (sid->down.hold_animator)
1206      {
1207         ecore_animator_del(sid->down.hold_animator);
1208         sid->down.hold_animator = NULL;
1209         if (sid->content_info.resized)
1210           _elm_scroll_wanted_region_set(sid->obj);
1211      }
1212    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1213    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1214    psd->api->pos_get(sid->pan_obj, &px, &py);
1215    bx = px;
1216    by = py;
1217    if (px < minx) px = minx;
1218    if ((px - minx) > mx) px = mx + minx;
1219    if (py < miny) py = miny;
1220    if ((py - miny) > my) py = my + miny;
1221    b2x = px;
1222    b2y = py;
1223    if ((!sid->obj) ||
1224        (!elm_widget_drag_child_locked_x_get(sid->obj)))
1225      {
1226         if ((!sid->down.bounce_x_animator) && (!sid->bounce_animator_disabled))
1227           {
1228              if (sid->bouncemex)
1229                {
1230                   if (sid->scrollto.x.animator)
1231                     {
1232                        ecore_animator_del(sid->scrollto.x.animator);
1233                        sid->scrollto.x.animator = NULL;
1234                     }
1235                   sid->down.bounce_x_animator =
1236                     ecore_animator_add(_elm_scroll_bounce_x_animator, sid);
1237                   sid->down.anim_start2 = ecore_loop_time_get();
1238                   sid->down.bx = bx;
1239                   sid->down.bx0 = bx;
1240                   sid->down.b2x = b2x;
1241                   if (sid->down.momentum_animator)
1242                     sid->down.b0x = sid->down.ax;
1243                   else sid->down.b0x = 0;
1244                }
1245           }
1246      }
1247    if ((!sid->obj) ||
1248        (!elm_widget_drag_child_locked_y_get(sid->obj)))
1249      {
1250         if ((!sid->down.bounce_y_animator) && (!sid->bounce_animator_disabled))
1251           {
1252              if (sid->bouncemey)
1253                {
1254                   if (sid->scrollto.y.animator)
1255                     {
1256                        ecore_animator_del(sid->scrollto.y.animator);
1257                        sid->scrollto.y.animator = NULL;
1258                     }
1259                   sid->down.bounce_y_animator =
1260                     ecore_animator_add(_elm_scroll_bounce_y_animator, sid);
1261                   sid->down.anim_start3 = ecore_loop_time_get();
1262                   sid->down.by = by;
1263                   sid->down.by0 = by;
1264                   sid->down.b2y = b2y;
1265                   if (sid->down.momentum_animator)
1266                     sid->down.b0y = sid->down.ay;
1267                   else sid->down.b0y = 0;
1268                }
1269           }
1270      }
1271 }
1272
1273 static void
1274 _elm_scroll_content_pos_get(const Evas_Object *obj,
1275                             Evas_Coord *x,
1276                             Evas_Coord *y)
1277 {
1278    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1279
1280    if (!sid->pan_obj) return;
1281
1282    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1283
1284    psd->api->pos_get(sid->pan_obj, x, y);
1285 }
1286
1287 static void
1288 _elm_scroll_content_pos_set(Evas_Object *obj,
1289                             Evas_Coord x,
1290                             Evas_Coord y,
1291                             Eina_Bool sig)
1292 {
1293    Evas_Coord mx = 0, my = 0, px = 0, py = 0, spx = 0, spy = 0, minx = 0, miny = 0;
1294    Evas_Coord cw =0, ch = 0, ww = 0, wh = 0; //// TIZEN ONLY
1295    double vx, vy;
1296
1297    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1298
1299    if (!sid->edje_obj || !sid->pan_obj) return;
1300
1301    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1302
1303    // FIXME: allow for bounce outside of range
1304    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1305    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1306    psd->api->content_size_get(sid->pan_obj, &cw, &ch); //// TIZEN ONLY
1307    _elm_scroll_content_viewport_size_get(obj, &ww, &wh); //// TIZEN ONLY
1308
1309    psd->api->pos_get(sid->pan_obj, &px, &py);
1310 //// TIZEN ONLY
1311    if (cw > ww)
1312      {
1313         if (x < minx)
1314           edje_object_signal_emit(sid->edje_obj, "elm,edge,left", "elm");
1315         if ((x - minx) > mx)
1316           edje_object_signal_emit(sid->edje_obj, "elm,edge,right", "elm");
1317      }
1318    if (ch > wh)
1319      {
1320         if (y < miny)
1321           edje_object_signal_emit(sid->edje_obj, "elm,edge,top", "elm");
1322         if ((y - miny) > my)
1323           edje_object_signal_emit(sid->edje_obj, "elm,edge,bottom", "elm");
1324      }
1325 //
1326    if (!_elm_config->thumbscroll_bounce_enable)
1327      {
1328         if (x < minx) x = minx;
1329         if ((x - minx) > mx) x = mx + minx;
1330         if (y < miny) y = miny;
1331         if ((y - miny) > my) y = my + miny;
1332      }
1333
1334    if (!sid->bounce_horiz)
1335      {
1336         if (x < minx) x = minx;
1337         if ((x - minx) > mx) x = mx + minx;
1338      }
1339    if (!sid->bounce_vert)
1340      {
1341         if (y < miny) y = miny;
1342         if (y - miny > my) y = my + miny;
1343      }
1344
1345    psd->api->pos_set(sid->pan_obj, x, y);
1346    psd->api->pos_get(sid->pan_obj, &spx, &spy);
1347
1348    if (mx > 0) vx = (double)(spx - minx) / (double)mx;
1349    else vx = 0.0;
1350
1351    if (vx < 0.0) vx = 0.0;
1352    else if (vx > 1.0)
1353      vx = 1.0;
1354
1355    if (my > 0) vy = (double)(spy - miny) / (double)my;
1356    else vy = 0.0;
1357
1358    if (vy < 0.0) vy = 0.0;
1359    else if (vy > 1.0)
1360      vy = 1.0;
1361
1362    edje_object_part_drag_value_set
1363      (sid->edje_obj, "elm.dragable.vbar", 0.0, vy);
1364    edje_object_part_drag_value_set
1365      (sid->edje_obj, "elm.dragable.hbar", vx, 0.0);
1366
1367    if (sig && ((px != x) || (py != y)))
1368      edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
1369    if (!sid->down.bounce_x_animator)
1370      {
1371         if (((x < minx) && (0 <= sid->down.dx)) ||
1372             ((x > (mx + minx)) && (0 >= sid->down.dx)))
1373           {
1374              sid->bouncemex = EINA_TRUE;
1375              _elm_scroll_bounce_eval(sid);
1376           }
1377         else
1378           sid->bouncemex = EINA_FALSE;
1379      }
1380    if (!sid->down.bounce_y_animator)
1381      {
1382         if (((y < miny) && (0 <= sid->down.dy)) ||
1383             ((y > (my + miny)) && (0 >= sid->down.dy)))
1384           {
1385              sid->bouncemey = EINA_TRUE;
1386              _elm_scroll_bounce_eval(sid);
1387           }
1388         else
1389           sid->bouncemey = EINA_FALSE;
1390      }
1391
1392    if ((x != px) || (y != py))
1393      {
1394         if (sid->cb_func.scroll)
1395           sid->cb_func.scroll(obj, NULL);
1396      }
1397    if (sig)
1398      {
1399         if (x != px)
1400           {
1401              if (x == minx)
1402                {
1403                   if (sid->cb_func.edge_left)
1404                     sid->cb_func.edge_left(obj, NULL);
1405                   edje_object_signal_emit(sid->edje_obj, "elm,edge,left", "elm");
1406                }
1407              if (x == (mx + minx))
1408                {
1409                   if (sid->cb_func.edge_right)
1410                     sid->cb_func.edge_right(obj, NULL);
1411                   edje_object_signal_emit(sid->edje_obj, "elm,edge,right", "elm");
1412                }
1413           }
1414         if (y != py)
1415           {
1416              if (y == miny)
1417                {
1418                   if (sid->cb_func.edge_top)
1419                     sid->cb_func.edge_top(obj, NULL);
1420                   edje_object_signal_emit(sid->edje_obj, "elm,edge,top", "elm");
1421                }
1422              if (y == my + miny)
1423                {
1424                   if (sid->cb_func.edge_bottom)
1425                     sid->cb_func.edge_bottom(obj, NULL);
1426                   edje_object_signal_emit(sid->edje_obj, "elm,edge,bottom", "elm");
1427                }
1428           }
1429      }
1430
1431    _elm_direction_arrows_eval(sid);
1432 }
1433
1434 static void
1435 _elm_scroll_mirrored_set(Evas_Object *obj,
1436                          Eina_Bool mirrored)
1437 {
1438    Evas_Coord wx;
1439
1440    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1441
1442    if (!sid->edje_obj) return;
1443
1444    mirrored = !!mirrored;
1445
1446    if (sid->is_mirrored == mirrored)
1447      return;
1448
1449    sid->is_mirrored = mirrored;
1450    edje_object_mirrored_set(sid->edje_obj, mirrored);
1451
1452    if (sid->is_mirrored)
1453      wx = _elm_scroll_x_mirrored_get(sid->obj, sid->wx);
1454    else
1455      wx = sid->wx;
1456
1457    _elm_scroll_content_pos_set(sid->obj, wx, sid->wy, EINA_FALSE);
1458 }
1459
1460 /* returns TRUE when we need to move the scroller, FALSE otherwise.
1461  * Updates w and h either way, so save them if you need them. */
1462 static Eina_Bool
1463 _elm_scroll_content_region_show_internal(Evas_Object *obj,
1464                                          Evas_Coord *_x,
1465                                          Evas_Coord *_y,
1466                                          Evas_Coord w,
1467                                          Evas_Coord h)
1468 {
1469    Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny,
1470               minx = 0, miny = 0, pw = 0, ph = 0, x = *_x, y = *_y;
1471
1472    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
1473
1474    if (!sid->pan_obj) return EINA_FALSE;
1475
1476    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
1477
1478    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1479    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1480    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1481    psd->api->pos_get(sid->pan_obj, &px, &py);
1482    evas_object_geometry_get(sid->pan_obj, NULL, NULL, &pw, &ph);
1483
1484    nx = px;
1485    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1486    else if ((x > px) && ((x + w) > (px + (cw - mx))))
1487      nx = x + w - (cw - mx);
1488    ny = py;
1489    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1490    else if ((y > py) && ((y + h) > (py + (ch - my))))
1491      ny = y + h - (ch - my);
1492
1493    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
1494        (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
1495      {
1496         _elm_scroll_anim_stop(sid);
1497      }
1498    if (sid->scrollto.x.animator)
1499      {
1500         ecore_animator_del(sid->scrollto.x.animator);
1501         sid->scrollto.x.animator = NULL;
1502      }
1503    if (sid->scrollto.y.animator)
1504      {
1505         ecore_animator_del(sid->scrollto.y.animator);
1506         sid->scrollto.y.animator = NULL;
1507      }
1508    if (sid->down.bounce_x_animator)
1509      {
1510         ecore_animator_del(sid->down.bounce_x_animator);
1511         sid->down.bounce_x_animator = NULL;
1512         sid->bouncemex = EINA_FALSE;
1513         if (sid->content_info.resized)
1514           _elm_scroll_wanted_region_set(sid->obj);
1515      }
1516    if (sid->down.bounce_y_animator)
1517      {
1518         ecore_animator_del(sid->down.bounce_y_animator);
1519         sid->down.bounce_y_animator = NULL;
1520         sid->bouncemey = EINA_FALSE;
1521         if (sid->content_info.resized)
1522           _elm_scroll_wanted_region_set(sid->obj);
1523      }
1524    if (sid->down.hold_animator)
1525      {
1526         ecore_animator_del(sid->down.hold_animator);
1527         sid->down.hold_animator = NULL;
1528         _elm_scroll_drag_stop(sid);
1529         if (sid->content_info.resized)
1530           _elm_scroll_wanted_region_set(sid->obj);
1531      }
1532    if (sid->down.momentum_animator)
1533      {
1534         ecore_animator_del(sid->down.momentum_animator);
1535         sid->down.momentum_animator = NULL;
1536         sid->down.bounce_x_hold = EINA_FALSE;
1537         sid->down.bounce_y_hold = EINA_FALSE;
1538         sid->down.ax = 0;
1539         sid->down.ay = 0;
1540         sid->down.pdx = 0;
1541         sid->down.pdy = 0;
1542         if (sid->content_info.resized)
1543           _elm_scroll_wanted_region_set(sid->obj);
1544      }
1545
1546    x = nx;
1547    if ((x + pw) > cw) x = cw - pw;
1548    if (x < minx) x = minx;
1549    y = ny;
1550    if ((y + ph) > ch) y = ch - ph;
1551    if (y < miny) y = miny;
1552
1553    if ((x == px) && (y == py)) return EINA_FALSE;
1554    *_x = x;
1555    *_y = y;
1556    return EINA_TRUE;
1557 }
1558
1559 /* Set should be used for calculated positions, for example, when we move
1560  * because of an animation or because this is the correct position after
1561  * constraints. */
1562 static void
1563 _elm_scroll_content_region_set(Evas_Object *obj,
1564                                Evas_Coord x,
1565                                Evas_Coord y,
1566                                Evas_Coord w,
1567                                Evas_Coord h)
1568 {
1569    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1570
1571    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
1572      {
1573         _elm_scroll_content_pos_set(obj, x, y, EINA_FALSE);
1574         sid->down.sx = x;
1575         sid->down.sy = y;
1576         sid->down.x = sid->down.history[0].x;
1577         sid->down.y = sid->down.history[0].y;
1578      }
1579 }
1580
1581 /* Set should be used for setting the wanted position, for example a
1582  * user scroll or moving the cursor in an entry. */
1583 static void
1584 _elm_scroll_content_region_show(Evas_Object *obj,
1585                                 Evas_Coord x,
1586                                 Evas_Coord y,
1587                                 Evas_Coord w,
1588                                 Evas_Coord h)
1589 {
1590    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1591
1592    sid->wx = x;
1593    sid->wy = y;
1594    sid->ww = w;
1595    sid->wh = h;
1596    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
1597      {
1598         _elm_scroll_content_pos_set(obj, x, y, EINA_TRUE);
1599         sid->down.sx = x;
1600         sid->down.sy = y;
1601         sid->down.x = sid->down.history[0].x;
1602         sid->down.y = sid->down.history[0].y;
1603      }
1604 }
1605
1606 static void
1607 _elm_scroll_wanted_region_set(Evas_Object *obj)
1608 {
1609    Evas_Coord ww, wh, wx;
1610
1611    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1612
1613    wx = sid->wx;
1614
1615    if (sid->down.now || sid->down.momentum_animator ||
1616        sid->down.bounce_x_animator || sid->down.bounce_y_animator ||
1617        sid->down.hold_animator || sid->down.onhold_animator ||
1618        sid->scrollto.x.animator || sid->scrollto.y.animator)
1619      return;
1620
1621    sid->content_info.resized = EINA_FALSE;
1622
1623    /* Flip to RTL cords only if init in RTL mode */
1624    if (sid->is_mirrored)
1625      wx = _elm_scroll_x_mirrored_get(obj, sid->wx);
1626
1627    if (sid->ww == -1)
1628      {
1629         _elm_scroll_content_viewport_size_get(obj, &ww, &wh);
1630      }
1631    else
1632      {
1633         ww = sid->ww;
1634         wh = sid->wh;
1635      }
1636
1637    _elm_scroll_content_region_set(obj, wx, sid->wy, ww, wh);
1638 }
1639
1640 static void
1641 _elm_scroll_wheel_event_cb(void *data,
1642                            Evas *e __UNUSED__,
1643                            Evas_Object *obj __UNUSED__,
1644                            void *event_info)
1645 {
1646    Elm_Scrollable_Smart_Interface_Data *sid;
1647    Evas_Event_Mouse_Wheel *ev;
1648    Evas_Coord x = 0, y = 0, vw = 0, vh = 0, cw = 0, ch = 0;
1649    int direction = 0;
1650
1651    sid = data;
1652    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1653    ev = event_info;
1654    direction = ev->direction;
1655    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1656    if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
1657        (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
1658        (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
1659        (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
1660        (evas_key_modifier_is_set(ev->modifiers, "Super")))
1661      return;
1662    else if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
1663      direction = !direction;
1664    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1665    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
1666        (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
1667      {
1668         _elm_scroll_anim_stop(sid);
1669      }
1670    if (sid->scrollto.x.animator)
1671      {
1672         ecore_animator_del(sid->scrollto.x.animator);
1673         sid->scrollto.x.animator = NULL;
1674      }
1675    if (sid->scrollto.y.animator)
1676      {
1677         ecore_animator_del(sid->scrollto.y.animator);
1678         sid->scrollto.y.animator = NULL;
1679      }
1680    if (sid->down.bounce_x_animator)
1681      {
1682         ecore_animator_del(sid->down.bounce_x_animator);
1683         sid->down.bounce_x_animator = NULL;
1684         sid->bouncemex = EINA_FALSE;
1685         if (sid->content_info.resized)
1686           _elm_scroll_wanted_region_set(sid->obj);
1687      }
1688    if (sid->down.bounce_y_animator)
1689      {
1690         ecore_animator_del(sid->down.bounce_y_animator);
1691         sid->down.bounce_y_animator = NULL;
1692         sid->bouncemey = EINA_FALSE;
1693         if (sid->content_info.resized)
1694           _elm_scroll_wanted_region_set(sid->obj);
1695      }
1696    _elm_scroll_content_viewport_size_get(sid->obj, &vw, &vh);
1697    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1698    if (!direction)
1699      {
1700         if (ch > vh || cw <= vw)
1701           y += ev->z * sid->step.y;
1702         else
1703           x += ev->z * sid->step.x;
1704      }
1705    else if (direction == 1)
1706      {
1707         if (cw > vw || ch <= vh)
1708           x += ev->z * sid->step.x;
1709         else
1710           y += ev->z * sid->step.y;
1711      }
1712
1713    if ((!sid->hold) && (!sid->freeze))
1714      {
1715         _elm_scroll_wanted_coordinates_update(sid, x, y);
1716         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1717      }
1718 }
1719
1720 static Eina_Bool
1721 _elm_scroll_post_event_up(void *data,
1722                           Evas *e __UNUSED__)
1723 {
1724    Elm_Scrollable_Smart_Interface_Data *sid = data;
1725
1726    if (sid->obj)
1727      {
1728         if (sid->down.dragged)
1729           {
1730              elm_widget_drag_lock_x_set(sid->obj, EINA_FALSE);
1731              elm_widget_drag_lock_y_set(sid->obj, EINA_FALSE);
1732           }
1733      }
1734    return EINA_TRUE;
1735 }
1736
1737 static Eina_Bool
1738 _paging_is_enabled(Elm_Scrollable_Smart_Interface_Data *sid)
1739 {
1740    if ((sid->pagerel_h == 0.0) && (!sid->pagesize_h) &&
1741        (sid->pagerel_v == 0.0) && (!sid->pagesize_v))
1742      return EINA_FALSE;
1743    return EINA_TRUE;
1744 }
1745
1746 static Eina_Bool
1747 _elm_scroll_momentum_animator(void *data)
1748 {
1749    double t, dt, p;
1750    Elm_Scrollable_Smart_Interface_Data *sid = data;
1751    Evas_Coord x, y, dx, dy, px, py, maxx, maxy, minx, miny;
1752    Eina_Bool no_bounce_x_end = EINA_FALSE, no_bounce_y_end = EINA_FALSE;
1753
1754    if (!sid->pan_obj) return ECORE_CALLBACK_CANCEL;
1755
1756    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, ECORE_CALLBACK_CANCEL);
1757
1758    t = ecore_loop_time_get();
1759    dt = t - sid->down.anim_start;
1760    if (dt >= 0.0)
1761      {
1762         dt = dt / (_elm_config->thumbscroll_friction + sid->down.extra_time);
1763         if (dt > 1.0) dt = 1.0;
1764         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
1765         dx = (sid->down.dx * (_elm_config->thumbscroll_friction +
1766                               sid->down.extra_time) * p);
1767         dy = (sid->down.dy * (_elm_config->thumbscroll_friction +
1768                               sid->down.extra_time) * p);
1769         sid->down.ax = dx;
1770         sid->down.ay = dy;
1771         x = sid->down.sx - dx;
1772         y = sid->down.sy - dy;
1773         _elm_scroll_content_pos_get(sid->obj, &px, &py);
1774         if ((sid->down.bounce_x_animator) ||
1775             (sid->down.bounce_x_hold))
1776           {
1777              sid->down.bx = sid->down.bx0 - dx + sid->down.b0x;
1778              x = px;
1779           }
1780         if ((sid->down.bounce_y_animator) ||
1781             (sid->down.bounce_y_hold))
1782           {
1783              sid->down.by = sid->down.by0 - dy + sid->down.b0y;
1784              y = py;
1785           }
1786         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1787         _elm_scroll_wanted_coordinates_update(sid, x, y);
1788         psd->api->pos_max_get(sid->pan_obj, &maxx, &maxy);
1789         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1790         if (!sid->bounce_horiz)
1791           {
1792              if (x <= minx) no_bounce_x_end = EINA_TRUE;
1793              if ((x - minx) >= maxx) no_bounce_x_end = EINA_TRUE;
1794           }
1795         if (!sid->bounce_vert)
1796           {
1797              if (y <= miny) no_bounce_y_end = EINA_TRUE;
1798              if ((y - miny) >= maxy) no_bounce_y_end = EINA_TRUE;
1799           }
1800         if ((dt >= 1.0) ||
1801             ((sid->down.bounce_x_hold) && (sid->down.bounce_y_hold)) ||
1802             (no_bounce_x_end && no_bounce_y_end))
1803           {
1804              _elm_scroll_anim_stop(sid);
1805
1806              sid->down.momentum_animator = NULL;
1807              sid->down.bounce_x_hold = EINA_FALSE;
1808              sid->down.bounce_y_hold = EINA_FALSE;
1809              sid->down.ax = 0;
1810              sid->down.ay = 0;
1811              sid->down.pdx = 0;
1812              sid->down.pdy = 0;
1813              if (sid->content_info.resized)
1814                _elm_scroll_wanted_region_set(sid->obj);
1815
1816              return ECORE_CALLBACK_CANCEL;
1817           }
1818      }
1819
1820    return ECORE_CALLBACK_RENEW;
1821 }
1822
1823 static Evas_Coord
1824 _elm_scroll_page_x_get(Elm_Scrollable_Smart_Interface_Data *sid,
1825                        int offset)
1826 {
1827    Evas_Coord x, y, w, h, cw, ch, minx = 0;
1828
1829    if (!sid->pan_obj) return 0;
1830
1831    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
1832
1833    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1834    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
1835    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1836    psd->api->pos_min_get(sid->pan_obj, &minx, NULL);
1837
1838    x += offset;
1839
1840    if (sid->pagerel_h > 0.0)
1841      sid->pagesize_h = w * sid->pagerel_h;
1842    if (sid->pagesize_h > 0)
1843      {
1844         x = x + (sid->pagesize_h * 0.5);
1845         x = x / (sid->pagesize_h);
1846         x = x * (sid->pagesize_h);
1847      }
1848    if ((x + w) > cw) x = cw - w;
1849    if (x < minx) x = minx;
1850
1851    return x;
1852 }
1853
1854 static Evas_Coord
1855 _elm_scroll_page_y_get(Elm_Scrollable_Smart_Interface_Data *sid,
1856                        int offset)
1857 {
1858    Evas_Coord x, y, w, h, cw, ch, miny = 0;
1859
1860    if (!sid->pan_obj) return 0;
1861
1862    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
1863
1864    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1865    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
1866    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1867    psd->api->pos_min_get(sid->pan_obj, NULL, &miny);
1868
1869    y += offset;
1870
1871    if (sid->pagerel_v > 0.0)
1872      sid->pagesize_v = h * sid->pagerel_v;
1873    if (sid->pagesize_v > 0)
1874      {
1875         y = y + (sid->pagesize_v * 0.5);
1876         y = y / (sid->pagesize_v);
1877         y = y * (sid->pagesize_v);
1878      }
1879    if ((y + h) > ch) y = ch - h;
1880    if (y < miny) y = miny;
1881
1882    return y;
1883 }
1884
1885 static Eina_Bool
1886 _elm_scroll_scroll_to_x_animator(void *data)
1887 {
1888    Elm_Scrollable_Smart_Interface_Data *sid = data;
1889    Evas_Coord px, py;
1890    double t, tt;
1891
1892    if (!sid->pan_obj) return ECORE_CALLBACK_CANCEL;
1893
1894    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, ECORE_CALLBACK_CANCEL);
1895
1896    t = ecore_loop_time_get();
1897    tt = (t - sid->scrollto.x.t_start) /
1898      (sid->scrollto.x.t_end - sid->scrollto.x.t_start);
1899    tt = 1.0 - tt;
1900    tt = 1.0 - (tt * tt);
1901    psd->api->pos_get(sid->pan_obj, &px, &py);
1902    px = (sid->scrollto.x.start * (1.0 - tt)) +
1903      (sid->scrollto.x.end * tt);
1904    if (t >= sid->scrollto.x.t_end)
1905      {
1906         px = sid->scrollto.x.end;
1907         _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1908         sid->down.sx = px;
1909         sid->down.x = sid->down.history[0].x;
1910         _elm_scroll_wanted_coordinates_update(sid, px, py);
1911         sid->scrollto.x.animator = NULL;
1912         if ((!sid->scrollto.y.animator) && (!sid->down.bounce_y_animator))
1913           _elm_scroll_anim_stop(sid);
1914         return ECORE_CALLBACK_CANCEL;
1915      }
1916    _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1917    _elm_scroll_wanted_coordinates_update(sid, px, py);
1918    return ECORE_CALLBACK_RENEW;
1919 }
1920
1921 static Eina_Bool
1922 _elm_scroll_scroll_to_y_animator(void *data)
1923 {
1924    Elm_Scrollable_Smart_Interface_Data *sid = data;
1925    Evas_Coord px, py;
1926    double t, tt;
1927
1928    if (!sid->pan_obj) return EINA_FALSE;
1929
1930    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
1931
1932    t = ecore_loop_time_get();
1933    tt = (t - sid->scrollto.y.t_start) /
1934      (sid->scrollto.y.t_end - sid->scrollto.y.t_start);
1935    tt = 1.0 - tt;
1936    tt = 1.0 - (tt * tt);
1937    psd->api->pos_get(sid->pan_obj, &px, &py);
1938    py = (sid->scrollto.y.start * (1.0 - tt)) +
1939      (sid->scrollto.y.end * tt);
1940    if (t >= sid->scrollto.y.t_end)
1941      {
1942         py = sid->scrollto.y.end;
1943         _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1944         sid->down.sy = py;
1945         sid->down.y = sid->down.history[0].y;
1946         _elm_scroll_wanted_coordinates_update(sid, px, py);
1947         sid->scrollto.y.animator = NULL;
1948         if ((!sid->scrollto.x.animator) && (!sid->down.bounce_x_animator))
1949           _elm_scroll_anim_stop(sid);
1950         return ECORE_CALLBACK_CANCEL;
1951      }
1952    _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1953    _elm_scroll_wanted_coordinates_update(sid, px, py);
1954
1955    return ECORE_CALLBACK_RENEW;
1956 }
1957
1958 static void
1959 _elm_scroll_scroll_to_y(Elm_Scrollable_Smart_Interface_Data *sid,
1960                         double t_in,
1961                         Evas_Coord pos_y)
1962 {
1963    Evas_Coord px, py, x, y, w, h;
1964    double t;
1965
1966    if (!sid->pan_obj) return;
1967
1968    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1969
1970    if (sid->freeze) return;
1971    if (t_in <= 0.0)
1972      {
1973         _elm_scroll_content_pos_get(sid->obj, &x, &y);
1974         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
1975         y = pos_y;
1976         _elm_scroll_content_region_set(sid->obj, x, y, w, h);
1977         return;
1978      }
1979    t = ecore_loop_time_get();
1980    psd->api->pos_get(sid->pan_obj, &px, &py);
1981    sid->scrollto.y.start = py;
1982    sid->scrollto.y.end = pos_y;
1983    sid->scrollto.y.t_start = t;
1984    sid->scrollto.y.t_end = t + t_in;
1985    if (!sid->scrollto.y.animator)
1986      {
1987         sid->scrollto.y.animator =
1988           ecore_animator_add(_elm_scroll_scroll_to_y_animator, sid);
1989         if (!sid->scrollto.x.animator)
1990           _elm_scroll_anim_start(sid);
1991      }
1992    if (sid->down.bounce_y_animator)
1993      {
1994         ecore_animator_del(sid->down.bounce_y_animator);
1995         sid->down.bounce_y_animator = NULL;
1996         _elm_scroll_momentum_end(sid);
1997         if (sid->content_info.resized)
1998           _elm_scroll_wanted_region_set(sid->obj);
1999      }
2000    sid->bouncemey = EINA_FALSE;
2001 }
2002
2003 static void
2004 _elm_scroll_scroll_to_x(Elm_Scrollable_Smart_Interface_Data *sid,
2005                         double t_in,
2006                         Evas_Coord pos_x)
2007 {
2008    Evas_Coord px, py, x, y, w, h;
2009    double t;
2010
2011    if (!sid->pan_obj) return;
2012
2013    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2014
2015    if (sid->freeze) return;
2016    if (t_in <= 0.0)
2017      {
2018         _elm_scroll_content_pos_get(sid->obj, &x, &y);
2019         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2020         x = pos_x;
2021         _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2022         return;
2023      }
2024    t = ecore_loop_time_get();
2025    psd->api->pos_get(sid->pan_obj, &px, &py);
2026    sid->scrollto.x.start = px;
2027    sid->scrollto.x.end = pos_x;
2028    sid->scrollto.x.t_start = t;
2029    sid->scrollto.x.t_end = t + t_in;
2030    if (!sid->scrollto.x.animator)
2031      {
2032         sid->scrollto.x.animator =
2033           ecore_animator_add(_elm_scroll_scroll_to_x_animator, sid);
2034         if (!sid->scrollto.y.animator)
2035           _elm_scroll_anim_start(sid);
2036      }
2037    if (sid->down.bounce_x_animator)
2038      {
2039         ecore_animator_del(sid->down.bounce_x_animator);
2040         sid->down.bounce_x_animator = NULL;
2041         _elm_scroll_momentum_end(sid);
2042         if (sid->content_info.resized)
2043           _elm_scroll_wanted_region_set(sid->obj);
2044      }
2045    sid->bouncemex = EINA_FALSE;
2046 }
2047
2048 static void
2049 _elm_scroll_mouse_up_event_cb(void *data,
2050                               Evas *e,
2051                               Evas_Object *obj __UNUSED__,
2052                               void *event_info)
2053 {
2054    Elm_Scrollable_Smart_Interface_Data *sid = data;
2055    Evas_Coord x = 0, y = 0, ox = 0, oy = 0;
2056    Evas_Event_Mouse_Down *ev;
2057
2058    if (!sid->pan_obj) return;
2059
2060    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2061
2062    ev = event_info;
2063    sid->down.hold_parent = EINA_FALSE;
2064    sid->down.dx = 0;
2065    sid->down.dy = 0;
2066    evas_post_event_callback_push(e, _elm_scroll_post_event_up, sid);
2067
2068    // FIXME: respect elm_widget_scroll_hold_get of parent container
2069    if (!_elm_config->thumbscroll_enable) return;
2070
2071    if (ev->button == 1)
2072      {
2073         if (sid->down.onhold_animator)
2074           {
2075              ecore_animator_del(sid->down.onhold_animator);
2076              sid->down.onhold_animator = NULL;
2077              if (sid->content_info.resized)
2078                _elm_scroll_wanted_region_set(sid->obj);
2079           }
2080         x = ev->canvas.x - sid->down.x;
2081         y = ev->canvas.y - sid->down.y;
2082         if (sid->down.dragged)
2083           {
2084              _elm_scroll_drag_stop(sid);
2085              if ((!sid->hold) && (!sid->freeze))
2086                {
2087                   int i;
2088                   double t, at, dt;
2089                   Evas_Coord ax, ay, dx, dy, vel;
2090
2091 #ifdef EVTIME
2092                   t = ev->timestamp / 1000.0;
2093 #else
2094                   t = ecore_loop_time_get();
2095 #endif
2096
2097                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2098                   ax = ev->canvas.x;
2099                   ay = ev->canvas.y;
2100                   at = 0.0;
2101 #ifdef SCROLLDBG
2102                   DBG("------ %i %i\n", ev->canvas.x, ev->canvas.y);
2103 #endif
2104                   for (i = 0; i < 60; i++)
2105                     {
2106                        dt = t - sid->down.history[i].timestamp;
2107                        if (dt > 0.2) break;
2108 #ifdef SCROLLDBG
2109                        DBG("H: %i %i @ %1.3f\n",
2110                            sid->down.history[i].x,
2111                            sid->down.history[i].y, dt);
2112 #endif
2113                        at += dt;
2114                        ax += sid->down.history[i].x;
2115                        ay += sid->down.history[i].y;
2116                     }
2117                   ax /= (i + 1);
2118                   ay /= (i + 1);
2119                   at /= (i + 1);
2120                   at /= _elm_config->thumbscroll_sensitivity_friction;
2121                   dx = ev->canvas.x - ax;
2122                   dy = ev->canvas.y - ay;
2123                   if (at > 0)
2124                     {
2125                        vel = sqrt((dx * dx) + (dy * dy)) / at;
2126                        if ((_elm_config->thumbscroll_friction > 0.0) &&
2127                            (vel > _elm_config->thumbscroll_momentum_threshold))
2128                          {
2129                             sid->down.dx = ((double)dx / at);
2130                             sid->down.dy = ((double)dy / at);
2131                             sid->down.extra_time = 0.0;
2132                             sid->down.pdx = sid->down.dx;
2133                             sid->down.pdy = sid->down.dy;
2134                             ox = -sid->down.dx;
2135                             oy = -sid->down.dy;
2136                             if (!_paging_is_enabled(sid))
2137                               {
2138                                  if ((!sid->down.momentum_animator) &&
2139                                      (!sid->momentum_animator_disabled) &&
2140                                      (sid->obj) &&
2141                                      (!elm_widget_drag_child_locked_y_get
2142                                         (sid->obj)))
2143                                    {
2144                                       sid->down.momentum_animator =
2145                                         ecore_animator_add
2146                                           (_elm_scroll_momentum_animator, sid);
2147                                       ev->event_flags |=
2148                                         EVAS_EVENT_FLAG_ON_SCROLL;
2149                                       _elm_scroll_anim_start(sid);
2150                                    }
2151                                  sid->down.anim_start = ecore_loop_time_get();
2152                                  _elm_scroll_content_pos_get(sid->obj, &x, &y);
2153                                  sid->down.sx = x;
2154                                  sid->down.sy = y;
2155                                  sid->down.b0x = 0;
2156                                  sid->down.b0y = 0;
2157                               }
2158                          }
2159                     }
2160                }
2161              else
2162                {
2163                   sid->down.pdx = 0;
2164                   sid->down.pdy = 0;
2165                }
2166              evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
2167              if (_paging_is_enabled(sid))
2168                {
2169                   Evas_Coord pgx, pgy;
2170
2171                   _elm_scroll_content_pos_get(sid->obj, &x, &y);
2172                   if ((!sid->obj) ||
2173                       (!elm_widget_drag_child_locked_x_get
2174                          (sid->obj)))
2175                     {
2176                        pgx = _elm_scroll_page_x_get(sid, ox);
2177                        if (pgx != x)
2178                          {
2179                             ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2180                             _elm_scroll_scroll_to_x
2181                               (sid, _elm_config->page_scroll_friction, pgx);
2182                          }
2183                     }
2184                   if ((!sid->obj) ||
2185                       (!elm_widget_drag_child_locked_y_get
2186                          (sid->obj)))
2187                     {
2188                        pgy = _elm_scroll_page_y_get(sid, oy);
2189                        if (pgy != y)
2190                          {
2191                             ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2192                             _elm_scroll_scroll_to_y
2193                               (sid, _elm_config->page_scroll_friction, pgy);
2194                          }
2195                     }
2196                }
2197           }
2198         else
2199           {
2200              sid->down.pdx = 0;
2201              sid->down.pdy = 0;
2202              if (_paging_is_enabled(sid))
2203                {
2204                   Evas_Coord pgx, pgy;
2205
2206                   _elm_scroll_content_pos_get(sid->obj, &x, &y);
2207                   if ((!sid->obj) ||
2208                       (!elm_widget_drag_child_locked_x_get
2209                          (sid->obj)))
2210                     {
2211                        pgx = _elm_scroll_page_x_get(sid, ox);
2212                        if (pgx != x)
2213                          _elm_scroll_scroll_to_x
2214                            (sid, _elm_config->page_scroll_friction, pgx);
2215                     }
2216                   if ((!sid->obj) ||
2217                       (!elm_widget_drag_child_locked_y_get
2218                          (sid->obj)))
2219                     {
2220                        pgy = _elm_scroll_page_y_get(sid, oy);
2221                        if (pgy != y)
2222                          _elm_scroll_scroll_to_y
2223                            (sid, _elm_config->page_scroll_friction, pgy);
2224                     }
2225                }
2226           }
2227         if (sid->down.hold_animator)
2228           {
2229              ecore_animator_del(sid->down.hold_animator);
2230              sid->down.hold_animator = NULL;
2231              if (sid->content_info.resized)
2232                _elm_scroll_wanted_region_set(sid->obj);
2233           }
2234         if (sid->down.scroll)
2235           {
2236              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2237              sid->down.scroll = EINA_FALSE;
2238           }
2239         if (sid->down.hold)
2240           {
2241              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2242              sid->down.hold = EINA_FALSE;
2243           }
2244         sid->down.dragged_began = EINA_FALSE;
2245         sid->down.dir_x = EINA_FALSE;
2246         sid->down.dir_y = EINA_FALSE;
2247         sid->down.want_dragged = EINA_FALSE;
2248         sid->down.dragged = EINA_FALSE;
2249         sid->down.now = EINA_FALSE;
2250         _elm_scroll_content_pos_get(sid->obj, &x, &y);
2251         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
2252         _elm_scroll_wanted_coordinates_update(sid, x, y);
2253
2254         if (sid->content_info.resized)
2255           _elm_scroll_wanted_region_set(sid->obj);
2256
2257         if (!_paging_is_enabled(sid))
2258           _elm_scroll_bounce_eval(sid);
2259      }
2260 }
2261
2262 static void
2263 _elm_scroll_mouse_down_event_cb(void *data,
2264                                 Evas *e __UNUSED__,
2265                                 Evas_Object *obj __UNUSED__,
2266                                 void *event_info)
2267 {
2268    Elm_Scrollable_Smart_Interface_Data *sid;
2269    Evas_Event_Mouse_Down *ev;
2270    Evas_Coord x = 0, y = 0;
2271
2272    sid = data;
2273    ev = event_info;
2274
2275    if (_elm_config->thumbscroll_enable)
2276      {
2277         sid->down.hold = EINA_FALSE;
2278         if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
2279             (sid->down.momentum_animator) || (sid->scrollto.x.animator) ||
2280             (sid->scrollto.y.animator))
2281           {
2282              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL |
2283                EVAS_EVENT_FLAG_ON_HOLD;
2284              sid->down.scroll = EINA_TRUE;
2285              sid->down.hold = EINA_TRUE;
2286              _elm_scroll_anim_stop(sid);
2287           }
2288         if (sid->scrollto.x.animator)
2289           {
2290              ecore_animator_del(sid->scrollto.x.animator);
2291              sid->scrollto.x.animator = NULL;
2292           }
2293         if (sid->scrollto.y.animator)
2294           {
2295              ecore_animator_del(sid->scrollto.y.animator);
2296              sid->scrollto.y.animator = NULL;
2297           }
2298         if (sid->down.bounce_x_animator)
2299           {
2300              ecore_animator_del(sid->down.bounce_x_animator);
2301              sid->down.bounce_x_animator = NULL;
2302              sid->bouncemex = EINA_FALSE;
2303              if (sid->content_info.resized)
2304                _elm_scroll_wanted_region_set(sid->obj);
2305           }
2306         if (sid->down.bounce_y_animator)
2307           {
2308              ecore_animator_del(sid->down.bounce_y_animator);
2309              sid->down.bounce_y_animator = NULL;
2310              sid->bouncemey = EINA_FALSE;
2311              if (sid->content_info.resized)
2312                _elm_scroll_wanted_region_set(sid->obj);
2313           }
2314         if (sid->down.hold_animator)
2315           {
2316              ecore_animator_del(sid->down.hold_animator);
2317              sid->down.hold_animator = NULL;
2318              _elm_scroll_drag_stop(sid);
2319              if (sid->content_info.resized)
2320                _elm_scroll_wanted_region_set(sid->obj);
2321           }
2322         if (sid->down.momentum_animator)
2323           {
2324              ecore_animator_del(sid->down.momentum_animator);
2325              sid->down.momentum_animator = NULL;
2326              sid->down.bounce_x_hold = EINA_FALSE;
2327              sid->down.bounce_y_hold = EINA_FALSE;
2328              sid->down.ax = 0;
2329              sid->down.ay = 0;
2330              if (sid->content_info.resized)
2331                _elm_scroll_wanted_region_set(sid->obj);
2332           }
2333         if (ev->button == 1)
2334           {
2335              sid->down.hist.est_timestamp_diff =
2336                ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
2337              sid->down.hist.tadd = 0.0;
2338              sid->down.hist.dxsum = 0.0;
2339              sid->down.hist.dysum = 0.0;
2340              sid->down.now = EINA_TRUE;
2341              sid->down.dragged = EINA_FALSE;
2342              sid->down.dir_x = EINA_FALSE;
2343              sid->down.dir_y = EINA_FALSE;
2344              sid->down.x = ev->canvas.x;
2345              sid->down.y = ev->canvas.y;
2346              _elm_scroll_content_pos_get(sid->obj, &x, &y);
2347              sid->down.sx = x;
2348              sid->down.sy = y;
2349              sid->down.locked = EINA_FALSE;
2350              memset(&(sid->down.history[0]), 0,
2351                     sizeof(sid->down.history[0]) * 60);
2352 #ifdef EVTIME
2353              sid->down.history[0].timestamp = ev->timestamp / 1000.0;
2354              sid->down.history[0].localtimestamp = ecore_loop_time_get();
2355 #else
2356              sid->down.history[0].timestamp = ecore_loop_time_get();
2357 #endif
2358              sid->down.history[0].x = ev->canvas.x;
2359              sid->down.history[0].y = ev->canvas.y;
2360           }
2361         sid->down.dragged_began = EINA_FALSE;
2362         sid->down.hold_parent = EINA_FALSE;
2363         sid->down.cancelled = EINA_FALSE;
2364         if (sid->hold || sid->freeze)
2365           sid->down.want_reset = EINA_TRUE;
2366         else
2367           sid->down.want_reset = EINA_FALSE;
2368      }
2369 }
2370
2371 static Eina_Bool
2372 _elm_scroll_can_scroll(Elm_Scrollable_Smart_Interface_Data *sid,
2373                        int dir)
2374 {
2375    Evas_Coord mx = 0, my = 0, px = 0, py = 0, minx = 0, miny = 0;
2376
2377    if (!sid->pan_obj) return EINA_FALSE;
2378
2379    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
2380
2381    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
2382    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2383    psd->api->pos_get(sid->pan_obj, &px, &py);
2384    switch (dir)
2385      {
2386       case LEFT:
2387         if (px > minx) return EINA_TRUE;
2388         break;
2389
2390       case RIGHT:
2391         if ((px - minx) < mx) return EINA_TRUE;
2392         break;
2393
2394       case UP:
2395         if (py > miny) return EINA_TRUE;
2396         break;
2397
2398       case DOWN:
2399         if ((py - miny) < my) return EINA_TRUE;
2400         break;
2401
2402       default:
2403         break;
2404      }
2405    return EINA_FALSE;
2406 }
2407
2408 static Eina_Bool
2409 _elm_scroll_post_event_move(void *data,
2410                             Evas *e __UNUSED__)
2411 {
2412    Elm_Scrollable_Smart_Interface_Data *sid = data;
2413
2414    if (sid->down.want_dragged)
2415      {
2416         int start = 0;
2417
2418         if (sid->down.hold_parent)
2419           {
2420              if ((sid->down.dir_x) &&
2421                  !_elm_scroll_can_scroll(sid, sid->down.hdir))
2422                {
2423                   sid->down.dir_x = EINA_FALSE;
2424                }
2425              if ((sid->down.dir_y) &&
2426                  !_elm_scroll_can_scroll(sid, sid->down.vdir))
2427                {
2428                   sid->down.dir_y = EINA_FALSE;
2429                }
2430           }
2431         if (sid->down.dir_x)
2432           {
2433              if ((!sid->obj) ||
2434                  (!elm_widget_drag_child_locked_x_get(sid->obj)))
2435                {
2436                   sid->down.want_dragged = EINA_FALSE;
2437                   sid->down.dragged = EINA_TRUE;
2438                   if (sid->obj)
2439                     {
2440                        elm_widget_drag_lock_x_set(sid->obj, 1);
2441                     }
2442                   start = 1;
2443                }
2444              else
2445                sid->down.dir_x = EINA_FALSE;
2446           }
2447         if (sid->down.dir_y)
2448           {
2449              if ((!sid->obj) ||
2450                  (!elm_widget_drag_child_locked_y_get(sid->obj)))
2451                {
2452                   sid->down.want_dragged = EINA_FALSE;
2453                   sid->down.dragged = EINA_TRUE;
2454                   if (sid->obj)
2455                     {
2456                        elm_widget_drag_lock_y_set
2457                          (sid->obj, EINA_TRUE);
2458                     }
2459                   start = 1;
2460                }
2461              else
2462                sid->down.dir_y = EINA_FALSE;
2463           }
2464         if ((!sid->down.dir_x) && (!sid->down.dir_y))
2465           {
2466              sid->down.cancelled = EINA_TRUE;
2467           }
2468         if (start) _elm_scroll_drag_start(sid);
2469      }
2470
2471    return EINA_TRUE;
2472 }
2473
2474 static void
2475 _elm_scroll_down_coord_eval(Elm_Scrollable_Smart_Interface_Data *sid,
2476                             Evas_Coord *x,
2477                             Evas_Coord *y)
2478 {
2479    Evas_Coord minx, miny;
2480
2481    if (!sid->pan_obj) return;
2482
2483    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2484
2485    if (sid->down.dir_x) *x = sid->down.sx - (*x - sid->down.x);
2486    else *x = sid->down.sx;
2487    if (sid->down.dir_y) *y = sid->down.sy - (*y - sid->down.y);
2488    else *y = sid->down.sy;
2489
2490    if ((sid->down.dir_x) || (sid->down.dir_y))
2491      {
2492         if (!((sid->down.dir_x) && (sid->down.dir_y)))
2493           {
2494              if (sid->down.dir_x) *y = sid->down.locked_y;
2495              else *x = sid->down.locked_x;
2496           }
2497      }
2498
2499    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2500
2501    if (*x < minx)
2502      *x += (minx - *x) * _elm_config->thumbscroll_border_friction;
2503    else if (sid->content_info.w <= sid->w)
2504      *x += (sid->down.sx - *x) * _elm_config->thumbscroll_border_friction;
2505    else if ((sid->content_info.w - sid->w + minx) < *x)
2506      *x += (sid->content_info.w - sid->w + minx - *x) *
2507        _elm_config->thumbscroll_border_friction;
2508
2509    if (*y < miny)
2510      *y += (miny - *y) * _elm_config->thumbscroll_border_friction;
2511    else if (sid->content_info.h <= sid->h)
2512      *y += (sid->down.sy - *y) * _elm_config->thumbscroll_border_friction;
2513    else if ((sid->content_info.h - sid->h + miny) < *y)
2514      *y += (sid->content_info.h - sid->h + miny - *y) *
2515        _elm_config->thumbscroll_border_friction;
2516 }
2517
2518 static Eina_Bool
2519 _elm_scroll_hold_animator(void *data)
2520 {
2521    Elm_Scrollable_Smart_Interface_Data *sid = data;
2522    Evas_Coord ox = 0, oy = 0, fx = 0, fy = 0;
2523
2524    fx = sid->down.hold_x;
2525    fy = sid->down.hold_y;
2526
2527    _elm_scroll_content_pos_get(sid->obj, &ox, &oy);
2528    if (sid->down.dir_x)
2529      {
2530         if ((!sid->obj) ||
2531             (!elm_widget_drag_child_locked_x_get(sid->obj)))
2532           ox = fx;
2533      }
2534    if (sid->down.dir_y)
2535      {
2536         if ((!sid->obj) ||
2537             (!elm_widget_drag_child_locked_y_get(sid->obj)))
2538           oy = fy;
2539      }
2540
2541    _elm_scroll_content_pos_set(sid->obj, ox, oy, EINA_TRUE);
2542
2543    return ECORE_CALLBACK_RENEW;
2544 }
2545
2546 static Eina_Bool
2547 _elm_scroll_on_hold_animator(void *data)
2548 {
2549    double t, td;
2550    double vx, vy;
2551    Evas_Coord x, y, ox, oy;
2552    Elm_Scrollable_Smart_Interface_Data *sid;
2553
2554    sid = data;
2555    t = ecore_loop_time_get();
2556    if (sid->down.onhold_tlast > 0.0)
2557      {
2558         td = t - sid->down.onhold_tlast;
2559         vx = sid->down.onhold_vx * td *
2560           (double)_elm_config->thumbscroll_hold_threshold * 2.0;
2561         vy = sid->down.onhold_vy * td *
2562           (double)_elm_config->thumbscroll_hold_threshold * 2.0;
2563         _elm_scroll_content_pos_get(sid->obj, &ox, &oy);
2564         x = ox;
2565         y = oy;
2566
2567         if (sid->down.dir_x)
2568           {
2569              if ((!sid->obj) ||
2570                  (!elm_widget_drag_child_locked_x_get(sid->obj)))
2571                {
2572                   sid->down.onhold_vxe += vx;
2573                   x = ox + (int)sid->down.onhold_vxe;
2574                   sid->down.onhold_vxe -= (int)sid->down.onhold_vxe;
2575                }
2576           }
2577
2578         if (sid->down.dir_y)
2579           {
2580              if ((!sid->obj) ||
2581                  (!elm_widget_drag_child_locked_y_get(sid->obj)))
2582                {
2583                   sid->down.onhold_vye += vy;
2584                   y = oy + (int)sid->down.onhold_vye;
2585                   sid->down.onhold_vye -= (int)sid->down.onhold_vye;
2586                }
2587           }
2588
2589         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
2590      }
2591    sid->down.onhold_tlast = t;
2592
2593    return ECORE_CALLBACK_RENEW;
2594 }
2595
2596 static void
2597 _elm_scroll_mouse_move_event_cb(void *data,
2598                                 Evas *e,
2599                                 Evas_Object *obj __UNUSED__,
2600                                 void *event_info)
2601 {
2602    Elm_Scrollable_Smart_Interface_Data *sid = data;
2603    Evas_Event_Mouse_Move *ev;
2604    Evas_Coord x = 0, y = 0;
2605
2606    if (!sid->pan_obj) return;
2607
2608    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2609
2610    ev = event_info;
2611    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
2612      sid->down.hold_parent = EINA_TRUE;
2613    evas_post_event_callback_push(e, _elm_scroll_post_event_move, sid);
2614
2615    // FIXME: respect elm_widget_scroll_hold_get of parent container
2616    if (_elm_config->thumbscroll_enable)
2617      {
2618         if (sid->down.now)
2619           {
2620              int dodir = 0;
2621
2622              if ((sid->scrollto.x.animator) && (!sid->hold) && (!sid->freeze))
2623                {
2624                   Evas_Coord px;
2625                   ecore_animator_del(sid->scrollto.x.animator);
2626                   sid->scrollto.x.animator = NULL;
2627                   psd->api->pos_get(sid->pan_obj, &px, NULL);
2628                   sid->down.sx = px;
2629                   sid->down.x = sid->down.history[0].x;
2630                }
2631
2632              if ((sid->scrollto.y.animator) && (!sid->hold) && (!sid->freeze))
2633                {
2634                   Evas_Coord py;
2635                   ecore_animator_del(sid->scrollto.y.animator);
2636                   sid->scrollto.y.animator = NULL;
2637                   psd->api->pos_get(sid->pan_obj, NULL, &py);
2638                   sid->down.sy = py;
2639                   sid->down.y = sid->down.history[0].y;
2640                }
2641
2642 #ifdef SCROLLDBG
2643              DBG("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2644 #endif
2645              memmove(&(sid->down.history[1]), &(sid->down.history[0]),
2646                      sizeof(sid->down.history[0]) * (60 - 1));
2647 #ifdef EVTIME
2648              sid->down.history[0].timestamp = ev->timestamp / 1000.0;
2649              sid->down.history[0].localtimestamp = ecore_loop_time_get();
2650 #else
2651              sid->down.history[0].timestamp = ecore_loop_time_get();
2652 #endif
2653              sid->down.history[0].x = ev->cur.canvas.x;
2654              sid->down.history[0].y = ev->cur.canvas.y;
2655
2656              if (!sid->down.dragged_began)
2657                {
2658                   x = ev->cur.canvas.x - sid->down.x;
2659                   y = ev->cur.canvas.y - sid->down.y;
2660
2661                   sid->down.hdir = -1;
2662                   sid->down.vdir = -1;
2663
2664                   if (x > 0) sid->down.hdir = LEFT;
2665                   else if (x < 0)
2666                     sid->down.hdir = RIGHT;
2667                   if (y > 0) sid->down.vdir = UP;
2668                   else if (y < 0)
2669                     sid->down.vdir = DOWN;
2670
2671                   if (x < 0) x = -x;
2672                   if (y < 0) y = -y;
2673
2674                   if ((sid->one_direction_at_a_time) &&
2675                       (!((sid->down.dir_x) || (sid->down.dir_y))))
2676                     {
2677                        if (x > _elm_config->thumbscroll_threshold)
2678                          {
2679                             if (x > (y * 2))
2680                               {
2681                                  sid->down.dir_x = EINA_TRUE;
2682                                  sid->down.dir_y = EINA_FALSE;
2683                                  dodir++;
2684                               }
2685                          }
2686                        if (y > _elm_config->thumbscroll_threshold)
2687                          {
2688                             if (y > (x * 2))
2689                               {
2690                                  sid->down.dir_x = EINA_FALSE;
2691                                  sid->down.dir_y = EINA_TRUE;
2692                                  dodir++;
2693                               }
2694                          }
2695                        if (!dodir)
2696                          {
2697                             sid->down.dir_x = EINA_TRUE;
2698                             sid->down.dir_y = EINA_TRUE;
2699                          }
2700                     }
2701                   else
2702                     {
2703                        sid->down.dir_x = EINA_TRUE;
2704                        sid->down.dir_y = EINA_TRUE;
2705                     }
2706                }
2707              if ((!sid->hold) && (!sid->freeze))
2708                {
2709                   if ((sid->down.dragged) ||
2710                       (((x * x) + (y * y)) >
2711                        (_elm_config->thumbscroll_threshold *
2712                         _elm_config->thumbscroll_threshold)))
2713                     {
2714                        sid->down.dragged_began = EINA_TRUE;
2715                        if (!sid->down.dragged)
2716                          {
2717                             sid->down.want_dragged = EINA_TRUE;
2718                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2719                          }
2720                        if (sid->down.dragged)
2721                          {
2722                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2723                          }
2724                        if (sid->down.dir_x)
2725                          x = sid->down.sx - (ev->cur.canvas.x - sid->down.x);
2726                        else
2727                          x = sid->down.sx;
2728                        if (sid->down.dir_y)
2729                          y = sid->down.sy - (ev->cur.canvas.y - sid->down.y);
2730                        else
2731                          y = sid->down.sy;
2732                        if (sid->down.want_reset)
2733                          {
2734                             sid->down.x = ev->cur.canvas.x;
2735                             sid->down.y = ev->cur.canvas.y;
2736                             sid->down.want_reset = EINA_FALSE;
2737                          }
2738                        if ((sid->down.dir_x) || (sid->down.dir_y))
2739                          {
2740                             if (!sid->down.locked)
2741                               {
2742                                  sid->down.locked_x = x;
2743                                  sid->down.locked_y = y;
2744                                  sid->down.locked = EINA_TRUE;
2745                               }
2746                             if (!((sid->down.dir_x) && (sid->down.dir_y)))
2747                               {
2748                                  if (sid->down.dir_x) y = sid->down.locked_y;
2749                                  else x = sid->down.locked_x;
2750                               }
2751                          }
2752                        {
2753                           Evas_Coord minx, miny, mx, my;
2754
2755                           psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2756                           psd->api->pos_max_get(sid->pan_obj, &mx, &my);
2757                           if (y < miny)
2758                             y += (miny - y) *
2759                               _elm_config->thumbscroll_border_friction;
2760                           else if (my <= 0)
2761                             y += (sid->down.sy - y) *
2762                               _elm_config->thumbscroll_border_friction;
2763                           else if ((my + miny) < y)
2764                             y += (my + miny - y) *
2765                               _elm_config->thumbscroll_border_friction;
2766                           if (x < minx)
2767                             x += (minx - x) *
2768                               _elm_config->thumbscroll_border_friction;
2769                           else if (mx <= 0)
2770                             x += (sid->down.sx - x) *
2771                               _elm_config->thumbscroll_border_friction;
2772                           else if ((mx + minx) < x)
2773                             x += (mx + minx - x) *
2774                               _elm_config->thumbscroll_border_friction;
2775                        }
2776
2777                        sid->down.hold_x = x;
2778                        sid->down.hold_y = y;
2779                        if (!sid->down.hold_animator)
2780                          sid->down.hold_animator =
2781                            ecore_animator_add(_elm_scroll_hold_animator, sid);
2782                     }
2783                   else
2784                     {
2785                        if (sid->down.dragged_began)
2786                          {
2787                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2788                             if (!sid->down.hold)
2789                               {
2790                                  sid->down.hold = EINA_TRUE;
2791                                  evas_event_feed_hold
2792                                    (e, 1, ev->timestamp, ev->data);
2793                               }
2794                          }
2795                     }
2796                }
2797              else if (!sid->freeze)
2798                {
2799                   double vx = 0.0, vy = 0.0;
2800
2801                   x = ev->cur.canvas.x - sid->x;
2802                   y = ev->cur.canvas.y - sid->y;
2803                   if (x < _elm_config->thumbscroll_hold_threshold)
2804                     {
2805                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2806                          vx = -(double)(_elm_config->thumbscroll_hold_threshold - x)
2807                            / _elm_config->thumbscroll_hold_threshold;
2808                        else
2809                          vx = -1.0;
2810                     }
2811                   else if (x > (sid->w - _elm_config->thumbscroll_hold_threshold))
2812                     {
2813                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2814                          vx = (double)(_elm_config->thumbscroll_hold_threshold -
2815                                        (sid->w - x)) /
2816                            _elm_config->thumbscroll_hold_threshold;
2817                        else
2818                          vx = 1.0;
2819                     }
2820                   if (y < _elm_config->thumbscroll_hold_threshold)
2821                     {
2822                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2823                          vy = -(double)(_elm_config->thumbscroll_hold_threshold - y)
2824                            / _elm_config->thumbscroll_hold_threshold;
2825                        else
2826                          vy = -1.0;
2827                     }
2828                   else if (y > (sid->h - _elm_config->thumbscroll_hold_threshold))
2829                     {
2830                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2831                          vy = (double)(_elm_config->thumbscroll_hold_threshold -
2832                                        (sid->h - y)) /
2833                            _elm_config->thumbscroll_hold_threshold;
2834                        else
2835                          vy = 1.0;
2836                     }
2837                   if ((vx != 0.0) || (vy != 0.0))
2838                     {
2839                        sid->down.onhold_vx = vx;
2840                        sid->down.onhold_vy = vy;
2841                        if (!sid->down.onhold_animator)
2842                          {
2843                             sid->down.onhold_vxe = 0.0;
2844                             sid->down.onhold_vye = 0.0;
2845                             sid->down.onhold_tlast = 0.0;
2846                             sid->down.onhold_animator = ecore_animator_add
2847                                 (_elm_scroll_on_hold_animator, sid);
2848                          }
2849                     }
2850                   else
2851                     {
2852                        if (sid->down.onhold_animator)
2853                          {
2854                             ecore_animator_del(sid->down.onhold_animator);
2855                             sid->down.onhold_animator = NULL;
2856                             if (sid->content_info.resized)
2857                               _elm_scroll_wanted_region_set(sid->obj);
2858                          }
2859                     }
2860                }
2861           }
2862      }
2863 }
2864
2865 static void
2866 _elm_scroll_page_adjust(Elm_Scrollable_Smart_Interface_Data *sid)
2867 {
2868    Evas_Coord x, y, w, h;
2869
2870    if (!_paging_is_enabled(sid)) return;
2871
2872    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2873
2874    x = _elm_scroll_page_x_get(sid, 0);
2875    y = _elm_scroll_page_y_get(sid, 0);
2876
2877    _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2878 }
2879
2880 static void
2881 _elm_scroll_reconfigure(Elm_Scrollable_Smart_Interface_Data *sid)
2882 {
2883    _elm_scroll_scroll_bar_size_adjust(sid);
2884    _elm_scroll_page_adjust(sid);
2885 }
2886
2887 static void
2888 _on_edje_move(void *data,
2889               Evas *e __UNUSED__,
2890               Evas_Object *edje_obj,
2891               void *event_info __UNUSED__)
2892 {
2893    Elm_Scrollable_Smart_Interface_Data *sid = data;
2894    int x, y;
2895
2896    evas_object_geometry_get(edje_obj, &x, &y, NULL, NULL);
2897
2898    sid->x = x;
2899    sid->y = y;
2900
2901    _elm_scroll_reconfigure(sid);
2902 }
2903
2904 static void
2905 _on_edje_resize(void *data,
2906                 Evas *e __UNUSED__,
2907                 Evas_Object *edje_obj,
2908                 void *event_info __UNUSED__)
2909 {
2910    Elm_Scrollable_Smart_Interface_Data *sid = data;
2911    int w, h;
2912
2913    evas_object_geometry_get(edje_obj, NULL, NULL, &w, &h);
2914
2915    sid->w = w;
2916    sid->h = h;
2917
2918    _elm_scroll_reconfigure(sid);
2919    _elm_scroll_wanted_region_set(sid->obj);
2920 }
2921
2922 static void
2923 _scroll_edje_object_attach(Evas_Object *obj)
2924 {
2925    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
2926
2927    evas_object_event_callback_add
2928      (sid->edje_obj, EVAS_CALLBACK_RESIZE, _on_edje_resize, sid);
2929    evas_object_event_callback_add
2930      (sid->edje_obj, EVAS_CALLBACK_MOVE, _on_edje_move, sid);
2931
2932    edje_object_signal_callback_add
2933      (sid->edje_obj, "drag", "elm.dragable.vbar", _elm_scroll_vbar_drag_cb,
2934      sid);
2935    edje_object_signal_callback_add
2936      (sid->edje_obj, "drag,set", "elm.dragable.vbar",
2937      _elm_scroll_edje_drag_v_cb, sid);
2938    edje_object_signal_callback_add
2939      (sid->edje_obj, "drag,start", "elm.dragable.vbar",
2940      _elm_scroll_edje_drag_v_start_cb, sid);
2941    edje_object_signal_callback_add
2942      (sid->edje_obj, "drag,stop", "elm.dragable.vbar",
2943      _elm_scroll_edje_drag_v_stop_cb, sid);
2944    edje_object_signal_callback_add
2945      (sid->edje_obj, "drag,step", "elm.dragable.vbar",
2946      _elm_scroll_edje_drag_v_cb, sid);
2947    edje_object_signal_callback_add
2948      (sid->edje_obj, "drag,page", "elm.dragable.vbar",
2949      _elm_scroll_edje_drag_v_cb, sid);
2950    edje_object_signal_callback_add
2951      (sid->edje_obj, "elm,vbar,press", "elm",
2952      _elm_scroll_vbar_press_cb, sid);
2953    edje_object_signal_callback_add
2954      (sid->edje_obj, "elm,vbar,unpress", "elm",
2955      _elm_scroll_vbar_unpress_cb, sid);
2956    edje_object_signal_callback_add
2957      (sid->edje_obj, "drag", "elm.dragable.hbar", _elm_scroll_hbar_drag_cb,
2958      sid);
2959    edje_object_signal_callback_add
2960      (sid->edje_obj, "drag,set", "elm.dragable.hbar",
2961      _elm_scroll_edje_drag_h_cb, sid);
2962    edje_object_signal_callback_add
2963      (sid->edje_obj, "drag,start", "elm.dragable.hbar",
2964      _elm_scroll_edje_drag_h_start_cb, sid);
2965    edje_object_signal_callback_add
2966      (sid->edje_obj, "drag,stop", "elm.dragable.hbar",
2967      _elm_scroll_edje_drag_h_stop_cb, sid);
2968    edje_object_signal_callback_add
2969      (sid->edje_obj, "drag,step", "elm.dragable.hbar",
2970      _elm_scroll_edje_drag_h_cb, sid);
2971    edje_object_signal_callback_add
2972      (sid->edje_obj, "drag,page", "elm.dragable.hbar",
2973      _elm_scroll_edje_drag_h_cb, sid);
2974    edje_object_signal_callback_add
2975      (sid->edje_obj, "elm,hbar,press", "elm",
2976      _elm_scroll_hbar_press_cb, sid);
2977    edje_object_signal_callback_add
2978      (sid->edje_obj, "elm,hbar,unpress", "elm",
2979      _elm_scroll_hbar_unpress_cb, sid);
2980 }
2981
2982 static void
2983 _scroll_event_object_attach(Evas_Object *obj)
2984 {
2985    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
2986
2987    evas_object_event_callback_add
2988      (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _elm_scroll_wheel_event_cb,
2989      sid);
2990    evas_object_event_callback_add
2991      (sid->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
2992      _elm_scroll_mouse_down_event_cb, sid);
2993    evas_object_event_callback_add
2994      (sid->event_rect, EVAS_CALLBACK_MOUSE_UP,
2995      _elm_scroll_mouse_up_event_cb, sid);
2996    evas_object_event_callback_add
2997      (sid->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
2998      _elm_scroll_mouse_move_event_cb, sid);
2999 }
3000
3001 static void
3002 _scroll_edje_object_detach(Evas_Object *obj)
3003 {
3004    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3005
3006    evas_object_event_callback_del_full
3007      (sid->edje_obj, EVAS_CALLBACK_RESIZE, _on_edje_resize, sid);
3008    evas_object_event_callback_del_full
3009      (sid->edje_obj, EVAS_CALLBACK_MOVE, _on_edje_move, sid);
3010
3011    edje_object_signal_callback_del_full
3012      (sid->edje_obj, "drag", "elm.dragable.vbar", _elm_scroll_vbar_drag_cb,
3013      sid);
3014    edje_object_signal_callback_del_full
3015      (sid->edje_obj, "drag,set", "elm.dragable.vbar",
3016      _elm_scroll_edje_drag_v_cb, sid);
3017    edje_object_signal_callback_del_full
3018      (sid->edje_obj, "drag,start", "elm.dragable.vbar",
3019      _elm_scroll_edje_drag_v_start_cb, sid);
3020    edje_object_signal_callback_del_full
3021      (sid->edje_obj, "drag,stop", "elm.dragable.vbar",
3022      _elm_scroll_edje_drag_v_stop_cb, sid);
3023    edje_object_signal_callback_del_full
3024      (sid->edje_obj, "drag,step", "elm.dragable.vbar",
3025      _elm_scroll_edje_drag_v_cb, sid);
3026    edje_object_signal_callback_del_full
3027      (sid->edje_obj, "drag,page", "elm.dragable.vbar",
3028      _elm_scroll_edje_drag_v_cb, sid);
3029    edje_object_signal_callback_del_full
3030      (sid->edje_obj, "elm,vbar,press", "elm",
3031      _elm_scroll_vbar_press_cb, sid);
3032    edje_object_signal_callback_del_full
3033      (sid->edje_obj, "elm,vbar,unpress", "elm",
3034      _elm_scroll_vbar_unpress_cb, sid);
3035    edje_object_signal_callback_del_full
3036      (sid->edje_obj, "drag", "elm.dragable.hbar", _elm_scroll_hbar_drag_cb,
3037      sid);
3038    edje_object_signal_callback_del_full
3039      (sid->edje_obj, "drag,set", "elm.dragable.hbar",
3040      _elm_scroll_edje_drag_h_cb, sid);
3041    edje_object_signal_callback_del_full
3042      (sid->edje_obj, "drag,start", "elm.dragable.hbar",
3043      _elm_scroll_edje_drag_h_start_cb, sid);
3044    edje_object_signal_callback_del_full
3045      (sid->edje_obj, "drag,stop", "elm.dragable.hbar",
3046      _elm_scroll_edje_drag_h_stop_cb, sid);
3047    edje_object_signal_callback_del_full
3048      (sid->edje_obj, "drag,step", "elm.dragable.hbar",
3049      _elm_scroll_edje_drag_h_cb, sid);
3050    edje_object_signal_callback_del_full
3051      (sid->edje_obj, "drag,page", "elm.dragable.hbar",
3052      _elm_scroll_edje_drag_h_cb, sid);
3053    edje_object_signal_callback_del_full
3054      (sid->edje_obj, "elm,hbar,press", "elm",
3055      _elm_scroll_hbar_press_cb, sid);
3056    edje_object_signal_callback_del_full
3057      (sid->edje_obj, "elm,hbar,unpress", "elm",
3058      _elm_scroll_hbar_unpress_cb, sid);
3059 }
3060
3061 static void
3062 _scroll_event_object_detach(Evas_Object *obj)
3063 {
3064    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3065
3066    evas_object_event_callback_del_full
3067      (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _elm_scroll_wheel_event_cb,
3068      sid);
3069    evas_object_event_callback_del_full
3070      (sid->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
3071      _elm_scroll_mouse_down_event_cb, sid);
3072    evas_object_event_callback_del_full
3073      (sid->event_rect, EVAS_CALLBACK_MOUSE_UP,
3074      _elm_scroll_mouse_up_event_cb, sid);
3075    evas_object_event_callback_del_full
3076      (sid->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
3077      _elm_scroll_mouse_move_event_cb, sid);
3078 }
3079
3080 static void
3081 _elm_scroll_objects_set(Evas_Object *obj,
3082                         Evas_Object *edje_object,
3083                         Evas_Object *hit_rectangle)
3084 {
3085    Evas_Coord mw, mh;
3086
3087    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3088
3089    if (!edje_object || !hit_rectangle) return;
3090
3091    if (sid->edje_obj)
3092        _scroll_edje_object_detach(obj);
3093
3094    sid->edje_obj = edje_object;
3095
3096    if (sid->event_rect)
3097        _scroll_event_object_detach(obj);
3098
3099    sid->event_rect = hit_rectangle;
3100    evas_object_repeat_events_set(hit_rectangle, EINA_TRUE);
3101
3102    _scroll_edje_object_attach(obj);
3103    _scroll_event_object_attach(obj);
3104
3105    mw = mh = -1;
3106    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
3107    if (edje_object_part_exists(sid->edje_obj, "elm.scrollbar.base"))
3108      {
3109         Evas_Object *base;
3110
3111         base = edje_object_part_swallow_get
3112             (sid->edje_obj, "elm.scrollbar.base");
3113         if (!base)
3114           {
3115              base = evas_object_rectangle_add
3116                  (evas_object_evas_get(sid->edje_obj));
3117              evas_object_color_set(base, 0, 0, 0, 0);
3118              edje_object_part_swallow
3119                (sid->edje_obj, "elm.scrollbar.base", base);
3120           }
3121         if (!_elm_config->thumbscroll_enable)
3122           evas_object_size_hint_min_set(base, mw, mh);
3123      }
3124
3125    _elm_scroll_scroll_bar_visibility_adjust(sid);
3126 }
3127
3128 static void
3129 _elm_scroll_scroll_bar_reset(Elm_Scrollable_Smart_Interface_Data *sid)
3130 {
3131    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
3132
3133    if (!sid->edje_obj) return;
3134
3135    edje_object_part_drag_value_set
3136      (sid->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
3137    edje_object_part_drag_value_set
3138      (sid->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
3139    if ((!sid->content) && (!sid->extern_pan))
3140      {
3141         edje_object_part_drag_size_set
3142           (sid->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
3143         edje_object_part_drag_size_set
3144           (sid->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
3145      }
3146    if (sid->pan_obj)
3147      {
3148         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3149
3150         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
3151         psd->api->pos_get(sid->pan_obj, &px, &py);
3152         psd->api->pos_set(sid->pan_obj, minx, miny);
3153      }
3154    if ((px != minx) || (py != miny))
3155      edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
3156    _elm_direction_arrows_eval(sid);
3157 }
3158
3159 /* even external pan objects get this */
3160 static void
3161 _elm_scroll_pan_changed_cb(void *data,
3162                            Evas_Object *obj __UNUSED__,
3163                            void *event_info __UNUSED__)
3164 {
3165    Evas_Coord w, h;
3166    Elm_Scrollable_Smart_Interface_Data *sid = data;
3167
3168    if (!sid->pan_obj) return;
3169
3170    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3171
3172    psd->api->content_size_get(sid->pan_obj, &w, &h);
3173    if ((w != sid->content_info.w) || (h != sid->content_info.h))
3174      {
3175         sid->content_info.w = w;
3176         sid->content_info.h = h;
3177         _elm_scroll_scroll_bar_size_adjust(sid);
3178
3179         evas_object_size_hint_min_set
3180           (sid->edje_obj, sid->content_info.w, sid->content_info.h);
3181         sid->content_info.resized = EINA_TRUE;
3182         _elm_scroll_wanted_region_set(sid->obj);
3183      }
3184 }
3185
3186 static void
3187 _elm_scroll_content_del_cb(void *data,
3188                            Evas *e __UNUSED__,
3189                            Evas_Object *obj __UNUSED__,
3190                            void *event_info __UNUSED__)
3191 {
3192    Elm_Scrollable_Smart_Interface_Data *sid = data;
3193
3194    sid->content = NULL;
3195    _elm_scroll_scroll_bar_size_adjust(sid);
3196    _elm_scroll_scroll_bar_reset(sid);
3197 }
3198
3199 static void
3200 _elm_scroll_content_set(Evas_Object *obj,
3201                         Evas_Object *content)
3202 {
3203    Evas_Coord w, h;
3204    Evas_Object *o;
3205
3206    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3207
3208    if (!sid->edje_obj) return;
3209
3210    if (sid->content)
3211      {
3212         /* if we had content, for sure we had a pan object */
3213         _elm_pan_content_set(sid->pan_obj, NULL);
3214         evas_object_event_callback_del_full
3215           (sid->content, EVAS_CALLBACK_DEL, _elm_scroll_content_del_cb, sid);
3216      }
3217
3218    sid->content = content;
3219    sid->wx = sid->wy = 0;
3220    /* (-1) means want viewports size */
3221    sid->ww = sid->wh = -1;
3222    if (!content) return;
3223
3224    if (!sid->pan_obj)
3225      {
3226         o = _elm_pan_add(evas_object_evas_get(obj));
3227         sid->pan_obj = o;
3228         evas_object_smart_callback_add
3229           (o, SIG_CHANGED, _elm_scroll_pan_changed_cb, sid);
3230         edje_object_part_swallow(sid->edje_obj, "elm.swallow.content", o);
3231      }
3232
3233    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3234
3235    evas_object_event_callback_add
3236      (content, EVAS_CALLBACK_DEL, _elm_scroll_content_del_cb, sid);
3237
3238    _elm_pan_content_set(sid->pan_obj, content);
3239    psd->api->content_size_get(sid->pan_obj, &w, &h);
3240    sid->content_info.w = w;
3241    sid->content_info.h = h;
3242
3243    _elm_scroll_scroll_bar_size_adjust(sid);
3244    _elm_scroll_scroll_bar_reset(sid);
3245 }
3246
3247 static void
3248 _elm_scroll_extern_pan_set(Evas_Object *obj,
3249                            Evas_Object *pan)
3250 {
3251    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3252
3253    if (!sid->edje_obj) return;
3254
3255    _elm_scroll_content_set(obj, NULL);
3256
3257    if (sid->pan_obj)
3258      {
3259         evas_object_smart_callback_del
3260           (sid->pan_obj, SIG_CHANGED, _elm_scroll_pan_changed_cb);
3261      }
3262
3263    if (sid->extern_pan)
3264      {
3265         if (sid->pan_obj)
3266           {
3267              /* not owned by scroller, just leave (was external already) */
3268              edje_object_part_unswallow(sid->edje_obj, sid->pan_obj);
3269              sid->pan_obj = NULL;
3270           }
3271      }
3272    else
3273      {
3274         if (sid->pan_obj)
3275           {
3276              evas_object_del(sid->pan_obj);
3277              sid->pan_obj = NULL;
3278           }
3279      }
3280    if (!pan)
3281      {
3282         sid->extern_pan = EINA_FALSE;
3283         return;
3284      }
3285
3286    sid->pan_obj = pan;
3287
3288    sid->extern_pan = EINA_TRUE;
3289    evas_object_smart_callback_add
3290      (sid->pan_obj, SIG_CHANGED, _elm_scroll_pan_changed_cb, sid);
3291    edje_object_part_swallow
3292      (sid->edje_obj, "elm.swallow.content", sid->pan_obj);
3293 }
3294
3295 static void
3296 _elm_scroll_drag_start_cb_set(Evas_Object *obj,
3297                               void (*drag_start_cb)(Evas_Object *obj,
3298                                                     void *data))
3299 {
3300    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3301
3302    sid->cb_func.drag_start = drag_start_cb;
3303 }
3304
3305 static void
3306 _elm_scroll_drag_stop_cb_set(Evas_Object *obj,
3307                              void (*drag_stop_cb)(Evas_Object *obj,
3308                                                   void *data))
3309 {
3310    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3311
3312    sid->cb_func.drag_stop = drag_stop_cb;
3313 }
3314
3315 static void
3316 _elm_scroll_animate_start_cb_set(Evas_Object *obj,
3317                                  void (*animate_start_cb)(Evas_Object *obj,
3318                                                           void *data))
3319 {
3320    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3321
3322    sid->cb_func.animate_start = animate_start_cb;
3323 }
3324
3325 static void
3326 _elm_scroll_animate_stop_cb_set(Evas_Object *obj,
3327                                 void (*animate_stop_cb)(Evas_Object *obj,
3328                                                         void *data))
3329 {
3330    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3331
3332    sid->cb_func.animate_stop = animate_stop_cb;
3333 }
3334
3335 static void
3336 _elm_scroll_scroll_cb_set(Evas_Object *obj,
3337                           void (*scroll_cb)(Evas_Object *obj,
3338                                             void *data))
3339 {
3340    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3341
3342    sid->cb_func.scroll = scroll_cb;
3343 }
3344
3345 static void
3346 _elm_scroll_edge_left_cb_set(Evas_Object *obj,
3347                              void (*edge_left_cb)(Evas_Object *obj,
3348                                                   void *data))
3349 {
3350    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3351
3352    sid->cb_func.edge_left = edge_left_cb;
3353 }
3354
3355 static void
3356 _elm_scroll_edge_right_cb_set(Evas_Object *obj,
3357                               void (*edge_right_cb)(Evas_Object *obj,
3358                                                     void *data))
3359 {
3360    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3361
3362    sid->cb_func.edge_right = edge_right_cb;
3363 }
3364
3365 static void
3366 _elm_scroll_edge_top_cb_set(Evas_Object *obj,
3367                             void (*edge_top_cb)(Evas_Object *obj,
3368                                                 void *data))
3369 {
3370    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3371
3372    sid->cb_func.edge_top = edge_top_cb;
3373 }
3374
3375 static void
3376 _elm_scroll_edge_bottom_cb_set(Evas_Object *obj,
3377                                void (*edge_bottom_cb)(Evas_Object *obj,
3378                                                       void *data))
3379 {
3380    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3381
3382    sid->cb_func.edge_bottom = edge_bottom_cb;
3383 }
3384
3385 static void
3386 _elm_scroll_vbar_drag_cb_set(Evas_Object *obj,
3387                                void (*vbar_drag_cb)(Evas_Object *obj,
3388                                                       void *data))
3389 {
3390    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3391
3392    sid->cb_func.vbar_drag = vbar_drag_cb;
3393 }
3394
3395 static void
3396 _elm_scroll_vbar_press_cb_set(Evas_Object *obj,
3397                                void (*vbar_press_cb)(Evas_Object *obj,
3398                                                       void *data))
3399 {
3400    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3401
3402    sid->cb_func.vbar_press = vbar_press_cb;
3403 }
3404
3405 static void
3406 _elm_scroll_vbar_unpress_cb_set(Evas_Object *obj,
3407                                void (*vbar_unpress_cb)(Evas_Object *obj,
3408                                                       void *data))
3409 {
3410    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3411
3412    sid->cb_func.vbar_unpress = vbar_unpress_cb;
3413 }
3414
3415 static void
3416 _elm_scroll_hbar_drag_cb_set(Evas_Object *obj,
3417                                void (*hbar_drag_cb)(Evas_Object *obj,
3418                                                       void *data))
3419 {
3420    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3421
3422    sid->cb_func.hbar_drag = hbar_drag_cb;
3423 }
3424
3425 static void
3426 _elm_scroll_hbar_press_cb_set(Evas_Object *obj,
3427                                void (*hbar_press_cb)(Evas_Object *obj,
3428                                                       void *data))
3429 {
3430    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3431
3432    sid->cb_func.hbar_press = hbar_press_cb;
3433 }
3434
3435 static void
3436 _elm_scroll_hbar_unpress_cb_set(Evas_Object *obj,
3437                                void (*hbar_unpress_cb)(Evas_Object *obj,
3438                                                       void *data))
3439 {
3440    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3441
3442    sid->cb_func.hbar_unpress = hbar_unpress_cb;
3443 }
3444
3445 static void
3446 _elm_scroll_content_min_limit_cb_set(Evas_Object *obj,
3447                                      void (*c_min_limit_cb)(Evas_Object *obj,
3448                                                             Eina_Bool w,
3449                                                             Eina_Bool h))
3450 {
3451    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3452
3453    sid->cb_func.content_min_limit = c_min_limit_cb;
3454 }
3455
3456 static Eina_Bool
3457 _elm_scroll_momentum_animator_disabled_get(const Evas_Object *obj)
3458 {
3459    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3460
3461    return sid->momentum_animator_disabled;
3462 }
3463
3464 static void
3465 _elm_scroll_momentum_animator_disabled_set(Evas_Object *obj,
3466                                            Eina_Bool disabled)
3467 {
3468    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3469
3470    sid->momentum_animator_disabled = disabled;
3471    if (sid->momentum_animator_disabled)
3472      {
3473         if (sid->down.momentum_animator)
3474           {
3475              ecore_animator_del(sid->down.momentum_animator);
3476              sid->down.momentum_animator = NULL;
3477              if (sid->content_info.resized)
3478                _elm_scroll_wanted_region_set(sid->obj);
3479           }
3480      }
3481 }
3482
3483 static Eina_Bool
3484 _elm_scroll_bounce_animator_disabled_get(const Evas_Object *obj)
3485 {
3486    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3487
3488    return sid->bounce_animator_disabled;
3489 }
3490
3491 static void
3492 _elm_scroll_bounce_animator_disabled_set(Evas_Object *obj,
3493                                          Eina_Bool disabled)
3494 {
3495    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3496
3497    sid->bounce_animator_disabled = disabled;
3498    if (sid->bounce_animator_disabled)
3499      {
3500         if (sid->scrollto.x.animator)
3501           {
3502              ecore_animator_del(sid->scrollto.x.animator);
3503              sid->scrollto.x.animator = NULL;
3504           }
3505
3506         if (sid->scrollto.y.animator)
3507           {
3508              ecore_animator_del(sid->scrollto.y.animator);
3509              sid->scrollto.y.animator = NULL;
3510           }
3511      }
3512 }
3513
3514 static Eina_Bool
3515 _elm_scroll_wheel_disabled_get(const Evas_Object *obj)
3516 {
3517    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3518
3519    return sid->wheel_disabled;
3520 }
3521
3522 static void
3523 _elm_scroll_wheel_disabled_set(Evas_Object *obj,
3524                                Eina_Bool disabled)
3525 {
3526    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3527
3528    if (!sid->event_rect) return;
3529
3530    if ((!sid->wheel_disabled) && (disabled))
3531      evas_object_event_callback_del_full
3532        (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL,
3533        _elm_scroll_wheel_event_cb, sid);
3534    else if ((sid->wheel_disabled) && (!disabled))
3535      evas_object_event_callback_add
3536        (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL,
3537        _elm_scroll_wheel_event_cb, sid);
3538    sid->wheel_disabled = disabled;
3539 }
3540
3541 static void
3542 _elm_scroll_step_size_set(Evas_Object *obj,
3543                           Evas_Coord x,
3544                           Evas_Coord y)
3545 {
3546    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3547
3548    if (x < 1) x = 1;
3549    if (y < 1) y = 1;
3550    sid->step.x = x;
3551    sid->step.y = y;
3552
3553    _elm_scroll_scroll_bar_size_adjust(sid);
3554 }
3555
3556 static void
3557 _elm_scroll_step_size_get(const Evas_Object *obj,
3558                           Evas_Coord *x,
3559                           Evas_Coord *y)
3560 {
3561    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3562
3563    if (x) *x = sid->step.x;
3564    if (y) *y = sid->step.y;
3565 }
3566
3567 static void
3568 _elm_scroll_page_size_set(Evas_Object *obj,
3569                           Evas_Coord x,
3570                           Evas_Coord y)
3571 {
3572    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3573
3574    sid->page.x = x;
3575    sid->page.y = y;
3576
3577    _elm_scroll_scroll_bar_size_adjust(sid);
3578 }
3579
3580 static void
3581 _elm_scroll_page_size_get(const Evas_Object *obj,
3582                           Evas_Coord *x,
3583                           Evas_Coord *y)
3584 {
3585    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3586
3587    if (x) *x = sid->page.x;
3588    if (y) *y = sid->page.y;
3589 }
3590
3591 static void
3592 _elm_scroll_policy_set(Evas_Object *obj,
3593                        Elm_Scroller_Policy hbar,
3594                        Elm_Scroller_Policy vbar)
3595 {
3596    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3597
3598    if (!sid->edje_obj) return;
3599
3600    if ((sid->hbar_flags == hbar) && (sid->vbar_flags == vbar)) return;
3601
3602    sid->hbar_flags = hbar;
3603    sid->vbar_flags = vbar;
3604    if (sid->hbar_flags == ELM_SCROLLER_POLICY_ON)
3605      edje_object_signal_emit
3606        (sid->edje_obj, "elm,action,show_always,hbar", "elm");
3607    else if (sid->hbar_flags == ELM_SCROLLER_POLICY_OFF)
3608      edje_object_signal_emit
3609        (sid->edje_obj, "elm,action,hide,hbar", "elm");
3610    else
3611      edje_object_signal_emit
3612        (sid->edje_obj, "elm,action,show_notalways,hbar", "elm");
3613    if (sid->vbar_flags == ELM_SCROLLER_POLICY_ON)
3614      edje_object_signal_emit
3615        (sid->edje_obj, "elm,action,show_always,vbar", "elm");
3616    else if (sid->vbar_flags == ELM_SCROLLER_POLICY_OFF)
3617      edje_object_signal_emit
3618        (sid->edje_obj, "elm,action,hide,vbar", "elm");
3619    else
3620      edje_object_signal_emit
3621        (sid->edje_obj, "elm,action,show_notalways,vbar", "elm");
3622    edje_object_message_signal_process(sid->edje_obj);
3623    _elm_scroll_scroll_bar_size_adjust(sid);
3624    if (sid->cb_func.content_min_limit)
3625      sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
3626    _elm_direction_arrows_eval(sid);
3627 }
3628
3629 static void
3630 _elm_scroll_policy_get(const Evas_Object *obj,
3631                        Elm_Scroller_Policy *hbar,
3632                        Elm_Scroller_Policy *vbar)
3633 {
3634    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3635
3636    if (hbar) *hbar = sid->hbar_flags;
3637    if (vbar) *vbar = sid->vbar_flags;
3638 }
3639
3640 static void
3641 _elm_scroll_single_direction_set(Evas_Object *obj,
3642                                  Eina_Bool single_dir)
3643 {
3644    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3645
3646    sid->one_direction_at_a_time = single_dir;
3647 }
3648
3649 static Eina_Bool
3650 _elm_scroll_single_direction_get(const Evas_Object *obj)
3651 {
3652    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3653
3654    return sid->one_direction_at_a_time;
3655 }
3656
3657 static void
3658 _elm_scroll_hold_set(Evas_Object *obj,
3659                      Eina_Bool hold)
3660 {
3661    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3662
3663    sid->hold = hold;
3664 }
3665
3666 static void
3667 _elm_scroll_freeze_set(Evas_Object *obj,
3668                        Eina_Bool freeze)
3669 {
3670    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3671
3672    sid->freeze = freeze;
3673    if (sid->freeze)
3674      {
3675         if (sid->down.onhold_animator)
3676           {
3677              ecore_animator_del(sid->down.onhold_animator);
3678              sid->down.onhold_animator = NULL;
3679              if (sid->content_info.resized)
3680                _elm_scroll_wanted_region_set(sid->obj);
3681           }
3682      }
3683    else
3684      _elm_scroll_bounce_eval(sid);
3685 }
3686
3687 static void
3688 _elm_scroll_bounce_allow_set(Evas_Object *obj,
3689                              Eina_Bool horiz,
3690                              Eina_Bool vert)
3691 {
3692    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3693
3694    sid->bounce_horiz = !!horiz;
3695    sid->bounce_vert = !!vert;
3696 }
3697
3698 static void
3699 _elm_scroll_bounce_allow_get(const Evas_Object *obj,
3700                              Eina_Bool *horiz,
3701                              Eina_Bool *vert)
3702 {
3703    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3704
3705    if (horiz) *horiz = sid->bounce_horiz;
3706    if (vert) *vert = sid->bounce_vert;
3707 }
3708
3709 static void
3710 _elm_scroll_paging_set(Evas_Object *obj,
3711                        double pagerel_h,
3712                        double pagerel_v,
3713                        Evas_Coord pagesize_h,
3714                        Evas_Coord pagesize_v)
3715 {
3716    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3717
3718    sid->pagerel_h = pagerel_h;
3719    sid->pagerel_v = pagerel_v;
3720    sid->pagesize_h = pagesize_h;
3721    sid->pagesize_v = pagesize_v;
3722
3723    _elm_scroll_page_adjust(sid);
3724 }
3725
3726 static void
3727 _elm_scroll_paging_get(const Evas_Object *obj,
3728                        double *pagerel_h,
3729                        double *pagerel_v,
3730                        Evas_Coord *pagesize_h,
3731                        Evas_Coord *pagesize_v)
3732 {
3733    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3734
3735    if (pagerel_h) *pagerel_h = sid->pagerel_h;
3736    if (pagerel_v) *pagerel_v = sid->pagerel_v;
3737    if (pagesize_h) *pagesize_h = sid->pagesize_h;
3738    if (pagesize_v) *pagesize_v = sid->pagesize_v;
3739 }
3740
3741 static void
3742 _elm_scroll_current_page_get(const Evas_Object *obj,
3743                              int *pagenumber_h,
3744                              int *pagenumber_v)
3745 {
3746    Evas_Coord x, y;
3747
3748    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3749
3750    _elm_scroll_content_pos_get(sid->obj, &x, &y);
3751    if (pagenumber_h)
3752      {
3753         if (sid->pagesize_h > 0)
3754           *pagenumber_h = (x + sid->pagesize_h - 1) / sid->pagesize_h;
3755         else
3756           *pagenumber_h = 0;
3757      }
3758    if (pagenumber_v)
3759      {
3760         if (sid->pagesize_v > 0)
3761           *pagenumber_v = (y + sid->pagesize_v - 1) / sid->pagesize_v;
3762         else
3763           *pagenumber_v = 0;
3764      }
3765 }
3766
3767 static void
3768 _elm_scroll_last_page_get(const Evas_Object *obj,
3769                           int *pagenumber_h,
3770                           int *pagenumber_v)
3771 {
3772    Evas_Coord cw, ch;
3773
3774    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3775
3776    if (!sid->pan_obj) return;
3777
3778    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3779
3780    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
3781    if (pagenumber_h)
3782      {
3783         if (sid->pagesize_h > 0)
3784           *pagenumber_h = cw / sid->pagesize_h + 1;
3785         else
3786           *pagenumber_h = 0;
3787      }
3788    if (pagenumber_v)
3789      {
3790         if (sid->pagesize_v > 0)
3791           *pagenumber_v = ch / sid->pagesize_v + 1;
3792         else
3793           *pagenumber_v = 0;
3794      }
3795 }
3796
3797 static void
3798 _elm_scroll_page_show(Evas_Object *obj,
3799                       int pagenumber_h,
3800                       int pagenumber_v)
3801 {
3802    Evas_Coord w, h;
3803    Evas_Coord x = 0;
3804    Evas_Coord y = 0;
3805
3806    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3807
3808    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
3809    if (pagenumber_h >= 0) x = sid->pagesize_h * pagenumber_h;
3810    if (pagenumber_v >= 0) y = sid->pagesize_v * pagenumber_v;
3811    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
3812      _elm_scroll_content_pos_set(obj, x, y, EINA_TRUE);
3813 }
3814
3815 static void
3816 _elm_scroll_page_bring_in(Evas_Object *obj,
3817                           int pagenumber_h,
3818                           int pagenumber_v)
3819 {
3820    Evas_Coord w, h;
3821    Evas_Coord x = 0;
3822    Evas_Coord y = 0;
3823
3824    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3825
3826    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
3827    if (pagenumber_h >= 0) x = sid->pagesize_h * pagenumber_h;
3828    if (pagenumber_v >= 0) y = sid->pagesize_v * pagenumber_v;
3829    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
3830      {
3831         _elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
3832         _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
3833      }
3834 }
3835
3836 static void
3837 _elm_scroll_region_bring_in(Evas_Object *obj,
3838                             Evas_Coord x,
3839                             Evas_Coord y,
3840                             Evas_Coord w,
3841                             Evas_Coord h)
3842 {
3843    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3844
3845    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
3846      {
3847         _elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
3848         _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
3849      }
3850 }
3851
3852 static void
3853 _elm_scroll_gravity_set(Evas_Object *obj,
3854                         double x,
3855                         double y)
3856 {
3857    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3858
3859    if (!sid->pan_obj) return;
3860
3861    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3862
3863    psd->api->gravity_set(sid->pan_obj, x, y);
3864 }
3865
3866 static void
3867 _elm_scroll_gravity_get(const Evas_Object *obj,
3868                         double *x,
3869                         double *y)
3870 {
3871    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3872
3873    if (!sid->pan_obj) return;
3874
3875    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3876
3877    psd->api->gravity_get(sid->pan_obj, x, y);
3878 }
3879
3880 static Eina_Bool
3881 _elm_scroll_interface_add(Evas_Object *obj)
3882 {
3883    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3884
3885    memset(sid, 0, sizeof(*sid));
3886
3887    sid->obj = obj;
3888
3889    sid->x = 0;
3890    sid->y = 0;
3891    sid->w = 0;
3892    sid->h = 0;
3893    sid->step.x = 32;
3894    sid->step.y = 32;
3895    sid->page.x = -50;
3896    sid->page.y = -50;
3897    sid->hbar_flags = ELM_SCROLLER_POLICY_AUTO;
3898    sid->vbar_flags = ELM_SCROLLER_POLICY_AUTO;
3899    sid->hbar_visible = EINA_TRUE;
3900    sid->vbar_visible = EINA_TRUE;
3901
3902    sid->bounce_horiz = EINA_TRUE;
3903    sid->bounce_vert = EINA_TRUE;
3904
3905    sid->one_direction_at_a_time = EINA_TRUE;
3906    sid->momentum_animator_disabled = EINA_FALSE;
3907    sid->bounce_animator_disabled = EINA_FALSE;
3908
3909    _elm_scroll_scroll_bar_reset(sid);
3910
3911    return EINA_TRUE;
3912 }
3913
3914 static void
3915 _elm_scroll_interface_del(Evas_Object *obj)
3916 {
3917    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3918
3919    _elm_scroll_content_set(obj, NULL);
3920    if (!sid->extern_pan) evas_object_del(sid->pan_obj);
3921
3922    if (sid->down.hold_animator)
3923      ecore_animator_del(sid->down.hold_animator);
3924    if (sid->down.onhold_animator)
3925      ecore_animator_del(sid->down.onhold_animator);
3926    if (sid->down.momentum_animator)
3927      ecore_animator_del(sid->down.momentum_animator);
3928    if (sid->down.bounce_x_animator)
3929      ecore_animator_del(sid->down.bounce_x_animator);
3930    if (sid->down.bounce_y_animator)
3931      ecore_animator_del(sid->down.bounce_y_animator);
3932    if (sid->scrollto.x.animator) ecore_animator_del(sid->scrollto.x.animator);
3933    if (sid->scrollto.y.animator) ecore_animator_del(sid->scrollto.y.animator);
3934 }
3935
3936 EAPI const char ELM_SCROLLABLE_IFACE_NAME[] = "elm_interface_scrollable";
3937
3938 EAPI const Elm_Scrollable_Smart_Interface ELM_SCROLLABLE_IFACE =
3939 {
3940    {
3941       ELM_SCROLLABLE_IFACE_NAME,
3942       sizeof(Elm_Scrollable_Smart_Interface_Data),
3943       _elm_scroll_interface_add,
3944       _elm_scroll_interface_del
3945    },
3946
3947    _elm_scroll_objects_set,
3948    _elm_scroll_content_set,
3949    _elm_scroll_extern_pan_set,
3950    _elm_scroll_drag_start_cb_set,
3951    _elm_scroll_drag_stop_cb_set,
3952    _elm_scroll_animate_start_cb_set,
3953    _elm_scroll_animate_stop_cb_set,
3954    _elm_scroll_scroll_cb_set,
3955    _elm_scroll_edge_left_cb_set,
3956    _elm_scroll_edge_right_cb_set,
3957    _elm_scroll_edge_top_cb_set,
3958    _elm_scroll_edge_bottom_cb_set,
3959    _elm_scroll_vbar_drag_cb_set,
3960    _elm_scroll_vbar_press_cb_set,
3961    _elm_scroll_vbar_unpress_cb_set,
3962    _elm_scroll_hbar_drag_cb_set,
3963    _elm_scroll_hbar_press_cb_set,
3964    _elm_scroll_hbar_unpress_cb_set,
3965    _elm_scroll_content_min_limit_cb_set,
3966    _elm_scroll_content_pos_set,
3967    _elm_scroll_content_pos_get,
3968    _elm_scroll_content_region_show,
3969    _elm_scroll_content_region_set,
3970    _elm_scroll_content_size_get,
3971    _elm_scroll_content_viewport_size_get,
3972    _elm_scroll_content_min_limit,
3973    _elm_scroll_step_size_set,
3974    _elm_scroll_step_size_get,
3975    _elm_scroll_page_size_set,
3976    _elm_scroll_page_size_get,
3977    _elm_scroll_policy_set,
3978    _elm_scroll_policy_get,
3979    _elm_scroll_single_direction_set,
3980    _elm_scroll_single_direction_get,
3981    _elm_scroll_mirrored_set,
3982    _elm_scroll_hold_set,
3983    _elm_scroll_freeze_set,
3984    _elm_scroll_bounce_allow_set,
3985    _elm_scroll_bounce_allow_get,
3986    _elm_scroll_paging_set,
3987    _elm_scroll_paging_get,
3988    _elm_scroll_current_page_get,
3989    _elm_scroll_last_page_get,
3990    _elm_scroll_page_show,
3991    _elm_scroll_page_bring_in,
3992    _elm_scroll_region_bring_in,
3993    _elm_scroll_gravity_set,
3994    _elm_scroll_gravity_get,
3995    _elm_scroll_momentum_animator_disabled_get,
3996    _elm_scroll_momentum_animator_disabled_set,
3997    _elm_scroll_bounce_animator_disabled_set,
3998    _elm_scroll_bounce_animator_disabled_get,
3999    _elm_scroll_wheel_disabled_get,
4000    _elm_scroll_wheel_disabled_set
4001 };