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