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