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