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