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