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