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