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