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