3c6f5b2dc6d158484eb87ac483f89067ca9feb3c
[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 void
37 _elm_scroll_scroll_to_x(Elm_Scrollable_Smart_Interface_Data *sid,
38                         double t_in,
39                         Evas_Coord pos_x);
40 static void
41 _elm_scroll_scroll_to_y(Elm_Scrollable_Smart_Interface_Data *sid,
42                         double t_in,
43                         Evas_Coord pos_y);
44 static void
45 _elm_scroll_current_page_get(const Evas_Object *obj,
46                              int *pagenumber_h,
47                              int *pagenumber_v);
48 static void
49 _elm_scroll_wanted_coordinates_update(Elm_Scrollable_Smart_Interface_Data *sid,
50                                       Evas_Coord x,
51                                       Evas_Coord y);
52 EAPI const Elm_Pan_Smart_Class *
53 elm_pan_smart_class_get(void)
54 {
55    static Elm_Pan_Smart_Class _sc =
56      ELM_PAN_SMART_CLASS_INIT_NAME_VERSION(PAN_SMART_NAME);
57    static const Elm_Pan_Smart_Class *class = NULL;
58    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
59
60    if (class)
61      return class;
62
63    _elm_pan_smart_set(&_sc);
64    esc->callbacks = _smart_callbacks;
65    class = &_sc;
66
67    return class;
68 }
69
70 static double
71 _round(double value, int pos)
72 {
73    double temp;
74
75    temp = value * pow( 10, pos );
76    temp = floor( temp + 0.5 );
77    temp *= pow( 10, -pos );
78
79    return temp;
80 }
81
82 static void
83 _elm_pan_update(Elm_Pan_Smart_Data *psd)
84 {
85    if (!psd->gravity_x && !psd->gravity_y)
86      {
87         evas_object_move(psd->content, psd->x - psd->px, psd->y - psd->py);
88         return;
89      }
90
91    if ((!psd->px) && (!psd->py))
92      {
93         psd->px = psd->delta_posx * psd->gravity_x;
94         psd->py = psd->delta_posy * psd->gravity_y;
95      }
96    psd->delta_posx += psd->content_w - psd->prev_cw;
97    psd->prev_cw = psd->content_w;
98    psd->delta_posy += psd->content_h - psd->prev_ch;
99    psd->prev_ch = psd->content_h;
100
101    evas_object_move(psd->content, psd->x - psd->px, psd->y - psd->py);
102    psd->px = psd->delta_posx * psd->gravity_x;
103    psd->py = psd->delta_posy * psd->gravity_y;
104 }
105
106 static void
107 _elm_pan_smart_add(Evas_Object *obj)
108 {
109    const Evas_Smart_Class *sc;
110    const Evas_Smart *smart;
111
112    EVAS_SMART_DATA_ALLOC(obj, Elm_Pan_Smart_Data);
113
114    _elm_pan_parent_sc->add(obj);
115
116    priv->self = obj;
117
118    priv->x = 0;
119    priv->y = 0;
120    priv->w = 0;
121    priv->h = 0;
122    priv->gravity_x = 0.0;
123    priv->gravity_y = 0.0;
124
125    smart = evas_object_smart_smart_get(obj);
126    sc = evas_smart_class_get(smart);
127    priv->api = (const Elm_Pan_Smart_Class *)sc;
128 }
129
130 static void
131 _elm_pan_smart_del(Evas_Object *obj)
132 {
133    _elm_pan_content_set(obj, NULL);
134
135    _elm_pan_parent_sc->del(obj);
136 }
137
138 static void
139 _elm_pan_smart_move(Evas_Object *obj,
140                     Evas_Coord x,
141                     Evas_Coord y)
142 {
143    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
144
145    /* we don't want the clipped smart object version here */
146
147    psd->x = x;
148    psd->y = y;
149
150    _elm_pan_update(psd);
151 }
152
153 static void
154 _elm_pan_smart_resize(Evas_Object *obj,
155                       Evas_Coord w,
156                       Evas_Coord h)
157 {
158    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
159
160    psd->w = w;
161    psd->h = h;
162
163    _elm_pan_update(psd);
164    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
165 }
166
167 static void
168 _elm_pan_smart_show(Evas_Object *obj)
169 {
170    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
171
172    _elm_pan_parent_sc->show(obj);
173
174    if (psd->content)
175      evas_object_show(psd->content);
176 }
177
178 static void
179 _elm_pan_smart_hide(Evas_Object *obj)
180 {
181    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
182
183    _elm_pan_parent_sc->hide(obj);
184
185    if (psd->content)
186      evas_object_hide(psd->content);
187 }
188
189 static void
190 _elm_pan_pos_set(Evas_Object *obj,
191                  Evas_Coord x,
192                  Evas_Coord y)
193 {
194    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
195
196    if ((x == psd->px) && (y == psd->py)) return;
197    psd->px = x;
198    psd->py = y;
199
200    _elm_pan_update(psd);
201    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
202 }
203
204 static void
205 _elm_pan_pos_get(const Evas_Object *obj,
206                  Evas_Coord *x,
207                  Evas_Coord *y)
208 {
209    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
210
211    if (x) *x = psd->px;
212    if (y) *y = psd->py;
213 }
214
215 static void
216 _elm_pan_pos_max_get(const Evas_Object *obj,
217                      Evas_Coord *x,
218                      Evas_Coord *y)
219 {
220    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
221
222    if (x)
223      {
224         if (psd->w < psd->content_w) *x = psd->content_w - psd->w;
225         else *x = 0;
226      }
227    if (y)
228      {
229         if (psd->h < psd->content_h) *y = psd->content_h - psd->h;
230         else *y = 0;
231      }
232 }
233
234 static void
235 _elm_pan_pos_min_get(const Evas_Object *obj __UNUSED__,
236                      Evas_Coord *x,
237                      Evas_Coord *y)
238 {
239    if (x)
240      *x = 0;
241    if (y)
242      *y = 0;
243 }
244
245 static void
246 _elm_pan_content_size_get(const Evas_Object *obj,
247                           Evas_Coord *w,
248                           Evas_Coord *h)
249 {
250    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
251
252    if (w) *w = psd->content_w;
253    if (h) *h = psd->content_h;
254 }
255
256 static void
257 _elm_pan_gravity_set(Evas_Object *obj,
258                      double x,
259                      double y)
260 {
261    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
262
263    psd->gravity_x = x;
264    psd->gravity_y = y;
265    psd->prev_cw = psd->content_w;
266    psd->prev_ch = psd->content_h;
267    psd->delta_posx = 0;
268    psd->delta_posy = 0;
269 }
270
271 static void
272 _elm_pan_gravity_get(const Evas_Object *obj,
273                      double *x,
274                      double *y)
275 {
276    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
277
278    if (x) *x = psd->gravity_x;
279    if (y) *y = psd->gravity_y;
280 }
281
282 static void
283 _elm_pan_smart_set_user(Elm_Pan_Smart_Class *sc)
284 {
285    sc->base.add = _elm_pan_smart_add;
286    sc->base.del = _elm_pan_smart_del;
287    sc->base.move = _elm_pan_smart_move;
288    sc->base.resize = _elm_pan_smart_resize;
289    sc->base.show = _elm_pan_smart_show;
290    sc->base.hide = _elm_pan_smart_hide;
291    sc->pos_set = _elm_pan_pos_set;
292    sc->pos_get = _elm_pan_pos_get;
293    sc->pos_max_get = _elm_pan_pos_max_get;
294    sc->pos_min_get = _elm_pan_pos_min_get;
295    sc->content_size_get = _elm_pan_content_size_get;
296    sc->gravity_set = _elm_pan_gravity_set;
297    sc->gravity_get = _elm_pan_gravity_get;
298    sc->pos_adjust = NULL;
299 }
300
301 static Evas_Object *
302 _elm_pan_add(Evas *evas)
303 {
304    return evas_object_smart_add(evas, _elm_pan_smart_class_new());
305 }
306
307 static void
308 _elm_pan_content_del_cb(void *data,
309                         Evas *e __UNUSED__,
310                         Evas_Object *obj __UNUSED__,
311                         void *event_info __UNUSED__)
312 {
313    Elm_Pan_Smart_Data *psd;
314
315    psd = data;
316    psd->content = NULL;
317    psd->content_w = psd->content_h = psd->px = psd->py =
318            psd->prev_cw = psd->prev_ch = psd->delta_posx = psd->delta_posy = 0;
319    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
320 }
321
322 static void
323 _elm_pan_content_resize_cb(void *data,
324                            Evas *e __UNUSED__,
325                            Evas_Object *obj __UNUSED__,
326                            void *event_info __UNUSED__)
327 {
328    Elm_Pan_Smart_Data *psd;
329    Evas_Coord w, h;
330
331    psd = data;
332    evas_object_geometry_get(psd->content, NULL, NULL, &w, &h);
333    if ((w != psd->content_w) || (h != psd->content_h))
334      {
335         psd->content_w = w;
336         psd->content_h = h;
337         _elm_pan_update(psd);
338      }
339    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
340 }
341
342 static void
343 _elm_pan_content_set(Evas_Object *obj,
344                      Evas_Object *content)
345 {
346    Evas_Coord w, h;
347
348    ELM_PAN_DATA_GET_OR_RETURN(obj, psd);
349
350    if (content == psd->content) return;
351    if (psd->content)
352      {
353         evas_object_smart_member_del(psd->content);
354         evas_object_event_callback_del_full
355           (psd->content, EVAS_CALLBACK_DEL, _elm_pan_content_del_cb, psd);
356         evas_object_event_callback_del_full
357           (psd->content, EVAS_CALLBACK_RESIZE, _elm_pan_content_resize_cb,
358           psd);
359         psd->content = NULL;
360      }
361    if (!content) goto end;
362
363    psd->content = content;
364    evas_object_smart_member_add(psd->content, psd->self);
365    evas_object_geometry_get(psd->content, NULL, NULL, &w, &h);
366    psd->content_w = w;
367    psd->content_h = h;
368    evas_object_event_callback_add
369      (content, EVAS_CALLBACK_DEL, _elm_pan_content_del_cb, psd);
370    evas_object_event_callback_add
371      (content, EVAS_CALLBACK_RESIZE, _elm_pan_content_resize_cb, psd);
372
373    if (evas_object_visible_get(psd->self))
374      evas_object_show(psd->content);
375    else
376      evas_object_hide(psd->content);
377
378    _elm_pan_update(psd);
379
380 end:
381    evas_object_smart_callback_call(psd->self, SIG_CHANGED, NULL);
382 }
383
384 /* pan smart object on top, scroller interface on bottom */
385 /* ============================================================ */
386
387 static const char SCROLL_SMART_NAME[] = "elm_scroll";
388
389 #define ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(o, ptr)                     \
390   Elm_Scrollable_Smart_Interface_Data *ptr =                            \
391     evas_object_smart_interface_data_get(o, &(ELM_SCROLLABLE_IFACE.base)); \
392   if (!ptr)                                                             \
393     {                                                                   \
394        CRITICAL("No interface data for object %p (%s)",                 \
395                 o, evas_object_type_get(o));                            \
396        return;                                                          \
397     }
398
399 #define ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(o, ptr, val)            \
400   Elm_Scrollable_Smart_Interface_Data *ptr =                            \
401     evas_object_smart_interface_data_get(o, &(ELM_SCROLLABLE_IFACE.base)); \
402   if (!ptr)                                                             \
403     {                                                                   \
404        CRITICAL("No interface data for object %p (%s)",                 \
405                 o, evas_object_type_get(o));                            \
406        return val;                                                      \
407     }
408
409 static void _elm_scroll_scroll_bar_size_adjust(
410   Elm_Scrollable_Smart_Interface_Data *);
411 static void _elm_scroll_wanted_region_set(Evas_Object *);
412 static Eina_Bool _paging_is_enabled(Elm_Scrollable_Smart_Interface_Data *sid);
413 static Evas_Coord _elm_scroll_page_x_get(
414    Elm_Scrollable_Smart_Interface_Data *sid, int offset, Eina_Bool limit);
415 static Evas_Coord _elm_scroll_page_y_get(
416    Elm_Scrollable_Smart_Interface_Data *sid, int offset, Eina_Bool limit);
417 static void _elm_scroll_content_pos_get(const Evas_Object *,
418                                         Evas_Coord *,
419                                         Evas_Coord *);
420 static void _elm_scroll_content_pos_set(Evas_Object *,
421                                         Evas_Coord,
422                                         Evas_Coord,
423                                         Eina_Bool);
424
425 #define LEFT               0
426 #define RIGHT              1
427 #define UP                 2
428 #define DOWN               3
429 #define EVTIME             1
430 //#define SCROLLDBG 1
431 /* smoothness debug calls - for debugging how much smooth your app is */
432 #define SMOOTHDBG          1
433
434 #ifdef SMOOTHDBG
435 #define SMOOTH_DEBUG_COUNT 100
436
437 #define FPS                1 / 60
438 typedef struct _smooth_debug_info smooth_debug_info;
439 struct _smooth_debug_info
440 {
441    double     t;
442    double     dt;
443    Evas_Coord pos;
444    Evas_Coord dpos;
445    double     vpos;
446 };
447
448 static smooth_debug_info smooth_x_history[SMOOTH_DEBUG_COUNT];
449 static smooth_debug_info smooth_y_history[SMOOTH_DEBUG_COUNT];
450 static int smooth_info_x_count = 0;
451 static int smooth_info_y_count = 0;
452 static double start_time = 0;
453 static int _elm_scroll_smooth_debug = 0;
454 static const int _elm_scroll_gradient_check_pixel = 30;
455
456
457 void
458 _elm_scroll_smooth_debug_init(void)
459 {
460    start_time = ecore_time_get();
461    smooth_info_x_count = 0;
462    smooth_info_y_count = 0;
463
464    memset(&(smooth_x_history[0]), 0,
465           sizeof(smooth_x_history[0]) * SMOOTH_DEBUG_COUNT);
466    memset(&(smooth_y_history[0]), 0,
467           sizeof(smooth_y_history[0]) * SMOOTH_DEBUG_COUNT);
468
469    return;
470 }
471
472 void
473 _elm_scroll_smooth_debug_shutdown(void)
474 {
475    int i = 0;
476    int info_x_count = 0;
477    int info_y_count = 0;
478    double x_ave = 0, y_ave = 0;
479    double x_sum = 0, y_sum = 0;
480    double x_dev = 0, y_dev = 0;
481    double x_dev_sum = 0, y_dev_sum = 0;
482
483    if (smooth_info_x_count >= SMOOTH_DEBUG_COUNT)
484      info_x_count = SMOOTH_DEBUG_COUNT;
485    else
486      info_x_count = smooth_info_x_count;
487
488    if (smooth_info_y_count >= SMOOTH_DEBUG_COUNT)
489      info_y_count = SMOOTH_DEBUG_COUNT;
490    else
491      info_y_count = smooth_info_y_count;
492
493    DBG("\n\n<<< X-axis Smoothness >>>\n");
494    DBG("| Num  | t(time)  | dt       | x    | dx   |vx(dx/1fps) |\n");
495
496    for (i = info_x_count - 1; i >= 0; i--)
497      {
498         DBG("| %4d | %1.6f | %1.6f | %4d | %4d | %9.3f |\n", info_x_count - i,
499             smooth_x_history[i].t,
500             smooth_x_history[i].dt,
501             smooth_x_history[i].pos,
502             smooth_x_history[i].dpos,
503             smooth_x_history[i].vpos);
504         if (i == info_x_count - 1) continue;
505         x_sum += smooth_x_history[i].vpos;
506      }
507
508    x_ave = x_sum / (info_x_count - 1);
509    for (i = 0; i < info_x_count - 1; i++)
510      {
511         x_dev_sum += (smooth_x_history[i].vpos - x_ave) *
512           (smooth_x_history[i].vpos - x_ave);
513      }
514    x_dev = x_dev_sum / (info_x_count - 1);
515    DBG(" Standard deviation of X-axis velocity: %9.3f\n", sqrt(x_dev));
516
517    DBG("\n\n<<< Y-axis Smoothness >>>\n");
518    DBG("| Num  | t(time)  | dt       | y    |  dy  |vy(dy/1fps) |\n");
519    for (i = info_y_count - 1; i >= 0; i--)
520      {
521         DBG("| %4d | %1.6f | %1.6f | %4d | %4d | %9.3f |\n", info_y_count - i,
522             smooth_y_history[i].t,
523             smooth_y_history[i].dt,
524             smooth_y_history[i].pos,
525             smooth_y_history[i].dpos,
526             smooth_y_history[i].vpos);
527         if (i == info_y_count - 1) continue;
528         y_sum += smooth_y_history[i].vpos;
529      }
530    y_ave = y_sum / (info_y_count - 1);
531    for (i = 0; i < info_y_count - 1; i++)
532      {
533         y_dev_sum += (smooth_y_history[i].vpos - y_ave) *
534           (smooth_y_history[i].vpos - y_ave);
535      }
536    y_dev = y_dev_sum / (info_y_count - 1);
537
538    DBG(" Standard deviation of Y-axis velocity: %9.3f\n", sqrt(y_dev));
539 }
540
541 static void
542 _elm_direction_arrows_eval(Elm_Scrollable_Smart_Interface_Data *sid)
543 {
544    Eina_Bool go_left = EINA_TRUE, go_right = EINA_TRUE;
545    Eina_Bool go_up = EINA_TRUE, go_down = EINA_TRUE;
546    Evas_Coord x = 0, y = 0, mx = 0, my = 0, minx = 0, miny = 0;
547    
548    if (!sid->edje_obj || !sid->pan_obj) return;
549    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
550    
551    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
552    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
553    psd->api->pos_get(sid->pan_obj, &x, &y);
554
555    if (x == minx) go_left = EINA_FALSE;
556    if (x == (mx + minx)) go_right = EINA_FALSE;
557    if (y == miny) go_up = EINA_FALSE;
558    if (y == (my + miny)) go_down = EINA_FALSE;
559    if (go_left != sid->go_left)
560      {
561         if (go_left)
562           edje_object_signal_emit(sid->edje_obj, "elm,action,show,left", "elm");
563         else
564           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,left", "elm");
565         sid->go_left = go_left;
566      }
567    if (go_right != sid->go_right)
568      {
569         if (go_right)
570           edje_object_signal_emit(sid->edje_obj, "elm,action,show,right", "elm");
571         else
572           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,right", "elm");
573         sid->go_right= go_right;
574      }
575    if (go_up != sid->go_up)
576      {
577         if (go_up)
578           edje_object_signal_emit(sid->edje_obj, "elm,action,show,up", "elm");
579         else
580           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,up", "elm");
581         sid->go_up = go_up;
582      }
583    if (go_down != sid->go_down)
584      {
585         if (go_down)
586           edje_object_signal_emit(sid->edje_obj, "elm,action,show,down", "elm");
587         else
588           edje_object_signal_emit(sid->edje_obj, "elm,action,hide,down", "elm");
589         sid->go_down= go_down;
590      }
591 }
592
593 void
594 _elm_scroll_smooth_debug_movetime_add(int x,
595                                       int y)
596 {
597    double tim = 0;
598    static int bx = 0;
599    static int by = 0;
600
601    tim = ecore_time_get();
602
603    if (bx != x)
604      {
605         smooth_info_x_count++;
606         memmove(&(smooth_x_history[1]), &(smooth_x_history[0]),
607                 sizeof(smooth_x_history[0]) * (SMOOTH_DEBUG_COUNT - 1));
608         smooth_x_history[0].t = tim - start_time;
609         smooth_x_history[0].dt = smooth_x_history[0].t - smooth_x_history[1].t;
610         smooth_x_history[0].pos = x;
611         smooth_x_history[0].dpos =
612           smooth_x_history[0].pos - smooth_x_history[1].pos;
613
614         if (smooth_x_history[0].dpos >= 0)
615           smooth_x_history[0].vpos = (double)(smooth_x_history[0].dpos) /
616             smooth_x_history[0].dt * FPS;
617         else
618           smooth_x_history[0].vpos = -((double)(smooth_x_history[0].dpos) /
619                                        smooth_x_history[0].dt * FPS);
620      }
621
622    if (by != y)
623      {
624         smooth_info_y_count++;
625         memmove(&(smooth_y_history[1]), &(smooth_y_history[0]),
626                 sizeof(smooth_y_history[0]) * (SMOOTH_DEBUG_COUNT - 1));
627         smooth_y_history[0].t = tim - start_time;
628         smooth_y_history[0].dt = smooth_y_history[0].t - smooth_y_history[1].t;
629         smooth_y_history[0].pos = y;
630         smooth_y_history[0].dpos = smooth_y_history[0].pos -
631           smooth_y_history[1].pos;
632
633         if (smooth_y_history[0].dpos >= 0)
634           smooth_y_history[0].vpos = (double)(smooth_y_history[0].dpos) /
635             smooth_y_history[0].dt * FPS;
636         else
637           smooth_y_history[0].vpos = -((double)(smooth_y_history[0].dpos) /
638                                        smooth_y_history[0].dt * FPS);
639      }
640
641    bx = x;
642    by = y;
643 }
644
645 #endif
646
647 static int
648 _elm_scroll_scroll_bar_h_visibility_adjust(
649   Elm_Scrollable_Smart_Interface_Data *sid)
650 {
651    int scroll_h_vis_change = 0;
652    Evas_Coord w, vw = 0, vh = 0;
653
654    if (!sid->edje_obj) return 0;
655
656    w = sid->content_info.w;
657    if (sid->pan_obj)
658      evas_object_geometry_get(sid->pan_obj, NULL, NULL, &vw, &vh);
659    if (sid->hbar_visible)
660      {
661         if (sid->min_w)
662           {
663              scroll_h_vis_change = 1;
664              sid->hbar_visible = EINA_FALSE;
665           }
666         else
667           {
668              if (sid->hbar_flags == ELM_SCROLLER_POLICY_AUTO)
669                {
670                   if ((sid->content) || (sid->extern_pan))
671                     {
672                        if (w <= vw)
673                          {
674                             scroll_h_vis_change = 1;
675                             sid->hbar_visible = EINA_FALSE;
676                          }
677                     }
678                   else
679                     {
680                        scroll_h_vis_change = 1;
681                        sid->hbar_visible = EINA_FALSE;
682                     }
683                }
684              else if (sid->hbar_flags == ELM_SCROLLER_POLICY_OFF)
685                {
686                   scroll_h_vis_change = 1;
687                   sid->hbar_visible = EINA_FALSE;
688                }
689           }
690      }
691    else
692      {
693         if (!sid->min_w)
694           {
695              if (sid->hbar_flags == ELM_SCROLLER_POLICY_AUTO)
696                {
697                   if ((sid->content) || (sid->extern_pan))
698                     {
699                        if (w > vw)
700                          {
701                             scroll_h_vis_change = 1;
702                             sid->hbar_visible = EINA_TRUE;
703                          }
704                     }
705                }
706              else if (sid->hbar_flags == ELM_SCROLLER_POLICY_ON)
707                {
708                   scroll_h_vis_change = 1;
709                   sid->hbar_visible = EINA_TRUE;
710                }
711           }
712      }
713    if (scroll_h_vis_change)
714      {
715         if (sid->hbar_flags != ELM_SCROLLER_POLICY_OFF)
716           {
717              if (sid->hbar_visible)
718                edje_object_signal_emit
719                  (sid->edje_obj, "elm,action,show,hbar", "elm");
720              else
721                edje_object_signal_emit
722                  (sid->edje_obj, "elm,action,hide,hbar", "elm");
723           }
724         else
725           edje_object_signal_emit
726             (sid->edje_obj, "elm,action,hide,hbar", "elm");
727         edje_object_message_signal_process(sid->edje_obj);
728         _elm_scroll_scroll_bar_size_adjust(sid);
729         if (sid->cb_func.content_min_limit)
730           sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
731      }
732    
733    _elm_direction_arrows_eval(sid);
734    return scroll_h_vis_change;
735 }
736
737 static int
738 _elm_scroll_scroll_bar_v_visibility_adjust(
739   Elm_Scrollable_Smart_Interface_Data *sid)
740 {
741    int scroll_v_vis_change = 0;
742    Evas_Coord h, vw = 0, vh = 0;
743
744    if (!sid->edje_obj) return 0;
745
746    h = sid->content_info.h;
747    if (sid->pan_obj)
748      evas_object_geometry_get(sid->pan_obj, NULL, NULL, &vw, &vh);
749    if (sid->vbar_visible)
750      {
751         if (sid->min_h)
752           {
753              scroll_v_vis_change = 1;
754              sid->vbar_visible = EINA_FALSE;
755           }
756         else
757           {
758              if (sid->vbar_flags == ELM_SCROLLER_POLICY_AUTO)
759                {
760                   if ((sid->content) || (sid->extern_pan))
761                     {
762                        if (h <= vh)
763                          {
764                             scroll_v_vis_change = 1;
765                             sid->vbar_visible = EINA_FALSE;
766                          }
767                     }
768                   else
769                     {
770                        scroll_v_vis_change = 1;
771                        sid->vbar_visible = EINA_FALSE;
772                     }
773                }
774              else if (sid->vbar_flags == ELM_SCROLLER_POLICY_OFF)
775                {
776                   scroll_v_vis_change = 1;
777                   sid->vbar_visible = EINA_FALSE;
778                }
779           }
780      }
781    else
782      {
783         if (!sid->min_h)
784           {
785              if (sid->vbar_flags == ELM_SCROLLER_POLICY_AUTO)
786                {
787                   if ((sid->content) || (sid->extern_pan))
788                     {
789                        if (h > vh)
790                          {
791                             scroll_v_vis_change = 1;
792                             sid->vbar_visible = EINA_TRUE;
793                          }
794                     }
795                }
796              else if (sid->vbar_flags == ELM_SCROLLER_POLICY_ON)
797                {
798                   scroll_v_vis_change = 1;
799                   sid->vbar_visible = EINA_TRUE;
800                }
801           }
802      }
803    if (scroll_v_vis_change)
804      {
805         if (sid->vbar_flags != ELM_SCROLLER_POLICY_OFF)
806           {
807              if (sid->vbar_visible)
808                edje_object_signal_emit
809                  (sid->edje_obj, "elm,action,show,vbar", "elm");
810              else
811                edje_object_signal_emit
812                  (sid->edje_obj, "elm,action,hide,vbar", "elm");
813           }
814         else
815           edje_object_signal_emit
816             (sid->edje_obj, "elm,action,hide,vbar", "elm");
817         edje_object_message_signal_process(sid->edje_obj);
818         _elm_scroll_scroll_bar_size_adjust(sid);
819         if (sid->cb_func.content_min_limit)
820           sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
821      }
822
823    _elm_direction_arrows_eval(sid);
824    return scroll_v_vis_change;
825 }
826
827 static void
828 _elm_scroll_scroll_bar_visibility_adjust(
829   Elm_Scrollable_Smart_Interface_Data *sid)
830 {
831    int changed = 0;
832
833    changed |= _elm_scroll_scroll_bar_h_visibility_adjust(sid);
834    changed |= _elm_scroll_scroll_bar_v_visibility_adjust(sid);
835
836    if (changed)
837      {
838         _elm_scroll_scroll_bar_h_visibility_adjust(sid);
839         _elm_scroll_scroll_bar_v_visibility_adjust(sid);
840      }
841 }
842
843 static void
844 _elm_scroll_scroll_bar_size_adjust(Elm_Scrollable_Smart_Interface_Data *sid)
845 {
846    if (!sid->pan_obj || !sid->edje_obj) return;
847
848    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
849
850    if ((sid->content) || (sid->extern_pan))
851      {
852         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py,
853                    minx = 0, miny = 0;
854         double vx, vy, size;
855
856         edje_object_calc_force(sid->edje_obj);
857         edje_object_part_geometry_get
858           (sid->edje_obj, "elm.swallow.content", NULL, NULL, &vw, &vh);
859         w = sid->content_info.w;
860         if (w < 1) w = 1;
861         size = (double)vw / (double)w;
862
863         if (size > 1.0)
864           {
865              size = 1.0;
866              edje_object_part_drag_value_set
867                (sid->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
868           }
869         edje_object_part_drag_size_set
870           (sid->edje_obj, "elm.dragable.hbar", size, 1.0);
871
872         h = sid->content_info.h;
873         if (h < 1) h = 1;
874         size = (double)vh / (double)h;
875         if (size > 1.0)
876           {
877              size = 1.0;
878              edje_object_part_drag_value_set
879                (sid->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
880           }
881         edje_object_part_drag_size_set
882           (sid->edje_obj, "elm.dragable.vbar", 1.0, size);
883
884         edje_object_part_drag_value_get
885           (sid->edje_obj, "elm.dragable.hbar", &vx, NULL);
886         edje_object_part_drag_value_get
887           (sid->edje_obj, "elm.dragable.vbar", NULL, &vy);
888
889         psd->api->pos_max_get(sid->pan_obj, &mx, &my);
890         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
891         x = vx * mx + minx;
892         y = vy * my + miny;
893
894         edje_object_part_drag_step_set
895           (sid->edje_obj, "elm.dragable.hbar", (double)sid->step.x /
896           (double)w, 0.0);
897         edje_object_part_drag_step_set
898           (sid->edje_obj, "elm.dragable.vbar", 0.0, (double)sid->step.y /
899           (double)h);
900         if (sid->page.x > 0)
901           edje_object_part_drag_page_set
902             (sid->edje_obj, "elm.dragable.hbar", (double)sid->page.x /
903             (double)w, 0.0);
904         else
905           edje_object_part_drag_page_set
906             (sid->edje_obj, "elm.dragable.hbar",
907             -((double)sid->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
908         if (sid->page.y > 0)
909           edje_object_part_drag_page_set
910             (sid->edje_obj, "elm.dragable.vbar", 0.0,
911             (double)sid->page.y / (double)h);
912         else
913           edje_object_part_drag_page_set
914             (sid->edje_obj, "elm.dragable.vbar", 0.0,
915             -((double)sid->page.y * ((double)vh / (double)h)) / 100.0);
916
917         psd->api->pos_get(sid->pan_obj, &px, &py);
918         if (vx != mx) x = px;
919         if (vy != my) y = py;
920         psd->api->pos_set(sid->pan_obj, x, y);
921      }
922    else
923      {
924         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
925
926         edje_object_part_drag_size_set
927           (sid->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
928         edje_object_part_drag_size_set
929           (sid->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
930         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
931         psd->api->pos_get(sid->pan_obj, &px, &py);
932         psd->api->pos_set(sid->pan_obj, minx, miny);
933         if ((px != minx) || (py != miny))
934           edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
935      }
936    _elm_scroll_scroll_bar_visibility_adjust(sid);
937 }
938
939 static void
940 _elm_scroll_scroll_bar_read_and_update(
941   Elm_Scrollable_Smart_Interface_Data *sid)
942 {
943    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
944    double vx, vy;
945
946    if (!sid->edje_obj || !sid->pan_obj) return;
947
948    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
949
950    if ((sid->down.dragged) || (sid->down.bounce_x_animator)
951        || (sid->down.bounce_y_animator) || (sid->down.momentum_animator)
952        || (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
953      return;
954    edje_object_part_drag_value_get
955      (sid->edje_obj, "elm.dragable.vbar", NULL, &vy);
956    edje_object_part_drag_value_get
957      (sid->edje_obj, "elm.dragable.hbar", &vx, NULL);
958    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
959    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
960    x = _round(vx * (double)mx + minx, 1);
961    y = _round(vy * (double)my + miny, 1);
962    psd->api->pos_get(sid->pan_obj, &px, &py);
963
964    if (!sid->freeze && _paging_is_enabled(sid))
965      {
966         x = _elm_scroll_page_x_get(sid, 0, EINA_FALSE);
967         y = _elm_scroll_page_y_get(sid, 0, EINA_FALSE);
968      }
969    psd->api->pos_set(sid->pan_obj, x, y);
970    if ((px != x) || (py != y))
971      {
972         edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
973      }
974 }
975
976 static void
977 _elm_scroll_drag_start(Elm_Scrollable_Smart_Interface_Data *sid)
978 {
979    if (sid->cb_func.drag_start)
980      sid->cb_func.drag_start(sid->obj, NULL);
981 }
982
983 static void
984 _elm_scroll_drag_stop(Elm_Scrollable_Smart_Interface_Data *sid)
985 {
986    sid->current_page.x = _elm_scroll_page_x_get(sid, 0, EINA_FALSE);
987    sid->current_page.y = _elm_scroll_page_y_get(sid, 0, EINA_FALSE);
988
989    if (sid->cb_func.drag_stop)
990      sid->cb_func.drag_stop(sid->obj, NULL);
991 }
992
993 static void
994 _elm_scroll_anim_start(Elm_Scrollable_Smart_Interface_Data *sid)
995 {
996    if (sid->cb_func.animate_start)
997      sid->cb_func.animate_start(sid->obj, NULL);
998 }
999
1000 static void
1001 _elm_scroll_anim_stop(Elm_Scrollable_Smart_Interface_Data *sid)
1002 {
1003    sid->current_page.x = _elm_scroll_page_x_get(sid, 0, EINA_FALSE);
1004    sid->current_page.y = _elm_scroll_page_y_get(sid, 0, EINA_FALSE);
1005
1006    if (sid->cb_func.animate_stop)
1007      sid->cb_func.animate_stop(sid->obj, NULL);
1008 }
1009
1010 static void
1011 _elm_scroll_policy_signal_emit(Elm_Scrollable_Smart_Interface_Data *sid)
1012 {
1013    if (sid->hbar_flags == ELM_SCROLLER_POLICY_ON)
1014      edje_object_signal_emit
1015        (sid->edje_obj, "elm,action,show_always,hbar", "elm");
1016    else if (sid->hbar_flags == ELM_SCROLLER_POLICY_OFF)
1017      edje_object_signal_emit
1018        (sid->edje_obj, "elm,action,hide,hbar", "elm");
1019    else
1020      edje_object_signal_emit
1021        (sid->edje_obj, "elm,action,show_notalways,hbar", "elm");
1022    if (sid->vbar_flags == ELM_SCROLLER_POLICY_ON)
1023      edje_object_signal_emit
1024        (sid->edje_obj, "elm,action,show_always,vbar", "elm");
1025    else if (sid->vbar_flags == ELM_SCROLLER_POLICY_OFF)
1026      edje_object_signal_emit
1027        (sid->edje_obj, "elm,action,hide,vbar", "elm");
1028    else
1029      edje_object_signal_emit
1030        (sid->edje_obj, "elm,action,show_notalways,vbar", "elm");
1031    edje_object_message_signal_process(sid->edje_obj);
1032    _elm_scroll_scroll_bar_size_adjust(sid);
1033 }
1034
1035 static void
1036 _elm_scroll_reload_cb(void *data,
1037                       Evas_Object *obj __UNUSED__,
1038                       const char *emission __UNUSED__,
1039                       const char *source __UNUSED__)
1040 {
1041    Elm_Scrollable_Smart_Interface_Data *sid = data;
1042
1043    // FIXME: refactoring for determining bar's size and visiblity
1044    sid->hbar_visible = EINA_TRUE;
1045    sid->vbar_visible = EINA_TRUE;
1046
1047    _elm_scroll_policy_signal_emit(sid);
1048 }
1049
1050 static void
1051 _elm_scroll_vbar_drag_cb(void *data,
1052                            Evas_Object *obj __UNUSED__,
1053                            const char *emission __UNUSED__,
1054                            const char *source __UNUSED__)
1055 {
1056    Elm_Scrollable_Smart_Interface_Data *sid = data;
1057
1058    if (sid->cb_func.vbar_drag)
1059      sid->cb_func.vbar_drag(sid->obj, NULL);
1060
1061    _elm_scroll_scroll_bar_read_and_update(sid);
1062 }
1063
1064 static void
1065 _elm_scroll_vbar_press_cb(void *data,
1066                            Evas_Object *obj __UNUSED__,
1067                            const char *emission __UNUSED__,
1068                            const char *source __UNUSED__)
1069 {
1070    Elm_Scrollable_Smart_Interface_Data *sid = data;
1071
1072    if (sid->cb_func.vbar_press)
1073      sid->cb_func.vbar_press(sid->obj, NULL);
1074 }
1075
1076 static void
1077 _elm_scroll_vbar_unpress_cb(void *data,
1078                            Evas_Object *obj __UNUSED__,
1079                            const char *emission __UNUSED__,
1080                            const char *source __UNUSED__)
1081 {
1082    Elm_Scrollable_Smart_Interface_Data *sid = data;
1083
1084    if (sid->cb_func.vbar_unpress)
1085      sid->cb_func.vbar_unpress(sid->obj, NULL);
1086 }
1087
1088 static void
1089 _elm_scroll_edje_drag_v_start_cb(void *data,
1090                                  Evas_Object *obj __UNUSED__,
1091                                  const char *emission __UNUSED__,
1092                                  const char *source __UNUSED__)
1093 {
1094    Elm_Scrollable_Smart_Interface_Data *sid = data;
1095
1096    _elm_scroll_scroll_bar_read_and_update(sid);
1097    _elm_scroll_drag_start(sid);
1098    sid->freeze = EINA_TRUE;
1099 }
1100
1101 static void
1102 _elm_scroll_edje_drag_v_stop_cb(void *data,
1103                                 Evas_Object *obj __UNUSED__,
1104                                 const char *emission __UNUSED__,
1105                                 const char *source __UNUSED__)
1106 {
1107    Elm_Scrollable_Smart_Interface_Data *sid = data;
1108
1109    _elm_scroll_scroll_bar_read_and_update(sid);
1110    _elm_scroll_drag_stop(sid);
1111    sid->freeze = EINA_FALSE;
1112 }
1113
1114 static void
1115 _elm_scroll_edje_drag_v_cb(void *data,
1116                            Evas_Object *obj __UNUSED__,
1117                            const char *emission __UNUSED__,
1118                            const char *source __UNUSED__)
1119 {
1120    Elm_Scrollable_Smart_Interface_Data *sid = data;
1121
1122    _elm_scroll_scroll_bar_read_and_update(sid);
1123 }
1124
1125 static void
1126 _elm_scroll_hbar_drag_cb(void *data,
1127                            Evas_Object *obj __UNUSED__,
1128                            const char *emission __UNUSED__,
1129                            const char *source __UNUSED__)
1130 {
1131    Elm_Scrollable_Smart_Interface_Data *sid = data;
1132
1133    if (sid->cb_func.hbar_drag)
1134      sid->cb_func.hbar_drag(sid->obj, NULL);
1135
1136    _elm_scroll_scroll_bar_read_and_update(sid);
1137 }
1138
1139 static void
1140 _elm_scroll_hbar_press_cb(void *data,
1141                            Evas_Object *obj __UNUSED__,
1142                            const char *emission __UNUSED__,
1143                            const char *source __UNUSED__)
1144 {
1145    Elm_Scrollable_Smart_Interface_Data *sid = data;
1146
1147    if (sid->cb_func.hbar_press)
1148      sid->cb_func.hbar_press(sid->obj, NULL);
1149 }
1150
1151 static void
1152 _elm_scroll_hbar_unpress_cb(void *data,
1153                            Evas_Object *obj __UNUSED__,
1154                            const char *emission __UNUSED__,
1155                            const char *source __UNUSED__)
1156 {
1157    Elm_Scrollable_Smart_Interface_Data *sid = data;
1158
1159    if (sid->cb_func.hbar_unpress)
1160      sid->cb_func.hbar_unpress(sid->obj, NULL);
1161 }
1162
1163 static void
1164 _elm_scroll_edje_drag_h_start_cb(void *data,
1165                                  Evas_Object *obj __UNUSED__,
1166                                  const char *emission __UNUSED__,
1167                                  const char *source __UNUSED__)
1168 {
1169    Elm_Scrollable_Smart_Interface_Data *sid = data;
1170
1171    _elm_scroll_scroll_bar_read_and_update(sid);
1172    _elm_scroll_drag_start(sid);
1173    sid->freeze = EINA_TRUE;
1174 }
1175
1176 static void
1177 _elm_scroll_edje_drag_h_stop_cb(void *data,
1178                                 Evas_Object *obj __UNUSED__,
1179                                 const char *emission __UNUSED__,
1180                                 const char *source __UNUSED__)
1181 {
1182    Elm_Scrollable_Smart_Interface_Data *sid = data;
1183
1184    _elm_scroll_scroll_bar_read_and_update(sid);
1185    _elm_scroll_drag_stop(sid);
1186    sid->freeze = EINA_FALSE;
1187 }
1188
1189 static void
1190 _elm_scroll_edje_drag_h_cb(void *data,
1191                            Evas_Object *obj __UNUSED__,
1192                            const char *emission __UNUSED__,
1193                            const char *source __UNUSED__)
1194 {
1195    Elm_Scrollable_Smart_Interface_Data *sid = data;
1196
1197    _elm_scroll_scroll_bar_read_and_update(sid);
1198 }
1199
1200 static void
1201 _elm_scroll_content_size_get(const Evas_Object *obj,
1202                              Evas_Coord *w,
1203                              Evas_Coord *h)
1204 {
1205    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1206
1207    if (sid->content)
1208      evas_object_geometry_get(sid->content, NULL, NULL, w, h);
1209    else if (sid->pan_obj)
1210      {
1211         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1212         psd->api->content_size_get(sid->pan_obj, w, h);
1213      }
1214 }
1215
1216 static void
1217 _elm_scroll_content_viewport_size_get(const Evas_Object *obj,
1218                                       Evas_Coord *w,
1219                                       Evas_Coord *h)
1220 {
1221    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1222
1223    if (!sid->pan_obj || !sid->edje_obj) return;
1224
1225    edje_object_calc_force(sid->edje_obj);
1226    evas_object_geometry_get(sid->pan_obj, NULL, NULL, w, h);
1227 }
1228
1229 static void
1230 _elm_scroll_content_viewport_pos_get(const Evas_Object *obj,
1231                                      Evas_Coord *x,
1232                                      Evas_Coord *y)
1233 {
1234    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1235
1236    if (!sid->pan_obj || !sid->edje_obj) return;
1237
1238    edje_object_calc_force(sid->edje_obj);
1239    evas_object_geometry_get(sid->pan_obj, x, y, NULL, NULL);
1240 }
1241
1242 static void
1243 _elm_scroll_content_min_limit(Evas_Object *obj,
1244                               Eina_Bool w,
1245                               Eina_Bool h)
1246 {
1247    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1248
1249    if (!sid->edje_obj) return;
1250
1251    if (!sid->cb_func.content_min_limit)
1252      {
1253         ERR("Content minimim size limiting is unimplemented -- you "
1254             "must provide it yourself\n");
1255         return;
1256      }
1257
1258    sid->min_w = !!w;
1259    sid->min_h = !!h;
1260    sid->cb_func.content_min_limit(sid->obj, w, h);
1261 }
1262
1263 static void
1264 _elm_scroll_origin_reverse_set(Evas_Object *obj,
1265                           Eina_Bool origin_x, Eina_Bool origin_y)
1266 {
1267    Evas_Coord x, y;
1268
1269    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1270
1271    sid->origin_x = origin_x;
1272    sid->origin_y = origin_y;
1273
1274    _elm_scroll_content_pos_get(sid->obj, &x, &y);
1275    _elm_scroll_wanted_coordinates_update(sid, x, y);
1276 }
1277
1278 static void
1279 _elm_scroll_origin_reverse_get(const Evas_Object *obj,
1280                           Eina_Bool *origin_x, Eina_Bool *origin_y)
1281 {
1282    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1283
1284    if (origin_x) *origin_x = sid->origin_x;
1285    if (origin_y) *origin_y = sid->origin_y;
1286 }
1287
1288 static Evas_Coord
1289 _elm_scroll_x_mirrored_get(const Evas_Object *obj,
1290                            Evas_Coord x)
1291 {
1292    Evas_Coord cw, ch, w, ret;
1293
1294    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, x);
1295
1296    if (!sid->pan_obj) return 0;
1297
1298    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
1299
1300    _elm_scroll_content_viewport_size_get(obj, &w, NULL);
1301    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1302    ret = (cw - (x + w));
1303
1304    return (ret >= 0) ? ret : 0;
1305 }
1306
1307 /* Update the wanted coordinates according to the x, y passed
1308  * widget directionality, content size and etc. */
1309 static void
1310 _elm_scroll_wanted_coordinates_update(Elm_Scrollable_Smart_Interface_Data *sid,
1311                                       Evas_Coord x,
1312                                       Evas_Coord y)
1313 {
1314    Evas_Coord cw, ch;
1315
1316    if (!sid->pan_obj) return;
1317
1318    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1319
1320    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1321
1322    /* Update wx/y/w/h - and if the requested positions aren't legal
1323     * adjust a bit. */
1324    _elm_scroll_content_viewport_size_get(sid->obj, &sid->ww, &sid->wh);
1325
1326    if (x < 0)
1327      {
1328         if (!sid->loop_h) sid->wx = 0;
1329         else sid->wx = cw - sid->ww;
1330      }
1331    else if (!sid->loop_h && (x + sid->ww) > cw)
1332      sid->wx = cw - sid->ww;
1333    else if (sid->loop_h && x >= cw)
1334      sid->wx = 0;
1335    else if (sid->is_mirrored)
1336      sid->wx = _elm_scroll_x_mirrored_get(sid->obj, x);
1337    else
1338      sid->wx = x;
1339
1340    if (sid->origin_x)
1341      {
1342         sid->wx = cw - sid->wx;
1343         if (sid->wx < 0) sid->wx = 0;
1344      }
1345
1346    if (y < 0)
1347      {
1348         if (!sid->loop_v) sid->wy = 0;
1349         else  sid->wy = ch - sid->wh;
1350      }
1351    else if (!sid->loop_v && (y + sid->wh) > ch)
1352      sid->wy = ch - sid->wh;
1353    else if (sid->loop_v && y >= ch)
1354      sid->wy = 0;
1355    else sid->wy = y;
1356
1357    if (sid->origin_y)
1358      {
1359         sid->wy = ch - sid->wy;
1360         if (sid->wy < 0) sid->wy = 0;
1361      }
1362 }
1363
1364 static void
1365 _elm_scroll_momentum_end(Elm_Scrollable_Smart_Interface_Data *sid)
1366 {
1367    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator)) return;
1368    if (sid->down.momentum_animator)
1369      {
1370         Evas_Coord px, py;
1371         _elm_scroll_content_pos_get(sid->obj, &px, &py);
1372         _elm_scroll_wanted_coordinates_update(sid, px, py);
1373
1374         ecore_animator_del(sid->down.momentum_animator);
1375         sid->down.momentum_animator = NULL;
1376         sid->down.bounce_x_hold = EINA_FALSE;
1377         sid->down.bounce_y_hold = EINA_FALSE;
1378         sid->down.ax = 0;
1379         sid->down.ay = 0;
1380         sid->down.dx = 0;
1381         sid->down.dy = 0;
1382         sid->down.pdx = 0;
1383         sid->down.pdy = 0;
1384         if (sid->content_info.resized)
1385           _elm_scroll_wanted_region_set(sid->obj);
1386      }
1387 }
1388
1389 static Eina_Bool
1390 _elm_scroll_bounce_x_animator(void *data)
1391 {
1392    Elm_Scrollable_Smart_Interface_Data *sid;
1393    Evas_Coord x, y, dx, w, odx, ed, md;
1394    double t, p, dt, pd, r;
1395
1396    sid = data;
1397    t = ecore_loop_time_get();
1398    dt = t - sid->down.anim_start2;
1399    if (dt >= 0.0)
1400      {
1401         dt = dt / _elm_config->thumbscroll_bounce_friction;
1402         odx = sid->down.b2x - sid->down.bx;
1403         _elm_scroll_content_viewport_size_get(sid->obj, &w, NULL);
1404         if (!sid->down.momentum_animator && (w > abs(odx)))
1405           {
1406              pd = (double)odx / (double)w;
1407              pd = (pd > 0) ? pd : -pd;
1408              pd = 1.0 - ((1.0 - pd) * (1.0 - pd));
1409              dt = dt / pd;
1410           }
1411         if (dt > 1.0) dt = 1.0;
1412         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
1413         _elm_scroll_content_pos_get(sid->obj, &x, &y);
1414         dx = (odx * p);
1415         r = 1.0;
1416         if (sid->down.momentum_animator)
1417           {
1418              ed = abs(sid->down.dx * (_elm_config->thumbscroll_friction +
1419                                       sid->down.extra_time) - sid->down.b0x);
1420              md = abs(_elm_config->thumbscroll_friction * 5 * w);
1421              if (ed > md) r = (double)(md) / (double)ed;
1422           }
1423         x = sid->down.b2x + (int)((double)(dx - odx) * r);
1424         if (!sid->down.cancelled)
1425           _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1426         if (dt >= 1.0)
1427           {
1428              if (sid->down.momentum_animator)
1429                sid->down.bounce_x_hold = EINA_TRUE;
1430              if ((!sid->down.bounce_y_animator) &&
1431                  (!sid->scrollto.y.animator))
1432                _elm_scroll_anim_stop(sid);
1433              sid->down.bounce_x_animator = NULL;
1434              sid->down.pdx = 0;
1435              sid->bouncemex = EINA_FALSE;
1436              _elm_scroll_momentum_end(sid);
1437              if (sid->content_info.resized)
1438                _elm_scroll_wanted_region_set(sid->obj);
1439              return ECORE_CALLBACK_CANCEL;
1440           }
1441      }
1442    return ECORE_CALLBACK_RENEW;
1443 }
1444
1445 static Eina_Bool
1446 _elm_scroll_bounce_y_animator(void *data)
1447 {
1448    Elm_Scrollable_Smart_Interface_Data *sid;
1449    Evas_Coord x, y, dy, h, ody, ed, md;
1450    double t, p, dt, pd, r;
1451
1452    sid = data;
1453    t = ecore_loop_time_get();
1454    dt = t - sid->down.anim_start3;
1455    if (dt >= 0.0)
1456      {
1457         dt = dt / _elm_config->thumbscroll_bounce_friction;
1458         ody = sid->down.b2y - sid->down.by;
1459         _elm_scroll_content_viewport_size_get(sid->obj, NULL, &h);
1460         if (!sid->down.momentum_animator && (h > abs(ody)))
1461           {
1462              pd = (double)ody / (double)h;
1463              pd = (pd > 0) ? pd : -pd;
1464              pd = 1.0 - ((1.0 - pd) * (1.0 - pd));
1465              dt = dt / pd;
1466           }
1467         if (dt > 1.0) dt = 1.0;
1468         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
1469         _elm_scroll_content_pos_get(sid->obj, &x, &y);
1470         dy = (ody * p);
1471         r = 1.0;
1472         if (sid->down.momentum_animator)
1473           {
1474              ed = abs(sid->down.dy * (_elm_config->thumbscroll_friction +
1475                                       sid->down.extra_time) - sid->down.b0y);
1476              md = abs(_elm_config->thumbscroll_friction * 5 * h);
1477              if (ed > md) r = (double)(md) / (double)ed;
1478           }
1479         y = sid->down.b2y + (int)((double)(dy - ody) * r);
1480         if (!sid->down.cancelled)
1481           _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
1482         if (dt >= 1.0)
1483           {
1484              if (sid->down.momentum_animator)
1485                sid->down.bounce_y_hold = EINA_TRUE;
1486              if ((!sid->down.bounce_x_animator) &&
1487                  (!sid->scrollto.y.animator))
1488                _elm_scroll_anim_stop(sid);
1489              sid->down.bounce_y_animator = NULL;
1490              sid->down.pdy = 0;
1491              sid->bouncemey = EINA_FALSE;
1492              _elm_scroll_momentum_end(sid);
1493              if (sid->content_info.resized)
1494                _elm_scroll_wanted_region_set(sid->obj);
1495              return ECORE_CALLBACK_CANCEL;
1496           }
1497      }
1498
1499    return ECORE_CALLBACK_RENEW;
1500 }
1501
1502 static void
1503 _elm_scroll_bounce_eval(Elm_Scrollable_Smart_Interface_Data *sid)
1504 {
1505    Evas_Coord mx, my, px, py, bx, by, b2x, b2y, minx = 0, miny = 0;
1506
1507    if (!sid->pan_obj) return;
1508
1509    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1510
1511    if (sid->freeze) return;
1512    if ((!sid->bouncemex) && (!sid->bouncemey)) return;
1513    if (sid->down.now) return;  // down bounce while still held down
1514    if (sid->down.onhold_animator)
1515      {
1516         ecore_animator_del(sid->down.onhold_animator);
1517         sid->down.onhold_animator = NULL;
1518         if (sid->content_info.resized)
1519           _elm_scroll_wanted_region_set(sid->obj);
1520      }
1521    if (sid->down.hold_animator)
1522      {
1523         ecore_animator_del(sid->down.hold_animator);
1524         sid->down.hold_animator = NULL;
1525         if (sid->content_info.resized)
1526           _elm_scroll_wanted_region_set(sid->obj);
1527      }
1528    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1529    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1530    psd->api->pos_get(sid->pan_obj, &px, &py);
1531    bx = px;
1532    by = py;
1533    if (px < minx) px = minx;
1534    if ((px - minx) > mx) px = mx + minx;
1535    if (py < miny) py = miny;
1536    if ((py - miny) > my) py = my + miny;
1537    b2x = px;
1538    b2y = py;
1539    if ((!sid->obj) ||
1540        (!elm_widget_drag_child_locked_x_get(sid->obj)))
1541      {
1542         if ((!sid->down.bounce_x_animator) && (!sid->bounce_animator_disabled))
1543           {
1544              if (sid->bouncemex)
1545                {
1546                   if (sid->scrollto.x.animator)
1547                     {
1548                        ecore_animator_del(sid->scrollto.x.animator);
1549                        sid->scrollto.x.animator = NULL;
1550                     }
1551                   sid->down.bounce_x_animator =
1552                     ecore_animator_add(_elm_scroll_bounce_x_animator, sid);
1553                   sid->down.anim_start2 = ecore_loop_time_get();
1554                   sid->down.bx = bx;
1555                   sid->down.bx0 = bx;
1556                   sid->down.b2x = b2x;
1557                   if (sid->down.momentum_animator)
1558                     sid->down.b0x = sid->down.ax;
1559                   else sid->down.b0x = 0;
1560                }
1561           }
1562      }
1563    if ((!sid->obj) ||
1564        (!elm_widget_drag_child_locked_y_get(sid->obj)))
1565      {
1566         if ((!sid->down.bounce_y_animator) && (!sid->bounce_animator_disabled))
1567           {
1568              if (sid->bouncemey)
1569                {
1570                   if (sid->scrollto.y.animator)
1571                     {
1572                        ecore_animator_del(sid->scrollto.y.animator);
1573                        sid->scrollto.y.animator = NULL;
1574                     }
1575                   sid->down.bounce_y_animator =
1576                     ecore_animator_add(_elm_scroll_bounce_y_animator, sid);
1577                   sid->down.anim_start3 = ecore_loop_time_get();
1578                   sid->down.by = by;
1579                   sid->down.by0 = by;
1580                   sid->down.b2y = b2y;
1581                   if (sid->down.momentum_animator)
1582                     sid->down.b0y = sid->down.ay;
1583                   else sid->down.b0y = 0;
1584                }
1585           }
1586      }
1587 }
1588
1589 static void
1590 _elm_scroll_content_pos_get(const Evas_Object *obj,
1591                             Evas_Coord *x,
1592                             Evas_Coord *y)
1593 {
1594    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1595
1596    if (!sid->pan_obj) return;
1597
1598    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1599
1600    psd->api->pos_get(sid->pan_obj, x, y);
1601 }
1602
1603 static void
1604 _elm_scroll_content_pos_set(Evas_Object *obj,
1605                             Evas_Coord x,
1606                             Evas_Coord y,
1607                             Eina_Bool sig)
1608 {
1609    Evas_Coord mx = 0, my = 0, px = 0, py = 0, spx = 0, spy = 0, minx = 0, miny = 0, pw = 0, ph = 0;
1610    Evas_Coord cw =0, ch = 0, ww = 0, wh = 0; //// TIZEN ONLY
1611    double vx, vy;
1612
1613    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1614
1615    if (!sid->edje_obj || !sid->pan_obj) return;
1616
1617    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
1618
1619    psd->api->pos_get(sid->pan_obj, &px, &py);
1620
1621    if ((px == x) && (py == y)) return;
1622
1623    // FIXME: allow for bounce outside of range
1624    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1625    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1626    psd->api->content_size_get(sid->pan_obj, &cw, &ch); //// TIZEN ONLY
1627    _elm_scroll_content_viewport_size_get(obj, &ww, &wh); //// TIZEN ONLY
1628    evas_object_geometry_get(sid->pan_obj, NULL, NULL, &pw, &ph);
1629
1630    if (_elm_config->access_mode)
1631      {
1632         if (((y > 0) && (y % _elm_config->finger_size) < 2 &&
1633              !((py % _elm_config->finger_size) < 2 && abs(py - y) < 2)) ||
1634             ((x > 0) && (x % _elm_config->finger_size) < 2 &&
1635              !((px % _elm_config->finger_size) < 2 && abs(px - x) < 2)))
1636           _elm_access_sound_play(ELM_ACCESS_SOUND_SCROLL);
1637      }
1638
1639    if (_paging_is_enabled(sid))
1640      {
1641         //Work when Page Snap is enabled.
1642         /*
1643         //we passed one page to the right
1644         if (x > sid->current_page.x + sid->pagesize_h)
1645           x = sid->current_page.x + sid->pagesize_h;
1646         //we passed one page to the left
1647         if (x < sid->current_page.x - sid->pagesize_h)
1648           x = sid->current_page.x - sid->pagesize_h;
1649
1650         //we passed one page to the bottom
1651         if (y > sid->current_page.y + sid->pagesize_v)
1652           y = sid->current_page.y + sid->pagesize_v;
1653         //we passed one page to the top
1654         if (y < sid->current_page.y - sid->pagesize_v)
1655           y = sid->current_page.y - sid->pagesize_v;
1656         */
1657      }
1658
1659    if (sid->loop_h && cw > 0)
1660      {
1661         if (_paging_is_enabled(sid))
1662           {
1663              if (x < 0) x = cw + (x % cw);
1664              else if (x >= (pw * sid->pagecount_h)) x = (x % cw);
1665           }
1666         else
1667           {
1668              if (x < 0) x = cw + (x % cw);
1669              else if (x >= cw) x = (x % cw);
1670           }
1671      }
1672    if (sid->loop_v && ch > 0)
1673      {
1674        if (_paging_is_enabled(sid))
1675          {
1676             if (y < 0) y = ch + (y % ch);
1677             else if (y >= (ph * sid->pagecount_v)) y = (y % ch);
1678          }
1679        else
1680          {
1681             if (y < 0) y = ch + (y % ch);
1682             else if (y >= ch) y = (y % ch);
1683          }
1684      }
1685
1686 //// TIZEN ONLY
1687    if (cw > ww)
1688      {
1689         if (x < minx)
1690           edje_object_signal_emit(sid->edje_obj, "elm,edge,left", "elm");
1691         if (!sid->loop_h && (x - minx) > mx)
1692           edje_object_signal_emit(sid->edje_obj, "elm,edge,right", "elm");
1693      }
1694    if (ch > wh)
1695      {
1696         if (y < miny)
1697           edje_object_signal_emit(sid->edje_obj, "elm,edge,top", "elm");
1698         if (!sid->loop_v && (y - miny) > my)
1699           edje_object_signal_emit(sid->edje_obj, "elm,edge,bottom", "elm");
1700      }
1701 //
1702    if (!_elm_config->thumbscroll_bounce_enable)
1703      {
1704         if (x < minx) x = minx;
1705         if (!sid->loop_h && (x - minx) > mx) x = mx + minx;
1706         if (y < miny) y = miny;
1707         if (!sid->loop_v && (y - miny) > my) y = my + miny;
1708      }
1709
1710    if (!sid->bounce_horiz)
1711      {
1712         if (x < minx) x = minx;
1713         if (!sid->loop_h && ((x - minx) > mx)) x = mx + minx;
1714      }
1715    if (!sid->bounce_vert)
1716      {
1717         if (y < miny) y = miny;
1718         if (!sid->loop_v && ((y - miny) > my)) y = my + miny;
1719      }
1720
1721    psd->api->pos_set(sid->pan_obj, x, y);
1722    psd->api->pos_get(sid->pan_obj, &spx, &spy);
1723
1724    if (mx > 0) vx = (double)(spx - minx) / (double)mx;
1725    else vx = 0.0;
1726
1727    if (vx < 0.0) vx = 0.0;
1728    else if (vx > 1.0)
1729      vx = 1.0;
1730
1731    if (my > 0) vy = (double)(spy - miny) / (double)my;
1732    else vy = 0.0;
1733
1734    if (vy < 0.0) vy = 0.0;
1735    else if (vy > 1.0)
1736      vy = 1.0;
1737
1738    edje_object_part_drag_value_set
1739      (sid->edje_obj, "elm.dragable.vbar", 0.0, vy);
1740    edje_object_part_drag_value_set
1741      (sid->edje_obj, "elm.dragable.hbar", vx, 0.0);
1742
1743    if (!sid->loop_h && !sid->down.bounce_x_animator)
1744      {
1745         if (((x < minx) && (0 <= sid->down.dx)) ||
1746             ((x > (mx + minx)) && (0 >= sid->down.dx)))
1747           {
1748              sid->bouncemex = EINA_TRUE;
1749              _elm_scroll_bounce_eval(sid);
1750           }
1751         else
1752           sid->bouncemex = EINA_FALSE;
1753      }
1754    if (!sid->loop_v && !sid->down.bounce_y_animator)
1755      {
1756         if (((y < miny) && (0 <= sid->down.dy)) ||
1757             ((y > (my + miny)) && (0 >= sid->down.dy)))
1758           {
1759              sid->bouncemey = EINA_TRUE;
1760              _elm_scroll_bounce_eval(sid);
1761           }
1762         else
1763           sid->bouncemey = EINA_FALSE;
1764      }
1765
1766    if (sig)
1767      {
1768         if ((x != px) || (y != py))
1769           {
1770              if (sid->cb_func.scroll)
1771                sid->cb_func.scroll(obj, NULL);
1772              edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
1773              if (x < px)
1774                {
1775                   if (sid->cb_func.scroll_left)
1776                     sid->cb_func.scroll_left(obj, NULL);
1777                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,left", "elm");
1778                }
1779              if (x > px)
1780                {
1781                   if (sid->cb_func.scroll_right)
1782                     sid->cb_func.scroll_right(obj, NULL);
1783                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,right", "elm");
1784                }
1785              if (y < py)
1786                {
1787                   if (sid->cb_func.scroll_up)
1788                     sid->cb_func.scroll_up(obj, NULL);
1789                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,up", "elm");
1790                }
1791              if (y > py)
1792                {
1793                   if (sid->cb_func.scroll_down)
1794                     sid->cb_func.scroll_down(obj, NULL);
1795                   edje_object_signal_emit(sid->edje_obj, "elm,action,scroll,down", "elm");
1796                }
1797                edje_message_signal_process();
1798           }
1799         if (x != px)
1800           {
1801              if (x == minx)
1802                {
1803                   if (sid->cb_func.edge_left)
1804                     sid->cb_func.edge_left(obj, NULL);
1805                }
1806              if (x == (mx + minx))
1807                {
1808                   if (sid->cb_func.edge_right)
1809                     sid->cb_func.edge_right(obj, NULL);
1810                }
1811           }
1812         if (y != py)
1813           {
1814              if (y == miny)
1815                {
1816                   if (sid->cb_func.edge_top)
1817                     sid->cb_func.edge_top(obj, NULL);
1818                }
1819              if (y == my + miny)
1820                {
1821                   if (sid->cb_func.edge_bottom)
1822                     sid->cb_func.edge_bottom(obj, NULL);
1823                }
1824           }
1825      }
1826
1827    _elm_direction_arrows_eval(sid);
1828 }
1829
1830 static void
1831 _elm_scroll_mirrored_set(Evas_Object *obj,
1832                          Eina_Bool mirrored)
1833 {
1834    Evas_Coord wx;
1835
1836    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1837
1838    if (!sid->edje_obj) return;
1839
1840    mirrored = !!mirrored;
1841
1842    if (sid->is_mirrored == mirrored)
1843      return;
1844
1845    sid->is_mirrored = mirrored;
1846    edje_object_mirrored_set(sid->edje_obj, mirrored);
1847
1848    if (sid->is_mirrored)
1849      wx = _elm_scroll_x_mirrored_get(sid->obj, sid->wx);
1850    else
1851      wx = sid->wx;
1852
1853    _elm_scroll_content_pos_set(sid->obj, wx, sid->wy, EINA_FALSE);
1854 }
1855
1856 /* returns TRUE when we need to move the scroller, FALSE otherwise.
1857  * Updates w and h either way, so save them if you need them. */
1858 static Eina_Bool
1859 _elm_scroll_content_region_show_internal(Evas_Object *obj,
1860                                          Evas_Coord *_x,
1861                                          Evas_Coord *_y,
1862                                          Evas_Coord w,
1863                                          Evas_Coord h)
1864 {
1865    Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx = 0, ny = 0,
1866               minx = 0, miny = 0, pw = 0, ph = 0, x = *_x, y = *_y;
1867
1868    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
1869
1870    if (!sid->pan_obj) return EINA_FALSE;
1871
1872    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
1873
1874    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
1875    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
1876    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
1877    psd->api->pos_get(sid->pan_obj, &px, &py);
1878    evas_object_geometry_get(sid->pan_obj, NULL, NULL, &pw, &ph);
1879
1880    nx = px;
1881    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1882    else if ((x > px) && ((x + w) > (px + (cw - mx))))
1883      nx = x + w - (cw - mx);
1884    ny = py;
1885    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1886    else if ((y > py) && ((y + h) > (py + (ch - my))))
1887      ny = y + h - (ch - my);
1888
1889    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
1890        (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
1891      {
1892         if (sid->scrollto.x.animator)
1893           {
1894              ecore_animator_del(sid->scrollto.x.animator);
1895              sid->scrollto.x.animator = NULL;
1896           }
1897         if (sid->scrollto.y.animator)
1898           {
1899              ecore_animator_del(sid->scrollto.y.animator);
1900              sid->scrollto.y.animator = NULL;
1901           }
1902         if (sid->down.bounce_x_animator)
1903           {
1904              ecore_animator_del(sid->down.bounce_x_animator);
1905              sid->down.bounce_x_animator = NULL;
1906              sid->bouncemex = EINA_FALSE;
1907              if (sid->content_info.resized)
1908                _elm_scroll_wanted_region_set(sid->obj);
1909           }
1910         if (sid->down.bounce_y_animator)
1911           {
1912              ecore_animator_del(sid->down.bounce_y_animator);
1913              sid->down.bounce_y_animator = NULL;
1914              sid->bouncemey = EINA_FALSE;
1915              if (sid->content_info.resized)
1916                _elm_scroll_wanted_region_set(sid->obj);
1917           }
1918         _elm_scroll_anim_stop(sid);
1919      }
1920    if (sid->down.hold_animator)
1921      {
1922         ecore_animator_del(sid->down.hold_animator);
1923         sid->down.hold_animator = NULL;
1924         _elm_scroll_drag_stop(sid);
1925         if (sid->content_info.resized)
1926           _elm_scroll_wanted_region_set(sid->obj);
1927      }
1928    if (sid->down.momentum_animator)
1929      {
1930         ecore_animator_del(sid->down.momentum_animator);
1931         sid->down.momentum_animator = NULL;
1932         sid->down.bounce_x_hold = EINA_FALSE;
1933         sid->down.bounce_y_hold = EINA_FALSE;
1934         sid->down.ax = 0;
1935         sid->down.ay = 0;
1936         sid->down.pdx = 0;
1937         sid->down.pdy = 0;
1938         if (sid->content_info.resized)
1939           _elm_scroll_wanted_region_set(sid->obj);
1940      }
1941
1942    if (_paging_is_enabled(sid))
1943      {
1944         x = _elm_scroll_page_x_get(sid, nx - px, EINA_FALSE);
1945         y = _elm_scroll_page_y_get(sid, ny - py, EINA_FALSE);
1946         if ((pw != sid->pagesize_h) && (sid->pagesize_h != 0))
1947           pw = sid->pagesize_h;
1948         if ((ph != sid->pagesize_v) && (sid->pagesize_v != 0))
1949           ph = sid->pagesize_v;
1950      }
1951    else
1952      {
1953         x = nx;
1954         y = ny;
1955      }
1956    if (!sid->loop_h)
1957      {
1958         if ((x + pw) > cw) x = cw - pw;
1959         if (x < minx) x = minx;
1960      }
1961    if (!sid->loop_v)
1962      {
1963        if ((y + ph) > ch) y = ch - ph;
1964        if (y < miny) y = miny;
1965      }
1966
1967    if ((x == px) && (y == py)) return EINA_FALSE;
1968    *_x = x;
1969    *_y = y;
1970
1971    return EINA_TRUE;
1972 }
1973
1974 /* Set should be used for calculated positions, for example, when we move
1975  * because of an animation or because this is the correct position after
1976  * constraints. */
1977 static void
1978 _elm_scroll_content_region_set(Evas_Object *obj,
1979                                Evas_Coord x,
1980                                Evas_Coord y,
1981                                Evas_Coord w,
1982                                Evas_Coord h)
1983 {
1984    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
1985
1986    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
1987      {
1988         _elm_scroll_content_pos_set(obj, x, y, EINA_FALSE);
1989         sid->down.sx = x;
1990         sid->down.sy = y;
1991         sid->down.x = sid->down.history[0].x;
1992         sid->down.y = sid->down.history[0].y;
1993      }
1994 }
1995
1996 /* Set should be used for setting the wanted position, for example a
1997  * user scroll or moving the cursor in an entry. */
1998 static void
1999 _elm_scroll_content_region_show(Evas_Object *obj,
2000                                 Evas_Coord x,
2001                                 Evas_Coord y,
2002                                 Evas_Coord w,
2003                                 Evas_Coord h)
2004 {
2005    Evas_Coord cw = 0, ch = 0;
2006    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
2007
2008    if (sid->pan_obj)
2009      {
2010         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2011         psd->api->content_size_get(sid->pan_obj, &cw, &ch);
2012      }
2013
2014    if (sid->origin_x && cw > 0)
2015      {
2016         sid->wx = cw - y;
2017         if (sid->wx < 0) sid->wx = 0;
2018      }
2019    else
2020      sid->wx = x;
2021
2022    if (sid->origin_y && ch > 0)
2023      {
2024         sid->wy = ch - y;
2025         if (sid->wy < 0) sid->wy = 0;
2026      }
2027    else
2028      sid->wy = y;
2029
2030    sid->ww = w;
2031    sid->wh = h;
2032    if (_paging_is_enabled(sid))
2033      {
2034         if (sid->pagesize_h != 0)
2035           {
2036              x = (int)(x / sid->pagesize_h) * sid->pagesize_h;
2037              if (sid->origin_x && cw > 0)
2038                {
2039                   sid->wx = cw - x;
2040                   if (sid->wx < 0) sid->wx = 0;
2041                }
2042              else
2043                sid->wx = x;
2044              sid->ww = w = sid->pagesize_h;
2045           }
2046         if (sid->pagesize_v != 0)
2047           {
2048              y = (int)(y / sid->pagesize_v) * sid->pagesize_v;
2049              if (sid->origin_y && ch > 0)
2050                {
2051                   sid->wy = ch - y;
2052                   if (sid->wy < 0) sid->wy = 0;
2053                }
2054              else
2055                sid->wy = y;
2056              sid->wh = h = sid->pagesize_v;
2057           }
2058      }
2059
2060    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
2061      {
2062         _elm_scroll_content_pos_set(obj, x, y, EINA_TRUE);
2063         sid->down.sx = x;
2064         sid->down.sy = y;
2065         sid->down.x = sid->down.history[0].x;
2066         sid->down.y = sid->down.history[0].y;
2067      }
2068 }
2069
2070 static void
2071 _elm_scroll_wanted_region_set(Evas_Object *obj)
2072 {
2073    Evas_Coord ww, wh, wx, wy, cw= 0, ch = 0;
2074
2075    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
2076
2077    wx = sid->wx;
2078    wy = sid->wy;
2079
2080    if (sid->down.now || sid->down.momentum_animator ||
2081        sid->down.bounce_x_animator || sid->down.bounce_y_animator ||
2082        sid->down.hold_animator || sid->down.onhold_animator ||
2083        sid->scrollto.x.animator || sid->scrollto.y.animator)
2084      return;
2085
2086    if (sid->pan_obj)
2087      {
2088         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2089         psd->api->content_size_get(sid->pan_obj, &cw, &ch);
2090      }
2091
2092    sid->content_info.resized = EINA_FALSE;
2093
2094    /* Flip to RTL cords only if init in RTL mode */
2095    if (sid->is_mirrored)
2096      wx = _elm_scroll_x_mirrored_get(obj, sid->wx);
2097
2098    if (sid->origin_x && cw > 0)
2099      {
2100         wx = cw - sid->wx;
2101         if (wx < 0) wx = 0;
2102      }
2103
2104    if (sid->origin_y && ch > 0)
2105      {
2106         wy = ch - sid->wy;
2107         if (wy < 0) wy = 0;
2108      }
2109
2110    if (sid->ww == -1)
2111      {
2112         _elm_scroll_content_viewport_size_get(obj, &ww, &wh);
2113      }
2114    else
2115      {
2116         ww = sid->ww;
2117         wh = sid->wh;
2118      }
2119
2120    _elm_scroll_content_region_set(obj, wx, wy, ww, wh);
2121 }
2122
2123 static void
2124 _elm_scroll_wheel_event_cb(void *data,
2125                            Evas *e __UNUSED__,
2126                            Evas_Object *obj __UNUSED__,
2127                            void *event_info)
2128 {
2129    Elm_Scrollable_Smart_Interface_Data *sid;
2130    Evas_Event_Mouse_Wheel *ev;
2131    Evas_Coord x = 0, y = 0, vw = 0, vh = 0, cw = 0, ch = 0;
2132    int direction = 0;
2133    int pagenumber_h, pagenumber_v;
2134
2135    sid = data;
2136    if (!sid->pan_obj) return;
2137    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2138    ev = event_info;
2139    direction = ev->direction;
2140
2141    if (sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL)
2142      return;
2143
2144    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2145    if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
2146        (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
2147        (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
2148        (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
2149        (evas_key_modifier_is_set(ev->modifiers, "Super")))
2150      return;
2151    else if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
2152      direction = !direction;
2153    _elm_scroll_content_pos_get(sid->obj, &x, &y);
2154    if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
2155        (sid->scrollto.x.animator) || (sid->scrollto.y.animator))
2156      {
2157         _elm_scroll_anim_stop(sid);
2158      }
2159    if (sid->scrollto.x.animator)
2160      {
2161         ecore_animator_del(sid->scrollto.x.animator);
2162         sid->scrollto.x.animator = NULL;
2163      }
2164    if (sid->scrollto.y.animator)
2165      {
2166         ecore_animator_del(sid->scrollto.y.animator);
2167         sid->scrollto.y.animator = NULL;
2168      }
2169    if (sid->down.bounce_x_animator)
2170      {
2171         ecore_animator_del(sid->down.bounce_x_animator);
2172         sid->down.bounce_x_animator = NULL;
2173         sid->bouncemex = EINA_FALSE;
2174         if (sid->content_info.resized)
2175           _elm_scroll_wanted_region_set(sid->obj);
2176      }
2177    if (sid->down.bounce_y_animator)
2178      {
2179         ecore_animator_del(sid->down.bounce_y_animator);
2180         sid->down.bounce_y_animator = NULL;
2181         sid->bouncemey = EINA_FALSE;
2182         if (sid->content_info.resized)
2183           _elm_scroll_wanted_region_set(sid->obj);
2184      }
2185    _elm_scroll_content_viewport_size_get(sid->obj, &vw, &vh);
2186    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
2187    if (!_paging_is_enabled(sid))
2188      {
2189         if (!direction)
2190           {
2191              if (ch > vh || cw <= vw)
2192                y += ev->z * sid->step.y;
2193              else
2194                x += ev->z * sid->step.x;
2195           }
2196         else if (direction == 1)
2197           {
2198              if (cw > vw || ch <= vh)
2199                x += ev->z * sid->step.x;
2200              else
2201                y += ev->z * sid->step.y;
2202           }
2203
2204         if ((!sid->hold) && (!sid->freeze))
2205           {
2206              _elm_scroll_wanted_coordinates_update(sid, x, y);
2207              _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
2208           }
2209      }
2210    else
2211      {
2212         _elm_scroll_current_page_get(sid->obj, &pagenumber_h, &pagenumber_v);
2213         if (!direction)
2214           {
2215              if (ch > vh || cw <= vw)
2216                y = (pagenumber_v + (1 * ev->z)) * sid->pagesize_v;
2217              else
2218                x = (pagenumber_h + (1 * ev->z)) * sid->pagesize_h;
2219           }
2220         else if (direction == 1)
2221           {
2222              if (cw > vw || ch <= vh)
2223                x = (pagenumber_h + (1 * ev->z)) * sid->pagesize_h;
2224              else
2225                y = (pagenumber_v + (1 * ev->z)) * sid->pagesize_v;
2226           }
2227
2228         if ((!sid->hold) && (!sid->freeze))
2229           {
2230              //_elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
2231              _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
2232           }
2233      }
2234 }
2235
2236 static Eina_Bool
2237 _elm_scroll_post_event_up(void *data,
2238                           Evas *e __UNUSED__)
2239 {
2240    Elm_Scrollable_Smart_Interface_Data *sid = data;
2241
2242    if (sid->obj)
2243      {
2244         if (sid->down.dragged)
2245           {
2246              elm_widget_drag_lock_x_set(sid->obj, EINA_FALSE);
2247              elm_widget_drag_lock_y_set(sid->obj, EINA_FALSE);
2248           }
2249      }
2250    return EINA_TRUE;
2251 }
2252
2253 static Eina_Bool
2254 _paging_is_enabled(Elm_Scrollable_Smart_Interface_Data *sid)
2255 {
2256    if ((sid->pagerel_h == 0.0) && (!sid->pagesize_h) &&
2257        (sid->pagerel_v == 0.0) && (!sid->pagesize_v))
2258      return EINA_FALSE;
2259    return EINA_TRUE;
2260 }
2261
2262 static Eina_Bool
2263 _elm_scroll_momentum_animator(void *data)
2264 {
2265    double t, at, dt, p, r;
2266    Elm_Scrollable_Smart_Interface_Data *sid = data;
2267    Evas_Coord x, y, dx, dy, px, py, maxx, maxy, minx, miny;
2268    Eina_Bool no_bounce_x_end = EINA_FALSE, no_bounce_y_end = EINA_FALSE;
2269
2270    if (!sid->pan_obj) return ECORE_CALLBACK_CANCEL;
2271
2272    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, ECORE_CALLBACK_CANCEL);
2273
2274    t = ecore_loop_time_get();
2275    dt = t - sid->down.anim_start;
2276    if (dt >= 0.0)
2277      {
2278         r = _elm_config->thumbscroll_min_friction / _elm_config->thumbscroll_friction;
2279         at = (double)sqrt(
2280            (sid->down.dx * sid->down.dx) + (sid->down.dy * sid->down.dy));
2281         at = at < ((1.0 - r) * _elm_config->thumbscroll_friction_standard) ?
2282            at : (1.0 - r) * _elm_config->thumbscroll_friction_standard;
2283         at = ((at / _elm_config->thumbscroll_friction_standard) + r) *
2284            (_elm_config->thumbscroll_friction + sid->down.extra_time);
2285         dt = dt / at;
2286         if (dt > 1.0) dt = 1.0;
2287         p = 1 - powf((1.0) - dt, 3);
2288
2289         if (psd->api->pos_adjust)
2290           {
2291              dx = sid->down.dx * p;
2292              dy = sid->down.dy * p;
2293           }
2294         else
2295           {
2296              dx = (sid->down.dx * (_elm_config->thumbscroll_friction +
2297                       sid->down.extra_time) * p);
2298              dy = (sid->down.dy * (_elm_config->thumbscroll_friction +
2299                       sid->down.extra_time) * p);
2300           }
2301
2302         sid->down.ax = dx;
2303         sid->down.ay = dy;
2304         x = sid->down.sx - dx;
2305         y = sid->down.sy - dy;
2306         _elm_scroll_content_pos_get(sid->obj, &px, &py);
2307         if ((sid->down.bounce_x_animator) ||
2308             (sid->down.bounce_x_hold))
2309           {
2310              sid->down.bx = sid->down.bx0 - dx + sid->down.b0x;
2311              x = px;
2312           }
2313         if ((sid->down.bounce_y_animator) ||
2314             (sid->down.bounce_y_hold))
2315           {
2316              sid->down.by = sid->down.by0 - dy + sid->down.b0y;
2317              y = py;
2318           }
2319         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
2320         _elm_scroll_wanted_coordinates_update(sid, x, y);
2321         psd->api->pos_max_get(sid->pan_obj, &maxx, &maxy);
2322         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
2323         if (!_elm_config->thumbscroll_bounce_enable || !sid->bounce_horiz)
2324           {
2325              if (x <= minx) no_bounce_x_end = EINA_TRUE;
2326              if (!sid->loop_h && (x - minx) >= maxx) no_bounce_x_end = EINA_TRUE;
2327           }
2328         if (!_elm_config->thumbscroll_bounce_enable || !sid->bounce_vert)
2329           {
2330              if (y <= miny) no_bounce_y_end = EINA_TRUE;
2331              if (!sid->loop_v && (y - miny) >= maxy) no_bounce_y_end = EINA_TRUE;
2332           }
2333         if ((dt >= 1.0) ||
2334             ((sid->down.bounce_x_hold) && (sid->down.bounce_y_hold)) ||
2335             (no_bounce_x_end && no_bounce_y_end))
2336           {
2337              _elm_scroll_anim_stop(sid);
2338
2339              sid->down.momentum_animator = NULL;
2340              sid->down.bounce_x_hold = EINA_FALSE;
2341              sid->down.bounce_y_hold = EINA_FALSE;
2342              sid->down.ax = 0;
2343              sid->down.ay = 0;
2344              sid->down.pdx = 0;
2345              sid->down.pdy = 0;
2346              if (sid->content_info.resized)
2347                _elm_scroll_wanted_region_set(sid->obj);
2348
2349              return ECORE_CALLBACK_CANCEL;
2350           }
2351      }
2352
2353    return ECORE_CALLBACK_RENEW;
2354 }
2355
2356 static Evas_Coord
2357 _elm_scroll_page_x_get(Elm_Scrollable_Smart_Interface_Data *sid,
2358                        int offset, Eina_Bool limit)
2359 {
2360    Evas_Coord x, y, w, h, dx, cw, ch, minx = 0;
2361
2362    if (!sid->pan_obj) return 0;
2363
2364    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
2365
2366    _elm_scroll_content_pos_get(sid->obj, &x, &y);
2367    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2368    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
2369    psd->api->pos_min_get(sid->pan_obj, &minx, NULL);
2370
2371    if (sid->pagerel_h > 0.0)
2372      {
2373         if (sid->pagecount_h != 0)
2374           w = cw / (sid->pagecount_h * sid->pagerel_h);
2375         x *= (w * sid->pagerel_h) / sid->pagesize_h;
2376         sid->pagesize_h = w * sid->pagerel_h;
2377      }
2378
2379    if (!limit)
2380      x += offset;
2381    else
2382      {
2383         dx = (sid->pagesize_h * ((double)sid->page_limit_h - 0.5));
2384
2385         if (offset > 0)
2386           x += (abs(offset) < dx ? offset : dx);
2387         else
2388           x += (abs(offset) < dx ? offset : -(dx + 1));
2389      }
2390
2391    if (sid->pagesize_h > 0)
2392      {
2393         if (x >= minx) x = x + (sid->pagesize_h * 0.5);
2394         else x = x - (sid->pagesize_h * 0.5);
2395         x = x / (sid->pagesize_h);
2396         x = x * (sid->pagesize_h);
2397      }
2398    if (!sid->loop_h)
2399      {
2400         if ((x + w) > cw) x = cw - w;
2401         if (x < minx) x = minx;
2402      }
2403
2404    return x;
2405 }
2406
2407 static Evas_Coord
2408 _elm_scroll_page_y_get(Elm_Scrollable_Smart_Interface_Data *sid,
2409                        int offset, Eina_Bool limit)
2410 {
2411    Evas_Coord x, y, w, h, dy, cw, ch, miny = 0;
2412
2413    if (!sid->pan_obj) return 0;
2414
2415    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, 0);
2416
2417    _elm_scroll_content_pos_get(sid->obj, &x, &y);
2418    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2419    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
2420    psd->api->pos_min_get(sid->pan_obj, NULL, &miny);
2421
2422    if (sid->pagerel_v > 0.0)
2423      {
2424         if (sid->pagecount_v != 0)
2425           h = ch / (sid->pagecount_v * sid->pagerel_v);
2426         y *= (h * sid->pagerel_v) / sid->pagesize_v;
2427         sid->pagesize_v = h * sid->pagerel_v;
2428      }
2429    if (!limit)
2430      y += offset;
2431    else
2432      {
2433         dy = (sid->pagesize_v * ((double)sid->page_limit_v - 0.5));
2434
2435         if (offset > 0)
2436           y += (abs(offset) < dy ? offset : dy);
2437         else
2438           y += (abs(offset) < dy ? offset : -(dy + 1));
2439      }
2440
2441    if (sid->pagesize_v > 0)
2442      {
2443         if (y >= miny) y = y + (sid->pagesize_v * 0.5);
2444         else y = y - (sid->pagesize_v * 0.5);
2445         y = y / (sid->pagesize_v);
2446         y = y * (sid->pagesize_v);
2447      }
2448    if (!sid->loop_v)
2449      {
2450         if ((y + h) > ch) y = ch - h;
2451         if (y < miny) y = miny;
2452      }
2453
2454    return y;
2455 }
2456
2457 static Eina_Bool
2458 _elm_scroll_scroll_to_x_animator(void *data)
2459 {
2460    Elm_Scrollable_Smart_Interface_Data *sid = data;
2461    Evas_Coord px, py;
2462    double t, tt;
2463
2464    if (!sid->pan_obj) return ECORE_CALLBACK_CANCEL;
2465
2466    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, ECORE_CALLBACK_CANCEL);
2467
2468    t = ecore_loop_time_get();
2469    tt = (t - sid->scrollto.x.t_start) /
2470      (sid->scrollto.x.t_end - sid->scrollto.x.t_start);
2471    tt = 1.0 - tt;
2472    tt = 1.0 - (tt * tt);
2473    psd->api->pos_get(sid->pan_obj, &px, &py);
2474    px = (sid->scrollto.x.start * (1.0 - tt)) +
2475      (sid->scrollto.x.end * tt);
2476    if (t >= sid->scrollto.x.t_end)
2477      {
2478         px = sid->scrollto.x.end;
2479         _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
2480         sid->down.sx = px;
2481         sid->down.x = sid->down.history[0].x;
2482         _elm_scroll_wanted_coordinates_update(sid, px, py);
2483         sid->scrollto.x.animator = NULL;
2484         if ((!sid->scrollto.y.animator) && (!sid->down.bounce_y_animator))
2485           _elm_scroll_anim_stop(sid);
2486         return ECORE_CALLBACK_CANCEL;
2487      }
2488    _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
2489    _elm_scroll_wanted_coordinates_update(sid, px, py);
2490    return ECORE_CALLBACK_RENEW;
2491 }
2492
2493 static Eina_Bool
2494 _elm_scroll_scroll_to_y_animator(void *data)
2495 {
2496    Elm_Scrollable_Smart_Interface_Data *sid = data;
2497    Evas_Coord px, py;
2498    double t, tt;
2499
2500    if (!sid->pan_obj) return EINA_FALSE;
2501
2502    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
2503
2504    t = ecore_loop_time_get();
2505    tt = (t - sid->scrollto.y.t_start) /
2506      (sid->scrollto.y.t_end - sid->scrollto.y.t_start);
2507    tt = 1.0 - tt;
2508    tt = 1.0 - (tt * tt);
2509    psd->api->pos_get(sid->pan_obj, &px, &py);
2510    py = (sid->scrollto.y.start * (1.0 - tt)) +
2511      (sid->scrollto.y.end * tt);
2512    if (t >= sid->scrollto.y.t_end)
2513      {
2514         py = sid->scrollto.y.end;
2515         _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
2516         sid->down.sy = py;
2517         sid->down.y = sid->down.history[0].y;
2518         _elm_scroll_wanted_coordinates_update(sid, px, py);
2519         sid->scrollto.y.animator = NULL;
2520         if ((!sid->scrollto.x.animator) && (!sid->down.bounce_x_animator))
2521           _elm_scroll_anim_stop(sid);
2522         return ECORE_CALLBACK_CANCEL;
2523      }
2524    _elm_scroll_content_pos_set(sid->obj, px, py, EINA_TRUE);
2525    _elm_scroll_wanted_coordinates_update(sid, px, py);
2526
2527    return ECORE_CALLBACK_RENEW;
2528 }
2529
2530 static void
2531 _elm_scroll_scroll_to_y(Elm_Scrollable_Smart_Interface_Data *sid,
2532                         double t_in,
2533                         Evas_Coord pos_y)
2534 {
2535    Evas_Coord px, py, x, y, w, h;
2536    double t;
2537
2538    if (!sid->pan_obj) return;
2539
2540    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2541
2542    if (sid->freeze) return;
2543    if (t_in <= 0.0)
2544      {
2545         _elm_scroll_content_pos_get(sid->obj, &x, &y);
2546         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2547         y = pos_y;
2548         _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2549         return;
2550      }
2551    t = ecore_loop_time_get();
2552    psd->api->pos_get(sid->pan_obj, &px, &py);
2553    sid->scrollto.y.start = py;
2554    sid->scrollto.y.end = pos_y;
2555    sid->scrollto.y.t_start = t;
2556    sid->scrollto.y.t_end = t + t_in;
2557    if (!sid->scrollto.y.animator)
2558      {
2559         sid->scrollto.y.animator =
2560           ecore_animator_add(_elm_scroll_scroll_to_y_animator, sid);
2561         if (!sid->scrollto.x.animator)
2562           _elm_scroll_anim_start(sid);
2563      }
2564    if (sid->down.bounce_y_animator)
2565      {
2566         ecore_animator_del(sid->down.bounce_y_animator);
2567         sid->down.bounce_y_animator = NULL;
2568         _elm_scroll_momentum_end(sid);
2569         if (sid->content_info.resized)
2570           _elm_scroll_wanted_region_set(sid->obj);
2571      }
2572    sid->bouncemey = EINA_FALSE;
2573 }
2574
2575 static void
2576 _elm_scroll_scroll_to_x(Elm_Scrollable_Smart_Interface_Data *sid,
2577                         double t_in,
2578                         Evas_Coord pos_x)
2579 {
2580    Evas_Coord px, py, x, y, w, h;
2581    double t;
2582
2583    if (!sid->pan_obj) return;
2584
2585    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2586
2587    if (sid->freeze) return;
2588    if (t_in <= 0.0)
2589      {
2590         _elm_scroll_content_pos_get(sid->obj, &x, &y);
2591         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
2592         x = pos_x;
2593         _elm_scroll_content_region_set(sid->obj, x, y, w, h);
2594         return;
2595      }
2596    t = ecore_loop_time_get();
2597    psd->api->pos_get(sid->pan_obj, &px, &py);
2598    sid->scrollto.x.start = px;
2599    sid->scrollto.x.end = pos_x;
2600    sid->scrollto.x.t_start = t;
2601    sid->scrollto.x.t_end = t + t_in;
2602    if (!sid->scrollto.x.animator)
2603      {
2604         sid->scrollto.x.animator =
2605           ecore_animator_add(_elm_scroll_scroll_to_x_animator, sid);
2606         if (!sid->scrollto.y.animator)
2607           _elm_scroll_anim_start(sid);
2608      }
2609    if (sid->down.bounce_x_animator)
2610      {
2611         ecore_animator_del(sid->down.bounce_x_animator);
2612         sid->down.bounce_x_animator = NULL;
2613         _elm_scroll_momentum_end(sid);
2614         if (sid->content_info.resized)
2615           _elm_scroll_wanted_region_set(sid->obj);
2616      }
2617    sid->bouncemex = EINA_FALSE;
2618 }
2619
2620 static void
2621 _elm_scroll_mouse_up_event_cb(void *data,
2622                               Evas *e,
2623                               Evas_Object *obj __UNUSED__,
2624                               void *event_info)
2625 {
2626    Elm_Scrollable_Smart_Interface_Data *sid = data;
2627    Evas_Coord x = 0, y = 0, ox = 0, oy = 0;
2628    Evas_Event_Mouse_Down *ev;
2629
2630    if (!sid->pan_obj) return;
2631
2632    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
2633
2634    if ((sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL) &&
2635        (sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
2636      return;
2637
2638 #ifdef SMOOTHDBG
2639    if (_elm_scroll_smooth_debug) _elm_scroll_smooth_debug_shutdown();
2640 #endif
2641
2642    ev = event_info;
2643    sid->down.hold_parent = EINA_FALSE;
2644    sid->down.dx = 0;
2645    sid->down.dy = 0;
2646    evas_post_event_callback_push(e, _elm_scroll_post_event_up, sid);
2647
2648    //REDWOOD ONLY
2649    edje_object_signal_emit(sid->edje_obj, "elm,state,mouse,up", "elm");
2650
2651    // FIXME: respect elm_widget_scroll_hold_get of parent container
2652    if (!_elm_config->thumbscroll_enable) return;
2653
2654    if (ev->button == 1)
2655      {
2656         if (sid->down.onhold_animator)
2657           {
2658              ecore_animator_del(sid->down.onhold_animator);
2659              sid->down.onhold_animator = NULL;
2660              if (sid->content_info.resized)
2661                _elm_scroll_wanted_region_set(sid->obj);
2662           }
2663         x = ev->canvas.x - sid->down.x;
2664         y = ev->canvas.y - sid->down.y;
2665         if (sid->down.dragged)
2666           {
2667              _elm_scroll_drag_stop(sid);
2668              if ((!sid->hold) && (!sid->freeze))
2669                {
2670                   int i;
2671                   double t, at, dt;
2672                   Evas_Coord ax, ay, dx, dy, vel;
2673
2674 #ifdef EVTIME
2675                   t = ev->timestamp / 1000.0;
2676 #else
2677                   t = ecore_loop_time_get();
2678 #endif
2679
2680                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2681
2682                   ax = ev->canvas.x;
2683                   ay = ev->canvas.y;
2684                   at = 0.0;
2685 #ifdef SCROLLDBG
2686                   DBG("------ %i %i\n", ev->canvas.x, ev->canvas.y);
2687 #endif
2688                   for (i = 0; i < 60; i++)
2689                     {
2690                        dt = t - sid->down.history[i].timestamp;
2691                        if (dt > 0.4) break;
2692 #ifdef SCROLLDBG
2693                        DBG("H: %i %i @ %1.3f\n",
2694                            sid->down.history[i].x,
2695                            sid->down.history[i].y, dt);
2696 #endif
2697                        at += dt;
2698                        ax += sid->down.history[i].x;
2699                        ay += sid->down.history[i].y;
2700                     }
2701                   ax /= (i + 1);
2702                   ay /= (i + 1);
2703                   at /= (i + 1);
2704                   at /= _elm_config->thumbscroll_sensitivity_friction;
2705                   dx = ev->canvas.x - ax;
2706                   dy = ev->canvas.y - ay;
2707                   if (at > 0)
2708                     {
2709                        vel = sqrt((dx * dx) + (dy * dy)) / at;
2710                        if ((_elm_config->thumbscroll_friction > 0.0) &&
2711                            (vel > _elm_config->thumbscroll_momentum_threshold))
2712                          {
2713                             Evas_Coord vw, vh, aw, ah, max_d;
2714                             int minx, miny, mx, my, px, py;
2715                             double tt = 0.0, dtt = 0.0;
2716
2717                             psd->api->pos_min_get
2718                               (sid->pan_obj, &minx, &miny);
2719                             psd->api->pos_max_get(sid->pan_obj, &mx, &my);
2720                             psd->api->pos_get(sid->pan_obj, &px, &py);
2721                             max_d = _elm_config->thumbscroll_flick_distance_tolerance;
2722                             /* TIZEN ONLY */
2723                             /* Original scroller used sin graph for calculating flick distance.
2724                                But calculated flick distance is so long.
2725                                So I divided into two sections. First section use sin grapth divided into 2.
2726                                And second section use original logic.
2727                                As a result, if flicking velocity is slow, flicking distance will be short.
2728                                */
2729                             if (dx > 0)
2730                               {
2731                                  if (dx > max_d) dx = max_d;
2732                                  if (0.4 >= ((sin((M_PI * (double)dx / max_d) - (M_PI / 2)) + 1) / 2))
2733                                    sid->down.dx = ((sin((M_PI * (double)dx / max_d)
2734                                                        - (M_PI / 2)) + 1) / 2) * max_d / at;
2735                                  else
2736                                    sid->down.dx = ((sin((M_PI * (double)dx / max_d)
2737                                                        - (M_PI / 2)) + 1)) * max_d / at;
2738                               }
2739                             else
2740                               {
2741                                  if (dx < -max_d) dx = -max_d;
2742                                  if (-0.4 <= ((sin((M_PI * (double)dx / max_d) + (M_PI / 2)) - 1) / 2))
2743                                    sid->down.dx = ((sin((M_PI * (double)dx / max_d)
2744                                                        + (M_PI / 2)) - 1) / 2) * max_d / at;
2745                                  else
2746                                    sid->down.dx = (sin((M_PI * (double)dx / max_d)
2747                                                        + (M_PI / 2)) - 1) * max_d / at;
2748                               }
2749                             if (dy > 0)
2750                               {
2751                                  if (dy > max_d) dy = max_d;
2752                                  if (0.4 >= ((sin((M_PI * (double)dy / max_d) - (M_PI / 2)) + 1) / 2))
2753                                    sid->down.dy = ((sin((M_PI * (double)dy / max_d)
2754                                                        - (M_PI / 2)) + 1) / 2) * max_d / at;
2755                                  else
2756                                    sid->down.dy = (sin((M_PI * (double)dy / max_d)
2757                                                        - (M_PI / 2)) + 1) * max_d / at;
2758                               }
2759                             else
2760                               {
2761                                  if (dy < -max_d) dy = -max_d;
2762                                  if (-0.4 <= ((sin((M_PI * (double)dy / max_d) + (M_PI / 2)) - 1) / 2))
2763                                    sid->down.dy = ((sin((M_PI * (double)dy / max_d)
2764                                                        + (M_PI / 2)) - 1) / 2) * max_d / at;
2765                                  else
2766                                    sid->down.dy = (sin((M_PI * (double)dy / max_d)
2767                                                        + (M_PI / 2)) - 1) * max_d / at;
2768                               }
2769                             if (((sid->down.dx > 0) && (sid->down.pdx > 0)) ||
2770                                 ((sid->down.dx < 0) && (sid->down.pdx < 0)) ||
2771                                 ((sid->down.dy > 0) && (sid->down.pdy > 0)) ||
2772                                 ((sid->down.dy < 0) && (sid->down.pdy < 0)))
2773                               {
2774                                  tt = ecore_loop_time_get();
2775                                  dtt = tt - sid->down.anim_start;
2776
2777                                  if (dtt < 0.0) dtt = 0.0;
2778                                  else if (dtt >
2779                                           _elm_config->thumbscroll_friction)
2780                                    dtt = _elm_config->thumbscroll_friction;
2781                                  sid->down.extra_time =
2782                                    _elm_config->thumbscroll_friction - dtt;
2783                               }
2784                             else
2785                               sid->down.extra_time = 0.0;
2786
2787                             aw = abs(sid->down.dx);
2788                             _elm_scroll_content_viewport_size_get(sid->obj, &vw, &vh);
2789                             if (aw  > vw * 3)
2790                               {
2791                                  if (sid->down.dx > 0) sid->down.dx = vw * 3;
2792                                  else sid->down.dx = -(vw * 3);
2793                               }
2794                             ah = abs(sid->down.dy);
2795                             if (ah  > vh * 3)
2796                               {
2797                                  if (sid->down.dy > 0) sid->down.dy = vh * 3;
2798                                  else sid->down.dy = -(vh * 3);
2799                               }
2800
2801                             if (psd->api->pos_adjust)
2802                               {
2803                                  Evas_Coord pos_x, pos_y;
2804
2805                                  pos_x = sid->down.dx;
2806                                  pos_y = sid->down.dy;
2807
2808                                  pos_x = _round(pos_x * (_elm_config->thumbscroll_friction +
2809                                                          sid->down.extra_time), 0);
2810                                  pos_y = _round(pos_y * (_elm_config->thumbscroll_friction +
2811                                                          sid->down.extra_time), 0);
2812                                  psd->api->pos_adjust(sid, &pos_x, &pos_y);
2813
2814                                  sid->down.dx = pos_x;
2815                                  sid->down.dy = pos_y;
2816                               }
2817
2818                             sid->down.pdx = sid->down.dx;
2819                             sid->down.pdy = sid->down.dy;
2820                             ox = -sid->down.dx;
2821                             oy = -sid->down.dy;
2822                             if (!_paging_is_enabled(sid))
2823                               {
2824                                  if ((!sid->down.momentum_animator) &&
2825                                      (!sid->momentum_animator_disabled) &&
2826                                      (sid->obj) &&
2827                                      (!elm_widget_drag_child_locked_y_get
2828                                         (sid->obj)))
2829                                    {
2830                                       sid->down.momentum_animator =
2831                                         ecore_animator_add
2832                                           (_elm_scroll_momentum_animator, sid);
2833                                       ev->event_flags |=
2834                                         EVAS_EVENT_FLAG_ON_SCROLL;
2835                                       _elm_scroll_anim_start(sid);
2836                                    }
2837                                  sid->down.anim_start = ecore_loop_time_get();
2838                                  _elm_scroll_content_pos_get(sid->obj, &x, &y);
2839                                  sid->down.sx = x;
2840                                  sid->down.sy = y;
2841                                  sid->down.b0x = 0;
2842                                  sid->down.b0y = 0;
2843                               }
2844                          }
2845                        else
2846                          {
2847                             if (psd->api->pos_adjust)
2848                               {
2849                                  Evas_Coord pos_x = 0, pos_y = 0;
2850                                  Evas_Coord adjust_x, adjust_y;
2851
2852                                  psd->api->pos_adjust(sid, &pos_x, &pos_y);
2853
2854                                  _elm_scroll_content_pos_get(sid->obj, &adjust_x, &adjust_y);
2855                                  pos_y = -pos_y;
2856                                  adjust_y += pos_y;
2857
2858                                  _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, adjust_y);
2859                               }
2860                          }
2861                   }
2862                 else
2863                   {
2864                      if (psd->api->pos_adjust)
2865                        {
2866                           Evas_Coord pos_x = 0, pos_y = 0;
2867                           Evas_Coord adjust_x, adjust_y;
2868
2869                           psd->api->pos_adjust(sid, &pos_x, &pos_y);
2870
2871                           _elm_scroll_content_pos_get(sid->obj, &adjust_x, &adjust_y);
2872                           pos_y = -pos_y;
2873                           adjust_y += pos_y;
2874
2875                           _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, adjust_y);
2876                        }
2877                   }
2878                }
2879              else
2880                {
2881                   sid->down.pdx = 0;
2882                   sid->down.pdy = 0;
2883                }
2884              evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
2885              if (_paging_is_enabled(sid))
2886                {
2887                   Evas_Coord pgx, pgy;
2888
2889                   _elm_scroll_content_pos_get(sid->obj, &x, &y);
2890                   if ((!sid->obj) ||
2891                       (!elm_widget_drag_child_locked_x_get
2892                          (sid->obj)))
2893                     {
2894                        //TIZEN ONLY
2895                        if (sid->down.dir_x && sid->pagesize_h > 0)
2896                          {
2897                             if (ox > 0)
2898                               {
2899                                 if (sid->down.pageflick_h < 0)
2900                                   ox = sid->pagesize_h + sid->down.pageflick_h;
2901                                 else
2902                                   ox = sid->pagesize_h * 0.5;
2903                               }
2904                             else if (ox < 0)
2905                               {
2906                                 if (sid->down.pageflick_h > 0)
2907                                   ox = -(sid->pagesize_h - sid->down.pageflick_h + 1);
2908                                 else
2909                                   ox = -(sid->pagesize_h * 0.5 + 1);
2910                               }
2911                          }
2912                        pgx = _elm_scroll_page_x_get(sid, ox, EINA_TRUE);
2913                        if (pgx != x &&
2914                            !(sid->block &
2915                              ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
2916                          {
2917                             ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2918                             _elm_scroll_scroll_to_x
2919                                (sid, _elm_config->page_scroll_friction, pgx);
2920                          }
2921                     }
2922                   if ((!sid->obj) ||
2923                       (!elm_widget_drag_child_locked_y_get
2924                          (sid->obj)))
2925                     {
2926                        //TIZEN ONLY
2927                        if (sid->down.dir_y && sid->pagesize_v > 0)
2928                          {
2929                             if (oy > 0)
2930                               {
2931                                 if (sid->down.pageflick_v < 0)
2932                                   oy = sid->pagesize_v + sid->down.pageflick_v;
2933                                 else
2934                                   oy = sid->pagesize_v * 0.5;
2935                               }
2936                             else if (oy < 0)
2937                               {
2938                                 if (sid->down.pageflick_v > 0)
2939                                   oy = -(sid->pagesize_v - sid->down.pageflick_v + 1);
2940                                 else
2941                                   oy = -(sid->pagesize_v * 0.5 + 1);
2942                               }
2943                          }
2944                        pgy = _elm_scroll_page_y_get(sid, oy, EINA_TRUE);
2945                        if (pgy != y &&
2946                            !(sid->block &
2947                              ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL))
2948                          {
2949                             ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2950                             _elm_scroll_scroll_to_y
2951                                (sid, _elm_config->page_scroll_friction, pgy);
2952                          }
2953                     }
2954                }
2955           }
2956         else
2957           {
2958              sid->down.pdx = 0;
2959              sid->down.pdy = 0;
2960              if (_paging_is_enabled(sid))
2961                {
2962                   Evas_Coord pgx, pgy;
2963
2964                   _elm_scroll_content_pos_get(sid->obj, &x, &y);
2965                   if ((!sid->obj) ||
2966                       (!elm_widget_drag_child_locked_x_get
2967                          (sid->obj)))
2968                     {
2969                        pgx = _elm_scroll_page_x_get(sid, ox, EINA_TRUE);
2970                        if (pgx != x)
2971                          _elm_scroll_scroll_to_x
2972                            (sid, _elm_config->page_scroll_friction, pgx);
2973                     }
2974                   if ((!sid->obj) ||
2975                       (!elm_widget_drag_child_locked_y_get
2976                          (sid->obj)))
2977                     {
2978                        pgy = _elm_scroll_page_y_get(sid, oy, EINA_TRUE);
2979                        if (pgy != y)
2980                          _elm_scroll_scroll_to_y
2981                            (sid, _elm_config->page_scroll_friction, pgy);
2982                     }
2983                }
2984           }
2985         if (sid->down.hold_animator)
2986           {
2987              ecore_animator_del(sid->down.hold_animator);
2988              sid->down.hold_animator = NULL;
2989              if (sid->content_info.resized)
2990                _elm_scroll_wanted_region_set(sid->obj);
2991           }
2992         if (sid->down.scroll)
2993           {
2994              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2995              sid->down.scroll = EINA_FALSE;
2996           }
2997         if (sid->down.hold)
2998           {
2999              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
3000              sid->down.hold = EINA_FALSE;
3001           }
3002         sid->down.dragged_began = EINA_FALSE;
3003         sid->down.dir_x = EINA_FALSE;
3004         sid->down.dir_y = EINA_FALSE;
3005         sid->down.want_dragged = EINA_FALSE;
3006         sid->down.dragged = EINA_FALSE;
3007         sid->down.now = EINA_FALSE;
3008         _elm_scroll_content_pos_get(sid->obj, &x, &y);
3009         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
3010         _elm_scroll_wanted_coordinates_update(sid, x, y);
3011
3012         if (sid->content_info.resized)
3013           _elm_scroll_wanted_region_set(sid->obj);
3014
3015         if (!_paging_is_enabled(sid))
3016           _elm_scroll_bounce_eval(sid);
3017      }
3018 }
3019
3020 static void
3021 _elm_scroll_mouse_down_event_cb(void *data,
3022                                 Evas *e __UNUSED__,
3023                                 Evas_Object *obj __UNUSED__,
3024                                 void *event_info)
3025 {
3026    Elm_Scrollable_Smart_Interface_Data *sid;
3027    Evas_Event_Mouse_Down *ev;
3028    Evas_Coord x = 0, y = 0;
3029
3030    sid = data;
3031    ev = event_info;
3032
3033 #ifdef SMOOTHDBG
3034    if (getenv("ELS_SCROLLER_SMOOTH_DEBUG")) _elm_scroll_smooth_debug = 1;
3035    if (_elm_scroll_smooth_debug) _elm_scroll_smooth_debug_init();
3036 #endif
3037
3038    if ((sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL) &&
3039        (sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3040      return;
3041
3042    //REDWOOD ONLY
3043    edje_object_signal_emit(sid->edje_obj, "elm,state,mouse,down", "elm");
3044
3045    if (_elm_config->thumbscroll_enable)
3046      {
3047         sid->down.hold = EINA_FALSE;
3048         if ((sid->down.bounce_x_animator) || (sid->down.bounce_y_animator) ||
3049             (sid->down.momentum_animator) || (sid->scrollto.x.animator) ||
3050             (sid->scrollto.y.animator))
3051           {
3052              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL |
3053                EVAS_EVENT_FLAG_ON_HOLD;
3054              sid->down.scroll = EINA_TRUE;
3055              sid->down.hold = EINA_TRUE;
3056              _elm_scroll_anim_stop(sid);
3057           }
3058         if (sid->scrollto.x.animator)
3059           {
3060              ecore_animator_del(sid->scrollto.x.animator);
3061              sid->scrollto.x.animator = NULL;
3062           }
3063         if (sid->scrollto.y.animator)
3064           {
3065              ecore_animator_del(sid->scrollto.y.animator);
3066              sid->scrollto.y.animator = NULL;
3067           }
3068         if (sid->down.bounce_x_animator)
3069           {
3070              ecore_animator_del(sid->down.bounce_x_animator);
3071              sid->down.bounce_x_animator = NULL;
3072              sid->bouncemex = EINA_FALSE;
3073              if (sid->content_info.resized)
3074                _elm_scroll_wanted_region_set(sid->obj);
3075           }
3076         if (sid->down.bounce_y_animator)
3077           {
3078              ecore_animator_del(sid->down.bounce_y_animator);
3079              sid->down.bounce_y_animator = NULL;
3080              sid->bouncemey = EINA_FALSE;
3081              if (sid->content_info.resized)
3082                _elm_scroll_wanted_region_set(sid->obj);
3083           }
3084         if (sid->down.hold_animator)
3085           {
3086              ecore_animator_del(sid->down.hold_animator);
3087              sid->down.hold_animator = NULL;
3088              _elm_scroll_drag_stop(sid);
3089              if (sid->content_info.resized)
3090                _elm_scroll_wanted_region_set(sid->obj);
3091           }
3092         if (sid->down.momentum_animator)
3093           {
3094              ecore_animator_del(sid->down.momentum_animator);
3095              sid->down.momentum_animator = NULL;
3096              sid->down.bounce_x_hold = EINA_FALSE;
3097              sid->down.bounce_y_hold = EINA_FALSE;
3098              sid->down.ax = 0;
3099              sid->down.ay = 0;
3100              if (sid->content_info.resized)
3101                _elm_scroll_wanted_region_set(sid->obj);
3102           }
3103         if (ev->button == 1)
3104           {
3105              if (_paging_is_enabled(sid))
3106                {
3107                   sid->down.pageflick_h = 0;
3108                   sid->down.pageflick_v = 0;
3109                }
3110              sid->down.hist.est_timestamp_diff =
3111                ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
3112              sid->down.hist.tadd = 0.0;
3113              sid->down.hist.dxsum = 0.0;
3114              sid->down.hist.dysum = 0.0;
3115              sid->down.now = EINA_TRUE;
3116              sid->down.dragged = EINA_FALSE;
3117              sid->down.dir_x = EINA_FALSE;
3118              sid->down.dir_y = EINA_FALSE;
3119              sid->down.x = ev->canvas.x;
3120              sid->down.y = ev->canvas.y;
3121              _elm_scroll_content_pos_get(sid->obj, &x, &y);
3122              sid->down.sx = x;
3123              sid->down.sy = y;
3124              sid->down.locked = EINA_FALSE;
3125              memset(&(sid->down.history[0]), 0,
3126                     sizeof(sid->down.history[0]) * ELM_SCROLL_HISTORY_SIZE);
3127 #ifdef EVTIME
3128              sid->down.history[0].timestamp = ev->timestamp / 1000.0;
3129              sid->down.history[0].localtimestamp = ecore_loop_time_get();
3130 #else
3131              sid->down.history[0].timestamp = ecore_loop_time_get();
3132 #endif
3133              sid->down.dragged_began_timestamp = sid->down.history[0].timestamp;
3134              sid->down.history[0].x = ev->canvas.x;
3135              sid->down.history[0].y = ev->canvas.y;
3136           }
3137         sid->down.dragged_began = EINA_FALSE;
3138         sid->down.hold_parent = EINA_FALSE;
3139         sid->down.cancelled = EINA_FALSE;
3140         if (sid->hold || sid->freeze)
3141           sid->down.want_reset = EINA_TRUE;
3142         else
3143           sid->down.want_reset = EINA_FALSE;
3144      }
3145 }
3146
3147 static Eina_Bool
3148 _elm_scroll_can_scroll(Elm_Scrollable_Smart_Interface_Data *sid,
3149                        int dir)
3150 {
3151    Evas_Coord mx = 0, my = 0, px = 0, py = 0, minx = 0, miny = 0;
3152
3153    if (!sid->pan_obj) return EINA_FALSE;
3154
3155    ELM_PAN_DATA_GET_OR_RETURN_VAL(sid->pan_obj, psd, EINA_FALSE);
3156
3157    psd->api->pos_max_get(sid->pan_obj, &mx, &my);
3158    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
3159    psd->api->pos_get(sid->pan_obj, &px, &py);
3160    switch (dir)
3161      {
3162       case LEFT:
3163         if (px > minx) return EINA_TRUE;
3164         break;
3165
3166       case RIGHT:
3167         if ((px - minx) < mx) return EINA_TRUE;
3168         break;
3169
3170       case UP:
3171         if (py > miny) return EINA_TRUE;
3172         break;
3173
3174       case DOWN:
3175         if ((py - miny) < my) return EINA_TRUE;
3176         break;
3177
3178       default:
3179         break;
3180      }
3181    return EINA_FALSE;
3182 }
3183
3184 static Eina_Bool
3185 _elm_scroll_post_event_move(void *data,
3186                             Evas *e __UNUSED__)
3187 {
3188    Elm_Scrollable_Smart_Interface_Data *sid = data;
3189    Eina_Bool horiz, vert;
3190
3191    if (sid->down.want_dragged)
3192      {
3193         int start = 0;
3194
3195         elm_widget_parents_bounce_get(sid->obj, &horiz, &vert);
3196         if (sid->down.hold_parent)
3197           {
3198              if ((sid->down.dir_x) && (horiz || !sid->bounce_horiz) &&
3199                  !_elm_scroll_can_scroll(sid, sid->down.hdir))
3200                {
3201                   sid->down.dir_x = EINA_FALSE;
3202                }
3203              if ((sid->down.dir_y) && (vert || !sid->bounce_vert) &&
3204                  !_elm_scroll_can_scroll(sid, sid->down.vdir))
3205                {
3206                   sid->down.dir_y = EINA_FALSE;
3207                }
3208              sid->down.dragged_began = EINA_TRUE;
3209           }
3210         if (sid->down.dir_x)
3211           {
3212              if ((!sid->obj) ||
3213                  (!elm_widget_drag_child_locked_x_get(sid->obj)))
3214                {
3215                   if (sid->down.dragged_began)
3216                     {
3217                        sid->down.want_dragged = EINA_FALSE;
3218                        sid->down.dragged = EINA_TRUE;
3219                        if (sid->obj)
3220                          {
3221                             elm_widget_drag_lock_x_set(sid->obj, 1);
3222                          }
3223                        start = 1;
3224                     }
3225                }
3226              else
3227                {
3228                   sid->down.dragged_began = EINA_TRUE;
3229                   sid->down.dir_x = EINA_FALSE;
3230                }
3231           }
3232         if (sid->down.dir_y)
3233           {
3234              if ((!sid->obj) ||
3235                  (!elm_widget_drag_child_locked_y_get(sid->obj)))
3236                {
3237                   if (sid->down.dragged_began)
3238                     {
3239                        sid->down.want_dragged = EINA_FALSE;
3240                        sid->down.dragged = EINA_TRUE;
3241                        if (sid->obj)
3242                          {
3243                             elm_widget_drag_lock_y_set
3244                                (sid->obj, EINA_TRUE);
3245                          }
3246                        start = 1;
3247                     }
3248                }
3249              else
3250                {
3251                   sid->down.dragged_began = EINA_TRUE;
3252                   sid->down.dir_y = EINA_FALSE;
3253                }
3254           }
3255         if ((!sid->down.dir_x) && (!sid->down.dir_y))
3256           {
3257              sid->down.cancelled = EINA_TRUE;
3258           }
3259         if (start) _elm_scroll_drag_start(sid);
3260      }
3261
3262    return EINA_TRUE;
3263 }
3264
3265 static void
3266 _elm_scroll_down_coord_eval(Elm_Scrollable_Smart_Interface_Data *sid,
3267                             Evas_Coord *x,
3268                             Evas_Coord *y)
3269 {
3270    Evas_Coord minx, miny;
3271
3272    if (!sid->pan_obj) return;
3273
3274    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3275
3276    if (_paging_is_enabled(sid))
3277      {
3278         sid->down.pageflick_h = *x - sid->down.x;
3279         sid->down.pageflick_v = *y - sid->down.y;
3280      }
3281
3282    if (sid->down.dir_x) *x = sid->down.sx - (*x - sid->down.x);
3283    else *x = sid->down.sx;
3284    if (sid->down.dir_y) *y = sid->down.sy - (*y - sid->down.y);
3285    else *y = sid->down.sy;
3286
3287    if ((sid->down.dir_x) || (sid->down.dir_y))
3288      {
3289         if (!((sid->down.dir_x) && (sid->down.dir_y)))
3290           {
3291              if (sid->down.dir_x) *y = sid->down.locked_y;
3292              else *x = sid->down.locked_x;
3293           }
3294      }
3295
3296    psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
3297
3298    if (!sid->loop_h && *x < minx)
3299      *x += (minx - *x) * _elm_config->thumbscroll_border_friction;
3300    else if (!sid->loop_h && sid->content_info.w <= sid->w)
3301      *x += (sid->down.sx - *x) * _elm_config->thumbscroll_border_friction;
3302    else if (!sid->loop_h && (sid->content_info.w - sid->w + minx) < *x)
3303      *x += (sid->content_info.w - sid->w + minx - *x) *
3304        _elm_config->thumbscroll_border_friction;
3305
3306    if (!sid->loop_v && *y < miny)
3307      *y += (miny - *y) * _elm_config->thumbscroll_border_friction;
3308    else if (!sid->loop_v && sid->content_info.h <= sid->h)
3309      *y += (sid->down.sy - *y) * _elm_config->thumbscroll_border_friction;
3310    else if (!sid->loop_v && (sid->content_info.h - sid->h + miny) < *y)
3311      *y += (sid->content_info.h - sid->h + miny - *y) *
3312        _elm_config->thumbscroll_border_friction;
3313 }
3314
3315 //TIZEN ONLY : for scroll smooth algorithm
3316
3317 #define iround(x) ((x)>=0?(int)((x)+0.5):(int)((x)-0.5))
3318
3319 //> Frequency of move events
3320 #define ELM_MOVE_PER_SECOND (90.75)
3321 //>Time between two subsequent events
3322 #define ELM_MOVE_TIMEOUT (1./ELM_MOVE_PER_SECOND)
3323
3324 //>Quantity of move events in time interval
3325 #define ELM_MOVE_COUNT(t) iround((t)*ELM_MOVE_PER_SECOND)
3326
3327 //>Getting coordinate (x is 0, y is 1) from struct Elm_Scroll_Pos or Elm_Scroll_History_Item.
3328 #define ELM_GET_COORD(p, coord) (*((int *)p + coord))
3329
3330 //>Difference of coordinates of points with indexes ind and ind+inc.
3331 #define ELM_DIFF(p, coord, ind, inc)  (ELM_GET_COORD((p + ind), coord) - ELM_GET_COORD((p + ind + inc), coord))
3332
3333 //>Index in array for calculation of smoothed velocity.
3334 #define ELM_SMOOTH_SPEED_INDEX 9
3335
3336 //>in seconds, includes driver to X time gap
3337 #define EXTRA_PREDIOCTION_TIME (-0.005)
3338
3339 //>Calculating current velocity. In normal situation it is (pos[0].x - pos[ELM_SMOOTH_SPEED_INDEX].x) / (pos[0].t - pos[ELM_SMOOTH_SPEED_INDEX].t).
3340 //>But in situations when: 1. Sign of velocity was changes or 2. The acceleration is of constant sign or 3. There was stop of movement
3341 //>The index ELM_SMOOTH_SPEED_INDEX is replaced by 1.
3342 double _elm_scroll_get_v(Elm_Scroll_Pos *pos, int num, int coord,
3343                          double *dt, int *pdiff, double *padt, Elm_Scroll_Predict *predict)
3344 {
3345    double v = 0;
3346    int nmeasure_idx = (num > ELM_SMOOTH_SPEED_INDEX) ? ELM_SMOOTH_SPEED_INDEX : (num -1);
3347    // a recent input takes higher priority
3348 #if USE_HISTORY_WEIGHT
3349    if (nmeasure_idx >= 2)
3350      *pdiff = (ELM_DIFF(pos, coord, 0, 1) * 2 + ELM_DIFF(pos, coord, 1, 1))/3;
3351    else
3352 #else
3353      *pdiff = ELM_DIFF(pos, coord, 0, 1);
3354 #endif
3355
3356 #if ADJUST_EVENT_TIME
3357    *dt = -ELM_MOVE_TIMEOUT;
3358 #else
3359    if (nmeasure_idx >= 2)
3360        *dt = -(pos[2].t - pos[0].t)/2.;
3361    else
3362        *dt = -(pos[1].t - pos[0].t);
3363 #endif
3364    if (*dt == 0)
3365      *dt = -ELM_MOVE_TIMEOUT;
3366    v = *pdiff / *dt;
3367    predict->k[coord] = 0;
3368    *padt = EXTRA_PREDIOCTION_TIME;
3369
3370    return v;
3371 }
3372
3373 static Eina_Bool _elm_scroll_get_pos(Elm_Scrollable_Smart_Interface_Data *sid,
3374                                      Elm_Scroll_Pos *pos, int num, int *fx, int *fy)
3375 {
3376    double vx = 0, vy = 0, dt = 0, dtx = 0, dty = 0;
3377
3378    if (num < 1)
3379      {
3380         return EINA_FALSE;
3381      }
3382    else if (num == 1)
3383      {
3384         *fx = iround((double)pos[0].x);
3385         *fy = iround((double)pos[0].y);
3386      }
3387    else if (num >= 2)
3388      {
3389         int diffx, diffy;
3390         if (sid->down.dir_y)
3391           vy = _elm_scroll_get_v(pos, num, 1, &dt, &diffy, &dty, &sid->down.predict);
3392         if (sid->down.dir_x)
3393           vx = _elm_scroll_get_v(pos, num, 0, &dt, &diffx, &dtx, &sid->down.predict);
3394      }
3395
3396    if (sid->down.dir_x)
3397      {
3398         *fx = iround((double)pos[0].x - (pos[0].t + dtx) * vx);
3399         // don't go back even though over-run is detected.
3400         if (sid->down.anim_vx_prev && sid->down.anim_vx_prev * vx >= 0)
3401           if (vx == 0 || (vx > 0 && *fx  > sid->down.anim_x_prev) ||
3402               (vx < 0 && *fx  < sid->down.anim_x_prev))
3403             *fx = sid->down.anim_x_prev;
3404      }
3405
3406    if (sid->down.dir_y)
3407      {
3408         *fy = iround((double)pos[0].y - (pos[0].t + dty) * vy);
3409         // don't go back even though over-run is detected.
3410         if (sid->down.anim_vy_prev && sid->down.anim_vy_prev * vy >= 0)
3411           if (vy == 0 || (vy > 0 && *fy  > sid->down.anim_y_prev) ||
3412               (vy < 0 && *fy  < sid->down.anim_y_prev))
3413             *fy = sid->down.anim_y_prev;
3414      }
3415
3416    sid->down.anim_x_prev = *fx;
3417    sid->down.anim_y_prev = *fy;
3418    sid->down.anim_vx_prev = vx;
3419    sid->down.anim_vy_prev = vy;
3420
3421    return EINA_TRUE;
3422 }
3423
3424 #define COMPENSATE_FOR_INITIAL_RENDER_DELAY 0
3425 #define ADJUST_ANIMATOR_TIMING              1
3426 #define SMART_SMOOTH_START                  1
3427 #define HOLD_ANIMATOR_DEBUG_LEVEL1          0
3428 #define HOLD_ANIMATOR_DEBUG_LEVEL2          0
3429 #define HOLD_ANIMATOR_DEBUG_X_AXIS          1
3430 #define USE_LOOP_TIME                       0
3431 #define ADJUST_EVENT_TIME                   0
3432 #define USE_HISTORY_WEIGHT                  0
3433 #define PREDICT_WHEN_PAUSED                 0
3434
3435 static Eina_Bool
3436 _elm_scroll_hold_animator(void *data)
3437 {
3438    Elm_Scrollable_Smart_Interface_Data *sid = data;
3439    Evas_Coord ox = 0, oy = 0, fx = 0, fy = 0, x = 0, y = 0, num = 0;
3440    Evas_Coord fx_coord = 0, fy_coord = 0;
3441    fx = sid->down.hold_x;
3442    fy = sid->down.hold_y;
3443    fx_coord = sid->down.anim_x_coord_prev;
3444    fy_coord = sid->down.anim_y_coord_prev;
3445 #define QUEUE_SIZE 3 /* for event queue size */
3446    Elm_Scroll_Pos pos[QUEUE_SIZE];
3447
3448    double now, now_diff, prev;
3449    double animators_frametime=0, d = 0;
3450    double pos_diff = 0;
3451
3452    Ecore_Animator_Source source;
3453
3454    sid->down.anim_count++;
3455
3456    source = ecore_animator_source_get();
3457
3458    // FIXME: assume server and client have the same "timezone"
3459    // (0 timepoint) for now. this needs to be figured out in advance
3460    // though.
3461 #if USE_LOOP_TIME
3462    now = ecore_loop_time_get();
3463 #else
3464    now = ecore_time_get();
3465 #endif
3466
3467    // init variables for the first animator run
3468    if (sid->down.anim_count == 1)
3469      {
3470         sid->down.anim_t_prev = now;
3471         sid->down.anim_x_coord_prev = fx;
3472         sid->down.anim_y_coord_prev = fy;
3473         fx_coord = fx;
3474         fy_coord = fy;
3475      }
3476    prev = sid->down.anim_t_prev;
3477    now_diff = now - prev;
3478    animators_frametime = ecore_animator_frametime_get();
3479 #if COMPENSATE_FOR_INITIAL_RENDER_DELAY
3480    if (sid->down.anim_count == 1)
3481      {
3482         if (source != ECORE_ANIMATOR_SOURCE_CUSTOM)
3483           sid->down.anim_t_delay = fmod(now, animators_frametime);
3484      }
3485    else
3486 #endif
3487      {
3488         sid->down.anim_t_delay += now_diff - animators_frametime;
3489      }
3490
3491    // skip this turn if specified.
3492    if (sid->down.anim_skip > 0)
3493      {
3494         sid->down.anim_skip--;
3495 #if HOLD_ANIMATOR_DEBUG_LEVEL1
3496         DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev: %.4f skip(%d)\n",
3497             sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
3498             now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
3499             now_diff*1000,
3500             (now_diff - d)*1000,
3501             d*1000,
3502             sid->down.history[0].timestamp,
3503             sid->down.anim_skip);
3504 #endif
3505             if ((now_diff * 1000) > 18)
3506               {
3507 #if ADJUST_ANIMATOR_TIMING
3508                  sid->down.anim_t_dont_adjust = 1;
3509 #endif
3510                  goto update_time_and_quit;
3511               }
3512      }
3513
3514    // We don't need to process old events again.
3515    if (sid->down.anim_count != 1 &&
3516            sid->down.anim_pos_t_prev == sid->down.history[0].timestamp)
3517      {
3518 #if HOLD_ANIMATOR_DEBUG_LEVEL1
3519         DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev:%.4f skip(%d) no events.\n",
3520             sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
3521             now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
3522             now_diff*1000,
3523             (now_diff - d)*1000,
3524             d*1000,
3525             sid->down.history[0].timestamp,
3526             sid->down.anim_skip);
3527 #endif
3528
3529         goto update_time_and_quit;
3530    }
3531
3532 #if ADJUST_ANIMATOR_TIMING
3533    if (sid->down.anim_count != 1 && !sid->down.anim_t_dont_adjust)
3534      {
3535         if (now_diff < animators_frametime*3/4)
3536           {
3537              d += animators_frametime/4;
3538           }
3539         else if (now_diff < animators_frametime)
3540           {
3541              d = animators_frametime - now_diff;
3542           }
3543         else if (now_diff < animators_frametime*5/4)
3544           {
3545              d = -(now_diff - animators_frametime);
3546           }
3547         else
3548           {
3549              d = -animators_frametime/4;
3550           }
3551
3552         now += d;
3553         now_diff +=d;
3554         sid->down.anim_t_adjusted += d;
3555      }
3556
3557    sid->down.anim_t_dont_adjust = 0;
3558
3559 #endif
3560
3561 #if COMPENSATE_FOR_INITIAL_RENDER_DELAY
3562    // in case the first animator is called manually to make up for gpu's wake-up time,
3563    // then the second animator should be skipped.
3564    if ((sid->down.anim_count == 1) && (sid->down.anim_skip <= 0))
3565      sid->down.anim_skip++;
3566 #endif
3567
3568    if ((!sid->hold) && (!sid->freeze) &&
3569        _elm_config->scroll_smooth_time_interval > 0.0)
3570      {
3571         int i = 0;
3572         int ncur_diff_x=0, ncur_diff_y=0;
3573         int nprev_diff_x=0, nprev_diff_y=0;
3574
3575         for (i = 0; i < QUEUE_SIZE; i++)
3576           {
3577              if (sid->down.history[i].timestamp >=
3578                  sid->down.dragged_began_timestamp)
3579                {
3580                   x = sid->down.history[i].x;
3581                   y = sid->down.history[i].y;
3582
3583                   //if there is no history value, we don't deal with it if
3584                   //there is better wat to know existance of history value
3585                   //, I will modify this code to it
3586                   if ((x == 0) && (y == 0))
3587                     {
3588                        break;
3589                     }
3590
3591                   pos[i].x = x;
3592                   pos[i].y = y;
3593                   pos[i].t = now - sid->down.history[i].timestamp;
3594                   num++;
3595
3596                   if (num <= 1)
3597                       continue;
3598
3599                   // get rid of histories with different move direction.
3600                   if (sid->down.dir_x)
3601                     ncur_diff_x = pos[i].x - pos[i-1].x;
3602                   if (sid->down.dir_y)
3603                     ncur_diff_y = pos[i].y - pos[i-1].y;
3604
3605                   if (ncur_diff_x * nprev_diff_x < 0 || ncur_diff_y * nprev_diff_y < 0)
3606                     {
3607                        num--;
3608 #if HOLD_ANIMATOR_DEBUG_LEVEL2
3609                        DBG("[%03d] i=%d a dir change detected. stopped.\n",
3610                            sid->down.anim_count, i);
3611 #endif
3612                        break;
3613                     }
3614
3615                   nprev_diff_x = ncur_diff_x;
3616                   nprev_diff_y = ncur_diff_y;
3617
3618 #if ADJUST_EVENT_TIME
3619                   //> a event is delayed??
3620                   if (ELM_MOVE_COUNT(pos[i].t - pos[i-1].t) <= 0)
3621                     {
3622                        DBG("[%03d] i=%d a event is delayed (%f) ??????????????????\n",
3623                            sid->down.anim_count,
3624                            i, pos[i].t - pos[i-1].t);
3625                     }
3626
3627                   //> a pause in movement detected
3628                   if (ELM_MOVE_COUNT(pos[i].t - pos[i-1].t) >= 2)
3629                     {
3630 #if HOLD_ANIMATOR_DEBUG_LEVEL2
3631                        DBG("[%03d] i=%d a pause(%f) in movement detected. stopped.\n",
3632                            sid->down.anim_count, i, pos[i].t - pos[i-1].t);
3633 #endif
3634 #if PREDICT_WHEN_PAUSED
3635                        pos[i].t = pos[i-1].t + ELM_MOVE_TIMEOUT;
3636 #else
3637                        num--;
3638 #endif
3639                        break;
3640                     }
3641 #endif
3642                }
3643           }
3644
3645 #if ADJUST_EVENT_TIME
3646         // X server fills in time in milisecond order and it rounds off.
3647         // let's makt it more precise and this is proven by machine moving at constant speed.
3648         if (num >= 2)
3649           {
3650              double tmp = sid->down.history[0].timestamp;
3651              for (i = num - 1; i >= 1; i--)
3652                {
3653                   pos[i-1].t = pos[i].t - ELM_MOVE_TIMEOUT;
3654                   sid->down.history[i-1].timestamp = now - pos[i-1].t;
3655                }
3656              pos_diff = sid->down.history[0].timestamp - tmp;
3657           }
3658
3659 #endif
3660         sid->down.anim_pos_t_prev = sid->down.history[0].timestamp;
3661
3662         //TIZEN ONLY : for scroll smooth algorithm
3663         _elm_scroll_get_pos(sid, pos, num, &fx, &fy);
3664
3665         fx_coord = fx;
3666         fy_coord = fy;
3667         _elm_scroll_down_coord_eval(sid, &fx_coord, &fy_coord);
3668
3669      }
3670
3671    _elm_scroll_content_pos_get(sid->obj, &ox, &oy);
3672    if (sid->down.dir_x)
3673      {
3674         if ((!sid->obj) ||
3675             (!elm_widget_drag_child_locked_x_get(sid->obj)))
3676           ox = fx_coord;
3677      }
3678    if (sid->down.dir_y)
3679      {
3680         if ((!sid->obj) ||
3681             (!elm_widget_drag_child_locked_y_get(sid->obj)))
3682           oy = fy_coord;
3683      }
3684
3685 #ifdef SMOOTHDBG
3686    if (_elm_scroll_smooth_debug)
3687      _elm_scroll_smooth_debug_movetime_add(ox, oy);
3688 #endif
3689
3690    _elm_scroll_content_pos_set(sid->obj, ox, oy, EINA_TRUE);
3691
3692 #if HOLD_ANIMATOR_DEBUG_LEVEL1
3693 #if HOLD_ANIMATOR_DEBUG_X_AXIS
3694    DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev:%02d %3.4f/%+.3f p:%d(%d) = %d%+d %d %d\n",
3695        sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
3696        now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
3697        now_diff*1000,
3698        (now_diff - d)*1000,
3699        d*1000,
3700        num, sid->down.history[0].timestamp, pos_diff*1000,
3701        ox, fx,
3702        sid->down.hold_x, ox - sid->down.hold_x,
3703        ox - sid->down.anim_x_coord_prev,
3704        (int)sid->down.anim_vx_prev);
3705 #else
3706    DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev:%02d %3.4f/%+.3f p:%d(%d) = %d%+d %d %d\n",
3707        sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
3708        now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
3709        now_diff*1000,
3710        (now_diff - d)*1000,
3711        d*1000,
3712        num, sid->down.history[0].timestamp, pos_diff*1000,
3713        oy, fy,
3714        sid->down.hold_y, oy - sid->down.hold_y,
3715        oy - sid->down.anim_y_coord_prev,
3716        (int)sid->down.anim_vy_prev);
3717 #endif
3718 #endif
3719
3720    sid->down.anim_x_coord_prev = ox;
3721    sid->down.anim_y_coord_prev = oy;
3722
3723 update_time_and_quit:
3724    sid->down.anim_t_prev = now;
3725
3726    return ECORE_CALLBACK_RENEW;
3727 }
3728
3729 static Eina_Bool
3730 _elm_scroll_on_hold_animator(void *data)
3731 {
3732    double t, td;
3733    double vx, vy;
3734    Evas_Coord x, y, ox, oy;
3735    Elm_Scrollable_Smart_Interface_Data *sid;
3736
3737    sid = data;
3738    t = ecore_loop_time_get();
3739    if (sid->down.onhold_tlast > 0.0)
3740      {
3741         td = t - sid->down.onhold_tlast;
3742         vx = sid->down.onhold_vx * td *
3743           (double)_elm_config->thumbscroll_hold_threshold * 2.0;
3744         vy = sid->down.onhold_vy * td *
3745           (double)_elm_config->thumbscroll_hold_threshold * 2.0;
3746         _elm_scroll_content_pos_get(sid->obj, &ox, &oy);
3747         x = ox;
3748         y = oy;
3749
3750         if (sid->down.dir_x)
3751           {
3752              if ((!sid->obj) ||
3753                  (!elm_widget_drag_child_locked_x_get(sid->obj)))
3754                {
3755                   sid->down.onhold_vxe += vx;
3756                   x = ox + (int)sid->down.onhold_vxe;
3757                   sid->down.onhold_vxe -= (int)sid->down.onhold_vxe;
3758                }
3759           }
3760
3761         if (sid->down.dir_y)
3762           {
3763              if ((!sid->obj) ||
3764                  (!elm_widget_drag_child_locked_y_get(sid->obj)))
3765                {
3766                   sid->down.onhold_vye += vy;
3767                   y = oy + (int)sid->down.onhold_vye;
3768                   sid->down.onhold_vye -= (int)sid->down.onhold_vye;
3769                }
3770           }
3771
3772         _elm_scroll_content_pos_set(sid->obj, x, y, EINA_TRUE);
3773      }
3774    sid->down.onhold_tlast = t;
3775
3776    return ECORE_CALLBACK_RENEW;
3777 }
3778
3779 static void
3780 _elm_scroll_mouse_move_event_cb(void *data,
3781                                 Evas *e,
3782                                 Evas_Object *obj __UNUSED__,
3783                                 void *event_info)
3784 {
3785    Elm_Scrollable_Smart_Interface_Data *sid = data;
3786    Evas_Event_Mouse_Move *ev;
3787    Evas_Coord x = 0, y = 0;
3788
3789    if (!sid->pan_obj) return;
3790
3791    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
3792
3793    if ((sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL) &&
3794        (sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3795      return;
3796
3797    ev = event_info;
3798    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
3799      sid->down.hold_parent = EINA_TRUE;
3800    evas_post_event_callback_push(e, _elm_scroll_post_event_move, sid);
3801
3802    // FIXME: respect elm_widget_scroll_hold_get of parent container
3803    if (_elm_config->thumbscroll_enable)
3804      {
3805         if (sid->down.now)
3806           {
3807              //REDWOOD ONLY
3808              edje_object_signal_emit(sid->edje_obj, "elm,state,mouse,move", "elm");
3809
3810              if ((sid->scrollto.x.animator) && (!sid->hold) && (!sid->freeze) &&
3811                  !(sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3812                {
3813                   Evas_Coord px;
3814                   ecore_animator_del(sid->scrollto.x.animator);
3815                   sid->scrollto.x.animator = NULL;
3816                   psd->api->pos_get(sid->pan_obj, &px, NULL);
3817                   sid->down.sx = px;
3818                   sid->down.x = sid->down.history[0].x;
3819                }
3820
3821              if ((sid->scrollto.y.animator) && (!sid->hold) && (!sid->freeze) &&
3822                  !(sid->block & ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL))
3823                {
3824                   Evas_Coord py;
3825                   ecore_animator_del(sid->scrollto.y.animator);
3826                   sid->scrollto.y.animator = NULL;
3827                   psd->api->pos_get(sid->pan_obj, NULL, &py);
3828                   sid->down.sy = py;
3829                   sid->down.y = sid->down.history[0].y;
3830                }
3831
3832 #ifdef SCROLLDBG
3833              DBG("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
3834 #endif
3835              memmove(&(sid->down.history[1]), &(sid->down.history[0]),
3836                      sizeof(sid->down.history[0]) * (ELM_SCROLL_HISTORY_SIZE - 1));
3837 #ifdef EVTIME
3838              sid->down.history[0].timestamp = ev->timestamp / 1000.0;
3839              sid->down.history[0].localtimestamp = ecore_loop_time_get();
3840 #else
3841              sid->down.history[0].timestamp = ecore_loop_time_get();
3842 #endif
3843              sid->down.history[0].x = ev->cur.canvas.x;
3844              sid->down.history[0].y = ev->cur.canvas.y;
3845
3846              if (!sid->down.dragged_began)
3847                {
3848                   x = ev->cur.canvas.x - sid->down.x;
3849                   y = ev->cur.canvas.y - sid->down.y;
3850
3851                   if (sid->one_direction_at_a_time == ELM_SCROLLER_SINGLE_DIRECTION_HARD)
3852                     {
3853                        if (abs(x) <_elm_scroll_gradient_check_pixel && abs(y) <_elm_scroll_gradient_check_pixel)
3854                          {
3855                             return;
3856                          }
3857                     }
3858
3859                   sid->down.hdir = -1;
3860                   sid->down.vdir = -1;
3861
3862                   if (x > 0) sid->down.hdir = LEFT;
3863                   else if (x < 0)
3864                     sid->down.hdir = RIGHT;
3865                   if (y > 0) sid->down.vdir = UP;
3866                   else if (y < 0)
3867                     sid->down.vdir = DOWN;
3868
3869                   if (x < 0) x = -x;
3870                   if (y < 0) y = -y;
3871
3872                   if (sid->one_direction_at_a_time)
3873                     {
3874                        if (((x * x) + (y * y)) >
3875                             (_elm_config->thumbscroll_threshold *
3876                              _elm_config->thumbscroll_threshold))
3877                          {
3878                             if (sid->one_direction_at_a_time ==
3879                                 ELM_SCROLLER_SINGLE_DIRECTION_SOFT)
3880                               {
3881                                  int dodir = 0;
3882                                  if (x > (y * 2))
3883                                    {
3884                                       if (!(sid->block &
3885                                             ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3886                                         {
3887                                            sid->down.dir_x = EINA_TRUE;
3888                                         }
3889                                       sid->down.dir_y = EINA_FALSE;
3890                                       dodir++;
3891                                    }
3892                                  if (y > (x * 2))
3893                                    {
3894                                       sid->down.dir_x = EINA_FALSE;
3895                                       if (!(sid->block &
3896                                             ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL))
3897                                         {
3898                                            sid->down.dir_y = EINA_TRUE;
3899                                         }
3900                                       dodir++;
3901                                    }
3902                                  if (!dodir)
3903                                    {
3904                                       if (!(sid->block &
3905                                             ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3906                                         {
3907                                            sid->down.dir_x = EINA_TRUE;
3908                                         }
3909                                       if (!(sid->block &
3910                                             ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL))
3911                                         {
3912                                            sid->down.dir_y = EINA_TRUE;
3913                                         }
3914                                    }
3915                               }
3916                             else if (sid->one_direction_at_a_time ==
3917                                      ELM_SCROLLER_SINGLE_DIRECTION_HARD)
3918                               {
3919                                  if (x > y*2)
3920                                    {
3921                                       if (!(sid->block &
3922                                             ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3923                                         {
3924                                            sid->down.dir_x = EINA_TRUE;
3925                                         }
3926                                       sid->down.dir_y = EINA_FALSE;
3927                                    }
3928                                    else
3929                                  //if (y > x)
3930                                    {
3931                                       sid->down.dir_x = EINA_FALSE;
3932                                       if (!(sid->block &
3933                                             ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL))
3934                                         {
3935                                            sid->down.dir_y = EINA_TRUE;
3936                                         }
3937                                    }
3938                               }
3939                          }
3940                     }
3941                   else
3942                     {
3943                        if (!(sid->block &
3944                              ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL))
3945                          {
3946                             sid->down.dir_x = EINA_TRUE;
3947                          }
3948                        if (!(sid->block &
3949                              ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL))
3950                          {
3951                             sid->down.dir_y = EINA_TRUE;
3952                          }
3953                     }
3954                }
3955              if ((!sid->hold) && (!sid->freeze))
3956                {
3957                   if ((sid->down.dragged) ||
3958                       (((x * x) + (y * y)) >
3959                        (_elm_config->thumbscroll_threshold *
3960                         _elm_config->thumbscroll_threshold)))
3961                     {
3962                        if (!sid->down.dragged_began &&
3963                            _elm_config->scroll_smooth_start_enable)
3964                          {
3965 #if SMART_SMOOTH_START
3966                             int i = 0;
3967                             for (i = 0 ; i < 5 ; i++)
3968                               if (!sid->down.history[i].timestamp)
3969                                 break;
3970                             if (i > 0)
3971                               {
3972                                  i--;
3973                                  DBG("smooth-start(-%d): %d->%d->%d->%d->%d->%d\n",
3974                                      i,
3975                                      sid->down.history[0].x,
3976                                      sid->down.history[1].x,
3977                                      sid->down.history[2].x,
3978                                      sid->down.history[3].x,
3979                                      sid->down.history[4].x,
3980                                      sid->down.x);
3981                                  sid->down.x = sid->down.history[i].x;
3982                                  sid->down.y = sid->down.history[i].y;
3983                                  sid->down.dragged_began_timestamp = sid->down.history[i].timestamp;
3984
3985                               }
3986 #else
3987                             sid->down.x = ev->cur.canvas.x;
3988                             sid->down.y = ev->cur.canvas.y;
3989 #ifdef EVTIME
3990                             sid->down.dragged_began_timestamp =
3991                                ev->timestamp / 1000.0;
3992 #else
3993                             sid->down.dragged_began_timestamp =
3994                                ecore_loop_time_get();
3995 #endif
3996 #endif
3997                          }
3998
3999                        if (!sid->down.dragged)
4000                          {
4001                             sid->down.want_dragged = EINA_TRUE;
4002                          }
4003                        //***************** TIZEN Only
4004                        if ((((_elm_scroll_can_scroll(sid, LEFT) || _elm_scroll_can_scroll(sid, RIGHT)) && sid->down.dir_x) ||
4005                             ((_elm_scroll_can_scroll(sid, UP) || _elm_scroll_can_scroll(sid, DOWN)) && sid->down.dir_y)) &&
4006                            !sid->down.dragged_began)
4007                          {
4008                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
4009                             sid->down.dragged_began = EINA_TRUE;
4010                          }
4011                        else if (sid->down.dragged_began)
4012                          {
4013                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
4014                          }
4015                        //****************************
4016                        if (sid->down.dir_x)
4017                          x = sid->down.sx - (ev->cur.canvas.x - sid->down.x);
4018                        else
4019                          x = sid->down.sx;
4020                        if (sid->down.dir_y)
4021                          y = sid->down.sy - (ev->cur.canvas.y - sid->down.y);
4022                        else
4023                          y = sid->down.sy;
4024                        if (sid->down.want_reset)
4025                          {
4026                             sid->down.x = ev->cur.canvas.x;
4027                             sid->down.y = ev->cur.canvas.y;
4028                             sid->down.want_reset = EINA_FALSE;
4029                          }
4030                        if ((sid->down.dir_x) || (sid->down.dir_y))
4031                          {
4032                             if (!sid->down.locked)
4033                               {
4034                                  sid->down.locked_x = x;
4035                                  sid->down.locked_y = y;
4036                                  sid->down.locked = EINA_TRUE;
4037                               }
4038                             if (!((sid->down.dir_x) && (sid->down.dir_y)))
4039                               {
4040                                  if (sid->down.dir_x) y = sid->down.locked_y;
4041                                  else x = sid->down.locked_x;
4042                               }
4043                          }
4044                        {
4045                           Evas_Coord minx, miny, mx, my;
4046
4047                           psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
4048                           psd->api->pos_max_get(sid->pan_obj, &mx, &my);
4049                           if (!sid->loop_v && y < miny)
4050                             y += (miny - y) *
4051                               _elm_config->thumbscroll_border_friction;
4052                           else if (!sid->loop_v && my <= 0)
4053                             y += (sid->down.sy - y) *
4054                               _elm_config->thumbscroll_border_friction;
4055                           else if (!sid->loop_v && (my + miny) < y)
4056                             y += (my + miny - y) *
4057                               _elm_config->thumbscroll_border_friction;
4058                           if (!sid->loop_h && x < minx)
4059                             x += (minx - x) *
4060                               _elm_config->thumbscroll_border_friction;
4061                           else if (!sid->loop_h && mx <= 0)
4062                             x += (sid->down.sx - x) *
4063                               _elm_config->thumbscroll_border_friction;
4064                           else if (!sid->loop_h && (mx + minx) < x)
4065                             x += (mx + minx - x) *
4066                               _elm_config->thumbscroll_border_friction;
4067                        }
4068
4069                        sid->down.hold_x = x;
4070                        sid->down.hold_y = y;
4071                        if (!sid->down.hold_animator)
4072                          {
4073                             sid->down.hold_animator =
4074                                ecore_animator_add(_elm_scroll_hold_animator, sid);
4075                             sid->down.anim_x_prev = 0;
4076                             sid->down.anim_y_prev = 0;
4077                             sid->down.anim_vx_prev = 0;
4078                             sid->down.anim_vy_prev = 0;
4079                             sid->down.anim_t_prev = 0;
4080                             sid->down.anim_x_coord_prev = 0;
4081                             sid->down.anim_y_coord_prev = 0;
4082                             sid->down.anim_count = 0;
4083                             sid->down.anim_skip = 0;
4084                             sid->down.anim_t_dont_adjust = 0;
4085                             sid->down.anim_t_delay = 0;
4086                             sid->down.anim_t_adjusted = 0;
4087                             sid->down.anim_pos_t_prev = 0;
4088                             memset(&sid->down.predict, 0 , sizeof(sid->down.predict));
4089                          }
4090                     }
4091                   else
4092                     {
4093                        if (sid->down.dragged_began)
4094                          {
4095                             //***************** TIZEN Only
4096                             if ((_elm_scroll_can_scroll(sid, sid->down.hdir) && sid->down.dir_x) ||
4097                                 (_elm_scroll_can_scroll(sid, sid->down.vdir) && sid->down.dir_y))
4098                               {
4099                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
4100                               }
4101                             //****************************
4102                             if (!sid->down.hold)
4103                               {
4104                                  sid->down.hold = EINA_TRUE;
4105                                  evas_event_feed_hold
4106                                    (e, 1, ev->timestamp, ev->data);
4107                               }
4108                          }
4109                     }
4110                }
4111              else if (!sid->freeze)
4112                {
4113                   double vx = 0.0, vy = 0.0;
4114
4115                   x = ev->cur.canvas.x - sid->x;
4116                   y = ev->cur.canvas.y - sid->y;
4117                   if (x < _elm_config->thumbscroll_hold_threshold)
4118                     {
4119                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
4120                          vx = -(double)(_elm_config->thumbscroll_hold_threshold - x)
4121                            / _elm_config->thumbscroll_hold_threshold;
4122                        else
4123                          vx = -1.0;
4124                     }
4125                   else if (x > (sid->w - _elm_config->thumbscroll_hold_threshold))
4126                     {
4127                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
4128                          vx = (double)(_elm_config->thumbscroll_hold_threshold -
4129                                        (sid->w - x)) /
4130                            _elm_config->thumbscroll_hold_threshold;
4131                        else
4132                          vx = 1.0;
4133                     }
4134                   if (y < _elm_config->thumbscroll_hold_threshold)
4135                     {
4136                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
4137                          vy = -(double)(_elm_config->thumbscroll_hold_threshold - y)
4138                            / _elm_config->thumbscroll_hold_threshold;
4139                        else
4140                          vy = -1.0;
4141                     }
4142                   else if (y > (sid->h - _elm_config->thumbscroll_hold_threshold))
4143                     {
4144                        if (_elm_config->thumbscroll_hold_threshold > 0.0)
4145                          vy = (double)(_elm_config->thumbscroll_hold_threshold -
4146                                        (sid->h - y)) /
4147                            _elm_config->thumbscroll_hold_threshold;
4148                        else
4149                          vy = 1.0;
4150                     }
4151                   if ((vx != 0.0) || (vy != 0.0))
4152                     {
4153                        sid->down.onhold_vx = vx;
4154                        sid->down.onhold_vy = vy;
4155                        if (!sid->down.onhold_animator)
4156                          {
4157                             sid->down.onhold_vxe = 0.0;
4158                             sid->down.onhold_vye = 0.0;
4159                             sid->down.onhold_tlast = 0.0;
4160                             sid->down.onhold_animator = ecore_animator_add
4161                                (_elm_scroll_on_hold_animator, sid);
4162                          }
4163                     }
4164                   else
4165                     {
4166                        if (sid->down.onhold_animator)
4167                          {
4168                             ecore_animator_del(sid->down.onhold_animator);
4169                             sid->down.onhold_animator = NULL;
4170                             if (sid->content_info.resized)
4171                               _elm_scroll_wanted_region_set(sid->obj);
4172                          }
4173                     }
4174                }
4175           }
4176      }
4177 }
4178
4179 static void
4180 _elm_scroll_reconfigure(Elm_Scrollable_Smart_Interface_Data *sid)
4181 {
4182    _elm_scroll_scroll_bar_size_adjust(sid);
4183 }
4184
4185 static void
4186 _on_edje_move(void *data,
4187               Evas *e __UNUSED__,
4188               Evas_Object *edje_obj,
4189               void *event_info __UNUSED__)
4190 {
4191    Elm_Scrollable_Smart_Interface_Data *sid = data;
4192    int x, y;
4193
4194    evas_object_geometry_get(edje_obj, &x, &y, NULL, NULL);
4195
4196    sid->x = x;
4197    sid->y = y;
4198
4199    _elm_scroll_reconfigure(sid);
4200 }
4201
4202 static void
4203 _on_edje_resize(void *data,
4204                 Evas *e __UNUSED__,
4205                 Evas_Object *edje_obj,
4206                 void *event_info __UNUSED__)
4207 {
4208    Elm_Scrollable_Smart_Interface_Data *sid = data;
4209    int w, h;
4210
4211    evas_object_geometry_get(edje_obj, NULL, NULL, &w, &h);
4212
4213    sid->w = w;
4214    sid->h = h;
4215
4216    _elm_scroll_reconfigure(sid);
4217    _elm_scroll_wanted_region_set(sid->obj);
4218 }
4219
4220 static void
4221 _scroll_edje_object_attach(Evas_Object *obj)
4222 {
4223    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4224
4225    evas_object_event_callback_add
4226      (sid->edje_obj, EVAS_CALLBACK_RESIZE, _on_edje_resize, sid);
4227    evas_object_event_callback_add
4228      (sid->edje_obj, EVAS_CALLBACK_MOVE, _on_edje_move, sid);
4229
4230    edje_object_signal_callback_add
4231      (sid->edje_obj, "reload", "elm", _elm_scroll_reload_cb, sid);
4232    edje_object_signal_callback_add
4233      (sid->edje_obj, "drag", "elm.dragable.vbar", _elm_scroll_vbar_drag_cb,
4234      sid);
4235    edje_object_signal_callback_add
4236      (sid->edje_obj, "drag,set", "elm.dragable.vbar",
4237      _elm_scroll_edje_drag_v_cb, sid);
4238    edje_object_signal_callback_add
4239      (sid->edje_obj, "drag,start", "elm.dragable.vbar",
4240      _elm_scroll_edje_drag_v_start_cb, sid);
4241    edje_object_signal_callback_add
4242      (sid->edje_obj, "drag,stop", "elm.dragable.vbar",
4243      _elm_scroll_edje_drag_v_stop_cb, sid);
4244    edje_object_signal_callback_add
4245      (sid->edje_obj, "drag,step", "elm.dragable.vbar",
4246      _elm_scroll_edje_drag_v_cb, sid);
4247    edje_object_signal_callback_add
4248      (sid->edje_obj, "drag,page", "elm.dragable.vbar",
4249      _elm_scroll_edje_drag_v_cb, sid);
4250    edje_object_signal_callback_add
4251      (sid->edje_obj, "elm,vbar,press", "elm",
4252      _elm_scroll_vbar_press_cb, sid);
4253    edje_object_signal_callback_add
4254      (sid->edje_obj, "elm,vbar,unpress", "elm",
4255      _elm_scroll_vbar_unpress_cb, sid);
4256    edje_object_signal_callback_add
4257      (sid->edje_obj, "drag", "elm.dragable.hbar", _elm_scroll_hbar_drag_cb,
4258      sid);
4259    edje_object_signal_callback_add
4260      (sid->edje_obj, "drag,set", "elm.dragable.hbar",
4261      _elm_scroll_edje_drag_h_cb, sid);
4262    edje_object_signal_callback_add
4263      (sid->edje_obj, "drag,start", "elm.dragable.hbar",
4264      _elm_scroll_edje_drag_h_start_cb, sid);
4265    edje_object_signal_callback_add
4266      (sid->edje_obj, "drag,stop", "elm.dragable.hbar",
4267      _elm_scroll_edje_drag_h_stop_cb, sid);
4268    edje_object_signal_callback_add
4269      (sid->edje_obj, "drag,step", "elm.dragable.hbar",
4270      _elm_scroll_edje_drag_h_cb, sid);
4271    edje_object_signal_callback_add
4272      (sid->edje_obj, "drag,page", "elm.dragable.hbar",
4273      _elm_scroll_edje_drag_h_cb, sid);
4274    edje_object_signal_callback_add
4275      (sid->edje_obj, "elm,hbar,press", "elm",
4276      _elm_scroll_hbar_press_cb, sid);
4277    edje_object_signal_callback_add
4278      (sid->edje_obj, "elm,hbar,unpress", "elm",
4279      _elm_scroll_hbar_unpress_cb, sid);
4280 }
4281
4282 static void
4283 _scroll_event_object_attach(Evas_Object *obj)
4284 {
4285    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4286
4287    evas_object_event_callback_add
4288      (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _elm_scroll_wheel_event_cb,
4289      sid);
4290    evas_object_event_callback_add
4291      (sid->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
4292      _elm_scroll_mouse_down_event_cb, sid);
4293    evas_object_event_callback_add
4294      (sid->event_rect, EVAS_CALLBACK_MOUSE_UP,
4295      _elm_scroll_mouse_up_event_cb, sid);
4296    evas_object_event_callback_add
4297      (sid->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
4298      _elm_scroll_mouse_move_event_cb, sid);
4299 }
4300
4301 static void
4302 _scroll_edje_object_detach(Evas_Object *obj)
4303 {
4304    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4305
4306    evas_object_event_callback_del_full
4307      (sid->edje_obj, EVAS_CALLBACK_RESIZE, _on_edje_resize, sid);
4308    evas_object_event_callback_del_full
4309      (sid->edje_obj, EVAS_CALLBACK_MOVE, _on_edje_move, sid);
4310
4311    edje_object_signal_callback_del_full
4312      (sid->edje_obj, "drag", "elm.dragable.vbar", _elm_scroll_vbar_drag_cb,
4313      sid);
4314    edje_object_signal_callback_del_full
4315      (sid->edje_obj, "drag,set", "elm.dragable.vbar",
4316      _elm_scroll_edje_drag_v_cb, sid);
4317    edje_object_signal_callback_del_full
4318      (sid->edje_obj, "drag,start", "elm.dragable.vbar",
4319      _elm_scroll_edje_drag_v_start_cb, sid);
4320    edje_object_signal_callback_del_full
4321      (sid->edje_obj, "drag,stop", "elm.dragable.vbar",
4322      _elm_scroll_edje_drag_v_stop_cb, sid);
4323    edje_object_signal_callback_del_full
4324      (sid->edje_obj, "drag,step", "elm.dragable.vbar",
4325      _elm_scroll_edje_drag_v_cb, sid);
4326    edje_object_signal_callback_del_full
4327      (sid->edje_obj, "drag,page", "elm.dragable.vbar",
4328      _elm_scroll_edje_drag_v_cb, sid);
4329    edje_object_signal_callback_del_full
4330      (sid->edje_obj, "elm,vbar,press", "elm",
4331      _elm_scroll_vbar_press_cb, sid);
4332    edje_object_signal_callback_del_full
4333      (sid->edje_obj, "elm,vbar,unpress", "elm",
4334      _elm_scroll_vbar_unpress_cb, sid);
4335    edje_object_signal_callback_del_full
4336      (sid->edje_obj, "drag", "elm.dragable.hbar", _elm_scroll_hbar_drag_cb,
4337      sid);
4338    edje_object_signal_callback_del_full
4339      (sid->edje_obj, "drag,set", "elm.dragable.hbar",
4340      _elm_scroll_edje_drag_h_cb, sid);
4341    edje_object_signal_callback_del_full
4342      (sid->edje_obj, "drag,start", "elm.dragable.hbar",
4343      _elm_scroll_edje_drag_h_start_cb, sid);
4344    edje_object_signal_callback_del_full
4345      (sid->edje_obj, "drag,stop", "elm.dragable.hbar",
4346      _elm_scroll_edje_drag_h_stop_cb, sid);
4347    edje_object_signal_callback_del_full
4348      (sid->edje_obj, "drag,step", "elm.dragable.hbar",
4349      _elm_scroll_edje_drag_h_cb, sid);
4350    edje_object_signal_callback_del_full
4351      (sid->edje_obj, "drag,page", "elm.dragable.hbar",
4352      _elm_scroll_edje_drag_h_cb, sid);
4353    edje_object_signal_callback_del_full
4354      (sid->edje_obj, "elm,hbar,press", "elm",
4355      _elm_scroll_hbar_press_cb, sid);
4356    edje_object_signal_callback_del_full
4357      (sid->edje_obj, "elm,hbar,unpress", "elm",
4358      _elm_scroll_hbar_unpress_cb, sid);
4359 }
4360
4361 static void
4362 _scroll_event_object_detach(Evas_Object *obj)
4363 {
4364    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4365
4366    evas_object_event_callback_del_full
4367      (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL, _elm_scroll_wheel_event_cb,
4368      sid);
4369    evas_object_event_callback_del_full
4370      (sid->event_rect, EVAS_CALLBACK_MOUSE_DOWN,
4371      _elm_scroll_mouse_down_event_cb, sid);
4372    evas_object_event_callback_del_full
4373      (sid->event_rect, EVAS_CALLBACK_MOUSE_UP,
4374      _elm_scroll_mouse_up_event_cb, sid);
4375    evas_object_event_callback_del_full
4376      (sid->event_rect, EVAS_CALLBACK_MOUSE_MOVE,
4377      _elm_scroll_mouse_move_event_cb, sid);
4378 }
4379
4380 static void
4381 _elm_scroll_objects_set(Evas_Object *obj,
4382                         Evas_Object *edje_object,
4383                         Evas_Object *hit_rectangle)
4384 {
4385    Evas_Coord mw, mh;
4386
4387    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4388
4389    if (!edje_object || !hit_rectangle) return;
4390
4391    if (sid->edje_obj)
4392        _scroll_edje_object_detach(obj);
4393
4394    sid->edje_obj = edje_object;
4395
4396    if (sid->event_rect)
4397        _scroll_event_object_detach(obj);
4398
4399    sid->event_rect = hit_rectangle;
4400    evas_object_repeat_events_set(hit_rectangle, EINA_TRUE);
4401
4402    _scroll_edje_object_attach(obj);
4403    _scroll_event_object_attach(obj);
4404
4405    mw = mh = -1;
4406    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
4407    if (edje_object_part_exists(sid->edje_obj, "elm.scrollbar.base"))
4408      {
4409         Evas_Object *base;
4410
4411         base = edje_object_part_swallow_get
4412             (sid->edje_obj, "elm.scrollbar.base");
4413         if (!base)
4414           {
4415              base = evas_object_rectangle_add
4416                  (evas_object_evas_get(sid->edje_obj));
4417              evas_object_color_set(base, 0, 0, 0, 0);
4418              edje_object_part_swallow
4419                (sid->edje_obj, "elm.scrollbar.base", base);
4420           }
4421         if (!_elm_config->thumbscroll_enable)
4422           evas_object_size_hint_min_set(base, mw, mh);
4423      }
4424
4425    _elm_scroll_scroll_bar_visibility_adjust(sid);
4426 }
4427
4428 static void
4429 _elm_scroll_scroll_bar_reset(Elm_Scrollable_Smart_Interface_Data *sid)
4430 {
4431    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
4432
4433    if (!sid->edje_obj) return;
4434
4435    edje_object_part_drag_value_set
4436      (sid->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
4437    edje_object_part_drag_value_set
4438      (sid->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
4439    if ((!sid->content) && (!sid->extern_pan))
4440      {
4441         edje_object_part_drag_size_set
4442           (sid->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
4443         edje_object_part_drag_size_set
4444           (sid->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
4445      }
4446    if (sid->pan_obj)
4447      {
4448         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
4449
4450         psd->api->pos_min_get(sid->pan_obj, &minx, &miny);
4451         psd->api->pos_get(sid->pan_obj, &px, &py);
4452         psd->api->pos_set(sid->pan_obj, minx, miny);
4453      }
4454    if ((px != minx) || (py != miny))
4455      edje_object_signal_emit(sid->edje_obj, "elm,action,scroll", "elm");
4456    _elm_direction_arrows_eval(sid);
4457 }
4458
4459 /* even external pan objects get this */
4460 static void
4461 _elm_scroll_pan_changed_cb(void *data,
4462                            Evas_Object *obj __UNUSED__,
4463                            void *event_info __UNUSED__)
4464 {
4465    Evas_Coord w, h, vw, vh;
4466    Elm_Scrollable_Smart_Interface_Data *sid = data;
4467
4468    if (!sid->pan_obj) return;
4469
4470    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
4471
4472    psd->api->content_size_get(sid->pan_obj, &w, &h);
4473    _elm_scroll_content_viewport_size_get(sid->obj, &vw, &vh);
4474    if ((w != sid->content_info.w) || (h != sid->content_info.h))
4475      {
4476         if (_paging_is_enabled(sid))
4477           {
4478              if (w != sid->content_info.w)
4479                {
4480                   if (sid->pagerel_h > 0)
4481                     sid->pagecount_h = w / (vw * sid->pagerel_h);
4482                }
4483              if (h != sid->content_info.h)
4484                {
4485                   if (sid->pagerel_v > 0)
4486                     sid->pagecount_v = h / (vh * sid->pagerel_v);
4487                }
4488           }
4489         sid->content_info.w = w;
4490         sid->content_info.h = h;
4491         _elm_scroll_scroll_bar_size_adjust(sid);
4492
4493         evas_object_size_hint_min_set
4494           (sid->edje_obj, sid->content_info.w, sid->content_info.h);
4495         sid->content_info.resized = EINA_TRUE;
4496         _elm_scroll_reconfigure(sid);
4497         _elm_scroll_wanted_region_set(sid->obj);
4498      }
4499 }
4500
4501 static void
4502 _elm_scroll_pan_resized_cb(void *data,
4503                           Evas *e __UNUSED__,
4504                           Evas_Object *obj __UNUSED__,
4505                           void *event_info __UNUSED__)
4506 {
4507    Evas_Coord w, h;
4508    Elm_Scrollable_Smart_Interface_Data *sid = data;
4509
4510    if (sid->cb_func.content_viewport_resize)
4511      {
4512         _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
4513         sid->cb_func.content_viewport_resize(sid->obj, w, h);
4514      }
4515 }
4516
4517 static void
4518 _elm_scroll_content_del_cb(void *data,
4519                            Evas *e __UNUSED__,
4520                            Evas_Object *obj __UNUSED__,
4521                            void *event_info __UNUSED__)
4522 {
4523    Elm_Scrollable_Smart_Interface_Data *sid = data;
4524
4525    sid->content = NULL;
4526    _elm_scroll_scroll_bar_size_adjust(sid);
4527    _elm_scroll_scroll_bar_reset(sid);
4528 }
4529
4530 static void
4531 _elm_scroll_content_set(Evas_Object *obj,
4532                         Evas_Object *content)
4533 {
4534    Evas_Coord w, h;
4535    Evas_Object *o;
4536
4537    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4538
4539    if (!sid->edje_obj) return;
4540
4541    if (sid->content)
4542      {
4543         /* if we had content, for sure we had a pan object */
4544         _elm_pan_content_set(sid->pan_obj, NULL);
4545         evas_object_event_callback_del_full
4546           (sid->content, EVAS_CALLBACK_DEL, _elm_scroll_content_del_cb, sid);
4547      }
4548
4549    sid->content = content;
4550    sid->wx = sid->wy = 0;
4551    /* (-1) means want viewports size */
4552    sid->ww = sid->wh = -1;
4553    if (!content) return;
4554
4555    if (!sid->pan_obj)
4556      {
4557         o = _elm_pan_add(evas_object_evas_get(obj));
4558         sid->pan_obj = o;
4559         evas_object_smart_callback_add
4560           (o, SIG_CHANGED, _elm_scroll_pan_changed_cb, sid);
4561         evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE,
4562                                        _elm_scroll_pan_resized_cb, sid);
4563         edje_object_part_swallow(sid->edje_obj, "elm.swallow.content", o);
4564      }
4565
4566    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
4567
4568    evas_object_event_callback_add
4569      (content, EVAS_CALLBACK_DEL, _elm_scroll_content_del_cb, sid);
4570
4571    _elm_pan_content_set(sid->pan_obj, content);
4572    psd->api->content_size_get(sid->pan_obj, &w, &h);
4573    sid->content_info.w = w;
4574    sid->content_info.h = h;
4575
4576    _elm_scroll_scroll_bar_size_adjust(sid);
4577    _elm_scroll_scroll_bar_reset(sid);
4578 }
4579
4580 static void
4581 _elm_scroll_extern_pan_set(Evas_Object *obj,
4582                            Evas_Object *pan)
4583 {
4584    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4585
4586    if (!sid->edje_obj) return;
4587
4588    _elm_scroll_content_set(obj, NULL);
4589
4590    if (sid->pan_obj)
4591      {
4592         evas_object_smart_callback_del
4593           (sid->pan_obj, SIG_CHANGED, _elm_scroll_pan_changed_cb);
4594         evas_object_event_callback_del(sid->pan_obj, EVAS_CALLBACK_RESIZE,
4595                                        _elm_scroll_pan_resized_cb);
4596      }
4597
4598    if (sid->extern_pan)
4599      {
4600         if (sid->pan_obj)
4601           {
4602              /* not owned by scroller, just leave (was external already) */
4603              edje_object_part_unswallow(sid->edje_obj, sid->pan_obj);
4604              sid->pan_obj = NULL;
4605           }
4606      }
4607    else
4608      {
4609         if (sid->pan_obj)
4610           {
4611              evas_object_del(sid->pan_obj);
4612              sid->pan_obj = NULL;
4613           }
4614      }
4615    if (!pan)
4616      {
4617         sid->extern_pan = EINA_FALSE;
4618         return;
4619      }
4620
4621    sid->pan_obj = pan;
4622
4623    sid->extern_pan = EINA_TRUE;
4624    evas_object_smart_callback_add
4625      (sid->pan_obj, SIG_CHANGED, _elm_scroll_pan_changed_cb, sid);
4626    evas_object_event_callback_add(sid->pan_obj, EVAS_CALLBACK_RESIZE,
4627                                   _elm_scroll_pan_resized_cb, sid);
4628    edje_object_part_swallow
4629      (sid->edje_obj, "elm.swallow.content", sid->pan_obj);
4630 }
4631
4632 static void
4633 _elm_scroll_drag_start_cb_set(Evas_Object *obj,
4634                               void (*drag_start_cb)(Evas_Object *obj,
4635                                                     void *data))
4636 {
4637    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4638
4639    sid->cb_func.drag_start = drag_start_cb;
4640 }
4641
4642 static void
4643 _elm_scroll_drag_stop_cb_set(Evas_Object *obj,
4644                              void (*drag_stop_cb)(Evas_Object *obj,
4645                                                   void *data))
4646 {
4647    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4648
4649    sid->cb_func.drag_stop = drag_stop_cb;
4650 }
4651
4652 static void
4653 _elm_scroll_animate_start_cb_set(Evas_Object *obj,
4654                                  void (*animate_start_cb)(Evas_Object *obj,
4655                                                           void *data))
4656 {
4657    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4658
4659    sid->cb_func.animate_start = animate_start_cb;
4660 }
4661
4662 static void
4663 _elm_scroll_animate_stop_cb_set(Evas_Object *obj,
4664                                 void (*animate_stop_cb)(Evas_Object *obj,
4665                                                         void *data))
4666 {
4667    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4668
4669    sid->cb_func.animate_stop = animate_stop_cb;
4670 }
4671
4672 static void
4673 _elm_scroll_scroll_cb_set(Evas_Object *obj,
4674                           void (*scroll_cb)(Evas_Object *obj,
4675                                             void *data))
4676 {
4677    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4678
4679    sid->cb_func.scroll = scroll_cb;
4680 }
4681
4682 static void
4683 _elm_scroll_scroll_left_cb_set(Evas_Object *obj,
4684                           void (*scroll_left_cb)(Evas_Object *obj,
4685                                             void *data))
4686 {
4687    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4688
4689    sid->cb_func.scroll_left = scroll_left_cb;
4690 }
4691
4692 static void
4693 _elm_scroll_scroll_right_cb_set(Evas_Object *obj,
4694                           void (*scroll_right_cb)(Evas_Object *obj,
4695                                             void *data))
4696 {
4697    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4698
4699    sid->cb_func.scroll_right = scroll_right_cb;
4700 }
4701
4702 static void
4703 _elm_scroll_scroll_up_cb_set(Evas_Object *obj,
4704                           void (*scroll_up_cb)(Evas_Object *obj,
4705                                             void *data))
4706 {
4707    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4708
4709    sid->cb_func.scroll_up = scroll_up_cb;
4710 }
4711
4712 static void
4713 _elm_scroll_scroll_down_cb_set(Evas_Object *obj,
4714                           void (*scroll_down_cb)(Evas_Object *obj,
4715                                             void *data))
4716 {
4717    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4718
4719    sid->cb_func.scroll_down = scroll_down_cb;
4720 }
4721
4722 static void
4723 _elm_scroll_edge_left_cb_set(Evas_Object *obj,
4724                              void (*edge_left_cb)(Evas_Object *obj,
4725                                                   void *data))
4726 {
4727    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4728
4729    sid->cb_func.edge_left = edge_left_cb;
4730 }
4731
4732 static void
4733 _elm_scroll_edge_right_cb_set(Evas_Object *obj,
4734                               void (*edge_right_cb)(Evas_Object *obj,
4735                                                     void *data))
4736 {
4737    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4738
4739    sid->cb_func.edge_right = edge_right_cb;
4740 }
4741
4742 static void
4743 _elm_scroll_edge_top_cb_set(Evas_Object *obj,
4744                             void (*edge_top_cb)(Evas_Object *obj,
4745                                                 void *data))
4746 {
4747    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4748
4749    sid->cb_func.edge_top = edge_top_cb;
4750 }
4751
4752 static void
4753 _elm_scroll_edge_bottom_cb_set(Evas_Object *obj,
4754                                void (*edge_bottom_cb)(Evas_Object *obj,
4755                                                       void *data))
4756 {
4757    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4758
4759    sid->cb_func.edge_bottom = edge_bottom_cb;
4760 }
4761
4762 static void
4763 _elm_scroll_vbar_drag_cb_set(Evas_Object *obj,
4764                                void (*vbar_drag_cb)(Evas_Object *obj,
4765                                                       void *data))
4766 {
4767    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4768
4769    sid->cb_func.vbar_drag = vbar_drag_cb;
4770 }
4771
4772 static void
4773 _elm_scroll_vbar_press_cb_set(Evas_Object *obj,
4774                                void (*vbar_press_cb)(Evas_Object *obj,
4775                                                       void *data))
4776 {
4777    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4778
4779    sid->cb_func.vbar_press = vbar_press_cb;
4780 }
4781
4782 static void
4783 _elm_scroll_vbar_unpress_cb_set(Evas_Object *obj,
4784                                void (*vbar_unpress_cb)(Evas_Object *obj,
4785                                                       void *data))
4786 {
4787    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4788
4789    sid->cb_func.vbar_unpress = vbar_unpress_cb;
4790 }
4791
4792 static void
4793 _elm_scroll_hbar_drag_cb_set(Evas_Object *obj,
4794                                void (*hbar_drag_cb)(Evas_Object *obj,
4795                                                       void *data))
4796 {
4797    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4798
4799    sid->cb_func.hbar_drag = hbar_drag_cb;
4800 }
4801
4802 static void
4803 _elm_scroll_hbar_press_cb_set(Evas_Object *obj,
4804                                void (*hbar_press_cb)(Evas_Object *obj,
4805                                                       void *data))
4806 {
4807    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4808
4809    sid->cb_func.hbar_press = hbar_press_cb;
4810 }
4811
4812 static void
4813 _elm_scroll_hbar_unpress_cb_set(Evas_Object *obj,
4814                                void (*hbar_unpress_cb)(Evas_Object *obj,
4815                                                       void *data))
4816 {
4817    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4818
4819    sid->cb_func.hbar_unpress = hbar_unpress_cb;
4820 }
4821
4822 static void
4823 _elm_scroll_content_min_limit_cb_set(Evas_Object *obj,
4824                                      void (*c_min_limit_cb)(Evas_Object *obj,
4825                                                             Eina_Bool w,
4826                                                             Eina_Bool h))
4827 {
4828    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4829
4830    sid->cb_func.content_min_limit = c_min_limit_cb;
4831 }
4832
4833 static void
4834 _elm_scroll_content_viewport_resize_cb_set(Evas_Object *obj,
4835                                  void (*c_viewport_resize_cb)(Evas_Object *obj,
4836                                                               Evas_Coord w,
4837                                                               Evas_Coord h))
4838 {
4839    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4840
4841    sid->cb_func.content_viewport_resize = c_viewport_resize_cb;
4842 }
4843
4844 static Eina_Bool
4845 _elm_scroll_momentum_animator_disabled_get(const Evas_Object *obj)
4846 {
4847    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
4848
4849    return sid->momentum_animator_disabled;
4850 }
4851
4852 static void
4853 _elm_scroll_momentum_animator_disabled_set(Evas_Object *obj,
4854                                            Eina_Bool disabled)
4855 {
4856    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4857
4858    sid->momentum_animator_disabled = disabled;
4859    if (sid->momentum_animator_disabled)
4860      {
4861         if (sid->down.momentum_animator)
4862           {
4863              ecore_animator_del(sid->down.momentum_animator);
4864              sid->down.momentum_animator = NULL;
4865              if (sid->content_info.resized)
4866                _elm_scroll_wanted_region_set(sid->obj);
4867           }
4868      }
4869 }
4870
4871 static Eina_Bool
4872 _elm_scroll_bounce_animator_disabled_get(const Evas_Object *obj)
4873 {
4874    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
4875
4876    return sid->bounce_animator_disabled;
4877 }
4878
4879 static void
4880 _elm_scroll_bounce_animator_disabled_set(Evas_Object *obj,
4881                                          Eina_Bool disabled)
4882 {
4883    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4884
4885    sid->bounce_animator_disabled = disabled;
4886    if (sid->bounce_animator_disabled)
4887      {
4888         if (sid->scrollto.x.animator)
4889           {
4890              ecore_animator_del(sid->scrollto.x.animator);
4891              sid->scrollto.x.animator = NULL;
4892           }
4893
4894         if (sid->scrollto.y.animator)
4895           {
4896              ecore_animator_del(sid->scrollto.y.animator);
4897              sid->scrollto.y.animator = NULL;
4898           }
4899      }
4900 }
4901
4902 static Eina_Bool
4903 _elm_scroll_wheel_disabled_get(const Evas_Object *obj)
4904 {
4905    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
4906
4907    return sid->wheel_disabled;
4908 }
4909
4910 static void
4911 _elm_scroll_wheel_disabled_set(Evas_Object *obj,
4912                                Eina_Bool disabled)
4913 {
4914    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4915
4916    if (!sid->event_rect) return;
4917
4918    if ((!sid->wheel_disabled) && (disabled))
4919      evas_object_event_callback_del_full
4920        (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL,
4921        _elm_scroll_wheel_event_cb, sid);
4922    else if ((sid->wheel_disabled) && (!disabled))
4923      evas_object_event_callback_add
4924        (sid->event_rect, EVAS_CALLBACK_MOUSE_WHEEL,
4925        _elm_scroll_wheel_event_cb, sid);
4926    sid->wheel_disabled = disabled;
4927 }
4928
4929 static void
4930 _elm_scroll_movement_block_set(Evas_Object *obj,
4931                                Elm_Scroller_Movement_Block block)
4932 {
4933    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4934
4935    sid->block = block;
4936 }
4937
4938 static Elm_Scroller_Movement_Block
4939 _elm_scroll_movement_block_get(const Evas_Object *obj)
4940 {
4941    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, ELM_SCROLLER_MOVEMENT_NO_BLOCK);
4942
4943    return sid->block;
4944 }
4945
4946 static void
4947 _elm_scroll_step_size_set(Evas_Object *obj,
4948                           Evas_Coord x,
4949                           Evas_Coord y)
4950 {
4951    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4952
4953    if (x < 1) x = 1;
4954    if (y < 1) y = 1;
4955    sid->step.x = x;
4956    sid->step.y = y;
4957
4958    _elm_scroll_scroll_bar_size_adjust(sid);
4959 }
4960
4961 static void
4962 _elm_scroll_step_size_get(const Evas_Object *obj,
4963                           Evas_Coord *x,
4964                           Evas_Coord *y)
4965 {
4966    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4967
4968    if (x) *x = sid->step.x;
4969    if (y) *y = sid->step.y;
4970 }
4971
4972 static void
4973 _elm_scroll_page_size_set(Evas_Object *obj,
4974                           Evas_Coord x,
4975                           Evas_Coord y)
4976 {
4977    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4978
4979    sid->page.x = x;
4980    sid->page.y = y;
4981
4982    _elm_scroll_scroll_bar_size_adjust(sid);
4983 }
4984
4985 static void
4986 _elm_scroll_page_size_get(const Evas_Object *obj,
4987                           Evas_Coord *x,
4988                           Evas_Coord *y)
4989 {
4990    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
4991
4992    if (x) *x = sid->page.x;
4993    if (y) *y = sid->page.y;
4994 }
4995
4996 static void
4997 _elm_scroll_policy_set(Evas_Object *obj,
4998                        Elm_Scroller_Policy hbar,
4999                        Elm_Scroller_Policy vbar)
5000 {
5001    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5002
5003    if (!sid->edje_obj) return;
5004
5005    if ((sid->hbar_flags == hbar) && (sid->vbar_flags == vbar)) return;
5006
5007    sid->hbar_flags = hbar;
5008    sid->vbar_flags = vbar;
5009    _elm_scroll_policy_signal_emit(sid);
5010    if (sid->cb_func.content_min_limit)
5011      sid->cb_func.content_min_limit(sid->obj, sid->min_w, sid->min_h);
5012    _elm_direction_arrows_eval(sid);
5013 }
5014
5015 static void
5016 _elm_scroll_policy_get(const Evas_Object *obj,
5017                        Elm_Scroller_Policy *hbar,
5018                        Elm_Scroller_Policy *vbar)
5019 {
5020    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5021
5022    if (hbar) *hbar = sid->hbar_flags;
5023    if (vbar) *vbar = sid->vbar_flags;
5024 }
5025
5026 static void
5027 _elm_scroll_single_direction_set(Evas_Object *obj,
5028                                  Elm_Scroller_Single_Direction single_dir)
5029 {
5030    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5031
5032    sid->one_direction_at_a_time = single_dir;
5033 }
5034
5035 static Elm_Scroller_Single_Direction
5036 _elm_scroll_single_direction_get(const Evas_Object *obj)
5037 {
5038    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, ELM_SCROLLER_SINGLE_DIRECTION_SOFT);
5039
5040    return sid->one_direction_at_a_time;
5041 }
5042
5043 static void
5044 _elm_scroll_repeat_events_set(Evas_Object *obj,
5045                                  Eina_Bool repeat_events)
5046 {
5047    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5048
5049    evas_object_repeat_events_set(sid->event_rect, repeat_events);
5050 }
5051
5052 static Eina_Bool
5053 _elm_scroll_repeat_events_get(const Evas_Object *obj)
5054 {
5055    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
5056
5057    return evas_object_repeat_events_get(sid->event_rect);
5058 }
5059
5060 static void
5061 _elm_scroll_hold_set(Evas_Object *obj,
5062                      Eina_Bool hold)
5063 {
5064    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5065
5066    sid->hold = hold;
5067 }
5068
5069 static void
5070 _elm_scroll_freeze_set(Evas_Object *obj,
5071                        Eina_Bool freeze)
5072 {
5073    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5074
5075    sid->freeze = freeze;
5076    if (sid->freeze)
5077      {
5078         if (sid->down.onhold_animator)
5079           {
5080              ecore_animator_del(sid->down.onhold_animator);
5081              sid->down.onhold_animator = NULL;
5082              if (sid->content_info.resized)
5083                _elm_scroll_wanted_region_set(sid->obj);
5084           }
5085      }
5086    else
5087      _elm_scroll_bounce_eval(sid);
5088 }
5089
5090 static void
5091 _elm_scroll_bounce_allow_set(Evas_Object *obj,
5092                              Eina_Bool horiz,
5093                              Eina_Bool vert)
5094 {
5095    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5096
5097    sid->bounce_horiz = !!horiz;
5098    sid->bounce_vert = !!vert;
5099 }
5100
5101 static void
5102 _elm_scroll_bounce_allow_get(const Evas_Object *obj,
5103                              Eina_Bool *horiz,
5104                              Eina_Bool *vert)
5105 {
5106    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5107
5108    if (horiz) *horiz = sid->bounce_horiz;
5109    if (vert) *vert = sid->bounce_vert;
5110 }
5111
5112 static void
5113 _elm_scroll_paging_set(Evas_Object *obj,
5114                        double pagerel_h,
5115                        double pagerel_v,
5116                        Evas_Coord pagesize_h,
5117                        Evas_Coord pagesize_v)
5118 {
5119    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5120
5121    sid->pagerel_h = pagerel_h;
5122    sid->pagerel_v = pagerel_v;
5123    sid->pagesize_h = pagesize_h;
5124    sid->pagesize_v = pagesize_v;
5125 }
5126
5127 static void
5128 _elm_scroll_paging_get(const Evas_Object *obj,
5129                        double *pagerel_h,
5130                        double *pagerel_v,
5131                        Evas_Coord *pagesize_h,
5132                        Evas_Coord *pagesize_v)
5133 {
5134    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5135
5136    if (pagerel_h) *pagerel_h = sid->pagerel_h;
5137    if (pagerel_v) *pagerel_v = sid->pagerel_v;
5138    if (pagesize_h) *pagesize_h = sid->pagesize_h;
5139    if (pagesize_v) *pagesize_v = sid->pagesize_v;
5140 }
5141
5142 static void
5143 _elm_scroll_page_scroll_limit_set(const Evas_Object *obj,
5144                                   int page_limit_h,
5145                                   int page_limit_v)
5146 {
5147    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5148
5149    sid->page_limit_h = page_limit_h;
5150    sid->page_limit_v = page_limit_v;
5151 }
5152
5153 static void
5154 _elm_scroll_page_scroll_limit_get(const Evas_Object *obj,
5155                                   int *page_limit_h,
5156                                   int *page_limit_v)
5157 {
5158    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5159
5160    if (page_limit_h) *page_limit_h = sid->page_limit_h;
5161    if (page_limit_v) *page_limit_v = sid->page_limit_v;
5162 }
5163
5164 static void
5165 _elm_scroll_current_page_get(const Evas_Object *obj,
5166                              int *pagenumber_h,
5167                              int *pagenumber_v)
5168 {
5169    Evas_Coord x, y;
5170
5171    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5172
5173    _elm_scroll_content_pos_get(sid->obj, &x, &y);
5174    if (pagenumber_h)
5175      {
5176         if (sid->pagesize_h > 0)
5177           {
5178              double result = (double)x / (double)sid->pagesize_h;
5179              double rest = result - (x / sid->pagesize_h);
5180              if (rest >= 0.5)
5181                *pagenumber_h = result + 1;
5182              else
5183                *pagenumber_h = result;
5184           }
5185         else
5186           *pagenumber_h = 0;
5187      }
5188    if (pagenumber_v)
5189      {
5190         if (sid->pagesize_v > 0)
5191           {
5192              double result = (double)y / (double)sid->pagesize_v;
5193              double rest = result - (y / sid->pagesize_v);
5194              if (rest >= 0.5)
5195                *pagenumber_v = result + 1;
5196              else
5197                *pagenumber_v = result;
5198           }
5199         else
5200           *pagenumber_v = 0;
5201      }
5202 }
5203
5204 static void
5205 _elm_scroll_last_page_get(const Evas_Object *obj,
5206                           int *pagenumber_h,
5207                           int *pagenumber_v)
5208 {
5209    Evas_Coord cw, ch;
5210
5211    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5212
5213    if (!sid->pan_obj) return;
5214
5215    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
5216
5217    psd->api->content_size_get(sid->pan_obj, &cw, &ch);
5218    if (pagenumber_h)
5219      {
5220         if (sid->pagesize_h > 0)
5221           *pagenumber_h = cw / sid->pagesize_h - 1;
5222         else
5223           *pagenumber_h = 0;
5224      }
5225    if (pagenumber_v)
5226      {
5227         if (sid->pagesize_v > 0)
5228           *pagenumber_v = ch / sid->pagesize_v - 1;
5229         else
5230           *pagenumber_v = 0;
5231      }
5232 }
5233
5234 static void
5235 _elm_scroll_page_show(Evas_Object *obj,
5236                       int pagenumber_h,
5237                       int pagenumber_v)
5238 {
5239    Evas_Coord w, h, cw = 0, ch = 0;
5240    Evas_Coord x = 0;
5241    Evas_Coord y = 0;
5242
5243    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5244    if (sid->pan_obj)
5245      {
5246         ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
5247         psd->api->content_size_get(sid->pan_obj, &cw, &ch);
5248      }
5249
5250    sid->current_page.x = _elm_scroll_page_x_get(sid, 0, EINA_FALSE);
5251    sid->current_page.y = _elm_scroll_page_y_get(sid, 0, EINA_FALSE);
5252
5253    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
5254    if (pagenumber_h >= 0) x = sid->pagesize_h * pagenumber_h;
5255    if (pagenumber_v >= 0) y = sid->pagesize_v * pagenumber_v;
5256
5257    if (sid->origin_x && cw > 0)
5258      {
5259         sid->wx = cw - x;
5260         if (sid->wx < 0) sid->wx = 0;
5261      }
5262    else
5263      sid->wx = x;
5264
5265    if (sid->origin_y && ch > 0)
5266      {
5267         sid->wy = ch - y;
5268         if (sid->wy < 0) sid->wy = 0;
5269      }
5270    else
5271      sid->wy = y;
5272    sid->ww = w;
5273    sid->wh = h;
5274
5275    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
5276      _elm_scroll_content_pos_set(obj, x, y, EINA_TRUE);
5277 }
5278
5279 static void
5280 _elm_scroll_page_bring_in(Evas_Object *obj,
5281                           int pagenumber_h,
5282                           int pagenumber_v)
5283 {
5284    Evas_Coord w, h;
5285    Evas_Coord x = 0;
5286    Evas_Coord y = 0;
5287
5288    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5289
5290    sid->current_page.x = _elm_scroll_page_x_get(sid, 0, EINA_FALSE);
5291    sid->current_page.y = _elm_scroll_page_y_get(sid, 0, EINA_FALSE);
5292
5293    _elm_scroll_content_viewport_size_get(sid->obj, &w, &h);
5294    if (pagenumber_h >= 0) x = sid->pagesize_h * pagenumber_h;
5295    if (pagenumber_v >= 0) y = sid->pagesize_v * pagenumber_v;
5296    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
5297      {
5298         _elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
5299         _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
5300      }
5301 }
5302
5303 static void
5304 _elm_scroll_region_bring_in(Evas_Object *obj,
5305                             Evas_Coord x,
5306                             Evas_Coord y,
5307                             Evas_Coord w,
5308                             Evas_Coord h)
5309 {
5310    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5311
5312    if (_elm_scroll_content_region_show_internal(obj, &x, &y, w, h))
5313      {
5314         _elm_scroll_scroll_to_x(sid, _elm_config->bring_in_scroll_friction, x);
5315         _elm_scroll_scroll_to_y(sid, _elm_config->bring_in_scroll_friction, y);
5316      }
5317 }
5318
5319 static void
5320 _elm_scroll_gravity_set(Evas_Object *obj,
5321                         double x,
5322                         double y)
5323 {
5324    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5325
5326    if (!sid->pan_obj) return;
5327
5328    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
5329
5330    psd->api->gravity_set(sid->pan_obj, x, y);
5331 }
5332
5333 static void
5334 _elm_scroll_gravity_get(const Evas_Object *obj,
5335                         double *x,
5336                         double *y)
5337 {
5338    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5339
5340    if (!sid->pan_obj) return;
5341
5342    ELM_PAN_DATA_GET_OR_RETURN(sid->pan_obj, psd);
5343
5344    psd->api->gravity_get(sid->pan_obj, x, y);
5345 }
5346
5347
5348 static void
5349 _elm_scroll_loop_set(Evas_Object *obj,
5350                               Eina_Bool loop_h,
5351                               Eina_Bool loop_v)
5352 {
5353    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5354
5355    if (sid->loop_h == loop_h &&
5356        sid->loop_v == loop_v)
5357      return;
5358
5359    sid->loop_h = loop_h;
5360    sid->loop_v = loop_v;
5361 }
5362
5363 static void
5364 _elm_scroll_loop_get(const Evas_Object *obj,
5365                               Eina_Bool *loop_h,
5366                               Eina_Bool *loop_v)
5367 {
5368    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5369
5370    *loop_h = sid->loop_h;
5371    *loop_v = sid->loop_v;
5372 }
5373
5374
5375 static Eina_Bool
5376 _elm_scroll_interface_add(Evas_Object *obj)
5377 {
5378    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN_VAL(obj, sid, EINA_FALSE);
5379
5380    memset(sid, 0, sizeof(*sid));
5381
5382    sid->obj = obj;
5383
5384    sid->x = 0;
5385    sid->y = 0;
5386    sid->w = 0;
5387    sid->h = 0;
5388    sid->step.x = 32;
5389    sid->step.y = 32;
5390    sid->page.x = -50;
5391    sid->page.y = -50;
5392    sid->page_limit_h = 9999;
5393    sid->page_limit_v = 9999;
5394    sid->hbar_flags = ELM_SCROLLER_POLICY_AUTO;
5395    sid->vbar_flags = ELM_SCROLLER_POLICY_AUTO;
5396    sid->hbar_visible = EINA_TRUE;
5397    sid->vbar_visible = EINA_TRUE;
5398    sid->loop_h = EINA_FALSE;
5399    sid->loop_v = EINA_FALSE;
5400    sid->origin_x = EINA_FALSE;
5401    sid->origin_y = EINA_FALSE;
5402
5403    sid->bounce_horiz = EINA_TRUE;
5404    sid->bounce_vert = EINA_TRUE;
5405
5406    sid->one_direction_at_a_time = ELM_SCROLLER_SINGLE_DIRECTION_SOFT;
5407    sid->momentum_animator_disabled = EINA_FALSE;
5408    sid->bounce_animator_disabled = EINA_FALSE;
5409    sid->block = ELM_SCROLLER_MOVEMENT_NO_BLOCK;
5410
5411    _elm_scroll_scroll_bar_reset(sid);
5412
5413    return EINA_TRUE;
5414 }
5415
5416 static void
5417 _elm_scroll_interface_del(Evas_Object *obj)
5418 {
5419    ELM_SCROLL_IFACE_DATA_GET_OR_RETURN(obj, sid);
5420
5421    _elm_scroll_content_set(obj, NULL);
5422    if (!sid->extern_pan) evas_object_del(sid->pan_obj);
5423
5424    if (sid->down.hold_animator)
5425      ecore_animator_del(sid->down.hold_animator);
5426    if (sid->down.onhold_animator)
5427      ecore_animator_del(sid->down.onhold_animator);
5428    if (sid->down.momentum_animator)
5429      ecore_animator_del(sid->down.momentum_animator);
5430    if (sid->down.bounce_x_animator)
5431      ecore_animator_del(sid->down.bounce_x_animator);
5432    if (sid->down.bounce_y_animator)
5433      ecore_animator_del(sid->down.bounce_y_animator);
5434    if (sid->scrollto.x.animator) ecore_animator_del(sid->scrollto.x.animator);
5435    if (sid->scrollto.y.animator) ecore_animator_del(sid->scrollto.y.animator);
5436 }
5437
5438 EAPI const char ELM_SCROLLABLE_IFACE_NAME[] = "elm_interface_scrollable";
5439
5440 EAPI const Elm_Scrollable_Smart_Interface ELM_SCROLLABLE_IFACE =
5441 {
5442    {
5443       ELM_SCROLLABLE_IFACE_NAME,
5444       sizeof(Elm_Scrollable_Smart_Interface_Data),
5445       _elm_scroll_interface_add,
5446       _elm_scroll_interface_del
5447    },
5448
5449    _elm_scroll_objects_set,
5450    _elm_scroll_content_set,
5451    _elm_scroll_extern_pan_set,
5452    _elm_scroll_drag_start_cb_set,
5453    _elm_scroll_drag_stop_cb_set,
5454    _elm_scroll_animate_start_cb_set,
5455    _elm_scroll_animate_stop_cb_set,
5456    _elm_scroll_scroll_cb_set,
5457    _elm_scroll_scroll_left_cb_set,
5458    _elm_scroll_scroll_right_cb_set,
5459    _elm_scroll_scroll_up_cb_set,
5460    _elm_scroll_scroll_down_cb_set,
5461    _elm_scroll_edge_left_cb_set,
5462    _elm_scroll_edge_right_cb_set,
5463    _elm_scroll_edge_top_cb_set,
5464    _elm_scroll_edge_bottom_cb_set,
5465    _elm_scroll_vbar_drag_cb_set,
5466    _elm_scroll_vbar_press_cb_set,
5467    _elm_scroll_vbar_unpress_cb_set,
5468    _elm_scroll_hbar_drag_cb_set,
5469    _elm_scroll_hbar_press_cb_set,
5470    _elm_scroll_hbar_unpress_cb_set,
5471    _elm_scroll_content_min_limit_cb_set,
5472    _elm_scroll_content_viewport_resize_cb_set,
5473    _elm_scroll_content_pos_set,
5474    _elm_scroll_content_pos_get,
5475    _elm_scroll_content_region_show,
5476    _elm_scroll_content_region_set,
5477    _elm_scroll_content_size_get,
5478    _elm_scroll_content_viewport_size_get,
5479    _elm_scroll_content_viewport_pos_get,
5480    _elm_scroll_content_min_limit,
5481    _elm_scroll_step_size_set,
5482    _elm_scroll_step_size_get,
5483    _elm_scroll_page_size_set,
5484    _elm_scroll_page_size_get,
5485    _elm_scroll_policy_set,
5486    _elm_scroll_policy_get,
5487    _elm_scroll_single_direction_set,
5488    _elm_scroll_single_direction_get,
5489    _elm_scroll_repeat_events_set,
5490    _elm_scroll_repeat_events_get,
5491    _elm_scroll_mirrored_set,
5492    _elm_scroll_hold_set,
5493    _elm_scroll_freeze_set,
5494    _elm_scroll_bounce_allow_set,
5495    _elm_scroll_bounce_allow_get,
5496    _elm_scroll_origin_reverse_set,
5497    _elm_scroll_origin_reverse_get,
5498    _elm_scroll_paging_set,
5499    _elm_scroll_paging_get,
5500    _elm_scroll_page_scroll_limit_set,
5501    _elm_scroll_page_scroll_limit_get,
5502    _elm_scroll_current_page_get,
5503    _elm_scroll_last_page_get,
5504    _elm_scroll_page_show,
5505    _elm_scroll_page_bring_in,
5506    _elm_scroll_region_bring_in,
5507    _elm_scroll_gravity_set,
5508    _elm_scroll_gravity_get,
5509    _elm_scroll_loop_set,
5510    _elm_scroll_loop_get,
5511    _elm_scroll_momentum_animator_disabled_get,
5512    _elm_scroll_momentum_animator_disabled_set,
5513    _elm_scroll_bounce_animator_disabled_set,
5514    _elm_scroll_bounce_animator_disabled_get,
5515    _elm_scroll_wheel_disabled_get,
5516    _elm_scroll_wheel_disabled_set,
5517    _elm_scroll_movement_block_set,
5518    _elm_scroll_movement_block_get
5519 };