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