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