Removed smooth scrolling. Patch by Jiyoun Park <jy0703.park@samsung.com>
[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                        ax /= (i + 1);
1927                        ay /= (i + 1);
1928                        at /= (i + 1);
1929                        at /= _elm_config->thumbscroll_sensitivity_friction;
1930                        dx = ev->canvas.x - ax;
1931                        dy = ev->canvas.y - ay;
1932                        if (at > 0)
1933                          {
1934                             vel = sqrt((dx * dx) + (dy * dy)) / at;
1935                             if ((_elm_config->thumbscroll_friction > 0.0) &&
1936                                 (vel > _elm_config->thumbscroll_momentum_threshold))
1937                               {
1938                                  int minx, miny, mx, my, px, py;
1939                                  sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
1940                                  sd->pan_func.max_get(sd->pan_obj, &mx, &my);
1941                                  sd->pan_func.get(sd->pan_obj, &px, &py);
1942                                  sd->down.dx = ((double)dx / at);
1943                                  sd->down.dy = ((double)dy / at);
1944                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1945                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)))
1946                                    if (px > minx && px < mx)
1947                                      sd->down.dx += (double)sd->down.pdx * 1.5; // FIXME: * 1.5 - probably should be config
1948                                  if (((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1949                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1950                                    if (py > miny && py < my)
1951                                      sd->down.dy += (double)sd->down.pdy * 1.5; // FIXME: * 1.5 - probably should be config
1952                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1953                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)) ||
1954                                      ((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1955                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1956                                    {
1957                                       double tt = ecore_loop_time_get();
1958                                       double dtt = tt - sd->down.anim_start;
1959
1960                                       if (dtt < 0.0) dtt = 0.0;
1961                                       else if (dtt > _elm_config->thumbscroll_friction)
1962                                         dtt = _elm_config->thumbscroll_friction;
1963                                       sd->down.extra_time = _elm_config->thumbscroll_friction - dtt;
1964                                    }
1965                                  else
1966                                    sd->down.extra_time = 0.0;
1967                                  elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &vw, &vh);
1968                                  aw = abs(sd->down.dx);
1969                                  if (aw  > vw*3)
1970                                    {
1971                                       if (sd->down.dx > 0) sd->down.dx = vw*3;
1972                                       else sd->down.dx = -(vw*3);
1973                                    }
1974                                  ah = abs(sd->down.dy);
1975                                  if (ah  > vh*3)
1976                                    {
1977                                       if (sd->down.dy > 0) sd->down.dy = vh*3;
1978                                       else sd->down.dy = -(vh*3);
1979                                    }
1980                                  sd->down.pdx = sd->down.dx;
1981                                  sd->down.pdy = sd->down.dy;
1982                                  ox = -sd->down.dx;
1983                                  oy = -sd->down.dy;
1984                                  if (!_smart_do_page(sd))
1985                                    {
1986                                       if ((!sd->down.momentum_animator) && (!sd->momentum_animator_disabled))
1987                                         {
1988                                            sd->down.momentum_animator = ecore_animator_add(_smart_momentum_animator, sd);
1989                                            ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1990                                            _smart_anim_start(sd->smart_obj);
1991                                         }
1992                                       sd->down.anim_start = ecore_loop_time_get();
1993                                       elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1994                                       sd->down.sx = x;
1995                                       sd->down.sy = y;
1996                                       sd->down.b0x = 0;
1997                                       sd->down.b0y = 0;
1998                                    }
1999                               }
2000                          }
2001                     }
2002                   else
2003                     {
2004                        sd->down.pdx = 0;
2005                        sd->down.pdy = 0;
2006                     }
2007                   evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
2008                   if (_smart_do_page(sd))
2009                     {
2010                        Evas_Coord pgx, pgy;
2011
2012                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
2013                        if ((!sd->widget) ||
2014                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
2015                          {
2016                             pgx = _smart_page_x_get(sd, ox);
2017                             if (pgx != x)
2018                               {
2019                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2020                                  _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
2021                               }
2022                          }
2023                        if ((!sd->widget) ||
2024                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
2025                          {
2026                             pgy = _smart_page_y_get(sd, oy);
2027                             if (pgy != y)
2028                               {
2029                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2030                                  _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
2031                               }
2032                          }
2033                     }
2034                }
2035              else
2036                {
2037                   sd->down.pdx = 0;
2038                   sd->down.pdy = 0;
2039                   if (_smart_do_page(sd))
2040                     {
2041                        Evas_Coord pgx, pgy;
2042
2043                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
2044                        if ((!sd->widget) ||
2045                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
2046                          {
2047                             pgx = _smart_page_x_get(sd, ox);
2048                             if (pgx != x) _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
2049                          }
2050                        if ((!sd->widget) ||
2051                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
2052                          {
2053                             pgy = _smart_page_y_get(sd, oy);
2054                             if (pgy != y) _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
2055                          }
2056                     }
2057                }
2058              if (sd->down.hold_animator)
2059                {
2060                   ecore_animator_del(sd->down.hold_animator);
2061                   sd->down.hold_animator = NULL;
2062                   if (sd->child.resized)
2063                     _elm_smart_scroller_wanted_region_set(sd->smart_obj);
2064                }
2065              if (sd->down.scroll)
2066                {
2067                   ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2068                   sd->down.scroll = EINA_FALSE;
2069                }
2070              if (sd->down.hold)
2071                {
2072                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2073                   sd->down.hold = EINA_FALSE;
2074                }
2075              sd->down.dragged_began = EINA_FALSE;
2076              sd->down.dir_x = EINA_FALSE;
2077              sd->down.dir_y = EINA_FALSE;
2078              sd->down.want_dragged = EINA_FALSE;
2079              sd->down.dragged = EINA_FALSE;
2080              sd->down.now = EINA_FALSE;
2081              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
2082              elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2083              _update_wanted_coordinates(sd, x, y);
2084
2085              if (sd->child.resized)
2086                _elm_smart_scroller_wanted_region_set(sd->smart_obj);
2087
2088              if (!_smart_do_page(sd))
2089                bounce_eval(sd);
2090           }
2091      }
2092 }
2093
2094 static Eina_Bool
2095 _smart_onhold_animator(void *data)
2096 {
2097    Smart_Data *sd;
2098    double t, td;
2099    double vx, vy;
2100    Evas_Coord x, y, ox, oy;
2101
2102    sd = data;
2103    t = ecore_loop_time_get();
2104    if (sd->down.onhold_tlast > 0.0)
2105      {
2106         td = t - sd->down.onhold_tlast;
2107         vx = sd->down.onhold_vx * td * (double)_elm_config->thumbscroll_threshold * 2.0;
2108         vy = sd->down.onhold_vy * td * (double)_elm_config->thumbscroll_threshold * 2.0;
2109         elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
2110         x = ox;
2111         y = oy;
2112
2113         if (sd->down.dir_x)
2114           {
2115              if ((!sd->widget) ||
2116                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
2117                {
2118                   sd->down.onhold_vxe += vx;
2119                   x = ox + (int)sd->down.onhold_vxe;
2120                   sd->down.onhold_vxe -= (int)sd->down.onhold_vxe;
2121                }
2122           }
2123
2124         if (sd->down.dir_y)
2125           {
2126              if ((!sd->widget) ||
2127                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2128                {
2129                   sd->down.onhold_vye += vy;
2130                   y = oy + (int)sd->down.onhold_vye;
2131                   sd->down.onhold_vye -= (int)sd->down.onhold_vye;
2132                }
2133           }
2134
2135         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2136      }
2137    sd->down.onhold_tlast = t;
2138    return ECORE_CALLBACK_RENEW;
2139 }
2140
2141 static Eina_Bool
2142 _smart_event_post_move(void *data, Evas *e __UNUSED__)
2143 {
2144    Smart_Data *sd = data;
2145
2146    if (sd->down.want_dragged)
2147      {
2148         int start = 0;
2149
2150         if (sd->down.hold_parent)
2151           {
2152              if ((sd->down.dir_x) && !can_scroll(sd, sd->down.hdir))
2153                {
2154                   sd->down.dir_x = EINA_FALSE;
2155                }
2156              if ((sd->down.dir_y) && !can_scroll(sd, sd->down.vdir))
2157                {
2158                   sd->down.dir_y = EINA_FALSE;
2159                }
2160           }
2161         if (sd->down.dir_x)
2162           {
2163              if ((!sd->widget) ||
2164                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
2165                {
2166                   sd->down.want_dragged = EINA_FALSE;
2167                   sd->down.dragged = EINA_TRUE;
2168                   if (sd->widget)
2169                     {
2170                        elm_widget_drag_lock_x_set(sd->widget, 1);
2171                     }
2172                   start = 1;
2173                }
2174              else
2175                sd->down.dir_x = EINA_FALSE;
2176           }
2177         if (sd->down.dir_y)
2178           {
2179              if ((!sd->widget) ||
2180                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2181                {
2182                   sd->down.want_dragged = EINA_FALSE;
2183                   sd->down.dragged = EINA_TRUE;
2184                   if (sd->widget)
2185                     {
2186                        elm_widget_drag_lock_y_set(sd->widget, 1);
2187                     }
2188                   start = 1;
2189                }
2190              else
2191                sd->down.dir_y = EINA_FALSE;
2192           }
2193         if ((!sd->down.dir_x) && (!sd->down.dir_y))
2194           {
2195              sd->down.cancelled = EINA_TRUE;
2196           }
2197         if (start) _smart_drag_start(sd->smart_obj);
2198      }
2199    return EINA_TRUE;
2200 }
2201
2202 static void
2203 _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
2204 {
2205    Evas_Event_Mouse_Move *ev;
2206    Smart_Data *sd;
2207    Evas_Coord x = 0, y = 0;
2208
2209    sd = data;
2210    ev = event_info;
2211    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
2212    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
2213      sd->down.hold_parent = EINA_TRUE;
2214    evas_post_event_callback_push(e, _smart_event_post_move, sd);
2215
2216    // FIXME: respect elm_widget_scroll_hold_get of parent container
2217    if (_elm_config->thumbscroll_enable)
2218      {
2219         if (sd->down.now)
2220           {
2221              int dodir = 0;
2222
2223              if ((sd->scrollto.x.animator) && (!sd->hold) && (!sd->freeze))
2224                {
2225                   Evas_Coord px;
2226                   ecore_animator_del(sd->scrollto.x.animator);
2227                   sd->scrollto.x.animator = NULL;
2228                   sd->pan_func.get(sd->pan_obj, &px, NULL);
2229                   sd->down.sx = px;
2230                   sd->down.x = sd->down.history[0].x;
2231                }
2232
2233              if ((sd->scrollto.y.animator) && (!sd->hold) && (!sd->freeze))
2234                {
2235                   Evas_Coord py;
2236                   ecore_animator_del(sd->scrollto.y.animator);
2237                   sd->scrollto.y.animator = NULL;
2238                   sd->pan_func.get(sd->pan_obj, NULL, &py);
2239                   sd->down.sy = py;
2240                   sd->down.y = sd->down.history[0].y;
2241                }
2242
2243 #ifdef SCROLLDBG
2244              printf("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2245 #endif
2246              memmove(&(sd->down.history[1]), &(sd->down.history[0]),
2247                      sizeof(sd->down.history[0]) * (60 - 1));
2248 #ifdef EVTIME
2249              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
2250              sd->down.history[0].localtimestamp = ecore_loop_time_get();
2251 #else
2252              sd->down.history[0].timestamp = ecore_loop_time_get();
2253 #endif
2254              sd->down.history[0].x = ev->cur.canvas.x;
2255              sd->down.history[0].y = ev->cur.canvas.y;
2256
2257              if (!sd->down.dragged_began)
2258                {
2259                   x = ev->cur.canvas.x - sd->down.x;
2260                   y = ev->cur.canvas.y - sd->down.y;
2261
2262                   sd->down.hdir = -1;
2263                   sd->down.vdir = -1;
2264
2265                   if      (x > 0) sd->down.hdir = LEFT;
2266                   else if (x < 0) sd->down.hdir = RIGHT;
2267                   if      (y > 0) sd->down.vdir = UP;
2268                   else if (y < 0) sd->down.vdir = DOWN;
2269
2270                   if (x < 0) x = -x;
2271                   if (y < 0) y = -y;
2272
2273                   if ((sd->one_dir_at_a_time) &&
2274                       (!((sd->down.dir_x) || (sd->down.dir_y))))
2275                     {
2276                        if (x > _elm_config->thumbscroll_threshold)
2277                          {
2278                             if (x > (y * 2))
2279                               {
2280                                  sd->down.dir_x = EINA_TRUE;
2281                                  sd->down.dir_y = EINA_FALSE;
2282                                  dodir++;
2283                               }
2284                          }
2285                        if (y > _elm_config->thumbscroll_threshold)
2286                          {
2287                             if (y > (x * 2))
2288                               {
2289                                  sd->down.dir_x = EINA_FALSE;
2290                                  sd->down.dir_y = EINA_TRUE;
2291                                  dodir++;
2292                               }
2293                          }
2294                        if (!dodir)
2295                          {
2296                             sd->down.dir_x = EINA_TRUE;
2297                             sd->down.dir_y = EINA_TRUE;
2298                          }
2299                     }
2300                   else
2301                     {
2302                        sd->down.dir_x = EINA_TRUE;
2303                        sd->down.dir_y = EINA_TRUE;
2304                     }
2305                }
2306              if ((!sd->hold) && (!sd->freeze))
2307                {
2308                   if ((sd->down.dragged) ||
2309                       (((x * x) + (y * y)) >
2310                        (_elm_config->thumbscroll_threshold *
2311                         _elm_config->thumbscroll_threshold)))
2312                     {
2313                        sd->down.dragged_began = EINA_TRUE;
2314                        if (!sd->down.dragged)
2315                          {
2316                             sd->down.want_dragged = EINA_TRUE;
2317                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2318                             //                            evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2319                             //                            _smart_drag_start(sd->smart_obj);
2320                          }
2321                        if (sd->down.dragged)
2322                          {
2323                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2324                          }
2325                        //                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2326                        //                       sd->down.dragged = 1;
2327                        if (sd->down.dir_x)
2328                          x = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
2329                        else
2330                          x = sd->down.sx;
2331                        if (sd->down.dir_y)
2332                          y = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
2333                        else
2334                          y = sd->down.sy;
2335                        if (sd->down.want_reset)
2336                          {
2337                             sd->down.x = ev->cur.canvas.x;
2338                             sd->down.y = ev->cur.canvas.y;
2339                             sd->down.want_reset = EINA_FALSE;
2340                          }
2341                        if ((sd->down.dir_x) || (sd->down.dir_y))
2342                          {
2343                             if (!sd->down.locked)
2344                               {
2345                                  sd->down.locked_x = x;
2346                                  sd->down.locked_y = y;
2347                                  sd->down.locked = EINA_TRUE;
2348                               }
2349                             if (!((sd->down.dir_x) && (sd->down.dir_y)))
2350                               {
2351                                  if (sd->down.dir_x) y = sd->down.locked_y;
2352                                  else x = sd->down.locked_x;
2353                               }
2354                          }
2355                          {
2356                             Evas_Coord minx, miny;
2357                             sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2358                             if (y < miny)
2359                               y += (miny - y) *
2360                                  _elm_config->thumbscroll_border_friction;
2361                             else if (sd->child.h <= sd->h)
2362                               y += (sd->down.sy - y) *
2363                                  _elm_config->thumbscroll_border_friction;
2364                             else if ((sd->child.h - sd->h + miny) < y)
2365                               y += (sd->child.h - sd->h + miny - y) *
2366                                  _elm_config->thumbscroll_border_friction;
2367                             if (x < minx)
2368                               x += (minx - x) *
2369                                  _elm_config->thumbscroll_border_friction;
2370                             else if (sd->child.w <= sd->w)
2371                               x += (sd->down.sx - x) *
2372                                  _elm_config->thumbscroll_border_friction;
2373                             else if ((sd->child.w - sd->w + minx) < x)
2374                               x += (sd->child.w - sd->w + minx - x) *
2375                                  _elm_config->thumbscroll_border_friction;
2376                          }
2377
2378                        sd->down.hold_x = x;
2379                        sd->down.hold_y = y;
2380                        if (!sd->down.hold_animator)
2381                          sd->down.hold_animator =
2382                             ecore_animator_add(_smart_hold_animator, sd);
2383                        //                       printf("a %i %i\n", sd->down.hold_x, sd->down.hold_y);
2384                        //                       _smart_onhold_animator(sd);
2385                        //                       elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2386                     }
2387                   else
2388                     {
2389                        if (sd->down.dragged_began)
2390                          {
2391                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2392                             if (!sd->down.hold)
2393                               {
2394                                  sd->down.hold = EINA_TRUE;
2395                                  evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2396                               }
2397                          }
2398                     }
2399                }
2400              else if (!sd->freeze)
2401                {
2402                   Evas_Coord ex, ey, ew, eh;
2403                   double vx = 0.0, vy = 0.0;
2404
2405                   evas_object_geometry_get(sd->event_obj, &ex, &ey, &ew, &eh);
2406                   x = ev->cur.canvas.x - ex;
2407                   y = ev->cur.canvas.y - ey;
2408                   if (x < _elm_config->thumbscroll_threshold)
2409                     {
2410                        if (_elm_config->thumbscroll_threshold > 0.0)
2411                          vx = -(double)(_elm_config->thumbscroll_threshold - x) /
2412                             _elm_config->thumbscroll_threshold;
2413                        else
2414                          vx = -1.0;
2415                     }
2416                   else if (x > (ew - _elm_config->thumbscroll_threshold))
2417                     {
2418                        if (_elm_config->thumbscroll_threshold > 0.0)
2419                          vx = (double)(_elm_config->thumbscroll_threshold - (ew - x)) /
2420                             _elm_config->thumbscroll_threshold;
2421                        else
2422                          vx = 1.0;
2423                     }
2424                   if (y < _elm_config->thumbscroll_threshold)
2425                     {
2426                        if (_elm_config->thumbscroll_threshold > 0.0)
2427                          vy = -(double)(_elm_config->thumbscroll_threshold - y) /
2428                             _elm_config->thumbscroll_threshold;
2429                        else
2430                          vy = -1.0;
2431                     }
2432                   else if (y > (eh - _elm_config->thumbscroll_threshold))
2433                     {
2434                        if (_elm_config->thumbscroll_threshold > 0.0)
2435                          vy = (double)(_elm_config->thumbscroll_threshold - (eh - y)) /
2436                             _elm_config->thumbscroll_threshold;
2437                        else
2438                          vy = 1.0;
2439                     }
2440                   if ((vx != 0.0) || (vy != 0.0))
2441                     {
2442                        sd->down.onhold_vx = vx;
2443                        sd->down.onhold_vy = vy;
2444                        if (!sd->down.onhold_animator)
2445                          {
2446                             sd->down.onhold_vxe = 0.0;
2447                             sd->down.onhold_vye = 0.0;
2448                             sd->down.onhold_tlast = 0.0;
2449                             sd->down.onhold_animator = ecore_animator_add(_smart_onhold_animator, sd);
2450                          }
2451                        //                       printf("b %i %i\n", sd->down.hold_x, sd->down.hold_y);
2452                     }
2453                   else
2454                     {
2455                        if (sd->down.onhold_animator)
2456                          {
2457                             ecore_animator_del(sd->down.onhold_animator);
2458                             sd->down.onhold_animator = NULL;
2459                             if (sd->child.resized)
2460                               _elm_smart_scroller_wanted_region_set(sd->smart_obj);
2461                          }
2462                     }
2463                }
2464           }
2465      }
2466 }
2467
2468 static void
2469 _smart_scrollbar_read(Smart_Data *sd)
2470 {
2471    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
2472    double vx, vy;
2473
2474    if ((sd->down.dragged) || (sd->down.bounce_x_animator)
2475        || (sd->down.bounce_y_animator) || (sd->down.momentum_animator)
2476        || (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
2477      return;
2478    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2479    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2480    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2481    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2482    x = vx * (double)mx + minx;
2483    y = vy * (double)my + miny;
2484    sd->pan_func.get(sd->pan_obj, &px, &py);
2485    sd->pan_func.set(sd->pan_obj, x, y);
2486    if ((px != x) || (py != y))
2487      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2488 }
2489
2490 static void
2491 _smart_scrollbar_reset(Smart_Data *sd)
2492 {
2493    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2494
2495    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2496    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2497    if ((!sd->child_obj) && (!sd->extern_pan))
2498      {
2499         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2500         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2501      }
2502    if (sd->pan_obj)
2503      {
2504         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2505         sd->pan_func.get(sd->pan_obj, &px, &py);
2506         sd->pan_func.set(sd->pan_obj, minx, miny);
2507      }
2508    if ((px != minx) || (py != miny))
2509      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2510 }
2511
2512 static int
2513 _smart_scrollbar_bar_v_visibility_adjust(Smart_Data *sd)
2514 {
2515    int scroll_v_vis_change = 0;
2516    Evas_Coord h, vw = 0, vh = 0;
2517
2518    h = sd->child.h;
2519    if (sd->pan_obj)
2520      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2521    if (sd->vbar_visible)
2522      {
2523         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2524           {
2525              if ((sd->child_obj) || (sd->extern_pan))
2526                {
2527                   if (h <= vh)
2528                     {
2529                        scroll_v_vis_change = 1;
2530                        sd->vbar_visible = EINA_FALSE;
2531                     }
2532                }
2533              else
2534                {
2535                   scroll_v_vis_change = 1;
2536                   sd->vbar_visible = EINA_FALSE;
2537                }
2538           }
2539         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2540           {
2541              scroll_v_vis_change = 1;
2542              sd->vbar_visible = EINA_FALSE;
2543           }
2544      }
2545    else
2546      {
2547         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2548           {
2549              if ((sd->child_obj) || (sd->extern_pan))
2550                {
2551                   if (h > vh)
2552                     {
2553                        scroll_v_vis_change = 1;
2554                        sd->vbar_visible = EINA_TRUE;
2555                     }
2556                }
2557           }
2558         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2559           {
2560              scroll_v_vis_change = 1;
2561              sd->vbar_visible = EINA_TRUE;
2562           }
2563      }
2564    if (scroll_v_vis_change)
2565      {
2566         if (sd->vbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2567           {
2568              if (sd->vbar_visible)
2569                edje_object_signal_emit(sd->edje_obj, "elm,action,show,vbar", "elm");
2570              else
2571                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2572              edje_object_message_signal_process(sd->edje_obj);
2573              _smart_scrollbar_size_adjust(sd);
2574           }
2575         else
2576           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2577      }
2578    return scroll_v_vis_change;
2579 }
2580
2581 static int
2582 _smart_scrollbar_bar_h_visibility_adjust(Smart_Data *sd)
2583 {
2584    int scroll_h_vis_change = 0;
2585    Evas_Coord w, vw = 0, vh = 0;
2586
2587    w = sd->child.w;
2588    if (sd->pan_obj)
2589      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2590    if (sd->hbar_visible)
2591      {
2592         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2593           {
2594              if ((sd->child_obj) || (sd->extern_pan))
2595                {
2596                   if (w <= vw)
2597                     {
2598                        scroll_h_vis_change = 1;
2599                        sd->hbar_visible = EINA_FALSE;
2600                     }
2601                }
2602              else
2603                {
2604                   scroll_h_vis_change = 1;
2605                   sd->hbar_visible = EINA_FALSE;
2606                }
2607           }
2608         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2609           {
2610              scroll_h_vis_change = 1;
2611              sd->hbar_visible = EINA_FALSE;
2612           }
2613      }
2614    else
2615      {
2616         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2617           {
2618              if ((sd->child_obj) || (sd->extern_pan))
2619                {
2620                   if (w > vw)
2621                     {
2622                        scroll_h_vis_change = 1;
2623                        sd->hbar_visible = EINA_TRUE;
2624                     }
2625                }
2626           }
2627         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2628           {
2629              scroll_h_vis_change = 1;
2630              sd->hbar_visible = EINA_TRUE;
2631           }
2632      }
2633    if (scroll_h_vis_change)
2634      {
2635         if (sd->hbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2636           {
2637              if (sd->hbar_visible)
2638                edje_object_signal_emit(sd->edje_obj, "elm,action,show,hbar", "elm");
2639              else
2640                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2641              edje_object_message_signal_process(sd->edje_obj);
2642              _smart_scrollbar_size_adjust(sd);
2643           }
2644         else
2645           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2646         _smart_scrollbar_size_adjust(sd);
2647      }
2648    return scroll_h_vis_change;
2649 }
2650
2651 static void
2652 _smart_scrollbar_bar_visibility_adjust(Smart_Data *sd)
2653 {
2654    int changed = 0;
2655
2656    changed |= _smart_scrollbar_bar_h_visibility_adjust(sd);
2657    changed |= _smart_scrollbar_bar_v_visibility_adjust(sd);
2658    if (changed)
2659      {
2660         _smart_scrollbar_bar_h_visibility_adjust(sd);
2661         _smart_scrollbar_bar_v_visibility_adjust(sd);
2662      }
2663 }
2664
2665 static void
2666 _smart_scrollbar_size_adjust(Smart_Data *sd)
2667 {
2668    if ((sd->child_obj) || (sd->extern_pan))
2669      {
2670         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py, minx = 0, miny = 0;
2671         double vx, vy, size;
2672
2673         edje_object_part_geometry_get(sd->edje_obj, "elm.swallow.content",
2674                                       NULL, NULL, &vw, &vh);
2675         w = sd->child.w;
2676         if (w < 1) w = 1;
2677         size = (double)vw / (double)w;
2678         if (size > 1.0)
2679           {
2680              size = 1.0;
2681              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2682           }
2683         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", size, 1.0);
2684
2685         h = sd->child.h;
2686         if (h < 1) h = 1;
2687         size = (double)vh / (double)h;
2688         if (size > 1.0)
2689           {
2690              size = 1.0;
2691              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2692           }
2693         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, size);
2694
2695         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2696         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2697         sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2698         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2699         x = vx * mx + minx;
2700         y = vy * my + miny;
2701
2702         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->step.x / (double)w, 0.0);
2703         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->step.y / (double)h);
2704         if (sd->page.x > 0)
2705           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->page.x / (double)w, 0.0);
2706         else
2707           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", -((double)sd->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
2708         if (sd->page.y > 0)
2709           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->page.y / (double)h);
2710         else
2711           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, -((double)sd->page.y * ((double)vh / (double)h)) / 100.0);
2712
2713         sd->pan_func.get(sd->pan_obj, &px, &py);
2714         if (vx != mx) x = px;
2715         if (vy != my) y = py;
2716         sd->pan_func.set(sd->pan_obj, x, y);
2717         //      if ((px != 0) || (py != 0))
2718         //        edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2719      }
2720    else
2721      {
2722         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2723
2724         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2725         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2726         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2727         sd->pan_func.get(sd->pan_obj, &px, &py);
2728         sd->pan_func.set(sd->pan_obj, minx, miny);
2729         if ((px != minx) || (py != miny))
2730           edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2731      }
2732    _smart_scrollbar_bar_visibility_adjust(sd);
2733 }
2734
2735 static void
2736 _smart_reconfigure(Smart_Data *sd)
2737 {
2738    evas_object_move(sd->edje_obj, sd->x, sd->y);
2739    evas_object_resize(sd->edje_obj, sd->w, sd->h);
2740    evas_object_move(sd->event_obj, sd->x, sd->y);
2741    evas_object_resize(sd->event_obj, sd->w, sd->h);
2742    _smart_scrollbar_size_adjust(sd);
2743    _smart_page_adjust(sd);
2744 }
2745
2746 static void
2747 _smart_add(Evas_Object *obj)
2748 {
2749    Smart_Data *sd;
2750    Evas_Object *o;
2751
2752    sd = calloc(1, sizeof(Smart_Data));
2753    if (!sd) return;
2754    evas_object_smart_data_set(obj, sd);
2755
2756    sd->smart_obj = obj;
2757    sd->x = 0;
2758    sd->y = 0;
2759    sd->w = 0;
2760    sd->h = 0;
2761    sd->step.x = 32;
2762    sd->step.y = 32;
2763    sd->page.x = -50;
2764    sd->page.y = -50;
2765    sd->hbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2766    sd->vbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2767    sd->hbar_visible = EINA_TRUE;
2768    sd->vbar_visible = EINA_TRUE;
2769
2770    sd->bounce_horiz = EINA_TRUE;
2771    sd->bounce_vert = EINA_TRUE;
2772
2773    sd->one_dir_at_a_time = EINA_TRUE;
2774    sd->momentum_animator_disabled = EINA_FALSE;
2775    sd->bounce_animator_disabled = EINA_FALSE;
2776
2777    o = edje_object_add(evas_object_evas_get(obj));
2778    evas_object_propagate_events_set(o, 0);
2779    sd->edje_obj = o;
2780    elm_smart_scroller_object_theme_set(NULL, obj, "scroller", "base", "default");
2781    edje_object_signal_callback_add(o, "drag", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2782    edje_object_signal_callback_add(o, "drag,set", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2783    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.vbar", _smart_edje_drag_v_start, sd);
2784    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.vbar", _smart_edje_drag_v_stop, sd);
2785    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2786    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2787    edje_object_signal_callback_add(o, "drag", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2788    edje_object_signal_callback_add(o, "drag,set", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2789    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.hbar", _smart_edje_drag_h_start, sd);
2790    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.hbar", _smart_edje_drag_h_stop, sd);
2791    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2792    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2793    evas_object_smart_member_add(o, obj);
2794
2795    o = evas_object_rectangle_add(evas_object_evas_get(obj));
2796    sd->event_obj = o;
2797    evas_object_color_set(o, 0, 0, 0, 0);
2798    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
2799    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _smart_event_mouse_down, sd);
2800    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _smart_event_mouse_up, sd);
2801    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _smart_event_mouse_move, sd);
2802    evas_object_smart_member_add(o, obj);
2803    evas_object_repeat_events_set(o, 1);
2804
2805    sd->pan_func.set = _elm_smart_pan_set;
2806    sd->pan_func.get = _elm_smart_pan_get;
2807    sd->pan_func.max_get = _elm_smart_pan_max_get;
2808    sd->pan_func.min_get = _elm_smart_pan_min_get;
2809    sd->pan_func.child_size_get = _elm_smart_pan_child_size_get;
2810    sd->pan_func.gravity_set = _elm_smart_pan_gravity_set;
2811    sd->pan_func.gravity_get = _elm_smart_pan_gravity_get;
2812
2813    _smart_scrollbar_reset(sd);
2814 }
2815
2816 static void
2817 _smart_del(Evas_Object *obj)
2818 {
2819    INTERNAL_ENTRY;
2820    elm_smart_scroller_child_set(obj, NULL);
2821    if (!sd->extern_pan) evas_object_del(sd->pan_obj);
2822    evas_object_del(sd->edje_obj);
2823    evas_object_del(sd->event_obj);
2824    if (sd->down.hold_animator) ecore_animator_del(sd->down.hold_animator);
2825    if (sd->down.onhold_animator) ecore_animator_del(sd->down.onhold_animator);
2826    if (sd->down.momentum_animator) ecore_animator_del(sd->down.momentum_animator);
2827    if (sd->down.bounce_x_animator) ecore_animator_del(sd->down.bounce_x_animator);
2828    if (sd->down.bounce_y_animator) ecore_animator_del(sd->down.bounce_y_animator);
2829    if (sd->scrollto.x.animator) ecore_animator_del(sd->scrollto.x.animator);
2830    if (sd->scrollto.y.animator) ecore_animator_del(sd->scrollto.y.animator);
2831    free(sd);
2832    evas_object_smart_data_set(obj, NULL);
2833 }
2834
2835 static void
2836 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2837 {
2838    INTERNAL_ENTRY;
2839    sd->x = x;
2840    sd->y = y;
2841    _smart_reconfigure(sd);
2842 }
2843
2844 static void
2845 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2846 {
2847    INTERNAL_ENTRY;
2848    sd->w = w;
2849    sd->h = h;
2850    _smart_reconfigure(sd);
2851    _elm_smart_scroller_wanted_region_set(obj);
2852 }
2853
2854 static void
2855 _smart_show(Evas_Object *obj)
2856 {
2857    INTERNAL_ENTRY;
2858    evas_object_show(sd->edje_obj);
2859    evas_object_show(sd->event_obj);
2860 }
2861
2862 static void
2863 _smart_hide(Evas_Object *obj)
2864 {
2865    INTERNAL_ENTRY;
2866    evas_object_hide(sd->edje_obj);
2867    evas_object_hide(sd->event_obj);
2868 }
2869
2870 static void
2871 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
2872 {
2873    INTERNAL_ENTRY;
2874    evas_object_color_set(sd->edje_obj, r, g, b, a);
2875 }
2876
2877 static void
2878 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
2879 {
2880    INTERNAL_ENTRY;
2881    evas_object_clip_set(sd->edje_obj, clip);
2882    evas_object_clip_set(sd->event_obj, clip);
2883 }
2884
2885 static void
2886 _smart_clip_unset(Evas_Object *obj)
2887 {
2888    INTERNAL_ENTRY;
2889    evas_object_clip_unset(sd->edje_obj);
2890    evas_object_clip_unset(sd->event_obj);
2891 }
2892
2893 /* never need to touch this */
2894
2895 static void
2896 _smart_init(void)
2897 {
2898    if (_smart) return;
2899      {
2900         static const Evas_Smart_Class sc =
2901           {
2902              SMART_NAME,
2903              EVAS_SMART_CLASS_VERSION,
2904              _smart_add,
2905              _smart_del,
2906              _smart_move,
2907              _smart_resize,
2908              _smart_show,
2909              _smart_hide,
2910              _smart_color_set,
2911              _smart_clip_set,
2912              _smart_clip_unset,
2913              NULL,
2914              NULL,
2915              NULL,
2916              NULL,
2917              NULL,
2918              NULL,
2919              NULL
2920           };
2921         _smart = evas_smart_class_new(&sc);
2922      }
2923 }