elementary/transit - more simple code.
[framework/uifw/elementary.git] / src / lib / elm_transit.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define ELM_TRANSIT_CHECK_OR_RETURN(transit, ...) \
5    do { \
6       if (!transit) { \
7          CRITICAL("Elm_Transit " # transit " is NULL!"); \
8          return __VA_ARGS__; \
9       } \
10       if (!EINA_MAGIC_CHECK(transit, ELM_TRANSIT_MAGIC)) { \
11          EINA_MAGIC_FAIL(transit, ELM_TRANSIT_MAGIC); \
12          return __VA_ARGS__; \
13       } \
14       if (transit->deleted){ \
15          ERR("Elm_Transit " # transit " has already been deleted!"); \
16          return __VA_ARGS__; \
17       } \
18    } while (0)
19
20
21 #define _TRANSIT_FOCAL 2000
22
23 struct _Elm_Transit
24 {
25 #define ELM_TRANSIT_MAGIC 0xd27f190a
26    EINA_MAGIC;
27
28    Ecore_Animator *animator;
29    Eina_Inlist *effect_list;
30    Eina_List *objs;
31    Elm_Transit *prev_chain_transit;
32    Eina_List *next_chain_transits;
33    Elm_Transit_Tween_Mode tween_mode;
34    struct {
35       Elm_Transit_Del_Cb func;
36       void *arg;
37    } del_data;
38    struct {
39       double delayed;
40       double paused;
41       double duration;
42       double begin;
43       double current;
44    } time;
45    struct {
46       int count;
47       int current;
48       Eina_Bool reverse;
49    } repeat;
50    double progress;
51    unsigned int effects_pending_del;
52    int walking;
53    Eina_Bool auto_reverse : 1;
54    Eina_Bool event_enabled : 1;
55    Eina_Bool deleted : 1;
56    Eina_Bool state_keep : 1;
57    Eina_Bool finished : 1;
58 };
59
60 struct _Elm_Transit_Effect_Module
61 {
62    EINA_INLIST;
63    Elm_Transit_Effect_Transition_Cb transition_cb;
64    Elm_Transit_Effect_End_Cb end_cb;
65    Elm_Transit_Effect *effect;
66    Eina_Bool deleted : 1;
67 };
68
69 struct _Elm_Transit_Obj_State
70 {
71    Evas_Coord x, y, w, h;
72    int r,g,b,a;
73    Evas_Map *map;
74    Eina_Bool map_enabled : 1;
75    Eina_Bool visible : 1;
76 };
77
78 struct _Elm_Transit_Obj_Data
79 {
80    struct _Elm_Transit_Obj_State *state;
81    Eina_Bool freeze_events : 1;
82 };
83
84 typedef struct _Elm_Transit_Effect_Module Elm_Transit_Effect_Module;
85 typedef struct _Elm_Transit_Obj_Data Elm_Transit_Obj_Data;
86 typedef struct _Elm_Transit_Obj_State Elm_Transit_Obj_State;
87
88 static void _transit_obj_data_update(Elm_Transit *transit, Evas_Object *obj);
89 static void _transit_obj_data_recover(Elm_Transit *transit, Evas_Object *obj);
90 static void _transit_obj_states_save(Evas_Object *obj, Elm_Transit_Obj_Data *obj_data);
91 static void _transit_obj_remove_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
92 static void _transit_obj_remove(Elm_Transit *transit, Evas_Object *obj);
93 static void _transit_effect_del(Elm_Transit *transit, Elm_Transit_Effect_Module *effect_module);
94 static void _transit_remove_dead_effects(Elm_Transit *transit);
95 static void _transit_chain_go(Elm_Transit *transit);
96 static void _transit_del(Elm_Transit *transit);
97 static Eina_Bool _transit_animate_op(Elm_Transit *transit, double progress);
98 static Eina_Bool _transit_animate_cb(void *data);
99
100 static char *_transit_key= "_elm_transit_key";
101
102 static void
103 _transit_obj_data_update(Elm_Transit *transit, Evas_Object *obj)
104 {
105    Elm_Transit_Obj_Data *obj_data = evas_object_data_get(obj, _transit_key);
106
107    if (!obj_data)
108      obj_data = ELM_NEW(Elm_Transit_Obj_Data);
109
110    obj_data->freeze_events = evas_object_freeze_events_get(obj);
111
112    if ((!transit->state_keep) && (obj_data->state))
113      {
114         free(obj_data->state);
115         obj_data->state = NULL;
116      }
117    else
118      {
119        _transit_obj_states_save(obj, obj_data);
120      }
121
122    evas_object_data_set(obj, _transit_key, obj_data);
123 }
124
125 static void
126 _transit_obj_states_save(Evas_Object *obj, Elm_Transit_Obj_Data *obj_data)
127 {
128    Elm_Transit_Obj_State *state = obj_data->state;
129
130    if (!state)
131      state = calloc(1, sizeof(Elm_Transit_Obj_State));
132    if (!state) return;
133
134    evas_object_geometry_get(obj, &state->x, &state->y, &state->w, &state->h);
135    evas_object_color_get(obj, &state->r, &state->g, &state->b, &state->a);
136    state->visible = evas_object_visible_get(obj);
137    state->map_enabled = evas_object_map_enable_get(obj);
138    if (evas_object_map_get(obj))
139      state->map = evas_map_dup(evas_object_map_get(obj));
140    obj_data->state = state;
141 }
142
143 static void
144 _remove_obj_from_list(Elm_Transit *transit, Evas_Object *obj)
145 {
146    //Remove duplicated objects
147    //TODO: Need to consider about optimizing here
148    while(1)
149      {
150         if (!eina_list_data_find_list(transit->objs, obj))
151           break;
152         transit->objs = eina_list_remove(transit->objs, obj);
153         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
154                                        _transit_obj_remove_cb,
155                                        transit);
156      }
157 }
158
159 static void
160 _transit_obj_remove_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
161 {
162    Elm_Transit *transit = data;
163    Elm_Transit_Obj_Data *obj_data = evas_object_data_get(obj, _transit_key);
164    if (obj_data)
165      {
166         if (obj_data->state)
167           free(obj_data->state);
168         free(obj_data);
169      }
170    _remove_obj_from_list(transit, obj);
171    if (!transit->objs) elm_transit_del(transit);
172 }
173
174 static void
175 _transit_obj_data_recover(Elm_Transit *transit, Evas_Object *obj)
176 {
177    Elm_Transit_Obj_Data *obj_data;
178    Elm_Transit_Obj_State *state;
179
180    obj_data = evas_object_data_get(obj, _transit_key);
181    if (!obj_data) return;
182    evas_object_data_del(obj, _transit_key);
183    evas_object_freeze_events_set(obj, obj_data->freeze_events);
184    state = obj_data->state;
185    if (state)
186      {
187         //recover the states of the object.
188         if (!transit->state_keep)
189           {
190              evas_object_move(obj, state->x, state->y);
191              evas_object_resize(obj, state->w, state->h);
192              evas_object_color_set(obj, state->r, state->g, state->b, state->a);
193              if (state->visible) evas_object_show(obj);
194              else evas_object_hide(obj);
195              evas_object_map_enable_set(obj, state->map_enabled);
196              evas_object_map_set(obj, state->map);
197           }
198         free(state);
199      }
200    free(obj_data);
201 }
202
203 static void
204 _transit_obj_remove(Elm_Transit *transit, Evas_Object *obj)
205 {
206    _remove_obj_from_list(transit, obj);
207    _transit_obj_data_recover(transit, obj);
208 }
209
210 static void
211 _transit_effect_del(Elm_Transit *transit, Elm_Transit_Effect_Module *effect_module)
212 {
213    if (effect_module->end_cb)
214      effect_module->end_cb(effect_module->effect, transit);
215    free(effect_module);
216 }
217
218 static void
219 _transit_remove_dead_effects(Elm_Transit *transit)
220 {
221    Elm_Transit_Effect_Module *effect_module;
222
223    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
224      {
225         if (effect_module->deleted)
226           {
227              _transit_effect_del(transit, effect_module);
228              transit->effects_pending_del--;
229              if (!transit->effects_pending_del) return;
230           }
231      }
232 }
233
234 static void
235 _transit_chain_go(Elm_Transit *transit)
236 {
237    ELM_TRANSIT_CHECK_OR_RETURN(transit);
238    elm_transit_go(transit);
239    _transit_animate_cb(transit);
240 }
241
242 static void
243 _transit_del(Elm_Transit *transit)
244 {
245    Elm_Transit_Effect_Module *effect_module;
246    Elm_Transit *chain_transit;
247    Eina_List *elist, *elist_next;
248
249    if (transit->animator)
250      ecore_animator_del(transit->animator);
251
252    //remove effects
253    while (transit->effect_list)
254      {
255         effect_module = EINA_INLIST_CONTAINER_GET(transit->effect_list, Elm_Transit_Effect_Module);
256         transit->effect_list = eina_inlist_remove(transit->effect_list, transit->effect_list);
257         _transit_effect_del(transit, effect_module);
258      }
259
260    //remove objects.
261    while (transit->objs)
262      _transit_obj_remove(transit, eina_list_data_get(transit->objs));
263
264    transit->deleted = EINA_TRUE;
265
266    if (transit->del_data.func)
267      transit->del_data.func(transit->del_data.arg, transit);
268
269    //cut off the chain transit relationship
270    EINA_LIST_FOREACH_SAFE(transit->next_chain_transits, elist, elist_next, chain_transit)
271      chain_transit->prev_chain_transit = NULL;
272
273    if (transit->prev_chain_transit)
274      transit->prev_chain_transit->next_chain_transits =
275         eina_list_remove(transit->prev_chain_transit->next_chain_transits, transit);
276
277    // run chain transits
278    if (transit->finished && transit->next_chain_transits)
279      {
280         EINA_LIST_FOREACH_SAFE(transit->next_chain_transits, elist, elist_next, chain_transit)
281           _transit_chain_go(chain_transit);
282
283      }
284
285    eina_list_free(transit->next_chain_transits);
286
287    EINA_MAGIC_SET(transit, EINA_MAGIC_NONE);
288    free(transit);
289 }
290
291 //If the transit is deleted then EINA_FALSE is retruned.
292 static Eina_Bool
293 _transit_animate_op(Elm_Transit *transit, double progress)
294 {
295    Elm_Transit_Effect_Module *effect_module;
296
297    transit->walking++;
298    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
299      {
300         if (transit->deleted) break;
301         if (!effect_module->deleted)
302           effect_module->transition_cb(effect_module->effect, transit, progress);
303      }
304    transit->walking--;
305
306    if (transit->walking) return EINA_TRUE;
307
308    if (transit->deleted)
309      {
310         _transit_del(transit);
311         return EINA_FALSE;
312      }
313
314    else if (transit->effects_pending_del) _transit_remove_dead_effects(transit);
315
316    return EINA_TRUE;
317 }
318
319 static Eina_Bool
320 _transit_animate_cb(void *data)
321 {
322    Elm_Transit *transit = data;
323    double elapsed_time, duration;
324
325    transit->time.current = ecore_loop_time_get();
326    elapsed_time = transit->time.current - transit->time.begin;
327    duration = transit->time.duration + transit->time.delayed;
328
329    if (elapsed_time > duration)
330      elapsed_time = duration;
331
332    transit->progress = elapsed_time / duration;
333    switch (transit->tween_mode)
334      {
335       case ELM_TRANSIT_TWEEN_MODE_LINEAR:
336          transit->progress = ecore_animator_pos_map(transit->progress,
337                                                     ECORE_POS_MAP_LINEAR,
338                                                     0, 0);
339       case ELM_TRANSIT_TWEEN_MODE_ACCELERATE:
340          transit->progress = ecore_animator_pos_map(transit->progress,
341                                                     ECORE_POS_MAP_ACCELERATE,
342                                                     0, 0);
343          break;
344       case ELM_TRANSIT_TWEEN_MODE_DECELERATE:
345          transit->progress = ecore_animator_pos_map(transit->progress,
346                                                     ECORE_POS_MAP_DECELERATE,
347                                                     0, 0);
348          break;
349       case ELM_TRANSIT_TWEEN_MODE_SINUSOIDAL:
350          transit->progress = ecore_animator_pos_map(transit->progress,
351                                                     ECORE_POS_MAP_SINUSOIDAL,
352                                                     0, 0);
353          break;
354       default:
355          break;
356      }
357
358    /* Reverse? */
359    if (transit->repeat.reverse) transit->progress = 1 - transit->progress;
360
361    if (transit->time.duration > 0)
362      {
363         if (!_transit_animate_op(transit, transit->progress))
364           return ECORE_CALLBACK_CANCEL;
365      }
366
367    /* Not end. Keep going. */
368    if (elapsed_time < duration) return ECORE_CALLBACK_RENEW;
369
370    /* Repeat and reverse and time done! */
371    if ((transit->repeat.count >= 0) &&
372        (transit->repeat.current == transit->repeat.count) &&
373        ((!transit->auto_reverse) || transit->repeat.reverse))
374      {
375         transit->finished = EINA_TRUE;
376         elm_transit_del(transit);
377         return ECORE_CALLBACK_CANCEL;
378      }
379
380    /* Repeat Case */
381    if (!transit->auto_reverse || transit->repeat.reverse)
382      {
383         transit->repeat.current++;
384         transit->repeat.reverse = EINA_FALSE;
385      }
386    else transit->repeat.reverse = EINA_TRUE;
387
388    transit->time.begin = ecore_loop_time_get();
389
390    return ECORE_CALLBACK_RENEW;
391 }
392
393 static void
394 _recover_image_uv_by_y(Evas_Map *map, int iw, int ih)
395 {
396    evas_map_point_image_uv_set(map, 0, iw, 0);
397    evas_map_point_image_uv_set(map, 1, 0, 0);
398    evas_map_point_image_uv_set(map, 2, 0, ih);
399    evas_map_point_image_uv_set(map, 3, iw, ih);
400 }
401
402 static void
403 _recover_image_uv_by_x(Evas_Map *map, int iw, int ih)
404 {
405    evas_map_point_image_uv_set(map, 0, 0, ih);
406    evas_map_point_image_uv_set(map, 1, iw, ih);
407    evas_map_point_image_uv_set(map, 2, iw, 0);
408    evas_map_point_image_uv_set(map, 3, 0, 0);
409 }
410
411 static Eina_Bool
412 _recover_image_uv(Evas_Object *obj, Evas_Map *map, Eina_Bool revert, Eina_Bool by_x)
413 {
414    //Since the map is not proper for all types of objects,
415    //Need to handle uvs only for image objects
416    int iw, ih;
417    const char *type = evas_object_type_get(obj);
418    if ((!type) || (strcmp(type, "image"))) return EINA_FALSE;
419
420    evas_object_image_size_get(obj, &iw, &ih);
421
422    if (revert)
423      {
424         if (by_x)
425           _recover_image_uv_by_x(map, iw, ih);
426         else
427           _recover_image_uv_by_y(map, iw, ih);
428      }
429    else
430      {
431         evas_map_point_image_uv_set(map, 0, 0, 0);
432         evas_map_point_image_uv_set(map, 1, iw, 0);
433         evas_map_point_image_uv_set(map, 2, iw, ih);
434         evas_map_point_image_uv_set(map, 3, 0, ih);
435      }
436    return EINA_TRUE;
437 }
438
439 EAPI Elm_Transit *
440 elm_transit_add(void)
441 {
442    Elm_Transit *transit = ELM_NEW(Elm_Transit);
443    if (!transit)
444      {
445         ERR("Failed to allocate a elm_transit object!");
446         return NULL;
447      }
448
449    EINA_MAGIC_SET(transit, ELM_TRANSIT_MAGIC);
450
451    elm_transit_tween_mode_set(transit, ELM_TRANSIT_TWEEN_MODE_LINEAR);
452
453    return transit;
454 }
455
456 EAPI void
457 elm_transit_del(Elm_Transit *transit)
458 {
459    ELM_TRANSIT_CHECK_OR_RETURN(transit);
460
461    if (transit->walking) transit->deleted = EINA_TRUE;
462    else _transit_del(transit);
463 }
464
465 EAPI void
466 elm_transit_effect_add(Elm_Transit *transit, Elm_Transit_Effect_Transition_Cb transition_cb, Elm_Transit_Effect *effect, Elm_Transit_Effect_End_Cb end_cb)
467 {
468    ELM_TRANSIT_CHECK_OR_RETURN(transit);
469    EINA_SAFETY_ON_NULL_RETURN(transition_cb);
470    Elm_Transit_Effect_Module *effect_module;
471
472    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
473      if ((effect_module->transition_cb == transition_cb) && (effect_module->effect == effect))
474        {
475           WRN("elm_transit does not allow to add the duplicated effect! : transit=%p", transit);
476           return;
477        }
478
479    effect_module = ELM_NEW(Elm_Transit_Effect_Module);
480    if (!effect_module)
481      {
482         ERR("Failed to allocate a new effect!: transit=%p", transit);
483         return;
484      }
485
486    effect_module->end_cb = end_cb;
487    effect_module->transition_cb = transition_cb;
488    effect_module->effect = effect;
489
490    transit->effect_list = eina_inlist_append(transit->effect_list, (Eina_Inlist*) effect_module);
491 }
492
493 EAPI void
494 elm_transit_effect_del(Elm_Transit *transit, Elm_Transit_Effect_Transition_Cb transition_cb, Elm_Transit_Effect *effect)
495 {
496    ELM_TRANSIT_CHECK_OR_RETURN(transit);
497    EINA_SAFETY_ON_NULL_RETURN(transition_cb);
498    Elm_Transit_Effect_Module *effect_module;
499
500    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
501      {
502         if ((effect_module->transition_cb == transition_cb) && (effect_module->effect == effect))
503           {
504              if (transit->walking)
505                {
506                   effect_module->deleted = EINA_TRUE;
507                   transit->effects_pending_del++;
508                }
509              else
510                {
511                   _transit_effect_del(transit, effect_module);
512                   if (!transit->effect_list) elm_transit_del(transit);
513                }
514              return;
515           }
516      }
517 }
518
519 EAPI void
520 elm_transit_object_add(Elm_Transit *transit, Evas_Object *obj)
521 {
522    ELM_TRANSIT_CHECK_OR_RETURN(transit);
523    EINA_SAFETY_ON_NULL_RETURN(obj);
524
525    if (transit->animator)
526      {
527         if (!evas_object_data_get(obj, _transit_key))
528           {
529              _transit_obj_data_update(transit, obj);
530              evas_object_freeze_events_set(obj, EINA_TRUE);
531           }
532      }
533
534    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
535                                   _transit_obj_remove_cb,
536                                   transit);
537
538    transit->objs = eina_list_append(transit->objs, obj);
539 }
540
541 EAPI void
542 elm_transit_object_remove(Elm_Transit *transit, Evas_Object *obj)
543 {
544    ELM_TRANSIT_CHECK_OR_RETURN(transit);
545    EINA_SAFETY_ON_NULL_RETURN(obj);
546
547    _transit_obj_remove(transit, obj);
548    if (!transit->objs) elm_transit_del(transit);
549 }
550
551 EAPI const Eina_List *
552 elm_transit_objects_get(const Elm_Transit *transit)
553 {
554    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
555    return transit->objs;
556 }
557
558 EAPI void
559 elm_transit_event_enabled_set(Elm_Transit *transit, Eina_Bool enabled)
560 {
561    ELM_TRANSIT_CHECK_OR_RETURN(transit);
562
563    Eina_List *list;
564    Evas_Object *obj;
565
566    if (transit->event_enabled == enabled) return;
567    transit->event_enabled = !!enabled;
568    if (!transit->animator) return;
569
570    EINA_LIST_FOREACH(transit->objs, list, obj)
571      evas_object_freeze_events_set(obj, enabled);
572 }
573
574 EAPI Eina_Bool
575 elm_transit_event_enabled_get(const Elm_Transit *transit)
576 {
577    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
578    return transit->event_enabled;
579 }
580
581 EAPI void
582 elm_transit_del_cb_set(Elm_Transit *transit, void (*cb) (void *data, Elm_Transit *transit), void *data)
583 {
584    ELM_TRANSIT_CHECK_OR_RETURN(transit);
585    transit->del_data.func = cb;
586    transit->del_data.arg = data;
587 }
588
589 EAPI void
590 elm_transit_auto_reverse_set(Elm_Transit *transit, Eina_Bool reverse)
591 {
592    ELM_TRANSIT_CHECK_OR_RETURN(transit);
593    transit->auto_reverse = reverse;
594 }
595
596 EAPI Eina_Bool
597 elm_transit_auto_reverse_get(const Elm_Transit *transit)
598 {
599    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
600    return transit->auto_reverse;
601 }
602
603 EAPI void
604 elm_transit_repeat_times_set(Elm_Transit *transit, int repeat)
605 {
606    ELM_TRANSIT_CHECK_OR_RETURN(transit);
607    transit->repeat.count = repeat;
608    transit->repeat.current = 0;
609 }
610
611 EAPI int
612 elm_transit_repeat_times_get(const Elm_Transit *transit)
613 {
614    ELM_TRANSIT_CHECK_OR_RETURN(transit, 0);
615    return transit->repeat.count;
616 }
617
618 EAPI void
619 elm_transit_tween_mode_set(Elm_Transit *transit, Elm_Transit_Tween_Mode tween_mode)
620 {
621    ELM_TRANSIT_CHECK_OR_RETURN(transit);
622    transit->tween_mode = tween_mode;
623 }
624
625 EAPI Elm_Transit_Tween_Mode
626 elm_transit_tween_mode_get(const Elm_Transit *transit)
627 {
628    ELM_TRANSIT_CHECK_OR_RETURN(transit, ELM_TRANSIT_TWEEN_MODE_LINEAR);
629    return transit->tween_mode;
630 }
631
632 EAPI void
633 elm_transit_duration_set(Elm_Transit *transit, double duration)
634 {
635    ELM_TRANSIT_CHECK_OR_RETURN(transit);
636    if (transit->animator)
637      {
638         WRN("elm_transit does not allow to set the duration time in operating! : transit=%p", transit);
639         return;
640      }
641    transit->time.duration = duration;
642 }
643
644 EAPI double
645 elm_transit_duration_get(const Elm_Transit *transit)
646 {
647    ELM_TRANSIT_CHECK_OR_RETURN(transit, 0.0);
648    return transit->time.duration;
649 }
650
651 EAPI void
652 elm_transit_go(Elm_Transit *transit)
653 {
654    ELM_TRANSIT_CHECK_OR_RETURN(transit);
655
656    Eina_List *elist;
657    Evas_Object *obj;
658
659    if (transit->animator)
660      ecore_animator_del(transit->animator);
661
662    EINA_LIST_FOREACH(transit->objs, elist, obj)
663      _transit_obj_data_update(transit, obj);
664
665    if (!transit->event_enabled)
666      {
667         EINA_LIST_FOREACH(transit->objs, elist, obj)
668           evas_object_freeze_events_set(obj, EINA_TRUE);
669      }
670
671    transit->time.paused = 0;
672    transit->time.delayed = 0;
673    transit->time.begin = ecore_loop_time_get();
674    transit->animator = ecore_animator_add(_transit_animate_cb, transit);
675 }
676
677 EAPI void
678 elm_transit_paused_set(Elm_Transit *transit, Eina_Bool paused)
679 {
680    ELM_TRANSIT_CHECK_OR_RETURN(transit);
681
682    if (!transit->animator) return;
683
684    if (paused)
685      {
686         if (transit->time.paused > 0)
687           return;
688         ecore_animator_freeze(transit->animator);
689         transit->time.paused = ecore_loop_time_get();
690      }
691    else
692      {
693         if (transit->time.paused == 0)
694           return;
695         ecore_animator_thaw(transit->animator);
696         transit->time.delayed += (ecore_loop_time_get() - transit->time.paused);
697         transit->time.paused = 0;
698      }
699 }
700
701 EAPI Eina_Bool
702 elm_transit_paused_get(const Elm_Transit *transit)
703 {
704    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
705
706    if (transit->time.paused == 0)
707      return EINA_FALSE;
708
709    return EINA_TRUE;
710 }
711
712 EAPI double
713 elm_transit_progress_value_get(const Elm_Transit *transit)
714 {
715    ELM_TRANSIT_CHECK_OR_RETURN(transit, 0);
716
717    return transit->progress;
718 }
719
720 EAPI void
721 elm_transit_objects_final_state_keep_set(Elm_Transit *transit, Eina_Bool state_keep)
722 {
723    ELM_TRANSIT_CHECK_OR_RETURN(transit);
724
725    if (transit->state_keep == state_keep) return;
726    if (transit->animator)
727      {
728         WRN("elm_transit does not allow to change final state keep mode in operating! : transit=%p", transit);
729         return;
730      }
731    transit->state_keep = !!state_keep;
732 }
733
734 EAPI Eina_Bool
735 elm_transit_objects_final_state_keep_get(const Elm_Transit *transit)
736 {
737    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
738    return transit->state_keep;
739 }
740
741 EAPI void
742 elm_transit_chain_transit_add(Elm_Transit *transit, Elm_Transit *chain_transit)
743 {
744    ELM_TRANSIT_CHECK_OR_RETURN(transit);
745    ELM_TRANSIT_CHECK_OR_RETURN(chain_transit);
746
747    if (transit == chain_transit)
748      {
749         WRN("You add a same transit as a chain transit! : transit=%p, chain_transit=%p", transit, chain_transit);
750         return;
751      }
752    if (transit == chain_transit->prev_chain_transit)
753      return;
754
755    if (chain_transit->prev_chain_transit)
756      chain_transit->prev_chain_transit->next_chain_transits = eina_list_remove(chain_transit->prev_chain_transit->next_chain_transits, chain_transit);
757
758    chain_transit->prev_chain_transit = transit;
759    transit->next_chain_transits = eina_list_append(transit->next_chain_transits, chain_transit);
760 }
761
762 EAPI void
763 elm_transit_chain_transit_del(Elm_Transit *transit, Elm_Transit *chain_transit)
764 {
765    ELM_TRANSIT_CHECK_OR_RETURN(transit);
766    ELM_TRANSIT_CHECK_OR_RETURN(chain_transit);
767
768    if (chain_transit->prev_chain_transit != transit)
769      {
770         WRN("A pair of transits does not have the chain relationship! : transit=%p, chain_transit=%p", transit, chain_transit);
771         return;
772      }
773
774    chain_transit->prev_chain_transit = NULL;
775    transit->next_chain_transits = eina_list_remove(transit->next_chain_transits, chain_transit);
776 }
777
778 EAPI Eina_List *
779 elm_transit_chain_transits_get(const Elm_Transit * transit)
780 {
781    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
782    return transit->next_chain_transits;
783 }
784
785 ///////////////////////////////////////////////////////////////////////////
786 //Resizing Effect
787 ///////////////////////////////////////////////////////////////////////////
788 typedef struct _Elm_Transit_Effect_Resizing Elm_Transit_Effect_Resizing;
789
790 struct _Elm_Transit_Effect_Resizing
791 {
792    struct _size {
793       Evas_Coord w, h;
794    } from, to;
795 };
796
797 static void
798 _transit_effect_resizing_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
799 {
800    Elm_Transit_Effect_Resizing *resizing = effect;
801    free(resizing);
802 }
803
804 static void
805 _transit_effect_resizing_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
806 {
807    EINA_SAFETY_ON_NULL_RETURN(effect);
808    EINA_SAFETY_ON_NULL_RETURN(transit);
809    Evas_Coord w, h;
810    Evas_Object *obj;
811    Eina_List *elist;
812    Elm_Transit_Effect_Resizing *resizing = effect;
813
814    w = resizing->from.w + (resizing->to.w * progress);
815    h = resizing->from.h + (resizing->to.h * progress);
816
817    EINA_LIST_FOREACH(transit->objs, elist, obj)
818      evas_object_resize(obj, w, h);
819 }
820
821 static Elm_Transit_Effect *
822 _transit_effect_resizing_context_new(Evas_Coord from_w, Evas_Coord from_h, Evas_Coord to_w, Evas_Coord to_h)
823 {
824    Elm_Transit_Effect_Resizing *resizing;
825
826    resizing = ELM_NEW(Elm_Transit_Effect_Resizing);
827    if (!resizing) return NULL;
828
829    resizing->from.w = from_w;
830    resizing->from.h = from_h;
831    resizing->to.w = to_w - from_w;
832    resizing->to.h = to_h - from_h;
833
834    return resizing;
835 }
836
837 EAPI Elm_Transit_Effect *
838 elm_transit_effect_resizing_add(Elm_Transit *transit, Evas_Coord from_w, Evas_Coord from_h, Evas_Coord to_w, Evas_Coord to_h)
839 {
840    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
841    Elm_Transit_Effect *effect = _transit_effect_resizing_context_new(from_w, from_h, to_w, to_h);
842
843    if (!effect)
844      {
845         ERR("Failed to allocate resizing effect! : transit=%p", transit);
846         return NULL;
847      }
848    elm_transit_effect_add(transit,
849                           _transit_effect_resizing_op, effect,
850                           _transit_effect_resizing_context_free);
851    return effect;
852 }
853
854 ///////////////////////////////////////////////////////////////////////////
855 //Translation Effect
856 ///////////////////////////////////////////////////////////////////////////
857 typedef struct _Elm_Transit_Effect_Translation Elm_Transit_Effect_Translation;
858 typedef struct _Elm_Transit_Effect_Translation_Node Elm_Transit_Effect_Translation_Node;
859
860 struct _Elm_Transit_Effect_Translation_Node
861 {
862    Evas_Object *obj;
863    Evas_Coord x, y;
864 };
865
866 struct _Elm_Transit_Effect_Translation
867 {
868    struct _position_variation {
869       Evas_Coord dx, dy;
870    } from, to;
871    Eina_List *nodes;
872 };
873
874 static void
875 _translation_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
876 {
877    Elm_Transit_Effect_Translation *translation = data;
878    Eina_List *elist;
879    Elm_Transit_Effect_Translation_Node *translation_node;
880
881    EINA_LIST_FOREACH(translation->nodes, elist, translation_node)
882      {
883         if (translation_node->obj != obj) continue;
884         translation->nodes = eina_list_remove_list(translation->nodes, elist);
885         free(translation_node);
886         break;
887      }
888 }
889
890 static Eina_List *
891 _translation_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_Translation *translation)
892 {
893    Elm_Transit_Effect_Translation_Node *translation_node;
894    const Eina_List *elist;
895    Evas_Object *obj;
896    Eina_List *data_list = NULL;
897    const Eina_List *objs = elm_transit_objects_get(transit);
898
899    EINA_LIST_FOREACH(objs, elist, obj)
900      {
901         translation_node = ELM_NEW(Elm_Transit_Effect_Translation_Node);
902         if (!translation_node)
903           {
904              eina_list_free(data_list);
905              return NULL;
906           }
907         translation_node->obj = obj;
908         evas_object_geometry_get(obj, &(translation_node->x),
909                                  &(translation_node->y), NULL, NULL);
910         data_list = eina_list_append(data_list, translation_node);
911         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
912                                        _translation_object_del_cb, translation);
913      }
914    return data_list;
915 }
916
917 void
918 _transit_effect_translation_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
919 {
920    EINA_SAFETY_ON_NULL_RETURN(effect);
921    Elm_Transit_Effect_Translation *translation = effect;
922    Eina_List *elist, *elist_next;
923    Elm_Transit_Effect_Translation_Node *translation_node;
924
925    EINA_LIST_FOREACH_SAFE(translation->nodes,
926                           elist, elist_next, translation_node)
927      {
928         evas_object_event_callback_del(translation_node->obj,
929                                        EVAS_CALLBACK_DEL, _translation_object_del_cb);
930         translation->nodes = eina_list_remove_list(translation->nodes, elist);
931         free(translation_node);
932      }
933    free(translation);
934 }
935
936 void
937 _transit_effect_translation_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress __UNUSED__)
938 {
939    EINA_SAFETY_ON_NULL_RETURN(effect);
940    EINA_SAFETY_ON_NULL_RETURN(transit);
941    Evas_Coord x, y;
942    Elm_Transit_Effect_Translation *translation = effect;
943    Elm_Transit_Effect_Translation_Node *translation_node;
944    Eina_List *elist;
945
946    if (!translation->nodes)
947      translation->nodes = _translation_nodes_build(transit, translation);
948
949    EINA_LIST_FOREACH(translation->nodes, elist, translation_node)
950      {
951         x = translation_node->x + translation->from.dx
952            + (translation->to.dx * progress);
953         y = translation_node->y + translation->from.dy
954            + (translation->to.dy * progress);
955         evas_object_move(translation_node->obj, x, y);
956      }
957 }
958
959 static Elm_Transit_Effect *
960 _transit_effect_translation_context_new(Evas_Coord from_dx, Evas_Coord from_dy, Evas_Coord to_dx, Evas_Coord to_dy)
961 {
962    Elm_Transit_Effect_Translation *translation;
963
964    translation = ELM_NEW(Elm_Transit_Effect_Translation);
965    if (!translation) return NULL;
966
967    translation->from.dx = from_dx;
968    translation->from.dy = from_dy;
969    translation->to.dx = to_dx - from_dx;
970    translation->to.dy = to_dy - from_dy;
971
972    return translation;
973 }
974
975 EAPI Elm_Transit_Effect *
976 elm_transit_effect_translation_add(Elm_Transit *transit, Evas_Coord from_dx, Evas_Coord from_dy, Evas_Coord to_dx, Evas_Coord to_dy)
977 {
978    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
979    Elm_Transit_Effect *effect = _transit_effect_translation_context_new(from_dx, from_dy, to_dx, to_dy);
980
981    if (!effect)
982      {
983         ERR("Failed to allocate translation effect! : transit=%p", transit);
984         return NULL;
985      }
986    elm_transit_effect_add(transit,
987                           _transit_effect_translation_op, effect,
988                           _transit_effect_translation_context_free);
989    return effect;
990 }
991
992 ///////////////////////////////////////////////////////////////////////////
993 //Zoom Effect
994 ///////////////////////////////////////////////////////////////////////////
995 typedef struct _Elm_Transit_Effect_Zoom Elm_Transit_Effect_Zoom;
996
997 struct _Elm_Transit_Effect_Zoom
998 {
999    float from, to;
1000 };
1001
1002 void
1003 _transit_effect_zoom_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1004 {
1005    Elm_Transit_Effect_Zoom *zoom = effect;
1006    free(zoom);
1007 }
1008
1009 static void
1010 _transit_effect_zoom_op(Elm_Transit_Effect *effect, Elm_Transit *transit , double progress)
1011 {
1012    EINA_SAFETY_ON_NULL_RETURN(effect);
1013    EINA_SAFETY_ON_NULL_RETURN(transit);
1014    Evas_Object *obj;
1015    Eina_List *elist;
1016    Elm_Transit_Effect_Zoom *zoom = effect;
1017    Evas_Map *map;
1018    Evas_Coord x, y, w, h;
1019
1020    map = evas_map_new(4);
1021    if (!map) return;
1022
1023    EINA_LIST_FOREACH(transit->objs, elist, obj)
1024      {
1025         evas_object_geometry_get(obj, &x, &y, &w, &h);
1026         evas_map_util_points_populate_from_object_full(map, obj, zoom->from +
1027                                                        (progress * zoom->to));
1028         _recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE);
1029         evas_map_util_3d_perspective(map, x + (w / 2), y + (h / 2), 0,
1030                                      _TRANSIT_FOCAL);
1031         evas_object_map_set(obj, map);
1032         evas_object_map_enable_set(obj, EINA_TRUE);
1033      }
1034    evas_map_free(map);
1035 }
1036
1037 static Elm_Transit_Effect *
1038 _transit_effect_zoom_context_new(float from_rate, float to_rate)
1039 {
1040    Elm_Transit_Effect_Zoom *zoom;
1041
1042    zoom = ELM_NEW(Elm_Transit_Effect_Zoom);
1043    if (!zoom) return NULL;
1044
1045    zoom->from = (_TRANSIT_FOCAL - (from_rate * _TRANSIT_FOCAL)) * (1 / from_rate);
1046    zoom->to = ((_TRANSIT_FOCAL - (to_rate * _TRANSIT_FOCAL)) * (1 / to_rate)) - zoom->from;
1047
1048    return zoom;
1049 }
1050
1051 EAPI Elm_Transit_Effect *
1052 elm_transit_effect_zoom_add(Elm_Transit *transit, float from_rate, float to_rate)
1053 {
1054    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1055    Elm_Transit_Effect *effect = _transit_effect_zoom_context_new(from_rate, to_rate);
1056
1057    if (!effect)
1058      {
1059         ERR("Failed to allocate zoom effect! : transit=%p", transit);
1060         return NULL;
1061      }
1062    elm_transit_effect_add(transit,
1063                           _transit_effect_zoom_op, effect,
1064                           _transit_effect_zoom_context_free);
1065    return effect;
1066 }
1067
1068 ///////////////////////////////////////////////////////////////////////////
1069 //Flip Effect
1070 ///////////////////////////////////////////////////////////////////////////
1071 typedef struct _Elm_Transit_Effect_Flip Elm_Transit_Effect_Flip;
1072
1073 struct _Elm_Transit_Effect_Flip
1074 {
1075    Elm_Transit_Effect_Flip_Axis axis;
1076    Eina_Bool cw : 1;
1077 };
1078
1079 static void
1080 _transit_effect_flip_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit)
1081 {
1082    EINA_SAFETY_ON_NULL_RETURN(effect);
1083    EINA_SAFETY_ON_NULL_RETURN(transit);
1084    Elm_Transit_Effect_Flip *flip = effect;
1085    Evas_Object *front, *back;
1086    int i;
1087    int count = eina_list_count(transit->objs);
1088
1089    for (i = 0; i < (count - 1); i += 2)
1090      {
1091         front = eina_list_nth(transit->objs, i);
1092         back = eina_list_nth(transit->objs, i+1);
1093         evas_object_map_enable_set(front, EINA_FALSE);
1094         evas_object_map_enable_set(back, EINA_FALSE);
1095      }
1096    free(flip);
1097 }
1098
1099 static void
1100 _transit_effect_flip_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
1101 {
1102    EINA_SAFETY_ON_NULL_RETURN(effect);
1103    EINA_SAFETY_ON_NULL_RETURN(transit);
1104    Evas_Object *obj, *front, *back;
1105    int count, i;
1106    Elm_Transit_Effect_Flip *flip = effect;
1107    Evas_Map *map;
1108    float degree;
1109    Evas_Coord x, y, w, h;
1110
1111    map = evas_map_new(4);
1112    if (!map) return;
1113
1114    if (flip->cw) degree = (float)(progress * 180);
1115    else degree = (float)(progress * -180);
1116
1117    count = eina_list_count(transit->objs);
1118
1119    for (i = 0; i < (count - 1); i += 2)
1120      {
1121         Evas_Coord half_w, half_h;
1122
1123         front = eina_list_nth(transit->objs, i);
1124         back = eina_list_nth(transit->objs, i+1);
1125
1126         if ((degree < 90) && (degree > -90))
1127           {
1128              obj = front;
1129              if (front != back)
1130                {
1131                   evas_object_hide(back);
1132                   evas_object_show(front);
1133                }
1134           }
1135         else
1136           {
1137              obj = back;
1138              if (front != back)
1139                {
1140                   evas_object_hide(front);
1141                   evas_object_show(back);
1142                }
1143           }
1144
1145         evas_map_util_points_populate_from_object_full(map, obj, 0);
1146         evas_object_geometry_get(obj, &x, &y, &w, &h);
1147         half_w = (w / 2);
1148         half_h = (h / 2);
1149
1150         if (flip->axis == ELM_TRANSIT_EFFECT_FLIP_AXIS_Y)
1151           {
1152              if ((degree >= 90) || (degree <= -90))
1153                {
1154                   if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_FALSE))
1155                     {
1156                        evas_map_point_image_uv_set(map, 0, w, 0);
1157                        evas_map_point_image_uv_set(map, 1, 0, 0);
1158                        evas_map_point_image_uv_set(map, 2, 0, h);
1159                        evas_map_point_image_uv_set(map, 3, w, h);
1160                     }
1161                }
1162              else
1163                _recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE);
1164              evas_map_util_3d_rotate(map, 0, degree,
1165                                      0, x + half_w, y + half_h, 0);
1166           }
1167         else
1168           {
1169              if ((degree >= 90) || (degree <= -90))
1170                {
1171                   if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_TRUE))
1172                     {
1173                        evas_map_point_image_uv_set(map, 0, 0, h);
1174                        evas_map_point_image_uv_set(map, 1, w, h);
1175                        evas_map_point_image_uv_set(map, 2, w, 0);
1176                        evas_map_point_image_uv_set(map, 3, 0, 0);
1177                     }
1178                }
1179              else
1180                _recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE);
1181              evas_map_util_3d_rotate(map, degree,
1182                                      0, 0, x + half_w, y + half_h, 0);
1183           }
1184         evas_map_util_3d_perspective(map, x + half_w, y + half_h, 0, _TRANSIT_FOCAL);
1185         evas_object_map_enable_set(front, EINA_TRUE);
1186         evas_object_map_enable_set(back, EINA_TRUE);
1187         evas_object_map_set(obj, map);
1188      }
1189    evas_map_free(map);
1190 }
1191
1192 static Elm_Transit_Effect *
1193 _transit_effect_flip_context_new(Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1194 {
1195    Elm_Transit_Effect_Flip *flip;
1196
1197    flip = ELM_NEW(Elm_Transit_Effect_Flip);
1198    if (!flip) return NULL;
1199
1200    flip->cw = cw;
1201    flip->axis = axis;
1202
1203    return flip;
1204 }
1205
1206 EAPI Elm_Transit_Effect *
1207 elm_transit_effect_flip_add(Elm_Transit *transit, Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1208 {
1209    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1210    Elm_Transit_Effect *effect = _transit_effect_flip_context_new(axis, cw);
1211
1212    if (!effect)
1213      {
1214         ERR("Failed to allocate flip effect! : transit=%p", transit);
1215         return NULL;
1216      }
1217    elm_transit_effect_add(transit,
1218                           _transit_effect_flip_op, effect,
1219                           _transit_effect_flip_context_free);
1220    return effect;
1221 }
1222
1223 ///////////////////////////////////////////////////////////////////////////
1224 //ResizableFlip Effect
1225 ///////////////////////////////////////////////////////////////////////////
1226 typedef struct _Elm_Transit_Effect_Resizable_Flip Elm_Transit_Effect_ResizableFlip;
1227 typedef struct _Elm_Transit_Effect_Resizable_Flip_Node Elm_Transit_Effect_ResizableFlip_Node;
1228
1229 struct _Elm_Transit_Effect_Resizable_Flip_Node
1230 {
1231    Evas_Object *front;
1232    Evas_Object *back;
1233    struct _vector2d {
1234       float x, y;
1235    } from_pos, from_size, to_pos, to_size;
1236 };
1237
1238 struct _Elm_Transit_Effect_Resizable_Flip
1239 {
1240    Eina_List *nodes;
1241    Eina_Bool cw : 1;
1242    Elm_Transit_Effect_Flip_Axis axis;
1243 };
1244
1245 static void
1246 _resizable_flip_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1247 {
1248    Elm_Transit_Effect_ResizableFlip *resizable_flip = data;
1249    Eina_List *elist;
1250    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1251
1252    EINA_LIST_FOREACH(resizable_flip->nodes, elist, resizable_flip_node)
1253      {
1254         if (resizable_flip_node->front == obj)
1255           evas_object_event_callback_del(resizable_flip_node->back,
1256                                          EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1257         else if (resizable_flip_node->back == obj)
1258           evas_object_event_callback_del(resizable_flip_node->front,
1259                                          EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1260         else continue;
1261
1262         resizable_flip->nodes = eina_list_remove_list(resizable_flip->nodes,
1263                                                       elist);
1264         free(resizable_flip_node);
1265         break;
1266      }
1267 }
1268
1269 static Eina_List *
1270 _resizable_flip_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_ResizableFlip *resizable_flip)
1271 {
1272    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1273    Eina_List *data_list = NULL;
1274    Evas_Coord front_x, front_y, front_w, front_h;
1275    Evas_Coord back_x, back_y, back_w, back_h;
1276    int i, count;
1277
1278    count = eina_list_count(transit->objs);
1279    for (i = 0; i < (count - 1); i += 2)
1280      {
1281         resizable_flip_node = ELM_NEW(Elm_Transit_Effect_ResizableFlip_Node);
1282         if (!resizable_flip_node)
1283           {
1284              eina_list_free(data_list);
1285              return NULL;
1286           }
1287
1288         resizable_flip_node->front = eina_list_nth(transit->objs, i);
1289         resizable_flip_node->back = eina_list_nth(transit->objs, i+1);
1290
1291         evas_object_geometry_get(resizable_flip_node->front,
1292                                  &front_x, &front_y, &front_w, &front_h);
1293         evas_object_geometry_get(resizable_flip_node->back,
1294                                  &back_x, &back_y, &back_w, &back_h);
1295
1296         resizable_flip_node->from_pos.x = front_x;
1297         resizable_flip_node->from_pos.y = front_y;
1298         resizable_flip_node->to_pos.x = back_x - front_x;
1299         resizable_flip_node->to_pos.y = back_y - front_y;
1300
1301         resizable_flip_node->from_size.x = front_w;
1302         resizable_flip_node->from_size.y = front_h;
1303         resizable_flip_node->to_size.x = back_w - front_w;
1304         resizable_flip_node->to_size.y = back_h - front_h;
1305
1306         data_list = eina_list_append(data_list, resizable_flip_node);
1307
1308         evas_object_event_callback_add(resizable_flip_node->back,
1309                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb, resizable_flip);
1310         evas_object_event_callback_add(resizable_flip_node->front,
1311                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb, resizable_flip);
1312      }
1313
1314    return data_list;
1315 }
1316
1317 static void
1318 _set_image_uv_by_axis_y(Evas_Map *map, Elm_Transit_Effect_ResizableFlip_Node *flip, Eina_Bool revert)
1319 {
1320    if (revert)
1321      {
1322         evas_map_point_image_uv_set(map, 0,
1323                                     (flip->from_size.x * 2) + flip->to_size.x,
1324                                     0);
1325         evas_map_point_image_uv_set(map, 1, 0, 0);
1326         evas_map_point_image_uv_set(map, 2, 0,
1327                                     (flip->from_size.y * 2) + flip->to_size.y);
1328         evas_map_point_image_uv_set(map, 3,
1329                                     (flip->from_size.x * 2) + flip->to_size.x,
1330                                     (flip->from_size.y * 2) + flip->to_size.y);
1331      }
1332    else
1333      {
1334         evas_map_point_image_uv_set(map, 0, 0, 0);
1335         evas_map_point_image_uv_set(map, 1, flip->from_size.x, 0);
1336         evas_map_point_image_uv_set(map, 2, flip->from_size.x,
1337                                     flip->from_size.y);
1338         evas_map_point_image_uv_set(map, 3, 0, flip->from_size.y);
1339      }
1340 }
1341
1342 static void
1343 _set_image_uv_by_axis_x(Evas_Map *map, Elm_Transit_Effect_ResizableFlip_Node *flip, Eina_Bool revert)
1344 {
1345    if (revert)
1346      {
1347         evas_map_point_image_uv_set(map, 0, 0,
1348                                     (flip->from_size.y * 2) + flip->to_size.y);
1349         evas_map_point_image_uv_set(map, 1,
1350                                     (flip->from_size.x * 2) + flip->to_size.x,
1351                                     (flip->from_size.y * 2) + flip->to_size.y);
1352         evas_map_point_image_uv_set(map, 2,
1353                                     (flip->from_size.x * 2) + flip->to_size.x,
1354                                     0);
1355         evas_map_point_image_uv_set(map, 3, 0, 0);
1356      }
1357    else
1358      {
1359         evas_map_point_image_uv_set(map, 0, 0, 0);
1360         evas_map_point_image_uv_set(map, 1, flip->from_size.x, 0);
1361         evas_map_point_image_uv_set(map, 2, flip->from_size.x,
1362                                     flip->from_size.y);
1363         evas_map_point_image_uv_set(map, 3, 0, flip->from_size.y);
1364      }
1365 }
1366
1367 void
1368 _transit_effect_resizable_flip_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1369 {
1370    EINA_SAFETY_ON_NULL_RETURN(effect);
1371
1372    Elm_Transit_Effect_ResizableFlip *resizable_flip = effect;
1373    Eina_List *elist, *elist_next;
1374    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1375
1376    EINA_LIST_FOREACH_SAFE(resizable_flip->nodes,
1377                           elist, elist_next, resizable_flip_node)
1378      {
1379         evas_object_map_enable_set(resizable_flip_node->front, EINA_FALSE);
1380         evas_object_map_enable_set(resizable_flip_node->back, EINA_FALSE);
1381
1382         resizable_flip->nodes = eina_list_remove_list(resizable_flip->nodes,
1383                                                       elist);
1384
1385         evas_object_event_callback_del(resizable_flip_node->back,
1386                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1387         evas_object_event_callback_del(resizable_flip_node->front,
1388                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1389         free(resizable_flip_node);
1390      }
1391    free(resizable_flip);
1392 }
1393
1394 void
1395 _transit_effect_resizable_flip_op(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__, double progress)
1396 {
1397    EINA_SAFETY_ON_NULL_RETURN(effect);
1398    Evas_Map *map;
1399    Evas_Object *obj;
1400    float x, y, w, h;
1401    float degree;
1402    Evas_Coord half_w, half_h;
1403    Elm_Transit_Effect_ResizableFlip *resizable_flip = effect;
1404    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1405    Eina_List *elist;
1406
1407    map = evas_map_new(4);
1408    if (!map) return;
1409
1410    if (resizable_flip->cw) degree = (float)(progress * 180);
1411    else degree = (float)(progress * -180);
1412
1413    if (!resizable_flip->nodes)
1414      resizable_flip->nodes = _resizable_flip_nodes_build(transit,
1415                                                          resizable_flip);
1416
1417    EINA_LIST_FOREACH(resizable_flip->nodes, elist, resizable_flip_node)
1418      {
1419         if ((degree < 90) && (degree > -90))
1420           {
1421              obj = resizable_flip_node->front;
1422              if (resizable_flip_node->front != resizable_flip_node->back)
1423                {
1424                   evas_object_hide(resizable_flip_node->back);
1425                   evas_object_show(resizable_flip_node->front);
1426                }
1427           }
1428         else
1429           {
1430              obj = resizable_flip_node->back;
1431              if (resizable_flip_node->front != resizable_flip_node->back)
1432                {
1433                   evas_object_hide(resizable_flip_node->front);
1434                   evas_object_show(resizable_flip_node->back);
1435                }
1436           }
1437
1438         x = resizable_flip_node->from_pos.x +
1439            (resizable_flip_node->to_pos.x * progress);
1440         y = resizable_flip_node->from_pos.y +
1441            (resizable_flip_node->to_pos.y * progress);
1442         w = resizable_flip_node->from_size.x +
1443            (resizable_flip_node->to_size.x * progress);
1444         h = resizable_flip_node->from_size.y +
1445            (resizable_flip_node->to_size.y * progress);
1446         evas_map_point_coord_set(map, 0, x, y, 0);
1447         evas_map_point_coord_set(map, 1, x + w, y, 0);
1448         evas_map_point_coord_set(map, 2, x + w, y + h, 0);
1449         evas_map_point_coord_set(map, 3, x, y + h, 0);
1450
1451         half_w = (Evas_Coord)(w / 2);
1452         half_h = (Evas_Coord)(h / 2);
1453
1454         if (resizable_flip->axis == ELM_TRANSIT_EFFECT_FLIP_AXIS_Y)
1455           {
1456              if ((degree >= 90) || (degree <= -90))
1457                 {
1458                    if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_FALSE))
1459                      _set_image_uv_by_axis_y(map, resizable_flip_node,
1460                                              EINA_TRUE);
1461                 }
1462              else
1463                {
1464                   if (!_recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE))
1465                     _set_image_uv_by_axis_y(map, resizable_flip_node,
1466                                             EINA_FALSE);
1467                }
1468              evas_map_util_3d_rotate(map, 0, degree,
1469                                      0, x + half_w, y + half_h, 0);
1470           }
1471         else
1472           {
1473              if ((degree >= 90) || (degree <= -90))
1474                 {
1475                    if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_TRUE))
1476                      _set_image_uv_by_axis_x(map, resizable_flip_node,
1477                                              EINA_TRUE);
1478                 }
1479              else
1480                {
1481                    if (!_recover_image_uv(obj, map, EINA_FALSE, EINA_TRUE))
1482                      _set_image_uv_by_axis_x(map, resizable_flip_node,
1483                                              EINA_FALSE);
1484                }
1485              evas_map_util_3d_rotate(map, degree, 0,
1486                                      0, x + half_w, y + half_h, 0);
1487           }
1488
1489         evas_map_util_3d_perspective(map, x + half_w, y + half_h, 0,
1490                                      _TRANSIT_FOCAL);
1491         evas_object_map_enable_set(resizable_flip_node->front, EINA_TRUE);
1492         evas_object_map_enable_set(resizable_flip_node->back, EINA_TRUE);
1493         evas_object_map_set(obj, map);
1494      }
1495    evas_map_free(map);
1496 }
1497
1498 static Elm_Transit_Effect *
1499 _transit_effect_resizable_flip_context_new(Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1500 {
1501    Elm_Transit_Effect_ResizableFlip *resizable_flip;
1502
1503    resizable_flip = ELM_NEW(Elm_Transit_Effect_ResizableFlip);
1504    if (!resizable_flip) return NULL;
1505
1506    resizable_flip->cw = cw;
1507    resizable_flip->axis = axis;
1508
1509    return resizable_flip;
1510 }
1511
1512 EAPI Elm_Transit_Effect *
1513 elm_transit_effect_resizable_flip_add(Elm_Transit *transit, Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1514 {
1515    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1516    Elm_Transit_Effect *effect = _transit_effect_resizable_flip_context_new(axis, cw);
1517
1518    if (!effect)
1519      {
1520         ERR("Failed to allocate resizable_flip effect! : transit=%p", transit);
1521         return NULL;
1522      }
1523    elm_transit_effect_add(transit,
1524                           _transit_effect_resizable_flip_op, effect,
1525                           _transit_effect_resizable_flip_context_free);
1526    return effect;
1527 }
1528
1529 ///////////////////////////////////////////////////////////////////////////
1530 //Wipe Effect
1531 ///////////////////////////////////////////////////////////////////////////
1532 typedef struct _Elm_Transit_Effect_Wipe Elm_Transit_Effect_Wipe;
1533
1534 struct _Elm_Transit_Effect_Wipe
1535 {
1536    Elm_Transit_Effect_Wipe_Type type;
1537    Elm_Transit_Effect_Wipe_Dir dir;
1538 };
1539
1540 static void
1541 _elm_fx_wipe_hide(Evas_Map * map, Elm_Transit_Effect_Wipe_Dir dir, float x, float y, float w, float h, float progress)
1542 {
1543    float w2, h2;
1544
1545    switch (dir)
1546      {
1547       case ELM_TRANSIT_EFFECT_WIPE_DIR_LEFT:
1548          w2 = w - (w * progress);
1549          h2 = (y + h);
1550          evas_map_point_image_uv_set(map, 0, 0, 0);
1551          evas_map_point_image_uv_set(map, 1, w2, 0);
1552          evas_map_point_image_uv_set(map, 2, w2, h);
1553          evas_map_point_image_uv_set(map, 3, 0, h);
1554          evas_map_point_coord_set(map, 0, x, y, 0);
1555          evas_map_point_coord_set(map, 1, x + w2, y, 0);
1556          evas_map_point_coord_set(map, 2, x + w2, h2, 0);
1557          evas_map_point_coord_set(map, 3, x, h2, 0);
1558          break;
1559       case ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT:
1560          w2 = (w * progress);
1561          h2 = (y + h);
1562          evas_map_point_image_uv_set(map, 0, w2, 0);
1563          evas_map_point_image_uv_set(map, 1, w, 0);
1564          evas_map_point_image_uv_set(map, 2, w, h);
1565          evas_map_point_image_uv_set(map, 3, w2, h);
1566          evas_map_point_coord_set(map, 0, x + w2, y, 0);
1567          evas_map_point_coord_set(map, 1, x + w, y, 0);
1568          evas_map_point_coord_set(map, 2, x + w, h2, 0);
1569          evas_map_point_coord_set(map, 3, x + w2, h2, 0);
1570          break;
1571       case ELM_TRANSIT_EFFECT_WIPE_DIR_UP:
1572          w2 = (x + w);
1573          h2 = h - (h * progress);
1574          evas_map_point_image_uv_set(map, 0, 0, 0);
1575          evas_map_point_image_uv_set(map, 1, w, 0);
1576          evas_map_point_image_uv_set(map, 2, w, h2);
1577          evas_map_point_image_uv_set(map, 3, 0, h2);
1578          evas_map_point_coord_set(map, 0, x, y, 0);
1579          evas_map_point_coord_set(map, 1, w2, y, 0);
1580          evas_map_point_coord_set(map, 2, w2, y+h2, 0);
1581          evas_map_point_coord_set(map, 3, x, y+h2, 0);
1582          break;
1583       case ELM_TRANSIT_EFFECT_WIPE_DIR_DOWN:
1584          w2 = (x + w);
1585          h2 = (h * progress);
1586          evas_map_point_image_uv_set(map, 0, 0, h2);
1587          evas_map_point_image_uv_set(map, 1, w, h2);
1588          evas_map_point_image_uv_set(map, 2, w, h);
1589          evas_map_point_image_uv_set(map, 3, 0, h);
1590          evas_map_point_coord_set(map, 0, x, y + h2, 0);
1591          evas_map_point_coord_set(map, 1, w2, y + h2, 0);
1592          evas_map_point_coord_set(map, 2, w2, y + h, 0);
1593          evas_map_point_coord_set(map, 3, x, y + h, 0);
1594          break;
1595       default:
1596          break;
1597      }
1598    evas_map_util_3d_perspective(map, x + (w / 2), y + (h / 2), 0, _TRANSIT_FOCAL);
1599 }
1600
1601 static void
1602 _elm_fx_wipe_show(Evas_Map *map, Elm_Transit_Effect_Wipe_Dir dir, float x, float y, float w, float h, float progress)
1603 {
1604    float w2, h2;
1605
1606    switch (dir)
1607      {
1608       case ELM_TRANSIT_EFFECT_WIPE_DIR_LEFT:
1609          w2 = (w - (w * progress));
1610          h2 = (y + h);
1611          evas_map_point_image_uv_set(map, 0, w2, 0);
1612          evas_map_point_image_uv_set(map, 1, w, 0);
1613          evas_map_point_image_uv_set(map, 2, w, h);
1614          evas_map_point_image_uv_set(map, 3, w2, h);
1615          evas_map_point_coord_set(map, 0, x + w2, y, 0);
1616          evas_map_point_coord_set(map, 1, w, y, 0);
1617          evas_map_point_coord_set(map, 2, w, h2, 0);
1618          evas_map_point_coord_set(map, 3, x + w2, h2, 0);
1619          break;
1620       case ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT:
1621          w2 = (w * progress);
1622          h2 = (y + h);
1623          evas_map_point_image_uv_set(map, 0, 0, 0);
1624          evas_map_point_image_uv_set(map, 1, w2, 0);
1625          evas_map_point_image_uv_set(map, 2, w2, h);
1626          evas_map_point_image_uv_set(map, 3, 0, h);
1627          evas_map_point_coord_set(map, 0, x, y, 0);
1628          evas_map_point_coord_set(map, 1, x + w2, y, 0);
1629          evas_map_point_coord_set(map, 2, x + w2, h2, 0);
1630          evas_map_point_coord_set(map, 3, x, h2, 0);
1631          break;
1632       case ELM_TRANSIT_EFFECT_WIPE_DIR_UP:
1633          w2 = (x + w);
1634          h2 = (h - (h * progress));
1635          evas_map_point_image_uv_set(map, 0, 0, h2);
1636          evas_map_point_image_uv_set(map, 1, w, h2);
1637          evas_map_point_image_uv_set(map, 2, w, h);
1638          evas_map_point_image_uv_set(map, 3, 0, h);
1639          evas_map_point_coord_set(map, 0, x, y + h2, 0);
1640          evas_map_point_coord_set(map, 1, w2, y + h2, 0);
1641          evas_map_point_coord_set(map, 2, w2, y + h, 0);
1642          evas_map_point_coord_set(map, 3, x, y + h, 0);
1643          break;
1644       case ELM_TRANSIT_EFFECT_WIPE_DIR_DOWN:
1645          w2 = (x + w);
1646          h2 = (h * progress);
1647          evas_map_point_image_uv_set(map, 0, 0, 0);
1648          evas_map_point_image_uv_set(map, 1, w, 0);
1649          evas_map_point_image_uv_set(map, 2, w, h2);
1650          evas_map_point_image_uv_set(map, 3, 0, h2);
1651          evas_map_point_coord_set(map, 0, x, y, 0);
1652          evas_map_point_coord_set(map, 1, w2, y, 0);
1653          evas_map_point_coord_set(map, 2, w2, y + h2, 0);
1654          evas_map_point_coord_set(map, 3, x, y + h2, 0);
1655          break;
1656       default:
1657          break;
1658      }
1659    evas_map_util_3d_perspective(map, x + (w / 2), y + (h / 2), 0, _TRANSIT_FOCAL);
1660 }
1661
1662 static void
1663 _transit_effect_wipe_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit)
1664 {
1665    EINA_SAFETY_ON_NULL_RETURN(effect);
1666    EINA_SAFETY_ON_NULL_RETURN(transit);
1667    Eina_List *elist;
1668    Evas_Object *obj;
1669    Elm_Transit_Effect_Wipe *wipe = effect;
1670    Eina_Bool reverse = elm_transit_auto_reverse_get(transit);
1671
1672    EINA_LIST_FOREACH(transit->objs, elist, obj)
1673      {
1674         if ((wipe->type == ELM_TRANSIT_EFFECT_WIPE_TYPE_SHOW && !reverse)
1675             || (wipe->type == ELM_TRANSIT_EFFECT_WIPE_TYPE_HIDE && reverse))
1676           evas_object_show(obj);
1677         else evas_object_hide(obj);
1678         evas_object_map_enable_set(obj, EINA_FALSE);
1679      }
1680
1681    free(wipe);
1682 }
1683
1684 static void
1685 _transit_effect_wipe_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
1686 {
1687    EINA_SAFETY_ON_NULL_RETURN(effect);
1688    EINA_SAFETY_ON_NULL_RETURN(transit);
1689    Elm_Transit_Effect_Wipe *wipe = effect;
1690    Evas_Map *map;
1691    Evas_Coord _x, _y, _w, _h;
1692    Eina_List *elist;
1693    Evas_Object *obj;
1694    const char *type;
1695
1696    map = evas_map_new(4);
1697    if (!map) return;
1698
1699    EINA_LIST_FOREACH(transit->objs, elist, obj)
1700      {
1701         type = evas_object_type_get(obj);
1702         if ((!type) || (strcmp(type, "image")))
1703           evas_object_geometry_get(obj, &_x, &_y, &_w, &_h);
1704         else
1705           {
1706              evas_object_image_size_get(obj, &_w, &_h);
1707              _x = 0;
1708              _y = 0;
1709           }
1710         if (wipe->type == ELM_TRANSIT_EFFECT_WIPE_TYPE_SHOW)
1711           _elm_fx_wipe_show(map, wipe->dir, _x, _y, _w, _h, (float)progress);
1712         else
1713           _elm_fx_wipe_hide(map, wipe->dir, _x, _y, _w, _h, (float)progress);
1714
1715         evas_object_map_enable_set(obj, EINA_TRUE);
1716         evas_object_map_set(obj, map);
1717      }
1718    evas_map_free(map);
1719 }
1720
1721 static Elm_Transit_Effect *
1722 _transit_effect_wipe_context_new(Elm_Transit_Effect_Wipe_Type type, Elm_Transit_Effect_Wipe_Dir dir)
1723 {
1724    Elm_Transit_Effect_Wipe *wipe;
1725
1726    wipe = ELM_NEW(Elm_Transit_Effect_Wipe);
1727    if (!wipe) return NULL;
1728
1729    wipe->type = type;
1730    wipe->dir = dir;
1731
1732    return wipe;
1733 }
1734
1735 EAPI void *
1736 elm_transit_effect_wipe_add(Elm_Transit *transit, Elm_Transit_Effect_Wipe_Type type, Elm_Transit_Effect_Wipe_Dir dir)
1737 {
1738    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1739    void *effect = _transit_effect_wipe_context_new(type, dir);
1740
1741    if (!effect)
1742      {
1743         ERR("Failed to allocate wipe effect! : transit=%p", transit);
1744         return NULL;
1745      }
1746    elm_transit_effect_add(transit,
1747                           _transit_effect_wipe_op, effect,
1748                           _transit_effect_wipe_context_free);
1749    return effect;
1750 }
1751
1752 ///////////////////////////////////////////////////////////////////////////
1753 //Color Effect
1754 ///////////////////////////////////////////////////////////////////////////
1755 typedef struct _Elm_Transit_Effect_Color Elm_Transit_Effect_Color;
1756
1757 struct _Elm_Transit_Effect_Color
1758 {
1759    struct _unsigned_color {
1760       unsigned int r, g, b, a;
1761    } from;
1762    struct _signed_color {
1763       int r, g, b, a;
1764    } to;
1765 };
1766
1767 static void
1768 _transit_effect_color_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1769 {
1770    Elm_Transit_Effect_Color *color = effect;
1771    free(color);
1772 }
1773
1774 static void
1775 _transit_effect_color_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
1776 {
1777    EINA_SAFETY_ON_NULL_RETURN(effect);
1778    EINA_SAFETY_ON_NULL_RETURN(transit);
1779    Elm_Transit_Effect_Color *color = effect;
1780    Evas_Object *obj;
1781    Eina_List *elist;
1782    unsigned int r, g, b, a;
1783
1784    r = (color->from.r + (int)((float)color->to.r * progress));
1785    g = (color->from.g + (int)((float)color->to.g * progress));
1786    b = (color->from.b + (int)((float)color->to.b * progress));
1787    a = (color->from.a + (int)((float)color->to.a * progress));
1788
1789    EINA_LIST_FOREACH(transit->objs, elist, obj)
1790      evas_object_color_set(obj, r, g, b, a);
1791 }
1792
1793 static Elm_Transit_Effect *
1794 _transit_effect_color_context_new(unsigned int from_r, unsigned int from_g, unsigned int from_b, unsigned int from_a, unsigned int to_r, unsigned int to_g, unsigned int to_b, unsigned int to_a)
1795 {
1796    Elm_Transit_Effect_Color *color;
1797
1798    color = ELM_NEW(Elm_Transit_Effect_Color);
1799    if (!color) return NULL;
1800
1801    color->from.r = from_r;
1802    color->from.g = from_g;
1803    color->from.b = from_b;
1804    color->from.a = from_a;
1805    color->to.r = to_r - from_r;
1806    color->to.g = to_g - from_g;
1807    color->to.b = to_b - from_b;
1808    color->to.a = to_a - from_a;
1809
1810    return color;
1811 }
1812
1813 EAPI Elm_Transit_Effect *
1814 elm_transit_effect_color_add(Elm_Transit *transit, unsigned int from_r, unsigned int from_g, unsigned int from_b, unsigned int from_a, unsigned int to_r, unsigned int to_g, unsigned int to_b, unsigned int to_a)
1815 {
1816    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1817    Elm_Transit_Effect *effect = _transit_effect_color_context_new(from_r, from_g, from_b, from_a, to_r, to_g, to_b, to_a);
1818
1819    if (!effect)
1820      {
1821         ERR("Failed to allocate color effect! : transit=%p", transit);
1822         return NULL;
1823      }
1824    elm_transit_effect_add(transit,
1825                           _transit_effect_color_op, effect,
1826                           _transit_effect_color_context_free);
1827    return effect;
1828 }
1829
1830 ///////////////////////////////////////////////////////////////////////////
1831 //Fade Effect
1832 ///////////////////////////////////////////////////////////////////////////
1833 typedef struct _Elm_Transit_Effect_Fade Elm_Transit_Effect_Fade;
1834 typedef struct _Elm_Transit_Effect_Fade_Node Elm_Transit_Effect_Fade_Node;
1835
1836 struct _Elm_Transit_Effect_Fade_Node
1837 {
1838    Evas_Object *before;
1839    Evas_Object *after;
1840    struct _signed_color before_color, after_color;
1841    int before_alpha;
1842    int after_alpha;
1843    Eina_Bool inversed : 1;
1844 };
1845
1846 struct _Elm_Transit_Effect_Fade
1847 {
1848    Eina_List *nodes;
1849 };
1850
1851 static void
1852 _fade_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1853 {
1854    Elm_Transit_Effect_Fade *fade = data;
1855    Eina_List *elist;
1856    Elm_Transit_Effect_Fade_Node *fade_node;
1857
1858    EINA_LIST_FOREACH(fade->nodes, elist, fade_node)
1859      {
1860         if (fade_node->before == obj)
1861           evas_object_event_callback_del(fade_node->after,
1862                                          EVAS_CALLBACK_DEL, _fade_object_del_cb);
1863         else if (fade_node->after == obj)
1864           evas_object_event_callback_del(fade_node->before,
1865                                          EVAS_CALLBACK_DEL, _fade_object_del_cb);
1866         else continue;
1867
1868         fade->nodes = eina_list_remove_list(fade->nodes, elist);
1869         free(fade_node);
1870         break;
1871      }
1872 }
1873
1874 static Eina_List *
1875 _fade_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_Fade *fade_data)
1876 {
1877    Elm_Transit_Effect_Fade_Node *fade;
1878    Eina_List *data_list = NULL;
1879    int i, count;
1880
1881    count = eina_list_count(transit->objs);
1882    for (i = 0; i < count; i += 2)
1883      {
1884         fade = ELM_NEW(Elm_Transit_Effect_Fade_Node);
1885         if (!fade)
1886           {
1887              eina_list_free(data_list);
1888              return NULL;
1889           }
1890
1891         fade->before = eina_list_nth(transit->objs, i);
1892         fade->after = eina_list_nth(transit->objs, i+1);
1893
1894         evas_object_color_get(fade->before,
1895                               &fade->before_color.r, &fade->before_color.g,
1896                               &fade->before_color.b, &fade->before_color.a);
1897         evas_object_color_get(fade->after,
1898                               &fade->after_color.r, &fade->after_color.g,
1899                               &fade->after_color.b, &fade->after_color.a);
1900
1901         fade->before_alpha = (255 - fade->before_color.a);
1902         fade->after_alpha = (255 - fade->after_color.a);
1903
1904         data_list = eina_list_append(data_list, fade);
1905
1906         evas_object_event_callback_add(fade->before,
1907                                        EVAS_CALLBACK_DEL, _fade_object_del_cb, fade_data);
1908         evas_object_event_callback_add(fade->after,
1909                                        EVAS_CALLBACK_DEL, _fade_object_del_cb, fade_data);
1910      }
1911    return data_list;
1912 }
1913
1914 static void
1915 _transit_effect_fade_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1916 {
1917    EINA_SAFETY_ON_NULL_RETURN(effect);
1918    Elm_Transit_Effect_Fade *fade = effect;
1919    Elm_Transit_Effect_Fade_Node *fade_node;
1920    Eina_List *elist, *elist_next;
1921
1922    EINA_LIST_FOREACH_SAFE(fade->nodes, elist, elist_next, fade_node)
1923      {
1924         evas_object_color_set(fade_node->before, fade_node->before_color.r,
1925                               fade_node->before_color.g,
1926                               fade_node->before_color.b,
1927                               fade_node->before_color.a);
1928         evas_object_color_set(fade_node->after, fade_node->after_color.r,
1929                               fade_node->after_color.g,
1930                               fade_node->after_color.b,
1931                               fade_node->after_color.a);
1932
1933         fade->nodes = eina_list_remove_list(fade->nodes, elist);
1934         evas_object_event_callback_del(fade_node->before,
1935                                        EVAS_CALLBACK_DEL, _fade_object_del_cb);
1936         evas_object_event_callback_del(fade_node->after,
1937                                        EVAS_CALLBACK_DEL, _fade_object_del_cb);
1938         free(fade_node);
1939      }
1940
1941    free(fade);
1942 }
1943
1944 static void
1945 _transit_effect_fade_op(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__, double progress)
1946 {
1947    EINA_SAFETY_ON_NULL_RETURN(effect);
1948    Elm_Transit_Effect_Fade *fade = effect;
1949    Eina_List *elist;
1950    Elm_Transit_Effect_Fade_Node *fade_node;
1951    float _progress;
1952
1953    if (!fade->nodes)
1954      fade->nodes = _fade_nodes_build(transit, fade);
1955
1956    EINA_LIST_FOREACH(fade->nodes, elist, fade_node)
1957      {
1958         if (progress < 0.5)
1959           {
1960              if (!fade_node->inversed)
1961                {
1962                   evas_object_hide(fade_node->after);
1963                   evas_object_show(fade_node->before);
1964                   fade_node->inversed = EINA_TRUE;
1965                }
1966
1967              _progress = (1 - (progress * 2));
1968
1969              evas_object_color_set(fade_node->before,
1970                                    fade_node->before_color.r * _progress,
1971                                    fade_node->before_color.g * _progress,
1972                                    fade_node->before_color.b * _progress,
1973                                    fade_node->before_color.a +
1974                                    fade_node->before_alpha * (1 - _progress));
1975           }
1976         else
1977           {
1978              if (fade_node->inversed)
1979                {
1980                   evas_object_hide(fade_node->before);
1981                   evas_object_show(fade_node->after);
1982                   fade_node->inversed = EINA_FALSE;
1983                }
1984
1985              _progress = ((progress - 0.5) * 2);
1986
1987              evas_object_color_set(fade_node->after,
1988                                    fade_node->after_color.r * _progress,
1989                                    fade_node->after_color.g * _progress,
1990                                    fade_node->after_color.b * _progress,
1991                                    fade_node->after_color.a +
1992                                    fade_node->after_alpha * (1 - _progress));
1993           }
1994      }
1995 }
1996
1997 static Elm_Transit_Effect *
1998 _transit_effect_fade_context_new(void)
1999 {
2000    Elm_Transit_Effect_Fade *fade;
2001    fade = ELM_NEW(Elm_Transit_Effect_Fade);
2002    if (!fade) return NULL;
2003    return fade;
2004 }
2005
2006 EAPI Elm_Transit_Effect *
2007 elm_transit_effect_fade_add(Elm_Transit *transit)
2008 {
2009    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2010
2011    Elm_Transit_Effect *effect = _transit_effect_fade_context_new();
2012
2013    if (!effect)
2014      {
2015         ERR("Failed to allocate fade effect! : transit=%p", transit);
2016         return NULL;
2017      }
2018    elm_transit_effect_add(transit,
2019                           _transit_effect_fade_op, effect,
2020                           _transit_effect_fade_context_free);
2021    return effect;
2022 }
2023
2024 ///////////////////////////////////////////////////////////////////////////
2025 //Blend Effect
2026 ///////////////////////////////////////////////////////////////////////////
2027 typedef struct _Elm_Transit_Effect_Blend Elm_Transit_Effect_Blend;
2028 typedef struct _Elm_Transit_Effect_Blend_Node Elm_Transit_Effect_Blend_Node;
2029
2030 struct _Elm_Transit_Effect_Blend_Node
2031 {
2032    Evas_Object *before;
2033    Evas_Object *after;
2034    struct _signed_color from, to;
2035 };
2036
2037 struct _Elm_Transit_Effect_Blend
2038 {
2039    Eina_List *nodes;
2040 };
2041
2042 static void
2043 _blend_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2044 {
2045    Elm_Transit_Effect_Blend *blend = data;
2046    Eina_List *elist;
2047    Elm_Transit_Effect_Blend_Node *blend_node;
2048
2049    EINA_LIST_FOREACH(blend->nodes, elist, blend_node)
2050      {
2051         if (blend_node->after == obj)
2052           evas_object_event_callback_del(blend_node->before,
2053                                          EVAS_CALLBACK_DEL, _blend_object_del_cb);
2054         else if (blend_node->before == obj)
2055           evas_object_event_callback_del(blend_node->after,
2056                                          EVAS_CALLBACK_DEL, _blend_object_del_cb);
2057         else continue;
2058
2059         blend->nodes = eina_list_remove_list(blend->nodes, elist);
2060         free(blend_node);
2061         break;
2062      }
2063 }
2064
2065 static Eina_List *
2066 _blend_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_Blend *blend)
2067 {
2068    Elm_Transit_Effect_Blend_Node *blend_node;
2069    Eina_List *data_list = NULL;
2070    int i, count;
2071
2072    count = eina_list_count(transit->objs);
2073    for (i = 0; i < (count - 1); i += 2)
2074      {
2075         blend_node = ELM_NEW(Elm_Transit_Effect_Blend_Node);
2076         if (!blend_node)
2077           {
2078              eina_list_free(data_list);
2079              return NULL;
2080           }
2081
2082         blend_node->before = eina_list_nth(transit->objs, i);
2083         blend_node->after = eina_list_nth(transit->objs, i + 1);
2084         evas_object_show(blend_node->before);
2085         evas_object_show(blend_node->after);
2086
2087         evas_object_color_get(blend_node->before, &blend_node->from.r,
2088                               &blend_node->from.g, &blend_node->from.b,
2089                               &blend_node->from.a);
2090         evas_object_color_get(blend_node->after, &blend_node->to.r,
2091                               &blend_node->to.g, &blend_node->to.b,
2092                               &blend_node->to.a);
2093
2094         data_list = eina_list_append(data_list, blend_node);
2095
2096         evas_object_event_callback_add(blend_node->before,
2097                                        EVAS_CALLBACK_DEL, _blend_object_del_cb, blend);
2098         evas_object_event_callback_add(blend_node->after,
2099                                        EVAS_CALLBACK_DEL, _blend_object_del_cb, blend);
2100      }
2101    return data_list;
2102 }
2103
2104 void
2105 _transit_effect_blend_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
2106 {
2107    EINA_SAFETY_ON_NULL_RETURN(effect);
2108    Elm_Transit_Effect_Blend *blend = effect;
2109    Elm_Transit_Effect_Blend_Node *blend_node;
2110    Eina_List *elist, *elist_next;
2111
2112    EINA_LIST_FOREACH_SAFE(blend->nodes, elist, elist_next, blend_node)
2113      {
2114         evas_object_color_set(blend_node->before,
2115                               blend_node->from.r, blend_node->from.g,
2116                               blend_node->from.b, blend_node->from.a);
2117         evas_object_color_set(blend_node->after, blend_node->to.r,
2118                               blend_node->to.g, blend_node->to.b,
2119                               blend_node->to.a);
2120
2121         if (elm_transit_auto_reverse_get(transit))
2122           evas_object_hide(blend_node->after);
2123         else
2124           evas_object_hide(blend_node->before);
2125
2126         blend->nodes = eina_list_remove_list(blend->nodes, elist);
2127
2128         evas_object_event_callback_del(blend_node->before,
2129                                        EVAS_CALLBACK_DEL, _blend_object_del_cb);
2130         evas_object_event_callback_del(blend_node->after,
2131                                        EVAS_CALLBACK_DEL, _blend_object_del_cb);
2132         free(blend_node);
2133      }
2134    free(blend);
2135 }
2136
2137 void
2138 _transit_effect_blend_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
2139 {
2140    EINA_SAFETY_ON_NULL_RETURN(effect);
2141    EINA_SAFETY_ON_NULL_RETURN(transit);
2142    Elm_Transit_Effect_Blend *blend = effect;
2143    Elm_Transit_Effect_Blend_Node *blend_node;
2144    Eina_List *elist;
2145
2146    if (!blend->nodes) blend->nodes = _blend_nodes_build(transit, blend);
2147
2148    EINA_LIST_FOREACH(blend->nodes, elist, blend_node)
2149      {
2150         evas_object_color_set(blend_node->before,
2151                               (int)(blend_node->from.r * (1 - progress)),
2152                               (int)(blend_node->from.g * (1 - progress)),
2153                               (int)(blend_node->from.b * (1 - progress)),
2154                               (int)(blend_node->from.a * (1 - progress)));
2155         evas_object_color_set(blend_node->after,
2156                               (int)(blend_node->to.r * progress),
2157                               (int)(blend_node->to.g * progress),
2158                               (int)(blend_node->to.b * progress),
2159                               (int)(blend_node->to.a * progress));
2160      }
2161 }
2162
2163 static Elm_Transit_Effect *
2164 _transit_effect_blend_context_new(void)
2165 {
2166    Elm_Transit_Effect_Blend *blend;
2167
2168    blend = ELM_NEW(Elm_Transit_Effect_Blend);
2169    if (!blend) return NULL;
2170    return blend;
2171 }
2172
2173 EAPI Elm_Transit_Effect *
2174 elm_transit_effect_blend_add(Elm_Transit *transit)
2175 {
2176    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2177    Elm_Transit_Effect *effect = _transit_effect_blend_context_new();
2178
2179    if (!effect)
2180      {
2181         ERR("Failed to allocate blend effect! : transit=%p", transit);
2182         return NULL;
2183      }
2184    elm_transit_effect_add(transit,
2185                           _transit_effect_blend_op, effect,
2186                           _transit_effect_blend_context_free);
2187    return effect;
2188 }
2189
2190 ///////////////////////////////////////////////////////////////////////////
2191 //Rotation Effect
2192 ///////////////////////////////////////////////////////////////////////////
2193 typedef struct _Elm_Transit_Effect_Rotation Elm_Transit_Effect_Rotation;
2194
2195 struct _Elm_Transit_Effect_Rotation
2196 {
2197    float from, to;
2198 };
2199
2200 static void
2201 _transit_effect_rotation_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
2202 {
2203    Elm_Transit_Effect_Rotation *rotation = effect;
2204    free(rotation);
2205 }
2206
2207 static void
2208 _transit_effect_rotation_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
2209 {
2210    EINA_SAFETY_ON_NULL_RETURN(effect);
2211    EINA_SAFETY_ON_NULL_RETURN(transit);
2212    Elm_Transit_Effect_Rotation *rotation = effect;
2213    Evas_Map *map;
2214    Evas_Coord x, y, w, h;
2215    float degree;
2216    float half_w, half_h;
2217    Eina_List *elist;
2218    Evas_Object *obj;
2219
2220    map = evas_map_new(4);
2221    if (!map) return;
2222
2223    EINA_LIST_FOREACH(transit->objs, elist, obj)
2224      {
2225         evas_map_util_points_populate_from_object_full(map, obj, 0);
2226         degree = rotation->from + (float)(progress * rotation->to);
2227
2228         evas_object_geometry_get(obj, &x, &y, &w, &h);
2229
2230         half_w = (float)w * 0.5;
2231         half_h = (float)h * 0.5;
2232
2233         evas_map_util_rotate(map, degree, x + half_w, y + half_h);
2234         evas_map_util_3d_perspective(map, x + half_w, y + half_h, 0, _TRANSIT_FOCAL);
2235         evas_object_map_enable_set(obj, EINA_TRUE);
2236         evas_object_map_set(obj, map);
2237      }
2238    evas_map_free(map);
2239 }
2240
2241 static Elm_Transit_Effect *
2242 _transit_effect_rotation_context_new(float from_degree, float to_degree)
2243 {
2244    Elm_Transit_Effect_Rotation *rotation;
2245
2246    rotation = ELM_NEW(Elm_Transit_Effect_Rotation);
2247    if (!rotation) return NULL;
2248
2249    rotation->from = from_degree;
2250    rotation->to = to_degree - from_degree;
2251
2252    return rotation;
2253 }
2254
2255 EAPI Elm_Transit_Effect *
2256 elm_transit_effect_rotation_add(Elm_Transit *transit, float from_degree, float to_degree)
2257 {
2258    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2259    Elm_Transit_Effect *effect = _transit_effect_rotation_context_new(from_degree, to_degree);
2260
2261    if (!effect)
2262      {
2263         ERR("Failed to allocate rotation effect! : transit=%p", transit);
2264         return NULL;
2265      }
2266    elm_transit_effect_add(transit,
2267                           _transit_effect_rotation_op, effect,
2268                           _transit_effect_rotation_context_free);
2269    return effect;
2270 }
2271
2272 ///////////////////////////////////////////////////////////////////////////
2273 //ImageAnimation Effect
2274 ///////////////////////////////////////////////////////////////////////////
2275 typedef struct _Elm_Transit_Effect_Image_Animation Elm_Transit_Effect_Image_Animation;
2276
2277 struct _Elm_Transit_Effect_Image_Animation
2278 {
2279    Eina_List *images;
2280 };
2281
2282 static void
2283 _transit_effect_image_animation_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
2284 {
2285    EINA_SAFETY_ON_NULL_RETURN(effect);
2286    Elm_Transit_Effect_Image_Animation *image_animation = effect;
2287    const char *image;
2288    Eina_List *elist, *elist_next;
2289
2290    EINA_LIST_FOREACH_SAFE(image_animation->images, elist, elist_next, image)
2291      {
2292         image_animation->images =
2293            eina_list_remove_list(image_animation->images, elist);
2294         eina_stringshare_del(image);
2295      }
2296
2297    free(image_animation);
2298 }
2299
2300 static void
2301 _transit_effect_image_animation_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
2302 {
2303    EINA_SAFETY_ON_NULL_RETURN(effect);
2304    EINA_SAFETY_ON_NULL_RETURN(transit);
2305    Eina_List *elist;
2306    Evas_Object *obj;
2307    const char *type;
2308    Elm_Transit_Effect_Image_Animation *image_animation = effect;
2309    unsigned int count = 0;
2310    int len;
2311
2312    type = eina_stringshare_add("icon");
2313    len = eina_list_count(image_animation->images);
2314
2315    if (!len) count = floor(progress * len);
2316    else count = floor(progress * (len - 1));
2317
2318    EINA_LIST_FOREACH(transit->objs, elist, obj)
2319      {
2320         if (elm_widget_type_check(obj, type, __func__))
2321           elm_icon_file_set(obj,
2322                             eina_list_nth(image_animation->images, count), NULL);
2323      }
2324
2325    eina_stringshare_del(type);
2326 }
2327
2328 static Elm_Transit_Effect *
2329 _transit_effect_image_animation_context_new(Eina_List *images)
2330 {
2331    Elm_Transit_Effect_Image_Animation *image_animation;
2332    image_animation = ELM_NEW(Elm_Transit_Effect_Image_Animation);
2333
2334    if (!image_animation) return NULL;
2335    image_animation->images = images;
2336    return image_animation;
2337 }
2338
2339 EAPI Elm_Transit_Effect *
2340 elm_transit_effect_image_animation_add(Elm_Transit *transit, Eina_List *images)
2341 {
2342    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2343    Elm_Transit_Effect *effect = _transit_effect_image_animation_context_new(images);
2344
2345    if (!effect)
2346      {
2347         ERR("Failed to allocate image_animation effect! : transit=%p", transit);
2348         return NULL;
2349      }
2350    elm_transit_effect_add(transit,
2351                           _transit_effect_image_animation_op, effect,
2352                           _transit_effect_image_animation_context_free);
2353    return effect;
2354 }