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