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