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