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