[Image Slider] Bug fix
[framework/uifw/elementary.git] / src / lib / elm_imageslider.c
1 /* 
2
3 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 
4 */
5 #include <stdio.h>
6 #include <math.h>
7 #include <Elementary.h>
8 #include "elm_priv.h"
9
10 /**
11 * @defgroup Imageslider Imageslider
12 * @ingroup Elementary
13 *
14 * By flicking images on the screen, 
15 * you can see the images in specific path.
16 */
17
18 typedef struct _Widget_Data Widget_Data;
19
20 #define ANI_STEP                                (14 * elm_scale_get())
21 #define ANI_TIME                                (0.005)
22 #define ANI_TIME_MSEC           (12)
23 #define FLICK_TIME_MAX          (200)
24 #define FLICK_WIDTH_MIN (elm_finger_size_get() >> 2)
25 #define MOVE_STEP                       (3)
26 #define STEP_WEIGHT_DEF (1)
27 #define STEP_WEIGHT_MAX (2)
28 #define STEP_WEIGHT_MIN (0)
29 #define MOVING_IMAGE_SIZE       (128)
30 #define MAX_ZOOM_SIZE           (6)
31 #define INTERVAL_WIDTH          (15)
32 #define MULTITOUCHDEVICE        (11)
33
34 enum {
35         BLOCK_LEFT = 0,
36         BLOCK_CENTER,
37         BLOCK_RIGHT,
38         BLOCK_MAX
39 };
40
41 struct _Imageslider_Item 
42 {
43         Evas_Object *obj;
44         const char *photo_file;
45         void (*func)(void *data, Evas_Object *obj, void *event_info);
46         void *data;
47         Evas_Coord x, y, w, h;
48         Evas_Coord ox, oy, ow, oh;
49         int moving : 1;
50 };
51
52 struct _Widget_Data
53 {
54         Evas_Object *ly[BLOCK_MAX];
55         Evas_Object *clip;
56         Eina_List *its;
57         Eina_List *cur;
58         Evas_Coord x, y, w, h;
59         Evas_Object *obj;
60         Ecore_Idler *queue_idler;
61         Ecore_Timer *anim_timer;
62
63         Evas_Coord_Point down_pos;
64         Evas_Coord move_x;
65         Evas_Coord move_y;
66         Evas_Coord dest_x;
67         struct timeval tv;
68         unsigned int timestamp;
69         int step;
70         int move_cnt;
71         int ani_lock : 1;
72         int moving : 1;
73
74         Eina_Bool on_zoom : 1;
75         Eina_Bool on_hold : 1;
76         int dx, dy, mx, my;
77         int mdx, mdy, mmx, mmy;
78         int dratio;
79         int ratio;
80 };
81
82
83 static const char *widtype = NULL;
84 static void _del_hook(Evas_Object *obj);
85 static void _theme_hook(Evas_Object *obj);
86 static void _sizing_eval(Evas_Object *obj);
87 static void _imageslider_del_all(Widget_Data *wd);
88 static void _imageslider_move(void *data,Evas *e, Evas_Object *obj, void *event_info);
89 static void _imageslider_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
90 //static void _imageslider_show(Evas_Object *obj);
91 //static void _imageslider_hide(Evas_Object *obj);
92 static void _imageslider_show(void * data, Evas * e, Evas_Object * obj, void * event_info);
93 static void _imageslider_hide(void * data, Evas * e, Evas_Object * obj, void * event_info);
94 static void _imageslider_update(Widget_Data *wd);
95 static void _imageslider_update_pos(Widget_Data *wd, Evas_Coord x, Evas_Coord y, Evas_Coord w);
96 static void _imageslider_update_center_pos(Widget_Data *wd, Evas_Coord x, Evas_Coord my, Evas_Coord y, Evas_Coord w);
97 static Evas_Object *_imageslider_add_obj(Widget_Data *wd);
98 static void _imageslider_obj_shift(Widget_Data *wd, Eina_Bool left);
99 static void _imageslider_obj_move(Widget_Data *wd, Evas_Coord step);
100 static int _icon_to_image(void *data);
101 static int _check_drag(int state, void *data);
102 static void _check_zoom(void *data);
103 static void _anim(Widget_Data *wd);
104 static int _timer_cb(void *data);
105 static void ev_imageslider_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
106 static void ev_imageslider_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
107 static void ev_imageslider_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
108
109 static void _del_hook(Evas_Object * obj)
110 {
111         int i;
112         Widget_Data * wd;
113         wd = elm_widget_data_get(obj);
114
115         if (!wd) return;
116
117         for (i = 0; i < BLOCK_MAX; i++) {
118                 evas_object_del(wd->ly[i]);
119         }
120
121         if (wd->its) {
122                 eina_list_free(wd->its);
123                 wd->its = NULL;
124         }
125
126         if (wd->queue_idler) {
127                 ecore_idler_del(wd->queue_idler);
128                 wd->queue_idler = NULL;         
129         }
130
131         if (wd->anim_timer) {
132                 ecore_timer_del(wd->anim_timer);
133                 wd->anim_timer = NULL;
134         }
135
136         if (wd) free(wd);
137         
138 }
139
140 static void _theme_hook(Evas_Object * obj)
141 {
142         int i;
143         Widget_Data *wd;
144         wd = elm_widget_data_get(obj);
145
146         if (!wd || !wd->ly ) {
147                 return;
148         }
149
150         for (i=0; i < BLOCK_MAX; i++) {
151                 wd->ly[i] = elm_layout_add(obj);
152                 _elm_theme_object_set(obj, wd->ly[i], "imageslider", "base", "default");
153                 elm_widget_resize_object_set(obj, wd->ly[i]);
154                 evas_object_show(wd->ly[i]);                    
155         }
156
157         _sizing_eval(obj);      
158 }
159
160
161 static void _sizing_eval(Evas_Object * obj)
162 {
163         Evas *e;
164         Widget_Data *wd = elm_widget_data_get(obj);
165
166         if (!wd) {
167                 return;
168         }
169
170         e = evas_object_evas_get(wd->obj);
171
172         _imageslider_move(obj, e, obj, NULL);
173         _imageslider_resize(obj, e, obj, NULL);
174
175 }
176
177 static void _imageslider_move(void * data, Evas * e, Evas_Object * obj, void * event_info)
178 {
179         Widget_Data *wd;
180         Evas_Coord x, y;
181
182         if (!data) {
183                 return;
184         }
185         
186         wd = elm_widget_data_get((Evas_Object *) data);
187         if (!wd) {
188                 return;
189         }
190
191         evas_object_geometry_get(obj, &x, &y, NULL, NULL);
192         wd->x = x;
193         wd->y = y;
194         evas_object_move(wd->clip, x, y);
195         
196         _imageslider_update_pos(wd, wd->x, wd->y, wd->w);
197         
198 }
199
200 static void _imageslider_resize(void * data, Evas * e, Evas_Object * obj, void * event_info)
201 {
202         int i;
203         Widget_Data *wd;
204         Evas_Coord w, h;
205
206         if (!data) {
207                 return;
208         }
209                 
210         wd = elm_widget_data_get((Evas_Object *) data);
211         if (!wd || !wd->ly) {
212                 return;         
213         }
214
215         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
216         fprintf( stderr, "%d %d -resize\n" , w, h );
217         wd->w = w;
218         wd->h = h;
219
220         for (i = 0; i < BLOCK_MAX; i++) {
221                 evas_object_resize(wd->ly[i], w, h);
222         }
223
224         evas_object_resize(wd->clip, w, h);
225
226         _imageslider_update_pos(wd, wd->x, wd->y, wd->w);
227         
228 }
229
230
231 //static void _imageslider_show(Evas_Object * obj)
232 static void _imageslider_show(void *data, Evas *e, Evas_Object * obj, void *event_info)
233 {
234         Widget_Data *wd;
235
236         if (!data) {
237                 return;
238         }
239         
240         wd = elm_widget_data_get((Evas_Object *) data);
241         if (!wd) {
242                 return;
243         }
244         
245         evas_object_show(wd->clip);
246 }
247
248 //static void _imageslider_hide(Evas_Object *obj)
249 static void _imageslider_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
250 {
251         Widget_Data *wd;
252
253         if (!data) {
254                 return;
255         }
256         
257         wd = elm_widget_data_get((Evas_Object *) data);
258         if (!wd) {
259                 return;
260         }
261         evas_object_hide(wd->clip);
262 }
263
264 static void _imageslider_del_all(Widget_Data * wd)
265 {
266         int i;
267         
268         if (!wd) {
269                 return;
270         }
271
272         for (i = 0; i < BLOCK_MAX; i++) {
273                 evas_object_del(wd->ly[i]);
274         }
275 }
276
277 static void _imageslider_update_pos(Widget_Data * wd, Evas_Coord x, Evas_Coord y, Evas_Coord w)
278 {
279         evas_object_move(wd->ly[BLOCK_LEFT], x - (w + INTERVAL_WIDTH), y);
280         evas_object_move(wd->ly[BLOCK_CENTER], x, y);
281         evas_object_move(wd->ly[BLOCK_RIGHT], x + (w + INTERVAL_WIDTH), y);
282         evas_render_idle_flush(evas_object_evas_get(wd->obj));
283 }
284
285 static void _imageslider_update_center_pos(Widget_Data * wd, Evas_Coord x, Evas_Coord my, Evas_Coord y, Evas_Coord w)
286 {
287         Evas_Object *eo;
288         Evas_Coord ix, iy, iw, ih;
289
290         eo = edje_object_part_swallow_get(elm_layout_edje_get(wd->ly[BLOCK_CENTER]), "swl.photo");
291         evas_object_geometry_get(eo, &ix, &iy, &iw, &ih);
292
293         if ((ix > 0) || (ix + iw < wd->w)) {
294                 edje_object_signal_emit(elm_layout_edje_get(wd->ly[BLOCK_CENTER]), "block.on", "block");
295 //              edje_freeze();
296 //              evas_event_feed_mouse_cancel(evas_object_evas_get(wd->obj), NULL, NULL);
297 //              evas_event_feed_mouse_down(evas_object_evas_get(wd->obj), 1, EVAS_BUTTON_NONE, NULL, NULL);             
298
299                 _imageslider_update_pos(wd, x, y, w);
300                 wd->on_zoom = EINA_FALSE;
301         }
302 }
303
304 static Evas_Object *_imageslider_add_obj(Widget_Data *wd)
305 {
306         Evas_Object *eo;
307         eo = elm_layout_add(wd->obj);
308         elm_layout_theme_set(eo, "imageslider", "base", "default");
309         elm_widget_resize_object_set(wd->obj, eo);
310 //      evas_object_smart_member_add(eo, wd->obj);
311         evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_DOWN, ev_imageslider_down_cb, wd);
312         evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_UP, ev_imageslider_up_cb, wd);
313         evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_MOVE, ev_imageslider_move_cb, wd);
314         evas_object_resize(eo, wd->w, wd->h);
315         evas_object_move(eo, wd->w + INTERVAL_WIDTH, wd->y);
316         evas_object_clip_set(eo, wd->clip);
317         evas_object_show(eo);
318
319         return eo;
320 }
321
322 static void _imageslider_obj_shift(Widget_Data *wd, Eina_Bool left)
323 {
324         if (!left) {
325                 if (wd->ly[BLOCK_LEFT]) {
326                         evas_object_del(wd->ly[BLOCK_LEFT]);
327                         wd->ly[BLOCK_LEFT] = NULL;
328                 }
329
330                 wd->ly[BLOCK_LEFT] = wd->ly[BLOCK_CENTER];
331                 wd->ly[BLOCK_CENTER]= wd->ly[BLOCK_RIGHT];
332                 wd->ly[BLOCK_RIGHT] = _imageslider_add_obj(wd);
333         } else {
334                 if (wd->ly[BLOCK_RIGHT]) {
335                         evas_object_del(wd->ly[BLOCK_RIGHT]);
336                         wd->ly[BLOCK_RIGHT] = NULL;
337                 }
338
339                 wd->ly[BLOCK_RIGHT]= wd->ly[BLOCK_CENTER];
340                 wd->ly[BLOCK_CENTER]= wd->ly[BLOCK_LEFT];
341                 wd->ly[BLOCK_LEFT]= _imageslider_add_obj(wd);
342         }
343 }
344
345
346 static void _imageslider_obj_move(Widget_Data * wd, Evas_Coord step)
347 {
348         if (step > 0) {
349                 wd->cur = eina_list_next(wd->cur);
350                 if (wd->cur == NULL) {
351                         wd->cur = eina_list_last(wd->its);
352                         wd->step = ANI_STEP;
353                 } else {
354                         wd->step = -ANI_STEP;
355                         wd->move_x += wd->w;
356                         _imageslider_obj_shift(wd, 0);
357                 }
358                 wd->moving = 1;         
359         } else if (step < 0) {
360                 wd->cur = eina_list_prev(wd->cur);
361                 if (wd->cur == NULL) {
362                         wd->cur = wd->its;
363                         wd->step = -ANI_STEP;
364                 } else {
365                         wd->step = ANI_STEP;
366                         wd->move_x -= wd->w;
367                         _imageslider_obj_shift(wd, 1);
368                 }
369                 wd->moving = 1;
370         } else {
371                 if (wd->move_x < 0) wd->step = ANI_STEP;
372                 else wd->step = -ANI_STEP;
373                 wd->moving = 0;
374         }
375
376         _imageslider_update(wd);
377 }
378
379 static void ev_imageslider_down_cb(void * data, Evas * e, Evas_Object * obj, void * event_info)
380 {
381         Widget_Data *wd = data;
382         Evas_Event_Mouse_Down *ev = event_info;
383         Evas_Coord ix, iy, iw, ih;
384         Evas_Object *eo = NULL;
385
386         if (wd->ani_lock) return;
387
388         wd->down_pos = ev->canvas;
389         wd->timestamp = ev->timestamp;
390         wd->move_cnt = MOVE_STEP;
391
392         wd->dx = ev->canvas.x;
393         wd->dy = ev->canvas.y;
394         wd->mx = ev->canvas.x;
395         wd->my = ev->canvas.y;
396
397         wd->dratio = 1;
398         wd->ratio = 1;
399
400         eo = edje_object_part_swallow_get(elm_layout_edje_get(obj), "swl.photo");
401         if (eo) evas_object_geometry_get(eo, &ix, &iy, &iw, &ih);
402
403         if (iw != wd->w) {
404                 wd->on_zoom = EINA_TRUE;
405                 edje_object_signal_emit(elm_layout_edje_get(obj), "block.off", "block");
406 //              edje_thaw();            
407         }
408
409         fprintf( stderr, "down!\n" );
410
411 }
412
413 static void ev_imageslider_up_cb(void * data, Evas * e, Evas_Object * obj, void * event_info)
414 {
415         Widget_Data *wd = data;
416         Evas_Event_Mouse_Up *ev = event_info;
417         Evas_Coord step;
418         int interval;
419
420         if (wd->ani_lock) return;
421
422         if (wd->on_zoom) {              
423         } else {
424                 step = wd->down_pos.x - ev->canvas.x;
425                 interval = ev->timestamp - wd->timestamp;
426                 if (step == 0 || interval == 0) return;
427
428                 if (interval < FLICK_TIME_MAX) {
429                         if (step < FLICK_WIDTH_MIN && step > FLICK_WIDTH_MIN) _imageslider_obj_move(wd, 0);
430                         else _imageslider_obj_move(wd, step);
431                 } else {
432                         step = (wd->x - wd->move_x) << 1;
433                         if (step <= wd->w && step >= -(wd->w)) _imageslider_obj_move(wd, 0);
434                         else _imageslider_obj_move(wd, step);
435                 }
436         }
437
438 }
439
440 static void ev_imageslider_move_cb(void * data, Evas * e, Evas_Object * obj, void * event_info)
441 {
442         int idx;
443         Evas_Object *eo;
444         Evas_Coord step;
445         Widget_Data *wd = data;
446         Evas_Event_Mouse_Move *ev = event_info;
447         Elm_Imageslider_Item *it;
448
449         if (wd->ani_lock) return;
450
451         if (wd->move_cnt == MOVE_STEP) {
452                 if (wd->on_hold == EINA_FALSE) {
453                         wd->move_cnt = 0;
454
455                         if (ev->buttons) {
456                                 step = ev->cur.canvas.x - wd->down_pos.x;
457                                 if (step > 0) idx = BLOCK_LEFT;
458                                 else idx = BLOCK_RIGHT;
459
460                                 wd->move_x = wd->x + ((ev->cur.canvas.x - wd->down_pos.x));
461                                 wd->move_y = wd->y + ((ev->cur.canvas.y - wd->down_pos.y));
462
463                                 if (wd->on_zoom) {
464                                         _imageslider_update_center_pos(wd, wd->move_x, wd->move_y, wd->y, wd->w);
465                                 } else {
466                                         _imageslider_update_pos(wd, wd->move_x, wd->y, wd->w);
467                                 }
468                         }
469                 } else {
470                         wd->mx = ev->cur.canvas.x;
471                         wd->my = ev->cur.canvas.y;
472
473                         wd->ratio = sqrt((wd->mx -wd->mmx)*(wd->mx -wd->mmx) + (wd->my - wd->mmy)*(wd->my - wd->mmy));
474
475                         eo = edje_object_part_swallow_get(elm_layout_edje_get(obj), "swl.photo");
476                         if (eo) {
477                                 it = eina_list_data_get(wd->cur);
478                                 if (((it->w * wd->ratio/wd->dratio)/it->ow) < MAX_ZOOM_SIZE ) {
479                                         edje_object_part_unswallow(elm_layout_edje_get(obj), eo);
480                                         evas_object_resize(eo, it->w * wd->ratio/wd->dratio, it->h * wd->ratio/wd->dratio);
481                                         evas_object_size_hint_min_set(eo, it->w * wd->ratio/wd->dratio, it->h * wd->ratio/wd->dratio);
482                                         edje_object_part_swallow(elm_layout_edje_get(obj), "swl.photo", eo);
483                                 }
484                         }                       
485                 }
486         }
487
488         wd->move_cnt++;
489
490 }
491
492
493 #if 0 // REMOVED about Multi-touch.
494 static void ev_imageslider_multi_down_cb(void * data, Evas * e, Evas_Object * obj, void * event_info)
495 {
496         Evas_Event_Multi_Down *ev = event_info;
497         Widget_Data *wd = data;
498
499         if (ev->device == MULTITOUCHDEVICE) return;
500
501         wd->on_hold = EINA_TRUE;
502         wd->mdx = ev->canvas.x;
503         wd->mdy = ev->canvas.y;
504         wd->mmx = ev->canvas.x;
505         wd->mmy = ev->canvas.y;
506
507         wd->dratio = sqrt((wd->mx - wd->mmx)*(wd->mx - wd->mmx) + (wd->my - wd->mmy)*(wd->my - wd->mmy));
508         wd->ratio = sqrt((wd->mx - wd->mmx)*(wd->mx - wd->mmx)+ (wd->my - wd->mmy)*(wd->my - wd->mmy));
509
510         if (wd->on_zoom){
511                 wd->on_zoom = EINA_FALSE;
512                 edje_object_signal_emit(elm_layout_edje_get(obj), "block.on", "block");
513 //              edje_freeze();
514         }
515 }
516
517 static void ev_imageslider_multi_up_cb(void * data, Evas * e, Evas_Object * obj, void * event_info)
518 {
519         Evas_Event_Multi_Up *ev = event_info;
520         Widget_Data *wd = data;
521         Elm_Imageslider_Item *it;
522
523         if (ev->device == MULTITOUCHDEVICE) return;
524
525         it = eina_list_data_get(wd->cur);
526         it->w = (int)it->w * wd->ratio/wd->dratio;
527         it->h = (int)it->h * wd->ratio/wd->dratio;
528
529         if (it->w != it->ow) {
530                 wd->on_zoom = EINA_TRUE;
531                 edje_object_signal_emit(elm_layout_edje_get(obj), "block.off", "block");
532 //              edje_thaw();
533         } else {
534                 wd->on_zoom = EINA_FALSE;
535         }
536
537         wd->on_hold = EINA_FALSE;
538         wd->mdx = 0;
539         wd->mdy = 0;
540         wd->mmx = 0;
541         wd->mmy = 0;
542         wd->ratio = 0;
543         wd->dratio = 0;
544         
545 }
546
547 static void ev_imageslider_multi_move_cb(void * data, Evas * e, Evas_Object * obj, void * event_info)
548 {
549         Evas_Event_Multi_Move *ev = event_info;
550         Widget_Data *wd = data;
551         Evas_Object *eo = NULL;
552         Elm_Imageslider_Item *it;
553
554         if (ev->device == MULTITOUCHDEVICE) return;
555
556         if ((wd->mdx == 0) && (wd->mdy == 0) && (wd->mmx == 0) && (wd->mmy == 0)) {
557                 wd->mdx = ev->cur.canvas.x;
558                 wd->mdy = ev->cur.canvas.y;
559                 wd->mmx = ev->cur.canvas.x;
560                 wd->mmy = ev->cur.canvas.y;
561
562                 wd->dratio = sqrt((wd->dx - wd->mdx)*(wd->dx - wd->mdx) + (wd->dy - wd->mdy)*(wd->dy - wd->mdy));
563         }
564
565         wd->mmx = ev->cur.canvas.x;
566         wd->mmy = ev->cur.canvas.y;
567         wd->ratio = sqrt((wd->mx - wd->mmx)*(wd->mx - wd->mmx) + (wd->my - wd->mmy)*(wd->my - wd->mmy));
568
569         eo = edje_object_part_swallow_get(elm_layout_edje_get(obj), "swl.photo");
570
571         if (eo) {
572                 it = eina_list_data_get(wd->cur);
573                 if (((it->w * wd->ratio/wd->dratio)/it->ow) < MAX_ZOOM_SIZE) {
574                         edje_object_part_unswallow(elm_layout_edje_get(obj), eo);
575                         evas_object_resize(eo, it->w * wd->ratio/wd->dratio, it->h * wd->ratio/wd->dratio);
576                         evas_object_size_hint_min_set(eo, it->w * wd->ratio/wd->dratio, it->h * wd->ratio/wd->dratio);
577                         edje_object_part_swallow(elm_layout_edje_get(obj), "swl.photo", eo);
578                 }
579         }       
580 }
581
582 #endif // about Multi-touch.
583
584 static inline double time_get(Evas_Coord x, Evas_Coord w)
585 {
586         double time;
587         time = (-sin(x / w) + 1) / 500;
588
589         if (time == 0) time = ANI_TIME;
590         
591         return time;
592 }
593
594 static int _icon_to_image(void *data)
595 {
596         Widget_Data *wd = data;
597         wd->moving = 0;
598         _imageslider_update(wd);
599
600         return 0;
601 }
602
603 static int _check_drag(int state, void *data)
604 {
605         Widget_Data *wd = data;
606         Elm_Imageslider_Item *it;
607         Evas_Coord ix, iy, iw, ih;
608         double dx, dy = 0;
609         Eina_List *l[BLOCK_MAX];
610         Evas_Object *eo = NULL;
611         l[BLOCK_LEFT] = eina_list_prev(wd->cur);
612         l[BLOCK_CENTER] = wd->cur;
613         l[BLOCK_RIGHT] = eina_list_next(wd->cur);
614
615         it = eina_list_data_get(l[state]);
616
617         eo = edje_object_part_swallow_get(elm_layout_edje_get(wd->ly[state]), "swl.photo");
618         if (eo) evas_object_geometry_get(eo, &ix, &iy, &iw, &ih);
619         evas_object_geometry_get(eo, &ix, &iy, &iw, &ih);
620         edje_object_part_drag_value_get(elm_layout_edje_get(wd->ly[state]), "swl.photo", &dx, &dy);
621
622         if ((iw != wd->w) || ((dx != 0 ) || (dy != 0 ))) {
623                 if (wd->ly[state]) {
624                         evas_object_del(wd->ly[state]);
625                         wd->ly[state] = NULL;
626                 }
627                 wd->ly[state] = _imageslider_add_obj(wd);
628         } else {
629                 return 1;
630         }
631
632         return 0;
633 }
634
635
636 static void _check_zoom(void *data)
637 {
638         Widget_Data *wd = data;
639         Elm_Imageslider_Item *it;
640         Evas_Coord ix, iy, iw, ih;
641         double dx, dy = 0;
642         Evas_Object *eo = NULL;
643
644         it = eina_list_data_get(wd->cur);
645
646         eo = edje_object_part_swallow_get(elm_layout_edje_get(wd->ly[BLOCK_CENTER]), "swl.photo");
647         if (eo) evas_object_geometry_get(eo, &ix, &iy, &iw, &ih);
648         evas_object_geometry_get(eo, &ix, &iy, &iw, &ih);
649         edje_object_part_drag_value_get(elm_layout_edje_get(wd->ly[BLOCK_CENTER]), "swl.photo", &dx, &dy);
650
651         if ((iw != wd->w) || ((dx != 0) || (dy != 0))) {
652                 wd->on_zoom = EINA_TRUE;
653                 edje_object_signal_emit(elm_layout_edje_get(wd->ly[BLOCK_CENTER]), "block.off", "block");
654 //              edje_thaw();
655         } else {
656                 wd->on_zoom = EINA_FALSE;
657                 edje_object_signal_emit(elm_layout_edje_get(wd->ly[BLOCK_CENTER]), "block.on", "block");
658 //              edje_freeze();
659         }
660 }
661
662
663 static int _timer_cb(void *data)
664 {
665         Widget_Data *wd;
666         Elm_Imageslider_Item *it;
667         struct timeval tv;
668         int t;
669         int ret;
670         wd = data;
671         if (wd->ani_lock == 0 ) return 0;
672
673         gettimeofday(&tv, NULL);
674
675         t = (tv.tv_sec - wd->tv.tv_sec) * 1000 + (tv.tv_usec - wd->tv.tv_usec) / 1000;
676         gettimeofday(&wd->tv, NULL);
677
678         t = t / ANI_TIME_MSEC;
679         if (t <= STEP_WEIGHT_MIN) t = STEP_WEIGHT_DEF;
680         else if (t >  STEP_WEIGHT_MAX) t = STEP_WEIGHT_MAX;
681
682         wd->move_x += (wd->step) * t;
683
684         if (wd->step < 0 && wd->move_x < wd->x) wd->move_x = wd->x;
685         else if (wd->step > 0 && wd->move_x > wd->x) wd->move_x = wd->x;
686
687         _imageslider_update_pos(wd, wd->move_x, wd->y, wd->w);
688
689         if (wd->move_x == wd->x) {
690                 wd->ani_lock = 0;
691                 if (wd->cur) {
692                         it = eina_list_data_get(wd->cur);
693                         if (it->func) it->func(it->data, wd->obj, it);
694                 }
695                 if (wd->cur) {
696                         it = eina_list_data_get(wd->cur);
697                         evas_object_smart_callback_call(wd->obj, "changed", it);
698                 }
699
700                 ret = _check_drag(BLOCK_LEFT, wd);
701                 ret = _check_drag(BLOCK_RIGHT, wd);
702                 _check_zoom(wd);
703
704
705                 if (wd->queue_idler) {
706                         ecore_idler_del(wd->queue_idler);
707                         wd->queue_idler = NULL;
708                 }
709
710                 if (!wd->queue_idler) wd->queue_idler = ecore_idler_add(_icon_to_image, wd);
711
712                 return 0;
713         }
714
715         return 1;       
716 }
717
718 static void _anim(Widget_Data *wd)
719 {
720         Evas_Coord w;
721
722         if (wd->x == wd->move_x) {
723                 _imageslider_update_pos(wd, wd->move_x, wd->y, wd->w);
724                 return;
725         }
726
727         wd->ani_lock = 1;
728
729         w = wd->move_x;
730         gettimeofday(&wd->tv, NULL);
731
732         if (wd->anim_timer) {
733                 ecore_timer_del(wd->anim_timer);
734                 wd->anim_timer = NULL;
735         }
736         
737         if (!wd->anim_timer) wd->anim_timer = ecore_timer_add(ANI_TIME, _timer_cb, wd);
738         
739 }
740
741 static void _imageslider_update(Widget_Data *wd)
742 {
743         int i;
744         Eina_List *l[BLOCK_MAX];
745         Elm_Imageslider_Item *it;
746         Evas_Object *eo;
747
748         if (!wd) {
749                 return;
750         }
751
752         if (!wd->cur) {
753                 _imageslider_del_all(wd);
754                 return;
755         }
756
757         l[BLOCK_LEFT] = eina_list_prev(wd->cur);
758         l[BLOCK_CENTER] = wd->cur;
759         l[BLOCK_RIGHT] = eina_list_next(wd->cur);
760
761         for (i = 0; i < BLOCK_MAX; i++) {
762                 eo = edje_object_part_swallow_get(elm_layout_edje_get(wd->ly[i]), "swl.photo");
763                 if (!l[i]) {
764                         elm_layout_content_set(wd->ly[i], "swl.photo", NULL);
765                         evas_object_del(eo);
766                 } else {
767                         it = eina_list_data_get(l[i]);
768                         if (!it) return;
769
770                         if (!eo) {
771                                 eo = elm_image_add(wd->obj);
772                                 elm_layout_content_set(wd->ly[i], "swl.photo", eo);
773                                 elm_image_prescale_set(eo, wd->w);
774                                 elm_image_file_set(eo, it->photo_file, NULL);
775                                 elm_image_object_size_get(eo, &it->w, &it->h);
776                                 evas_object_geometry_get(eo, &it->ox, &it->oy, &it->ow, &it->oh);
777                                 it->ow = it->w;
778                                 it->oh = it->h;
779                         }
780
781                         if (wd->moving != it->moving) {
782                                 it->moving = wd->moving;
783                                 if (wd->moving) {
784                                         elm_image_prescale_set(eo, MOVING_IMAGE_SIZE);
785                                 } else {
786                                         elm_image_prescale_set(eo, it->w > it->h ? it->w : it->h);
787                                 }
788                         }
789                 }
790         }
791
792         _anim(wd);
793
794 }
795
796
797 /** 
798 * Add an Image Slider widget 
799
800 * @param        parent  The parent object 
801 * @return       The new Image slider object or NULL if it cannot be created 
802
803 * @ingroup Imageslider 
804 */
805 EAPI Evas_Object *
806 elm_imageslider_add(Evas_Object * parent)
807 {
808         int i;
809         Evas_Object *obj = NULL;
810         Widget_Data *wd = NULL;
811         Evas *e;
812
813         if (!parent) {
814                 return NULL;
815         }
816
817         wd = ELM_NEW(Widget_Data);
818         e = evas_object_evas_get(parent);
819         if (e == NULL ) {
820                 return NULL;
821         }
822         
823         obj = elm_widget_add(e);
824         ELM_SET_WIDTYPE(widtype, "imageslider");
825         elm_widget_type_set(obj, "imageslider");
826         elm_widget_sub_object_add(parent, obj);
827         elm_widget_data_set(obj, wd);
828         //wd->parent = parent;
829         elm_widget_del_hook_set(obj, _del_hook);
830         //elm_widget_theme_hook_set(obj, _theme_hook);
831
832         wd->clip = evas_object_rectangle_add(e);
833         
834         for (i=0; i < BLOCK_MAX; i++) {
835                 wd->ly[i] = elm_layout_add(obj);
836                 elm_layout_theme_set(wd->ly[i], "imageslider", "base", "default");
837                 elm_widget_resize_object_set(obj, wd->ly[i]);
838                 evas_object_smart_member_add(wd->ly[i], obj);
839                 evas_object_event_callback_add(wd->ly[i], EVAS_CALLBACK_MOUSE_DOWN, ev_imageslider_down_cb, wd);
840                 evas_object_event_callback_add(wd->ly[i], EVAS_CALLBACK_MOUSE_UP, ev_imageslider_up_cb, wd);
841                 evas_object_event_callback_add(wd->ly[i], EVAS_CALLBACK_MOUSE_MOVE, ev_imageslider_move_cb, wd);
842                 evas_object_clip_set(wd->ly[i], wd->clip);
843                 evas_object_show(wd->ly[i]);                    
844         }
845
846         wd->obj = obj;
847
848         evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _imageslider_resize, obj);
849         evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _imageslider_move, obj);
850         evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _imageslider_show, obj);
851         evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _imageslider_hide, obj);
852         
853         _sizing_eval(obj);
854
855    return obj;  
856 }
857
858
859 /** 
860 * Append an Image Slider item 
861
862 * @param        obj          The Image Slider object 
863 * @param        photo_file   photo file path 
864 * @param        func         callback function 
865 * @param        data         callback data 
866 * @return       The Image Slider item handle or NULL 
867
868 * @ingroup Imageslider 
869 */
870 EAPI Elm_Imageslider_Item *
871 elm_imageslider_item_append(Evas_Object * obj, const char * photo_file, Elm_Imageslider_Cb func, void * data)
872 {
873         ELM_CHECK_WIDTYPE(obj, widtype) NULL;
874         Widget_Data *wd;
875         Elm_Imageslider_Item *it;
876
877         if (!obj || !(wd = elm_widget_data_get(obj))) {
878                 return NULL;
879         }
880
881         it = (Elm_Imageslider_Item *)calloc(1, sizeof(Elm_Imageslider_Item));
882         if (!it) return NULL;
883         it->photo_file = eina_stringshare_add(photo_file);
884         it->func = func;
885         it->data = data;
886         it->obj = obj;
887         wd->its = eina_list_append(wd->its, it);
888
889         if (!wd->cur) wd->cur = wd->its;
890
891         _imageslider_update(wd);
892
893         return it; 
894 }
895
896
897 /** 
898 * Prepend Image Slider item 
899
900 * @param        obj          The Image Slider object 
901 * @param        photo_file   photo file path 
902 * @param        func         callback function 
903 * @param        data         callback data 
904 * @return       The imageslider item handle or NULL 
905
906 * @ingroup Imageslider 
907 */
908 EAPI Elm_Imageslider_Item *
909 elm_imageslider_item_prepend(Evas_Object * obj, const char * photo_file, Elm_Imageslider_Cb func, void * data)
910 {
911         ELM_CHECK_WIDTYPE(obj, widtype) NULL;
912         Widget_Data *wd;
913         Elm_Imageslider_Item *it;
914
915         if (!obj || !(wd = elm_widget_data_get(obj))) {
916                 return NULL;
917         }
918
919         it = (Elm_Imageslider_Item *)calloc(1, sizeof(Elm_Imageslider_Item));
920         it->photo_file = eina_stringshare_add(photo_file);
921         it->func = func;
922         it->data = data;
923         it->obj = obj;
924         wd->its = eina_list_prepend(wd->its, it );
925
926         if (!wd->cur) wd->cur = wd->its;
927
928         _imageslider_update(wd);
929
930         return it;
931 }
932
933
934
935 /**
936 * Delete the selected Image Slider item
937 *
938 * @param it             The selected Image Slider item handle
939 *
940 * @ingroup Imageslider
941 */
942 EAPI void
943 elm_imageslider_item_del(Elm_Imageslider_Item * it)
944 {
945         Widget_Data *wd;
946         Elm_Imageslider_Item *_it;
947         Eina_List *l;
948
949         if (!it || !(wd = elm_widget_data_get(it->obj))) {
950                 return ;
951         }
952
953         EINA_LIST_FOREACH(wd->its, l, _it) {
954                 if (_it == it ) {
955                         if (l == wd->cur) wd->cur = eina_list_prev(wd->cur);
956                         wd->its = eina_list_remove(wd->its, it);
957                         if (!wd->cur) wd->cur = wd->its;
958                         break;
959                 }
960         }
961
962         _imageslider_update(wd);
963         
964 }
965
966
967 /**
968 * Get the selected Image Slider item
969 *
970 * @param obj            The Image Slider object
971 * @return The selected Image Slider item or NULL
972 *
973 * @ingroup Imageslider
974 */
975 EAPI Elm_Imageslider_Item *
976 elm_imageslider_selected_item_get(Evas_Object * obj)
977 {
978         ELM_CHECK_WIDTYPE(obj, widtype) NULL;
979         Widget_Data *wd;
980
981         if (!obj || (!(wd = elm_widget_data_get(obj)))) {
982                 return NULL;
983         }
984
985         if (!wd->cur) return NULL;
986
987         return eina_list_data_get(wd->cur);
988 }
989
990 /**
991 * Get whether an Image Slider item is selected or not
992 *
993 * @param it              the selected Image Slider item
994 * @return EINA_TRUE or EINA_FALSE
995 *
996 * @ingroup Imageslider
997 */
998 EAPI Eina_Bool
999 elm_imageslider_item_selected_get(Elm_Imageslider_Item * it)
1000 {
1001         Widget_Data *wd;
1002         
1003         if (!it || !it->obj || (!(wd = elm_widget_data_get(it->obj)))) {
1004                 return EINA_FALSE;
1005         }
1006
1007         if (!wd->cur) return EINA_FALSE;
1008
1009         if (eina_list_data_get(wd->cur) == it ) return EINA_TRUE;
1010         else return EINA_FALSE;
1011         
1012 }
1013
1014 /**
1015 * Set the selected Image Slider item
1016 *
1017 * @param it             The Imaga Slider item
1018 *
1019 * @ingroup Imageslider
1020 */
1021 EAPI void
1022 elm_imageslider_item_selected_set(Elm_Imageslider_Item * it)
1023 {
1024         int i;
1025         Widget_Data *wd;
1026         Elm_Imageslider_Item *_it;
1027         Eina_List *l;
1028         Evas_Object *eo;
1029
1030         if (!it || !it->obj || (!(wd = elm_widget_data_get(it->obj)))) {
1031                 return ;
1032         }
1033
1034         EINA_LIST_FOREACH(wd->its, l, _it) {
1035                 if (_it == it ) {
1036                         wd->cur = l;
1037                 }
1038         }
1039
1040         for (i = 0; i < BLOCK_MAX; i++) {
1041                 eo = edje_object_part_swallow_get(elm_layout_edje_get(wd->ly[i]), "swl.photo");
1042                 if (eo) {
1043                         elm_layout_content_set(wd->ly[i], "swl.photo", NULL);
1044                         evas_object_del(eo);
1045                 }
1046         }
1047
1048         _imageslider_update(wd);
1049         
1050 }
1051
1052
1053 /**
1054 * Get the photo file path of given Image Slider item
1055 *
1056 * @param it             The Image Slider item
1057 * @return The photo file path or NULL;
1058 *
1059 * @ingroup Imageslider
1060 */
1061 EAPI const char *
1062 elm_imageslider_item_photo_file_get(Elm_Imageslider_Item * it)
1063 {
1064         if (!it) {
1065                 return NULL;
1066         }
1067
1068         return it->photo_file;
1069 }
1070
1071
1072 /**
1073 * Get the previous Image Slider item
1074 *
1075 * @param it             The Image Slider item
1076 * @return The previous Image Slider item or NULL
1077 *
1078 * @ingroup Imageslider
1079 */
1080 EAPI Elm_Imageslider_Item *
1081 elm_imageslider_item_prev(Elm_Imageslider_Item * it)
1082 {
1083         Widget_Data *wd;
1084         Elm_Imageslider_Item *_it;
1085         Eina_List *l;
1086
1087         if (!it || (!(wd = elm_widget_data_get(it->obj)))) {
1088                 return NULL;
1089         }
1090
1091         EINA_LIST_FOREACH(wd->its, l, _it) {
1092                 if (_it == it) {
1093                         l = eina_list_prev(l);
1094                         if (!l) break;
1095                         return eina_list_data_get(l);
1096                 }
1097         }
1098
1099         return NULL;    
1100 }
1101
1102
1103 /**
1104 * Get the next Image Slider item
1105 *
1106 * @param it             The Image Slider item
1107 * @return The next Image Slider item or NULL
1108 *
1109 * @ingroup Imageslider
1110 */
1111 EAPI Elm_Imageslider_Item *
1112 elm_imageslider_item_next(Elm_Imageslider_Item * it)
1113 {
1114         Widget_Data *wd;
1115         Elm_Imageslider_Item *_it;
1116         Eina_List *l;
1117
1118         if (!it || (!(wd = elm_widget_data_get(it->obj)))) {
1119                 return NULL;
1120         }
1121
1122         EINA_LIST_FOREACH(wd->its, l, _it) {
1123                 if (_it == it) {
1124                         l = eina_list_next(l);
1125                         if (!l) break;
1126                         return eina_list_data_get(l);
1127                 }
1128         }
1129
1130         return NULL;
1131 }
1132
1133
1134 /**
1135 * Move to the previous Image Slider item
1136 *
1137 * @param obj    The Image Slider object
1138 *
1139 * @ingroup Imageslider
1140 */
1141 EAPI void 
1142 elm_imageslider_prev(Evas_Object * obj)
1143 {
1144         ELM_CHECK_WIDTYPE(obj, widtype);
1145         Widget_Data *wd;
1146         
1147         if (!obj || (!(wd = elm_widget_data_get(obj)))) {
1148                 return;
1149         }
1150
1151         if (wd->ani_lock) return;
1152
1153         _imageslider_obj_move(wd, -1);
1154 }
1155
1156
1157 /**
1158 * Move to the next Image Slider item
1159 *
1160 * @param obj The Image Slider object
1161 *
1162 * @ingroup Imageslider
1163 */
1164 EAPI void
1165 elm_imageslider_next(Evas_Object * obj)
1166 {
1167         ELM_CHECK_WIDTYPE(obj, widtype);
1168         Widget_Data *wd;
1169         
1170         if (!obj || (!(wd = elm_widget_data_get(obj)))) {
1171                 return;
1172         }
1173
1174         if (wd->ani_lock) return;
1175
1176         _imageslider_obj_move(wd, 1);
1177         
1178 }
1179
1180
1181
1182
1183