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