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