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