d7ac688abd534132808df5a1a10aeb6305b11026
[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 (!sid->down.bounce_x_animator)
1368      {
1369         if (((x < minx) && (0 <= sid->down.dx)) ||
1370             ((x > (mx + minx)) && (0 >= sid->down.dx)))
1371           {
1372              sid->bouncemex = EINA_TRUE;
1373              _elm_scroll_bounce_eval(sid);
1374           }
1375         else
1376           sid->bouncemex = EINA_FALSE;
1377      }
1378    if (!sid->down.bounce_y_animator)
1379      {
1380         if (((y < miny) && (0 <= sid->down.dy)) ||
1381             ((y > (my + miny)) && (0 >= sid->down.dy)))
1382           {
1383              sid->bouncemey = EINA_TRUE;
1384              _elm_scroll_bounce_eval(sid);
1385           }
1386         else
1387           sid->bouncemey = EINA_FALSE;
1388      }
1389
1390    if (sig)
1391      {
1392         if ((x != px) || (y != py))
1393           {
1394              if (sid->cb_func.scroll)
1395                sid->cb_func.scroll(obj, NULL);
1396              edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
1397              if (x < px)
1398                {
1399                   if (sid->cb_func.scroll_left)
1400                     sid->cb_func.scroll_left(obj, NULL);
1401                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,left", "elm");
1402                }
1403              if (x > px)
1404                {
1405                   if (sid->cb_func.scroll_right)
1406                     sid->cb_func.scroll_right(obj, NULL);
1407                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,right", "elm");
1408                }
1409              if (y < py)
1410                {
1411                   if (sid->cb_func.scroll_up)
1412                     sid->cb_func.scroll_up(obj, NULL);
1413                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,up", "elm");
1414                }
1415              if (y > py)
1416                {
1417                   if (sid->cb_func.scroll_down)
1418                     sid->cb_func.scroll_down(obj, NULL);
1419                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,down", "elm");
1420                }
1421           }
1422         if (x != px)
1423           {
1424              if (x == minx)
1425                {
1426                   if (sid->cb_func.edge_left)
1427                     sid->cb_func.edge_left(obj, NULL);
1428                   edje_object_signal_emit(sid->edje_obj, "elm,edge,left", "elm");
1429                }
1430              if (x == (mx + minx))
1431                {
1432                   if (sid->cb_func.edge_right)
1433                     sid->cb_func.edge_right(obj, NULL);
1434                   edje_object_signal_emit(sid->edje_obj, "elm,edge,right", "elm");
1435                }
1436           }
1437         if (y != py)
1438           {
1439              if (y == miny)
1440                {
1441                   if (sid->cb_func.edge_top)
1442                     sid->cb_func.edge_top(obj, NULL);
1443                   edje_object_signal_emit(sid->edje_obj, "elm,edge,top", "elm");
1444                }
1445              if (y == my + miny)
1446                {
1447                   if (sid->cb_func.edge_bottom)
1448                     sid->cb_func.edge_bottom(obj, NULL);
1449                   edje_object_signal_emit(sid->edje_obj, "elm,edge,bottom", "elm");
1450                }
1451           }
1452      }
1453
1454    _elm_direction_arrows_eval(sid);
1455 }
1456
1457 static void
1458 _elm_scroll_mirrored_set(Evas_Object *obj,
1459                          Eina_Bool mirrored)
1460 {
1461    Evas_Coord wx;
1462
1463    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1464
1465    if (!sid->edje_obj) return;
1466
1467    mirrored = !!mirrored;
1468
1469    if (sid->is_mirrored == mirrored)
1470      return;
1471
1472    sid->is_mirrored = mirrored;
1473    edje_object_mirrored_set(sid->edje_obj, mirrored);
1474
1475    if (sid->is_mirrored)
1476      wx = _elm_scroll_x_mirrored_get(sid->obj, sid->wx);
1477    else
1478      wx = sid->wx;
1479
1480    _elm_scroll_content_pos_set(sid->obj, wx, sid->wy, EINA_FALSE);
1481 }
1482
1483 /* returns TRUE when we need to move the scroller, FALSE otherwise.
1484  * Updates w and h either way, so save them if you need them. */
1485 static Eina_Bool
1486 _elm_scroll_content_region_show_internal(Evas_Object *obj,
1487                                          Evas_Coord *_x,
1488                                          Evas_Coord *_y,
1489                                          Evas_Coord w,
1490                                          Evas_Coord h)
1491 {
1492    Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny,
1493               minx = 0, miny = 0, pw = 0, ph = 0, x = *_x, y = *_y;
1494
1495    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
1496
1497    if (!sid->pan_obj) return EINA_FALSE;
1498
1499    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
1500
1501    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1502    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1503    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1504    psd->api->pos_get(sid->pan_obj, &px, &py);
1505    evas_object_geometry_get(sid->pan_obj, NULL, NULL, &pw, &ph);
1506
1507    nx = px;
1508    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1509    else if ((x > px) && ((x + w) > (px + (cw - mx))))
1510      nx = x + w - (cw - mx);
1511    ny = py;
1512    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1513    else if ((y > py) && ((y + h) > (py + (ch - my))))
1514      ny = y + h - (ch - my);
1515
1516    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
1517        (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
1518      {
1519         _elm_scroll_anim_stop(sid);
1520      }
1521    if (sid->scrollto.x.animator)
1522      {
1523         ecore_animator_del(sid->scrollto.x.animator);
1524         sid->scrollto.x.animator = NULL;
1525      }
1526    if (sid->scrollto.y.animator)
1527      {
1528         ecore_animator_del(sid->scrollto.y.animator);
1529         sid->scrollto.y.animator = NULL;
1530      }
1531    if (sid->down.bounce_x_animator)
1532      {
1533         ecore_animator_del(sid->down.bounce_x_animator);
1534         sid->down.bounce_x_animator = NULL;
1535         sid->bouncemex = EINA_FALSE;
1536         if (sid->content_info.resized)
1537           _elm_scroll_wanted_region_set(sid->obj);
1538      }
1539    if (sid->down.bounce_y_animator)
1540      {
1541         ecore_animator_del(sid->down.bounce_y_animator);
1542         sid->down.bounce_y_animator = NULL;
1543         sid->bouncemey = EINA_FALSE;
1544         if (sid->content_info.resized)
1545           _elm_scroll_wanted_region_set(sid->obj);
1546      }
1547    if (sid->down.hold_animator)
1548      {
1549         ecore_animator_del(sid->down.hold_animator);
1550         sid->down.hold_animator = NULL;
1551         _elm_scroll_drag_stop(sid);
1552         if (sid->content_info.resized)
1553           _elm_scroll_wanted_region_set(sid->obj);
1554      }
1555    if (sid->down.momentum_animator)
1556      {
1557         ecore_animator_del(sid->down.momentum_animator);
1558         sid->down.momentum_animator = NULL;
1559         sid->down.bounce_x_hold = EINA_FALSE;
1560         sid->down.bounce_y_hold = EINA_FALSE;
1561         sid->down.ax = 0;
1562         sid->down.ay = 0;
1563         sid->down.pdx = 0;
1564         sid->down.pdy = 0;
1565         if (sid->content_info.resized)
1566           _elm_scroll_wanted_region_set(sid->obj);
1567      }
1568
1569    x = nx;
1570    if ((x + pw) > cw) x = cw - pw;
1571    if (x < minx) x = minx;
1572    y = ny;
1573    if ((y + ph) > ch) y = ch - ph;
1574    if (y < miny) y = miny;
1575
1576    if ((x == px) && (y == py)) return EINA_FALSE;
1577    *_x = x;
1578    *_y = y;
1579    return EINA_TRUE;
1580 }
1581
1582 /* Set should be used for calculated positions, for example, when we move
1583  * because of an animation or because this is the correct position after
1584  * constraints. */
1585 static void
1586 _elm_scroll_content_region_set(Evas_Object *obj,
1587                                Evas_Coord x,
1588                                Evas_Coord y,
1589                                Evas_Coord w,
1590                                Evas_Coord h)
1591 {
1592    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1593
1594    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
1595      {
1596         _elm_scroll_content_pos_set(obj, x, y, EINA_FALSE);
1597         sid->down.sx = x;
1598         sid->down.sy = y;
1599         sid->down.x = sid->down.history[0].x;
1600         sid->down.y = sid->down.history[0].y;
1601      }
1602 }
1603
1604 /* Set should be used for setting the wanted position, for example a
1605  * user scroll or moving the cursor in an entry. */
1606 static void
1607 _elm_scroll_content_region_show(Evas_Object *obj,
1608                                 Evas_Coord x,
1609                                 Evas_Coord y,
1610                                 Evas_Coord w,
1611                                 Evas_Coord h)
1612 {
1613    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1614
1615    sid->wx = x;
1616    sid->wy = y;
1617    sid->ww = w;
1618    sid->wh = h;
1619    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
1620      {
1621         _elm_scroll_content_pos_set(obj, x, y, EINA_TRUE);
1622         sid->down.sx = x;
1623         sid->down.sy = y;
1624         sid->down.x = sid->down.history[0].x;
1625         sid->down.y = sid->down.history[0].y;
1626      }
1627 }
1628
1629 static void
1630 _elm_scroll_wanted_region_set(Evas_Object *obj)
1631 {
1632    Evas_Coord ww, wh, wx;
1633
1634    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1635
1636    wx = sid->wx;
1637
1638    if (sid->down.now || sid->down.momentum_animator ||
1639        sid->down.bounce_x_animator || sid->down.bounce_y_animator ||
1640        sid->down.hold_animator || sid->down.onhold_animator ||
1641        sid->scrollto.x.animator || sid->scrollto.y.animator)
1642      return;
1643
1644    sid->content_info.resized = EINA_FALSE;
1645
1646    /* Flip to RTL cords only if init in RTL mode */
1647    if (sid->is_mirrored)
1648      wx = _elm_scroll_x_mirrored_get(obj, sid->wx);
1649
1650    if (sid->ww == -1)
1651      {
1652         _elm_scroll_content_viewport_size_get(obj, &ww, &wh);
1653      }
1654    else
1655      {
1656         ww = sid->ww;
1657         wh = sid->wh;
1658      }
1659
1660    _elm_scroll_content_region_set(obj, wx, sid->wy, ww, wh);
1661 }
1662
1663 static void
1664 _elm_scroll_wheel_event_cb(void *data,
1665                            Evas *e __UNUSED__,
1666                            Evas_Object *obj __UNUSED__,
1667                            void *event_info)
1668 {
1669    Elm_Scrollable_Smart_Interface_Data *sid;
1670    Evas_Event_Mouse_Wheel *ev;
1671    Evas_Coord x = 0, y = 0, vw = 0, vh = 0, cw = 0, ch = 0;
1672    int direction = 0;
1673
1674    sid = data;
1675    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1676    ev = event_info;
1677    direction = ev->direction;
1678    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1679    if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
1680        (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
1681        (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
1682        (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
1683        (evas_key_modifier_is_set(ev->modifiers, "Super")))
1684      return;
1685    else if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
1686      direction = !direction;
1687    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1688    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
1689        (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
1690      {
1691         _elm_scroll_anim_stop(sid);
1692      }
1693    if (sid->scrollto.x.animator)
1694      {
1695         ecore_animator_del(sid->scrollto.x.animator);
1696         sid->scrollto.x.animator = NULL;
1697      }
1698    if (sid->scrollto.y.animator)
1699      {
1700         ecore_animator_del(sid->scrollto.y.animator);
1701         sid->scrollto.y.animator = NULL;
1702      }
1703    if (sid->down.bounce_x_animator)
1704      {
1705         ecore_animator_del(sid->down.bounce_x_animator);
1706         sid->down.bounce_x_animator = NULL;
1707         sid->bouncemex = EINA_FALSE;
1708         if (sid->content_info.resized)
1709           _elm_scroll_wanted_region_set(sid->obj);
1710      }
1711    if (sid->down.bounce_y_animator)
1712      {
1713         ecore_animator_del(sid->down.bounce_y_animator);
1714         sid->down.bounce_y_animator = NULL;
1715         sid->bouncemey = EINA_FALSE;
1716         if (sid->content_info.resized)
1717           _elm_scroll_wanted_region_set(sid->obj);
1718      }
1719    _elm_scroll_content_viewport_size_get(sid->obj, &vw, &vh);
1720    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1721    if (!direction)
1722      {
1723         if (ch > vh || cw <= vw)
1724           y += ev->z * sid->step.y;
1725         else
1726           x += ev->z * sid->step.x;
1727      }
1728    else if (direction == 1)
1729      {
1730         if (cw > vw || ch <= vh)
1731           x += ev->z * sid->step.x;
1732         else
1733           y += ev->z * sid->step.y;
1734      }
1735
1736    if ((!sid->hold) && (!sid->freeze))
1737      {
1738         _elm_scroll_wanted_coordinates_update(sid, x, y);
1739         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1740      }
1741 }
1742
1743 static Eina_Bool
1744 _elm_scroll_post_event_up(void *data,
1745                           Evas *e __UNUSED__)
1746 {
1747    Elm_Scrollable_Smart_Interface_Data *sid = data;
1748
1749    if (sid->obj)
1750      {
1751         if (sid->down.dragged)
1752           {
1753              elm_widget_drag_lock_x_set(sid->obj, EINA_FALSE);
1754              elm_widget_drag_lock_y_set(sid->obj, EINA_FALSE);
1755           }
1756      }
1757    return EINA_TRUE;
1758 }
1759
1760 static Eina_Bool
1761 _paging_is_enabled(Elm_Scrollable_Smart_Interface_Data *sid)
1762 {
1763    if ((sid->pagerel_h == 0.0) && (!sid->pagesize_h) &&
1764        (sid->pagerel_v == 0.0) && (!sid->pagesize_v))
1765      return EINA_FALSE;
1766    return EINA_TRUE;
1767 }
1768
1769 static Eina_Bool
1770 _elm_scroll_momentum_animator(void *data)
1771 {
1772    double t, dt, p;
1773    Elm_Scrollable_Smart_Interface_Data *sid = data;
1774    Evas_Coord x, y, dx, dy, px, py, maxx, maxy, minx, miny;
1775    Eina_Bool no_bounce_x_end = EINA_FALSE, no_bounce_y_end = EINA_FALSE;
1776
1777    if (!sid->pan_obj) return ECORE_CALLBACK_CANCEL;
1778
1779    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, ECORE_CALLBACK_CANCEL);
1780
1781    t = ecore_loop_time_get();
1782    dt = t - sid->down.anim_start;
1783    if (dt >= 0.0)
1784      {
1785         dt = dt / (_elm_config->thumbscroll_friction + sid->down.extra_time);
1786         if (dt > 1.0) dt = 1.0;
1787         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
1788         dx = (sid->down.dx * (_elm_config->thumbscroll_friction +
1789                               sid->down.extra_time) * p);
1790         dy = (sid->down.dy * (_elm_config->thumbscroll_friction +
1791                               sid->down.extra_time) * p);
1792         sid->down.ax = dx;
1793         sid->down.ay = dy;
1794         x = sid->down.sx - dx;
1795         y = sid->down.sy - dy;
1796         _elm_scroll_content_pos_get(sid->obj, &px, &py);
1797         if ((sid->down.bounce_x_animator) ||
1798             (sid->down.bounce_x_hold))
1799           {
1800              sid->down.bx = sid->down.bx0 - dx + sid->down.b0x;
1801              x = px;
1802           }
1803         if ((sid->down.bounce_y_animator) ||
1804             (sid->down.bounce_y_hold))
1805           {
1806              sid->down.by = sid->down.by0 - dy + sid->down.b0y;
1807              y = py;
1808           }
1809         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1810         _elm_scroll_wanted_coordinates_update(sid, x, y);
1811         psd->api->pos_max_get(sid->pan_obj, &maxx, &maxy);
1812         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1813         if (!sid->bounce_horiz)
1814           {
1815              if (x <= minx) no_bounce_x_end = EINA_TRUE;
1816              if ((x - minx) >= maxx) no_bounce_x_end = EINA_TRUE;
1817           }
1818         if (!sid->bounce_vert)
1819           {
1820              if (y <= miny) no_bounce_y_end = EINA_TRUE;
1821              if ((y - miny) >= maxy) no_bounce_y_end = EINA_TRUE;
1822           }
1823         if ((dt >= 1.0) ||
1824             ((sid->down.bounce_x_hold) && (sid->down.bounce_y_hold)) ||
1825             (no_bounce_x_end && no_bounce_y_end))
1826           {
1827              _elm_scroll_anim_stop(sid);
1828
1829              sid->down.momentum_animator = NULL;
1830              sid->down.bounce_x_hold = EINA_FALSE;
1831              sid->down.bounce_y_hold = EINA_FALSE;
1832              sid->down.ax = 0;
1833              sid->down.ay = 0;
1834              sid->down.pdx = 0;
1835              sid->down.pdy = 0;
1836              if (sid->content_info.resized)
1837                _elm_scroll_wanted_region_set(sid->obj);
1838
1839              return ECORE_CALLBACK_CANCEL;
1840           }
1841      }
1842
1843    return ECORE_CALLBACK_RENEW;
1844 }
1845
1846 static Evas_Coord
1847 _elm_scroll_page_x_get(Elm_Scrollable_Smart_Interface_Data *sid,
1848                        int offset)
1849 {
1850    Evas_Coord x, y, w, h, cw, ch, minx = 0;
1851
1852    if (!sid->pan_obj) return 0;
1853
1854    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
1855
1856    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1857    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
1858    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1859    psd->api->pos_min_get(sid->pan_obj, &minx, NULL);
1860
1861    x += offset;
1862
1863    if (sid->pagerel_h > 0.0)
1864      sid->pagesize_h = w * sid->pagerel_h;
1865    if (sid->pagesize_h > 0)
1866      {
1867         x = x + (sid->pagesize_h * 0.5);
1868         x = x / (sid->pagesize_h);
1869         x = x * (sid->pagesize_h);
1870      }
1871    if ((x + w) > cw) x = cw - w;
1872    if (x < minx) x = minx;
1873
1874    return x;
1875 }
1876
1877 static Evas_Coord
1878 _elm_scroll_page_y_get(Elm_Scrollable_Smart_Interface_Data *sid,
1879                        int offset)
1880 {
1881    Evas_Coord x, y, w, h, cw, ch, miny = 0;
1882
1883    if (!sid->pan_obj) return 0;
1884
1885    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
1886
1887    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1888    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
1889    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1890    psd->api->pos_min_get(sid->pan_obj, NULL, &miny);
1891
1892    y += offset;
1893
1894    if (sid->pagerel_v > 0.0)
1895      sid->pagesize_v = h * sid->pagerel_v;
1896    if (sid->pagesize_v > 0)
1897      {
1898         y = y + (sid->pagesize_v * 0.5);
1899         y = y / (sid->pagesize_v);
1900         y = y * (sid->pagesize_v);
1901      }
1902    if ((y + h) > ch) y = ch - h;
1903    if (y < miny) y = miny;
1904
1905    return y;
1906 }
1907
1908 static Eina_Bool
1909 _elm_scroll_scroll_to_x_animator(void *data)
1910 {
1911    Elm_Scrollable_Smart_Interface_Data *sid = data;
1912    Evas_Coord px, py;
1913    double t, tt;
1914
1915    if (!sid->pan_obj) return ECORE_CALLBACK_CANCEL;
1916
1917    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, ECORE_CALLBACK_CANCEL);
1918
1919    t = ecore_loop_time_get();
1920    tt = (t - sid->scrollto.x.t_start) /
1921      (sid->scrollto.x.t_end - sid->scrollto.x.t_start);
1922    tt = 1.0 - tt;
1923    tt = 1.0 - (tt * tt);
1924    psd->api->pos_get(sid->pan_obj, &px, &py);
1925    px = (sid->scrollto.x.start * (1.0 - tt)) +
1926      (sid->scrollto.x.end * tt);
1927    if (t >= sid->scrollto.x.t_end)
1928      {
1929         px = sid->scrollto.x.end;
1930         _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1931         sid->down.sx = px;
1932         sid->down.x = sid->down.history[0].x;
1933         _elm_scroll_wanted_coordinates_update(sid, px, py);
1934         sid->scrollto.x.animator = NULL;
1935         if ((!sid->scrollto.y.animator) && (!sid->down.bounce_y_animator))
1936           _elm_scroll_anim_stop(sid);
1937         return ECORE_CALLBACK_CANCEL;
1938      }
1939    _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1940    _elm_scroll_wanted_coordinates_update(sid, px, py);
1941    return ECORE_CALLBACK_RENEW;
1942 }
1943
1944 static Eina_Bool
1945 _elm_scroll_scroll_to_y_animator(void *data)
1946 {
1947    Elm_Scrollable_Smart_Interface_Data *sid = data;
1948    Evas_Coord px, py;
1949    double t, tt;
1950
1951    if (!sid->pan_obj) return EINA_FALSE;
1952
1953    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
1954
1955    t = ecore_loop_time_get();
1956    tt = (t - sid->scrollto.y.t_start) /
1957      (sid->scrollto.y.t_end - sid->scrollto.y.t_start);
1958    tt = 1.0 - tt;
1959    tt = 1.0 - (tt * tt);
1960    psd->api->pos_get(sid->pan_obj, &px, &py);
1961    py = (sid->scrollto.y.start * (1.0 - tt)) +
1962      (sid->scrollto.y.end * tt);
1963    if (t >= sid->scrollto.y.t_end)
1964      {
1965         py = sid->scrollto.y.end;
1966         _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1967         sid->down.sy = py;
1968         sid->down.y = sid->down.history[0].y;
1969         _elm_scroll_wanted_coordinates_update(sid, px, py);
1970         sid->scrollto.y.animator = NULL;
1971         if ((!sid->scrollto.x.animator) && (!sid->down.bounce_x_animator))
1972           _elm_scroll_anim_stop(sid);
1973         return ECORE_CALLBACK_CANCEL;
1974      }
1975    _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
1976    _elm_scroll_wanted_coordinates_update(sid, px, py);
1977
1978    return ECORE_CALLBACK_RENEW;
1979 }
1980
1981 static void
1982 _elm_scroll_scroll_to_y(Elm_Scrollable_Smart_Interface_Data *sid,
1983                         double t_in,
1984                         Evas_Coord pos_y)
1985 {
1986    Evas_Coord px, py, x, y, w, h;
1987    double t;
1988
1989    if (!sid->pan_obj) return;
1990
1991    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1992
1993    if (sid->freeze) return;
1994    if (t_in <= 0.0)
1995      {
1996         _elm_scroll_content_pos_get(sid->obj, &x, &y);
1997         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
1998         y = pos_y;
1999         _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2000         return;
2001      }
2002    t = ecore_loop_time_get();
2003    psd->api->pos_get(sid->pan_obj, &px, &py);
2004    sid->scrollto.y.start = py;
2005    sid->scrollto.y.end = pos_y;
2006    sid->scrollto.y.t_start = t;
2007    sid->scrollto.y.t_end = t + t_in;
2008    if (!sid->scrollto.y.animator)
2009      {
2010         sid->scrollto.y.animator =
2011           ecore_animator_add(_elm_scroll_scroll_to_y_animator, sid);
2012         if (!sid->scrollto.x.animator)
2013           _elm_scroll_anim_start(sid);
2014      }
2015    if (sid->down.bounce_y_animator)
2016      {
2017         ecore_animator_del(sid->down.bounce_y_animator);
2018         sid->down.bounce_y_animator = NULL;
2019         _elm_scroll_momentum_end(sid);
2020         if (sid->content_info.resized)
2021           _elm_scroll_wanted_region_set(sid->obj);
2022      }
2023    sid->bouncemey = EINA_FALSE;
2024 }
2025
2026 static void
2027 _elm_scroll_scroll_to_x(Elm_Scrollable_Smart_Interface_Data *sid,
2028                         double t_in,
2029                         Evas_Coord pos_x)
2030 {
2031    Evas_Coord px, py, x, y, w, h;
2032    double t;
2033
2034    if (!sid->pan_obj) return;
2035
2036    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2037
2038    if (sid->freeze) return;
2039    if (t_in <= 0.0)
2040      {
2041         _elm_scroll_content_pos_get(sid->obj, &x, &y);
2042         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2043         x = pos_x;
2044         _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2045         return;
2046      }
2047    t = ecore_loop_time_get();
2048    psd->api->pos_get(sid->pan_obj, &px, &py);
2049    sid->scrollto.x.start = px;
2050    sid->scrollto.x.end = pos_x;
2051    sid->scrollto.x.t_start = t;
2052    sid->scrollto.x.t_end = t + t_in;
2053    if (!sid->scrollto.x.animator)
2054      {
2055         sid->scrollto.x.animator =
2056           ecore_animator_add(_elm_scroll_scroll_to_x_animator, sid);
2057         if (!sid->scrollto.y.animator)
2058           _elm_scroll_anim_start(sid);
2059      }
2060    if (sid->down.bounce_x_animator)
2061      {
2062         ecore_animator_del(sid->down.bounce_x_animator);
2063         sid->down.bounce_x_animator = NULL;
2064         _elm_scroll_momentum_end(sid);
2065         if (sid->content_info.resized)
2066           _elm_scroll_wanted_region_set(sid->obj);
2067      }
2068    sid->bouncemex = EINA_FALSE;
2069 }
2070
2071 static void
2072 _elm_scroll_mouse_up_event_cb(void *data,
2073                               Evas *e,
2074                               Evas_Object *obj __UNUSED__,
2075                               void *event_info)
2076 {
2077    Elm_Scrollable_Smart_Interface_Data *sid = data;
2078    Evas_Coord x = 0, y = 0, ox = 0, oy = 0;
2079    Evas_Event_Mouse_Down *ev;
2080
2081    if (!sid->pan_obj) return;
2082
2083    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2084
2085    ev = event_info;
2086    sid->down.hold_parent = EINA_FALSE;
2087    sid->down.dx = 0;
2088    sid->down.dy = 0;
2089    evas_post_event_callback_push(e, _elm_scroll_post_event_up, sid);
2090
2091    // FIXME: respect elm_widget_scroll_hold_get of parent container
2092    if (!_elm_config->thumbscroll_enable) return;
2093
2094    if (ev->button == 1)
2095      {
2096         if (sid->down.onhold_animator)
2097           {
2098              ecore_animator_del(sid->down.onhold_animator);
2099              sid->down.onhold_animator = NULL;
2100              if (sid->content_info.resized)
2101                _elm_scroll_wanted_region_set(sid->obj);
2102           }
2103         x = ev->canvas.x - sid->down.x;
2104         y = ev->canvas.y - sid->down.y;
2105         if (sid->down.dragged)
2106           {
2107              _elm_scroll_drag_stop(sid);
2108              if ((!sid->hold) && (!sid->freeze))
2109                {
2110                   int i;
2111                   double t, at, dt;
2112                   Evas_Coord ax, ay, dx, dy, vel;
2113
2114 #ifdef EVTIME
2115                   t = ev->timestamp / 1000.0;
2116 #else
2117                   t = ecore_loop_time_get();
2118 #endif
2119
2120                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2121                   ax = ev->canvas.x;
2122                   ay = ev->canvas.y;
2123                   at = 0.0;
2124 #ifdef SCROLLDBG
2125                   DBG("------ %i %i\n", ev->canvas.x, ev->canvas.y);
2126 #endif
2127                   for (i = 0; i < 60; i++)
2128                     {
2129                        dt = t - sid->down.history[i].timestamp;
2130                        if (dt > 0.2) break;
2131 #ifdef SCROLLDBG
2132                        DBG("H: %i %i @ %1.3f\n",
2133                            sid->down.history[i].x,
2134                            sid->down.history[i].y, dt);
2135 #endif
2136                        at += dt;
2137                        ax += sid->down.history[i].x;
2138                        ay += sid->down.history[i].y;
2139                     }
2140                   ax /= (i + 1);
2141                   ay /= (i + 1);
2142                   at /= (i + 1);
2143                   at /= _elm_config->thumbscroll_sensitivity_friction;
2144                   dx = ev->canvas.x - ax;
2145                   dy = ev->canvas.y - ay;
2146                   if (at > 0)
2147                     {
2148                        vel = sqrt((dx * dx) + (dy * dy)) / at;
2149                        if ((_elm_config->thumbscroll_friction > 0.0) &&
2150                            (vel > _elm_config->thumbscroll_momentum_threshold))
2151                          {
2152                             sid->down.dx = ((double)dx / at);
2153                             sid->down.dy = ((double)dy / at);
2154                             sid->down.extra_time = 0.0;
2155                             sid->down.pdx = sid->down.dx;
2156                             sid->down.pdy = sid->down.dy;
2157                             ox = -sid->down.dx;
2158                             oy = -sid->down.dy;
2159                             if (!_paging_is_enabled(sid))
2160                               {
2161                                  if ((!sid->down.momentum_animator) &&
2162                                      (!sid->momentum_animator_disabled) &&
2163                                      (sid->obj) &&
2164                                      (!elm_widget_drag_child_locked_y_get
2165                                         (sid->obj)))
2166                                    {
2167                                       sid->down.momentum_animator =
2168                                         ecore_animator_add
2169                                           (_elm_scroll_momentum_animator, sid);
2170                                       ev->event_flags |=
2171                                         EVAS_EVENT_FLAG_ON_SCROLL;
2172                                       _elm_scroll_anim_start(sid);
2173                                    }
2174                                  sid->down.anim_start = ecore_loop_time_get();
2175                                  _elm_scroll_content_pos_get(sid->obj, &x, &y);
2176                                  sid->down.sx = x;
2177                                  sid->down.sy = y;
2178                                  sid->down.b0x = 0;
2179                                  sid->down.b0y = 0;
2180                               }
2181                          }
2182                     }
2183                }
2184              else
2185                {
2186                   sid->down.pdx = 0;
2187                   sid->down.pdy = 0;
2188                }
2189              evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
2190              if (_paging_is_enabled(sid))
2191                {
2192                   Evas_Coord pgx, pgy;
2193
2194                   _elm_scroll_content_pos_get(sid->obj, &x, &y);
2195                   if ((!sid->obj) ||
2196                       (!elm_widget_drag_child_locked_x_get
2197                          (sid->obj)))
2198                     {
2199                        pgx = _elm_scroll_page_x_get(sid, ox);
2200                        if (pgx != x)
2201                          {
2202                             ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2203                             _elm_scroll_scroll_to_x
2204                               (sid, _elm_config->page_scroll_friction, pgx);
2205                          }
2206                     }
2207                   if ((!sid->obj) ||
2208                       (!elm_widget_drag_child_locked_y_get
2209                          (sid->obj)))
2210                     {
2211                        pgy = _elm_scroll_page_y_get(sid, oy);
2212                        if (pgy != y)
2213                          {
2214                             ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2215                             _elm_scroll_scroll_to_y
2216                               (sid, _elm_config->page_scroll_friction, pgy);
2217                          }
2218                     }
2219                }
2220           }
2221         else
2222           {
2223              sid->down.pdx = 0;
2224              sid->down.pdy = 0;
2225              if (_paging_is_enabled(sid))
2226                {
2227                   Evas_Coord pgx, pgy;
2228
2229                   _elm_scroll_content_pos_get(sid->obj, &x, &y);
2230                   if ((!sid->obj) ||
2231                       (!elm_widget_drag_child_locked_x_get
2232                          (sid->obj)))
2233                     {
2234                        pgx = _elm_scroll_page_x_get(sid, ox);
2235                        if (pgx != x)
2236                          _elm_scroll_scroll_to_x
2237                            (sid, _elm_config->page_scroll_friction, pgx);
2238                     }
2239                   if ((!sid->obj) ||
2240                       (!elm_widget_drag_child_locked_y_get
2241                          (sid->obj)))
2242                     {
2243                        pgy = _elm_scroll_page_y_get(sid, oy);
2244                        if (pgy != y)
2245                          _elm_scroll_scroll_to_y
2246                            (sid, _elm_config->page_scroll_friction, pgy);
2247                     }
2248                }
2249           }
2250         if (sid->down.hold_animator)
2251           {
2252              ecore_animator_del(sid->down.hold_animator);
2253              sid->down.hold_animator = NULL;
2254              if (sid->content_info.resized)
2255                _elm_scroll_wanted_region_set(sid->obj);
2256           }
2257         if (sid->down.scroll)
2258           {
2259              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2260              sid->down.scroll = EINA_FALSE;
2261           }
2262         if (sid->down.hold)
2263           {
2264              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2265              sid->down.hold = EINA_FALSE;
2266           }
2267         sid->down.dragged_began = EINA_FALSE;
2268         sid->down.dir_x = EINA_FALSE;
2269         sid->down.dir_y = EINA_FALSE;
2270         sid->down.want_dragged = EINA_FALSE;
2271         sid->down.dragged = EINA_FALSE;
2272         sid->down.now = EINA_FALSE;
2273         _elm_scroll_content_pos_get(sid->obj, &x, &y);
2274         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
2275         _elm_scroll_wanted_coordinates_update(sid, x, y);
2276
2277         if (sid->content_info.resized)
2278           _elm_scroll_wanted_region_set(sid->obj);
2279
2280         if (!_paging_is_enabled(sid))
2281           _elm_scroll_bounce_eval(sid);
2282      }
2283 }
2284
2285 static void
2286 _elm_scroll_mouse_down_event_cb(void *data,
2287                                 Evas *e __UNUSED__,
2288                                 Evas_Object *obj __UNUSED__,
2289                                 void *event_info)
2290 {
2291    Elm_Scrollable_Smart_Interface_Data *sid;
2292    Evas_Event_Mouse_Down *ev;
2293    Evas_Coord x = 0, y = 0;
2294
2295    sid = data;
2296    ev = event_info;
2297
2298    if (_elm_config->thumbscroll_enable)
2299      {
2300         sid->down.hold = EINA_FALSE;
2301         if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
2302             (sid->down.momentum_animator) || (sid->scrollto.x.animator) ||
2303             (sid->scrollto.y.animator))
2304           {
2305              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL |
2306                EVAS_EVENT_FLAG_ON_HOLD;
2307              sid->down.scroll = EINA_TRUE;
2308              sid->down.hold = EINA_TRUE;
2309              _elm_scroll_anim_stop(sid);
2310           }
2311         if (sid->scrollto.x.animator)
2312           {
2313              ecore_animator_del(sid->scrollto.x.animator);
2314              sid->scrollto.x.animator = NULL;
2315           }
2316         if (sid->scrollto.y.animator)
2317           {
2318              ecore_animator_del(sid->scrollto.y.animator);
2319              sid->scrollto.y.animator = NULL;
2320           }
2321         if (sid->down.bounce_x_animator)
2322           {
2323              ecore_animator_del(sid->down.bounce_x_animator);
2324              sid->down.bounce_x_animator = NULL;
2325              sid->bouncemex = EINA_FALSE;
2326              if (sid->content_info.resized)
2327                _elm_scroll_wanted_region_set(sid->obj);
2328           }
2329         if (sid->down.bounce_y_animator)
2330           {
2331              ecore_animator_del(sid->down.bounce_y_animator);
2332              sid->down.bounce_y_animator = NULL;
2333              sid->bouncemey = EINA_FALSE;
2334              if (sid->content_info.resized)
2335                _elm_scroll_wanted_region_set(sid->obj);
2336           }
2337         if (sid->down.hold_animator)
2338           {
2339              ecore_animator_del(sid->down.hold_animator);
2340              sid->down.hold_animator = NULL;
2341              _elm_scroll_drag_stop(sid);
2342              if (sid->content_info.resized)
2343                _elm_scroll_wanted_region_set(sid->obj);
2344           }
2345         if (sid->down.momentum_animator)
2346           {
2347              ecore_animator_del(sid->down.momentum_animator);
2348              sid->down.momentum_animator = NULL;
2349              sid->down.bounce_x_hold = EINA_FALSE;
2350              sid->down.bounce_y_hold = EINA_FALSE;
2351              sid->down.ax = 0;
2352              sid->down.ay = 0;
2353              if (sid->content_info.resized)
2354                _elm_scroll_wanted_region_set(sid->obj);
2355           }
2356         if (ev->button == 1)
2357           {
2358              sid->down.hist.est_timestamp_diff =
2359                ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
2360              sid->down.hist.tadd = 0.0;
2361              sid->down.hist.dxsum = 0.0;
2362              sid->down.hist.dysum = 0.0;
2363              sid->down.now = EINA_TRUE;
2364              sid->down.dragged = EINA_FALSE;
2365              sid->down.dir_x = EINA_FALSE;
2366              sid->down.dir_y = EINA_FALSE;
2367              sid->down.x = ev->canvas.x;
2368              sid->down.y = ev->canvas.y;
2369              _elm_scroll_content_pos_get(sid->obj, &x, &y);
2370              sid->down.sx = x;
2371              sid->down.sy = y;
2372              sid->down.locked = EINA_FALSE;
2373              memset(&(sid->down.history[0]), 0,
2374                     sizeof(sid->down.history[0]) * 60);
2375 #ifdef EVTIME
2376              sid->down.history[0].timestamp = ev->timestamp / 1000.0;
2377              sid->down.history[0].localtimestamp = ecore_loop_time_get();
2378 #else
2379              sid->down.history[0].timestamp = ecore_loop_time_get();
2380 #endif
2381              sid->down.history[0].x = ev->canvas.x;
2382              sid->down.history[0].y = ev->canvas.y;
2383           }
2384         sid->down.dragged_began = EINA_FALSE;
2385         sid->down.hold_parent = EINA_FALSE;
2386         sid->down.cancelled = EINA_FALSE;
2387         if (sid->hold || sid->freeze)
2388           sid->down.want_reset = EINA_TRUE;
2389         else
2390           sid->down.want_reset = EINA_FALSE;
2391      }
2392 }
2393
2394 static Eina_Bool
2395 _elm_scroll_can_scroll(Elm_Scrollable_Smart_Interface_Data *sid,
2396                        int dir)
2397 {
2398    Evas_Coord mx = 0, my = 0, px = 0, py = 0, minx = 0, miny = 0;
2399
2400    if (!sid->pan_obj) return EINA_FALSE;
2401
2402    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
2403
2404    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
2405    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2406    psd->api->pos_get(sid->pan_obj, &px, &py);
2407    switch (dir)
2408      {
2409       case LEFT:
2410         if (px > minx) return EINA_TRUE;
2411         break;
2412
2413       case RIGHT:
2414         if ((px - minx) < mx) return EINA_TRUE;
2415         break;
2416
2417       case UP:
2418         if (py > miny) return EINA_TRUE;
2419         break;
2420
2421       case DOWN:
2422         if ((py - miny) < my) return EINA_TRUE;
2423         break;
2424
2425       default:
2426         break;
2427      }
2428    return EINA_FALSE;
2429 }
2430
2431 static Eina_Bool
2432 _elm_scroll_post_event_move(void *data,
2433                             Evas *e __UNUSED__)
2434 {
2435    Elm_Scrollable_Smart_Interface_Data *sid = data;
2436
2437    if (sid->down.want_dragged)
2438      {
2439         int start = 0;
2440
2441         if (sid->down.hold_parent)
2442           {
2443              if ((sid->down.dir_x) &&
2444                  !_elm_scroll_can_scroll(sid, sid->down.hdir))
2445                {
2446                   sid->down.dir_x = EINA_FALSE;
2447                }
2448              if ((sid->down.dir_y) &&
2449                  !_elm_scroll_can_scroll(sid, sid->down.vdir))
2450                {
2451                   sid->down.dir_y = EINA_FALSE;
2452                }
2453           }
2454         if (sid->down.dir_x)
2455           {
2456              if ((!sid->obj) ||
2457                  (!elm_widget_drag_child_locked_x_get(sid->obj)))
2458                {
2459                   sid->down.want_dragged = EINA_FALSE;
2460                   sid->down.dragged = EINA_TRUE;
2461                   if (sid->obj)
2462                     {
2463                        elm_widget_drag_lock_x_set(sid->obj, 1);
2464                     }
2465                   start = 1;
2466                }
2467              else
2468                sid->down.dir_x = EINA_FALSE;
2469           }
2470         if (sid->down.dir_y)
2471           {
2472              if ((!sid->obj) ||
2473                  (!elm_widget_drag_child_locked_y_get(sid->obj)))
2474                {
2475                   sid->down.want_dragged = EINA_FALSE;
2476                   sid->down.dragged = EINA_TRUE;
2477                   if (sid->obj)
2478                     {
2479                        elm_widget_drag_lock_y_set
2480                          (sid->obj, EINA_TRUE);
2481                     }
2482                   start = 1;
2483                }
2484              else
2485                sid->down.dir_y = EINA_FALSE;
2486           }
2487         if ((!sid->down.dir_x) && (!sid->down.dir_y))
2488           {
2489              sid->down.cancelled = EINA_TRUE;
2490           }
2491         if (start) _elm_scroll_drag_start(sid);
2492      }
2493
2494    return EINA_TRUE;
2495 }
2496
2497 static void
2498 _elm_scroll_down_coord_eval(Elm_Scrollable_Smart_Interface_Data *sid,
2499                             Evas_Coord *x,
2500                             Evas_Coord *y)
2501 {
2502    Evas_Coord minx, miny;
2503
2504    if (!sid->pan_obj) return;
2505
2506    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2507
2508    if (sid->down.dir_x) *x = sid->down.sx - (*x - sid->down.x);
2509    else *x = sid->down.sx;
2510    if (sid->down.dir_y) *y = sid->down.sy - (*y - sid->down.y);
2511    else *y = sid->down.sy;
2512
2513    if ((sid->down.dir_x) || (sid->down.dir_y))
2514      {
2515         if (!((sid->down.dir_x) && (sid->down.dir_y)))
2516           {
2517              if (sid->down.dir_x) *y = sid->down.locked_y;
2518              else *x = sid->down.locked_x;
2519           }
2520      }
2521
2522    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2523
2524    if (*x < minx)
2525      *x += (minx - *x) * _elm_config->thumbscroll_border_friction;
2526    else if (sid->content_info.w <= sid->w)
2527      *x += (sid->down.sx - *x) * _elm_config->thumbscroll_border_friction;
2528    else if ((sid->content_info.w - sid->w + minx) < *x)
2529      *x += (sid->content_info.w - sid->w + minx - *x) *
2530        _elm_config->thumbscroll_border_friction;
2531
2532    if (*y < miny)
2533      *y += (miny - *y) * _elm_config->thumbscroll_border_friction;
2534    else if (sid->content_info.h <= sid->h)
2535      *y += (sid->down.sy - *y) * _elm_config->thumbscroll_border_friction;
2536    else if ((sid->content_info.h - sid->h + miny) < *y)
2537      *y += (sid->content_info.h - sid->h + miny - *y) *
2538        _elm_config->thumbscroll_border_friction;
2539 }
2540
2541 static Eina_Bool
2542 _elm_scroll_hold_animator(void *data)
2543 {
2544    Elm_Scrollable_Smart_Interface_Data *sid = data;
2545    Evas_Coord ox = 0, oy = 0, fx = 0, fy = 0;
2546
2547    fx = sid->down.hold_x;
2548    fy = sid->down.hold_y;
2549
2550    _elm_scroll_content_pos_get(sid->obj, &ox, &oy);
2551    if (sid->down.dir_x)
2552      {
2553         if ((!sid->obj) ||
2554             (!elm_widget_drag_child_locked_x_get(sid->obj)))
2555           ox = fx;
2556      }
2557    if (sid->down.dir_y)
2558      {
2559         if ((!sid->obj) ||
2560             (!elm_widget_drag_child_locked_y_get(sid->obj)))
2561           oy = fy;
2562      }
2563
2564    _elm_scroll_content_pos_set(sid->obj, ox, oy, EINA_TRUE);
2565
2566    return ECORE_CALLBACK_RENEW;
2567 }
2568
2569 static Eina_Bool
2570 _elm_scroll_on_hold_animator(void *data)
2571 {
2572    double t, td;
2573    double vx, vy;
2574    Evas_Coord x, y, ox, oy;
2575    Elm_Scrollable_Smart_Interface_Data *sid;
2576
2577    sid = data;
2578    t = ecore_loop_time_get();
2579    if (sid->down.onhold_tlast > 0.0)
2580      {
2581         td = t - sid->down.onhold_tlast;
2582         vx = sid->down.onhold_vx * td *
2583           (double)_elm_config->thumbscroll_hold_threshold * 2.0;
2584         vy = sid->down.onhold_vy * td *
2585           (double)_elm_config->thumbscroll_hold_threshold * 2.0;
2586         _elm_scroll_content_pos_get(sid->obj, &ox, &oy);
2587         x = ox;
2588         y = oy;
2589
2590         if (sid->down.dir_x)
2591           {
2592              if ((!sid->obj) ||
2593                  (!elm_widget_drag_child_locked_x_get(sid->obj)))
2594                {
2595                   sid->down.onhold_vxe += vx;
2596                   x = ox + (int)sid->down.onhold_vxe;
2597                   sid->down.onhold_vxe -= (int)sid->down.onhold_vxe;
2598                }
2599           }
2600
2601         if (sid->down.dir_y)
2602           {
2603              if ((!sid->obj) ||
2604                  (!elm_widget_drag_child_locked_y_get(sid->obj)))
2605                {
2606                   sid->down.onhold_vye += vy;
2607                   y = oy + (int)sid->down.onhold_vye;
2608                   sid->down.onhold_vye -= (int)sid->down.onhold_vye;
2609                }
2610           }
2611
2612         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
2613      }
2614    sid->down.onhold_tlast = t;
2615
2616    return ECORE_CALLBACK_RENEW;
2617 }
2618
2619 static void
2620 _elm_scroll_mouse_move_event_cb(void *data,
2621                                 Evas *e,
2622                                 Evas_Object *obj __UNUSED__,
2623                                 void *event_info)
2624 {
2625    Elm_Scrollable_Smart_Interface_Data *sid = data;
2626    Evas_Event_Mouse_Move *ev;
2627    Evas_Coord x = 0, y = 0;
2628
2629    if (!sid->pan_obj) return;
2630
2631    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2632
2633    ev = event_info;
2634    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
2635      sid->down.hold_parent = EINA_TRUE;
2636    evas_post_event_callback_push(e, _elm_scroll_post_event_move, sid);
2637
2638    // FIXME: respect elm_widget_scroll_hold_get of parent container
2639    if (_elm_config->thumbscroll_enable)
2640      {
2641         if (sid->down.now)
2642           {
2643              int dodir = 0;
2644
2645              if ((sid->scrollto.x.animator) && (!sid->hold) && (!sid->freeze))
2646                {
2647                   Evas_Coord px;
2648                   ecore_animator_del(sid->scrollto.x.animator);
2649                   sid->scrollto.x.animator = NULL;
2650                   psd->api->pos_get(sid->pan_obj, &px, NULL);
2651                   sid->down.sx = px;
2652                   sid->down.x = sid->down.history[0].x;
2653                }
2654
2655              if ((sid->scrollto.y.animator) && (!sid->hold) && (!sid->freeze))
2656                {
2657                   Evas_Coord py;
2658                   ecore_animator_del(sid->scrollto.y.animator);
2659                   sid->scrollto.y.animator = NULL;
2660                   psd->api->pos_get(sid->pan_obj, NULL, &py);
2661                   sid->down.sy = py;
2662                   sid->down.y = sid->down.history[0].y;
2663                }
2664
2665 #ifdef SCROLLDBG
2666              DBG("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2667 #endif
2668              memmove(&(sid->down.history[1]), &(sid->down.history[0]),
2669                      sizeof(sid->down.history[0]) * (60 - 1));
2670 #ifdef EVTIME
2671              sid->down.history[0].timestamp = ev->timestamp / 1000.0;
2672              sid->down.history[0].localtimestamp = ecore_loop_time_get();
2673 #else
2674              sid->down.history[0].timestamp = ecore_loop_time_get();
2675 #endif
2676              sid->down.history[0].x = ev->cur.canvas.x;
2677              sid->down.history[0].y = ev->cur.canvas.y;
2678
2679              if (!sid->down.dragged_began)
2680                {
2681                   x = ev->cur.canvas.x - sid->down.x;
2682                   y = ev->cur.canvas.y - sid->down.y;
2683
2684                   sid->down.hdir = -1;
2685                   sid->down.vdir = -1;
2686
2687                   if (x > 0) sid->down.hdir = LEFT;
2688                   else if (x < 0)
2689                     sid->down.hdir = RIGHT;
2690                   if (y > 0) sid->down.vdir = UP;
2691                   else if (y < 0)
2692                     sid->down.vdir = DOWN;
2693
2694                   if (x < 0) x = -x;
2695                   if (y < 0) y = -y;
2696
2697                   if ((sid->one_direction_at_a_time) &&
2698                       (!((sid->down.dir_x) || (sid->down.dir_y))))
2699                     {
2700                        if (x > _elm_config->thumbscroll_threshold)
2701                          {
2702                             if (x > (y * 2))
2703                               {
2704                                  sid->down.dir_x = EINA_TRUE;
2705                                  sid->down.dir_y = EINA_FALSE;
2706                                  dodir++;
2707                               }
2708                          }
2709                        if (y > _elm_config->thumbscroll_threshold)
2710                          {
2711                             if (y > (x * 2))
2712                               {
2713                                  sid->down.dir_x = EINA_FALSE;
2714                                  sid->down.dir_y = EINA_TRUE;
2715                                  dodir++;
2716                               }
2717                          }
2718                        if (!dodir)
2719                          {
2720                             sid->down.dir_x = EINA_TRUE;
2721                             sid->down.dir_y = EINA_TRUE;
2722                          }
2723                     }
2724                   else
2725                     {
2726                        sid->down.dir_x = EINA_TRUE;
2727                        sid->down.dir_y = EINA_TRUE;
2728                     }
2729                }
2730              if ((!sid->hold) && (!sid->freeze))
2731                {
2732                   if ((sid->down.dragged) ||
2733                       (((x * x) + (y * y)) >
2734                        (_elm_config->thumbscroll_threshold *
2735                         _elm_config->thumbscroll_threshold)))
2736                     {
2737                        sid->down.dragged_began = EINA_TRUE;
2738                        if (!sid->down.dragged)
2739                          {
2740                             sid->down.want_dragged = EINA_TRUE;
2741                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2742                          }
2743                        if (sid->down.dragged)
2744                          {
2745                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2746                          }
2747                        if (sid->down.dir_x)
2748                          x = sid->down.sx - (ev->cur.canvas.x - sid->down.x);
2749                        else
2750                          x = sid->down.sx;
2751                        if (sid->down.dir_y)
2752                          y = sid->down.sy - (ev->cur.canvas.y - sid->down.y);
2753                        else
2754                          y = sid->down.sy;
2755                        if (sid->down.want_reset)
2756                          {
2757                             sid->down.x = ev->cur.canvas.x;
2758                             sid->down.y = ev->cur.canvas.y;
2759                             sid->down.want_reset = EINA_FALSE;
2760                          }
2761                        if ((sid->down.dir_x) || (sid->down.dir_y))
2762                          {
2763                             if (!sid->down.locked)
2764                               {
2765                                  sid->down.locked_x = x;
2766                                  sid->down.locked_y = y;
2767                                  sid->down.locked = EINA_TRUE;
2768                               }
2769                             if (!((sid->down.dir_x) && (sid->down.dir_y)))
2770                               {
2771                                  if (sid->down.dir_x) y = sid->down.locked_y;
2772                                  else x = sid->down.locked_x;
2773                               }
2774                          }
2775                        {
2776                           Evas_Coord minx, miny, mx, my;
2777
2778                           psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2779                           psd->api->pos_max_get(sid->pan_obj, &mx, &my);
2780                           if (y < miny)
2781                             y += (miny - y) *
2782                               _elm_config->thumbscroll_border_friction;
2783                           else if (my <= 0)
2784                             y += (sid->down.sy - y) *
2785                               _elm_config->thumbscroll_border_friction;
2786                           else if ((my + miny) < y)
2787                             y += (my + miny - y) *
2788                               _elm_config->thumbscroll_border_friction;
2789                           if (x < minx)
2790                             x += (minx - x) *
2791                               _elm_config->thumbscroll_border_friction;
2792                           else if (mx <= 0)
2793                             x += (sid->down.sx - x) *
2794                               _elm_config->thumbscroll_border_friction;
2795                           else if ((mx + minx) < x)
2796                             x += (mx + minx - x) *
2797                               _elm_config->thumbscroll_border_friction;
2798                        }
2799
2800                        sid->down.hold_x = x;
2801                        sid->down.hold_y = y;
2802                        if (!sid->down.hold_animator)
2803                          sid->down.hold_animator =
2804                            ecore_animator_add(_elm_scroll_hold_animator, sid);
2805                     }
2806                   else
2807                     {
2808                        if (sid->down.dragged_began)
2809                          {
2810                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2811                             if (!sid->down.hold)
2812                               {
2813                                  sid->down.hold = EINA_TRUE;
2814                                  evas_event_feed_hold
2815                                    (e, 1, ev->timestamp, ev->data);
2816                               }
2817                          }
2818                     }
2819                }
2820              else if (!sid->freeze)
2821                {
2822                   double vx = 0.0, vy = 0.0;
2823
2824                   x = ev->cur.canvas.x - sid->x;
2825                   y = ev->cur.canvas.y - sid->y;
2826                   if (x < _elm_config->thumbscroll_hold_threshold)
2827                     {
2828                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2829                          vx = -(double)(_elm_config->thumbscroll_hold_threshold - x)
2830                            / _elm_config->thumbscroll_hold_threshold;
2831                        else
2832                          vx = -1.0;
2833                     }
2834                   else if (x > (sid->w - _elm_config->thumbscroll_hold_threshold))
2835                     {
2836                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2837                          vx = (double)(_elm_config->thumbscroll_hold_threshold -
2838                                        (sid->w - x)) /
2839                            _elm_config->thumbscroll_hold_threshold;
2840                        else
2841                          vx = 1.0;
2842                     }
2843                   if (y < _elm_config->thumbscroll_hold_threshold)
2844                     {
2845                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2846                          vy = -(double)(_elm_config->thumbscroll_hold_threshold - y)
2847                            / _elm_config->thumbscroll_hold_threshold;
2848                        else
2849                          vy = -1.0;
2850                     }
2851                   else if (y > (sid->h - _elm_config->thumbscroll_hold_threshold))
2852                     {
2853                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
2854                          vy = (double)(_elm_config->thumbscroll_hold_threshold -
2855                                        (sid->h - y)) /
2856                            _elm_config->thumbscroll_hold_threshold;
2857                        else
2858                          vy = 1.0;
2859                     }
2860                   if ((vx != 0.0) || (vy != 0.0))
2861                     {
2862                        sid->down.onhold_vx = vx;
2863                        sid->down.onhold_vy = vy;
2864                        if (!sid->down.onhold_animator)
2865                          {
2866                             sid->down.onhold_vxe = 0.0;
2867                             sid->down.onhold_vye = 0.0;
2868                             sid->down.onhold_tlast = 0.0;
2869                             sid->down.onhold_animator = ecore_animator_add
2870                                 (_elm_scroll_on_hold_animator, sid);
2871                          }
2872                     }
2873                   else
2874                     {
2875                        if (sid->down.onhold_animator)
2876                          {
2877                             ecore_animator_del(sid->down.onhold_animator);
2878                             sid->down.onhold_animator = NULL;
2879                             if (sid->content_info.resized)
2880                               _elm_scroll_wanted_region_set(sid->obj);
2881                          }
2882                     }
2883                }
2884           }
2885      }
2886 }
2887
2888 static void
2889 _elm_scroll_page_adjust(Elm_Scrollable_Smart_Interface_Data *sid)
2890 {
2891    Evas_Coord x, y, w, h;
2892
2893    if (!_paging_is_enabled(sid)) return;
2894
2895    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2896
2897    x = _elm_scroll_page_x_get(sid, 0);
2898    y = _elm_scroll_page_y_get(sid, 0);
2899
2900    _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2901 }
2902
2903 static void
2904 _elm_scroll_reconfigure(Elm_Scrollable_Smart_Interface_Data *sid)
2905 {
2906    _elm_scroll_scroll_bar_size_adjust(sid);
2907    _elm_scroll_page_adjust(sid);
2908 }
2909
2910 static void
2911 _on_edje_move(void *data,
2912               Evas *e __UNUSED__,
2913               Evas_Object *edje_obj,
2914               void *event_info __UNUSED__)
2915 {
2916    Elm_Scrollable_Smart_Interface_Data *sid = data;
2917    int x, y;
2918
2919    evas_object_geometry_get(edje_obj, &x, &y, NULL, NULL);
2920
2921    sid->x = x;
2922    sid->y = y;
2923
2924    _elm_scroll_reconfigure(sid);
2925 }
2926
2927 static void
2928 _on_edje_resize(void *data,
2929                 Evas *e __UNUSED__,
2930                 Evas_Object *edje_obj,
2931                 void *event_info __UNUSED__)
2932 {
2933    Elm_Scrollable_Smart_Interface_Data *sid = data;
2934    int w, h;
2935
2936    evas_object_geometry_get(edje_obj, NULL, NULL, &w, &h);
2937
2938    sid->w = w;
2939    sid->h = h;
2940
2941    _elm_scroll_reconfigure(sid);
2942    _elm_scroll_wanted_region_set(sid->obj);
2943 }
2944
2945 static void
2946 _scroll_edje_object_attach(Evas_Object *obj)
2947 {
2948    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
2949
2950    evas_object_event_callback_add
2951      (sid->edje_obj, EVAS_CALLBACK_RESIZE, _on_edje_resize, sid);
2952    evas_object_event_callback_add
2953      (sid->edje_obj, EVAS_CALLBACK_MOVE, _on_edje_move, sid);
2954
2955    edje_object_signal_callback_add
2956      (sid->edje_obj, "drag", "elm.dragable.vbar", _elm_scroll_vbar_drag_cb,
2957      sid);
2958    edje_object_signal_callback_add
2959      (sid->edje_obj, "drag,set", "elm.dragable.vbar",
2960      _elm_scroll_edje_drag_v_cb, sid);
2961    edje_object_signal_callback_add
2962      (sid->edje_obj, "drag,start", "elm.dragable.vbar",
2963      _elm_scroll_edje_drag_v_start_cb, sid);
2964    edje_object_signal_callback_add
2965      (sid->edje_obj, "drag,stop", "elm.dragable.vbar",
2966      _elm_scroll_edje_drag_v_stop_cb, sid);
2967    edje_object_signal_callback_add
2968      (sid->edje_obj, "drag,step", "elm.dragable.vbar",
2969      _elm_scroll_edje_drag_v_cb, sid);
2970    edje_object_signal_callback_add
2971      (sid->edje_obj, "drag,page", "elm.dragable.vbar",
2972      _elm_scroll_edje_drag_v_cb, sid);
2973    edje_object_signal_callback_add
2974      (sid->edje_obj, "elm,vbar,press", "elm",
2975      _elm_scroll_vbar_press_cb, sid);
2976    edje_object_signal_callback_add
2977      (sid->edje_obj, "elm,vbar,unpress", "elm",
2978      _elm_scroll_vbar_unpress_cb, sid);
2979    edje_object_signal_callback_add
2980      (sid->edje_obj, "drag", "elm.dragable.hbar", _elm_scroll_hbar_drag_cb,
2981      sid);
2982    edje_object_signal_callback_add
2983      (sid->edje_obj, "drag,set", "elm.dragable.hbar",
2984      _elm_scroll_edje_drag_h_cb, sid);
2985    edje_object_signal_callback_add
2986      (sid->edje_obj, "drag,start", "elm.dragable.hbar",
2987      _elm_scroll_edje_drag_h_start_cb, sid);
2988    edje_object_signal_callback_add
2989      (sid->edje_obj, "drag,stop", "elm.dragable.hbar",
2990      _elm_scroll_edje_drag_h_stop_cb, sid);
2991    edje_object_signal_callback_add
2992      (sid->edje_obj, "drag,step", "elm.dragable.hbar",
2993      _elm_scroll_edje_drag_h_cb, sid);
2994    edje_object_signal_callback_add
2995      (sid->edje_obj, "drag,page", "elm.dragable.hbar",
2996      _elm_scroll_edje_drag_h_cb, sid);
2997    edje_object_signal_callback_add
2998      (sid->edje_obj, "elm,hbar,press", "elm",
2999      _elm_scroll_hbar_press_cb, sid);
3000    edje_object_signal_callback_add
3001      (sid->edje_obj, "elm,hbar,unpress", "elm",
3002      _elm_scroll_hbar_unpress_cb, sid);
3003 }
3004
3005 static void
3006 _scroll_event_object_attach(Evas_Object *obj)
3007 {
3008    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3009
3010    evas_object_event_callback_add
3011      (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _elm_scroll_wheel_event_cb,
3012      sid);
3013    evas_object_event_callback_add
3014      (sid->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
3015      _elm_scroll_mouse_down_event_cb, sid);
3016    evas_object_event_callback_add
3017      (sid->event_rect, EVAS_CALLBACK_MOUSE_UP,
3018      _elm_scroll_mouse_up_event_cb, sid);
3019    evas_object_event_callback_add
3020      (sid->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
3021      _elm_scroll_mouse_move_event_cb, sid);
3022 }
3023
3024 static void
3025 _scroll_edje_object_detach(Evas_Object *obj)
3026 {
3027    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3028
3029    evas_object_event_callback_del_full
3030      (sid->edje_obj, EVAS_CALLBACK_RESIZE, _on_edje_resize, sid);
3031    evas_object_event_callback_del_full
3032      (sid->edje_obj, EVAS_CALLBACK_MOVE, _on_edje_move, sid);
3033
3034    edje_object_signal_callback_del_full
3035      (sid->edje_obj, "drag", "elm.dragable.vbar", _elm_scroll_vbar_drag_cb,
3036      sid);
3037    edje_object_signal_callback_del_full
3038      (sid->edje_obj, "drag,set", "elm.dragable.vbar",
3039      _elm_scroll_edje_drag_v_cb, sid);
3040    edje_object_signal_callback_del_full
3041      (sid->edje_obj, "drag,start", "elm.dragable.vbar",
3042      _elm_scroll_edje_drag_v_start_cb, sid);
3043    edje_object_signal_callback_del_full
3044      (sid->edje_obj, "drag,stop", "elm.dragable.vbar",
3045      _elm_scroll_edje_drag_v_stop_cb, sid);
3046    edje_object_signal_callback_del_full
3047      (sid->edje_obj, "drag,step", "elm.dragable.vbar",
3048      _elm_scroll_edje_drag_v_cb, sid);
3049    edje_object_signal_callback_del_full
3050      (sid->edje_obj, "drag,page", "elm.dragable.vbar",
3051      _elm_scroll_edje_drag_v_cb, sid);
3052    edje_object_signal_callback_del_full
3053      (sid->edje_obj, "elm,vbar,press", "elm",
3054      _elm_scroll_vbar_press_cb, sid);
3055    edje_object_signal_callback_del_full
3056      (sid->edje_obj, "elm,vbar,unpress", "elm",
3057      _elm_scroll_vbar_unpress_cb, sid);
3058    edje_object_signal_callback_del_full
3059      (sid->edje_obj, "drag", "elm.dragable.hbar", _elm_scroll_hbar_drag_cb,
3060      sid);
3061    edje_object_signal_callback_del_full
3062      (sid->edje_obj, "drag,set", "elm.dragable.hbar",
3063      _elm_scroll_edje_drag_h_cb, sid);
3064    edje_object_signal_callback_del_full
3065      (sid->edje_obj, "drag,start", "elm.dragable.hbar",
3066      _elm_scroll_edje_drag_h_start_cb, sid);
3067    edje_object_signal_callback_del_full
3068      (sid->edje_obj, "drag,stop", "elm.dragable.hbar",
3069      _elm_scroll_edje_drag_h_stop_cb, sid);
3070    edje_object_signal_callback_del_full
3071      (sid->edje_obj, "drag,step", "elm.dragable.hbar",
3072      _elm_scroll_edje_drag_h_cb, sid);
3073    edje_object_signal_callback_del_full
3074      (sid->edje_obj, "drag,page", "elm.dragable.hbar",
3075      _elm_scroll_edje_drag_h_cb, sid);
3076    edje_object_signal_callback_del_full
3077      (sid->edje_obj, "elm,hbar,press", "elm",
3078      _elm_scroll_hbar_press_cb, sid);
3079    edje_object_signal_callback_del_full
3080      (sid->edje_obj, "elm,hbar,unpress", "elm",
3081      _elm_scroll_hbar_unpress_cb, sid);
3082 }
3083
3084 static void
3085 _scroll_event_object_detach(Evas_Object *obj)
3086 {
3087    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3088
3089    evas_object_event_callback_del_full
3090      (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _elm_scroll_wheel_event_cb,
3091      sid);
3092    evas_object_event_callback_del_full
3093      (sid->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
3094      _elm_scroll_mouse_down_event_cb, sid);
3095    evas_object_event_callback_del_full
3096      (sid->event_rect, EVAS_CALLBACK_MOUSE_UP,
3097      _elm_scroll_mouse_up_event_cb, sid);
3098    evas_object_event_callback_del_full
3099      (sid->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
3100      _elm_scroll_mouse_move_event_cb, sid);
3101 }
3102
3103 static void
3104 _elm_scroll_objects_set(Evas_Object *obj,
3105                         Evas_Object *edje_object,
3106                         Evas_Object *hit_rectangle)
3107 {
3108    Evas_Coord mw, mh;
3109
3110    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3111
3112    if (!edje_object || !hit_rectangle) return;
3113
3114    if (sid->edje_obj)
3115        _scroll_edje_object_detach(obj);
3116
3117    sid->edje_obj = edje_object;
3118
3119    if (sid->event_rect)
3120        _scroll_event_object_detach(obj);
3121
3122    sid->event_rect = hit_rectangle;
3123    evas_object_repeat_events_set(hit_rectangle, EINA_TRUE);
3124
3125    _scroll_edje_object_attach(obj);
3126    _scroll_event_object_attach(obj);
3127
3128    mw = mh = -1;
3129    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
3130    if (edje_object_part_exists(sid->edje_obj, "elm.scrollbar.base"))
3131      {
3132         Evas_Object *base;
3133
3134         base = edje_object_part_swallow_get
3135             (sid->edje_obj, "elm.scrollbar.base");
3136         if (!base)
3137           {
3138              base = evas_object_rectangle_add
3139                  (evas_object_evas_get(sid->edje_obj));
3140              evas_object_color_set(base, 0, 0, 0, 0);
3141              edje_object_part_swallow
3142                (sid->edje_obj, "elm.scrollbar.base", base);
3143           }
3144         if (!_elm_config->thumbscroll_enable)
3145           evas_object_size_hint_min_set(base, mw, mh);
3146      }
3147
3148    _elm_scroll_scroll_bar_visibility_adjust(sid);
3149 }
3150
3151 static void
3152 _elm_scroll_scroll_bar_reset(Elm_Scrollable_Smart_Interface_Data *sid)
3153 {
3154    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
3155
3156    if (!sid->edje_obj) return;
3157
3158    edje_object_part_drag_value_set
3159      (sid->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
3160    edje_object_part_drag_value_set
3161      (sid->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
3162    if ((!sid->content) && (!sid->extern_pan))
3163      {
3164         edje_object_part_drag_size_set
3165           (sid->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
3166         edje_object_part_drag_size_set
3167           (sid->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
3168      }
3169    if (sid->pan_obj)
3170      {
3171         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3172
3173         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
3174         psd->api->pos_get(sid->pan_obj, &px, &py);
3175         psd->api->pos_set(sid->pan_obj, minx, miny);
3176      }
3177    if ((px != minx) || (py != miny))
3178      edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
3179    _elm_direction_arrows_eval(sid);
3180 }
3181
3182 /* even external pan objects get this */
3183 static void
3184 _elm_scroll_pan_changed_cb(void *data,
3185                            Evas_Object *obj __UNUSED__,
3186                            void *event_info __UNUSED__)
3187 {
3188    Evas_Coord w, h;
3189    Elm_Scrollable_Smart_Interface_Data *sid = data;
3190
3191    if (!sid->pan_obj) return;
3192
3193    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3194
3195    psd->api->content_size_get(sid->pan_obj, &w, &h);
3196    if ((w != sid->content_info.w) || (h != sid->content_info.h))
3197      {
3198         sid->content_info.w = w;
3199         sid->content_info.h = h;
3200         _elm_scroll_scroll_bar_size_adjust(sid);
3201
3202         evas_object_size_hint_min_set
3203           (sid->edje_obj, sid->content_info.w, sid->content_info.h);
3204         sid->content_info.resized = EINA_TRUE;
3205         _elm_scroll_wanted_region_set(sid->obj);
3206      }
3207 }
3208
3209 static void
3210 _elm_scroll_content_del_cb(void *data,
3211                            Evas *e __UNUSED__,
3212                            Evas_Object *obj __UNUSED__,
3213                            void *event_info __UNUSED__)
3214 {
3215    Elm_Scrollable_Smart_Interface_Data *sid = data;
3216
3217    sid->content = NULL;
3218    _elm_scroll_scroll_bar_size_adjust(sid);
3219    _elm_scroll_scroll_bar_reset(sid);
3220 }
3221
3222 static void
3223 _elm_scroll_content_set(Evas_Object *obj,
3224                         Evas_Object *content)
3225 {
3226    Evas_Coord w, h;
3227    Evas_Object *o;
3228
3229    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3230
3231    if (!sid->edje_obj) return;
3232
3233    if (sid->content)
3234      {
3235         /* if we had content, for sure we had a pan object */
3236         _elm_pan_content_set(sid->pan_obj, NULL);
3237         evas_object_event_callback_del_full
3238           (sid->content, EVAS_CALLBACK_DEL, _elm_scroll_content_del_cb, sid);
3239      }
3240
3241    sid->content = content;
3242    sid->wx = sid->wy = 0;
3243    /* (-1) means want viewports size */
3244    sid->ww = sid->wh = -1;
3245    if (!content) return;
3246
3247    if (!sid->pan_obj)
3248      {
3249         o = _elm_pan_add(evas_object_evas_get(obj));
3250         sid->pan_obj = o;
3251         evas_object_smart_callback_add
3252           (o, SIG_CHANGED, _elm_scroll_pan_changed_cb, sid);
3253         edje_object_part_swallow(sid->edje_obj, "elm.swallow.content", o);
3254      }
3255
3256    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3257
3258    evas_object_event_callback_add
3259      (content, EVAS_CALLBACK_DEL, _elm_scroll_content_del_cb, sid);
3260
3261    _elm_pan_content_set(sid->pan_obj, content);
3262    psd->api->content_size_get(sid->pan_obj, &w, &h);
3263    sid->content_info.w = w;
3264    sid->content_info.h = h;
3265
3266    _elm_scroll_scroll_bar_size_adjust(sid);
3267    _elm_scroll_scroll_bar_reset(sid);
3268 }
3269
3270 static void
3271 _elm_scroll_extern_pan_set(Evas_Object *obj,
3272                            Evas_Object *pan)
3273 {
3274    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3275
3276    if (!sid->edje_obj) return;
3277
3278    _elm_scroll_content_set(obj, NULL);
3279
3280    if (sid->pan_obj)
3281      {
3282         evas_object_smart_callback_del
3283           (sid->pan_obj, SIG_CHANGED, _elm_scroll_pan_changed_cb);
3284      }
3285
3286    if (sid->extern_pan)
3287      {
3288         if (sid->pan_obj)
3289           {
3290              /* not owned by scroller, just leave (was external already) */
3291              edje_object_part_unswallow(sid->edje_obj, sid->pan_obj);
3292              sid->pan_obj = NULL;
3293           }
3294      }
3295    else
3296      {
3297         if (sid->pan_obj)
3298           {
3299              evas_object_del(sid->pan_obj);
3300              sid->pan_obj = NULL;
3301           }
3302      }
3303    if (!pan)
3304      {
3305         sid->extern_pan = EINA_FALSE;
3306         return;
3307      }
3308
3309    sid->pan_obj = pan;
3310
3311    sid->extern_pan = EINA_TRUE;
3312    evas_object_smart_callback_add
3313      (sid->pan_obj, SIG_CHANGED, _elm_scroll_pan_changed_cb, sid);
3314    edje_object_part_swallow
3315      (sid->edje_obj, "elm.swallow.content", sid->pan_obj);
3316 }
3317
3318 static void
3319 _elm_scroll_drag_start_cb_set(Evas_Object *obj,
3320                               void (*drag_start_cb)(Evas_Object *obj,
3321                                                     void *data))
3322 {
3323    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3324
3325    sid->cb_func.drag_start = drag_start_cb;
3326 }
3327
3328 static void
3329 _elm_scroll_drag_stop_cb_set(Evas_Object *obj,
3330                              void (*drag_stop_cb)(Evas_Object *obj,
3331                                                   void *data))
3332 {
3333    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3334
3335    sid->cb_func.drag_stop = drag_stop_cb;
3336 }
3337
3338 static void
3339 _elm_scroll_animate_start_cb_set(Evas_Object *obj,
3340                                  void (*animate_start_cb)(Evas_Object *obj,
3341                                                           void *data))
3342 {
3343    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3344
3345    sid->cb_func.animate_start = animate_start_cb;
3346 }
3347
3348 static void
3349 _elm_scroll_animate_stop_cb_set(Evas_Object *obj,
3350                                 void (*animate_stop_cb)(Evas_Object *obj,
3351                                                         void *data))
3352 {
3353    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3354
3355    sid->cb_func.animate_stop = animate_stop_cb;
3356 }
3357
3358 static void
3359 _elm_scroll_scroll_cb_set(Evas_Object *obj,
3360                           void (*scroll_cb)(Evas_Object *obj,
3361                                             void *data))
3362 {
3363    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3364
3365    sid->cb_func.scroll = scroll_cb;
3366 }
3367
3368 static void
3369 _elm_scroll_scroll_left_cb_set(Evas_Object *obj,
3370                           void (*scroll_left_cb)(Evas_Object *obj,
3371                                             void *data))
3372 {
3373    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3374
3375    sid->cb_func.scroll_left = scroll_left_cb;
3376 }
3377
3378 static void
3379 _elm_scroll_scroll_right_cb_set(Evas_Object *obj,
3380                           void (*scroll_right_cb)(Evas_Object *obj,
3381                                             void *data))
3382 {
3383    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3384
3385    sid->cb_func.scroll_right = scroll_right_cb;
3386 }
3387
3388 static void
3389 _elm_scroll_scroll_up_cb_set(Evas_Object *obj,
3390                           void (*scroll_up_cb)(Evas_Object *obj,
3391                                             void *data))
3392 {
3393    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3394
3395    sid->cb_func.scroll_up = scroll_up_cb;
3396 }
3397
3398 static void
3399 _elm_scroll_scroll_down_cb_set(Evas_Object *obj,
3400                           void (*scroll_down_cb)(Evas_Object *obj,
3401                                             void *data))
3402 {
3403    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3404
3405    sid->cb_func.scroll_down = scroll_down_cb;
3406 }
3407
3408 static void
3409 _elm_scroll_edge_left_cb_set(Evas_Object *obj,
3410                              void (*edge_left_cb)(Evas_Object *obj,
3411                                                   void *data))
3412 {
3413    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3414
3415    sid->cb_func.edge_left = edge_left_cb;
3416 }
3417
3418 static void
3419 _elm_scroll_edge_right_cb_set(Evas_Object *obj,
3420                               void (*edge_right_cb)(Evas_Object *obj,
3421                                                     void *data))
3422 {
3423    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3424
3425    sid->cb_func.edge_right = edge_right_cb;
3426 }
3427
3428 static void
3429 _elm_scroll_edge_top_cb_set(Evas_Object *obj,
3430                             void (*edge_top_cb)(Evas_Object *obj,
3431                                                 void *data))
3432 {
3433    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3434
3435    sid->cb_func.edge_top = edge_top_cb;
3436 }
3437
3438 static void
3439 _elm_scroll_edge_bottom_cb_set(Evas_Object *obj,
3440                                void (*edge_bottom_cb)(Evas_Object *obj,
3441                                                       void *data))
3442 {
3443    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3444
3445    sid->cb_func.edge_bottom = edge_bottom_cb;
3446 }
3447
3448 static void
3449 _elm_scroll_vbar_drag_cb_set(Evas_Object *obj,
3450                                void (*vbar_drag_cb)(Evas_Object *obj,
3451                                                       void *data))
3452 {
3453    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3454
3455    sid->cb_func.vbar_drag = vbar_drag_cb;
3456 }
3457
3458 static void
3459 _elm_scroll_vbar_press_cb_set(Evas_Object *obj,
3460                                void (*vbar_press_cb)(Evas_Object *obj,
3461                                                       void *data))
3462 {
3463    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3464
3465    sid->cb_func.vbar_press = vbar_press_cb;
3466 }
3467
3468 static void
3469 _elm_scroll_vbar_unpress_cb_set(Evas_Object *obj,
3470                                void (*vbar_unpress_cb)(Evas_Object *obj,
3471                                                       void *data))
3472 {
3473    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3474
3475    sid->cb_func.vbar_unpress = vbar_unpress_cb;
3476 }
3477
3478 static void
3479 _elm_scroll_hbar_drag_cb_set(Evas_Object *obj,
3480                                void (*hbar_drag_cb)(Evas_Object *obj,
3481                                                       void *data))
3482 {
3483    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3484
3485    sid->cb_func.hbar_drag = hbar_drag_cb;
3486 }
3487
3488 static void
3489 _elm_scroll_hbar_press_cb_set(Evas_Object *obj,
3490                                void (*hbar_press_cb)(Evas_Object *obj,
3491                                                       void *data))
3492 {
3493    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3494
3495    sid->cb_func.hbar_press = hbar_press_cb;
3496 }
3497
3498 static void
3499 _elm_scroll_hbar_unpress_cb_set(Evas_Object *obj,
3500                                void (*hbar_unpress_cb)(Evas_Object *obj,
3501                                                       void *data))
3502 {
3503    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3504
3505    sid->cb_func.hbar_unpress = hbar_unpress_cb;
3506 }
3507
3508 static void
3509 _elm_scroll_content_min_limit_cb_set(Evas_Object *obj,
3510                                      void (*c_min_limit_cb)(Evas_Object *obj,
3511                                                             Eina_Bool w,
3512                                                             Eina_Bool h))
3513 {
3514    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3515
3516    sid->cb_func.content_min_limit = c_min_limit_cb;
3517 }
3518
3519 static Eina_Bool
3520 _elm_scroll_momentum_animator_disabled_get(const Evas_Object *obj)
3521 {
3522    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3523
3524    return sid->momentum_animator_disabled;
3525 }
3526
3527 static void
3528 _elm_scroll_momentum_animator_disabled_set(Evas_Object *obj,
3529                                            Eina_Bool disabled)
3530 {
3531    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3532
3533    sid->momentum_animator_disabled = disabled;
3534    if (sid->momentum_animator_disabled)
3535      {
3536         if (sid->down.momentum_animator)
3537           {
3538              ecore_animator_del(sid->down.momentum_animator);
3539              sid->down.momentum_animator = NULL;
3540              if (sid->content_info.resized)
3541                _elm_scroll_wanted_region_set(sid->obj);
3542           }
3543      }
3544 }
3545
3546 static Eina_Bool
3547 _elm_scroll_bounce_animator_disabled_get(const Evas_Object *obj)
3548 {
3549    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3550
3551    return sid->bounce_animator_disabled;
3552 }
3553
3554 static void
3555 _elm_scroll_bounce_animator_disabled_set(Evas_Object *obj,
3556                                          Eina_Bool disabled)
3557 {
3558    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3559
3560    sid->bounce_animator_disabled = disabled;
3561    if (sid->bounce_animator_disabled)
3562      {
3563         if (sid->scrollto.x.animator)
3564           {
3565              ecore_animator_del(sid->scrollto.x.animator);
3566              sid->scrollto.x.animator = NULL;
3567           }
3568
3569         if (sid->scrollto.y.animator)
3570           {
3571              ecore_animator_del(sid->scrollto.y.animator);
3572              sid->scrollto.y.animator = NULL;
3573           }
3574      }
3575 }
3576
3577 static Eina_Bool
3578 _elm_scroll_wheel_disabled_get(const Evas_Object *obj)
3579 {
3580    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3581
3582    return sid->wheel_disabled;
3583 }
3584
3585 static void
3586 _elm_scroll_wheel_disabled_set(Evas_Object *obj,
3587                                Eina_Bool disabled)
3588 {
3589    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3590
3591    if (!sid->event_rect) return;
3592
3593    if ((!sid->wheel_disabled) && (disabled))
3594      evas_object_event_callback_del_full
3595        (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL,
3596        _elm_scroll_wheel_event_cb, sid);
3597    else if ((sid->wheel_disabled) && (!disabled))
3598      evas_object_event_callback_add
3599        (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL,
3600        _elm_scroll_wheel_event_cb, sid);
3601    sid->wheel_disabled = disabled;
3602 }
3603
3604 static void
3605 _elm_scroll_step_size_set(Evas_Object *obj,
3606                           Evas_Coord x,
3607                           Evas_Coord y)
3608 {
3609    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3610
3611    if (x < 1) x = 1;
3612    if (y < 1) y = 1;
3613    sid->step.x = x;
3614    sid->step.y = y;
3615
3616    _elm_scroll_scroll_bar_size_adjust(sid);
3617 }
3618
3619 static void
3620 _elm_scroll_step_size_get(const Evas_Object *obj,
3621                           Evas_Coord *x,
3622                           Evas_Coord *y)
3623 {
3624    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3625
3626    if (x) *x = sid->step.x;
3627    if (y) *y = sid->step.y;
3628 }
3629
3630 static void
3631 _elm_scroll_page_size_set(Evas_Object *obj,
3632                           Evas_Coord x,
3633                           Evas_Coord y)
3634 {
3635    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3636
3637    sid->page.x = x;
3638    sid->page.y = y;
3639
3640    _elm_scroll_scroll_bar_size_adjust(sid);
3641 }
3642
3643 static void
3644 _elm_scroll_page_size_get(const Evas_Object *obj,
3645                           Evas_Coord *x,
3646                           Evas_Coord *y)
3647 {
3648    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3649
3650    if (x) *x = sid->page.x;
3651    if (y) *y = sid->page.y;
3652 }
3653
3654 static void
3655 _elm_scroll_policy_set(Evas_Object *obj,
3656                        Elm_Scroller_Policy hbar,
3657                        Elm_Scroller_Policy vbar)
3658 {
3659    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3660
3661    if (!sid->edje_obj) return;
3662
3663    if ((sid->hbar_flags == hbar) && (sid->vbar_flags == vbar)) return;
3664
3665    sid->hbar_flags = hbar;
3666    sid->vbar_flags = vbar;
3667    if (sid->hbar_flags == ELM_SCROLLER_POLICY_ON)
3668      edje_object_signal_emit
3669        (sid->edje_obj, "elm,action,show_always,hbar", "elm");
3670    else if (sid->hbar_flags == ELM_SCROLLER_POLICY_OFF)
3671      edje_object_signal_emit
3672        (sid->edje_obj, "elm,action,hide,hbar", "elm");
3673    else
3674      edje_object_signal_emit
3675        (sid->edje_obj, "elm,action,show_notalways,hbar", "elm");
3676    if (sid->vbar_flags == ELM_SCROLLER_POLICY_ON)
3677      edje_object_signal_emit
3678        (sid->edje_obj, "elm,action,show_always,vbar", "elm");
3679    else if (sid->vbar_flags == ELM_SCROLLER_POLICY_OFF)
3680      edje_object_signal_emit
3681        (sid->edje_obj, "elm,action,hide,vbar", "elm");
3682    else
3683      edje_object_signal_emit
3684        (sid->edje_obj, "elm,action,show_notalways,vbar", "elm");
3685    edje_object_message_signal_process(sid->edje_obj);
3686    _elm_scroll_scroll_bar_size_adjust(sid);
3687    if (sid->cb_func.content_min_limit)
3688      sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
3689    _elm_direction_arrows_eval(sid);
3690 }
3691
3692 static void
3693 _elm_scroll_policy_get(const Evas_Object *obj,
3694                        Elm_Scroller_Policy *hbar,
3695                        Elm_Scroller_Policy *vbar)
3696 {
3697    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3698
3699    if (hbar) *hbar = sid->hbar_flags;
3700    if (vbar) *vbar = sid->vbar_flags;
3701 }
3702
3703 static void
3704 _elm_scroll_single_direction_set(Evas_Object *obj,
3705                                  Eina_Bool single_dir)
3706 {
3707    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3708
3709    sid->one_direction_at_a_time = single_dir;
3710 }
3711
3712 static Eina_Bool
3713 _elm_scroll_single_direction_get(const Evas_Object *obj)
3714 {
3715    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3716
3717    return sid->one_direction_at_a_time;
3718 }
3719
3720 static void
3721 _elm_scroll_hold_set(Evas_Object *obj,
3722                      Eina_Bool hold)
3723 {
3724    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3725
3726    sid->hold = hold;
3727 }
3728
3729 static void
3730 _elm_scroll_freeze_set(Evas_Object *obj,
3731                        Eina_Bool freeze)
3732 {
3733    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3734
3735    sid->freeze = freeze;
3736    if (sid->freeze)
3737      {
3738         if (sid->down.onhold_animator)
3739           {
3740              ecore_animator_del(sid->down.onhold_animator);
3741              sid->down.onhold_animator = NULL;
3742              if (sid->content_info.resized)
3743                _elm_scroll_wanted_region_set(sid->obj);
3744           }
3745      }
3746    else
3747      _elm_scroll_bounce_eval(sid);
3748 }
3749
3750 static void
3751 _elm_scroll_bounce_allow_set(Evas_Object *obj,
3752                              Eina_Bool horiz,
3753                              Eina_Bool vert)
3754 {
3755    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3756
3757    sid->bounce_horiz = !!horiz;
3758    sid->bounce_vert = !!vert;
3759 }
3760
3761 static void
3762 _elm_scroll_bounce_allow_get(const Evas_Object *obj,
3763                              Eina_Bool *horiz,
3764                              Eina_Bool *vert)
3765 {
3766    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3767
3768    if (horiz) *horiz = sid->bounce_horiz;
3769    if (vert) *vert = sid->bounce_vert;
3770 }
3771
3772 static void
3773 _elm_scroll_paging_set(Evas_Object *obj,
3774                        double pagerel_h,
3775                        double pagerel_v,
3776                        Evas_Coord pagesize_h,
3777                        Evas_Coord pagesize_v)
3778 {
3779    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3780
3781    sid->pagerel_h = pagerel_h;
3782    sid->pagerel_v = pagerel_v;
3783    sid->pagesize_h = pagesize_h;
3784    sid->pagesize_v = pagesize_v;
3785
3786    _elm_scroll_page_adjust(sid);
3787 }
3788
3789 static void
3790 _elm_scroll_paging_get(const Evas_Object *obj,
3791                        double *pagerel_h,
3792                        double *pagerel_v,
3793                        Evas_Coord *pagesize_h,
3794                        Evas_Coord *pagesize_v)
3795 {
3796    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3797
3798    if (pagerel_h) *pagerel_h = sid->pagerel_h;
3799    if (pagerel_v) *pagerel_v = sid->pagerel_v;
3800    if (pagesize_h) *pagesize_h = sid->pagesize_h;
3801    if (pagesize_v) *pagesize_v = sid->pagesize_v;
3802 }
3803
3804 static void
3805 _elm_scroll_current_page_get(const Evas_Object *obj,
3806                              int *pagenumber_h,
3807                              int *pagenumber_v)
3808 {
3809    Evas_Coord x, y;
3810
3811    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3812
3813    _elm_scroll_content_pos_get(sid->obj, &x, &y);
3814    if (pagenumber_h)
3815      {
3816         if (sid->pagesize_h > 0)
3817           *pagenumber_h = (x + sid->pagesize_h - 1) / sid->pagesize_h;
3818         else
3819           *pagenumber_h = 0;
3820      }
3821    if (pagenumber_v)
3822      {
3823         if (sid->pagesize_v > 0)
3824           *pagenumber_v = (y + sid->pagesize_v - 1) / sid->pagesize_v;
3825         else
3826           *pagenumber_v = 0;
3827      }
3828 }
3829
3830 static void
3831 _elm_scroll_last_page_get(const Evas_Object *obj,
3832                           int *pagenumber_h,
3833                           int *pagenumber_v)
3834 {
3835    Evas_Coord cw, ch;
3836
3837    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3838
3839    if (!sid->pan_obj) return;
3840
3841    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3842
3843    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
3844    if (pagenumber_h)
3845      {
3846         if (sid->pagesize_h > 0)
3847           *pagenumber_h = cw / sid->pagesize_h + 1;
3848         else
3849           *pagenumber_h = 0;
3850      }
3851    if (pagenumber_v)
3852      {
3853         if (sid->pagesize_v > 0)
3854           *pagenumber_v = ch / sid->pagesize_v + 1;
3855         else
3856           *pagenumber_v = 0;
3857      }
3858 }
3859
3860 static void
3861 _elm_scroll_page_show(Evas_Object *obj,
3862                       int pagenumber_h,
3863                       int pagenumber_v)
3864 {
3865    Evas_Coord w, h;
3866    Evas_Coord x = 0;
3867    Evas_Coord y = 0;
3868
3869    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3870
3871    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
3872    if (pagenumber_h >= 0) x = sid->pagesize_h * pagenumber_h;
3873    if (pagenumber_v >= 0) y = sid->pagesize_v * pagenumber_v;
3874    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
3875      _elm_scroll_content_pos_set(obj, x, y, EINA_TRUE);
3876 }
3877
3878 static void
3879 _elm_scroll_page_bring_in(Evas_Object *obj,
3880                           int pagenumber_h,
3881                           int pagenumber_v)
3882 {
3883    Evas_Coord w, h;
3884    Evas_Coord x = 0;
3885    Evas_Coord y = 0;
3886
3887    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3888
3889    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
3890    if (pagenumber_h >= 0) x = sid->pagesize_h * pagenumber_h;
3891    if (pagenumber_v >= 0) y = sid->pagesize_v * pagenumber_v;
3892    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
3893      {
3894         _elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
3895         _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
3896      }
3897 }
3898
3899 static void
3900 _elm_scroll_region_bring_in(Evas_Object *obj,
3901                             Evas_Coord x,
3902                             Evas_Coord y,
3903                             Evas_Coord w,
3904                             Evas_Coord h)
3905 {
3906    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3907
3908    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
3909      {
3910         _elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
3911         _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
3912      }
3913 }
3914
3915 static void
3916 _elm_scroll_gravity_set(Evas_Object *obj,
3917                         double x,
3918                         double y)
3919 {
3920    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3921
3922    if (!sid->pan_obj) return;
3923
3924    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3925
3926    psd->api->gravity_set(sid->pan_obj, x, y);
3927 }
3928
3929 static void
3930 _elm_scroll_gravity_get(const Evas_Object *obj,
3931                         double *x,
3932                         double *y)
3933 {
3934    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3935
3936    if (!sid->pan_obj) return;
3937
3938    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3939
3940    psd->api->gravity_get(sid->pan_obj, x, y);
3941 }
3942
3943 static Eina_Bool
3944 _elm_scroll_interface_add(Evas_Object *obj)
3945 {
3946    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
3947
3948    memset(sid, 0, sizeof(*sid));
3949
3950    sid->obj = obj;
3951
3952    sid->x = 0;
3953    sid->y = 0;
3954    sid->w = 0;
3955    sid->h = 0;
3956    sid->step.x = 32;
3957    sid->step.y = 32;
3958    sid->page.x = -50;
3959    sid->page.y = -50;
3960    sid->hbar_flags = ELM_SCROLLER_POLICY_AUTO;
3961    sid->vbar_flags = ELM_SCROLLER_POLICY_AUTO;
3962    sid->hbar_visible = EINA_TRUE;
3963    sid->vbar_visible = EINA_TRUE;
3964
3965    sid->bounce_horiz = EINA_TRUE;
3966    sid->bounce_vert = EINA_TRUE;
3967
3968    sid->one_direction_at_a_time = EINA_TRUE;
3969    sid->momentum_animator_disabled = EINA_FALSE;
3970    sid->bounce_animator_disabled = EINA_FALSE;
3971
3972    _elm_scroll_scroll_bar_reset(sid);
3973
3974    return EINA_TRUE;
3975 }
3976
3977 static void
3978 _elm_scroll_interface_del(Evas_Object *obj)
3979 {
3980    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
3981
3982    _elm_scroll_content_set(obj, NULL);
3983    if (!sid->extern_pan) evas_object_del(sid->pan_obj);
3984
3985    if (sid->down.hold_animator)
3986      ecore_animator_del(sid->down.hold_animator);
3987    if (sid->down.onhold_animator)
3988      ecore_animator_del(sid->down.onhold_animator);
3989    if (sid->down.momentum_animator)
3990      ecore_animator_del(sid->down.momentum_animator);
3991    if (sid->down.bounce_x_animator)
3992      ecore_animator_del(sid->down.bounce_x_animator);
3993    if (sid->down.bounce_y_animator)
3994      ecore_animator_del(sid->down.bounce_y_animator);
3995    if (sid->scrollto.x.animator) ecore_animator_del(sid->scrollto.x.animator);
3996    if (sid->scrollto.y.animator) ecore_animator_del(sid->scrollto.y.animator);
3997 }
3998
3999 EAPI const char ELM_SCROLLABLE_IFACE_NAME[] = "elm_interface_scrollable";
4000
4001 EAPI const Elm_Scrollable_Smart_Interface ELM_SCROLLABLE_IFACE =
4002 {
4003    {
4004       ELM_SCROLLABLE_IFACE_NAME,
4005       sizeof(Elm_Scrollable_Smart_Interface_Data),
4006       _elm_scroll_interface_add,
4007       _elm_scroll_interface_del
4008    },
4009
4010    _elm_scroll_objects_set,
4011    _elm_scroll_content_set,
4012    _elm_scroll_extern_pan_set,
4013    _elm_scroll_drag_start_cb_set,
4014    _elm_scroll_drag_stop_cb_set,
4015    _elm_scroll_animate_start_cb_set,
4016    _elm_scroll_animate_stop_cb_set,
4017    _elm_scroll_scroll_cb_set,
4018    _elm_scroll_scroll_left_cb_set,
4019    _elm_scroll_scroll_right_cb_set,
4020    _elm_scroll_scroll_up_cb_set,
4021    _elm_scroll_scroll_down_cb_set,
4022    _elm_scroll_edge_left_cb_set,
4023    _elm_scroll_edge_right_cb_set,
4024    _elm_scroll_edge_top_cb_set,
4025    _elm_scroll_edge_bottom_cb_set,
4026    _elm_scroll_vbar_drag_cb_set,
4027    _elm_scroll_vbar_press_cb_set,
4028    _elm_scroll_vbar_unpress_cb_set,
4029    _elm_scroll_hbar_drag_cb_set,
4030    _elm_scroll_hbar_press_cb_set,
4031    _elm_scroll_hbar_unpress_cb_set,
4032    _elm_scroll_content_min_limit_cb_set,
4033    _elm_scroll_content_pos_set,
4034    _elm_scroll_content_pos_get,
4035    _elm_scroll_content_region_show,
4036    _elm_scroll_content_region_set,
4037    _elm_scroll_content_size_get,
4038    _elm_scroll_content_viewport_size_get,
4039    _elm_scroll_content_min_limit,
4040    _elm_scroll_step_size_set,
4041    _elm_scroll_step_size_get,
4042    _elm_scroll_page_size_set,
4043    _elm_scroll_page_size_get,
4044    _elm_scroll_policy_set,
4045    _elm_scroll_policy_get,
4046    _elm_scroll_single_direction_set,
4047    _elm_scroll_single_direction_get,
4048    _elm_scroll_mirrored_set,
4049    _elm_scroll_hold_set,
4050    _elm_scroll_freeze_set,
4051    _elm_scroll_bounce_allow_set,
4052    _elm_scroll_bounce_allow_get,
4053    _elm_scroll_paging_set,
4054    _elm_scroll_paging_get,
4055    _elm_scroll_current_page_get,
4056    _elm_scroll_last_page_get,
4057    _elm_scroll_page_show,
4058    _elm_scroll_page_bring_in,
4059    _elm_scroll_region_bring_in,
4060    _elm_scroll_gravity_set,
4061    _elm_scroll_gravity_get,
4062    _elm_scroll_momentum_animator_disabled_get,
4063    _elm_scroll_momentum_animator_disabled_set,
4064    _elm_scroll_bounce_animator_disabled_set,
4065    _elm_scroll_bounce_animator_disabled_get,
4066    _elm_scroll_wheel_disabled_get,
4067    _elm_scroll_wheel_disabled_set
4068 };