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