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