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