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