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