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