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