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