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