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