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