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