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