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