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