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