7938f00adfbae60443daa650ca5b9a6965aae30d
[framework/uifw/elementary.git] / src / lib / els_scroller.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define SMART_NAME "els_scroller"
5 #define API_ENTRY Smart_Data *sd; sd = evas_object_smart_data_get(obj); if ((!obj) || (!sd) || (evas_object_type_get(obj) && strcmp(evas_object_type_get(obj), SMART_NAME)))
6 #define INTERNAL_ENTRY Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return;
7 typedef struct _Smart_Data Smart_Data;
8
9 #define EVTIME 1
10 //#define SCROLLDBG 1
11
12 struct _Smart_Data
13 {
14    Evas_Coord   x, y, w, h;
15    Evas_Coord   wx, wy, ww, wh; /* Last "wanted" geometry */
16
17    Evas_Object *smart_obj;
18    Evas_Object *child_obj;
19    Evas_Object *pan_obj;
20    Evas_Object *edje_obj;
21    Evas_Object *event_obj;
22
23    Evas_Object *widget;
24
25    Elm_Smart_Scroller_Policy hbar_flags, vbar_flags;
26
27    struct {
28         Evas_Coord x, y;
29         Evas_Coord sx, sy;
30         Evas_Coord dx, dy;
31         Evas_Coord pdx, pdy;
32         Evas_Coord bx, by;
33         Evas_Coord ax, ay;
34         Evas_Coord bx0, by0;
35         Evas_Coord b0x, b0y;
36         Evas_Coord b2x, b2y;
37         struct {
38              Evas_Coord    x, y;
39              double        timestamp, localtimestamp;
40         } history[60];
41         struct {
42            double tadd, dxsum, dysum;
43            double est_timestamp_diff;
44         } hist;
45       double anim_start;
46       double anim_start2;
47       double anim_start3;
48       double onhold_vx, onhold_vy, onhold_tlast, onhold_vxe, onhold_vye;
49       double extra_time;
50       Evas_Coord hold_x, hold_y;
51       Ecore_Animator *hold_animator;
52       Ecore_Animator *onhold_animator;
53       Ecore_Animator *momentum_animator;
54       Ecore_Animator *bounce_x_animator;
55       Ecore_Animator *bounce_y_animator;
56       Evas_Coord locked_x, locked_y;
57       int hdir, vdir;
58       unsigned char now : 1;
59       unsigned char cancelled : 1;
60       unsigned char hold : 1;
61       unsigned char hold_parent : 1;
62       unsigned char want_dragged : 1;
63       unsigned char dragged : 1;
64       unsigned char dragged_began : 1;
65       unsigned char dir_x : 1;
66       unsigned char dir_y : 1;
67       unsigned char locked : 1;
68       unsigned char bounce_x_hold : 1;
69       unsigned char bounce_y_hold : 1;
70       unsigned char scroll : 1;
71    } down;
72
73    struct {
74       Evas_Coord w, h;
75    } child;
76    struct {
77       Evas_Coord x, y;
78    } step, page;
79
80    struct {
81       void (*set) (Evas_Object *obj, Evas_Coord x, Evas_Coord y);
82       void (*get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
83       void (*max_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
84       void (*min_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
85       void (*child_size_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
86    } pan_func;
87
88    struct {
89       struct {
90          Evas_Coord start, end;
91          double t_start, t_end;
92          Ecore_Animator *animator;
93       } x, y;
94    } scrollto;
95
96    double pagerel_h, pagerel_v;
97    Evas_Coord pagesize_h, pagesize_v;
98
99    unsigned char hbar_visible : 1;
100    unsigned char vbar_visible : 1;
101    unsigned char extern_pan : 1;
102    unsigned char one_dir_at_a_time : 1;
103    unsigned char hold : 1;
104    unsigned char freeze : 1;
105    unsigned char bouncemex : 1;
106    unsigned char bouncemey : 1;
107    unsigned char bounce_horiz : 1;
108    unsigned char bounce_vert : 1;
109    Eina_Bool momentum_animator_disabled :1;
110    Eina_Bool bounce_animator_disabled :1;
111    Eina_Bool is_mirrored : 1;
112    Eina_Bool wheel_disabled : 1;
113 };
114
115 /* local subsystem functions */
116 static void _smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info);
117 static void _smart_pan_changed_hook(void *data, Evas_Object *obj, void *event_info);
118 static void _smart_pan_pan_changed_hook(void *data, Evas_Object *obj, void *event_info);
119 static void _smart_event_wheel(void *data, Evas *e, Evas_Object *obj, void *event_info);
120 static void _smart_event_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
121 static Eina_Bool  _smart_hold_animator(void *data);
122 static Eina_Bool  _smart_momentum_animator(void *data);
123 static void _smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
124 static Eina_Bool  _smart_onhold_animator(void *data);
125 static void _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
126 static void _smart_edje_drag_v_start(void *data, Evas_Object *obj, const char *emission, const char *source);
127 static void _smart_edje_drag_v_stop(void *data, Evas_Object *obj, const char *emission, const char *source);
128 static void _smart_edje_drag_v(void *data, Evas_Object *obj, const char *emission, const char *source);
129 static void _smart_edje_drag_h_start(void *data, Evas_Object *obj, const char *emission, const char *source);
130 static void _smart_edje_drag_h_stop(void *data, Evas_Object *obj, const char *emission, const char *source);
131 static void _smart_edje_drag_h(void *data, Evas_Object *obj, const char *emission, const char *source);
132 static void _smart_scrollbar_read(Smart_Data *sd);
133 static void _smart_scrollbar_reset(Smart_Data *sd);
134 static int  _smart_scrollbar_bar_h_visibility_adjust(Smart_Data *sd);
135 static int  _smart_scrollbar_bar_v_visibility_adjust(Smart_Data *sd);
136 static void _smart_scrollbar_bar_visibility_adjust(Smart_Data *sd);
137 static void _smart_scrollbar_size_adjust(Smart_Data *sd);
138 static void _smart_reconfigure(Smart_Data *sd);
139 static void _smart_add(Evas_Object *obj);
140 static void _smart_del(Evas_Object *obj);
141 static void _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
142 static void _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
143 static void _smart_show(Evas_Object *obj);
144 static void _smart_hide(Evas_Object *obj);
145 static void _smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
146 static void _smart_clip_set(Evas_Object *obj, Evas_Object *clip);
147 static void _smart_clip_unset(Evas_Object *obj);
148 static void _smart_init(void);
149
150 /* local subsystem globals */
151 static Evas_Smart *_smart = NULL;
152
153 /* externally accessible functions */
154 Evas_Object *
155 elm_smart_scroller_add(Evas *evas)
156 {
157    _smart_init();
158    return evas_object_smart_add(evas, _smart);
159 }
160
161 static Evas_Coord
162 _elm_smart_scroller_x_mirrored_get(Evas_Object *obj, Evas_Coord x)
163 {
164    API_ENTRY return x;
165
166    Evas_Coord cw, ch, w, ret;
167    elm_smart_scroller_child_viewport_size_get(obj, &w, NULL);
168    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
169    ret = (cw - (x + w));
170    return (ret >= 0) ? ret : 0;
171 }
172
173 void
174 elm_smart_scroller_mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
175 {
176    API_ENTRY return;
177    Evas_Coord wx;
178    if (sd->is_mirrored == mirrored)
179      return;
180
181    sd->is_mirrored = mirrored;
182    edje_object_mirrored_set(sd->edje_obj, mirrored);
183
184    if (sd->is_mirrored)
185      wx = _elm_smart_scroller_x_mirrored_get(sd->smart_obj, sd->wx);
186    else
187      wx = sd->wx;
188
189    elm_smart_scroller_child_pos_set(sd->smart_obj, wx, sd->wy);
190 }
191
192 void
193 elm_smart_scroller_child_set(Evas_Object *obj, Evas_Object *child)
194 {
195    Evas_Coord w, h;
196    Evas_Object *o;
197
198    API_ENTRY return;
199    if (sd->child_obj)
200      {
201         _elm_smart_pan_child_set(sd->pan_obj, NULL);
202         evas_object_event_callback_del_full(sd->child_obj, EVAS_CALLBACK_DEL, _smart_child_del_hook, sd);
203      }
204
205    sd->child_obj = child;
206    sd->wx = sd->wy = 0;
207    /* (-1) means want viewports size */
208    sd->ww = sd->wh = -1;
209    if (!child) return;
210
211    if (!sd->pan_obj)
212      {
213         o = _elm_smart_pan_add(evas_object_evas_get(obj));
214         sd->pan_obj = o;
215         evas_object_smart_callback_add(o, "changed", _smart_pan_changed_hook, sd);
216         evas_object_smart_callback_add(o, "pan_changed", _smart_pan_pan_changed_hook, sd);
217         edje_object_part_swallow(sd->edje_obj, "elm.swallow.content", o);
218      }
219
220    sd->pan_func.set = _elm_smart_pan_set;
221    sd->pan_func.get = _elm_smart_pan_get;
222    sd->pan_func.max_get = _elm_smart_pan_max_get;
223    sd->pan_func.min_get = _elm_smart_pan_min_get;
224    sd->pan_func.child_size_get = _elm_smart_pan_child_size_get;
225
226    evas_object_event_callback_add(child, EVAS_CALLBACK_DEL, _smart_child_del_hook, sd);
227    _elm_smart_pan_child_set(sd->pan_obj, child);
228    sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
229    sd->child.w = w;
230    sd->child.h = h;
231    _smart_scrollbar_size_adjust(sd);
232    _smart_scrollbar_reset(sd);
233 }
234
235 void
236 elm_smart_scroller_extern_pan_set(Evas_Object *obj, Evas_Object *pan,
237                                   void (*pan_set) (Evas_Object *obj, Evas_Coord x, Evas_Coord y),
238                                   void (*pan_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
239                                   void (*pan_max_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
240                                   void (*pan_min_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
241                                   void (*pan_child_size_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y))
242 {
243    API_ENTRY return;
244
245    elm_smart_scroller_child_set(obj, NULL);
246
247    if (sd->pan_obj)
248      {
249         evas_object_smart_callback_del(sd->pan_obj, "changed", _smart_pan_changed_hook);
250         evas_object_smart_callback_del(sd->pan_obj, "pan_changed", _smart_pan_pan_changed_hook);
251      }
252
253    if (sd->extern_pan)
254      {
255         if (sd->pan_obj)
256           {
257              edje_object_part_unswallow(sd->edje_obj, sd->pan_obj);
258              sd->pan_obj = NULL;
259           }
260      }
261    else
262      {
263         if (sd->pan_obj)
264           {
265              evas_object_del(sd->pan_obj);
266              sd->pan_obj = NULL;
267           }
268      }
269    if (!pan)
270      {
271         sd->extern_pan = 0;
272         return;
273      }
274
275    sd->pan_obj = pan;
276    sd->pan_func.set = pan_set;
277    sd->pan_func.get = pan_get;
278    sd->pan_func.max_get = pan_max_get;
279    sd->pan_func.min_get = pan_min_get;
280    sd->pan_func.child_size_get = pan_child_size_get;
281    sd->extern_pan = 1;
282    evas_object_smart_callback_add(sd->pan_obj, "changed", _smart_pan_changed_hook, sd);
283    evas_object_smart_callback_add(sd->pan_obj, "pan_changed", _smart_pan_pan_changed_hook, sd);
284    edje_object_part_swallow(sd->edje_obj, "elm.swallow.content", sd->pan_obj);
285    evas_object_show(sd->pan_obj);
286 }
287
288 void
289 elm_smart_scroller_custom_edje_file_set(Evas_Object *obj, char *file, char *group)
290 {
291    API_ENTRY return;
292
293    edje_object_file_set(sd->edje_obj, file, group);
294    if (sd->pan_obj)
295      edje_object_part_swallow(sd->edje_obj, "elm.swallow.content", sd->pan_obj);
296    sd->vbar_visible = !sd->vbar_visible;
297    sd->hbar_visible = !sd->hbar_visible;
298    _smart_scrollbar_bar_visibility_adjust(sd);
299    if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
300      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,hbar", "elm");
301    else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
302      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
303    else
304      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,hbar", "elm");
305    if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
306      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,vbar", "elm");
307    else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
308      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
309    else
310      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,vbar", "elm");
311 }
312
313 Eina_Bool
314 elm_smart_scroller_momentum_animator_disabled_get(Evas_Object *obj)
315 {
316    API_ENTRY return EINA_FALSE;
317    return sd->momentum_animator_disabled;
318 }
319
320 void
321 elm_smart_scroller_momentum_animator_disabled_set(Evas_Object *obj, Eina_Bool disabled)
322 {
323    API_ENTRY return;
324    sd->momentum_animator_disabled = disabled;
325    if (sd->momentum_animator_disabled)
326      {
327         if (sd->down.momentum_animator)
328           {
329              ecore_animator_del(sd->down.momentum_animator);
330              sd->down.momentum_animator = NULL;
331           }
332      }
333 }
334
335 Eina_Bool
336 elm_smart_scroller_bounce_animator_disabled_get(Evas_Object *obj)
337 {
338    API_ENTRY return EINA_FALSE;
339    return sd->bounce_animator_disabled;
340 }
341
342 void
343 elm_smart_scroller_bounce_animator_disabled_set(Evas_Object *obj, Eina_Bool disabled)
344 {
345    API_ENTRY return;
346    sd->bounce_animator_disabled = disabled;
347    if (sd->bounce_animator_disabled)
348      {
349         if (sd->scrollto.x.animator)
350           {
351              ecore_animator_del(sd->scrollto.x.animator);
352              sd->scrollto.x.animator = NULL;
353           }
354
355         if (sd->scrollto.y.animator)
356           {
357              ecore_animator_del(sd->scrollto.y.animator);
358              sd->scrollto.y.animator = NULL;
359           }
360      }
361 }
362
363 Eina_Bool
364 elm_smart_scroller_wheel_disabled_get(Evas_Object *obj)
365 {
366    API_ENTRY return EINA_FALSE;
367    return sd->wheel_disabled;
368 }
369
370 void
371 elm_smart_scroller_wheel_disabled_set(Evas_Object *obj, Eina_Bool disabled)
372 {
373    API_ENTRY return;
374    if ((!sd->wheel_disabled) && (disabled))
375      evas_object_event_callback_del_full(sd->event_obj, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
376    else if ((sd->wheel_disabled) && (!disabled))
377      evas_object_event_callback_add(sd->event_obj, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
378    sd->wheel_disabled = disabled;
379 }
380
381 /* Update the wanted coordinates according to the x, y passed
382  * widget directionality, child size and etc. */
383 static void
384 _update_wanted_coordinates(Smart_Data *sd, Evas_Coord x, Evas_Coord y)
385 {
386    Evas_Coord cw, ch;
387
388    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
389
390    /* Update wx/y/w/h - and if the requested positions aren't legal
391     * adjust a bit. */
392    elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &sd->ww, &sd->wh);
393    if (x < 0)
394       sd->wx = 0;
395    else if ((x + sd->ww) > cw)
396       sd->wx = cw - sd->ww;
397    else if (sd->is_mirrored)
398       sd->wx = _elm_smart_scroller_x_mirrored_get(sd->smart_obj, x);
399    else
400       sd->wx = x;
401    if (y < 0) sd->wy = 0;
402    else if ((y + sd->wh) > ch) sd->wy = ch - sd->wh;
403    else sd->wy = y;
404 }
405
406 static void
407 _smart_anim_start(Evas_Object *obj)
408 {
409    evas_object_smart_callback_call(obj, "animate,start", NULL);
410 }
411
412 static void
413 _smart_anim_stop(Evas_Object *obj)
414 {
415    evas_object_smart_callback_call(obj, "animate,stop", NULL);
416 }
417
418 static void
419 _smart_drag_start(Evas_Object *obj)
420 {
421    evas_object_smart_callback_call(obj, "drag,start", NULL);
422 }
423
424 static void
425 _smart_drag_stop(Evas_Object *obj)
426 {
427    evas_object_smart_callback_call(obj, "drag,stop", NULL);
428 }
429
430 static Eina_Bool
431 _smart_scrollto_x_animator(void *data)
432 {
433    Smart_Data *sd = data;
434    Evas_Coord px, py;
435    double t, tt;
436
437    t = ecore_loop_time_get();
438    tt = (t - sd->scrollto.x.t_start) / (sd->scrollto.x.t_end - sd->scrollto.x.t_start);
439    tt = 1.0 - tt;
440    tt = 1.0 - (tt * tt);
441    sd->pan_func.get(sd->pan_obj, &px, &py);
442    px = (sd->scrollto.x.start * (1.0 - tt)) +
443      (sd->scrollto.x.end * tt);
444    if (t >= sd->scrollto.x.t_end)
445      {
446         px = sd->scrollto.x.end;
447         elm_smart_scroller_child_pos_set(sd->smart_obj, px, py);
448         sd->scrollto.x.animator = NULL;
449         if ((!sd->scrollto.y.animator) && (!sd->down.bounce_y_animator))
450           _smart_anim_stop(sd->smart_obj);
451         return ECORE_CALLBACK_CANCEL;
452      }
453    elm_smart_scroller_child_pos_set(sd->smart_obj, px, py);
454    return ECORE_CALLBACK_RENEW;
455 }
456
457 static void
458 _smart_momentum_end(Smart_Data *sd)
459 {
460    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator)) return;
461    if (sd->down.momentum_animator)
462      {
463         Evas_Coord px, py;
464         elm_smart_scroller_child_pos_get(sd->smart_obj, &px, &py);
465         _update_wanted_coordinates(sd, px, py);
466
467         ecore_animator_del(sd->down.momentum_animator);
468         sd->down.momentum_animator = NULL;
469         sd->down.bounce_x_hold = 0;
470         sd->down.bounce_y_hold = 0;
471         sd->down.ax = 0;
472         sd->down.ay = 0;
473         sd->down.pdx = 0;
474         sd->down.pdy = 0;
475      }
476 }
477
478 static void
479 _smart_scrollto_x(Smart_Data *sd, double t_in, Evas_Coord pos_x)
480 {
481    Evas_Coord px, py, x, y, w, h;
482    double t;
483
484    if (sd->freeze) return;
485    if (t_in <= 0.0)
486      {
487         elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
488         elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &w, &h);
489         x = pos_x;
490         elm_smart_scroller_child_region_set(sd->smart_obj, x, y, w, h);
491         return;
492      }
493    t = ecore_loop_time_get();
494    sd->pan_func.get(sd->pan_obj, &px, &py);
495    sd->scrollto.x.start = px;
496    sd->scrollto.x.end = pos_x;
497    sd->scrollto.x.t_start = t;
498    sd->scrollto.x.t_end = t + t_in;
499    if (!sd->scrollto.x.animator)
500      {
501         if (!sd->scrollto.y.animator)
502           _smart_anim_start(sd->smart_obj);
503         sd->scrollto.x.animator = ecore_animator_add(_smart_scrollto_x_animator, sd);
504      }
505    if (sd->down.bounce_x_animator)
506      {
507         ecore_animator_del(sd->down.bounce_x_animator);
508         sd->down.bounce_x_animator = NULL;
509         _smart_momentum_end(sd);
510      }
511    sd->bouncemex = 0;
512 }
513
514 static Eina_Bool
515 _smart_scrollto_y_animator(void *data)
516 {
517    Smart_Data *sd = data;
518    Evas_Coord px, py;
519    double t, tt;
520
521    t = ecore_loop_time_get();
522    tt = (t - sd->scrollto.y.t_start) / (sd->scrollto.y.t_end - sd->scrollto.y.t_start);
523    tt = 1.0 - tt;
524    tt = 1.0 - (tt * tt);
525    sd->pan_func.get(sd->pan_obj, &px, &py);
526    py = (sd->scrollto.y.start * (1.0 - tt)) +
527      (sd->scrollto.y.end * tt);
528    if (t >= sd->scrollto.y.t_end)
529      {
530         py = sd->scrollto.y.end;
531         elm_smart_scroller_child_pos_set(sd->smart_obj, px, py);
532         sd->scrollto.y.animator = NULL;
533         if ((!sd->scrollto.x.animator) && (!sd->down.bounce_x_animator))
534           _smart_anim_stop(sd->smart_obj);
535         return ECORE_CALLBACK_CANCEL;
536      }
537    elm_smart_scroller_child_pos_set(sd->smart_obj, px, py);
538
539    return ECORE_CALLBACK_RENEW;
540 }
541
542 static void
543 _smart_scrollto_y(Smart_Data *sd, double t_in, Evas_Coord pos_y)
544 {
545    Evas_Coord px, py, x, y, w, h;
546    double t;
547
548    if (sd->freeze) return;
549    if (t_in <= 0.0)
550      {
551         elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
552         elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &w, &h);
553         y = pos_y;
554         elm_smart_scroller_child_region_set(sd->smart_obj, x, y, w, h);
555         return;
556      }
557    t = ecore_loop_time_get();
558    sd->pan_func.get(sd->pan_obj, &px, &py);
559    sd->scrollto.y.start = py;
560    sd->scrollto.y.end = pos_y;
561    sd->scrollto.y.t_start = t;
562    sd->scrollto.y.t_end = t + t_in;
563    if (!sd->scrollto.y.animator)
564      {
565         if (!sd->scrollto.x.animator)
566           _smart_anim_start(sd->smart_obj);
567         sd->scrollto.y.animator = ecore_animator_add(_smart_scrollto_y_animator, sd);
568      }
569    if (sd->down.bounce_y_animator)
570      {
571         ecore_animator_del(sd->down.bounce_y_animator);
572         sd->down.bounce_y_animator = NULL;
573         _smart_momentum_end(sd);
574      }
575    sd->bouncemey = 0;
576 }
577
578 static Eina_Bool
579 _smart_do_page(Smart_Data *sd)
580 {
581    if ((sd->pagerel_h == 0.0) && (!sd->pagesize_h) &&
582        (sd->pagerel_v == 0.0) && (!sd->pagesize_v))
583      return EINA_FALSE;
584    return EINA_TRUE;
585 }
586
587 static Evas_Coord
588 _smart_page_x_get(Smart_Data *sd, int offset)
589 {
590    Evas_Coord x, y, w, h, cw, ch, minx = 0;
591
592    elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
593    elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &w, &h);
594    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
595    sd->pan_func.min_get(sd->pan_obj, &minx, NULL);
596
597    x += offset;
598
599    if (sd->pagerel_h > 0.0)
600      {
601         x = x + (w * sd->pagerel_h * 0.5);
602         x = x / (w * sd->pagerel_h);
603         x = x * (w * sd->pagerel_h);
604      }
605    else if (sd->pagesize_h > 0)
606      {
607         x = x + (sd->pagesize_h * 0.5);
608         x = x / (sd->pagesize_h);
609         x = x * (sd->pagesize_h);
610      }
611    if ((x + w) > cw) x = cw - w;
612    if (x < minx) x = minx;
613    return x;
614 }
615
616 static Evas_Coord
617 _smart_page_y_get(Smart_Data *sd, int offset)
618 {
619    Evas_Coord x, y, w, h, cw, ch, miny = 0;
620
621    elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
622    elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &w, &h);
623    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
624    sd->pan_func.min_get(sd->pan_obj, NULL, &miny);
625
626    y += offset;
627
628    if (sd->pagerel_v > 0.0)
629      {
630         y = y + (h * sd->pagerel_v * 0.5);
631         y = y / (h * sd->pagerel_v);
632         y = y * (h * sd->pagerel_v);
633      }
634    else if (sd->pagesize_v > 0)
635      {
636         y = y + (sd->pagesize_v * 0.5);
637         y = y / (sd->pagesize_v);
638         y = y * (sd->pagesize_v);
639      }
640    if ((y + h) > ch) y = ch - h;
641    if (y < miny) y = miny;
642    return y;
643 }
644
645 static void
646 _smart_page_adjust(Smart_Data *sd)
647 {
648    Evas_Coord x, y, w, h;
649
650    if (!_smart_do_page(sd)) return;
651
652    elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &w, &h);
653
654    x = _smart_page_x_get(sd, 0);
655    y = _smart_page_y_get(sd, 0);
656
657    elm_smart_scroller_child_region_set(sd->smart_obj, x, y, w, h);
658 }
659
660 static Eina_Bool
661 _smart_bounce_x_animator(void *data)
662 {
663    Smart_Data *sd;
664    Evas_Coord x, y, dx;
665    double t, p, dt;
666
667    sd = data;
668    t = ecore_loop_time_get();
669    dt = t - sd->down.anim_start2;
670    if (dt >= 0.0)
671      {
672         dt = dt / _elm_config->thumbscroll_bounce_friction;
673         if (dt > 1.0) dt = 1.0;
674         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
675         elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
676         dx = sd->down.b2x - sd->down.bx;
677         dx = (dx * p);
678         x = sd->down.bx + dx;
679         if (!sd->down.cancelled)
680           elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
681         if (dt >= 1.0)
682           {
683              if (sd->down.momentum_animator)
684                sd->down.bounce_x_hold = 1;
685              else if ((!sd->down.bounce_y_animator) &&
686                       (!sd->scrollto.y.animator))
687                _smart_anim_stop(sd->smart_obj);
688              sd->down.bounce_x_animator = NULL;
689              sd->down.pdx = 0;
690              sd->bouncemex = 0;
691              _smart_momentum_end(sd);
692              return ECORE_CALLBACK_CANCEL;
693           }
694      }
695    return ECORE_CALLBACK_RENEW;
696 }
697
698 static Eina_Bool
699 _smart_bounce_y_animator(void *data)
700 {
701    Smart_Data *sd;
702    Evas_Coord x, y, dy;
703    double t, p, dt;
704
705    sd = data;
706    t = ecore_loop_time_get();
707    dt = t - sd->down.anim_start3;
708    if (dt >= 0.0)
709      {
710         dt = dt / _elm_config->thumbscroll_bounce_friction;
711         if (dt > 1.0) dt = 1.0;
712         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
713         elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
714         dy = sd->down.b2y - sd->down.by;
715         dy = (dy * p);
716         y = sd->down.by + dy;
717         if (!sd->down.cancelled)
718           elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
719         if (dt >= 1.0)
720           {
721              if (sd->down.momentum_animator)
722                sd->down.bounce_y_hold = 1;
723              else if ((!sd->down.bounce_x_animator) &&
724                  (!sd->scrollto.y.animator))
725                _smart_anim_stop(sd->smart_obj);
726              sd->down.bounce_y_animator = NULL;
727              sd->down.pdy = 0;
728              sd->bouncemey = 0;
729              _smart_momentum_end(sd);
730              return ECORE_CALLBACK_CANCEL;
731           }
732      }
733    return ECORE_CALLBACK_RENEW;
734 }
735
736 #define LEFT 0
737 #define RIGHT 1
738 #define UP 2
739 #define DOWN 3
740 static Eina_Bool
741 can_scroll(Smart_Data *sd, int dir)
742 {
743    Evas_Coord mx = 0, my = 0, px = 0, py = 0, minx = 0, miny = 0;
744
745    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
746    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
747    sd->pan_func.get(sd->pan_obj, &px, &py);
748    switch (dir)
749      {
750      case LEFT:
751         if (px > minx) return EINA_TRUE;
752         break;
753      case RIGHT:
754         if ((px - minx) < mx) return EINA_TRUE;
755         break;
756      case UP:
757         if (py > miny) return EINA_TRUE;
758         break;
759      case DOWN:
760         if ((py - miny) < my) return EINA_TRUE;
761         break;
762      default:
763         break;
764      }
765    return EINA_FALSE;
766 }
767
768 static Eina_Bool
769 _smart_momentum_animator(void *data)
770 {
771    Smart_Data *sd;
772    double t, dt, p;
773    Evas_Coord x, y, dx, dy, px, py, maxx, maxy, minx, miny;
774    Eina_Bool no_bounce_x_end = EINA_FALSE, no_bounce_y_end = EINA_FALSE;
775
776    sd = data;
777    t = ecore_loop_time_get();
778    dt = t - sd->down.anim_start;
779    if (dt >= 0.0)
780      {
781         /*
782         if (sd->down.hold_parent)
783           {
784              if ((sd->down.dir_x) && !can_scroll(sd, sd->down.hdir))
785                {
786                   sd->down.dir_x = 0;
787                }
788              if ((sd->down.dir_y) && !can_scroll(sd, sd->down.vdir))
789                {
790                   sd->down.dir_y = 0;
791                   }
792                   }
793                   if ((!sd->down.dir_x) && (!sd->down.dir_y))
794                   {
795                   sd->down.cancelled = 1;
796                   }
797          */
798         dt = dt / (_elm_config->thumbscroll_friction + sd->down.extra_time);
799         if (dt > 1.0) dt = 1.0;
800         p = 1.0 - ((1.0 - dt) * (1.0 - dt));
801         dx = (sd->down.dx * (_elm_config->thumbscroll_friction + sd->down.extra_time) * p);
802         dy = (sd->down.dy * (_elm_config->thumbscroll_friction + sd->down.extra_time) * p);
803         sd->down.ax = dx;
804         sd->down.ay = dy;
805         x = sd->down.sx - dx;
806         y = sd->down.sy - dy;
807         elm_smart_scroller_child_pos_get(sd->smart_obj, &px, &py);
808         if ((sd->down.bounce_x_animator) ||
809             (sd->down.bounce_x_hold))
810           {
811              sd->down.bx = sd->down.bx0 - dx + sd->down.b0x;
812              x = px;
813           }
814         if ((sd->down.bounce_y_animator) ||
815             (sd->down.bounce_y_hold))
816           {
817              sd->down.by = sd->down.by0 - dy + sd->down.b0y;
818              y = py;
819           }
820         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
821         _update_wanted_coordinates(sd, x, y);
822         sd->pan_func.max_get(sd->pan_obj, &maxx, &maxy);
823         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
824         if (!sd->bounce_horiz)
825           {
826              if (x <= minx) no_bounce_x_end = EINA_TRUE;
827              if ((x - minx) >= maxx) no_bounce_x_end = EINA_TRUE;
828           }
829         if (!sd->bounce_vert)
830           {
831              if (y <= miny) no_bounce_y_end = EINA_TRUE;
832              if ((y - miny) >= maxy) no_bounce_y_end = EINA_TRUE;
833           }
834         if ((dt >= 1.0) ||
835             ((sd->down.bounce_x_hold) && (sd->down.bounce_y_hold)) ||
836             (no_bounce_x_end && no_bounce_y_end))
837           {
838              _smart_anim_stop(sd->smart_obj);
839
840              sd->down.momentum_animator = NULL;
841              sd->down.bounce_x_hold = 0;
842              sd->down.bounce_y_hold = 0;
843              sd->down.ax = 0;
844              sd->down.ay = 0;
845              sd->down.pdx = 0;
846              sd->down.pdy = 0;
847              return ECORE_CALLBACK_CANCEL;
848           }
849      }
850    return ECORE_CALLBACK_RENEW;
851 }
852
853 static void
854 bounce_eval(Smart_Data *sd)
855 {
856    Evas_Coord mx, my, px, py, bx, by, b2x, b2y, minx = 0, miny = 0;
857
858    if (sd->freeze) return;
859    if ((!sd->bouncemex) && (!sd->bouncemey)) return;
860    if (sd->down.now) return; // down bounce while still held down
861    if (sd->down.onhold_animator)
862      {
863         ecore_animator_del(sd->down.onhold_animator);
864         sd->down.onhold_animator = NULL;
865      }
866    if (sd->down.hold_animator)
867      {
868         ecore_animator_del(sd->down.hold_animator);
869         sd->down.hold_animator = NULL;
870      }
871    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
872    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
873    sd->pan_func.get(sd->pan_obj, &px, &py);
874    bx = px;
875    by = py;
876    if (px < minx) px = minx;
877    if ((px - minx) > mx) px = mx + minx;
878    if (py < miny) py = miny;
879    if ((py - miny) > my) py = my + miny;
880    b2x = px;
881    b2y = py;
882    if ((!sd->widget) ||
883        (!elm_widget_drag_child_locked_x_get(sd->widget)))
884      {
885         if ((!sd->down.bounce_x_animator) && (!sd->bounce_animator_disabled))
886           {
887              if (sd->bouncemex)
888                {
889                   if (sd->scrollto.x.animator)
890                     {
891                        ecore_animator_del(sd->scrollto.x.animator);
892                        sd->scrollto.x.animator = NULL;
893                     }
894                   sd->down.bounce_x_animator = ecore_animator_add(_smart_bounce_x_animator, sd);
895                   sd->down.anim_start2 = ecore_loop_time_get();
896                   sd->down.bx = bx;
897                   sd->down.bx0 = bx;
898                   sd->down.b2x = b2x;
899                   if (sd->down.momentum_animator) sd->down.b0x = sd->down.ax;
900                   else sd->down.b0x = 0;
901                }
902           }
903      }
904    if ((!sd->widget) ||
905        (!elm_widget_drag_child_locked_y_get(sd->widget)))
906      {
907         if ((!sd->down.bounce_y_animator) && (!sd->bounce_animator_disabled))
908           {
909              if (sd->bouncemey)
910                {
911                   if (sd->scrollto.y.animator)
912                     {
913                        ecore_animator_del(sd->scrollto.y.animator);
914                        sd->scrollto.y.animator = NULL;
915                     }
916                   sd->down.bounce_y_animator = ecore_animator_add(_smart_bounce_y_animator, sd);
917                   sd->down.anim_start3 = ecore_loop_time_get();
918                   sd->down.by = by;
919                   sd->down.by0 = by;
920                   sd->down.b2y = b2y;
921                   if (sd->down.momentum_animator) sd->down.b0y = sd->down.ay;
922                   else sd->down.b0y = 0;
923                }
924           }
925      }
926 }
927
928 void
929 elm_smart_scroller_child_pos_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
930 {
931    Evas_Coord mx = 0, my = 0, px = 0, py = 0, minx = 0, miny = 0;
932    double vx, vy;
933
934    API_ENTRY return;
935    // FIXME: allow for bounce outside of range
936    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
937    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
938    if (mx > 0) vx = (double)(x - minx) / (double)mx;
939    else vx = 0.0;
940    if (vx < 0.0) vx = 0.0;
941    else if (vx > 1.0) vx = 1.0;
942    if (my > 0) vy = (double)(y - miny) / (double)my;
943    else vy = 0.0;
944    if (vy < 0.0) vy = 0.0;
945    else if (vy > 1.0) vy = 1.0;
946    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, vy);
947    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", vx, 0.0);
948    sd->pan_func.get(sd->pan_obj, &px, &py);
949    if (!_elm_config->thumbscroll_bounce_enable)
950      {
951         if (x < minx) x = minx;
952         if ((x - minx) > mx) x = mx + minx;
953         if (y < miny) y = miny;
954         if ((y - miny) > my) y = my + miny;
955      }
956
957    if (!sd->bounce_horiz)
958      {
959         if (x < minx) x = minx;
960         if ((x - minx) > mx) x = mx + minx;
961      }
962    if (!sd->bounce_vert)
963      {
964         if (y < miny) y = miny;
965         if (y - miny > my) y = my + miny;
966      }
967
968    sd->pan_func.set(sd->pan_obj, x, y);
969    if ((px != x) || (py != y))
970      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
971    if (!sd->down.bounce_x_animator)
972      {
973         if ((x < minx) || (x > (mx + minx)))
974           {
975              sd->bouncemex = 1;
976              bounce_eval(sd);
977           }
978      }
979    if (!sd->down.bounce_y_animator)
980      {
981         if ((y < miny) || (y > my + miny))
982           {
983              sd->bouncemey = 1;
984              bounce_eval(sd);
985           }
986      }
987    if ((x != px) || (y != py))
988      {
989         evas_object_smart_callback_call(obj, "scroll", NULL);
990      }
991    if ((x != px)/* && (!sd->bouncemex)*/)
992      {
993         if (x == minx)
994           evas_object_smart_callback_call(obj, "edge,left", NULL);
995         if (x == (mx + minx))
996           evas_object_smart_callback_call(obj, "edge,right", NULL);
997      }
998    if ((y != py)/* && (!sd->bouncemey)*/)
999      {
1000         if (y == miny)
1001           evas_object_smart_callback_call(obj, "edge,top", NULL);
1002         if (y == my + miny)
1003           evas_object_smart_callback_call(obj, "edge,bottom", NULL);
1004      }
1005 }
1006
1007 void
1008 elm_smart_scroller_child_pos_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1009 {
1010    API_ENTRY return;
1011    sd->pan_func.get(sd->pan_obj, x, y);
1012 }
1013
1014 /* returns TRUE when we need to move the scroller, FALSE otherwise.
1015  * Updates w and h either way, so save them if you need them. */
1016 static Eina_Bool
1017 _elm_smart_scroller_child_region_show_internal(Evas_Object *obj, Evas_Coord *_x, Evas_Coord *_y, Evas_Coord w, Evas_Coord h)
1018 {
1019    Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny, minx = 0, miny = 0, pw = 0, ph = 0, x = *_x, y = *_y;
1020
1021    API_ENTRY return EINA_FALSE;
1022    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
1023    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
1024    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
1025    sd->pan_func.get(sd->pan_obj, &px, &py);
1026    evas_object_geometry_get(sd->pan_obj, NULL, NULL, &pw, &ph);
1027
1028    nx = px;
1029    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1030    else if ((x > px) && ((x + w) > (px + (cw - mx)))) nx = x + w - (cw - mx);
1031    ny = py;
1032    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1033    else if ((y > py) && ((y + h) > (py + (ch - my)))) ny = y + h - (ch - my);
1034
1035    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1036        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1037      {
1038         _smart_anim_stop(sd->smart_obj);
1039      }
1040    if (sd->scrollto.x.animator)
1041      {
1042         ecore_animator_del(sd->scrollto.x.animator);
1043         sd->scrollto.x.animator = NULL;
1044      }
1045    if (sd->scrollto.y.animator)
1046      {
1047         ecore_animator_del(sd->scrollto.y.animator);
1048         sd->scrollto.y.animator = NULL;
1049      }
1050    if (sd->down.bounce_x_animator)
1051      {
1052         ecore_animator_del(sd->down.bounce_x_animator);
1053         sd->down.bounce_x_animator = NULL;
1054         sd->bouncemex = 0;
1055      }
1056    if (sd->down.bounce_y_animator)
1057      {
1058         ecore_animator_del(sd->down.bounce_y_animator);
1059         sd->down.bounce_y_animator = NULL;
1060         sd->bouncemey = 0;
1061      }
1062    if (sd->down.hold_animator)
1063      {
1064         ecore_animator_del(sd->down.hold_animator);
1065         sd->down.hold_animator = NULL;
1066         _smart_drag_stop(sd->smart_obj);
1067      }
1068    if (sd->down.momentum_animator)
1069      {
1070         ecore_animator_del(sd->down.momentum_animator);
1071         sd->down.momentum_animator = NULL;
1072         sd->down.bounce_x_hold = 0;
1073         sd->down.bounce_y_hold = 0;
1074         sd->down.ax = 0;
1075         sd->down.ay = 0;
1076         sd->down.pdx = 0;
1077         sd->down.pdy = 0;
1078      }
1079
1080    x = nx;
1081    if ((x + pw) > cw) x = cw - pw;
1082    if (x < minx) x = minx;
1083    y = ny;
1084    if ((y + ph) > ch) y = ch - ph;
1085    if (y < miny) y = miny;
1086
1087    if ((x == px) && (y == py)) return EINA_FALSE;
1088    *_x = x;
1089    *_y = y;
1090    return EINA_TRUE;
1091 }
1092
1093 /* Set should be used for calculated positions, for example, when we move
1094  * because of an animation or because this is the correct position after
1095  * constraints. */
1096 void
1097 elm_smart_scroller_child_region_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1098 {
1099    if (_elm_smart_scroller_child_region_show_internal(obj, &x, &y, w, h))
1100       elm_smart_scroller_child_pos_set(obj, x, y);
1101 }
1102
1103 /* Set should be used for setting the wanted position, for example a user scroll
1104  * or moving the cursor in an entry. */
1105 void
1106 elm_smart_scroller_child_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1107 {
1108    API_ENTRY return;
1109    sd->wx = x;
1110    sd->wy = y;
1111    sd->ww = w;
1112    sd->wh = h;
1113    if (_elm_smart_scroller_child_region_show_internal(obj, &x, &y, w, h))
1114       elm_smart_scroller_child_pos_set(obj, x, y);
1115 }
1116
1117 void
1118 elm_smart_scroller_child_viewport_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
1119 {
1120    API_ENTRY return;
1121    if (!sd->pan_obj) return;
1122    edje_object_calc_force(sd->edje_obj);
1123    evas_object_geometry_get(sd->pan_obj, NULL, NULL, w, h);
1124 }
1125
1126 void
1127 elm_smart_scroller_step_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1128 {
1129    API_ENTRY return;
1130    if (x < 1) x = 1;
1131    if (y < 1) y = 1;
1132    sd->step.x = x;
1133    sd->step.y = y;
1134    _smart_scrollbar_size_adjust(sd);
1135 }
1136
1137 void
1138 elm_smart_scroller_step_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1139 {
1140    API_ENTRY return;
1141    if (x) *x = sd->step.x;
1142    if (y) *y = sd->step.y;
1143 }
1144
1145 void
1146 elm_smart_scroller_page_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1147 {
1148    API_ENTRY return;
1149    sd->page.x = x;
1150    sd->page.y = y;
1151    _smart_scrollbar_size_adjust(sd);
1152 }
1153
1154 void
1155 elm_smart_scroller_page_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1156 {
1157    API_ENTRY return;
1158    if (x) *x = sd->page.x;
1159    if (y) *y = sd->page.y;
1160 }
1161
1162 void
1163 elm_smart_scroller_policy_set(Evas_Object *obj, Elm_Smart_Scroller_Policy hbar, Elm_Smart_Scroller_Policy vbar)
1164 {
1165    API_ENTRY return;
1166    if ((sd->hbar_flags == hbar) && (sd->vbar_flags == vbar)) return;
1167    sd->hbar_flags = hbar;
1168    sd->vbar_flags = vbar;
1169    if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
1170      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,hbar", "elm");
1171    else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
1172      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
1173    else
1174      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,hbar", "elm");
1175    if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
1176      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,vbar", "elm");
1177    else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
1178      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
1179    else
1180      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,vbar", "elm");
1181    _smart_scrollbar_size_adjust(sd);
1182 }
1183
1184 void
1185 elm_smart_scroller_policy_get(Evas_Object *obj, Elm_Smart_Scroller_Policy *hbar, Elm_Smart_Scroller_Policy *vbar)
1186 {
1187    API_ENTRY return;
1188    if (hbar) *hbar = sd->hbar_flags;
1189    if (vbar) *vbar = sd->vbar_flags;
1190 }
1191
1192 Evas_Object *
1193 elm_smart_scroller_edje_object_get(Evas_Object *obj)
1194 {
1195    API_ENTRY return NULL;
1196    return sd->edje_obj;
1197 }
1198
1199 void
1200 elm_smart_scroller_single_dir_set(Evas_Object *obj, Eina_Bool single_dir)
1201 {
1202    API_ENTRY return;
1203    sd->one_dir_at_a_time = single_dir;
1204 }
1205
1206 Eina_Bool
1207 elm_smart_scroller_single_dir_get(Evas_Object *obj)
1208 {
1209    API_ENTRY return EINA_FALSE;
1210    return sd->one_dir_at_a_time;
1211 }
1212
1213 void
1214 elm_smart_scroller_object_theme_set(Evas_Object *parent, Evas_Object *obj, const char *clas, const char *group, const char *style)
1215 {
1216    API_ENTRY return;
1217    Evas_Coord mw, mh;
1218    //Does this API require parent object absolutely? if then remove this exception.
1219    double parent_scale = parent ? elm_widget_scale_get(parent) : 1;
1220    _elm_theme_object_set(parent, sd->edje_obj, clas, group, style);
1221    edje_object_scale_set(sd->edje_obj, parent_scale * _elm_config->scale);
1222    if (sd->pan_obj)
1223      edje_object_part_swallow(sd->edje_obj, "elm.swallow.content", sd->pan_obj);
1224    mw = mh = -1;
1225    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1226    if (edje_object_part_exists(sd->edje_obj, "elm.scrollbar.base"))
1227      {
1228         Evas_Object *base;
1229         base = edje_object_part_swallow_get(sd->edje_obj, "elm.scrollbar.base");
1230         if (!base)
1231           {
1232              base = evas_object_rectangle_add(evas_object_evas_get(sd->edje_obj));
1233              evas_object_color_set(base, 0, 0, 0, 0);
1234              edje_object_part_swallow(sd->edje_obj, "elm.scrollbar.base", base);
1235           }
1236         if (!_elm_config->thumbscroll_enable)
1237            evas_object_size_hint_min_set(base, mw, mh);
1238      }
1239    sd->vbar_visible = !sd->vbar_visible;
1240    sd->hbar_visible = !sd->hbar_visible;
1241    _smart_scrollbar_bar_visibility_adjust(sd);
1242 }
1243
1244 void
1245 elm_smart_scroller_hold_set(Evas_Object *obj, Eina_Bool hold)
1246 {
1247    API_ENTRY return;
1248    sd->hold = hold;
1249 }
1250
1251 void
1252 elm_smart_scroller_freeze_set(Evas_Object *obj, Eina_Bool freeze)
1253 {
1254    API_ENTRY return;
1255    sd->freeze = freeze;
1256    if (sd->freeze)
1257      {
1258         if (sd->down.onhold_animator)
1259           {
1260              ecore_animator_del(sd->down.onhold_animator);
1261              sd->down.onhold_animator = NULL;
1262           }
1263      }
1264    else
1265      bounce_eval(sd);
1266 }
1267
1268 void
1269 elm_smart_scroller_bounce_allow_set(Evas_Object *obj, Eina_Bool horiz, Eina_Bool vert)
1270 {
1271    API_ENTRY return;
1272    sd->bounce_horiz = horiz;
1273    sd->bounce_vert = vert;
1274 }
1275
1276 void
1277 elm_smart_scroller_bounce_allow_get(const Evas_Object *obj, Eina_Bool *horiz, Eina_Bool *vert)
1278 {
1279    API_ENTRY return;
1280    *horiz = sd->bounce_horiz;
1281    *vert = sd->bounce_vert;
1282 }
1283
1284 void
1285 elm_smart_scroller_paging_set(Evas_Object *obj, double pagerel_h, double pagerel_v, Evas_Coord pagesize_h, Evas_Coord pagesize_v)
1286 {
1287    API_ENTRY return;
1288    sd->pagerel_h = pagerel_h;
1289    sd->pagerel_v = pagerel_v;
1290    sd->pagesize_h = pagesize_h;
1291    sd->pagesize_v = pagesize_v;
1292    _smart_page_adjust(sd);
1293 }
1294
1295 void
1296 elm_smart_scroller_paging_get(Evas_Object *obj, double *pagerel_h, double *pagerel_v, Evas_Coord *pagesize_h, Evas_Coord *pagesize_v)
1297 {
1298    API_ENTRY return;
1299    if(pagerel_h) *pagerel_h = sd->pagerel_h;
1300    if(pagerel_v) *pagerel_v = sd->pagerel_v;
1301    if(pagesize_h) *pagesize_h = sd->pagesize_h;
1302    if(pagesize_v) *pagesize_v = sd->pagesize_v;
1303 }
1304
1305 void
1306 elm_smart_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1307 {
1308    API_ENTRY return;
1309    if (_elm_smart_scroller_child_region_show_internal(obj, &x, &y, w, h))
1310      {
1311         _smart_scrollto_x(sd, _elm_config->bring_in_scroll_friction, x);
1312         _smart_scrollto_y(sd, _elm_config->bring_in_scroll_friction, y);
1313      }
1314 }
1315
1316 void
1317 elm_smart_scroller_widget_set(Evas_Object *obj, Evas_Object *wid)
1318 {
1319    API_ENTRY return;
1320    sd->widget = wid;
1321 }
1322
1323 static void
1324 _elm_smart_scroller_wanted_region_set(Evas_Object *obj)
1325 {
1326    INTERNAL_ENTRY;
1327    Evas_Coord ww, wh, wx = sd->wx;
1328
1329    if (sd->down.now || sd->down.momentum_animator ||
1330        sd->down.bounce_x_animator || sd->down.bounce_y_animator ||
1331        sd->down.hold_animator || sd->down.onhold_animator) return;
1332
1333    /* Flip to RTL cords only if init in RTL mode */
1334    if(sd->is_mirrored)
1335      wx = _elm_smart_scroller_x_mirrored_get(obj, sd->wx);
1336
1337    if (sd->ww == -1)
1338      {
1339         elm_smart_scroller_child_viewport_size_get(obj, &ww, &wh);
1340      }
1341    else
1342      {
1343         ww = sd->ww;
1344         wh = sd->wh;
1345      }
1346
1347    elm_smart_scroller_child_region_set(obj, wx, sd->wy, ww, wh);
1348 }
1349
1350 /* local subsystem functions */
1351 static void
1352 _smart_edje_drag_v_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1353 {
1354    Smart_Data *sd;
1355
1356    sd = data;
1357    _smart_scrollbar_read(sd);
1358    _smart_drag_start(sd->smart_obj);
1359    sd->freeze = EINA_TRUE;
1360 }
1361
1362 static void
1363 _smart_edje_drag_v_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1364 {
1365    Smart_Data *sd;
1366
1367    sd = data;
1368    _smart_scrollbar_read(sd);
1369    _smart_drag_stop(sd->smart_obj);
1370    sd->freeze = EINA_FALSE;
1371 }
1372
1373 static void
1374 _smart_edje_drag_v(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1375 {
1376    Smart_Data *sd;
1377
1378    sd = data;
1379    _smart_scrollbar_read(sd);
1380 }
1381
1382 static void
1383 _smart_edje_drag_h_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1384 {
1385    Smart_Data *sd;
1386
1387    sd = data;
1388    _smart_scrollbar_read(sd);
1389    _smart_drag_start(sd->smart_obj);
1390    sd->freeze = EINA_TRUE;
1391 }
1392
1393 static void
1394 _smart_edje_drag_h_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1395 {
1396    Smart_Data *sd;
1397
1398    sd = data;
1399    _smart_scrollbar_read(sd);
1400    _smart_drag_stop(sd->smart_obj);
1401    sd->freeze = EINA_FALSE;
1402 }
1403
1404 static void
1405 _smart_edje_drag_h(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1406 {
1407    Smart_Data *sd;
1408
1409    sd = data;
1410    _smart_scrollbar_read(sd);
1411 }
1412
1413 static void
1414 _smart_child_del_hook(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1415 {
1416    Smart_Data *sd;
1417
1418    sd = data;
1419    sd->child_obj = NULL;
1420    _smart_scrollbar_size_adjust(sd);
1421    _smart_scrollbar_reset(sd);
1422 }
1423
1424 static void
1425 _smart_pan_changed_hook(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1426 {
1427    Evas_Coord w, h;
1428    Smart_Data *sd;
1429
1430    sd = data;
1431    sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
1432    if ((w != sd->child.w) || (h != sd->child.h))
1433      {
1434         sd->child.w = w;
1435         sd->child.h = h;
1436         _smart_scrollbar_size_adjust(sd);
1437         evas_object_size_hint_min_set(sd->smart_obj, sd->child.w, sd->child.h);
1438         _elm_smart_scroller_wanted_region_set(sd->smart_obj);
1439      }
1440 }
1441
1442 static void
1443 _smart_pan_pan_changed_hook(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1444 {
1445    Smart_Data *sd;
1446
1447    sd = data;
1448    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1449        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1450      {
1451         _smart_anim_stop(sd->smart_obj);
1452      }
1453    if (sd->scrollto.x.animator)
1454      {
1455         ecore_animator_del(sd->scrollto.x.animator);
1456         sd->scrollto.x.animator = NULL;
1457      }
1458    if (sd->scrollto.y.animator)
1459      {
1460         ecore_animator_del(sd->scrollto.y.animator);
1461         sd->scrollto.y.animator = NULL;
1462      }
1463    if (sd->down.bounce_x_animator)
1464      {
1465         ecore_animator_del(sd->down.bounce_x_animator);
1466         sd->down.bounce_x_animator = NULL;
1467         sd->bouncemex = 0;
1468      }
1469    if (sd->down.bounce_y_animator)
1470      {
1471         ecore_animator_del(sd->down.bounce_y_animator);
1472         sd->down.bounce_y_animator = NULL;
1473         sd->bouncemey = 0;
1474      }
1475    _elm_smart_scroller_wanted_region_set(sd->smart_obj);
1476 }
1477
1478 static void
1479 _smart_event_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1480 {
1481    Evas_Event_Mouse_Wheel *ev;
1482    Smart_Data *sd;
1483    Evas_Coord x = 0, y = 0;
1484
1485    sd = data;
1486    ev = event_info;
1487    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1488    if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
1489        (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
1490        (evas_key_modifier_is_set(ev->modifiers, "Shift")) ||
1491        (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
1492        (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
1493        (evas_key_modifier_is_set(ev->modifiers, "Super")))
1494      return;
1495    elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1496    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1497        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1498      {
1499         _smart_anim_stop(sd->smart_obj);
1500      }
1501    if (sd->scrollto.x.animator)
1502      {
1503         ecore_animator_del(sd->scrollto.x.animator);
1504         sd->scrollto.x.animator = NULL;
1505      }
1506    if (sd->scrollto.y.animator)
1507      {
1508         ecore_animator_del(sd->scrollto.y.animator);
1509         sd->scrollto.y.animator = NULL;
1510      }
1511    if (sd->down.bounce_x_animator)
1512      {
1513         ecore_animator_del(sd->down.bounce_x_animator);
1514         sd->down.bounce_x_animator = NULL;
1515         sd->bouncemex = 0;
1516      }
1517    if (sd->down.bounce_y_animator)
1518      {
1519         ecore_animator_del(sd->down.bounce_y_animator);
1520         sd->down.bounce_y_animator = NULL;
1521         sd->bouncemey = 0;
1522      }
1523    if (!ev->direction)
1524      y += ev->z * sd->step.y;
1525    else if (ev->direction == 1)
1526      x += ev->z * sd->step.x;
1527
1528    if ((!sd->hold) && (!sd->freeze))
1529      {
1530         _update_wanted_coordinates(sd, x, y);
1531         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1532      }
1533 }
1534
1535 static void
1536 _smart_event_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1537 {
1538    Evas_Event_Mouse_Down *ev;
1539    Smart_Data *sd;
1540    Evas_Coord x = 0, y = 0;
1541
1542    sd = data;
1543    ev = event_info;
1544    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1545    if (_elm_config->thumbscroll_enable)
1546      {
1547         sd->down.hold = 0;
1548         if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1549             (sd->down.momentum_animator) || (sd->scrollto.x.animator) ||
1550             (sd->scrollto.y.animator))
1551           {
1552              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL | EVAS_EVENT_FLAG_ON_HOLD;
1553              sd->down.scroll = 1;
1554              sd->down.hold = 1;
1555              _smart_anim_stop(sd->smart_obj);
1556           }
1557         if (sd->scrollto.x.animator)
1558           {
1559              ecore_animator_del(sd->scrollto.x.animator);
1560              sd->scrollto.x.animator = NULL;
1561           }
1562         if (sd->scrollto.y.animator)
1563           {
1564              ecore_animator_del(sd->scrollto.y.animator);
1565              sd->scrollto.y.animator = NULL;
1566           }
1567         if (sd->down.bounce_x_animator)
1568           {
1569              ecore_animator_del(sd->down.bounce_x_animator);
1570              sd->down.bounce_x_animator = NULL;
1571              sd->bouncemex = 0;
1572           }
1573         if (sd->down.bounce_y_animator)
1574           {
1575              ecore_animator_del(sd->down.bounce_y_animator);
1576              sd->down.bounce_y_animator = NULL;
1577              sd->bouncemey = 0;
1578           }
1579         if (sd->down.hold_animator)
1580           {
1581              ecore_animator_del(sd->down.hold_animator);
1582              sd->down.hold_animator = NULL;
1583              _smart_drag_stop(sd->smart_obj);
1584           }
1585         if (sd->down.momentum_animator)
1586           {
1587              ecore_animator_del(sd->down.momentum_animator);
1588              sd->down.momentum_animator = NULL;
1589              sd->down.bounce_x_hold = 0;
1590              sd->down.bounce_y_hold = 0;
1591              sd->down.ax = 0;
1592              sd->down.ay = 0;
1593           }
1594         if (ev->button == 1)
1595           {
1596              sd->down.hist.est_timestamp_diff =
1597                 ecore_loop_time_get() - ((double)ev->timestamp / 1000.0);
1598              sd->down.hist.tadd = 0.0;
1599              sd->down.hist.dxsum = 0.0;
1600              sd->down.hist.dysum = 0.0;
1601              sd->down.now = 1;
1602              sd->down.dragged = 0;
1603              sd->down.dir_x = 0;
1604              sd->down.dir_y = 0;
1605              sd->down.x = ev->canvas.x;
1606              sd->down.y = ev->canvas.y;
1607              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1608              sd->down.sx = x;
1609              sd->down.sy = y;
1610              sd->down.locked = 0;
1611              memset(&(sd->down.history[0]), 0, sizeof(sd->down.history[0]) * 60);
1612 #ifdef EVTIME
1613              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
1614              sd->down.history[0].localtimestamp = ecore_loop_time_get();
1615 #else
1616              sd->down.history[0].timestamp = ecore_loop_time_get();
1617 #endif
1618              sd->down.history[0].x = ev->canvas.x;
1619              sd->down.history[0].y = ev->canvas.y;
1620           }
1621         sd->down.dragged_began = 0;
1622         sd->down.hold_parent = 0;
1623         sd->down.cancelled = 0;
1624      }
1625 }
1626
1627 static void
1628 _down_coord_eval(Smart_Data *sd, Evas_Coord *x, Evas_Coord *y)
1629 {
1630    Evas_Coord minx, miny;
1631
1632    if (sd->down.dir_x) *x = sd->down.sx - (*x - sd->down.x);
1633    else *x = sd->down.sx;
1634    if (sd->down.dir_y) *y = sd->down.sy - (*y - sd->down.y);
1635    else *y = sd->down.sy;
1636
1637    if ((sd->down.dir_x) || (sd->down.dir_y))
1638      {
1639         if (!((sd->down.dir_x) && (sd->down.dir_y)))
1640           {
1641              if (sd->down.dir_x) *y = sd->down.locked_y;
1642              else *x = sd->down.locked_x;
1643           }
1644      }
1645
1646    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
1647
1648    if (*x < minx)
1649       *x += (minx - *x) * _elm_config->thumbscroll_border_friction;
1650    else if (sd->child.w <= sd->w)
1651       *x += (sd->down.sx - *x) * _elm_config->thumbscroll_border_friction;
1652    else if ((sd->child.w - sd->w + minx) < *x)
1653       *x += (sd->child.w - sd->w + minx - *x) *
1654       _elm_config->thumbscroll_border_friction;
1655
1656    if (*y < miny)
1657       *y += (miny - *y) * _elm_config->thumbscroll_border_friction;
1658    else if (sd->child.h <= sd->h)
1659       *y += (sd->down.sy - *y) * _elm_config->thumbscroll_border_friction;
1660    else if ((sd->child.h - sd->h + miny) < *y)
1661       *y += (sd->child.h - sd->h + miny - *y) *
1662       _elm_config->thumbscroll_border_friction;
1663 }
1664
1665 static Eina_Bool
1666 _smart_hold_animator(void *data)
1667 {
1668    Smart_Data *sd = data;
1669    Evas_Coord ox = 0, oy = 0, fx, fy;
1670
1671    fx = sd->down.hold_x;
1672    fy = sd->down.hold_y;
1673    if (_elm_config->scroll_smooth_amount > 0.0)
1674      {
1675         int i, count = 0;
1676         Evas_Coord basex = 0, basey = 0, x, y;
1677         double dt, t, tdiff, tnow, twin;
1678         struct {
1679            Evas_Coord x, y, dx, dy;
1680            double t, dt;
1681         } pos[60];
1682
1683         tdiff = sd->down.hist.est_timestamp_diff;
1684         tnow = ecore_time_get() - tdiff;
1685         t = tnow;
1686         twin = _elm_config->scroll_smooth_time_window;
1687         for (i = 0; i < 60; i++)
1688           {
1689              // oldest point is sd->down.history[i]
1690              // newset is sd->down.history[0]
1691              dt = t - sd->down.history[i].timestamp;
1692              if (dt > twin)
1693                {
1694                   i--;
1695                   break;
1696                }
1697              x = sd->down.history[i].x;
1698              y = sd->down.history[i].y;
1699              _down_coord_eval(sd, &x, &y);
1700              if (i == 0)
1701                {
1702                   basex = x;
1703                   basey = y;
1704                }
1705              pos[i].x = x - basex;
1706              pos[i].y = y - basey;
1707              pos[i].t =
1708                 sd->down.history[i].timestamp - sd->down.history[0].timestamp;
1709              count++;
1710           }
1711         count = i;
1712         if (count >= 2)
1713           {
1714              double dtsum = 0.0, tadd, maxdt;
1715              double dxsum = 0.0, dysum = 0.0, xsum = 0.0, ysum = 0.0;
1716
1717              for (i = 0; i < (count - 1); i++)
1718                {
1719                   pos[i].dx = pos[i].x - pos[i + 1].x;
1720                   pos[i].dy = pos[i].y - pos[i + 1].y;
1721                   pos[i].dt = pos[i].t - pos[i + 1].t;
1722                   dxsum += pos[i].dx;
1723                   dysum += pos[i].dy;
1724                   dtsum += pos[i].dt;
1725                   xsum += pos[i].x;
1726                   ysum += pos[i].y;
1727                }
1728              maxdt = pos[i].t;
1729              dxsum /= (double)i;
1730              dysum /= (double)i;
1731              dtsum /= (double)i;
1732              xsum /= (double)i;
1733              ysum /= (double)i;
1734              tadd = tnow - sd->down.history[0].timestamp + _elm_config->scroll_smooth_future_time;
1735              tadd = tadd - (maxdt / 2);
1736 #define WEIGHT(n, o, v) n = (((double)o * (1.0 - v)) + ((double)n * v))
1737              WEIGHT(tadd, sd->down.hist.tadd, _elm_config->scroll_smooth_history_weight);
1738              WEIGHT(dxsum, sd->down.hist.dxsum, _elm_config->scroll_smooth_history_weight);
1739              WEIGHT(dysum, sd->down.hist.dysum, _elm_config->scroll_smooth_history_weight);
1740              fx = basex + xsum + ((dxsum * tadd) / dtsum);
1741              fy = basey + ysum + ((dysum * tadd) / dtsum);
1742              sd->down.hist.tadd = tadd;
1743              sd->down.hist.dxsum = dxsum;
1744              sd->down.hist.dysum = dysum;
1745              WEIGHT(fx, sd->down.hold_x, _elm_config->scroll_smooth_amount);
1746              WEIGHT(fy, sd->down.hold_y, _elm_config->scroll_smooth_amount);
1747           }
1748 //        printf("%3.5f %i %i\n", ecore_time_get(), sd->down.hold_y, fy);
1749      }
1750
1751    elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
1752    if (sd->down.dir_x)
1753      {
1754         if ((!sd->widget) ||
1755             (!elm_widget_drag_child_locked_x_get(sd->widget)))
1756            ox = fx;
1757      }
1758    if (sd->down.dir_y)
1759      {
1760         if ((!sd->widget) ||
1761             (!elm_widget_drag_child_locked_y_get(sd->widget)))
1762            oy = fy;
1763      }
1764
1765    elm_smart_scroller_child_pos_set(sd->smart_obj, ox, oy);
1766    return ECORE_CALLBACK_RENEW;
1767 }
1768
1769 static Eina_Bool
1770 _smart_event_post_up(void *data, Evas *e __UNUSED__)
1771 {
1772    Smart_Data *sd = data;
1773    if (sd->widget)
1774      {
1775         if (sd->down.dragged)
1776           {
1777              elm_widget_drag_lock_x_set(sd->widget, 0);
1778              elm_widget_drag_lock_y_set(sd->widget, 0);
1779           }
1780      }
1781    return EINA_TRUE;
1782 }
1783
1784 static void
1785 _smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
1786 {
1787    Evas_Event_Mouse_Down *ev;
1788    Smart_Data *sd;
1789    Evas_Coord x = 0, y = 0, ox = 0, oy = 0;
1790
1791    sd = data;
1792    ev = event_info;
1793    sd->down.hold_parent = 0;
1794    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1795    evas_post_event_callback_push(e, _smart_event_post_up, sd);
1796    // FIXME: respect elm_widget_scroll_hold_get of parent container
1797    if (_elm_config->thumbscroll_enable)
1798      {
1799         if (ev->button == 1)
1800           {
1801              if (sd->down.onhold_animator)
1802                {
1803                   ecore_animator_del(sd->down.onhold_animator);
1804                   sd->down.onhold_animator = NULL;
1805                }
1806              x = ev->canvas.x - sd->down.x;
1807              y = ev->canvas.y - sd->down.y;
1808              if (sd->down.dragged)
1809                {
1810                   _smart_drag_stop(sd->smart_obj);
1811                   if ((!sd->hold) && (!sd->freeze))
1812                     {
1813                        double t, at, dt;
1814                        int i;
1815                        Evas_Coord ax, ay, dx, dy, vel;
1816
1817 #ifdef EVTIME
1818                        t = ev->timestamp / 1000.0;
1819 #else
1820                        t = ecore_loop_time_get();
1821 #endif
1822                        ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1823                        ax = ev->canvas.x;
1824                        ay = ev->canvas.y;
1825                        at = 0.0;
1826 #ifdef SCROLLDBG
1827                        printf("------ %i %i\n", ev->canvas.x, ev->canvas.y);
1828 #endif
1829                        for (i = 0; i < 60; i++)
1830                          {
1831                             dt = t - sd->down.history[i].timestamp;
1832                             if (dt > 0.2) break;
1833 #ifdef SCROLLDBG
1834                             printf("H: %i %i @ %1.3f\n",
1835                                    sd->down.history[i].x,
1836                                    sd->down.history[i].y, dt);
1837 #endif
1838                             at += dt;
1839                             ax += sd->down.history[i].x;
1840                             ay += sd->down.history[i].y;
1841                          }
1842                        ax /= (i + 1);
1843                        ay /= (i + 1);
1844                        at /= (i + 1);
1845                        at *= 4.0; // magic number! just trial and error shows this makes it behave "nicer" and not run off at high speed all the time
1846                        dx = ev->canvas.x - ax;
1847                        dy = ev->canvas.y - ay;
1848                        if (at > 0)
1849                          {
1850                             vel = sqrt((dx * dx) + (dy * dy)) / at;
1851                             if ((_elm_config->thumbscroll_friction > 0.0) &&
1852                                 (vel > _elm_config->thumbscroll_momentum_threshold))
1853                               {
1854                                  sd->down.dx = ((double)dx / at);
1855                                  sd->down.dy = ((double)dy / at);
1856                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1857                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)))
1858                                    sd->down.dx += (double)sd->down.pdx * 1.5; // FIXME: * 1.5 - probably should be config
1859                                  if (((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1860                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1861                                    sd->down.dy += (double)sd->down.pdy * 1.5; // FIXME: * 1.5 - probably should be config
1862                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1863                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)) ||
1864                                      ((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1865                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1866                                    {
1867                                       double t = ecore_loop_time_get();
1868                                       double dt = t - sd->down.anim_start;
1869
1870                                       if (dt < 0.0) dt = 0.0;
1871                                       else if (dt > _elm_config->thumbscroll_friction)
1872                                         dt = _elm_config->thumbscroll_friction;
1873                                       sd->down.extra_time = _elm_config->thumbscroll_friction - dt;
1874                                    }
1875                                  else
1876                                    sd->down.extra_time = 0.0;
1877                                  sd->down.pdx = sd->down.dx;
1878                                  sd->down.pdy = sd->down.dy;
1879                                  ox = -sd->down.dx;
1880                                  oy = -sd->down.dy;
1881                                  if (!_smart_do_page(sd))
1882                                    {
1883                                       if ((!sd->down.momentum_animator) && (!sd->momentum_animator_disabled))
1884                                         {
1885                                            sd->down.momentum_animator = ecore_animator_add(_smart_momentum_animator, sd);
1886                                            ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1887                                            _smart_anim_start(sd->smart_obj);
1888                                         }
1889                                       sd->down.anim_start = ecore_loop_time_get();
1890                                       elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1891                                       sd->down.sx = x;
1892                                       sd->down.sy = y;
1893                                       sd->down.b0x = 0;
1894                                       sd->down.b0y = 0;
1895                                    }
1896                               }
1897                          }
1898                        if (sd->down.hold_animator)
1899                          {
1900                             ecore_animator_del(sd->down.hold_animator);
1901                             sd->down.hold_animator = NULL;
1902                          }
1903                     }
1904                   else
1905                     {
1906                        sd->down.pdx = 0;
1907                        sd->down.pdy = 0;
1908                     }
1909                   evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
1910                   if (_smart_do_page(sd))
1911                     {
1912                        Evas_Coord pgx, pgy;
1913
1914                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1915                        if ((!sd->widget) ||
1916                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1917                          {
1918                             pgx = _smart_page_x_get(sd, ox);
1919                             if (pgx != x)
1920                               {
1921                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1922                                  _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1923                               }
1924                          }
1925                        if ((!sd->widget) ||
1926                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1927                          {
1928                             pgy = _smart_page_y_get(sd, oy);
1929                             if (pgy != y)
1930                               {
1931                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1932                                  _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
1933                               }
1934                          }
1935                     }
1936                }
1937              else
1938                {
1939                   sd->down.pdx = 0;
1940                   sd->down.pdy = 0;
1941                   if (_smart_do_page(sd))
1942                     {
1943                        Evas_Coord pgx, pgy;
1944
1945                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1946                        if ((!sd->widget) ||
1947                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1948                          {
1949                             pgx = _smart_page_x_get(sd, ox);
1950                             if (pgx != x) _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1951                          }
1952                        if ((!sd->widget) ||
1953                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1954                          {
1955                             pgy = _smart_page_y_get(sd, oy);
1956                             if (pgy != y) _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
1957                          }
1958                     }
1959                   if (sd->down.hold_animator)
1960                     {
1961                        ecore_animator_del(sd->down.hold_animator);
1962                        sd->down.hold_animator = NULL;
1963                     }
1964                }
1965              if (sd->down.scroll)
1966                {
1967                   ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1968                   sd->down.scroll = 0;
1969                }
1970              if (sd->down.hold)
1971                {
1972                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1973                   sd->down.hold = 0;
1974                }
1975              sd->down.dragged_began = 0;
1976              sd->down.dir_x = 0;
1977              sd->down.dir_y = 0;
1978              sd->down.want_dragged = 0;
1979              sd->down.dragged = 0;
1980              sd->down.now = 0;
1981              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1982              elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1983              _update_wanted_coordinates(sd, x, y);
1984
1985              if (!_smart_do_page(sd))
1986                bounce_eval(sd);
1987           }
1988      }
1989 }
1990
1991 static Eina_Bool
1992 _smart_onhold_animator(void *data)
1993 {
1994    Smart_Data *sd;
1995    double t, td;
1996    double vx, vy;
1997    Evas_Coord x, y, ox, oy;
1998
1999    sd = data;
2000    t = ecore_loop_time_get();
2001    if (sd->down.onhold_tlast > 0.0)
2002      {
2003         td = t - sd->down.onhold_tlast;
2004         vx = sd->down.onhold_vx * td * (double)_elm_config->thumbscroll_threshold * 2.0;
2005         vy = sd->down.onhold_vy * td * (double)_elm_config->thumbscroll_threshold * 2.0;
2006         elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
2007         x = ox;
2008         y = oy;
2009
2010         if (sd->down.dir_x)
2011           {
2012              if ((!sd->widget) ||
2013                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
2014                {
2015                   sd->down.onhold_vxe += vx;
2016                   x = ox + (int)sd->down.onhold_vxe;
2017                   sd->down.onhold_vxe -= (int)sd->down.onhold_vxe;
2018                }
2019           }
2020
2021         if (sd->down.dir_y)
2022           {
2023              if ((!sd->widget) ||
2024                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2025                {
2026                   sd->down.onhold_vye += vy;
2027                   y = oy + (int)sd->down.onhold_vye;
2028                   sd->down.onhold_vye -= (int)sd->down.onhold_vye;
2029                }
2030           }
2031
2032         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2033      }
2034    sd->down.onhold_tlast = t;
2035    return ECORE_CALLBACK_RENEW;
2036 }
2037
2038 static Eina_Bool
2039 _smart_event_post_move(void *data, Evas *e __UNUSED__)
2040 {
2041    Smart_Data *sd = data;
2042
2043    if (sd->down.want_dragged)
2044      {
2045         int start = 0;
2046
2047         if (sd->down.hold_parent)
2048           {
2049              if ((sd->down.dir_x) && !can_scroll(sd, sd->down.hdir))
2050                {
2051                   sd->down.dir_x = 0;
2052                }
2053              if ((sd->down.dir_y) && !can_scroll(sd, sd->down.vdir))
2054                {
2055                   sd->down.dir_y = 0;
2056                }
2057           }
2058         if (sd->down.dir_x)
2059           {
2060              if ((!sd->widget) ||
2061                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
2062                {
2063                   sd->down.want_dragged = 0;
2064                   sd->down.dragged = 1;
2065                   if (sd->widget)
2066                     {
2067                        elm_widget_drag_lock_x_set(sd->widget, 1);
2068                     }
2069                   start = 1;
2070                }
2071              else
2072                sd->down.dir_x = 0;
2073           }
2074         if (sd->down.dir_y)
2075           {
2076              if ((!sd->widget) ||
2077                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2078                {
2079                   sd->down.want_dragged = 0;
2080                   sd->down.dragged = 1;
2081                   if (sd->widget)
2082                     {
2083                        elm_widget_drag_lock_y_set(sd->widget, 1);
2084                     }
2085                   start = 1;
2086                }
2087              else
2088                sd->down.dir_y = 0;
2089           }
2090         if ((!sd->down.dir_x) && (!sd->down.dir_y))
2091           {
2092              sd->down.cancelled = 1;
2093           }
2094         if (start) _smart_drag_start(sd->smart_obj);
2095      }
2096    return EINA_TRUE;
2097 }
2098
2099 static void
2100 _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
2101 {
2102    Evas_Event_Mouse_Move *ev;
2103    Smart_Data *sd;
2104    Evas_Coord x = 0, y = 0;
2105
2106    sd = data;
2107    ev = event_info;
2108    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
2109    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->down.hold_parent = 1;
2110    evas_post_event_callback_push(e, _smart_event_post_move, sd);
2111    // FIXME: respect elm_widget_scroll_hold_get of parent container
2112    if (_elm_config->thumbscroll_enable)
2113      {
2114         if (sd->down.now)
2115           {
2116              int dodir = 0;
2117
2118 #ifdef SCROLLDBG
2119              printf("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2120 #endif
2121              memmove(&(sd->down.history[1]), &(sd->down.history[0]),
2122                      sizeof(sd->down.history[0]) * (60 - 1));
2123 #ifdef EVTIME
2124              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
2125              sd->down.history[0].localtimestamp = ecore_loop_time_get();
2126 #else
2127              sd->down.history[0].timestamp = ecore_loop_time_get();
2128 #endif
2129              sd->down.history[0].x = ev->cur.canvas.x;
2130              sd->down.history[0].y = ev->cur.canvas.y;
2131
2132              if (!sd->down.dragged_began)
2133                {
2134                   x = ev->cur.canvas.x - sd->down.x;
2135                   y = ev->cur.canvas.y - sd->down.y;
2136
2137                   sd->down.hdir = -1;
2138                   sd->down.vdir = -1;
2139
2140                   if      (x > 0) sd->down.hdir = LEFT;
2141                   else if (x < 0) sd->down.hdir = RIGHT;
2142                   if      (y > 0) sd->down.vdir = UP;
2143                   else if (y < 0) sd->down.vdir = DOWN;
2144
2145                   if (x < 0) x = -x;
2146                   if (y < 0) y = -y;
2147
2148                   if ((sd->one_dir_at_a_time) &&
2149                       (!((sd->down.dir_x) || (sd->down.dir_y))))
2150                     {
2151                        if (x > _elm_config->thumbscroll_threshold)
2152                          {
2153                             if (x > (y * 2))
2154                               {
2155                                  sd->down.dir_x = 1;
2156                                  sd->down.dir_y = 0;
2157                                  dodir++;
2158                               }
2159                          }
2160                        if (y > _elm_config->thumbscroll_threshold)
2161                          {
2162                             if (y > (x * 2))
2163                               {
2164                                  sd->down.dir_x = 0;
2165                                  sd->down.dir_y = 1;
2166                                  dodir++;
2167                               }
2168                          }
2169                        if (!dodir)
2170                          {
2171                             sd->down.dir_x = 1;
2172                             sd->down.dir_y = 1;
2173                          }
2174                     }
2175                   else
2176                     {
2177                        //                       can_scroll(sd, LEFT);
2178                        //                       can_scroll(sd, RIGHT);
2179                        //                       can_scroll(sd, UP);
2180                        //                       can_scroll(sd, DOWN);
2181                        sd->down.dir_x = 1;
2182                        sd->down.dir_y = 1;
2183                     }
2184                }
2185              if ((!sd->hold) && (!sd->freeze))
2186                {
2187                   if ((sd->down.dragged) ||
2188                       (((x * x) + (y * y)) >
2189                        (_elm_config->thumbscroll_threshold *
2190                         _elm_config->thumbscroll_threshold)))
2191                     {
2192                        sd->down.dragged_began = 1;
2193                        if (!sd->down.dragged)
2194                          {
2195                             sd->down.want_dragged = 1;
2196                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2197                             //                            evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2198                             //                            _smart_drag_start(sd->smart_obj);
2199                          }
2200                        if (sd->down.dragged)
2201                          {
2202                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2203                          }
2204                        //                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2205                        //                       sd->down.dragged = 1;
2206                        if (sd->down.dir_x)
2207                          x = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
2208                        else
2209                          x = sd->down.sx;
2210                        if (sd->down.dir_y)
2211                          y = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
2212                        else
2213                          y = sd->down.sy;
2214                        if ((sd->down.dir_x) || (sd->down.dir_y))
2215                          {
2216                             if (!sd->down.locked)
2217                               {
2218                                  sd->down.locked_x = x;
2219                                  sd->down.locked_y = y;
2220                                  sd->down.locked = 1;
2221                               }
2222                             if (!((sd->down.dir_x) && (sd->down.dir_y)))
2223                               {
2224                                  if (sd->down.dir_x) y = sd->down.locked_y;
2225                                  else x = sd->down.locked_x;
2226                               }
2227                          }
2228                          {
2229                             Evas_Coord minx, miny;
2230                             sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2231                             if (y < miny)
2232                               y += (miny - y) *
2233                                  _elm_config->thumbscroll_border_friction;
2234                             else if (sd->child.h <= sd->h)
2235                               y += (sd->down.sy - y) *
2236                                  _elm_config->thumbscroll_border_friction;
2237                             else if ((sd->child.h - sd->h + miny) < y)
2238                               y += (sd->child.h - sd->h + miny - y) *
2239                                  _elm_config->thumbscroll_border_friction;
2240                             if (x < minx)
2241                               x += (minx - x) *
2242                                  _elm_config->thumbscroll_border_friction;
2243                             else if (sd->child.w <= sd->w)
2244                               x += (sd->down.sx - x) *
2245                                  _elm_config->thumbscroll_border_friction;
2246                             else if ((sd->child.w - sd->w + minx) < x)
2247                               x += (sd->child.w - sd->w + minx - x) *
2248                                  _elm_config->thumbscroll_border_friction;
2249                          }
2250
2251                        sd->down.hold_x = x;
2252                        sd->down.hold_y = y;
2253                        if (!sd->down.hold_animator)
2254                          sd->down.hold_animator =
2255                             ecore_animator_add(_smart_hold_animator, sd);
2256                        //                       printf("a %i %i\n", sd->down.hold_x, sd->down.hold_y);
2257                        //                       _smart_onhold_animator(sd);
2258                        //                       elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2259                     }
2260                   else
2261                     {
2262                        if (sd->down.dragged_began)
2263                          {
2264                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2265                             if (!sd->down.hold)
2266                               {
2267                                  sd->down.hold = 1;
2268                                  evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2269                               }
2270                          }
2271                     }
2272                }
2273              else if (!sd->freeze)
2274                {
2275                   Evas_Coord ex, ey, ew, eh;
2276                   double vx = 0.0, vy = 0.0;
2277
2278                   evas_object_geometry_get(sd->event_obj, &ex, &ey, &ew, &eh);
2279                   x = ev->cur.canvas.x - ex;
2280                   y = ev->cur.canvas.y - ey;
2281                   if (x < _elm_config->thumbscroll_threshold)
2282                     {
2283                        if (_elm_config->thumbscroll_threshold > 0.0)
2284                          vx = -(double)(_elm_config->thumbscroll_threshold - x) /
2285                             _elm_config->thumbscroll_threshold;
2286                        else
2287                          vx = -1.0;
2288                     }
2289                   else if (x > (ew - _elm_config->thumbscroll_threshold))
2290                     {
2291                        if (_elm_config->thumbscroll_threshold > 0.0)
2292                          vx = (double)(_elm_config->thumbscroll_threshold - (ew - x)) /
2293                             _elm_config->thumbscroll_threshold;
2294                        else
2295                          vx = 1.0;
2296                     }
2297                   if (y < _elm_config->thumbscroll_threshold)
2298                     {
2299                        if (_elm_config->thumbscroll_threshold > 0.0)
2300                          vy = -(double)(_elm_config->thumbscroll_threshold - y) /
2301                             _elm_config->thumbscroll_threshold;
2302                        else
2303                          vy = -1.0;
2304                     }
2305                   else if (y > (eh - _elm_config->thumbscroll_threshold))
2306                     {
2307                        if (_elm_config->thumbscroll_threshold > 0.0)
2308                          vy = (double)(_elm_config->thumbscroll_threshold - (eh - y)) /
2309                             _elm_config->thumbscroll_threshold;
2310                        else
2311                          vy = 1.0;
2312                     }
2313                   if ((vx != 0.0) || (vy != 0.0))
2314                     {
2315                        sd->down.onhold_vx = vx;
2316                        sd->down.onhold_vy = vy;
2317                        if (!sd->down.onhold_animator)
2318                          {
2319                             sd->down.onhold_vxe = 0.0;
2320                             sd->down.onhold_vye = 0.0;
2321                             sd->down.onhold_tlast = 0.0;
2322                             sd->down.onhold_animator = ecore_animator_add(_smart_onhold_animator, sd);
2323                          }
2324                        //                       printf("b %i %i\n", sd->down.hold_x, sd->down.hold_y);
2325                     }
2326                   else
2327                     {
2328                        if (sd->down.onhold_animator)
2329                          {
2330                             ecore_animator_del(sd->down.onhold_animator);
2331                             sd->down.onhold_animator = NULL;
2332                          }
2333                     }
2334                }
2335           }
2336      }
2337 }
2338
2339 static void
2340 _smart_scrollbar_read(Smart_Data *sd)
2341 {
2342    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
2343    double vx, vy;
2344
2345    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2346    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2347    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2348    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2349    x = vx * (double)mx + minx;
2350    y = vy * (double)my + miny;
2351    sd->pan_func.get(sd->pan_obj, &px, &py);
2352    sd->pan_func.set(sd->pan_obj, x, y);
2353    if ((px != x) || (py != y))
2354      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2355 }
2356
2357 static void
2358 _smart_scrollbar_reset(Smart_Data *sd)
2359 {
2360    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2361
2362    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2363    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2364    if ((!sd->child_obj) && (!sd->extern_pan))
2365      {
2366         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2367         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2368      }
2369    if (sd->pan_obj)
2370      {
2371         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2372         sd->pan_func.get(sd->pan_obj, &px, &py);
2373         sd->pan_func.set(sd->pan_obj, minx, miny);
2374      }
2375    if ((px != minx) || (py != miny))
2376      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2377 }
2378
2379 static int
2380 _smart_scrollbar_bar_v_visibility_adjust(Smart_Data *sd)
2381 {
2382    int scroll_v_vis_change = 0;
2383    Evas_Coord h, vw = 0, vh = 0;
2384
2385    h = sd->child.h;
2386    if (sd->pan_obj)
2387      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2388    if (sd->vbar_visible)
2389      {
2390         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2391           {
2392              if ((sd->child_obj) || (sd->extern_pan))
2393                {
2394                   if (h <= vh)
2395                     {
2396                        scroll_v_vis_change = 1;
2397                        sd->vbar_visible = 0;
2398                     }
2399                }
2400              else
2401                {
2402                   scroll_v_vis_change = 1;
2403                   sd->vbar_visible = 0;
2404                }
2405           }
2406         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2407           {
2408              scroll_v_vis_change = 1;
2409              sd->vbar_visible = 0;
2410           }
2411      }
2412    else
2413      {
2414         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2415           {
2416              if ((sd->child_obj) || (sd->extern_pan))
2417                {
2418                   if (h > vh)
2419                     {
2420                        scroll_v_vis_change = 1;
2421                        sd->vbar_visible = 1;
2422                     }
2423                }
2424           }
2425         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2426           {
2427              scroll_v_vis_change = 1;
2428              sd->vbar_visible = 1;
2429           }
2430      }
2431    if (scroll_v_vis_change)
2432      {
2433         if (sd->vbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2434           {
2435              if (sd->vbar_visible)
2436                edje_object_signal_emit(sd->edje_obj, "elm,action,show,vbar", "elm");
2437              else
2438                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2439              edje_object_message_signal_process(sd->edje_obj);
2440              _smart_scrollbar_size_adjust(sd);
2441           }
2442         else
2443           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2444      }
2445    return scroll_v_vis_change;
2446 }
2447
2448 static int
2449 _smart_scrollbar_bar_h_visibility_adjust(Smart_Data *sd)
2450 {
2451    int scroll_h_vis_change = 0;
2452    Evas_Coord w, vw = 0, vh = 0;
2453
2454    w = sd->child.w;
2455    if (sd->pan_obj)
2456      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2457    if (sd->hbar_visible)
2458      {
2459         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2460           {
2461              if ((sd->child_obj) || (sd->extern_pan))
2462                {
2463                   if (w <= vw)
2464                     {
2465                        scroll_h_vis_change = 1;
2466                        sd->hbar_visible = 0;
2467                     }
2468                }
2469              else
2470                {
2471                   scroll_h_vis_change = 1;
2472                   sd->hbar_visible = 0;
2473                }
2474           }
2475         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2476           {
2477              scroll_h_vis_change = 1;
2478              sd->hbar_visible = 0;
2479           }
2480      }
2481    else
2482      {
2483         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2484           {
2485              if ((sd->child_obj) || (sd->extern_pan))
2486                {
2487                   if (w > vw)
2488                     {
2489                        scroll_h_vis_change = 1;
2490                        sd->hbar_visible = 1;
2491                     }
2492                }
2493           }
2494         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2495           {
2496              scroll_h_vis_change = 1;
2497              sd->hbar_visible = 1;
2498           }
2499      }
2500    if (scroll_h_vis_change)
2501      {
2502         if (sd->hbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2503           {
2504              if (sd->hbar_visible)
2505                edje_object_signal_emit(sd->edje_obj, "elm,action,show,hbar", "elm");
2506              else
2507                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2508              edje_object_message_signal_process(sd->edje_obj);
2509              _smart_scrollbar_size_adjust(sd);
2510           }
2511         else
2512           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2513         _smart_scrollbar_size_adjust(sd);
2514      }
2515    return scroll_h_vis_change;
2516 }
2517
2518 static void
2519 _smart_scrollbar_bar_visibility_adjust(Smart_Data *sd)
2520 {
2521    int changed = 0;
2522
2523    changed |= _smart_scrollbar_bar_h_visibility_adjust(sd);
2524    changed |= _smart_scrollbar_bar_v_visibility_adjust(sd);
2525    if (changed)
2526      {
2527         _smart_scrollbar_bar_h_visibility_adjust(sd);
2528         _smart_scrollbar_bar_v_visibility_adjust(sd);
2529      }
2530 }
2531
2532 static void
2533 _smart_scrollbar_size_adjust(Smart_Data *sd)
2534 {
2535    if ((sd->child_obj) || (sd->extern_pan))
2536      {
2537         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py, minx = 0, miny = 0;
2538         double vx, vy, size;
2539
2540         edje_object_part_geometry_get(sd->edje_obj, "elm.swallow.content",
2541                                       NULL, NULL, &vw, &vh);
2542         w = sd->child.w;
2543         if (w < 1) w = 1;
2544         size = (double)vw / (double)w;
2545         if (size > 1.0)
2546           {
2547              size = 1.0;
2548              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2549           }
2550         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", size, 1.0);
2551
2552         h = sd->child.h;
2553         if (h < 1) h = 1;
2554         size = (double)vh / (double)h;
2555         if (size > 1.0)
2556           {
2557              size = 1.0;
2558              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2559           }
2560         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, size);
2561
2562         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2563         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2564         sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2565         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2566         x = vx * mx + minx;
2567         y = vy * my + miny;
2568
2569         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->step.x / (double)w, 0.0);
2570         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->step.y / (double)h);
2571         if (sd->page.x > 0)
2572           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->page.x / (double)w, 0.0);
2573         else
2574           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", -((double)sd->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
2575         if (sd->page.y > 0)
2576           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->page.y / (double)h);
2577         else
2578           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, -((double)sd->page.y * ((double)vh / (double)h)) / 100.0);
2579
2580         sd->pan_func.get(sd->pan_obj, &px, &py);
2581         if (vx != mx) x = px;
2582         if (vy != my) y = py;
2583         sd->pan_func.set(sd->pan_obj, x, y);
2584         //      if ((px != 0) || (py != 0))
2585         //        edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2586      }
2587    else
2588      {
2589         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2590
2591         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2592         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2593         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2594         sd->pan_func.get(sd->pan_obj, &px, &py);
2595         sd->pan_func.set(sd->pan_obj, minx, miny);
2596         if ((px != minx) || (py != miny))
2597           edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2598      }
2599    _smart_scrollbar_bar_visibility_adjust(sd);
2600 }
2601
2602 static void
2603 _smart_reconfigure(Smart_Data *sd)
2604 {
2605    evas_object_move(sd->edje_obj, sd->x, sd->y);
2606    evas_object_resize(sd->edje_obj, sd->w, sd->h);
2607    evas_object_move(sd->event_obj, sd->x, sd->y);
2608    evas_object_resize(sd->event_obj, sd->w, sd->h);
2609    _smart_scrollbar_size_adjust(sd);
2610 }
2611
2612 static void
2613 _smart_add(Evas_Object *obj)
2614 {
2615    Smart_Data *sd;
2616    Evas_Object *o;
2617
2618    sd = calloc(1, sizeof(Smart_Data));
2619    if (!sd) return;
2620    evas_object_smart_data_set(obj, sd);
2621
2622    sd->smart_obj = obj;
2623    sd->x = 0;
2624    sd->y = 0;
2625    sd->w = 0;
2626    sd->h = 0;
2627    sd->step.x = 32;
2628    sd->step.y = 32;
2629    sd->page.x = -50;
2630    sd->page.y = -50;
2631    sd->hbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2632    sd->vbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2633    sd->hbar_visible = 1;
2634    sd->vbar_visible = 1;
2635
2636    sd->bounce_horiz = 1;
2637    sd->bounce_vert = 1;
2638
2639    sd->one_dir_at_a_time = 1;
2640    sd->momentum_animator_disabled = EINA_FALSE;
2641    sd->bounce_animator_disabled = EINA_FALSE;
2642
2643    o = edje_object_add(evas_object_evas_get(obj));
2644    evas_object_propagate_events_set(o, 0);
2645    sd->edje_obj = o;
2646    elm_smart_scroller_object_theme_set(NULL, obj, "scroller", "base", "default");
2647    edje_object_signal_callback_add(o, "drag", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2648    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.vbar", _smart_edje_drag_v_start, sd);
2649    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.vbar", _smart_edje_drag_v_stop, sd);
2650    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2651    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2652    edje_object_signal_callback_add(o, "drag", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2653    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.hbar", _smart_edje_drag_h_start, sd);
2654    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.hbar", _smart_edje_drag_h_stop, sd);
2655    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2656    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2657    evas_object_smart_member_add(o, obj);
2658
2659    o = evas_object_rectangle_add(evas_object_evas_get(obj));
2660    sd->event_obj = o;
2661    evas_object_color_set(o, 0, 0, 0, 0);
2662    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
2663    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _smart_event_mouse_down, sd);
2664    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _smart_event_mouse_up, sd);
2665    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _smart_event_mouse_move, sd);
2666    evas_object_smart_member_add(o, obj);
2667    evas_object_repeat_events_set(o, 1);
2668
2669    sd->pan_func.set = _elm_smart_pan_set;
2670    sd->pan_func.get = _elm_smart_pan_get;
2671    sd->pan_func.max_get = _elm_smart_pan_max_get;
2672    sd->pan_func.min_get = _elm_smart_pan_min_get;
2673    sd->pan_func.child_size_get = _elm_smart_pan_child_size_get;
2674
2675    _smart_scrollbar_reset(sd);
2676 }
2677
2678 static void
2679 _smart_del(Evas_Object *obj)
2680 {
2681    INTERNAL_ENTRY;
2682    elm_smart_scroller_child_set(obj, NULL);
2683    if (!sd->extern_pan) evas_object_del(sd->pan_obj);
2684    evas_object_del(sd->edje_obj);
2685    evas_object_del(sd->event_obj);
2686    if (sd->down.hold_animator) ecore_animator_del(sd->down.hold_animator);
2687    if (sd->down.onhold_animator) ecore_animator_del(sd->down.onhold_animator);
2688    if (sd->down.momentum_animator) ecore_animator_del(sd->down.momentum_animator);
2689    if (sd->down.bounce_x_animator) ecore_animator_del(sd->down.bounce_x_animator);
2690    if (sd->down.bounce_y_animator) ecore_animator_del(sd->down.bounce_y_animator);
2691    if (sd->scrollto.x.animator) ecore_animator_del(sd->scrollto.x.animator);
2692    if (sd->scrollto.y.animator) ecore_animator_del(sd->scrollto.y.animator);
2693    free(sd);
2694    evas_object_smart_data_set(obj, NULL);
2695 }
2696
2697 static void
2698 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2699 {
2700    INTERNAL_ENTRY;
2701    sd->x = x;
2702    sd->y = y;
2703    _smart_reconfigure(sd);
2704 }
2705
2706 static void
2707 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2708 {
2709    INTERNAL_ENTRY;
2710    sd->w = w;
2711    sd->h = h;
2712    _smart_reconfigure(sd);
2713    _elm_smart_scroller_wanted_region_set(obj);
2714 }
2715
2716 static void
2717 _smart_show(Evas_Object *obj)
2718 {
2719    INTERNAL_ENTRY;
2720    evas_object_show(sd->edje_obj);
2721    evas_object_show(sd->event_obj);
2722 }
2723
2724 static void
2725 _smart_hide(Evas_Object *obj)
2726 {
2727    INTERNAL_ENTRY;
2728    evas_object_hide(sd->edje_obj);
2729    evas_object_hide(sd->event_obj);
2730 }
2731
2732 static void
2733 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
2734 {
2735    INTERNAL_ENTRY;
2736    evas_object_color_set(sd->edje_obj, r, g, b, a);
2737 }
2738
2739 static void
2740 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
2741 {
2742    INTERNAL_ENTRY;
2743    evas_object_clip_set(sd->edje_obj, clip);
2744    evas_object_clip_set(sd->event_obj, clip);
2745 }
2746
2747 static void
2748 _smart_clip_unset(Evas_Object *obj)
2749 {
2750    INTERNAL_ENTRY;
2751    evas_object_clip_unset(sd->edje_obj);
2752    evas_object_clip_unset(sd->event_obj);
2753 }
2754
2755 /* never need to touch this */
2756
2757 static void
2758 _smart_init(void)
2759 {
2760    if (_smart) return;
2761      {
2762         static const Evas_Smart_Class sc =
2763           {
2764              SMART_NAME,
2765              EVAS_SMART_CLASS_VERSION,
2766              _smart_add,
2767              _smart_del,
2768              _smart_move,
2769              _smart_resize,
2770              _smart_show,
2771              _smart_hide,
2772              _smart_color_set,
2773              _smart_clip_set,
2774              _smart_clip_unset,
2775              NULL,
2776              NULL,
2777              NULL,
2778              NULL,
2779              NULL,
2780              NULL,
2781              NULL
2782           };
2783         _smart = evas_smart_class_new(&sc);
2784      }
2785 }