[*][Scroller] merge from upstream revision 64051, but didn't accept data/theme/widget...
[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    sd->down.dx = 0;
1851    sd->down.dy = 0;
1852    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1853    evas_post_event_callback_push(e, _smart_event_post_up, sd);
1854    // FIXME: respect elm_widget_scroll_hold_get of parent container
1855    if (_elm_config->thumbscroll_enable)
1856      {
1857         if (ev->button == 1)
1858           {
1859              if (sd->down.onhold_animator)
1860                {
1861                   ecore_animator_del(sd->down.onhold_animator);
1862                   sd->down.onhold_animator = NULL;
1863                }
1864              x = ev->canvas.x - sd->down.x;
1865              y = ev->canvas.y - sd->down.y;
1866              if (sd->down.dragged)
1867                {
1868                   _smart_drag_stop(sd->smart_obj);
1869                   if ((!sd->hold) && (!sd->freeze))
1870                     {
1871                        double t, at, dt;
1872                        int i;
1873                        Evas_Coord ax, ay, dx, dy, vel;
1874
1875 #ifdef EVTIME
1876                        t = ev->timestamp / 1000.0;
1877 #else
1878                        t = ecore_loop_time_get();
1879 #endif
1880                        ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1881                        ax = ev->canvas.x;
1882                        ay = ev->canvas.y;
1883                        at = 0.0;
1884 #ifdef SCROLLDBG
1885                        printf("------ %i %i\n", ev->canvas.x, ev->canvas.y);
1886 #endif
1887                        for (i = 0; i < 60; i++)
1888                          {
1889                             dt = t - sd->down.history[i].timestamp;
1890                             if (dt > 0.2) break;
1891 #ifdef SCROLLDBG
1892                             printf("H: %i %i @ %1.3f\n",
1893                                    sd->down.history[i].x,
1894                                    sd->down.history[i].y, dt);
1895 #endif
1896                             at += dt;
1897                             ax += sd->down.history[i].x;
1898                             ay += sd->down.history[i].y;
1899                          }
1900                        ax /= (i + 1);
1901                        ay /= (i + 1);
1902                        at /= (i + 1);
1903                        at /= _elm_config->thumbscroll_sensitivity_friction;
1904                        dx = ev->canvas.x - ax;
1905                        dy = ev->canvas.y - ay;
1906                        if (at > 0)
1907                          {
1908                             vel = sqrt((dx * dx) + (dy * dy)) / at;
1909                             if ((_elm_config->thumbscroll_friction > 0.0) &&
1910                                 (vel > _elm_config->thumbscroll_momentum_threshold))
1911                               {
1912                                  int minx, miny, mx, my, px, py;
1913                                  sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
1914                                  sd->pan_func.max_get(sd->pan_obj, &mx, &my);
1915                                  sd->pan_func.get(sd->pan_obj, &px, &py);
1916                                  sd->down.dx = ((double)dx / at);
1917                                  sd->down.dy = ((double)dy / at);
1918                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1919                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)))
1920                                    if (px > minx && px < mx)
1921                                      sd->down.dx += (double)sd->down.pdx * 1.5; // FIXME: * 1.5 - probably should be config
1922                                  if (((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1923                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1924                                    if (py > miny && py < my)
1925                                      sd->down.dy += (double)sd->down.pdy * 1.5; // FIXME: * 1.5 - probably should be config
1926                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1927                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)) ||
1928                                      ((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1929                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1930                                    {
1931                                       double t = ecore_loop_time_get();
1932                                       double dt = t - sd->down.anim_start;
1933
1934                                       if (dt < 0.0) dt = 0.0;
1935                                       else if (dt > _elm_config->thumbscroll_friction)
1936                                         dt = _elm_config->thumbscroll_friction;
1937                                       sd->down.extra_time = _elm_config->thumbscroll_friction - dt;
1938                                    }
1939                                  else
1940                                    sd->down.extra_time = 0.0;
1941                                  elm_smart_scroller_child_viewport_size_get(sd->smart_obj, &vw, &vh);
1942                                  aw = abs(sd->down.dx);
1943                                  if (aw  > vw*3)
1944                                    {
1945                                       if (sd->down.dx > 0) sd->down.dx = vw*3;
1946                                       else sd->down.dx = -(vw*3);
1947                                    }
1948                                  ah = abs(sd->down.dy);
1949                                  if (ah  > vh*3)
1950                                    {
1951                                       if (sd->down.dy > 0) sd->down.dy = vh*3;
1952                                       else sd->down.dy = -(vh*3);
1953                                    }
1954                                  sd->down.pdx = sd->down.dx;
1955                                  sd->down.pdy = sd->down.dy;
1956                                  ox = -sd->down.dx;
1957                                  oy = -sd->down.dy;
1958                                  if (!_smart_do_page(sd))
1959                                    {
1960                                       if ((!sd->down.momentum_animator) && (!sd->momentum_animator_disabled))
1961                                         {
1962                                            sd->down.momentum_animator = ecore_animator_add(_smart_momentum_animator, sd);
1963                                            ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1964                                            _smart_anim_start(sd->smart_obj);
1965                                         }
1966                                       sd->down.anim_start = ecore_loop_time_get();
1967                                       elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1968                                       sd->down.sx = x;
1969                                       sd->down.sy = y;
1970                                       sd->down.b0x = 0;
1971                                       sd->down.b0y = 0;
1972                                    }
1973                               }
1974                          }
1975                     }
1976                   else
1977                     {
1978                        sd->down.pdx = 0;
1979                        sd->down.pdy = 0;
1980                     }
1981                   evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
1982                   if (_smart_do_page(sd))
1983                     {
1984                        Evas_Coord pgx, pgy;
1985
1986                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1987                        if ((!sd->widget) ||
1988                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1989                          {
1990                             pgx = _smart_page_x_get(sd, ox);
1991                             if (pgx != x)
1992                               {
1993                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1994                                  _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1995                               }
1996                          }
1997                        if ((!sd->widget) ||
1998                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1999                          {
2000                             pgy = _smart_page_y_get(sd, oy);
2001                             if (pgy != y)
2002                               {
2003                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2004                                  _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
2005                               }
2006                          }
2007                     }
2008                }
2009              else
2010                {
2011                   sd->down.pdx = 0;
2012                   sd->down.pdy = 0;
2013                   if (_smart_do_page(sd))
2014                     {
2015                        Evas_Coord pgx, pgy;
2016
2017                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
2018                        if ((!sd->widget) ||
2019                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
2020                          {
2021                             pgx = _smart_page_x_get(sd, ox);
2022                             if (pgx != x) _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
2023                          }
2024                        if ((!sd->widget) ||
2025                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
2026                          {
2027                             pgy = _smart_page_y_get(sd, oy);
2028                             if (pgy != y) _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
2029                          }
2030                     }
2031                }
2032              if (sd->down.hold_animator)
2033                {
2034                   ecore_animator_del(sd->down.hold_animator);
2035                   sd->down.hold_animator = NULL;
2036                }
2037              if (sd->down.scroll)
2038                {
2039                   ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
2040                   sd->down.scroll = 0;
2041                }
2042              if (sd->down.hold)
2043                {
2044                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2045                   sd->down.hold = 0;
2046                }
2047              sd->down.dragged_began = 0;
2048              sd->down.dir_x = 0;
2049              sd->down.dir_y = 0;
2050              sd->down.want_dragged = 0;
2051              sd->down.dragged = 0;
2052              sd->down.now = 0;
2053              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
2054              elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2055              _update_wanted_coordinates(sd, x, y);
2056
2057              if (!_smart_do_page(sd))
2058                bounce_eval(sd);
2059           }
2060      }
2061 }
2062
2063 static Eina_Bool
2064 _smart_onhold_animator(void *data)
2065 {
2066    Smart_Data *sd;
2067    double t, td;
2068    double vx, vy;
2069    Evas_Coord x, y, ox, oy;
2070
2071    sd = data;
2072    t = ecore_loop_time_get();
2073    if (sd->down.onhold_tlast > 0.0)
2074      {
2075         td = t - sd->down.onhold_tlast;
2076         vx = sd->down.onhold_vx * td * (double)_elm_config->thumbscroll_threshold * 2.0;
2077         vy = sd->down.onhold_vy * td * (double)_elm_config->thumbscroll_threshold * 2.0;
2078         elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
2079         x = ox;
2080         y = oy;
2081
2082         if (sd->down.dir_x)
2083           {
2084              if ((!sd->widget) ||
2085                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
2086                {
2087                   sd->down.onhold_vxe += vx;
2088                   x = ox + (int)sd->down.onhold_vxe;
2089                   sd->down.onhold_vxe -= (int)sd->down.onhold_vxe;
2090                }
2091           }
2092
2093         if (sd->down.dir_y)
2094           {
2095              if ((!sd->widget) ||
2096                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2097                {
2098                   sd->down.onhold_vye += vy;
2099                   y = oy + (int)sd->down.onhold_vye;
2100                   sd->down.onhold_vye -= (int)sd->down.onhold_vye;
2101                }
2102           }
2103
2104         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2105      }
2106    sd->down.onhold_tlast = t;
2107    return ECORE_CALLBACK_RENEW;
2108 }
2109
2110 static Eina_Bool
2111 _smart_event_post_move(void *data, Evas *e __UNUSED__)
2112 {
2113    Smart_Data *sd = data;
2114
2115    if (sd->down.want_dragged)
2116      {
2117         int start = 0;
2118
2119         if (sd->down.hold_parent)
2120           {
2121              if ((sd->down.dir_x) && !can_scroll(sd, sd->down.hdir))
2122                {
2123                   sd->down.dir_x = 0;
2124                }
2125              if ((sd->down.dir_y) && !can_scroll(sd, sd->down.vdir))
2126                {
2127                   sd->down.dir_y = 0;
2128                }
2129           }
2130         if (sd->down.dir_x)
2131           {
2132              if ((!sd->widget) ||
2133                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
2134                {
2135                   sd->down.want_dragged = 0;
2136                   sd->down.dragged = 1;
2137                   if (sd->widget)
2138                     {
2139                        elm_widget_drag_lock_x_set(sd->widget, 1);
2140                     }
2141                   start = 1;
2142                }
2143              else
2144                sd->down.dir_x = 0;
2145           }
2146         if (sd->down.dir_y)
2147           {
2148              if ((!sd->widget) ||
2149                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2150                {
2151                   sd->down.want_dragged = 0;
2152                   sd->down.dragged = 1;
2153                   if (sd->widget)
2154                     {
2155                        elm_widget_drag_lock_y_set(sd->widget, 1);
2156                     }
2157                   start = 1;
2158                }
2159              else
2160                sd->down.dir_y = 0;
2161           }
2162         if ((!sd->down.dir_x) && (!sd->down.dir_y))
2163           {
2164              sd->down.cancelled = 1;
2165           }
2166         if (start) _smart_drag_start(sd->smart_obj);
2167      }
2168    return EINA_TRUE;
2169 }
2170
2171 static void
2172 _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
2173 {
2174    Evas_Event_Mouse_Move *ev;
2175    Smart_Data *sd;
2176    Evas_Coord x = 0, y = 0;
2177
2178    sd = data;
2179    ev = event_info;
2180    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
2181    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->down.hold_parent = 1;
2182    evas_post_event_callback_push(e, _smart_event_post_move, sd);
2183    // FIXME: respect elm_widget_scroll_hold_get of parent container
2184    if (_elm_config->thumbscroll_enable)
2185      {
2186         if (sd->down.now)
2187           {
2188              int dodir = 0;
2189
2190 #ifdef SCROLLDBG
2191              printf("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2192 #endif
2193              memmove(&(sd->down.history[1]), &(sd->down.history[0]),
2194                      sizeof(sd->down.history[0]) * (60 - 1));
2195 #ifdef EVTIME
2196              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
2197              sd->down.history[0].localtimestamp = ecore_loop_time_get();
2198 #else
2199              sd->down.history[0].timestamp = ecore_loop_time_get();
2200 #endif
2201              sd->down.history[0].x = ev->cur.canvas.x;
2202              sd->down.history[0].y = ev->cur.canvas.y;
2203
2204              if (!sd->down.dragged_began)
2205                {
2206                   x = ev->cur.canvas.x - sd->down.x;
2207                   y = ev->cur.canvas.y - sd->down.y;
2208
2209                   sd->down.hdir = -1;
2210                   sd->down.vdir = -1;
2211
2212                   if      (x > 0) sd->down.hdir = LEFT;
2213                   else if (x < 0) sd->down.hdir = RIGHT;
2214                   if      (y > 0) sd->down.vdir = UP;
2215                   else if (y < 0) sd->down.vdir = DOWN;
2216
2217                   if (x < 0) x = -x;
2218                   if (y < 0) y = -y;
2219
2220                   if ((sd->one_dir_at_a_time) &&
2221                       (!((sd->down.dir_x) || (sd->down.dir_y))))
2222                     {
2223                        if (x > _elm_config->thumbscroll_threshold)
2224                          {
2225                             if (x > (y * 2))
2226                               {
2227                                  sd->down.dir_x = 1;
2228                                  sd->down.dir_y = 0;
2229                                  dodir++;
2230                               }
2231                          }
2232                        if (y > _elm_config->thumbscroll_threshold)
2233                          {
2234                             if (y > (x * 2))
2235                               {
2236                                  sd->down.dir_x = 0;
2237                                  sd->down.dir_y = 1;
2238                                  dodir++;
2239                               }
2240                          }
2241                        if (!dodir)
2242                          {
2243                             sd->down.dir_x = 1;
2244                             sd->down.dir_y = 1;
2245                          }
2246                     }
2247                   else
2248                     {
2249                        //                       can_scroll(sd, LEFT);
2250                        //                       can_scroll(sd, RIGHT);
2251                        //                       can_scroll(sd, UP);
2252                        //                       can_scroll(sd, DOWN);
2253                        sd->down.dir_x = 1;
2254                        sd->down.dir_y = 1;
2255                     }
2256                }
2257              if ((!sd->hold) && (!sd->freeze))
2258                {
2259                   if ((sd->down.dragged) ||
2260                       (((x * x) + (y * y)) >
2261                        (_elm_config->thumbscroll_threshold *
2262                         _elm_config->thumbscroll_threshold)))
2263                     {
2264                        sd->down.dragged_began = 1;
2265                        if (!sd->down.dragged)
2266                          {
2267                             sd->down.want_dragged = 1;
2268                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2269                             //                            evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2270                             //                            _smart_drag_start(sd->smart_obj);
2271                          }
2272                        if (sd->down.dragged)
2273                          {
2274                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2275                          }
2276                        //                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2277                        //                       sd->down.dragged = 1;
2278                        if (sd->down.dir_x)
2279                          x = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
2280                        else
2281                          x = sd->down.sx;
2282                        if (sd->down.dir_y)
2283                          y = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
2284                        else
2285                          y = sd->down.sy;
2286                        if(sd->down.want_reset)
2287                          {
2288                             sd->down.x = ev->cur.canvas.x;
2289                             sd->down.y = ev->cur.canvas.y;
2290                             sd->down.want_reset = 0;
2291                          }
2292                        if ((sd->down.dir_x) || (sd->down.dir_y))
2293                          {
2294                             if (!sd->down.locked)
2295                               {
2296                                  sd->down.locked_x = x;
2297                                  sd->down.locked_y = y;
2298                                  sd->down.locked = 1;
2299                               }
2300                             if (!((sd->down.dir_x) && (sd->down.dir_y)))
2301                               {
2302                                  if (sd->down.dir_x) y = sd->down.locked_y;
2303                                  else x = sd->down.locked_x;
2304                               }
2305                          }
2306                          {
2307                             Evas_Coord minx, miny;
2308                             sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2309                             if (y < miny)
2310                               y += (miny - y) *
2311                                  _elm_config->thumbscroll_border_friction;
2312                             else if (sd->child.h <= sd->h)
2313                               y += (sd->down.sy - y) *
2314                                  _elm_config->thumbscroll_border_friction;
2315                             else if ((sd->child.h - sd->h + miny) < y)
2316                               y += (sd->child.h - sd->h + miny - y) *
2317                                  _elm_config->thumbscroll_border_friction;
2318                             if (x < minx)
2319                               x += (minx - x) *
2320                                  _elm_config->thumbscroll_border_friction;
2321                             else if (sd->child.w <= sd->w)
2322                               x += (sd->down.sx - x) *
2323                                  _elm_config->thumbscroll_border_friction;
2324                             else if ((sd->child.w - sd->w + minx) < x)
2325                               x += (sd->child.w - sd->w + minx - x) *
2326                                  _elm_config->thumbscroll_border_friction;
2327                          }
2328
2329                        sd->down.hold_x = x;
2330                        sd->down.hold_y = y;
2331                        if (!sd->down.hold_animator)
2332                          sd->down.hold_animator =
2333                             ecore_animator_add(_smart_hold_animator, sd);
2334                        //                       printf("a %i %i\n", sd->down.hold_x, sd->down.hold_y);
2335                        //                       _smart_onhold_animator(sd);
2336                        //                       elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2337                     }
2338                   else
2339                     {
2340                        if (sd->down.dragged_began)
2341                          {
2342                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2343                             if (!sd->down.hold)
2344                               {
2345                                  sd->down.hold = 1;
2346                                  evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2347                               }
2348                          }
2349                     }
2350                }
2351              else if (!sd->freeze)
2352                {
2353                   Evas_Coord ex, ey, ew, eh;
2354                   double vx = 0.0, vy = 0.0;
2355
2356                   evas_object_geometry_get(sd->event_obj, &ex, &ey, &ew, &eh);
2357                   x = ev->cur.canvas.x - ex;
2358                   y = ev->cur.canvas.y - ey;
2359                   if (x < _elm_config->thumbscroll_threshold)
2360                     {
2361                        if (_elm_config->thumbscroll_threshold > 0.0)
2362                          vx = -(double)(_elm_config->thumbscroll_threshold - x) /
2363                             _elm_config->thumbscroll_threshold;
2364                        else
2365                          vx = -1.0;
2366                     }
2367                   else if (x > (ew - _elm_config->thumbscroll_threshold))
2368                     {
2369                        if (_elm_config->thumbscroll_threshold > 0.0)
2370                          vx = (double)(_elm_config->thumbscroll_threshold - (ew - x)) /
2371                             _elm_config->thumbscroll_threshold;
2372                        else
2373                          vx = 1.0;
2374                     }
2375                   if (y < _elm_config->thumbscroll_threshold)
2376                     {
2377                        if (_elm_config->thumbscroll_threshold > 0.0)
2378                          vy = -(double)(_elm_config->thumbscroll_threshold - y) /
2379                             _elm_config->thumbscroll_threshold;
2380                        else
2381                          vy = -1.0;
2382                     }
2383                   else if (y > (eh - _elm_config->thumbscroll_threshold))
2384                     {
2385                        if (_elm_config->thumbscroll_threshold > 0.0)
2386                          vy = (double)(_elm_config->thumbscroll_threshold - (eh - y)) /
2387                             _elm_config->thumbscroll_threshold;
2388                        else
2389                          vy = 1.0;
2390                     }
2391                   if ((vx != 0.0) || (vy != 0.0))
2392                     {
2393                        sd->down.onhold_vx = vx;
2394                        sd->down.onhold_vy = vy;
2395                        if (!sd->down.onhold_animator)
2396                          {
2397                             sd->down.onhold_vxe = 0.0;
2398                             sd->down.onhold_vye = 0.0;
2399                             sd->down.onhold_tlast = 0.0;
2400                             sd->down.onhold_animator = ecore_animator_add(_smart_onhold_animator, sd);
2401                          }
2402                        //                       printf("b %i %i\n", sd->down.hold_x, sd->down.hold_y);
2403                     }
2404                   else
2405                     {
2406                        if (sd->down.onhold_animator)
2407                          {
2408                             ecore_animator_del(sd->down.onhold_animator);
2409                             sd->down.onhold_animator = NULL;
2410                          }
2411                     }
2412                }
2413           }
2414      }
2415 }
2416
2417 static void
2418 _smart_scrollbar_read(Smart_Data *sd)
2419 {
2420    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
2421    double vx, vy;
2422
2423    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2424    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2425    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2426    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2427    x = vx * (double)mx + minx;
2428    y = vy * (double)my + miny;
2429    sd->pan_func.get(sd->pan_obj, &px, &py);
2430    sd->pan_func.set(sd->pan_obj, x, y);
2431    if ((px != x) || (py != y))
2432      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2433 }
2434
2435 static void
2436 _smart_scrollbar_reset(Smart_Data *sd)
2437 {
2438    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2439
2440    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2441    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2442    if ((!sd->child_obj) && (!sd->extern_pan))
2443      {
2444         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2445         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2446      }
2447    if (sd->pan_obj)
2448      {
2449         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2450         sd->pan_func.get(sd->pan_obj, &px, &py);
2451         sd->pan_func.set(sd->pan_obj, minx, miny);
2452      }
2453    if ((px != minx) || (py != miny))
2454      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2455 }
2456
2457 static int
2458 _smart_scrollbar_bar_v_visibility_adjust(Smart_Data *sd)
2459 {
2460    int scroll_v_vis_change = 0;
2461    Evas_Coord h, vw = 0, vh = 0;
2462
2463    h = sd->child.h;
2464    if (sd->pan_obj)
2465      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2466    if (sd->vbar_visible)
2467      {
2468         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2469           {
2470              if ((sd->child_obj) || (sd->extern_pan))
2471                {
2472                   if (h <= vh)
2473                     {
2474                        scroll_v_vis_change = 1;
2475                        sd->vbar_visible = 0;
2476                     }
2477                }
2478              else
2479                {
2480                   scroll_v_vis_change = 1;
2481                   sd->vbar_visible = 0;
2482                }
2483           }
2484         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2485           {
2486              scroll_v_vis_change = 1;
2487              sd->vbar_visible = 0;
2488           }
2489      }
2490    else
2491      {
2492         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2493           {
2494              if ((sd->child_obj) || (sd->extern_pan))
2495                {
2496                   if (h > vh)
2497                     {
2498                        scroll_v_vis_change = 1;
2499                        sd->vbar_visible = 1;
2500                     }
2501                }
2502           }
2503         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2504           {
2505              scroll_v_vis_change = 1;
2506              sd->vbar_visible = 1;
2507           }
2508      }
2509    if (scroll_v_vis_change)
2510      {
2511         if (sd->vbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2512           {
2513              if (sd->vbar_visible)
2514                edje_object_signal_emit(sd->edje_obj, "elm,action,show,vbar", "elm");
2515              else
2516                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2517              edje_object_message_signal_process(sd->edje_obj);
2518              _smart_scrollbar_size_adjust(sd);
2519           }
2520         else
2521           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2522      }
2523    return scroll_v_vis_change;
2524 }
2525
2526 static int
2527 _smart_scrollbar_bar_h_visibility_adjust(Smart_Data *sd)
2528 {
2529    int scroll_h_vis_change = 0;
2530    Evas_Coord w, vw = 0, vh = 0;
2531
2532    w = sd->child.w;
2533    if (sd->pan_obj)
2534      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2535    if (sd->hbar_visible)
2536      {
2537         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2538           {
2539              if ((sd->child_obj) || (sd->extern_pan))
2540                {
2541                   if (w <= vw)
2542                     {
2543                        scroll_h_vis_change = 1;
2544                        sd->hbar_visible = 0;
2545                     }
2546                }
2547              else
2548                {
2549                   scroll_h_vis_change = 1;
2550                   sd->hbar_visible = 0;
2551                }
2552           }
2553         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2554           {
2555              scroll_h_vis_change = 1;
2556              sd->hbar_visible = 0;
2557           }
2558      }
2559    else
2560      {
2561         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2562           {
2563              if ((sd->child_obj) || (sd->extern_pan))
2564                {
2565                   if (w > vw)
2566                     {
2567                        scroll_h_vis_change = 1;
2568                        sd->hbar_visible = 1;
2569                     }
2570                }
2571           }
2572         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2573           {
2574              scroll_h_vis_change = 1;
2575              sd->hbar_visible = 1;
2576           }
2577      }
2578    if (scroll_h_vis_change)
2579      {
2580         if (sd->hbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2581           {
2582              if (sd->hbar_visible)
2583                edje_object_signal_emit(sd->edje_obj, "elm,action,show,hbar", "elm");
2584              else
2585                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2586              edje_object_message_signal_process(sd->edje_obj);
2587              _smart_scrollbar_size_adjust(sd);
2588           }
2589         else
2590           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2591         _smart_scrollbar_size_adjust(sd);
2592      }
2593    return scroll_h_vis_change;
2594 }
2595
2596 static void
2597 _smart_scrollbar_bar_visibility_adjust(Smart_Data *sd)
2598 {
2599    int changed = 0;
2600
2601    changed |= _smart_scrollbar_bar_h_visibility_adjust(sd);
2602    changed |= _smart_scrollbar_bar_v_visibility_adjust(sd);
2603    if (changed)
2604      {
2605         _smart_scrollbar_bar_h_visibility_adjust(sd);
2606         _smart_scrollbar_bar_v_visibility_adjust(sd);
2607      }
2608 }
2609
2610 static void
2611 _smart_scrollbar_size_adjust(Smart_Data *sd)
2612 {
2613    if ((sd->child_obj) || (sd->extern_pan))
2614      {
2615         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py, minx = 0, miny = 0;
2616         double vx, vy, size;
2617
2618         edje_object_part_geometry_get(sd->edje_obj, "elm.swallow.content",
2619                                       NULL, NULL, &vw, &vh);
2620         w = sd->child.w;
2621         if (w < 1) w = 1;
2622         size = (double)vw / (double)w;
2623         if (size > 1.0)
2624           {
2625              size = 1.0;
2626              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2627           }
2628         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", size, 1.0);
2629
2630         h = sd->child.h;
2631         if (h < 1) h = 1;
2632         size = (double)vh / (double)h;
2633         if (size > 1.0)
2634           {
2635              size = 1.0;
2636              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2637           }
2638         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, size);
2639
2640         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2641         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2642         sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2643         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2644         x = vx * mx + minx;
2645         y = vy * my + miny;
2646
2647         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->step.x / (double)w, 0.0);
2648         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->step.y / (double)h);
2649         if (sd->page.x > 0)
2650           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->page.x / (double)w, 0.0);
2651         else
2652           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", -((double)sd->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
2653         if (sd->page.y > 0)
2654           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->page.y / (double)h);
2655         else
2656           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, -((double)sd->page.y * ((double)vh / (double)h)) / 100.0);
2657
2658         sd->pan_func.get(sd->pan_obj, &px, &py);
2659         if (vx != mx) x = px;
2660         if (vy != my) y = py;
2661         sd->pan_func.set(sd->pan_obj, x, y);
2662         //      if ((px != 0) || (py != 0))
2663         //        edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2664      }
2665    else
2666      {
2667         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2668
2669         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2670         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2671         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2672         sd->pan_func.get(sd->pan_obj, &px, &py);
2673         sd->pan_func.set(sd->pan_obj, minx, miny);
2674         if ((px != minx) || (py != miny))
2675           edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2676      }
2677    _smart_scrollbar_bar_visibility_adjust(sd);
2678 }
2679
2680 static void
2681 _smart_reconfigure(Smart_Data *sd)
2682 {
2683    evas_object_move(sd->edje_obj, sd->x, sd->y);
2684    evas_object_resize(sd->edje_obj, sd->w, sd->h);
2685    evas_object_move(sd->event_obj, sd->x, sd->y);
2686    evas_object_resize(sd->event_obj, sd->w, sd->h);
2687    _smart_scrollbar_size_adjust(sd);
2688 }
2689
2690 static void
2691 _smart_add(Evas_Object *obj)
2692 {
2693    Smart_Data *sd;
2694    Evas_Object *o;
2695
2696    sd = calloc(1, sizeof(Smart_Data));
2697    if (!sd) return;
2698    evas_object_smart_data_set(obj, sd);
2699
2700    sd->smart_obj = obj;
2701    sd->x = 0;
2702    sd->y = 0;
2703    sd->w = 0;
2704    sd->h = 0;
2705    sd->step.x = 32;
2706    sd->step.y = 32;
2707    sd->page.x = -50;
2708    sd->page.y = -50;
2709    sd->hbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2710    sd->vbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2711    sd->hbar_visible = 1;
2712    sd->vbar_visible = 1;
2713
2714    sd->bounce_horiz = 1;
2715    sd->bounce_vert = 1;
2716
2717    sd->one_dir_at_a_time = 1;
2718    sd->momentum_animator_disabled = EINA_FALSE;
2719    sd->bounce_animator_disabled = EINA_FALSE;
2720
2721    o = edje_object_add(evas_object_evas_get(obj));
2722    evas_object_propagate_events_set(o, 0);
2723    sd->edje_obj = o;
2724    elm_smart_scroller_object_theme_set(NULL, obj, "scroller", "base", "default");
2725    edje_object_signal_callback_add(o, "drag", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2726    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.vbar", _smart_edje_drag_v_start, sd);
2727    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.vbar", _smart_edje_drag_v_stop, sd);
2728    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2729    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2730    edje_object_signal_callback_add(o, "drag", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2731    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.hbar", _smart_edje_drag_h_start, sd);
2732    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.hbar", _smart_edje_drag_h_stop, sd);
2733    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2734    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2735    evas_object_smart_member_add(o, obj);
2736
2737    o = evas_object_rectangle_add(evas_object_evas_get(obj));
2738    sd->event_obj = o;
2739    evas_object_color_set(o, 0, 0, 0, 0);
2740    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
2741    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _smart_event_mouse_down, sd);
2742    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _smart_event_mouse_up, sd);
2743    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _smart_event_mouse_move, sd);
2744    evas_object_smart_member_add(o, obj);
2745    evas_object_repeat_events_set(o, 1);
2746
2747    sd->pan_func.set = _elm_smart_pan_set;
2748    sd->pan_func.get = _elm_smart_pan_get;
2749    sd->pan_func.max_get = _elm_smart_pan_max_get;
2750    sd->pan_func.min_get = _elm_smart_pan_min_get;
2751    sd->pan_func.child_size_get = _elm_smart_pan_child_size_get;
2752
2753    _smart_scrollbar_reset(sd);
2754 }
2755
2756 static void
2757 _smart_del(Evas_Object *obj)
2758 {
2759    INTERNAL_ENTRY;
2760    elm_smart_scroller_child_set(obj, NULL);
2761    if (!sd->extern_pan) evas_object_del(sd->pan_obj);
2762    evas_object_del(sd->edje_obj);
2763    evas_object_del(sd->event_obj);
2764    if (sd->down.hold_animator) ecore_animator_del(sd->down.hold_animator);
2765    if (sd->down.onhold_animator) ecore_animator_del(sd->down.onhold_animator);
2766    if (sd->down.momentum_animator) ecore_animator_del(sd->down.momentum_animator);
2767    if (sd->down.bounce_x_animator) ecore_animator_del(sd->down.bounce_x_animator);
2768    if (sd->down.bounce_y_animator) ecore_animator_del(sd->down.bounce_y_animator);
2769    if (sd->scrollto.x.animator) ecore_animator_del(sd->scrollto.x.animator);
2770    if (sd->scrollto.y.animator) ecore_animator_del(sd->scrollto.y.animator);
2771    free(sd);
2772    evas_object_smart_data_set(obj, NULL);
2773 }
2774
2775 static void
2776 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2777 {
2778    INTERNAL_ENTRY;
2779    sd->x = x;
2780    sd->y = y;
2781    _smart_reconfigure(sd);
2782 }
2783
2784 static void
2785 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2786 {
2787    INTERNAL_ENTRY;
2788    sd->w = w;
2789    sd->h = h;
2790    _smart_reconfigure(sd);
2791    _elm_smart_scroller_wanted_region_set(obj);
2792 }
2793
2794 static void
2795 _smart_show(Evas_Object *obj)
2796 {
2797    INTERNAL_ENTRY;
2798    evas_object_show(sd->edje_obj);
2799    evas_object_show(sd->event_obj);
2800 }
2801
2802 static void
2803 _smart_hide(Evas_Object *obj)
2804 {
2805    INTERNAL_ENTRY;
2806    evas_object_hide(sd->edje_obj);
2807    evas_object_hide(sd->event_obj);
2808 }
2809
2810 static void
2811 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
2812 {
2813    INTERNAL_ENTRY;
2814    evas_object_color_set(sd->edje_obj, r, g, b, a);
2815 }
2816
2817 static void
2818 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
2819 {
2820    INTERNAL_ENTRY;
2821    evas_object_clip_set(sd->edje_obj, clip);
2822    evas_object_clip_set(sd->event_obj, clip);
2823 }
2824
2825 static void
2826 _smart_clip_unset(Evas_Object *obj)
2827 {
2828    INTERNAL_ENTRY;
2829    evas_object_clip_unset(sd->edje_obj);
2830    evas_object_clip_unset(sd->event_obj);
2831 }
2832
2833 /* never need to touch this */
2834
2835 static void
2836 _smart_init(void)
2837 {
2838    if (_smart) return;
2839      {
2840         static const Evas_Smart_Class sc =
2841           {
2842              SMART_NAME,
2843              EVAS_SMART_CLASS_VERSION,
2844              _smart_add,
2845              _smart_del,
2846              _smart_move,
2847              _smart_resize,
2848              _smart_show,
2849              _smart_hide,
2850              _smart_color_set,
2851              _smart_clip_set,
2852              _smart_clip_unset,
2853              NULL,
2854              NULL,
2855              NULL,
2856              NULL,
2857              NULL,
2858              NULL,
2859              NULL
2860           };
2861         _smart = evas_smart_class_new(&sc);
2862      }
2863 }