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