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