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