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