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