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