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