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