els_scroller: add apis for enable/disable default wheel control
[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;
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
1023    nx = px;
1024    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1025    else if ((x > px) && ((x + w) > (px + (cw - mx)))) nx = x + w - (cw - mx);
1026    ny = py;
1027    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1028    else if ((y > py) && ((y + h) > (py + (ch - my)))) ny = y + h - (ch - my);
1029    if (!internal_call)
1030      {
1031         sd->wx = x;
1032         sd->wy = y;
1033         sd->ww = w;
1034         sd->wh = h;
1035         if ((nx == px) && (ny == py)) return;
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    x = nx;
1083    if ((x + w) > cw) x = cw - w;
1084    if (x < minx) x = minx;
1085    y = ny;
1086    if ((y + h) > ch) y = ch - h;
1087    if (y < miny) y = miny;
1088    elm_smart_scroller_child_pos_set(obj, x, y);
1089 }
1090
1091 /* Set should be used for calculated positions, for example, when we move
1092  * because of an animation or because this is the correct position after
1093  * constraints. */
1094 void
1095 elm_smart_scroller_child_region_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1096 {
1097    _elm_smart_scroller_child_region_show_internal(obj, x, y, w, h, EINA_TRUE);
1098 }
1099
1100 /* Set should be used for setting the wanted position, for example a user scroll
1101  * or moving the cursor in an entry. */
1102 void
1103 elm_smart_scroller_child_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1104 {
1105    _elm_smart_scroller_child_region_show_internal(obj, x, y, w, h, EINA_FALSE);
1106 }
1107
1108 void
1109 elm_smart_scroller_child_viewport_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
1110 {
1111    API_ENTRY return;
1112    if (!sd->pan_obj) return;
1113    edje_object_calc_force(sd->edje_obj);
1114    evas_object_geometry_get(sd->pan_obj, NULL, NULL, w, h);
1115 }
1116
1117 void
1118 elm_smart_scroller_step_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1119 {
1120    API_ENTRY return;
1121    if (x < 1) x = 1;
1122    if (y < 1) y = 1;
1123    sd->step.x = x;
1124    sd->step.y = y;
1125    _smart_scrollbar_size_adjust(sd);
1126 }
1127
1128 void
1129 elm_smart_scroller_step_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1130 {
1131    API_ENTRY return;
1132    if (x) *x = sd->step.x;
1133    if (y) *y = sd->step.y;
1134 }
1135
1136 void
1137 elm_smart_scroller_page_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
1138 {
1139    API_ENTRY return;
1140    sd->page.x = x;
1141    sd->page.y = y;
1142    _smart_scrollbar_size_adjust(sd);
1143 }
1144
1145 void
1146 elm_smart_scroller_page_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
1147 {
1148    API_ENTRY return;
1149    if (x) *x = sd->page.x;
1150    if (y) *y = sd->page.y;
1151 }
1152
1153 void
1154 elm_smart_scroller_policy_set(Evas_Object *obj, Elm_Smart_Scroller_Policy hbar, Elm_Smart_Scroller_Policy vbar)
1155 {
1156    API_ENTRY return;
1157    if ((sd->hbar_flags == hbar) && (sd->vbar_flags == vbar)) return;
1158    sd->hbar_flags = hbar;
1159    sd->vbar_flags = vbar;
1160    if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
1161      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,hbar", "elm");
1162    else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
1163      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
1164    else
1165      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,hbar", "elm");
1166    if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
1167      edje_object_signal_emit(sd->edje_obj, "elm,action,show_always,vbar", "elm");
1168    else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
1169      edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
1170    else
1171      edje_object_signal_emit(sd->edje_obj, "elm,action,show_notalways,vbar", "elm");
1172    _smart_scrollbar_size_adjust(sd);
1173 }
1174
1175 void
1176 elm_smart_scroller_policy_get(Evas_Object *obj, Elm_Smart_Scroller_Policy *hbar, Elm_Smart_Scroller_Policy *vbar)
1177 {
1178    API_ENTRY return;
1179    if (hbar) *hbar = sd->hbar_flags;
1180    if (vbar) *vbar = sd->vbar_flags;
1181 }
1182
1183 Evas_Object *
1184 elm_smart_scroller_edje_object_get(Evas_Object *obj)
1185 {
1186    API_ENTRY return NULL;
1187    return sd->edje_obj;
1188 }
1189
1190 void
1191 elm_smart_scroller_single_dir_set(Evas_Object *obj, Eina_Bool single_dir)
1192 {
1193    API_ENTRY return;
1194    sd->one_dir_at_a_time = single_dir;
1195 }
1196
1197 Eina_Bool
1198 elm_smart_scroller_single_dir_get(Evas_Object *obj)
1199 {
1200    API_ENTRY return EINA_FALSE;
1201    return sd->one_dir_at_a_time;
1202 }
1203
1204 void
1205 elm_smart_scroller_object_theme_set(Evas_Object *parent, Evas_Object *obj, const char *clas, const char *group, const char *style)
1206 {
1207    API_ENTRY return;
1208    Evas_Coord mw, mh;
1209    //Does this API require parent object absolutely? if then remove this exception.
1210    double parent_scale = parent ? elm_widget_scale_get(parent) : 1;
1211    _elm_theme_object_set(parent, sd->edje_obj, clas, group, style);
1212    edje_object_scale_set(sd->edje_obj, parent_scale * _elm_config->scale);
1213    if (sd->pan_obj)
1214      edje_object_part_swallow(sd->edje_obj, "elm.swallow.content", sd->pan_obj);
1215    mw = mh = -1;
1216    elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1217    if (edje_object_part_exists(sd->edje_obj, "elm.scrollbar.base"))
1218      {
1219         Evas_Object *base;
1220         base = edje_object_part_swallow_get(sd->edje_obj, "elm.scrollbar.base");
1221         if (!base)
1222           {
1223              base = evas_object_rectangle_add(evas_object_evas_get(sd->edje_obj));
1224              evas_object_color_set(base, 0, 0, 0, 0);
1225              edje_object_part_swallow(sd->edje_obj, "elm.scrollbar.base", base);
1226           }
1227         if (!_elm_config->thumbscroll_enable)
1228            evas_object_size_hint_min_set(base, mw, mh);
1229      }
1230    sd->vbar_visible = !sd->vbar_visible;
1231    sd->hbar_visible = !sd->hbar_visible;
1232    _smart_scrollbar_bar_visibility_adjust(sd);
1233 }
1234
1235 void
1236 elm_smart_scroller_hold_set(Evas_Object *obj, Eina_Bool hold)
1237 {
1238    API_ENTRY return;
1239    sd->hold = hold;
1240 }
1241
1242 void
1243 elm_smart_scroller_freeze_set(Evas_Object *obj, Eina_Bool freeze)
1244 {
1245    API_ENTRY return;
1246    sd->freeze = freeze;
1247    if (sd->freeze)
1248      {
1249         if (sd->down.onhold_animator)
1250           {
1251              ecore_animator_del(sd->down.onhold_animator);
1252              sd->down.onhold_animator = NULL;
1253           }
1254      }
1255    else
1256      bounce_eval(sd);
1257 }
1258
1259 void
1260 elm_smart_scroller_bounce_allow_set(Evas_Object *obj, Eina_Bool horiz, Eina_Bool vert)
1261 {
1262    API_ENTRY return;
1263    sd->bounce_horiz = horiz;
1264    sd->bounce_vert = vert;
1265 }
1266
1267 void
1268 elm_smart_scroller_bounce_allow_get(const Evas_Object *obj, Eina_Bool *horiz, Eina_Bool *vert)
1269 {
1270    API_ENTRY return;
1271    *horiz = sd->bounce_horiz;
1272    *vert = sd->bounce_vert;
1273 }
1274
1275 void
1276 elm_smart_scroller_paging_set(Evas_Object *obj, double pagerel_h, double pagerel_v, Evas_Coord pagesize_h, Evas_Coord pagesize_v)
1277 {
1278    API_ENTRY return;
1279    sd->pagerel_h = pagerel_h;
1280    sd->pagerel_v = pagerel_v;
1281    sd->pagesize_h = pagesize_h;
1282    sd->pagesize_v = pagesize_v;
1283    _smart_page_adjust(sd);
1284 }
1285
1286 void
1287 elm_smart_scroller_paging_get(Evas_Object *obj, double *pagerel_h, double *pagerel_v, Evas_Coord *pagesize_h, Evas_Coord *pagesize_v)
1288 {
1289    API_ENTRY return;
1290    if(pagerel_h) *pagerel_h = sd->pagerel_h;
1291    if(pagerel_v) *pagerel_v = sd->pagerel_v;
1292    if(pagesize_h) *pagesize_h = sd->pagesize_h;
1293    if(pagesize_v) *pagesize_v = sd->pagesize_v;
1294 }
1295
1296 void
1297 elm_smart_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
1298 {
1299    Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny, minx = 0, miny = 0;
1300
1301    API_ENTRY return;
1302    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
1303    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
1304    sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
1305    sd->pan_func.get(sd->pan_obj, &px, &py);
1306
1307    nx = px;
1308    if ((x < px) && ((x + w) < (px + (cw - mx)))) nx = x;
1309    else if ((x > px) && ((x + w) > (px + (cw - mx)))) nx = x + w - (cw - mx);
1310    ny = py;
1311    if ((y < py) && ((y + h) < (py + (ch - my)))) ny = y;
1312    else if ((y > py) && ((y + h) > (py + (ch - my)))) ny = y + h - (ch - my);
1313    sd->wx = x;
1314    sd->wy = y;
1315    sd->ww = w;
1316    sd->wh = h;
1317    if ((nx == px) && (ny == py)) return;
1318    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1319        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1320      {
1321         _smart_anim_stop(sd->smart_obj);
1322      }
1323    if (sd->scrollto.x.animator)
1324      {
1325         ecore_animator_del(sd->scrollto.x.animator);
1326         sd->scrollto.x.animator = NULL;
1327      }
1328    if (sd->scrollto.y.animator)
1329      {
1330         ecore_animator_del(sd->scrollto.y.animator);
1331         sd->scrollto.y.animator = NULL;
1332      }
1333    if (sd->down.bounce_x_animator)
1334      {
1335         ecore_animator_del(sd->down.bounce_x_animator);
1336         sd->down.bounce_x_animator = NULL;
1337         sd->bouncemex = 0;
1338      }
1339    if (sd->down.bounce_y_animator)
1340      {
1341         ecore_animator_del(sd->down.bounce_y_animator);
1342         sd->down.bounce_y_animator = NULL;
1343         sd->bouncemey = 0;
1344      }
1345    if (sd->down.hold_animator)
1346      {
1347         ecore_animator_del(sd->down.hold_animator);
1348         sd->down.hold_animator = NULL;
1349         _smart_drag_stop(sd->smart_obj);
1350      }
1351    if (sd->down.momentum_animator)
1352      {
1353         ecore_animator_del(sd->down.momentum_animator);
1354         sd->down.momentum_animator = NULL;
1355         sd->down.bounce_x_hold = 0;
1356         sd->down.bounce_y_hold = 0;
1357         sd->down.ax = 0;
1358         sd->down.ay = 0;
1359         sd->down.pdx = 0;
1360         sd->down.pdy = 0;
1361      }
1362    x = nx;
1363    if ((x + w) > cw) x = cw - w;
1364    if (x < minx) x = minx;
1365    _smart_scrollto_x(sd, _elm_config->bring_in_scroll_friction, x);
1366    y = ny;
1367    if ((y + h) > ch) y = ch - h;
1368    if (y < miny) y = miny;
1369    _smart_scrollto_y(sd, _elm_config->bring_in_scroll_friction, y);
1370 }
1371
1372 void
1373 elm_smart_scroller_widget_set(Evas_Object *obj, Evas_Object *wid)
1374 {
1375    API_ENTRY return;
1376    sd->widget = wid;
1377 }
1378
1379 static void
1380 _elm_smart_scroller_wanted_region_set(Evas_Object *obj)
1381 {
1382    INTERNAL_ENTRY;
1383    Evas_Coord ww, wh, wx = sd->wx;
1384
1385    /* Flip to RTL cords only if init in RTL mode */
1386    if(sd->is_mirrored)
1387      wx = _elm_smart_scroller_x_mirrored_get(obj, sd->wx);
1388
1389    if (sd->ww == -1)
1390      {
1391         elm_smart_scroller_child_viewport_size_get(obj, &ww, &wh);
1392      }
1393    else
1394      {
1395         ww = sd->ww;
1396         wh = sd->wh;
1397      }
1398
1399    elm_smart_scroller_child_region_set(obj, wx, sd->wy, ww, wh);
1400 }
1401
1402 /* local subsystem functions */
1403 static void
1404 _smart_edje_drag_v_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1405 {
1406    Smart_Data *sd;
1407
1408    sd = data;
1409    _smart_scrollbar_read(sd);
1410    _smart_drag_start(sd->smart_obj);
1411    sd->freeze = EINA_TRUE;
1412 }
1413
1414 static void
1415 _smart_edje_drag_v_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1416 {
1417    Smart_Data *sd;
1418
1419    sd = data;
1420    _smart_scrollbar_read(sd);
1421    _smart_drag_stop(sd->smart_obj);
1422    sd->freeze = EINA_FALSE;
1423 }
1424
1425 static void
1426 _smart_edje_drag_v(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1427 {
1428    Smart_Data *sd;
1429
1430    sd = data;
1431    _smart_scrollbar_read(sd);
1432 }
1433
1434 static void
1435 _smart_edje_drag_h_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1436 {
1437    Smart_Data *sd;
1438
1439    sd = data;
1440    _smart_scrollbar_read(sd);
1441    _smart_drag_start(sd->smart_obj);
1442    sd->freeze = EINA_TRUE;
1443 }
1444
1445 static void
1446 _smart_edje_drag_h_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1447 {
1448    Smart_Data *sd;
1449
1450    sd = data;
1451    _smart_scrollbar_read(sd);
1452    _smart_drag_stop(sd->smart_obj);
1453    sd->freeze = EINA_FALSE;
1454 }
1455
1456 static void
1457 _smart_edje_drag_h(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1458 {
1459    Smart_Data *sd;
1460
1461    sd = data;
1462    _smart_scrollbar_read(sd);
1463 }
1464
1465 static void
1466 _smart_child_del_hook(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1467 {
1468    Smart_Data *sd;
1469
1470    sd = data;
1471    sd->child_obj = NULL;
1472    _smart_scrollbar_size_adjust(sd);
1473    _smart_scrollbar_reset(sd);
1474 }
1475
1476 static void
1477 _smart_pan_changed_hook(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1478 {
1479    Evas_Coord w, h;
1480    Smart_Data *sd;
1481
1482    sd = data;
1483    sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
1484    if ((w != sd->child.w) || (h != sd->child.h))
1485      {
1486         sd->child.w = w;
1487         sd->child.h = h;
1488         _smart_scrollbar_size_adjust(sd);
1489         evas_object_size_hint_min_set(sd->smart_obj, sd->child.w, sd->child.h);
1490         _elm_smart_scroller_wanted_region_set(sd->smart_obj);
1491      }
1492 }
1493
1494 static void
1495 _smart_pan_pan_changed_hook(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1496 {
1497    Smart_Data *sd;
1498
1499    sd = data;
1500    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1501        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1502      {
1503         _smart_anim_stop(sd->smart_obj);
1504      }
1505    if (sd->scrollto.x.animator)
1506      {
1507         ecore_animator_del(sd->scrollto.x.animator);
1508         sd->scrollto.x.animator = NULL;
1509      }
1510    if (sd->scrollto.y.animator)
1511      {
1512         ecore_animator_del(sd->scrollto.y.animator);
1513         sd->scrollto.y.animator = NULL;
1514      }
1515    if (sd->down.bounce_x_animator)
1516      {
1517         ecore_animator_del(sd->down.bounce_x_animator);
1518         sd->down.bounce_x_animator = NULL;
1519         sd->bouncemex = 0;
1520      }
1521    if (sd->down.bounce_y_animator)
1522      {
1523         ecore_animator_del(sd->down.bounce_y_animator);
1524         sd->down.bounce_y_animator = NULL;
1525         sd->bouncemey = 0;
1526      }
1527    _elm_smart_scroller_wanted_region_set(sd->smart_obj);
1528 }
1529
1530 static void
1531 _smart_event_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1532 {
1533    Evas_Event_Mouse_Wheel *ev;
1534    Smart_Data *sd;
1535    Evas_Coord x = 0, y = 0;
1536
1537    sd = data;
1538    ev = event_info;
1539    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1540    if ((evas_key_modifier_is_set(ev->modifiers, "Control")) ||
1541        (evas_key_modifier_is_set(ev->modifiers, "Alt")) ||
1542        (evas_key_modifier_is_set(ev->modifiers, "Shift")) ||
1543        (evas_key_modifier_is_set(ev->modifiers, "Meta")) ||
1544        (evas_key_modifier_is_set(ev->modifiers, "Hyper")) ||
1545        (evas_key_modifier_is_set(ev->modifiers, "Super")))
1546      return;
1547    elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1548    if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1549        (sd->scrollto.x.animator) || (sd->scrollto.y.animator))
1550      {
1551         _smart_anim_stop(sd->smart_obj);
1552      }
1553    if (sd->scrollto.x.animator)
1554      {
1555         ecore_animator_del(sd->scrollto.x.animator);
1556         sd->scrollto.x.animator = NULL;
1557      }
1558    if (sd->scrollto.y.animator)
1559      {
1560         ecore_animator_del(sd->scrollto.y.animator);
1561         sd->scrollto.y.animator = NULL;
1562      }
1563    if (sd->down.bounce_x_animator)
1564      {
1565         ecore_animator_del(sd->down.bounce_x_animator);
1566         sd->down.bounce_x_animator = NULL;
1567         sd->bouncemex = 0;
1568      }
1569    if (sd->down.bounce_y_animator)
1570      {
1571         ecore_animator_del(sd->down.bounce_y_animator);
1572         sd->down.bounce_y_animator = NULL;
1573         sd->bouncemey = 0;
1574      }
1575    if (!ev->direction)
1576      y += ev->z * sd->step.y;
1577    else if (ev->direction == 1)
1578      x += ev->z * sd->step.x;
1579
1580    if ((!sd->hold) && (!sd->freeze))
1581      {
1582         _update_wanted_coordinates(sd, x, y);
1583         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1584      }
1585 }
1586
1587 static void
1588 _smart_event_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
1589 {
1590    Evas_Event_Mouse_Down *ev;
1591    Smart_Data *sd;
1592    Evas_Coord x = 0, y = 0;
1593
1594    sd = data;
1595    ev = event_info;
1596    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1597    if (_elm_config->thumbscroll_enable)
1598      {
1599         sd->down.hold = 0;
1600         if ((sd->down.bounce_x_animator) || (sd->down.bounce_y_animator) ||
1601             (sd->down.momentum_animator) || (sd->scrollto.x.animator) ||
1602             (sd->scrollto.y.animator))
1603           {
1604              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL | EVAS_EVENT_FLAG_ON_HOLD;
1605              sd->down.scroll = 1;
1606              sd->down.hold = 1;
1607              _smart_anim_stop(sd->smart_obj);
1608           }
1609         if (sd->scrollto.x.animator)
1610           {
1611              ecore_animator_del(sd->scrollto.x.animator);
1612              sd->scrollto.x.animator = NULL;
1613           }
1614         if (sd->scrollto.y.animator)
1615           {
1616              ecore_animator_del(sd->scrollto.y.animator);
1617              sd->scrollto.y.animator = NULL;
1618           }
1619         if (sd->down.bounce_x_animator)
1620           {
1621              ecore_animator_del(sd->down.bounce_x_animator);
1622              sd->down.bounce_x_animator = NULL;
1623              sd->bouncemex = 0;
1624           }
1625         if (sd->down.bounce_y_animator)
1626           {
1627              ecore_animator_del(sd->down.bounce_y_animator);
1628              sd->down.bounce_y_animator = NULL;
1629              sd->bouncemey = 0;
1630           }
1631         if (sd->down.hold_animator)
1632           {
1633              ecore_animator_del(sd->down.hold_animator);
1634              sd->down.hold_animator = NULL;
1635              _smart_drag_stop(sd->smart_obj);
1636           }
1637         if (sd->down.momentum_animator)
1638           {
1639              ecore_animator_del(sd->down.momentum_animator);
1640              sd->down.momentum_animator = NULL;
1641              sd->down.bounce_x_hold = 0;
1642              sd->down.bounce_y_hold = 0;
1643              sd->down.ax = 0;
1644              sd->down.ay = 0;
1645           }
1646         if (ev->button == 1)
1647           {
1648              sd->down.now = 1;
1649              sd->down.dragged = 0;
1650              sd->down.dir_x = 0;
1651              sd->down.dir_y = 0;
1652              sd->down.x = ev->canvas.x;
1653              sd->down.y = ev->canvas.y;
1654              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1655              sd->down.sx = x;
1656              sd->down.sy = y;
1657              sd->down.locked = 0;
1658              memset(&(sd->down.history[0]), 0, sizeof(sd->down.history[0]) * 20);
1659 #ifdef EVTIME
1660              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
1661 #else
1662              sd->down.history[0].timestamp = ecore_loop_time_get();
1663 #endif
1664              sd->down.history[0].x = ev->canvas.x;
1665              sd->down.history[0].y = ev->canvas.y;
1666           }
1667         sd->down.dragged_began = 0;
1668         sd->down.hold_parent = 0;
1669         sd->down.cancelled = 0;
1670      }
1671 }
1672
1673 static Eina_Bool
1674 _smart_hold_animator(void *data)
1675 {
1676    Smart_Data *sd = data;
1677    Evas_Coord ox, oy;
1678
1679    elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
1680    if (sd->down.dir_x)
1681      {
1682         if ((!sd->widget) ||
1683             (!elm_widget_drag_child_locked_x_get(sd->widget)))
1684           {
1685              ox = sd->down.hold_x;
1686           }
1687      }
1688    if (sd->down.dir_y)
1689      {
1690         if ((!sd->widget) ||
1691             (!elm_widget_drag_child_locked_y_get(sd->widget)))
1692           {
1693              oy = sd->down.hold_y;
1694           }
1695      }
1696    elm_smart_scroller_child_pos_set(sd->smart_obj, ox, oy);
1697    return ECORE_CALLBACK_RENEW;
1698 }
1699
1700 static Eina_Bool
1701 _smart_event_post_up(void *data, Evas *e __UNUSED__)
1702 {
1703    Smart_Data *sd = data;
1704    if (sd->widget)
1705      {
1706         if (sd->down.dragged)
1707           {
1708              elm_widget_drag_lock_x_set(sd->widget, 0);
1709              elm_widget_drag_lock_y_set(sd->widget, 0);
1710           }
1711      }
1712    return EINA_TRUE;
1713 }
1714
1715 static void
1716 _smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
1717 {
1718    Evas_Event_Mouse_Down *ev;
1719    Smart_Data *sd;
1720    Evas_Coord x = 0, y = 0, ox = 0, oy = 0;
1721
1722    sd = data;
1723    ev = event_info;
1724    sd->down.hold_parent = 0;
1725    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
1726    evas_post_event_callback_push(e, _smart_event_post_up, sd);
1727    // FIXME: respect elm_widget_scroll_hold_get of parent container
1728    if (_elm_config->thumbscroll_enable)
1729      {
1730         if (ev->button == 1)
1731           {
1732              if (sd->down.onhold_animator)
1733                {
1734                   ecore_animator_del(sd->down.onhold_animator);
1735                   sd->down.onhold_animator = NULL;
1736                }
1737              x = ev->canvas.x - sd->down.x;
1738              y = ev->canvas.y - sd->down.y;
1739              if (sd->down.dragged)
1740                {
1741                   _smart_drag_stop(sd->smart_obj);
1742                   if ((!sd->hold) && (!sd->freeze))
1743                     {
1744                        double t, at, dt;
1745                        int i;
1746                        Evas_Coord ax, ay, dx, dy, vel;
1747
1748 #ifdef EVTIME
1749                        t = ev->timestamp / 1000.0;
1750 #else
1751                        t = ecore_loop_time_get();
1752 #endif
1753                        ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1754                        ax = ev->canvas.x;
1755                        ay = ev->canvas.y;
1756                        at = 0.0;
1757 #ifdef SCROLLDBG
1758                        printf("------ %i %i\n", ev->canvas.x, ev->canvas.y);
1759 #endif
1760                        for (i = 0; i < 20; i++)
1761                          {
1762                             dt = t - sd->down.history[i].timestamp;
1763                             if (dt > 0.2) break;
1764 #ifdef SCROLLDBG
1765                             printf("H: %i %i @ %1.3f\n",
1766                                    sd->down.history[i].x,
1767                                    sd->down.history[i].y, dt);
1768 #endif
1769                             at += dt;
1770                             ax += sd->down.history[i].x;
1771                             ay += sd->down.history[i].y;
1772                          }
1773                        ax /= (i + 1);
1774                        ay /= (i + 1);
1775                        at /= (i + 1);
1776                        at *= 4.0;
1777                        dx = ev->canvas.x - ax;
1778                        dy = ev->canvas.y - ay;
1779                        if (at > 0)
1780                          {
1781                             vel = sqrt((dx * dx) + (dy * dy)) / at;
1782                             if ((_elm_config->thumbscroll_friction > 0.0) &&
1783                                 (vel > _elm_config->thumbscroll_momentum_threshold))
1784                               {
1785                                  sd->down.dx = ((double)dx / at);
1786                                  sd->down.dy = ((double)dy / at);
1787                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1788                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)))
1789                                    sd->down.dx += (double)sd->down.pdx * 1.5; // FIXME: * 1.5 - probably should be config
1790                                  if (((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1791                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1792                                    sd->down.dy += (double)sd->down.pdy * 1.5; // FIXME: * 1.5 - probably should be config
1793                                  if (((sd->down.dx > 0) && (sd->down.pdx > 0)) ||
1794                                      ((sd->down.dx < 0) && (sd->down.pdx < 0)) ||
1795                                      ((sd->down.dy > 0) && (sd->down.pdy > 0)) ||
1796                                      ((sd->down.dy < 0) && (sd->down.pdy < 0)))
1797                                    {
1798                                       double t = ecore_loop_time_get();
1799                                       double dt = t - sd->down.anim_start;
1800
1801                                       if (dt < 0.0) dt = 0.0;
1802                                       else if (dt > _elm_config->thumbscroll_friction)
1803                                         dt = _elm_config->thumbscroll_friction;
1804                                       sd->down.extra_time = _elm_config->thumbscroll_friction - dt;
1805                                    }
1806                                  else
1807                                    sd->down.extra_time = 0.0;
1808                                  sd->down.pdx = sd->down.dx;
1809                                  sd->down.pdy = sd->down.dy;
1810                                  ox = -sd->down.dx;
1811                                  oy = -sd->down.dy;
1812                                  if (!_smart_do_page(sd))
1813                                    {
1814                                       if ((!sd->down.momentum_animator) && (!sd->momentum_animator_disabled))
1815                                         {
1816                                            sd->down.momentum_animator = ecore_animator_add(_smart_momentum_animator, sd);
1817                                            ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1818                                            _smart_anim_start(sd->smart_obj);
1819                                         }
1820                                       sd->down.anim_start = ecore_loop_time_get();
1821                                       elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1822                                       sd->down.sx = x;
1823                                       sd->down.sy = y;
1824                                       sd->down.b0x = 0;
1825                                       sd->down.b0y = 0;
1826                                    }
1827                               }
1828                          }
1829                        if (sd->down.hold_animator)
1830                          {
1831                             ecore_animator_del(sd->down.hold_animator);
1832                             sd->down.hold_animator = NULL;
1833                          }
1834                     }
1835                   else
1836                     {
1837                        sd->down.pdx = 0;
1838                        sd->down.pdy = 0;
1839                     }
1840                   evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
1841                   if (_smart_do_page(sd))
1842                     {
1843                        Evas_Coord pgx, pgy;
1844
1845                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1846                        if ((!sd->widget) ||
1847                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1848                          {
1849                             pgx = _smart_page_x_get(sd, ox);
1850                             if (pgx != x)
1851                               {
1852                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1853                                  _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1854                               }
1855                          }
1856                        if ((!sd->widget) ||
1857                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1858                          {
1859                             pgy = _smart_page_y_get(sd, oy);
1860                             if (pgy != y)
1861                               {
1862                                  ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1863                                  _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
1864                               }
1865                          }
1866                     }
1867                }
1868              else
1869                {
1870                   sd->down.pdx = 0;
1871                   sd->down.pdy = 0;
1872                   if (_smart_do_page(sd))
1873                     {
1874                        Evas_Coord pgx, pgy;
1875
1876                        elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1877                        if ((!sd->widget) ||
1878                            (!elm_widget_drag_child_locked_x_get(sd->widget)))
1879                          {
1880                             pgx = _smart_page_x_get(sd, ox);
1881                             if (pgx != x) _smart_scrollto_x(sd, _elm_config->page_scroll_friction, pgx);
1882                          }
1883                        if ((!sd->widget) ||
1884                            (!elm_widget_drag_child_locked_y_get(sd->widget)))
1885                          {
1886                             pgy = _smart_page_y_get(sd, oy);
1887                             if (pgy != y) _smart_scrollto_y(sd, _elm_config->page_scroll_friction, pgy);
1888                          }
1889                     }
1890                   if (sd->down.hold_animator)
1891                     {
1892                        ecore_animator_del(sd->down.hold_animator);
1893                        sd->down.hold_animator = NULL;
1894                     }
1895                }
1896              if (sd->down.scroll)
1897                {
1898                   ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
1899                   sd->down.scroll = 0;
1900                }
1901              if (sd->down.hold)
1902                {
1903                   ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1904                   sd->down.hold = 0;
1905                }
1906              sd->down.dragged_began = 0;
1907              sd->down.dir_x = 0;
1908              sd->down.dir_y = 0;
1909              sd->down.want_dragged = 0;
1910              sd->down.dragged = 0;
1911              sd->down.now = 0;
1912              elm_smart_scroller_child_pos_get(sd->smart_obj, &x, &y);
1913              elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1914              _update_wanted_coordinates(sd, x, y);
1915
1916              if (!_smart_do_page(sd))
1917                bounce_eval(sd);
1918           }
1919      }
1920 }
1921
1922 static Eina_Bool
1923 _smart_onhold_animator(void *data)
1924 {
1925    Smart_Data *sd;
1926    double t, td;
1927    double vx, vy;
1928    Evas_Coord x, y, ox, oy;
1929
1930    sd = data;
1931    t = ecore_loop_time_get();
1932    if (sd->down.onhold_tlast > 0.0)
1933      {
1934         td = t - sd->down.onhold_tlast;
1935         vx = sd->down.onhold_vx * td * (double)_elm_config->thumbscroll_threshold * 2.0;
1936         vy = sd->down.onhold_vy * td * (double)_elm_config->thumbscroll_threshold * 2.0;
1937         elm_smart_scroller_child_pos_get(sd->smart_obj, &ox, &oy);
1938         x = ox;
1939         y = oy;
1940
1941         if (sd->down.dir_x)
1942           {
1943              if ((!sd->widget) ||
1944                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
1945                {
1946                   sd->down.onhold_vxe += vx;
1947                   x = ox + (int)sd->down.onhold_vxe;
1948                   sd->down.onhold_vxe -= (int)sd->down.onhold_vxe;
1949                }
1950           }
1951
1952         if (sd->down.dir_y)
1953           {
1954              if ((!sd->widget) ||
1955                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
1956                {
1957                   sd->down.onhold_vye += vy;
1958                   y = oy + (int)sd->down.onhold_vye;
1959                   sd->down.onhold_vye -= (int)sd->down.onhold_vye;
1960                }
1961           }
1962
1963         elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
1964      }
1965    sd->down.onhold_tlast = t;
1966    return ECORE_CALLBACK_RENEW;
1967 }
1968
1969 static Eina_Bool
1970 _smart_event_post_move(void *data, Evas *e __UNUSED__)
1971 {
1972    Smart_Data *sd = data;
1973
1974    if (sd->down.want_dragged)
1975      {
1976         int start = 0;
1977
1978         if (sd->down.hold_parent)
1979           {
1980              if ((sd->down.dir_x) && !can_scroll(sd, sd->down.hdir))
1981                {
1982                   sd->down.dir_x = 0;
1983                }
1984              if ((sd->down.dir_y) && !can_scroll(sd, sd->down.vdir))
1985                {
1986                   sd->down.dir_y = 0;
1987                }
1988           }
1989         if (sd->down.dir_x)
1990           {
1991              if ((!sd->widget) ||
1992                  (!elm_widget_drag_child_locked_x_get(sd->widget)))
1993                {
1994                   sd->down.want_dragged = 0;
1995                   sd->down.dragged = 1;
1996                   if (sd->widget)
1997                     {
1998                        elm_widget_drag_lock_x_set(sd->widget, 1);
1999                     }
2000                   start = 1;
2001                }
2002              else
2003                sd->down.dir_x = 0;
2004           }
2005         if (sd->down.dir_y)
2006           {
2007              if ((!sd->widget) ||
2008                  (!elm_widget_drag_child_locked_y_get(sd->widget)))
2009                {
2010                   sd->down.want_dragged = 0;
2011                   sd->down.dragged = 1;
2012                   if (sd->widget)
2013                     {
2014                        elm_widget_drag_lock_y_set(sd->widget, 1);
2015                     }
2016                   start = 1;
2017                }
2018              else
2019                sd->down.dir_y = 0;
2020           }
2021         if ((!sd->down.dir_x) && (!sd->down.dir_y))
2022           {
2023              sd->down.cancelled = 1;
2024           }
2025         if (start) _smart_drag_start(sd->smart_obj);
2026      }
2027    return EINA_TRUE;
2028 }
2029
2030 static void
2031 _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info)
2032 {
2033    Evas_Event_Mouse_Move *ev;
2034    Smart_Data *sd;
2035    Evas_Coord x = 0, y = 0;
2036
2037    sd = data;
2038    ev = event_info;
2039    //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
2040    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->down.hold_parent = 1;
2041    evas_post_event_callback_push(e, _smart_event_post_move, sd);
2042    // FIXME: respect elm_widget_scroll_hold_get of parent container
2043    if (_elm_config->thumbscroll_enable)
2044      {
2045         if (sd->down.now)
2046           {
2047              int dodir = 0;
2048
2049 #ifdef SCROLLDBG
2050              printf("::: %i %i\n", ev->cur.canvas.x, ev->cur.canvas.y);
2051 #endif
2052              memmove(&(sd->down.history[1]), &(sd->down.history[0]),
2053                      sizeof(sd->down.history[0]) * 19);
2054 #ifdef EVTIME
2055              sd->down.history[0].timestamp = ev->timestamp / 1000.0;
2056 #else
2057              sd->down.history[0].timestamp = ecore_loop_time_get();
2058 #endif
2059              sd->down.history[0].x = ev->cur.canvas.x;
2060              sd->down.history[0].y = ev->cur.canvas.y;
2061
2062              if (!sd->down.dragged_began)
2063                {
2064                   x = ev->cur.canvas.x - sd->down.x;
2065                   y = ev->cur.canvas.y - sd->down.y;
2066
2067                   sd->down.hdir = -1;
2068                   sd->down.vdir = -1;
2069
2070                   if      (x > 0) sd->down.hdir = LEFT;
2071                   else if (x < 0) sd->down.hdir = RIGHT;
2072                   if      (y > 0) sd->down.vdir = UP;
2073                   else if (y < 0) sd->down.vdir = DOWN;
2074
2075                   if (x < 0) x = -x;
2076                   if (y < 0) y = -y;
2077
2078                   if ((sd->one_dir_at_a_time) &&
2079                       (!((sd->down.dir_x) || (sd->down.dir_y))))
2080                     {
2081                        if (x > _elm_config->thumbscroll_threshold)
2082                          {
2083                             if (x > (y * 2))
2084                               {
2085                                  sd->down.dir_x = 1;
2086                                  sd->down.dir_y = 0;
2087                                  dodir++;
2088                               }
2089                          }
2090                        if (y > _elm_config->thumbscroll_threshold)
2091                          {
2092                             if (y > (x * 2))
2093                               {
2094                                  sd->down.dir_x = 0;
2095                                  sd->down.dir_y = 1;
2096                                  dodir++;
2097                               }
2098                          }
2099                        if (!dodir)
2100                          {
2101                             sd->down.dir_x = 1;
2102                             sd->down.dir_y = 1;
2103                          }
2104                     }
2105                   else
2106                     {
2107                        //                       can_scroll(sd, LEFT);
2108                        //                       can_scroll(sd, RIGHT);
2109                        //                       can_scroll(sd, UP);
2110                        //                       can_scroll(sd, DOWN);
2111                        sd->down.dir_x = 1;
2112                        sd->down.dir_y = 1;
2113                     }
2114                }
2115              if ((!sd->hold) && (!sd->freeze))
2116                {
2117                   if ((sd->down.dragged) ||
2118                       (((x * x) + (y * y)) >
2119                        (_elm_config->thumbscroll_threshold *
2120                         _elm_config->thumbscroll_threshold)))
2121                     {
2122                        sd->down.dragged_began = 1;
2123                        if (!sd->down.dragged)
2124                          {
2125                             sd->down.want_dragged = 1;
2126                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2127                             //                            evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2128                             //                            _smart_drag_start(sd->smart_obj);
2129                          }
2130                        if (sd->down.dragged)
2131                          {
2132                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2133                          }
2134                        //                       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2135                        //                       sd->down.dragged = 1;
2136                        if (sd->down.dir_x)
2137                          x = sd->down.sx - (ev->cur.canvas.x - sd->down.x);
2138                        else
2139                          x = sd->down.sx;
2140                        if (sd->down.dir_y)
2141                          y = sd->down.sy - (ev->cur.canvas.y - sd->down.y);
2142                        else
2143                          y = sd->down.sy;
2144                        if ((sd->down.dir_x) || (sd->down.dir_y))
2145                          {
2146                             if (!sd->down.locked)
2147                               {
2148                                  sd->down.locked_x = x;
2149                                  sd->down.locked_y = y;
2150                                  sd->down.locked = 1;
2151                               }
2152                             if (!((sd->down.dir_x) && (sd->down.dir_y)))
2153                               {
2154                                  if (sd->down.dir_x) y = sd->down.locked_y;
2155                                  else x = sd->down.locked_x;
2156                               }
2157                          }
2158                        if (_elm_config->thumbscroll_border_friction > 0.0)
2159                          {
2160                             Evas_Coord minx, miny;
2161                             sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2162                             if (y < miny)
2163                               y += (miny - y) *
2164                                  _elm_config->thumbscroll_border_friction;
2165                             else if (sd->child.h <= sd->h)
2166                               y += (sd->down.sy - y) *
2167                                  _elm_config->thumbscroll_border_friction;
2168                             else if ((sd->child.h - sd->h + miny) < y)
2169                               y += (sd->child.h - sd->h + miny - y) *
2170                                  _elm_config->thumbscroll_border_friction;
2171                             if (x < minx)
2172                               x += (minx - x) *
2173                                  _elm_config->thumbscroll_border_friction;
2174                             else if (sd->child.w <= sd->w)
2175                               x += (sd->down.sx - x) *
2176                                  _elm_config->thumbscroll_border_friction;
2177                             else if ((sd->child.w - sd->w + minx) < x)
2178                               x += (sd->child.w - sd->w + minx - x) *
2179                                  _elm_config->thumbscroll_border_friction;
2180                          }
2181
2182                        sd->down.hold_x = x;
2183                        sd->down.hold_y = y;
2184                        if (!sd->down.hold_animator)
2185                          sd->down.hold_animator =
2186                             ecore_animator_add(_smart_hold_animator, sd);
2187                        //                       printf("a %i %i\n", sd->down.hold_x, sd->down.hold_y);
2188                        //                       _smart_onhold_animator(sd);
2189                        //                       elm_smart_scroller_child_pos_set(sd->smart_obj, x, y);
2190                     }
2191                   else
2192                     {
2193                        if (sd->down.dragged_began)
2194                          {
2195                             ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2196                             if (!sd->down.hold)
2197                               {
2198                                  sd->down.hold = 1;
2199                                  evas_event_feed_hold(e, 1, ev->timestamp, ev->data);
2200                               }
2201                          }
2202                     }
2203                }
2204              else if (!sd->freeze)
2205                {
2206                   Evas_Coord ex, ey, ew, eh;
2207                   double vx = 0.0, vy = 0.0;
2208
2209                   evas_object_geometry_get(sd->event_obj, &ex, &ey, &ew, &eh);
2210                   x = ev->cur.canvas.x - ex;
2211                   y = ev->cur.canvas.y - ey;
2212                   if (x < _elm_config->thumbscroll_threshold)
2213                     {
2214                        if (_elm_config->thumbscroll_threshold > 0.0)
2215                          vx = -(double)(_elm_config->thumbscroll_threshold - x) /
2216                             _elm_config->thumbscroll_threshold;
2217                        else
2218                          vx = -1.0;
2219                     }
2220                   else if (x > (ew - _elm_config->thumbscroll_threshold))
2221                     {
2222                        if (_elm_config->thumbscroll_threshold > 0.0)
2223                          vx = (double)(_elm_config->thumbscroll_threshold - (ew - x)) /
2224                             _elm_config->thumbscroll_threshold;
2225                        else
2226                          vx = 1.0;
2227                     }
2228                   if (y < _elm_config->thumbscroll_threshold)
2229                     {
2230                        if (_elm_config->thumbscroll_threshold > 0.0)
2231                          vy = -(double)(_elm_config->thumbscroll_threshold - y) /
2232                             _elm_config->thumbscroll_threshold;
2233                        else
2234                          vy = -1.0;
2235                     }
2236                   else if (y > (eh - _elm_config->thumbscroll_threshold))
2237                     {
2238                        if (_elm_config->thumbscroll_threshold > 0.0)
2239                          vy = (double)(_elm_config->thumbscroll_threshold - (eh - y)) /
2240                             _elm_config->thumbscroll_threshold;
2241                        else
2242                          vy = 1.0;
2243                     }
2244                   if ((vx != 0.0) || (vy != 0.0))
2245                     {
2246                        sd->down.onhold_vx = vx;
2247                        sd->down.onhold_vy = vy;
2248                        if (!sd->down.onhold_animator)
2249                          {
2250                             sd->down.onhold_vxe = 0.0;
2251                             sd->down.onhold_vye = 0.0;
2252                             sd->down.onhold_tlast = 0.0;
2253                             sd->down.onhold_animator = ecore_animator_add(_smart_onhold_animator, sd);
2254                          }
2255                        //                       printf("b %i %i\n", sd->down.hold_x, sd->down.hold_y);
2256                     }
2257                   else
2258                     {
2259                        if (sd->down.onhold_animator)
2260                          {
2261                             ecore_animator_del(sd->down.onhold_animator);
2262                             sd->down.onhold_animator = NULL;
2263                          }
2264                     }
2265                }
2266           }
2267      }
2268 }
2269
2270 static void
2271 _smart_scrollbar_read(Smart_Data *sd)
2272 {
2273    Evas_Coord x, y, mx = 0, my = 0, px, py, minx = 0, miny = 0;
2274    double vx, vy;
2275
2276    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2277    edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2278    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2279    sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2280    x = vx * (double)mx + minx;
2281    y = vy * (double)my + miny;
2282    sd->pan_func.get(sd->pan_obj, &px, &py);
2283    sd->pan_func.set(sd->pan_obj, x, y);
2284    if ((px != x) || (py != y))
2285      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2286 }
2287
2288 static void
2289 _smart_scrollbar_reset(Smart_Data *sd)
2290 {
2291    Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2292
2293    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2294    edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2295    if ((!sd->child_obj) && (!sd->extern_pan))
2296      {
2297         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2298         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2299      }
2300    if (sd->pan_obj)
2301      {
2302         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2303         sd->pan_func.get(sd->pan_obj, &px, &py);
2304         sd->pan_func.set(sd->pan_obj, minx, miny);
2305      }
2306    if ((px != minx) || (py != miny))
2307      edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2308 }
2309
2310 static int
2311 _smart_scrollbar_bar_v_visibility_adjust(Smart_Data *sd)
2312 {
2313    int scroll_v_vis_change = 0;
2314    Evas_Coord h, vw = 0, vh = 0;
2315
2316    h = sd->child.h;
2317    if (sd->pan_obj)
2318      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2319    if (sd->vbar_visible)
2320      {
2321         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2322           {
2323              if ((sd->child_obj) || (sd->extern_pan))
2324                {
2325                   if (h <= vh)
2326                     {
2327                        scroll_v_vis_change = 1;
2328                        sd->vbar_visible = 0;
2329                     }
2330                }
2331              else
2332                {
2333                   scroll_v_vis_change = 1;
2334                   sd->vbar_visible = 0;
2335                }
2336           }
2337         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2338           {
2339              scroll_v_vis_change = 1;
2340              sd->vbar_visible = 0;
2341           }
2342      }
2343    else
2344      {
2345         if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2346           {
2347              if ((sd->child_obj) || (sd->extern_pan))
2348                {
2349                   if (h > vh)
2350                     {
2351                        scroll_v_vis_change = 1;
2352                        sd->vbar_visible = 1;
2353                     }
2354                }
2355           }
2356         else if (sd->vbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2357           {
2358              scroll_v_vis_change = 1;
2359              sd->vbar_visible = 1;
2360           }
2361      }
2362    if (scroll_v_vis_change)
2363      {
2364         if (sd->vbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2365           {
2366              if (sd->vbar_visible)
2367                edje_object_signal_emit(sd->edje_obj, "elm,action,show,vbar", "elm");
2368              else
2369                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2370              edje_object_message_signal_process(sd->edje_obj);
2371              _smart_scrollbar_size_adjust(sd);
2372           }
2373         else
2374           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,vbar", "elm");
2375      }
2376    return scroll_v_vis_change;
2377 }
2378
2379 static int
2380 _smart_scrollbar_bar_h_visibility_adjust(Smart_Data *sd)
2381 {
2382    int scroll_h_vis_change = 0;
2383    Evas_Coord w, vw = 0, vh = 0;
2384
2385    w = sd->child.w;
2386    if (sd->pan_obj)
2387      evas_object_geometry_get(sd->pan_obj, NULL, NULL, &vw, &vh);
2388    if (sd->hbar_visible)
2389      {
2390         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2391           {
2392              if ((sd->child_obj) || (sd->extern_pan))
2393                {
2394                   if (w <= vw)
2395                     {
2396                        scroll_h_vis_change = 1;
2397                        sd->hbar_visible = 0;
2398                     }
2399                }
2400              else
2401                {
2402                   scroll_h_vis_change = 1;
2403                   sd->hbar_visible = 0;
2404                }
2405           }
2406         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_OFF)
2407           {
2408              scroll_h_vis_change = 1;
2409              sd->hbar_visible = 0;
2410           }
2411      }
2412    else
2413      {
2414         if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_AUTO)
2415           {
2416              if ((sd->child_obj) || (sd->extern_pan))
2417                {
2418                   if (w > vw)
2419                     {
2420                        scroll_h_vis_change = 1;
2421                        sd->hbar_visible = 1;
2422                     }
2423                }
2424           }
2425         else if (sd->hbar_flags == ELM_SMART_SCROLLER_POLICY_ON)
2426           {
2427              scroll_h_vis_change = 1;
2428              sd->hbar_visible = 1;
2429           }
2430      }
2431    if (scroll_h_vis_change)
2432      {
2433         if (sd->hbar_flags != ELM_SMART_SCROLLER_POLICY_OFF)
2434           {
2435              if (sd->hbar_visible)
2436                edje_object_signal_emit(sd->edje_obj, "elm,action,show,hbar", "elm");
2437              else
2438                edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2439              edje_object_message_signal_process(sd->edje_obj);
2440              _smart_scrollbar_size_adjust(sd);
2441           }
2442         else
2443           edje_object_signal_emit(sd->edje_obj, "elm,action,hide,hbar", "elm");
2444         _smart_scrollbar_size_adjust(sd);
2445      }
2446    return scroll_h_vis_change;
2447 }
2448
2449 static void
2450 _smart_scrollbar_bar_visibility_adjust(Smart_Data *sd)
2451 {
2452    int changed = 0;
2453
2454    changed |= _smart_scrollbar_bar_h_visibility_adjust(sd);
2455    changed |= _smart_scrollbar_bar_v_visibility_adjust(sd);
2456    if (changed)
2457      {
2458         _smart_scrollbar_bar_h_visibility_adjust(sd);
2459         _smart_scrollbar_bar_v_visibility_adjust(sd);
2460      }
2461 }
2462
2463 static void
2464 _smart_scrollbar_size_adjust(Smart_Data *sd)
2465 {
2466    if ((sd->child_obj) || (sd->extern_pan))
2467      {
2468         Evas_Coord x, y, w, h, mx = 0, my = 0, vw = 0, vh = 0, px, py, minx = 0, miny = 0;
2469         double vx, vy, size;
2470
2471         edje_object_part_geometry_get(sd->edje_obj, "elm.swallow.content",
2472                                       NULL, NULL, &vw, &vh);
2473         w = sd->child.w;
2474         if (w < 1) w = 1;
2475         size = (double)vw / (double)w;
2476         if (size > 1.0)
2477           {
2478              size = 1.0;
2479              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.hbar", 0.0, 0.0);
2480           }
2481         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", size, 1.0);
2482
2483         h = sd->child.h;
2484         if (h < 1) h = 1;
2485         size = (double)vh / (double)h;
2486         if (size > 1.0)
2487           {
2488              size = 1.0;
2489              edje_object_part_drag_value_set(sd->edje_obj, "elm.dragable.vbar", 0.0, 0.0);
2490           }
2491         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, size);
2492
2493         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.hbar", &vx, NULL);
2494         edje_object_part_drag_value_get(sd->edje_obj, "elm.dragable.vbar", NULL, &vy);
2495         sd->pan_func.max_get(sd->pan_obj, &mx, &my);
2496         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2497         x = vx * mx + minx;
2498         y = vy * my + miny;
2499
2500         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->step.x / (double)w, 0.0);
2501         edje_object_part_drag_step_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->step.y / (double)h);
2502         if (sd->page.x > 0)
2503           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", (double)sd->page.x / (double)w, 0.0);
2504         else
2505           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.hbar", -((double)sd->page.x * ((double)vw / (double)w)) / 100.0, 0.0);
2506         if (sd->page.y > 0)
2507           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, (double)sd->page.y / (double)h);
2508         else
2509           edje_object_part_drag_page_set(sd->edje_obj, "elm.dragable.vbar", 0.0, -((double)sd->page.y * ((double)vh / (double)h)) / 100.0);
2510
2511         sd->pan_func.get(sd->pan_obj, &px, &py);
2512         if (vx != mx) x = px;
2513         if (vy != my) y = py;
2514         sd->pan_func.set(sd->pan_obj, x, y);
2515         //      if ((px != 0) || (py != 0))
2516         //        edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2517      }
2518    else
2519      {
2520         Evas_Coord px = 0, py = 0, minx = 0, miny = 0;
2521
2522         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.vbar", 1.0, 1.0);
2523         edje_object_part_drag_size_set(sd->edje_obj, "elm.dragable.hbar", 1.0, 1.0);
2524         sd->pan_func.min_get(sd->pan_obj, &minx, &miny);
2525         sd->pan_func.get(sd->pan_obj, &px, &py);
2526         sd->pan_func.set(sd->pan_obj, minx, miny);
2527         if ((px != minx) || (py != miny))
2528           edje_object_signal_emit(sd->edje_obj, "elm,action,scroll", "elm");
2529      }
2530    _smart_scrollbar_bar_visibility_adjust(sd);
2531 }
2532
2533 static void
2534 _smart_reconfigure(Smart_Data *sd)
2535 {
2536    evas_object_move(sd->edje_obj, sd->x, sd->y);
2537    evas_object_resize(sd->edje_obj, sd->w, sd->h);
2538    evas_object_move(sd->event_obj, sd->x, sd->y);
2539    evas_object_resize(sd->event_obj, sd->w, sd->h);
2540    _smart_scrollbar_size_adjust(sd);
2541 }
2542
2543 static void
2544 _smart_add(Evas_Object *obj)
2545 {
2546    Smart_Data *sd;
2547    Evas_Object *o;
2548
2549    sd = calloc(1, sizeof(Smart_Data));
2550    if (!sd) return;
2551    evas_object_smart_data_set(obj, sd);
2552
2553    sd->smart_obj = obj;
2554    sd->x = 0;
2555    sd->y = 0;
2556    sd->w = 0;
2557    sd->h = 0;
2558    sd->step.x = 32;
2559    sd->step.y = 32;
2560    sd->page.x = -50;
2561    sd->page.y = -50;
2562    sd->hbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2563    sd->vbar_flags = ELM_SMART_SCROLLER_POLICY_AUTO;
2564    sd->hbar_visible = 1;
2565    sd->vbar_visible = 1;
2566
2567    sd->bounce_horiz = 1;
2568    sd->bounce_vert = 1;
2569
2570    sd->one_dir_at_a_time = 1;
2571    sd->momentum_animator_disabled = EINA_FALSE;
2572    sd->bounce_animator_disabled = EINA_FALSE;
2573
2574    o = edje_object_add(evas_object_evas_get(obj));
2575    evas_object_propagate_events_set(o, 0);
2576    sd->edje_obj = o;
2577    elm_smart_scroller_object_theme_set(NULL, obj, "scroller", "base", "default");
2578    edje_object_signal_callback_add(o, "drag", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2579    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.vbar", _smart_edje_drag_v_start, sd);
2580    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.vbar", _smart_edje_drag_v_stop, sd);
2581    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2582    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.vbar", _smart_edje_drag_v, sd);
2583    edje_object_signal_callback_add(o, "drag", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2584    edje_object_signal_callback_add(o, "drag,start", "elm.dragable.hbar", _smart_edje_drag_h_start, sd);
2585    edje_object_signal_callback_add(o, "drag,stop", "elm.dragable.hbar", _smart_edje_drag_h_stop, sd);
2586    edje_object_signal_callback_add(o, "drag,step", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2587    edje_object_signal_callback_add(o, "drag,page", "elm.dragable.hbar", _smart_edje_drag_h, sd);
2588    evas_object_smart_member_add(o, obj);
2589
2590    o = evas_object_rectangle_add(evas_object_evas_get(obj));
2591    sd->event_obj = o;
2592    evas_object_color_set(o, 0, 0, 0, 0);
2593    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _smart_event_wheel, sd);
2594    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _smart_event_mouse_down, sd);
2595    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _smart_event_mouse_up, sd);
2596    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _smart_event_mouse_move, sd);
2597    evas_object_smart_member_add(o, obj);
2598    evas_object_repeat_events_set(o, 1);
2599
2600    sd->pan_func.set = _elm_smart_pan_set;
2601    sd->pan_func.get = _elm_smart_pan_get;
2602    sd->pan_func.max_get = _elm_smart_pan_max_get;
2603    sd->pan_func.min_get = _elm_smart_pan_min_get;
2604    sd->pan_func.child_size_get = _elm_smart_pan_child_size_get;
2605
2606    _smart_scrollbar_reset(sd);
2607 }
2608
2609 static void
2610 _smart_del(Evas_Object *obj)
2611 {
2612    INTERNAL_ENTRY;
2613    elm_smart_scroller_child_set(obj, NULL);
2614    if (!sd->extern_pan) evas_object_del(sd->pan_obj);
2615    evas_object_del(sd->edje_obj);
2616    evas_object_del(sd->event_obj);
2617    if (sd->down.hold_animator) ecore_animator_del(sd->down.hold_animator);
2618    if (sd->down.onhold_animator) ecore_animator_del(sd->down.onhold_animator);
2619    if (sd->down.momentum_animator) ecore_animator_del(sd->down.momentum_animator);
2620    if (sd->down.bounce_x_animator) ecore_animator_del(sd->down.bounce_x_animator);
2621    if (sd->down.bounce_y_animator) ecore_animator_del(sd->down.bounce_y_animator);
2622    if (sd->scrollto.x.animator) ecore_animator_del(sd->scrollto.x.animator);
2623    if (sd->scrollto.y.animator) ecore_animator_del(sd->scrollto.y.animator);
2624    free(sd);
2625    evas_object_smart_data_set(obj, NULL);
2626 }
2627
2628 static void
2629 _smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
2630 {
2631    INTERNAL_ENTRY;
2632    sd->x = x;
2633    sd->y = y;
2634    _smart_reconfigure(sd);
2635 }
2636
2637 static void
2638 _smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
2639 {
2640    INTERNAL_ENTRY;
2641    sd->w = w;
2642    sd->h = h;
2643    _smart_reconfigure(sd);
2644    _elm_smart_scroller_wanted_region_set(obj);
2645 }
2646
2647 static void
2648 _smart_show(Evas_Object *obj)
2649 {
2650    INTERNAL_ENTRY;
2651    evas_object_show(sd->edje_obj);
2652    evas_object_show(sd->event_obj);
2653 }
2654
2655 static void
2656 _smart_hide(Evas_Object *obj)
2657 {
2658    INTERNAL_ENTRY;
2659    evas_object_hide(sd->edje_obj);
2660    evas_object_hide(sd->event_obj);
2661 }
2662
2663 static void
2664 _smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
2665 {
2666    INTERNAL_ENTRY;
2667    evas_object_color_set(sd->edje_obj, r, g, b, a);
2668 }
2669
2670 static void
2671 _smart_clip_set(Evas_Object *obj, Evas_Object *clip)
2672 {
2673    INTERNAL_ENTRY;
2674    evas_object_clip_set(sd->edje_obj, clip);
2675    evas_object_clip_set(sd->event_obj, clip);
2676 }
2677
2678 static void
2679 _smart_clip_unset(Evas_Object *obj)
2680 {
2681    INTERNAL_ENTRY;
2682    evas_object_clip_unset(sd->edje_obj);
2683    evas_object_clip_unset(sd->event_obj);
2684 }
2685
2686 /* never need to touch this */
2687
2688 static void
2689 _smart_init(void)
2690 {
2691    if (_smart) return;
2692      {
2693         static const Evas_Smart_Class sc =
2694           {
2695              SMART_NAME,
2696              EVAS_SMART_CLASS_VERSION,
2697              _smart_add,
2698              _smart_del,
2699              _smart_move,
2700              _smart_resize,
2701              _smart_show,
2702              _smart_hide,
2703              _smart_color_set,
2704              _smart_clip_set,
2705              _smart_clip_unset,
2706              NULL,
2707              NULL,
2708              NULL,
2709              NULL,
2710              NULL,
2711              NULL,
2712              NULL
2713           };
2714         _smart = evas_smart_class_new(&sc);
2715      }
2716 }