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