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