Elementary els_scroller: Fix moving to Wanted X (wx) on child resize.
[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    elm_smart_scroller_child_pos_set(obj, nx, ny);
1065 }
1066
1067 /* Set should be used for calculated positions, for example, when we move
1068  * because of an animation or because this is the correct position after
1069  * constraints. */
1070 void
1071 elm_smart_scroller_child_region_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1072 {
1073    _elm_smart_scroller_child_region_show_internal(obj, x, y, w, h, EINA_TRUE);
1074 }
1075
1076 /* Set should be used for setting the wanted position, for example a user scroll
1077  * or moving the cursor in an entry. */
1078 void
1079 elm_smart_scroller_child_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1080 {
1081    _elm_smart_scroller_child_region_show_internal(obj, x, y, w, h, EINA_FALSE);
1082 }
1083
1084 void
1085 elm_smart_scroller_child_viewport_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
1086 {
1087    API_ENTRY return;
1088    edje_object_calc_force(sd->edje_obj);
1089    evas_object_geometry_get(sd->pan_obj, NULL, NULL, w, h);
1090 }
1091
1092 void
1093 elm_smart_scroller_step_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1094 {
1095    API_ENTRY return;
1096    if (x < 1) x = 1;
1097    if (y < 1) y = 1;
1098    sd->step.x = x;
1099    sd->step.y = y;
1100    _smart_scrollbar_size_adjust(sd);
1101 }
1102
1103 void
1104 elm_smart_scroller_step_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1105 {
1106    API_ENTRY return;
1107    if (x) *x = sd->step.x;
1108    if (y) *y = sd->step.y;
1109 }
1110
1111 void
1112 elm_smart_scroller_page_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1113 {
1114    API_ENTRY return;
1115    sd->page.x = x;
1116    sd->page.y = y;
1117    _smart_scrollbar_size_adjust(sd);
1118 }
1119
1120 void
1121 elm_smart_scroller_page_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1122 {
1123    API_ENTRY return;
1124    if (x) *x = sd->page.x;
1125    if (y) *y = sd->page.y;
1126 }
1127
1128 void
1129 elm_smart_scroller_policy_set(Evas_Object *obj, Elm_Smart_Scroller_Policy hbar, Elm_Smart_Scroller_Policy vbar)
1130 {
1131    API_ENTRY return;
1132    if ((sd->hbar_flags == hbar) && (sd->vbar_flags == vbar)) return;
1133    sd->hbar_flags = hbar;
1134    sd->vbar_flags = vbar;
1135    if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
1136      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,hbar", "elm");
1137    else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
1138      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
1139    else
1140      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,hbar", "elm");
1141    if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
1142      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,vbar", "elm");
1143    else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
1144      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
1145    else
1146      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,vbar", "elm");
1147    _smart_scrollbar_size_adjust(sd);
1148 }
1149
1150 void
1151 elm_smart_scroller_policy_get(Evas_Object *obj, Elm_Smart_Scroller_Policy *hbar, Elm_Smart_Scroller_Policy *vbar)
1152 {
1153    API_ENTRY return;
1154    if (hbar) *hbar = sd->hbar_flags;
1155    if (vbar) *vbar = sd->vbar_flags;
1156 }
1157
1158 Evas_Object *
1159 elm_smart_scroller_edje_object_get(Evas_Object *obj)
1160 {
1161    API_ENTRY return NULL;
1162    return sd->edje_obj;
1163 }
1164
1165 void
1166 elm_smart_scroller_single_dir_set(Evas_Object *obj, Eina_Bool single_dir)
1167 {
1168    API_ENTRY return;
1169    sd->one_dir_at_a_time = single_dir;
1170 }
1171
1172 Eina_Bool
1173 elm_smart_scroller_single_dir_get(Evas_Object *obj)
1174 {
1175    API_ENTRY return EINA_FALSE;
1176    return sd->one_dir_at_a_time;
1177 }
1178
1179 void
1180 elm_smart_scroller_object_theme_set(Evas_Object *parent, Evas_Object *obj, const char *clas, const char *group, const char *style)
1181 {
1182    API_ENTRY return;
1183    Evas_Coord mw, mh;
1184    _elm_theme_object_set(parent, sd->edje_obj, clas, group, style);
1185    edje_object_scale_set(sd->edje_obj, elm_widget_scale_get(parent) * _elm_config->scale);
1186    if (sd->pan_obj)
1187      edje_object_part_swallow(sd->edje_obj, "elm.swallow.content", sd->pan_obj);
1188    mw = mh = -1;
1189    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1190    if (edje_object_part_exists(sd->edje_obj, "elm.scrollbar.base"))
1191      {
1192         Evas_Object *base;
1193         base = edje_object_part_swallow_get(sd->edje_obj, "elm.scrollbar.base");
1194         if (!base)
1195           {
1196              base = evas_object_rectangle_add(evas_object_evas_get(sd->edje_obj));
1197              evas_object_color_set(base, 0, 0, 0, 0);
1198              edje_object_part_swallow(sd->edje_obj, "elm.scrollbar.base", base);
1199           }
1200         if (!_elm_config->thumbscroll_enable)
1201            evas_object_size_hint_min_set(base, mw, mh);
1202      }
1203    sd->vbar_visible = !sd->vbar_visible;
1204    sd->hbar_visible = !sd->hbar_visible;
1205    _smart_scrollbar_bar_visibility_adjust(sd);
1206 }
1207
1208 void
1209 elm_smart_scroller_hold_set(Evas_Object *obj, Eina_Bool hold)
1210 {
1211    API_ENTRY return;
1212    sd->hold = hold;
1213 }
1214
1215 void
1216 elm_smart_scroller_freeze_set(Evas_Object *obj, Eina_Bool freeze)
1217 {
1218    API_ENTRY return;
1219    sd->freeze = freeze;
1220    if (sd->freeze)
1221      {
1222         if (sd->down.onhold_animator)
1223           {
1224              ecore_animator_del(sd->down.onhold_animator);
1225              sd->down.onhold_animator = NULL;
1226           }
1227      }
1228 }
1229
1230 void
1231 elm_smart_scroller_bounce_allow_set(Evas_Object *obj, Eina_Bool horiz, Eina_Bool vert)
1232 {
1233    API_ENTRY return;
1234    sd->bounce_horiz = horiz;
1235    sd->bounce_vert = vert;
1236 }
1237
1238 void
1239 elm_smart_scroller_bounce_allow_get(const Evas_Object *obj, Eina_Bool *horiz, Eina_Bool *vert)
1240 {
1241    API_ENTRY return;
1242    *horiz = sd->bounce_horiz;
1243    *vert = sd->bounce_vert;
1244 }
1245
1246 void
1247 elm_smart_scroller_paging_set(Evas_Object *obj, double pagerel_h, double pagerel_v, Evas_Coord pagesize_h, Evas_Coord pagesize_v)
1248 {
1249    API_ENTRY return;
1250    sd->pagerel_h = pagerel_h;
1251    sd->pagerel_v = pagerel_v;
1252    sd->pagesize_h = pagesize_h;
1253    sd->pagesize_v = pagesize_v;
1254    _smart_page_adjust(sd);
1255 }
1256
1257 void
1258 elm_smart_scroller_paging_get(Evas_Object *obj, double *pagerel_h, double *pagerel_v, Evas_Coord *pagesize_h, Evas_Coord *pagesize_v)
1259 {
1260    API_ENTRY return;
1261    if(pagerel_h) *pagerel_h = sd->pagerel_h;
1262    if(pagerel_v) *pagerel_v = sd->pagerel_v;
1263    if(pagesize_h) *pagesize_h = sd->pagesize_h;
1264    if(pagesize_v) *pagesize_v = sd->pagesize_v;
1265 }
1266
1267 void
1268 elm_smart_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1269 {
1270    Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny, minx = 0, miny = 0;
1271
1272    API_ENTRY return;
1273    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
1274    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
1275    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
1276    sd->pan_func.get(sd->pan_obj, &px, &py);
1277
1278    nx = px;
1279    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1280    else if ((x > px) && ((x + w) > (px + (cw - mx)))) nx = x + w - (cw - mx);
1281    ny = py;
1282    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1283    else if ((y > py) && ((y + h) > (py + (ch - my)))) ny = y + h - (ch - my);
1284    sd->wx = x;
1285    sd->wy = y;
1286    sd->ww = w;
1287    sd->wh = h;
1288    if ((nx == px) && (ny == py)) return;
1289    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1290        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1291      {
1292         _smart_anim_stop(sd->smart_obj);
1293      }
1294    if (sd->scrollto.x.animator)
1295      {
1296         ecore_animator_del(sd->scrollto.x.animator);
1297         sd->scrollto.x.animator = NULL;
1298      }
1299    if (sd->scrollto.y.animator)
1300      {
1301         ecore_animator_del(sd->scrollto.y.animator);
1302         sd->scrollto.y.animator = NULL;
1303      }
1304    if (sd->down.bounce_x_animator)
1305      {
1306         ecore_animator_del(sd->down.bounce_x_animator);
1307         sd->down.bounce_x_animator = NULL;
1308         sd->bouncemex = 0;
1309      }
1310    if (sd->down.bounce_y_animator)
1311      {
1312         ecore_animator_del(sd->down.bounce_y_animator);
1313         sd->down.bounce_y_animator = NULL;
1314         sd->bouncemey = 0;
1315      }
1316    if (sd->down.hold_animator)
1317      {
1318         ecore_animator_del(sd->down.hold_animator);
1319         sd->down.hold_animator = NULL;
1320         _smart_drag_stop(sd->smart_obj);
1321      }
1322    if (sd->down.momentum_animator)
1323      {
1324         ecore_animator_del(sd->down.momentum_animator);
1325         sd->down.momentum_animator = NULL;
1326         sd->down.bounce_x_hold = 0;
1327         sd->down.bounce_y_hold = 0;
1328         sd->down.ax = 0;
1329         sd->down.ay = 0;
1330         sd->down.pdx = 0;
1331         sd->down.pdy = 0;
1332      }
1333    x = nx;
1334    if (x < minx) x = minx;
1335    else if ((x + w) > cw) x = cw - w;
1336    _smart_scrollto_x(sd, _elm_config->bring_in_scroll_friction, x);
1337    y = ny;
1338    if (y < miny) y = miny;
1339    else if ((y + h) > ch) y = ch - h;
1340    _smart_scrollto_y(sd, _elm_config->bring_in_scroll_friction, y);
1341 }
1342
1343 void
1344 elm_smart_scroller_widget_set(Evas_Object *obj, Evas_Object *wid)
1345 {
1346    API_ENTRY return;
1347    sd->widget = wid;
1348 }
1349
1350 static void
1351 _elm_smart_scroller_wanted_region_set(Evas_Object *obj)
1352 {
1353    INTERNAL_ENTRY;
1354    Evas_Coord ww, wh, wx = sd->wx;
1355
1356    /* Flip to RTL cords only if init in RTL mode */
1357    if(sd->is_mirrored)
1358      wx = _elm_smart_scroller_x_mirrored_get(obj, sd->wx);
1359
1360    if (sd->ww == -1)
1361      {
1362         elm_smart_scroller_child_viewport_size_get(obj, &ww, &wh);
1363      }
1364    else
1365      {
1366         ww = sd->ww;
1367         wh = sd->wh;
1368      }
1369
1370    elm_smart_scroller_child_region_set(obj, wx, sd->wy, ww, wh);
1371 }
1372
1373 /* local subsystem functions */
1374 static void
1375 _smart_edje_drag_v_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1376 {
1377    Smart_Data *sd;
1378
1379    sd = data;
1380    _smart_scrollbar_read(sd);
1381    _smart_drag_start(sd->smart_obj);
1382    sd->freeze = EINA_TRUE;
1383 }
1384
1385 static void
1386 _smart_edje_drag_v_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1387 {
1388    Smart_Data *sd;
1389
1390    sd = data;
1391    _smart_scrollbar_read(sd);
1392    _smart_drag_stop(sd->smart_obj);
1393    sd->freeze = EINA_FALSE;
1394 }
1395
1396 static void
1397 _smart_edje_drag_v(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1398 {
1399    Smart_Data *sd;
1400
1401    sd = data;
1402    _smart_scrollbar_read(sd);
1403 }
1404
1405 static void
1406 _smart_edje_drag_h_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1407 {
1408    Smart_Data *sd;
1409
1410    sd = data;
1411    _smart_scrollbar_read(sd);
1412    _smart_drag_start(sd->smart_obj);
1413    sd->freeze = EINA_TRUE;
1414 }
1415
1416 static void
1417 _smart_edje_drag_h_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1418 {
1419    Smart_Data *sd;
1420
1421    sd = data;
1422    _smart_scrollbar_read(sd);
1423    _smart_drag_stop(sd->smart_obj);
1424    sd->freeze = EINA_FALSE;
1425 }
1426
1427 static void
1428 _smart_edje_drag_h(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1429 {
1430    Smart_Data *sd;
1431
1432    sd = data;
1433    _smart_scrollbar_read(sd);
1434 }
1435
1436 static void
1437 _smart_child_del_hook(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1438 {
1439    Smart_Data *sd;
1440
1441    sd = data;
1442    sd->child_obj = NULL;
1443    _smart_scrollbar_size_adjust(sd);
1444    _smart_scrollbar_reset(sd);
1445 }
1446
1447 static void
1448 _smart_pan_changed_hook(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1449 {
1450    Evas_Coord w, h;
1451    Smart_Data *sd;
1452
1453    sd = data;
1454    sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
1455    if ((w != sd->child.w) || (h != sd->child.h))
1456      {
1457         sd->child.w = w;
1458         sd->child.h = h;
1459         _smart_scrollbar_size_adjust(sd);
1460         evas_object_size_hint_min_set(sd->smart_obj, sd->child.w, sd->child.h);
1461         _elm_smart_scroller_wanted_region_set(sd->smart_obj);
1462      }
1463 }
1464
1465 static void
1466 _smart_pan_pan_changed_hook(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1467 {
1468    Smart_Data *sd;
1469
1470    sd = data;
1471    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1472        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1473      {
1474         _smart_anim_stop(sd->smart_obj);
1475      }
1476    if (sd->scrollto.x.animator)
1477      {
1478         ecore_animator_del(sd->scrollto.x.animator);
1479         sd->scrollto.x.animator = NULL;
1480      }
1481    if (sd->scrollto.y.animator)
1482      {
1483         ecore_animator_del(sd->scrollto.y.animator);
1484         sd->scrollto.y.animator = NULL;
1485      }
1486    if (sd->down.bounce_x_animator)
1487      {
1488         ecore_animator_del(sd->down.bounce_x_animator);
1489         sd->down.bounce_x_animator = NULL;
1490         sd->bouncemex = 0;
1491      }
1492    if (sd->down.bounce_y_animator)
1493      {
1494         ecore_animator_del(sd->down.bounce_y_animator);
1495         sd->down.bounce_y_animator = NULL;
1496         sd->bouncemey = 0;
1497      }
1498    _elm_smart_scroller_wanted_region_set(sd->smart_obj);
1499 }
1500
1501 static void
1502 _smart_event_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1503 {
1504    Evas_Event_Mouse_Wheel *ev;
1505    Smart_Data *sd;
1506    Evas_Coord x = 0, y = 0;
1507
1508    sd = data;
1509    ev = event_info;
1510    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1511    if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
1512        (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
1513        (evas_key_modifier_is_set(ev->modifiers, "Shift")) ||
1514        (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
1515        (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
1516        (evas_key_modifier_is_set(ev->modifiers, "Super")))
1517      return;
1518    elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1519    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1520        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1521      {
1522         _smart_anim_stop(sd->smart_obj);
1523      }
1524    if (sd->scrollto.x.animator)
1525      {
1526         ecore_animator_del(sd->scrollto.x.animator);
1527         sd->scrollto.x.animator = NULL;
1528      }
1529    if (sd->scrollto.y.animator)
1530      {
1531         ecore_animator_del(sd->scrollto.y.animator);
1532         sd->scrollto.y.animator = NULL;
1533      }
1534    if (sd->down.bounce_x_animator)
1535      {
1536         ecore_animator_del(sd->down.bounce_x_animator);
1537         sd->down.bounce_x_animator = NULL;
1538         sd->bouncemex = 0;
1539      }
1540    if (sd->down.bounce_y_animator)
1541      {
1542         ecore_animator_del(sd->down.bounce_y_animator);
1543         sd->down.bounce_y_animator = NULL;
1544         sd->bouncemey = 0;
1545      }
1546    if (!ev->direction)
1547      y += ev->z * sd->step.y;
1548    else if (ev->direction == 1)
1549      x += ev->z * sd->step.x;
1550
1551    if ((!sd->hold) && (!sd->freeze))
1552      {
1553         _update_wanted_coordinates(sd, x, y);
1554         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1555      }
1556 }
1557
1558 static void
1559 _smart_event_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1560 {
1561    Evas_Event_Mouse_Down *ev;
1562    Smart_Data *sd;
1563    Evas_Coord x = 0, y = 0;
1564
1565    sd = data;
1566    ev = event_info;
1567 //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1568    if (_elm_config->thumbscroll_enable)
1569      {
1570         sd->down.hold = 0;
1571         if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1572             (sd->down.momentum_animator) || (sd->scrollto.x.animator) ||
1573             (sd->scrollto.y.animator))
1574           {
1575              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL | EVAS_EVENT_FLAG_ON_HOLD;
1576              sd->down.scroll = 1;
1577              sd->down.hold = 1;
1578              _smart_anim_stop(sd->smart_obj);
1579           }
1580         if (sd->scrollto.x.animator)
1581           {
1582              ecore_animator_del(sd->scrollto.x.animator);
1583              sd->scrollto.x.animator = NULL;
1584           }
1585         if (sd->scrollto.y.animator)
1586           {
1587              ecore_animator_del(sd->scrollto.y.animator);
1588              sd->scrollto.y.animator = NULL;
1589           }
1590         if (sd->down.bounce_x_animator)
1591           {
1592              ecore_animator_del(sd->down.bounce_x_animator);
1593              sd->down.bounce_x_animator = NULL;
1594              sd->bouncemex = 0;
1595           }
1596         if (sd->down.bounce_y_animator)
1597           {
1598              ecore_animator_del(sd->down.bounce_y_animator);
1599              sd->down.bounce_y_animator = NULL;
1600              sd->bouncemey = 0;
1601           }
1602         if (sd->down.hold_animator)
1603           {
1604              ecore_animator_del(sd->down.hold_animator);
1605              sd->down.hold_animator = NULL;
1606              _smart_drag_stop(sd->smart_obj);
1607           }
1608         if (sd->down.momentum_animator)
1609           {
1610              ecore_animator_del(sd->down.momentum_animator);
1611              sd->down.momentum_animator = NULL;
1612              sd->down.bounce_x_hold = 0;
1613              sd->down.bounce_y_hold = 0;
1614              sd->down.ax = 0;
1615              sd->down.ay = 0;
1616           }
1617         if (ev->button == 1)
1618           {
1619              sd->down.now = 1;
1620              sd->down.dragged = 0;
1621              sd->down.dir_x = 0;
1622              sd->down.dir_y = 0;
1623              sd->down.x = ev->canvas.x;
1624              sd->down.y = ev->canvas.y;
1625              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1626              sd->down.sx = x;
1627              sd->down.sy = y;
1628              sd->down.locked = 0;
1629              memset(&(sd->down.history[0]), 0, sizeof(sd->down.history[0]) * 20);
1630 #ifdef EVTIME
1631              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
1632 #else
1633              sd->down.history[0].timestamp = ecore_loop_time_get();
1634 #endif
1635              sd->down.history[0].x = ev->canvas.x;
1636              sd->down.history[0].y = ev->canvas.y;
1637           }
1638         sd->down.dragged_began = 0;
1639         sd->down.hold_parent = 0;
1640         sd->down.cancelled = 0;
1641      }
1642 }
1643
1644 static Eina_Bool
1645 _smart_hold_animator(void *data)
1646 {
1647    Smart_Data *sd = data;
1648    Evas_Coord ox, oy;
1649    
1650    elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
1651    if (sd->down.dir_x)
1652      {
1653         if ((!sd->widget) || 
1654             (!elm_widget_drag_child_locked_x_get(sd->widget)))
1655           {
1656              ox = sd->down.hold_x;
1657           }
1658      }
1659    if (sd->down.dir_y)
1660      {
1661         if ((!sd->widget) || 
1662             (!elm_widget_drag_child_locked_y_get(sd->widget)))
1663           {
1664              oy = sd->down.hold_y;
1665           }
1666      }
1667    elm_smart_scroller_child_pos_set(sd->smart_obj, ox, oy);
1668    return ECORE_CALLBACK_RENEW;
1669 }
1670
1671 static Eina_Bool
1672 _smart_event_post_up(void *data, Evas *e __UNUSED__)
1673 {
1674    Smart_Data *sd = data;
1675    if (sd->widget)
1676      {
1677         if (sd->down.dragged)
1678           {
1679              elm_widget_drag_lock_x_set(sd->widget, 0);
1680              elm_widget_drag_lock_y_set(sd->widget, 0);
1681           }
1682      }
1683    return EINA_TRUE;
1684 }
1685
1686 static void
1687 _smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
1688 {
1689    Evas_Event_Mouse_Down *ev;
1690    Smart_Data *sd;
1691    Evas_Coord x = 0, y = 0, ox = 0, oy = 0;
1692
1693    sd = data;
1694    ev = event_info;
1695    sd->down.hold_parent = 0;
1696 //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1697    evas_post_event_callback_push(e, _smart_event_post_up, sd);
1698    // FIXME: respect elm_widget_scroll_hold_get of parent container
1699    if (_elm_config->thumbscroll_enable)
1700      {
1701         if (ev->button == 1)
1702           {
1703              if (sd->down.onhold_animator)
1704                {
1705                   ecore_animator_del(sd->down.onhold_animator);
1706                   sd->down.onhold_animator = NULL;
1707                }
1708              x = ev->canvas.x - sd->down.x;
1709              y = ev->canvas.y - sd->down.y;
1710              if (sd->down.dragged)
1711                {
1712                   _smart_drag_stop(sd->smart_obj);
1713                   if ((!sd->hold) && (!sd->freeze))
1714                     {
1715                        double t, at, dt;
1716                        int i;
1717                        Evas_Coord ax, ay, dx, dy, vel;
1718
1719 #ifdef EVTIME
1720                        t = ev->timestamp / 1000.0;
1721 #else
1722                        t = ecore_loop_time_get();
1723 #endif
1724                        ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1725                        ax = ev->canvas.x;
1726                        ay = ev->canvas.y;
1727                        at = 0.0;
1728 #ifdef SCROLLDBG
1729                        printf("------ %i %i\n", ev->canvas.x, ev->canvas.y);
1730 #endif
1731                        for (i = 0; i < 20; i++)
1732                          {
1733                             dt = t - sd->down.history[i].timestamp;
1734                             if (dt > 0.2) break;
1735 #ifdef SCROLLDBG
1736                             printf("H: %i %i @ %1.3f\n",
1737                                    sd->down.history[i].x,
1738                                    sd->down.history[i].y, dt);
1739 #endif
1740                             at += dt;
1741                             ax += sd->down.history[i].x;
1742                             ay += sd->down.history[i].y;
1743                          }
1744                        ax /= (i + 1);
1745                        ay /= (i + 1);
1746                        at /= (i + 1);
1747                        at *= 4.0;
1748                        dx = ev->canvas.x - ax;
1749                        dy = ev->canvas.y - ay;
1750                        if (at > 0)
1751                          {
1752                             vel = sqrt((dx * dx) + (dy * dy)) / at;
1753                             if ((_elm_config->thumbscroll_friction > 0.0) &&
1754                                 (vel > _elm_config->thumbscroll_momentum_threshold) &&
1755                                 (!sd->freeze))
1756                               {
1757                                  sd->down.dx = ((double)dx / at);
1758                                  sd->down.dy = ((double)dy / at);
1759                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1760                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)))
1761                                    sd->down.dx += (double)sd->down.pdx * 1.5; // FIXME: * 1.5 - probably should be config
1762                                  if (((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1763                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1764                                    sd->down.dy += (double)sd->down.pdy * 1.5; // FIXME: * 1.5 - probably should be config
1765                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1766                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)) ||
1767                                      ((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1768                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1769                                   {
1770                                     double t = ecore_loop_time_get();
1771                                     double dt = t - sd->down.anim_start;
1772                                     
1773                                     if (dt < 0.0) dt = 0.0;
1774                                     else if (dt > _elm_config->thumbscroll_friction)
1775                                       dt = _elm_config->thumbscroll_friction;
1776                                     sd->down.extra_time = _elm_config->thumbscroll_friction - dt;
1777                                   }
1778                                  else
1779                                   sd->down.extra_time = 0.0;
1780                                  sd->down.pdx = sd->down.dx;
1781                                  sd->down.pdy = sd->down.dy;
1782                                  ox = -sd->down.dx;
1783                                  oy = -sd->down.dy;
1784                                  if (!_smart_do_page(sd))
1785                                    {
1786                                       if (!sd->down.momentum_animator && !sd->momentum_animator_disabled)
1787                                         {
1788                                            sd->down.momentum_animator = ecore_animator_add(_smart_momentum_animator, sd);
1789                                            ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1790                                            _smart_anim_start(sd->smart_obj);
1791                                         }
1792                                       sd->down.anim_start = ecore_loop_time_get();
1793                                       elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1794                                       sd->down.sx = x;
1795                                       sd->down.sy = y;
1796                                       sd->down.b0x = 0;
1797                                       sd->down.b0y = 0;
1798                                    }
1799                               }
1800                          }
1801                        if (sd->down.hold_animator)
1802                          {
1803                             ecore_animator_del(sd->down.hold_animator);
1804                             sd->down.hold_animator = NULL;
1805                          }
1806                     }
1807                   else
1808                     {
1809                        sd->down.pdx = 0;
1810                        sd->down.pdy = 0;
1811                     }
1812                   evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
1813                   if (_smart_do_page(sd))
1814                     {
1815                        Evas_Coord pgx, pgy;
1816
1817                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1818                        if ((!sd->widget) || 
1819                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1820                          {
1821                             pgx = _smart_page_x_get(sd, ox);
1822                             if (pgx != x) 
1823                               {
1824                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1825                                  _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1826                               }
1827                          }
1828                        if ((!sd->widget) || 
1829                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1830                          {
1831                             pgy = _smart_page_y_get(sd, oy);
1832                             if (pgy != y) 
1833                               {
1834                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1835                                  _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
1836                               }
1837                          }
1838                     }
1839                }
1840              else
1841                {
1842                   sd->down.pdx = 0;
1843                   sd->down.pdy = 0;
1844                   if (_smart_do_page(sd))
1845                     {
1846                        Evas_Coord pgx, pgy;
1847
1848                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1849                        if ((!sd->widget) || 
1850                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1851                          {
1852                             pgx = _smart_page_x_get(sd, ox);
1853                             if (pgx != x) _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1854                          }
1855                        if ((!sd->widget) || 
1856                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1857                          {
1858                             pgy = _smart_page_y_get(sd, oy);
1859                             if (pgy != y) _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
1860                          }
1861                     }
1862                   if (sd->down.hold_animator)
1863                     {
1864                        ecore_animator_del(sd->down.hold_animator);
1865                        sd->down.hold_animator = NULL;
1866                     }
1867                }
1868              if (sd->down.scroll)
1869                {
1870                   ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1871                   sd->down.scroll = 0;
1872                }
1873              if (sd->down.hold)
1874                {
1875                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1876                   sd->down.hold = 0;
1877                }
1878              sd->down.dragged_began = 0;
1879              sd->down.dir_x = 0;
1880              sd->down.dir_y = 0;
1881              sd->down.want_dragged = 0;
1882              sd->down.dragged = 0;
1883              sd->down.now = 0;
1884              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1885              elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1886              _update_wanted_coordinates(sd, x, y);
1887
1888              if (!_smart_do_page(sd))
1889                bounce_eval(sd);
1890           }
1891      }
1892 }
1893
1894 static Eina_Bool
1895 _smart_onhold_animator(void *data)
1896 {
1897    Smart_Data *sd;
1898    double t, td;
1899    double vx, vy;
1900    Evas_Coord x, y, ox, oy;
1901
1902    sd = data;
1903    t = ecore_loop_time_get();
1904    if (sd->down.onhold_tlast > 0.0)
1905      {
1906         td = t - sd->down.onhold_tlast;
1907         vx = sd->down.onhold_vx * td * (double)_elm_config->thumbscroll_threshold * 2.0;
1908         vy = sd->down.onhold_vy * td * (double)_elm_config->thumbscroll_threshold * 2.0;
1909         elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
1910         x = ox;
1911         y = oy;
1912         
1913         if (sd->down.dir_x)
1914           {
1915              if ((!sd->widget) || 
1916                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
1917                {
1918                   sd->down.onhold_vxe += vx;
1919                   x = ox + (int)sd->down.onhold_vxe;
1920                   sd->down.onhold_vxe -= (int)sd->down.onhold_vxe;
1921                }
1922           }
1923         
1924         if (sd->down.dir_y)
1925           {
1926              if ((!sd->widget) || 
1927                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
1928                {
1929                   sd->down.onhold_vye += vy;
1930                   y = oy + (int)sd->down.onhold_vye;
1931                   sd->down.onhold_vye -= (int)sd->down.onhold_vye;
1932                }
1933           }
1934         
1935         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1936      }
1937    sd->down.onhold_tlast = t;
1938    return ECORE_CALLBACK_RENEW;
1939 }
1940
1941 static Eina_Bool
1942 _smart_event_post_move(void *data, Evas *e __UNUSED__)
1943 {
1944    Smart_Data *sd = data;
1945
1946    if (sd->down.want_dragged)
1947      {
1948         int start = 0;
1949
1950         if (sd->down.hold_parent)
1951           {
1952              if ((sd->down.dir_x) && !can_scroll(sd, sd->down.hdir))
1953                {
1954                   sd->down.dir_x = 0;
1955                }
1956              if ((sd->down.dir_y) && !can_scroll(sd, sd->down.vdir))
1957                {
1958                   sd->down.dir_y = 0;
1959                }
1960           }
1961         if (sd->down.dir_x)
1962           {
1963              if ((!sd->widget) || 
1964                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
1965                {
1966                   sd->down.want_dragged = 0;
1967                   sd->down.dragged = 1;
1968                   if (sd->widget)
1969                     {
1970                        elm_widget_drag_lock_x_set(sd->widget, 1);
1971                     }
1972                   start = 1;
1973                }
1974              else
1975                sd->down.dir_x = 0;
1976           }
1977         if (sd->down.dir_y)
1978           {
1979              if ((!sd->widget) || 
1980                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
1981                {
1982                   sd->down.want_dragged = 0;
1983                   sd->down.dragged = 1;
1984                   if (sd->widget)
1985                     {
1986                        elm_widget_drag_lock_y_set(sd->widget, 1);
1987                     }
1988                   start = 1;
1989                }
1990              else
1991                sd->down.dir_y = 0;
1992           }
1993         if ((!sd->down.dir_x) && (!sd->down.dir_y))
1994           {
1995              sd->down.cancelled = 1;
1996           }
1997         if (start) _smart_drag_start(sd->smart_obj);
1998      }
1999    return EINA_TRUE;
2000 }
2001
2002 static void
2003 _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
2004 {
2005    Evas_Event_Mouse_Move *ev;
2006    Smart_Data *sd;
2007    Evas_Coord x = 0, y = 0;
2008
2009    sd = data;
2010    ev = event_info;
2011 //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
2012    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->down.hold_parent = 1;
2013    evas_post_event_callback_push(e, _smart_event_post_move, sd);
2014    // FIXME: respect elm_widget_scroll_hold_get of parent container
2015    if (_elm_config->thumbscroll_enable)
2016      {
2017         if (sd->down.now)
2018           {
2019              int dodir = 0;
2020
2021 #ifdef SCROLLDBG
2022              printf("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2023 #endif
2024              memmove(&(sd->down.history[1]), &(sd->down.history[0]),
2025                      sizeof(sd->down.history[0]) * 19);
2026 #ifdef EVTIME
2027              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
2028 #else
2029              sd->down.history[0].timestamp = ecore_loop_time_get();
2030 #endif
2031              sd->down.history[0].x = ev->cur.canvas.x;
2032              sd->down.history[0].y = ev->cur.canvas.y;
2033
2034              if (!sd->down.dragged_began)
2035                {
2036                   x = ev->cur.canvas.x - sd->down.x;
2037                   y = ev->cur.canvas.y - sd->down.y;
2038                   
2039                   sd->down.hdir = -1;
2040                   sd->down.vdir = -1;
2041                     
2042                   if      (x > 0) sd->down.hdir = LEFT;
2043                   else if (x < 0) sd->down.hdir = RIGHT;
2044                   if      (y > 0) sd->down.vdir = UP;
2045                   else if (y < 0) sd->down.vdir = DOWN;
2046                   
2047                   if (x < 0) x = -x;
2048                   if (y < 0) y = -y;
2049              
2050                   if ((sd->one_dir_at_a_time) &&
2051                       (!((sd->down.dir_x) || (sd->down.dir_y))))
2052                     {
2053                        if (x > _elm_config->thumbscroll_threshold)
2054                          {
2055                             if (x > (y * 2))
2056                               {
2057                                  sd->down.dir_x = 1;
2058                                  sd->down.dir_y = 0;
2059                                  dodir++;
2060                               }
2061                          }
2062                        if (y > _elm_config->thumbscroll_threshold)
2063                          {
2064                             if (y > (x * 2))
2065                               {
2066                                  sd->down.dir_x = 0;
2067                                  sd->down.dir_y = 1;
2068                                  dodir++;
2069                               }
2070                          }
2071                        if (!dodir)
2072                          {
2073                             sd->down.dir_x = 1;
2074                             sd->down.dir_y = 1;
2075                          }
2076                     }
2077                   else
2078                     {
2079 //                       can_scroll(sd, LEFT);
2080 //                       can_scroll(sd, RIGHT);
2081 //                       can_scroll(sd, UP);
2082 //                       can_scroll(sd, DOWN);
2083                        sd->down.dir_x = 1;
2084                        sd->down.dir_y = 1;
2085                     }
2086                }
2087              if ((!sd->hold) && (!sd->freeze))
2088                {
2089                   if ((sd->down.dragged) ||
2090                       (((x * x) + (y * y)) >
2091                        (_elm_config->thumbscroll_threshold *
2092                         _elm_config->thumbscroll_threshold)))
2093                     {
2094                        sd->down.dragged_began = 1;
2095                        if (!sd->down.dragged)
2096                          {
2097                             sd->down.want_dragged = 1;
2098                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2099 //                            evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2100 //                            _smart_drag_start(sd->smart_obj);
2101                          }
2102                        if (sd->down.dragged)
2103                          {
2104                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2105                          }
2106 //                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2107 //                       sd->down.dragged = 1;
2108                        if (sd->down.dir_x)
2109                          x = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
2110                        else
2111                          x = sd->down.sx;
2112                        if (sd->down.dir_y)
2113                          y = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
2114                        else
2115                          y = sd->down.sy;
2116                        if ((sd->down.dir_x) || (sd->down.dir_y))
2117                          {
2118                             if (!sd->down.locked)
2119                               {
2120                                  sd->down.locked_x = x;
2121                                  sd->down.locked_y = y;
2122                                  sd->down.locked = 1;
2123                               }
2124                             if (!((sd->down.dir_x) && (sd->down.dir_y)))
2125                               {
2126                                  if (sd->down.dir_x) y = sd->down.locked_y;
2127                                  else x = sd->down.locked_x;
2128                               }
2129                          }
2130                        if (_elm_config->thumbscroll_border_friction > 0.0)
2131                          {
2132                             Evas_Coord minx, miny;
2133                             sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2134                             if (y < miny)
2135                                y += (miny - y) *
2136                                   _elm_config->thumbscroll_border_friction;
2137                             else if (sd->child.h <= sd->h)
2138                                y += (sd->down.sy - y) *
2139                                   _elm_config->thumbscroll_border_friction;
2140                             else if ((sd->child.h - sd->h + miny) < y)
2141                                y += (sd->child.h - sd->h + miny - y) *
2142                                   _elm_config->thumbscroll_border_friction;
2143                             if (x < minx)
2144                                x += (minx - x) *
2145                                   _elm_config->thumbscroll_border_friction;
2146                             else if (sd->child.w <= sd->w)
2147                                x += (sd->down.sx - x) *
2148                                   _elm_config->thumbscroll_border_friction;
2149                             else if ((sd->child.w - sd->w + minx) < x)
2150                                x += (sd->child.w - sd->w + minx - x) *
2151                                   _elm_config->thumbscroll_border_friction;
2152                          }
2153
2154                        sd->down.hold_x = x;
2155                        sd->down.hold_y = y;
2156                        if (!sd->down.hold_animator)
2157                          sd->down.hold_animator = 
2158                             ecore_animator_add(_smart_hold_animator, sd);
2159 //                       printf("a %i %i\n", sd->down.hold_x, sd->down.hold_y);
2160 //                       _smart_onhold_animator(sd);
2161 //                       elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2162                     }
2163                   else
2164                     {
2165                        if (sd->down.dragged_began)
2166                          {
2167                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2168                             if (!sd->down.hold)
2169                               {
2170                                  sd->down.hold = 1;
2171                                  evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2172                               }
2173                          }
2174                     }
2175                }
2176              else if (!sd->freeze)
2177                {
2178                   Evas_Coord ex, ey, ew, eh;
2179                   double vx = 0.0, vy = 0.0;
2180
2181                   evas_object_geometry_get(sd->event_obj, &ex, &ey, &ew, &eh);
2182                   x = ev->cur.canvas.x - ex;
2183                   y = ev->cur.canvas.y - ey;
2184                   if (x < _elm_config->thumbscroll_threshold)
2185                     {
2186                        if (_elm_config->thumbscroll_threshold > 0.0)
2187                          vx = -(double)(_elm_config->thumbscroll_threshold - x) /
2188                          _elm_config->thumbscroll_threshold;
2189                        else
2190                          vx = -1.0;
2191                     }
2192                   else if (x > (ew - _elm_config->thumbscroll_threshold))
2193                     {
2194                        if (_elm_config->thumbscroll_threshold > 0.0)
2195                          vx = (double)(_elm_config->thumbscroll_threshold - (ew - x)) /
2196                          _elm_config->thumbscroll_threshold;
2197                        else
2198                          vx = 1.0;
2199                     }
2200                   if (y < _elm_config->thumbscroll_threshold)
2201                     {
2202                        if (_elm_config->thumbscroll_threshold > 0.0)
2203                          vy = -(double)(_elm_config->thumbscroll_threshold - y) /
2204                          _elm_config->thumbscroll_threshold;
2205                        else
2206                          vy = -1.0;
2207                     }
2208                   else if (y > (eh - _elm_config->thumbscroll_threshold))
2209                     {
2210                        if (_elm_config->thumbscroll_threshold > 0.0)
2211                          vy = (double)(_elm_config->thumbscroll_threshold - (eh - y)) /
2212                          _elm_config->thumbscroll_threshold;
2213                        else
2214                          vy = 1.0;
2215                     }
2216                   if ((vx != 0.0) || (vy != 0.0))
2217                     {
2218                        sd->down.onhold_vx = vx;
2219                        sd->down.onhold_vy = vy;
2220                        if (!sd->down.onhold_animator)
2221                          {
2222                             sd->down.onhold_vxe = 0.0;
2223                             sd->down.onhold_vye = 0.0;
2224                             sd->down.onhold_tlast = 0.0;
2225                             sd->down.onhold_animator = ecore_animator_add(_smart_onhold_animator, sd);
2226                          }
2227 //                       printf("b %i %i\n", sd->down.hold_x, sd->down.hold_y);
2228                     }
2229                   else
2230                     {
2231                        if (sd->down.onhold_animator)
2232                          {
2233                             ecore_animator_del(sd->down.onhold_animator);
2234                             sd->down.onhold_animator = NULL;
2235                          }
2236                     }
2237                }
2238           }
2239      }
2240 }
2241
2242 static void
2243 _smart_scrollbar_read(Smart_Data *sd)
2244 {
2245    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
2246    double vx, vy;
2247
2248    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2249    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2250    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2251    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2252    x = vx * (double)mx + minx;
2253    y = vy * (double)my + miny;
2254    sd->pan_func.get(sd->pan_obj, &px, &py);
2255    sd->pan_func.set(sd->pan_obj, x, y);
2256    if ((px != x) || (py != y))
2257      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2258 }
2259
2260 static void
2261 _smart_scrollbar_reset(Smart_Data *sd)
2262 {
2263    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2264
2265    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2266    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2267    if ((!sd->child_obj) && (!sd->extern_pan))
2268      {
2269         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2270         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2271      }
2272    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2273    sd->pan_func.get(sd->pan_obj, &px, &py);
2274    sd->pan_func.set(sd->pan_obj, minx, miny);
2275    if ((px != minx) || (py != miny))
2276      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2277 }
2278
2279 static int
2280 _smart_scrollbar_bar_v_visibility_adjust(Smart_Data *sd)
2281 {
2282    int scroll_v_vis_change = 0;
2283    Evas_Coord h, vw, vh;
2284
2285    h = sd->child.h;
2286    evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2287    if (sd->vbar_visible)
2288      {
2289         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2290           {
2291              if ((sd->child_obj) || (sd->extern_pan))
2292                {
2293                   if (h <= vh)
2294                     {
2295                        scroll_v_vis_change = 1;
2296                        sd->vbar_visible = 0;
2297                     }
2298                }
2299              else
2300                {
2301                   scroll_v_vis_change = 1;
2302                   sd->vbar_visible = 0;
2303                }
2304           }
2305         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2306           {
2307              scroll_v_vis_change = 1;
2308              sd->vbar_visible = 0;
2309           }
2310      }
2311    else
2312      {
2313         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2314           {
2315              if ((sd->child_obj) || (sd->extern_pan))
2316                {
2317                   if (h > vh)
2318                     {
2319                        scroll_v_vis_change = 1;
2320                        sd->vbar_visible = 1;
2321                     }
2322                }
2323           }
2324         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2325           {
2326              scroll_v_vis_change = 1;
2327              sd->vbar_visible = 1;
2328           }
2329      }
2330    if (scroll_v_vis_change)
2331      {
2332         if (sd->vbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2333           {
2334              if (sd->vbar_visible)
2335                edje_object_signal_emit(sd->edje_obj, "elm,action,show,vbar", "elm");
2336              else
2337                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2338              edje_object_message_signal_process(sd->edje_obj);
2339              _smart_scrollbar_size_adjust(sd);
2340           }
2341         else
2342           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2343      }
2344    return scroll_v_vis_change;
2345 }
2346
2347 static int
2348 _smart_scrollbar_bar_h_visibility_adjust(Smart_Data *sd)
2349 {
2350    int scroll_h_vis_change = 0;
2351    Evas_Coord w, vw, vh;
2352
2353    w = sd->child.w;
2354    evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2355    if (sd->hbar_visible)
2356      {
2357         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2358           {
2359              if ((sd->child_obj) || (sd->extern_pan))
2360                {
2361                   if (w <= vw)
2362                     {
2363                        scroll_h_vis_change = 1;
2364                        sd->hbar_visible = 0;
2365                     }
2366                }
2367              else
2368                {
2369                   scroll_h_vis_change = 1;
2370                   sd->hbar_visible = 0;
2371                }
2372           }
2373         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2374           {
2375              scroll_h_vis_change = 1;
2376              sd->hbar_visible = 0;
2377           }
2378      }
2379    else
2380      {
2381         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2382           {
2383              if ((sd->child_obj) || (sd->extern_pan))
2384                {
2385                   if (w > vw)
2386                     {
2387                        scroll_h_vis_change = 1;
2388                        sd->hbar_visible = 1;
2389                     }
2390                }
2391           }
2392         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2393           {
2394              scroll_h_vis_change = 1;
2395              sd->hbar_visible = 1;
2396           }
2397      }
2398    if (scroll_h_vis_change)
2399      {
2400         if (sd->hbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2401           {
2402              if (sd->hbar_visible)
2403                edje_object_signal_emit(sd->edje_obj, "elm,action,show,hbar", "elm");
2404              else
2405                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2406              edje_object_message_signal_process(sd->edje_obj);
2407              _smart_scrollbar_size_adjust(sd);
2408           }
2409         else
2410           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2411         _smart_scrollbar_size_adjust(sd);
2412      }
2413    return scroll_h_vis_change;
2414 }
2415
2416 static void
2417 _smart_scrollbar_bar_visibility_adjust(Smart_Data *sd)
2418 {
2419    int changed = 0;
2420
2421    changed |= _smart_scrollbar_bar_h_visibility_adjust(sd);
2422    changed |= _smart_scrollbar_bar_v_visibility_adjust(sd);
2423    if (changed)
2424      {
2425         _smart_scrollbar_bar_h_visibility_adjust(sd);
2426         _smart_scrollbar_bar_v_visibility_adjust(sd);
2427      }
2428 }
2429
2430 static void
2431 _smart_scrollbar_size_adjust(Smart_Data *sd)
2432 {
2433    if ((sd->child_obj) || (sd->extern_pan))
2434      {
2435         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py, minx = 0, miny = 0;
2436         double vx, vy, size;
2437
2438         edje_object_part_geometry_get(sd->edje_obj, "elm.swallow.content",
2439                                       NULL, NULL, &vw, &vh);
2440         w = sd->child.w;
2441         if (w < 1) w = 1;
2442         size = (double)vw / (double)w;
2443         if (size > 1.0)
2444           {
2445              size = 1.0;
2446              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2447           }
2448         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", size, 1.0);
2449
2450         h = sd->child.h;
2451         if (h < 1) h = 1;
2452         size = (double)vh / (double)h;
2453         if (size > 1.0)
2454           {
2455              size = 1.0;
2456              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2457           }
2458         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, size);
2459
2460         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2461         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2462         sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2463         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2464         x = vx * mx + minx;
2465         y = vy * my + miny;
2466
2467         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->step.x / (double)w, 0.0);
2468         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->step.y / (double)h);
2469         if (sd->page.x > 0)
2470           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->page.x / (double)w, 0.0);
2471         else
2472           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", -((double)sd->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
2473         if (sd->page.y > 0)
2474           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->page.y / (double)h);
2475         else
2476           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, -((double)sd->page.y * ((double)vh / (double)h)) / 100.0);
2477
2478         sd->pan_func.get(sd->pan_obj, &px, &py);
2479         if (vx != mx) x = px;
2480         if (vy != my) y = py;
2481         sd->pan_func.set(sd->pan_obj, x, y);
2482 //      if ((px != 0) || (py != 0))
2483 //        edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2484      }
2485    else
2486      {
2487         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2488
2489         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2490         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2491         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2492         sd->pan_func.get(sd->pan_obj, &px, &py);
2493         sd->pan_func.set(sd->pan_obj, minx, miny);
2494         if ((px != minx) || (py != miny))
2495           edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2496      }
2497    _smart_scrollbar_bar_visibility_adjust(sd);
2498 }
2499
2500 static void
2501 _smart_reconfigure(Smart_Data *sd)
2502 {
2503    evas_object_move(sd->edje_obj, sd->x, sd->y);
2504    evas_object_resize(sd->edje_obj, sd->w, sd->h);
2505    evas_object_move(sd->event_obj, sd->x, sd->y);
2506    evas_object_resize(sd->event_obj, sd->w, sd->h);
2507    _smart_scrollbar_size_adjust(sd);
2508 }
2509
2510 static void
2511 _smart_add(Evas_Object *obj)
2512 {
2513    Smart_Data *sd;
2514    Evas_Object *o;
2515
2516    sd = calloc(1, sizeof(Smart_Data));
2517    if (!sd) return;
2518    evas_object_smart_data_set(obj, sd);
2519
2520    sd->smart_obj = obj;
2521    sd->x = 0;
2522    sd->y = 0;
2523    sd->w = 0;
2524    sd->h = 0;
2525    sd->step.x = 32;
2526    sd->step.y = 32;
2527    sd->page.x = -50;
2528    sd->page.y = -50;
2529    sd->hbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2530    sd->vbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2531    sd->hbar_visible = 1;
2532    sd->vbar_visible = 1;
2533
2534    sd->bounce_horiz = 1;
2535    sd->bounce_vert = 1;
2536
2537    sd->one_dir_at_a_time = 1;
2538    sd->momentum_animator_disabled = 0;
2539    sd->bounce_animator_disabled = 0;
2540    
2541    o = edje_object_add(evas_object_evas_get(obj));
2542    evas_object_propagate_events_set(o, 0);
2543    sd->edje_obj = o;
2544    // FIXME: null parent obj ... :(
2545    elm_smart_scroller_object_theme_set(NULL, obj, "scroller", "base", "default");
2546    edje_object_signal_callback_add(o, "drag", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2547    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.vbar", _smart_edje_drag_v_start, sd);
2548    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.vbar", _smart_edje_drag_v_stop, sd);
2549    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2550    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2551    edje_object_signal_callback_add(o, "drag", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2552    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.hbar", _smart_edje_drag_h_start, sd);
2553    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.hbar", _smart_edje_drag_h_stop, sd);
2554    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2555    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2556    evas_object_smart_member_add(o, obj);
2557
2558    o = evas_object_rectangle_add(evas_object_evas_get(obj));
2559    sd->event_obj = o;
2560    evas_object_color_set(o, 0, 0, 0, 0);
2561    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
2562    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _smart_event_mouse_down, sd);
2563    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _smart_event_mouse_up, sd);
2564    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _smart_event_mouse_move, sd);
2565    evas_object_smart_member_add(o, obj);
2566    evas_object_repeat_events_set(o, 1);
2567
2568    sd->pan_func.set = _elm_smart_pan_set;
2569    sd->pan_func.get = _elm_smart_pan_get;
2570    sd->pan_func.max_get = _elm_smart_pan_max_get;
2571    sd->pan_func.min_get = _elm_smart_pan_min_get;
2572    sd->pan_func.child_size_get = _elm_smart_pan_child_size_get;
2573
2574    _smart_scrollbar_reset(sd);
2575 }
2576
2577 static void
2578 _smart_del(Evas_Object *obj)
2579 {
2580    INTERNAL_ENTRY;
2581    elm_smart_scroller_child_set(obj, NULL);
2582    if (!sd->extern_pan) evas_object_del(sd->pan_obj);
2583    evas_object_del(sd->edje_obj);
2584    evas_object_del(sd->event_obj);
2585    if (sd->down.hold_animator) ecore_animator_del(sd->down.hold_animator);
2586    if (sd->down.onhold_animator) ecore_animator_del(sd->down.onhold_animator);
2587    if (sd->down.momentum_animator) ecore_animator_del(sd->down.momentum_animator);
2588    if (sd->down.bounce_x_animator) ecore_animator_del(sd->down.bounce_x_animator);
2589    if (sd->down.bounce_y_animator) ecore_animator_del(sd->down.bounce_y_animator);
2590    if (sd->scrollto.x.animator) ecore_animator_del(sd->scrollto.x.animator);
2591    if (sd->scrollto.y.animator) ecore_animator_del(sd->scrollto.y.animator);
2592    free(sd);
2593    evas_object_smart_data_set(obj, NULL);
2594 }
2595
2596 static void
2597 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2598 {
2599    INTERNAL_ENTRY;
2600    sd->x = x;
2601    sd->y = y;
2602    _smart_reconfigure(sd);
2603 }
2604
2605 static void
2606 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2607 {
2608    INTERNAL_ENTRY;
2609    sd->w = w;
2610    sd->h = h;
2611    _smart_reconfigure(sd);
2612    _elm_smart_scroller_wanted_region_set(obj);
2613 }
2614
2615 static void
2616 _smart_show(Evas_Object *obj)
2617 {
2618    INTERNAL_ENTRY;
2619    evas_object_show(sd->edje_obj);
2620    evas_object_show(sd->event_obj);
2621 }
2622
2623 static void
2624 _smart_hide(Evas_Object *obj)
2625 {
2626    INTERNAL_ENTRY;
2627    evas_object_hide(sd->edje_obj);
2628    evas_object_hide(sd->event_obj);
2629 }
2630
2631 static void
2632 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
2633 {
2634    INTERNAL_ENTRY;
2635    evas_object_color_set(sd->edje_obj, r, g, b, a);
2636 }
2637
2638 static void
2639 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
2640 {
2641    INTERNAL_ENTRY;
2642    evas_object_clip_set(sd->edje_obj, clip);
2643    evas_object_clip_set(sd->event_obj, clip);
2644 }
2645
2646 static void
2647 _smart_clip_unset(Evas_Object *obj)
2648 {
2649    INTERNAL_ENTRY;
2650    evas_object_clip_unset(sd->edje_obj);
2651    evas_object_clip_unset(sd->event_obj);
2652 }
2653
2654 /* never need to touch this */
2655
2656 static void
2657 _smart_init(void)
2658 {
2659    if (_smart) return;
2660      {
2661         static const Evas_Smart_Class sc =
2662           {
2663              SMART_NAME,
2664                EVAS_SMART_CLASS_VERSION,
2665                _smart_add,
2666                _smart_del,
2667                _smart_move,
2668                _smart_resize,
2669                _smart_show,
2670                _smart_hide,
2671                _smart_color_set,
2672                _smart_clip_set,
2673                _smart_clip_unset,
2674                NULL,
2675                NULL,
2676                NULL,
2677                NULL,
2678                NULL,
2679                NULL,
2680                NULL
2681           };
2682         _smart = evas_smart_class_new(&sc);
2683      }
2684 }
2685