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