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