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