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