elementary/map - map supports language,changed
[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 #define _TRANSIT_FOCAL 2000
22
23 struct _Elm_Transit
24 {
25 #define ELM_TRANSIT_MAGIC 0xd27f190a
26    EINA_MAGIC;
27
28    Ecore_Animator *animator;
29    Eina_Inlist *effect_list;
30    Eina_List *objs;
31    Elm_Transit *prev_chain_transit;
32    Eina_List *next_chain_transits;
33    Elm_Transit_Tween_Mode tween_mode;
34    struct
35      {
36         Elm_Transit_Del_Cb func;
37         void *arg;
38      } del_data;
39    struct
40      {
41         double delayed;
42         double paused;
43         double duration;
44         double begin;
45         double current;
46      } time;
47    struct
48      {
49         int count;
50         int current;
51         Eina_Bool reverse;
52      } repeat;
53    double progress;
54    unsigned int effects_pending_del;
55    int walking;
56    double v1, v2;
57    Eina_Bool auto_reverse : 1;
58    Eina_Bool event_enabled : 1;
59    Eina_Bool deleted : 1;
60    Eina_Bool state_keep : 1;
61    Eina_Bool finished : 1;
62    Eina_Bool smooth : 1;
63 };
64
65 struct _Elm_Transit_Effect_Module
66 {
67    EINA_INLIST;
68    Elm_Transit_Effect_Transition_Cb transition_cb;
69    Elm_Transit_Effect_End_Cb end_cb;
70    Elm_Transit_Effect *effect;
71    Eina_Bool deleted : 1;
72 };
73
74 struct _Elm_Transit_Obj_State
75 {
76    Evas_Coord x, y, w, h;
77    int r,g,b,a;
78    Evas_Map *map;
79    Eina_Bool map_enabled : 1;
80    Eina_Bool visible : 1;
81 };
82
83 struct _Elm_Transit_Obj_Data
84 {
85    struct _Elm_Transit_Obj_State *state;
86    Eina_Bool freeze_events : 1;
87 };
88
89 typedef struct _Elm_Transit_Effect_Module Elm_Transit_Effect_Module;
90 typedef struct _Elm_Transit_Obj_Data Elm_Transit_Obj_Data;
91 typedef struct _Elm_Transit_Obj_State Elm_Transit_Obj_State;
92
93 static void _transit_obj_data_update(Elm_Transit *transit, Evas_Object *obj);
94 static void _transit_obj_data_recover(Elm_Transit *transit, Evas_Object *obj);
95 static void _transit_obj_states_save(Evas_Object *obj, Elm_Transit_Obj_Data *obj_data);
96 static void _transit_obj_remove_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
97 static void _transit_obj_remove(Elm_Transit *transit, Evas_Object *obj);
98 static void _transit_effect_del(Elm_Transit *transit, Elm_Transit_Effect_Module *effect_module);
99 static void _transit_remove_dead_effects(Elm_Transit *transit);
100 static void _transit_chain_go(Elm_Transit *transit);
101 static void _transit_del(Elm_Transit *transit);
102 static Eina_Bool _transit_animate_op(Elm_Transit *transit, double progress);
103 static Eina_Bool _transit_animate_cb(void *data);
104
105 static char *_transit_key= "_elm_transit_key";
106
107 static void
108 _transit_obj_data_update(Elm_Transit *transit, Evas_Object *obj)
109 {
110    Elm_Transit_Obj_Data *obj_data = evas_object_data_get(obj, _transit_key);
111
112    if (!obj_data)
113      obj_data = ELM_NEW(Elm_Transit_Obj_Data);
114
115    obj_data->freeze_events = evas_object_freeze_events_get(obj);
116
117    if ((!transit->state_keep) && (obj_data->state))
118      {
119         free(obj_data->state);
120         obj_data->state = NULL;
121      }
122    else
123      {
124        _transit_obj_states_save(obj, obj_data);
125      }
126
127    evas_object_data_set(obj, _transit_key, obj_data);
128 }
129
130 static void
131 _transit_obj_states_save(Evas_Object *obj, Elm_Transit_Obj_Data *obj_data)
132 {
133    Elm_Transit_Obj_State *state = obj_data->state;
134
135    if (!state)
136      state = calloc(1, sizeof(Elm_Transit_Obj_State));
137    if (!state) return;
138
139    evas_object_geometry_get(obj, &state->x, &state->y, &state->w, &state->h);
140    evas_object_color_get(obj, &state->r, &state->g, &state->b, &state->a);
141    state->visible = evas_object_visible_get(obj);
142    state->map_enabled = evas_object_map_enable_get(obj);
143    if (evas_object_map_get(obj))
144      state->map = evas_map_dup(evas_object_map_get(obj));
145    obj_data->state = state;
146 }
147
148 static void
149 _remove_obj_from_list(Elm_Transit *transit, Evas_Object *obj)
150 {
151    //Remove duplicated objects
152    //TODO: Need to consider about optimizing here
153    while (1)
154      {
155         if (!eina_list_data_find_list(transit->objs, obj))
156           break;
157         transit->objs = eina_list_remove(transit->objs, obj);
158         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL,
159                                        _transit_obj_remove_cb,
160                                        transit);
161      }
162 }
163
164 static void
165 _transit_obj_remove_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
166 {
167    Elm_Transit *transit = data;
168    Elm_Transit_Obj_Data *obj_data = evas_object_data_get(obj, _transit_key);
169    if (obj_data)
170      {
171         if (obj_data->state)
172           free(obj_data->state);
173         free(obj_data);
174      }
175    _remove_obj_from_list(transit, obj);
176    if (!transit->objs && !transit->deleted) elm_transit_del(transit);
177 }
178
179 static void
180 _transit_obj_data_recover(Elm_Transit *transit, Evas_Object *obj)
181 {
182    Elm_Transit_Obj_Data *obj_data;
183    Elm_Transit_Obj_State *state;
184
185    obj_data = evas_object_data_get(obj, _transit_key);
186    if (!obj_data) return;
187    evas_object_data_del(obj, _transit_key);
188    evas_object_freeze_events_set(obj, obj_data->freeze_events);
189    state = obj_data->state;
190    if (state)
191      {
192         //recover the states of the object.
193         if (!transit->state_keep)
194           {
195              evas_object_move(obj, state->x, state->y);
196              evas_object_resize(obj, state->w, state->h);
197              evas_object_color_set(obj, state->r, state->g, state->b, state->a);
198              if (state->visible) evas_object_show(obj);
199              else evas_object_hide(obj);
200              evas_object_map_enable_set(obj, state->map_enabled);
201              evas_object_map_set(obj, state->map);
202           }
203         free(state);
204      }
205    free(obj_data);
206 }
207
208 static void
209 _transit_obj_remove(Elm_Transit *transit, Evas_Object *obj)
210 {
211    _remove_obj_from_list(transit, obj);
212    _transit_obj_data_recover(transit, obj);
213 }
214
215 static void
216 _transit_effect_del(Elm_Transit *transit, Elm_Transit_Effect_Module *effect_module)
217 {
218    if (effect_module->end_cb)
219      effect_module->end_cb(effect_module->effect, transit);
220    free(effect_module);
221 }
222
223 static void
224 _transit_remove_dead_effects(Elm_Transit *transit)
225 {
226    Elm_Transit_Effect_Module *effect_module = NULL;
227    Eina_Inlist *ll;
228
229    EINA_INLIST_FOREACH_SAFE(transit->effect_list, ll, effect_module)
230      {
231         if (effect_module->deleted)
232           {
233              _transit_effect_del(transit, effect_module);
234              transit->effects_pending_del--;
235              if (!transit->effects_pending_del) return;
236           }
237      }
238 }
239
240 static void
241 _transit_chain_go(Elm_Transit *transit)
242 {
243    ELM_TRANSIT_CHECK_OR_RETURN(transit);
244    elm_transit_go(transit);
245 }
246
247 static void
248 _transit_del(Elm_Transit *transit)
249 {
250    Elm_Transit_Effect_Module *effect_module;
251    Elm_Transit *chain_transit;
252    Eina_List *elist, *elist_next;
253
254    transit->deleted = EINA_TRUE;
255
256    if (transit->animator)
257      ecore_animator_del(transit->animator);
258
259    //remove effects
260    while (transit->effect_list)
261      {
262         effect_module = EINA_INLIST_CONTAINER_GET(transit->effect_list, Elm_Transit_Effect_Module);
263         transit->effect_list = eina_inlist_remove(transit->effect_list, transit->effect_list);
264         _transit_effect_del(transit, effect_module);
265      }
266
267    //remove objects.
268    while (transit->objs)
269      _transit_obj_remove(transit, eina_list_data_get(transit->objs));
270
271    if (transit->del_data.func)
272      transit->del_data.func(transit->del_data.arg, transit);
273
274    //cut off the chain transit relationship
275    EINA_LIST_FOREACH_SAFE(transit->next_chain_transits, elist, elist_next, chain_transit)
276      chain_transit->prev_chain_transit = NULL;
277
278    if (transit->prev_chain_transit)
279      transit->prev_chain_transit->next_chain_transits =
280         eina_list_remove(transit->prev_chain_transit->next_chain_transits, transit);
281
282    // run chain transits
283    if (transit->finished && transit->next_chain_transits)
284      {
285         EINA_LIST_FOREACH_SAFE(transit->next_chain_transits, elist, elist_next, chain_transit)
286           _transit_chain_go(chain_transit);
287      }
288
289    eina_list_free(transit->next_chain_transits);
290
291    EINA_MAGIC_SET(transit, EINA_MAGIC_NONE);
292    free(transit);
293 }
294
295 //If the transit is deleted then EINA_FALSE is retruned.
296 static Eina_Bool
297 _transit_animate_op(Elm_Transit *transit, double progress)
298 {
299    Elm_Transit_Effect_Module *effect_module;
300
301    transit->walking++;
302    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
303      {
304         if (transit->deleted) break;
305         if (!effect_module->deleted)
306           effect_module->transition_cb(effect_module->effect, transit, progress);
307      }
308    transit->walking--;
309
310    if (transit->walking) return EINA_TRUE;
311
312    if (transit->deleted)
313      {
314         _transit_del(transit);
315         return EINA_FALSE;
316      }
317
318    else if (transit->effects_pending_del) _transit_remove_dead_effects(transit);
319
320    return EINA_TRUE;
321 }
322
323 static Eina_Bool
324 _transit_animate_cb(void *data)
325 {
326    Elm_Transit *transit = data;
327    double elapsed_time, duration;
328
329    transit->time.current = ecore_loop_time_get();
330    elapsed_time = transit->time.current - transit->time.begin;
331    duration = transit->time.duration + transit->time.delayed;
332
333    if (elapsed_time > duration)
334      elapsed_time = duration;
335
336    transit->progress = elapsed_time / duration;
337    switch (transit->tween_mode)
338      {
339       case ELM_TRANSIT_TWEEN_MODE_LINEAR:
340          transit->progress = ecore_animator_pos_map(transit->progress,
341                                                     ECORE_POS_MAP_LINEAR,
342                                                     0, 0);
343          break;
344       case ELM_TRANSIT_TWEEN_MODE_ACCELERATE:
345          transit->progress = ecore_animator_pos_map(transit->progress,
346                                                     ECORE_POS_MAP_ACCELERATE,
347                                                     transit->v1, 0);
348          break;
349       case ELM_TRANSIT_TWEEN_MODE_DECELERATE:
350          transit->progress = ecore_animator_pos_map(transit->progress,
351                                                     ECORE_POS_MAP_DECELERATE,
352                                                     transit->v1, 0);
353          break;
354       case ELM_TRANSIT_TWEEN_MODE_SINUSOIDAL:
355          transit->progress = ecore_animator_pos_map(transit->progress,
356                                                     ECORE_POS_MAP_SINUSOIDAL,
357                                                     transit->v1, 0);
358          break;
359       case ELM_TRANSIT_TWEEN_MODE_DIVISOR_INTERP:
360          transit->progress = ecore_animator_pos_map(transit->progress,
361                                                     ECORE_POS_MAP_DIVISOR_INTERP,
362                                                     transit->v1, transit->v2);
363          break;
364       case ELM_TRANSIT_TWEEN_MODE_BOUNCE:
365          transit->progress = ecore_animator_pos_map(transit->progress,
366                                                     ECORE_POS_MAP_BOUNCE,
367                                                     transit->v1, transit->v2);
368          break;
369       case ELM_TRANSIT_TWEEN_MODE_SPRING:
370          transit->progress = ecore_animator_pos_map(transit->progress,
371                                                     ECORE_POS_MAP_SPRING,
372                                                     transit->v1, transit->v2);
373          break;
374       default:
375          break;
376      }
377
378    /* Reverse? */
379    if (transit->repeat.reverse) transit->progress = 1 - transit->progress;
380
381    if (transit->time.duration > 0)
382      {
383         if (!_transit_animate_op(transit, transit->progress))
384           return ECORE_CALLBACK_CANCEL;
385      }
386
387    /* Not end. Keep going. */
388    if (elapsed_time < duration) return ECORE_CALLBACK_RENEW;
389
390    /* Repeat and reverse and time done! */
391    if ((transit->repeat.count >= 0) &&
392        (transit->repeat.current == transit->repeat.count) &&
393        ((!transit->auto_reverse) || transit->repeat.reverse))
394      {
395         transit->finished = EINA_TRUE;
396         elm_transit_del(transit);
397         return ECORE_CALLBACK_CANCEL;
398      }
399
400    /* Repeat Case */
401    if (!transit->auto_reverse || transit->repeat.reverse)
402      {
403         transit->repeat.current++;
404         transit->repeat.reverse = EINA_FALSE;
405      }
406    else transit->repeat.reverse = EINA_TRUE;
407
408    transit->time.begin = ecore_loop_time_get();
409
410    return ECORE_CALLBACK_RENEW;
411 }
412
413 static void
414 _recover_image_uv_by_y(Evas_Map *map, int iw, int ih)
415 {
416    evas_map_point_image_uv_set(map, 0, iw, 0);
417    evas_map_point_image_uv_set(map, 1, 0, 0);
418    evas_map_point_image_uv_set(map, 2, 0, ih);
419    evas_map_point_image_uv_set(map, 3, iw, ih);
420 }
421
422 static void
423 _recover_image_uv_by_x(Evas_Map *map, int iw, int ih)
424 {
425    evas_map_point_image_uv_set(map, 0, 0, ih);
426    evas_map_point_image_uv_set(map, 1, iw, ih);
427    evas_map_point_image_uv_set(map, 2, iw, 0);
428    evas_map_point_image_uv_set(map, 3, 0, 0);
429 }
430
431 static Eina_Bool
432 _recover_image_uv(Evas_Object *obj, Evas_Map *map, Eina_Bool revert, Eina_Bool by_x)
433 {
434    //Since the map is not proper for all types of objects,
435    //Need to handle uvs only for image objects
436    int iw, ih;
437    const char *type = evas_object_type_get(obj);
438    if ((!type) || (strcmp(type, "image"))) return EINA_FALSE;
439    if (evas_object_image_source_get(obj)) return EINA_FALSE;
440
441    evas_object_image_size_get(obj, &iw, &ih);
442
443    if (revert)
444      {
445         if (by_x)
446           _recover_image_uv_by_x(map, iw, ih);
447         else
448           _recover_image_uv_by_y(map, iw, ih);
449      }
450    else
451      {
452         evas_map_point_image_uv_set(map, 0, 0, 0);
453         evas_map_point_image_uv_set(map, 1, iw, 0);
454         evas_map_point_image_uv_set(map, 2, iw, ih);
455         evas_map_point_image_uv_set(map, 3, 0, ih);
456      }
457    return EINA_TRUE;
458 }
459
460 EAPI Elm_Transit *
461 elm_transit_add(void)
462 {
463    Elm_Transit *transit = ELM_NEW(Elm_Transit);
464    if (!transit)
465      {
466         ERR("Failed to allocate a elm_transit object!");
467         return NULL;
468      }
469
470    EINA_MAGIC_SET(transit, ELM_TRANSIT_MAGIC);
471
472    elm_transit_tween_mode_set(transit, ELM_TRANSIT_TWEEN_MODE_LINEAR);
473
474    transit->v1 = 1.0;
475    transit->v2 = 0.0;
476    transit->smooth = EINA_TRUE;
477
478    return transit;
479 }
480
481 EAPI void
482 elm_transit_del(Elm_Transit *transit)
483 {
484    ELM_TRANSIT_CHECK_OR_RETURN(transit);
485
486    transit->deleted = EINA_TRUE;
487    if (transit->walking) return;
488    _transit_del(transit);
489 }
490
491 EAPI void
492 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)
493 {
494    ELM_TRANSIT_CHECK_OR_RETURN(transit);
495    EINA_SAFETY_ON_NULL_RETURN(transition_cb);
496    Elm_Transit_Effect_Module *effect_module;
497
498    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
499      if ((effect_module->transition_cb == transition_cb) && (effect_module->effect == effect))
500        {
501           WRN("elm_transit does not allow to add the duplicated effect! : transit=%p", transit);
502           return;
503        }
504
505    effect_module = ELM_NEW(Elm_Transit_Effect_Module);
506    if (!effect_module)
507      {
508         ERR("Failed to allocate a new effect!: transit=%p", transit);
509         return;
510      }
511
512    effect_module->end_cb = end_cb;
513    effect_module->transition_cb = transition_cb;
514    effect_module->effect = effect;
515
516    transit->effect_list = eina_inlist_append(transit->effect_list, (Eina_Inlist*) effect_module);
517 }
518
519 EAPI void
520 elm_transit_effect_del(Elm_Transit *transit, Elm_Transit_Effect_Transition_Cb transition_cb, Elm_Transit_Effect *effect)
521 {
522    ELM_TRANSIT_CHECK_OR_RETURN(transit);
523    EINA_SAFETY_ON_NULL_RETURN(transition_cb);
524    Elm_Transit_Effect_Module *effect_module;
525
526    EINA_INLIST_FOREACH(transit->effect_list, effect_module)
527      {
528         if ((effect_module->transition_cb == transition_cb) && (effect_module->effect == effect))
529           {
530              if (transit->walking)
531                {
532                   effect_module->deleted = EINA_TRUE;
533                   transit->effects_pending_del++;
534                }
535              else
536                {
537                   _transit_effect_del(transit, effect_module);
538                   if (!transit->effect_list) elm_transit_del(transit);
539                }
540              return;
541           }
542      }
543 }
544
545 EAPI void
546 elm_transit_object_add(Elm_Transit *transit, Evas_Object *obj)
547 {
548    ELM_TRANSIT_CHECK_OR_RETURN(transit);
549    EINA_SAFETY_ON_NULL_RETURN(obj);
550
551    if (transit->animator)
552      {
553         if (!evas_object_data_get(obj, _transit_key))
554           {
555              _transit_obj_data_update(transit, obj);
556              evas_object_freeze_events_set(obj, EINA_TRUE);
557           }
558      }
559
560    evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
561                                   _transit_obj_remove_cb,
562                                   transit);
563
564    transit->objs = eina_list_append(transit->objs, obj);
565 }
566
567 EAPI void
568 elm_transit_object_remove(Elm_Transit *transit, Evas_Object *obj)
569 {
570    ELM_TRANSIT_CHECK_OR_RETURN(transit);
571    EINA_SAFETY_ON_NULL_RETURN(obj);
572
573    _transit_obj_remove(transit, obj);
574    if (!transit->objs) elm_transit_del(transit);
575 }
576
577 EAPI const Eina_List *
578 elm_transit_objects_get(const Elm_Transit *transit)
579 {
580    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
581    return transit->objs;
582 }
583
584 EAPI void
585 elm_transit_smooth_set(Elm_Transit *transit, Eina_Bool smooth)
586 {
587    ELM_TRANSIT_CHECK_OR_RETURN(transit);
588    transit->smooth = !!smooth;
589 }
590
591 EAPI Eina_Bool
592 elm_transit_smooth_get(const Elm_Transit *transit)
593 {
594    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
595    return transit->smooth;
596 }
597
598 EAPI void
599 elm_transit_event_enabled_set(Elm_Transit *transit, Eina_Bool enabled)
600 {
601    ELM_TRANSIT_CHECK_OR_RETURN(transit);
602
603    Eina_List *list;
604    Evas_Object *obj;
605
606    if (transit->event_enabled == enabled) return;
607    transit->event_enabled = !!enabled;
608    if (!transit->animator) return;
609
610    EINA_LIST_FOREACH(transit->objs, list, obj)
611      evas_object_freeze_events_set(obj, enabled);
612 }
613
614 EAPI Eina_Bool
615 elm_transit_event_enabled_get(const Elm_Transit *transit)
616 {
617    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
618    return transit->event_enabled;
619 }
620
621 EAPI void
622 elm_transit_del_cb_set(Elm_Transit *transit, void (*cb) (void *data, Elm_Transit *transit), void *data)
623 {
624    ELM_TRANSIT_CHECK_OR_RETURN(transit);
625    transit->del_data.func = cb;
626    transit->del_data.arg = data;
627 }
628
629 EAPI void
630 elm_transit_auto_reverse_set(Elm_Transit *transit, Eina_Bool reverse)
631 {
632    ELM_TRANSIT_CHECK_OR_RETURN(transit);
633    transit->auto_reverse = reverse;
634 }
635
636 EAPI Eina_Bool
637 elm_transit_auto_reverse_get(const Elm_Transit *transit)
638 {
639    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
640    return transit->auto_reverse;
641 }
642
643 EAPI void
644 elm_transit_repeat_times_set(Elm_Transit *transit, int repeat)
645 {
646    ELM_TRANSIT_CHECK_OR_RETURN(transit);
647    transit->repeat.count = repeat;
648    transit->repeat.current = 0;
649 }
650
651 EAPI int
652 elm_transit_repeat_times_get(const Elm_Transit *transit)
653 {
654    ELM_TRANSIT_CHECK_OR_RETURN(transit, 0);
655    return transit->repeat.count;
656 }
657
658 EAPI void
659 elm_transit_tween_mode_set(Elm_Transit *transit, Elm_Transit_Tween_Mode tween_mode)
660 {
661    ELM_TRANSIT_CHECK_OR_RETURN(transit);
662    transit->tween_mode = tween_mode;
663 }
664
665 EAPI Elm_Transit_Tween_Mode
666 elm_transit_tween_mode_get(const Elm_Transit *transit)
667 {
668    ELM_TRANSIT_CHECK_OR_RETURN(transit, ELM_TRANSIT_TWEEN_MODE_LINEAR);
669    return transit->tween_mode;
670 }
671
672 EAPI void
673 elm_transit_tween_mode_factor_set(Elm_Transit *transit, double v1, double v2)
674 {
675    ELM_TRANSIT_CHECK_OR_RETURN(transit);
676    transit->v1 = v1;
677    transit->v2 = v2;
678 }
679
680 EAPI void
681 elm_transit_tween_mode_factor_get(const Elm_Transit *transit, double *v1, double *v2)
682 {
683    ELM_TRANSIT_CHECK_OR_RETURN(transit);
684    if (v1) *v1 = transit->v1;
685    if (v2) *v2 = transit->v2;
686 }
687
688 EAPI void
689 elm_transit_duration_set(Elm_Transit *transit, double duration)
690 {
691    ELM_TRANSIT_CHECK_OR_RETURN(transit);
692    if (transit->animator)
693      {
694         WRN("elm_transit does not allow to set the duration time in operating! : transit=%p", transit);
695         return;
696      }
697    transit->time.duration = duration;
698 }
699
700 EAPI double
701 elm_transit_duration_get(const Elm_Transit *transit)
702 {
703    ELM_TRANSIT_CHECK_OR_RETURN(transit, 0.0);
704    return transit->time.duration;
705 }
706
707 EAPI void
708 elm_transit_go(Elm_Transit *transit)
709 {
710    ELM_TRANSIT_CHECK_OR_RETURN(transit);
711
712    Eina_List *elist;
713    Evas_Object *obj;
714
715    if (transit->animator)
716      ecore_animator_del(transit->animator);
717
718    EINA_LIST_FOREACH(transit->objs, elist, obj)
719      _transit_obj_data_update(transit, obj);
720
721    if (!transit->event_enabled)
722      {
723         EINA_LIST_FOREACH(transit->objs, elist, obj)
724           evas_object_freeze_events_set(obj, EINA_TRUE);
725      }
726
727    transit->time.paused = 0;
728    transit->time.delayed = 0;
729    transit->time.begin = ecore_loop_time_get();
730    transit->animator = ecore_animator_add(_transit_animate_cb, transit);
731    _transit_animate_cb(transit);
732 }
733
734 EAPI void
735 elm_transit_paused_set(Elm_Transit *transit, Eina_Bool paused)
736 {
737    ELM_TRANSIT_CHECK_OR_RETURN(transit);
738
739    if (!transit->animator) return;
740
741    if (paused)
742      {
743         if (transit->time.paused > 0)
744           return;
745         ecore_animator_freeze(transit->animator);
746         transit->time.paused = ecore_loop_time_get();
747      }
748    else
749      {
750         if (transit->time.paused == 0)
751           return;
752         ecore_animator_thaw(transit->animator);
753         transit->time.delayed += (ecore_loop_time_get() - transit->time.paused);
754         transit->time.paused = 0;
755      }
756 }
757
758 EAPI Eina_Bool
759 elm_transit_paused_get(const Elm_Transit *transit)
760 {
761    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
762
763    if (transit->time.paused == 0)
764      return EINA_FALSE;
765
766    return EINA_TRUE;
767 }
768
769 EAPI double
770 elm_transit_progress_value_get(const Elm_Transit *transit)
771 {
772    ELM_TRANSIT_CHECK_OR_RETURN(transit, 0);
773
774    return transit->progress;
775 }
776
777 EAPI void
778 elm_transit_objects_final_state_keep_set(Elm_Transit *transit, Eina_Bool state_keep)
779 {
780    ELM_TRANSIT_CHECK_OR_RETURN(transit);
781
782    if (transit->state_keep == state_keep) return;
783    if (transit->animator)
784      {
785         WRN("elm_transit does not allow to change final state keep mode in operating! : transit=%p", transit);
786         return;
787      }
788    transit->state_keep = !!state_keep;
789 }
790
791 EAPI Eina_Bool
792 elm_transit_objects_final_state_keep_get(const Elm_Transit *transit)
793 {
794    ELM_TRANSIT_CHECK_OR_RETURN(transit, EINA_FALSE);
795    return transit->state_keep;
796 }
797
798 EAPI void
799 elm_transit_chain_transit_add(Elm_Transit *transit, Elm_Transit *chain_transit)
800 {
801    ELM_TRANSIT_CHECK_OR_RETURN(transit);
802    ELM_TRANSIT_CHECK_OR_RETURN(chain_transit);
803
804    if (transit == chain_transit)
805      {
806         WRN("You add a same transit as a chain transit! : transit=%p, chain_transit=%p", transit, chain_transit);
807         return;
808      }
809    if (transit == chain_transit->prev_chain_transit)
810      return;
811
812    if (chain_transit->prev_chain_transit)
813      chain_transit->prev_chain_transit->next_chain_transits = eina_list_remove(chain_transit->prev_chain_transit->next_chain_transits, chain_transit);
814
815    chain_transit->prev_chain_transit = transit;
816    transit->next_chain_transits = eina_list_append(transit->next_chain_transits, chain_transit);
817 }
818
819 EAPI void
820 elm_transit_chain_transit_del(Elm_Transit *transit, Elm_Transit *chain_transit)
821 {
822    ELM_TRANSIT_CHECK_OR_RETURN(transit);
823    ELM_TRANSIT_CHECK_OR_RETURN(chain_transit);
824
825    if (chain_transit->prev_chain_transit != transit)
826      {
827         WRN("A pair of transits does not have the chain relationship! : transit=%p, chain_transit=%p", transit, chain_transit);
828         return;
829      }
830
831    chain_transit->prev_chain_transit = NULL;
832    transit->next_chain_transits = eina_list_remove(transit->next_chain_transits, chain_transit);
833 }
834
835 EAPI Eina_List *
836 elm_transit_chain_transits_get(const Elm_Transit * transit)
837 {
838    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
839    return transit->next_chain_transits;
840 }
841
842 ///////////////////////////////////////////////////////////////////////////
843 //Resizing Effect
844 ///////////////////////////////////////////////////////////////////////////
845 typedef struct _Elm_Transit_Effect_Resizing Elm_Transit_Effect_Resizing;
846
847 struct _Elm_Transit_Effect_Resizing
848 {
849    struct _size {
850       Evas_Coord w, h;
851    } from, to;
852 };
853
854 static void
855 _transit_effect_resizing_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
856 {
857    Elm_Transit_Effect_Resizing *resizing = effect;
858    free(resizing);
859 }
860
861 static void
862 _transit_effect_resizing_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
863 {
864    EINA_SAFETY_ON_NULL_RETURN(effect);
865    EINA_SAFETY_ON_NULL_RETURN(transit);
866    Evas_Coord w, h;
867    Evas_Object *obj;
868    Eina_List *elist;
869    Elm_Transit_Effect_Resizing *resizing = effect;
870
871    w = resizing->from.w + (resizing->to.w * progress);
872    h = resizing->from.h + (resizing->to.h * progress);
873
874    EINA_LIST_FOREACH(transit->objs, elist, obj)
875      evas_object_resize(obj, w, h);
876 }
877
878 static Elm_Transit_Effect *
879 _transit_effect_resizing_context_new(Evas_Coord from_w, Evas_Coord from_h, Evas_Coord to_w, Evas_Coord to_h)
880 {
881    Elm_Transit_Effect_Resizing *resizing;
882
883    resizing = ELM_NEW(Elm_Transit_Effect_Resizing);
884    if (!resizing) return NULL;
885
886    resizing->from.w = from_w;
887    resizing->from.h = from_h;
888    resizing->to.w = to_w - from_w;
889    resizing->to.h = to_h - from_h;
890
891    return resizing;
892 }
893
894 EAPI Elm_Transit_Effect *
895 elm_transit_effect_resizing_add(Elm_Transit *transit, Evas_Coord from_w, Evas_Coord from_h, Evas_Coord to_w, Evas_Coord to_h)
896 {
897    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
898    Elm_Transit_Effect *effect = _transit_effect_resizing_context_new(from_w, from_h, to_w, to_h);
899
900    if (!effect)
901      {
902         ERR("Failed to allocate resizing effect! : transit=%p", transit);
903         return NULL;
904      }
905    elm_transit_effect_add(transit,
906                           _transit_effect_resizing_op, effect,
907                           _transit_effect_resizing_context_free);
908    return effect;
909 }
910
911 ///////////////////////////////////////////////////////////////////////////
912 //Translation Effect
913 ///////////////////////////////////////////////////////////////////////////
914 typedef struct _Elm_Transit_Effect_Translation Elm_Transit_Effect_Translation;
915 typedef struct _Elm_Transit_Effect_Translation_Node Elm_Transit_Effect_Translation_Node;
916
917 struct _Elm_Transit_Effect_Translation_Node
918 {
919    Evas_Object *obj;
920    Evas_Coord x, y;
921 };
922
923 struct _Elm_Transit_Effect_Translation
924 {
925    struct _position_variation {
926       Evas_Coord dx, dy;
927    } from, to;
928    Eina_List *nodes;
929 };
930
931 static void
932 _translation_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
933 {
934    Elm_Transit_Effect_Translation *translation = data;
935    Eina_List *elist;
936    Elm_Transit_Effect_Translation_Node *translation_node;
937
938    EINA_LIST_FOREACH(translation->nodes, elist, translation_node)
939      {
940         if (translation_node->obj != obj) continue;
941         translation->nodes = eina_list_remove_list(translation->nodes, elist);
942         free(translation_node);
943         break;
944      }
945 }
946
947 static Eina_List *
948 _translation_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_Translation *translation)
949 {
950    Elm_Transit_Effect_Translation_Node *translation_node;
951    const Eina_List *elist;
952    Evas_Object *obj;
953    Eina_List *data_list = NULL;
954    const Eina_List *objs = elm_transit_objects_get(transit);
955
956    EINA_LIST_FOREACH(objs, elist, obj)
957      {
958         translation_node = ELM_NEW(Elm_Transit_Effect_Translation_Node);
959         if (!translation_node)
960           {
961              eina_list_free(data_list);
962              return NULL;
963           }
964         translation_node->obj = obj;
965         evas_object_geometry_get(obj, &(translation_node->x),
966                                  &(translation_node->y), NULL, NULL);
967         data_list = eina_list_append(data_list, translation_node);
968         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
969                                        _translation_object_del_cb, translation);
970      }
971    return data_list;
972 }
973
974 void
975 _transit_effect_translation_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
976 {
977    EINA_SAFETY_ON_NULL_RETURN(effect);
978    Elm_Transit_Effect_Translation *translation = effect;
979    Eina_List *elist, *elist_next;
980    Elm_Transit_Effect_Translation_Node *translation_node;
981
982    EINA_LIST_FOREACH_SAFE(translation->nodes,
983                           elist, elist_next, translation_node)
984      {
985         evas_object_event_callback_del(translation_node->obj,
986                                        EVAS_CALLBACK_DEL, _translation_object_del_cb);
987         translation->nodes = eina_list_remove_list(translation->nodes, elist);
988         free(translation_node);
989      }
990    free(translation);
991 }
992
993 void
994 _transit_effect_translation_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress __UNUSED__)
995 {
996    EINA_SAFETY_ON_NULL_RETURN(effect);
997    EINA_SAFETY_ON_NULL_RETURN(transit);
998    Evas_Coord x, y;
999    Elm_Transit_Effect_Translation *translation = effect;
1000    Elm_Transit_Effect_Translation_Node *translation_node;
1001    Eina_List *elist;
1002
1003    if (!translation->nodes)
1004      translation->nodes = _translation_nodes_build(transit, translation);
1005
1006    EINA_LIST_FOREACH(translation->nodes, elist, translation_node)
1007      {
1008         x = translation_node->x + translation->from.dx
1009            + (translation->to.dx * progress);
1010         y = translation_node->y + translation->from.dy
1011            + (translation->to.dy * progress);
1012         evas_object_move(translation_node->obj, x, y);
1013      }
1014 }
1015
1016 static Elm_Transit_Effect *
1017 _transit_effect_translation_context_new(Evas_Coord from_dx, Evas_Coord from_dy, Evas_Coord to_dx, Evas_Coord to_dy)
1018 {
1019    Elm_Transit_Effect_Translation *translation;
1020
1021    translation = ELM_NEW(Elm_Transit_Effect_Translation);
1022    if (!translation) return NULL;
1023
1024    translation->from.dx = from_dx;
1025    translation->from.dy = from_dy;
1026    translation->to.dx = to_dx - from_dx;
1027    translation->to.dy = to_dy - from_dy;
1028
1029    return translation;
1030 }
1031
1032 EAPI Elm_Transit_Effect *
1033 elm_transit_effect_translation_add(Elm_Transit *transit, Evas_Coord from_dx, Evas_Coord from_dy, Evas_Coord to_dx, Evas_Coord to_dy)
1034 {
1035    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1036    Elm_Transit_Effect *effect = _transit_effect_translation_context_new(from_dx, from_dy, to_dx, to_dy);
1037
1038    if (!effect)
1039      {
1040         ERR("Failed to allocate translation effect! : transit=%p", transit);
1041         return NULL;
1042      }
1043    elm_transit_effect_add(transit,
1044                           _transit_effect_translation_op, effect,
1045                           _transit_effect_translation_context_free);
1046    return effect;
1047 }
1048
1049 ///////////////////////////////////////////////////////////////////////////
1050 //Zoom Effect
1051 ///////////////////////////////////////////////////////////////////////////
1052 typedef struct _Elm_Transit_Effect_Zoom Elm_Transit_Effect_Zoom;
1053
1054 struct _Elm_Transit_Effect_Zoom
1055 {
1056    float from, to;
1057 };
1058
1059 void
1060 _transit_effect_zoom_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1061 {
1062    Elm_Transit_Effect_Zoom *zoom = effect;
1063    free(zoom);
1064 }
1065
1066 static void
1067 _transit_effect_zoom_op(Elm_Transit_Effect *effect, Elm_Transit *transit , double progress)
1068 {
1069    EINA_SAFETY_ON_NULL_RETURN(effect);
1070    EINA_SAFETY_ON_NULL_RETURN(transit);
1071    Evas_Object *obj;
1072    Eina_List *elist;
1073    Elm_Transit_Effect_Zoom *zoom = effect;
1074    Evas_Map *map;
1075    Evas_Coord x, y, w, h;
1076
1077    map = evas_map_new(4);
1078    if (!map) return;
1079
1080    EINA_LIST_FOREACH(transit->objs, elist, obj)
1081      {
1082         evas_object_geometry_get(obj, &x, &y, &w, &h);
1083         evas_map_util_points_populate_from_object_full(map, obj, zoom->from +
1084                                                        (progress * zoom->to));
1085         _recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE);
1086         evas_map_util_3d_perspective(map, x + (w / 2), y + (h / 2), 0,
1087                                      _TRANSIT_FOCAL);
1088         if (!transit->smooth) evas_map_smooth_set(map, EINA_FALSE);
1089         evas_object_map_set(obj, map);
1090         evas_object_map_enable_set(obj, EINA_TRUE);
1091      }
1092    evas_map_free(map);
1093 }
1094
1095 static Elm_Transit_Effect *
1096 _transit_effect_zoom_context_new(float from_rate, float to_rate)
1097 {
1098    Elm_Transit_Effect_Zoom *zoom;
1099
1100    zoom = ELM_NEW(Elm_Transit_Effect_Zoom);
1101    if (!zoom) return NULL;
1102
1103    zoom->from = (_TRANSIT_FOCAL - (from_rate * _TRANSIT_FOCAL)) * (1 / from_rate);
1104    zoom->to = ((_TRANSIT_FOCAL - (to_rate * _TRANSIT_FOCAL)) * (1 / to_rate)) - zoom->from;
1105
1106    return zoom;
1107 }
1108
1109 EAPI Elm_Transit_Effect *
1110 elm_transit_effect_zoom_add(Elm_Transit *transit, float from_rate, float to_rate)
1111 {
1112    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1113    Elm_Transit_Effect *effect = _transit_effect_zoom_context_new(from_rate, to_rate);
1114
1115    if (!effect)
1116      {
1117         ERR("Failed to allocate zoom effect! : transit=%p", transit);
1118         return NULL;
1119      }
1120    elm_transit_effect_add(transit,
1121                           _transit_effect_zoom_op, effect,
1122                           _transit_effect_zoom_context_free);
1123    return effect;
1124 }
1125
1126 ///////////////////////////////////////////////////////////////////////////
1127 //Flip Effect
1128 ///////////////////////////////////////////////////////////////////////////
1129 typedef struct _Elm_Transit_Effect_Flip Elm_Transit_Effect_Flip;
1130
1131 struct _Elm_Transit_Effect_Flip
1132 {
1133    Elm_Transit_Effect_Flip_Axis axis;
1134    Eina_Bool cw : 1;
1135 };
1136
1137 static void
1138 _transit_effect_flip_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit)
1139 {
1140    EINA_SAFETY_ON_NULL_RETURN(effect);
1141    EINA_SAFETY_ON_NULL_RETURN(transit);
1142    Elm_Transit_Effect_Flip *flip = effect;
1143    Evas_Object *front, *back;
1144    int i;
1145    int count = eina_list_count(transit->objs);
1146
1147    for (i = 0; i < (count - 1); i += 2)
1148      {
1149         front = eina_list_nth(transit->objs, i);
1150         back = eina_list_nth(transit->objs, i+1);
1151         evas_object_map_enable_set(front, EINA_FALSE);
1152         evas_object_map_enable_set(back, EINA_FALSE);
1153      }
1154    free(flip);
1155 }
1156
1157 static void
1158 _transit_effect_flip_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
1159 {
1160    EINA_SAFETY_ON_NULL_RETURN(effect);
1161    EINA_SAFETY_ON_NULL_RETURN(transit);
1162    Evas_Object *obj, *front, *back;
1163    int count, i;
1164    Elm_Transit_Effect_Flip *flip = effect;
1165    Evas_Map *map;
1166    float degree;
1167    Evas_Coord x, y, w, h;
1168
1169    map = evas_map_new(4);
1170    if (!map) return;
1171
1172    if (flip->cw) degree = (float)(progress * 180);
1173    else degree = (float)(progress * -180);
1174
1175    count = eina_list_count(transit->objs);
1176
1177    for (i = 0; i < (count - 1); i += 2)
1178      {
1179         Evas_Coord half_w, half_h;
1180
1181         front = eina_list_nth(transit->objs, i);
1182         back = eina_list_nth(transit->objs, i+1);
1183
1184         if ((degree < 90) && (degree > -90))
1185           {
1186              obj = front;
1187              if (front != back)
1188                {
1189                   evas_object_hide(back);
1190                   evas_object_show(front);
1191                }
1192           }
1193         else
1194           {
1195              obj = back;
1196              if (front != back)
1197                {
1198                   evas_object_hide(front);
1199                   evas_object_show(back);
1200                }
1201           }
1202
1203         evas_map_util_points_populate_from_object_full(map, obj, 0);
1204         evas_object_geometry_get(obj, &x, &y, &w, &h);
1205         half_w = (w / 2);
1206         half_h = (h / 2);
1207
1208         if (flip->axis == ELM_TRANSIT_EFFECT_FLIP_AXIS_Y)
1209           {
1210              if ((degree >= 90) || (degree <= -90))
1211                {
1212                   if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_FALSE))
1213                     {
1214                        evas_map_point_image_uv_set(map, 0, w, 0);
1215                        evas_map_point_image_uv_set(map, 1, 0, 0);
1216                        evas_map_point_image_uv_set(map, 2, 0, h);
1217                        evas_map_point_image_uv_set(map, 3, w, h);
1218                     }
1219                }
1220              else
1221                _recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE);
1222              evas_map_util_3d_rotate(map, 0, degree,
1223                                      0, x + half_w, y + half_h, 0);
1224           }
1225         else
1226           {
1227              if ((degree >= 90) || (degree <= -90))
1228                {
1229                   if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_TRUE))
1230                     {
1231                        evas_map_point_image_uv_set(map, 0, 0, h);
1232                        evas_map_point_image_uv_set(map, 1, w, h);
1233                        evas_map_point_image_uv_set(map, 2, w, 0);
1234                        evas_map_point_image_uv_set(map, 3, 0, 0);
1235                     }
1236                }
1237              else
1238                _recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE);
1239              evas_map_util_3d_rotate(map, degree,
1240                                      0, 0, x + half_w, y + half_h, 0);
1241           }
1242         evas_map_util_3d_perspective(map, x + half_w, y + half_h, 0, _TRANSIT_FOCAL);
1243         evas_object_map_enable_set(front, EINA_TRUE);
1244         evas_object_map_enable_set(back, EINA_TRUE);
1245         if (!transit->smooth) evas_map_smooth_set(map, EINA_FALSE);
1246         evas_object_map_set(obj, map);
1247      }
1248    evas_map_free(map);
1249 }
1250
1251 static Elm_Transit_Effect *
1252 _transit_effect_flip_context_new(Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1253 {
1254    Elm_Transit_Effect_Flip *flip;
1255
1256    flip = ELM_NEW(Elm_Transit_Effect_Flip);
1257    if (!flip) return NULL;
1258
1259    flip->cw = cw;
1260    flip->axis = axis;
1261
1262    return flip;
1263 }
1264
1265 EAPI Elm_Transit_Effect *
1266 elm_transit_effect_flip_add(Elm_Transit *transit, Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1267 {
1268    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1269    Elm_Transit_Effect *effect = _transit_effect_flip_context_new(axis, cw);
1270
1271    if (!effect)
1272      {
1273         ERR("Failed to allocate flip effect! : transit=%p", transit);
1274         return NULL;
1275      }
1276    elm_transit_effect_add(transit,
1277                           _transit_effect_flip_op, effect,
1278                           _transit_effect_flip_context_free);
1279    return effect;
1280 }
1281
1282 ///////////////////////////////////////////////////////////////////////////
1283 //ResizableFlip Effect
1284 ///////////////////////////////////////////////////////////////////////////
1285 typedef struct _Elm_Transit_Effect_Resizable_Flip Elm_Transit_Effect_ResizableFlip;
1286 typedef struct _Elm_Transit_Effect_Resizable_Flip_Node Elm_Transit_Effect_ResizableFlip_Node;
1287
1288 struct _Elm_Transit_Effect_Resizable_Flip_Node
1289 {
1290    Evas_Object *front;
1291    Evas_Object *back;
1292    struct _vector2d {
1293       float x, y;
1294    } from_pos, from_size, to_pos, to_size;
1295 };
1296
1297 struct _Elm_Transit_Effect_Resizable_Flip
1298 {
1299    Eina_List *nodes;
1300    Eina_Bool cw : 1;
1301    Elm_Transit_Effect_Flip_Axis axis;
1302 };
1303
1304 static void
1305 _resizable_flip_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1306 {
1307    Elm_Transit_Effect_ResizableFlip *resizable_flip = data;
1308    Eina_List *elist;
1309    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1310
1311    EINA_LIST_FOREACH(resizable_flip->nodes, elist, resizable_flip_node)
1312      {
1313         if (resizable_flip_node->front == obj)
1314           evas_object_event_callback_del(resizable_flip_node->back,
1315                                          EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1316         else if (resizable_flip_node->back == obj)
1317           evas_object_event_callback_del(resizable_flip_node->front,
1318                                          EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1319         else continue;
1320
1321         resizable_flip->nodes = eina_list_remove_list(resizable_flip->nodes,
1322                                                       elist);
1323         free(resizable_flip_node);
1324         break;
1325      }
1326 }
1327
1328 static Eina_List *
1329 _resizable_flip_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_ResizableFlip *resizable_flip)
1330 {
1331    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1332    Eina_List *data_list = NULL;
1333    Evas_Coord front_x, front_y, front_w, front_h;
1334    Evas_Coord back_x, back_y, back_w, back_h;
1335    int i, count;
1336
1337    count = eina_list_count(transit->objs);
1338    for (i = 0; i < (count - 1); i += 2)
1339      {
1340         resizable_flip_node = ELM_NEW(Elm_Transit_Effect_ResizableFlip_Node);
1341         if (!resizable_flip_node)
1342           {
1343              eina_list_free(data_list);
1344              return NULL;
1345           }
1346
1347         resizable_flip_node->front = eina_list_nth(transit->objs, i);
1348         resizable_flip_node->back = eina_list_nth(transit->objs, i+1);
1349
1350         evas_object_geometry_get(resizable_flip_node->front,
1351                                  &front_x, &front_y, &front_w, &front_h);
1352         evas_object_geometry_get(resizable_flip_node->back,
1353                                  &back_x, &back_y, &back_w, &back_h);
1354
1355         resizable_flip_node->from_pos.x = front_x;
1356         resizable_flip_node->from_pos.y = front_y;
1357         resizable_flip_node->to_pos.x = back_x - front_x;
1358         resizable_flip_node->to_pos.y = back_y - front_y;
1359
1360         resizable_flip_node->from_size.x = front_w;
1361         resizable_flip_node->from_size.y = front_h;
1362         resizable_flip_node->to_size.x = back_w - front_w;
1363         resizable_flip_node->to_size.y = back_h - front_h;
1364
1365         data_list = eina_list_append(data_list, resizable_flip_node);
1366
1367         evas_object_event_callback_add(resizable_flip_node->back,
1368                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb, resizable_flip);
1369         evas_object_event_callback_add(resizable_flip_node->front,
1370                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb, resizable_flip);
1371      }
1372
1373    return data_list;
1374 }
1375
1376 static void
1377 _set_image_uv_by_axis_y(Evas_Map *map, Elm_Transit_Effect_ResizableFlip_Node *flip, Eina_Bool revert)
1378 {
1379    if (revert)
1380      {
1381         evas_map_point_image_uv_set(map, 0,
1382                                     (flip->from_size.x * 2) + flip->to_size.x,
1383                                     0);
1384         evas_map_point_image_uv_set(map, 1, 0, 0);
1385         evas_map_point_image_uv_set(map, 2, 0,
1386                                     (flip->from_size.y * 2) + flip->to_size.y);
1387         evas_map_point_image_uv_set(map, 3,
1388                                     (flip->from_size.x * 2) + flip->to_size.x,
1389                                     (flip->from_size.y * 2) + flip->to_size.y);
1390      }
1391    else
1392      {
1393         evas_map_point_image_uv_set(map, 0, 0, 0);
1394         evas_map_point_image_uv_set(map, 1, flip->from_size.x, 0);
1395         evas_map_point_image_uv_set(map, 2, flip->from_size.x,
1396                                     flip->from_size.y);
1397         evas_map_point_image_uv_set(map, 3, 0, flip->from_size.y);
1398      }
1399 }
1400
1401 static void
1402 _set_image_uv_by_axis_x(Evas_Map *map, Elm_Transit_Effect_ResizableFlip_Node *flip, Eina_Bool revert)
1403 {
1404    if (revert)
1405      {
1406         evas_map_point_image_uv_set(map, 0, 0,
1407                                     (flip->from_size.y * 2) + flip->to_size.y);
1408         evas_map_point_image_uv_set(map, 1,
1409                                     (flip->from_size.x * 2) + flip->to_size.x,
1410                                     (flip->from_size.y * 2) + flip->to_size.y);
1411         evas_map_point_image_uv_set(map, 2,
1412                                     (flip->from_size.x * 2) + flip->to_size.x,
1413                                     0);
1414         evas_map_point_image_uv_set(map, 3, 0, 0);
1415      }
1416    else
1417      {
1418         evas_map_point_image_uv_set(map, 0, 0, 0);
1419         evas_map_point_image_uv_set(map, 1, flip->from_size.x, 0);
1420         evas_map_point_image_uv_set(map, 2, flip->from_size.x,
1421                                     flip->from_size.y);
1422         evas_map_point_image_uv_set(map, 3, 0, flip->from_size.y);
1423      }
1424 }
1425
1426 void
1427 _transit_effect_resizable_flip_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1428 {
1429    EINA_SAFETY_ON_NULL_RETURN(effect);
1430
1431    Elm_Transit_Effect_ResizableFlip *resizable_flip = effect;
1432    Eina_List *elist, *elist_next;
1433    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1434
1435    EINA_LIST_FOREACH_SAFE(resizable_flip->nodes,
1436                           elist, elist_next, resizable_flip_node)
1437      {
1438         evas_object_map_enable_set(resizable_flip_node->front, EINA_FALSE);
1439         evas_object_map_enable_set(resizable_flip_node->back, EINA_FALSE);
1440
1441         resizable_flip->nodes = eina_list_remove_list(resizable_flip->nodes,
1442                                                       elist);
1443
1444         evas_object_event_callback_del(resizable_flip_node->back,
1445                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1446         evas_object_event_callback_del(resizable_flip_node->front,
1447                                        EVAS_CALLBACK_DEL, _resizable_flip_object_del_cb);
1448         free(resizable_flip_node);
1449      }
1450    free(resizable_flip);
1451 }
1452
1453 void
1454 _transit_effect_resizable_flip_op(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__, double progress)
1455 {
1456    EINA_SAFETY_ON_NULL_RETURN(effect);
1457    Evas_Map *map;
1458    Evas_Object *obj;
1459    float x, y, w, h;
1460    float degree;
1461    Evas_Coord half_w, half_h;
1462    Elm_Transit_Effect_ResizableFlip *resizable_flip = effect;
1463    Elm_Transit_Effect_ResizableFlip_Node *resizable_flip_node;
1464    Eina_List *elist;
1465
1466    map = evas_map_new(4);
1467    if (!map) return;
1468
1469    if (resizable_flip->cw) degree = (float)(progress * 180);
1470    else degree = (float)(progress * -180);
1471
1472    if (!resizable_flip->nodes)
1473      resizable_flip->nodes = _resizable_flip_nodes_build(transit,
1474                                                          resizable_flip);
1475
1476    EINA_LIST_FOREACH(resizable_flip->nodes, elist, resizable_flip_node)
1477      {
1478         if ((degree < 90) && (degree > -90))
1479           {
1480              obj = resizable_flip_node->front;
1481              if (resizable_flip_node->front != resizable_flip_node->back)
1482                {
1483                   evas_object_hide(resizable_flip_node->back);
1484                   evas_object_show(resizable_flip_node->front);
1485                }
1486           }
1487         else
1488           {
1489              obj = resizable_flip_node->back;
1490              if (resizable_flip_node->front != resizable_flip_node->back)
1491                {
1492                   evas_object_hide(resizable_flip_node->front);
1493                   evas_object_show(resizable_flip_node->back);
1494                }
1495           }
1496
1497         x = resizable_flip_node->from_pos.x +
1498            (resizable_flip_node->to_pos.x * progress);
1499         y = resizable_flip_node->from_pos.y +
1500            (resizable_flip_node->to_pos.y * progress);
1501         w = resizable_flip_node->from_size.x +
1502            (resizable_flip_node->to_size.x * progress);
1503         h = resizable_flip_node->from_size.y +
1504            (resizable_flip_node->to_size.y * progress);
1505         evas_map_point_coord_set(map, 0, x, y, 0);
1506         evas_map_point_coord_set(map, 1, x + w, y, 0);
1507         evas_map_point_coord_set(map, 2, x + w, y + h, 0);
1508         evas_map_point_coord_set(map, 3, x, y + h, 0);
1509
1510         half_w = (Evas_Coord)(w / 2);
1511         half_h = (Evas_Coord)(h / 2);
1512
1513         if (resizable_flip->axis == ELM_TRANSIT_EFFECT_FLIP_AXIS_Y)
1514           {
1515              if ((degree >= 90) || (degree <= -90))
1516                 {
1517                    if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_FALSE))
1518                      _set_image_uv_by_axis_y(map, resizable_flip_node,
1519                                              EINA_TRUE);
1520                 }
1521              else
1522                {
1523                   if (!_recover_image_uv(obj, map, EINA_FALSE, EINA_FALSE))
1524                     _set_image_uv_by_axis_y(map, resizable_flip_node,
1525                                             EINA_FALSE);
1526                }
1527              evas_map_util_3d_rotate(map, 0, degree,
1528                                      0, x + half_w, y + half_h, 0);
1529           }
1530         else
1531           {
1532              if ((degree >= 90) || (degree <= -90))
1533                 {
1534                    if (!_recover_image_uv(obj, map, EINA_TRUE, EINA_TRUE))
1535                      _set_image_uv_by_axis_x(map, resizable_flip_node,
1536                                              EINA_TRUE);
1537                 }
1538              else
1539                {
1540                    if (!_recover_image_uv(obj, map, EINA_FALSE, EINA_TRUE))
1541                      _set_image_uv_by_axis_x(map, resizable_flip_node,
1542                                              EINA_FALSE);
1543                }
1544              evas_map_util_3d_rotate(map, degree, 0,
1545                                      0, x + half_w, y + half_h, 0);
1546           }
1547
1548         evas_map_util_3d_perspective(map, x + half_w, y + half_h, 0,
1549                                      _TRANSIT_FOCAL);
1550         evas_object_map_enable_set(resizable_flip_node->front, EINA_TRUE);
1551         evas_object_map_enable_set(resizable_flip_node->back, EINA_TRUE);
1552         if (!transit->smooth) evas_map_smooth_set(map, EINA_FALSE);
1553         evas_object_map_set(obj, map);
1554      }
1555    evas_map_free(map);
1556 }
1557
1558 static Elm_Transit_Effect *
1559 _transit_effect_resizable_flip_context_new(Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1560 {
1561    Elm_Transit_Effect_ResizableFlip *resizable_flip;
1562
1563    resizable_flip = ELM_NEW(Elm_Transit_Effect_ResizableFlip);
1564    if (!resizable_flip) return NULL;
1565
1566    resizable_flip->cw = cw;
1567    resizable_flip->axis = axis;
1568
1569    return resizable_flip;
1570 }
1571
1572 EAPI Elm_Transit_Effect *
1573 elm_transit_effect_resizable_flip_add(Elm_Transit *transit, Elm_Transit_Effect_Flip_Axis axis, Eina_Bool cw)
1574 {
1575    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1576    Elm_Transit_Effect *effect = _transit_effect_resizable_flip_context_new(axis, cw);
1577
1578    if (!effect)
1579      {
1580         ERR("Failed to allocate resizable_flip effect! : transit=%p", transit);
1581         return NULL;
1582      }
1583    elm_transit_effect_add(transit,
1584                           _transit_effect_resizable_flip_op, effect,
1585                           _transit_effect_resizable_flip_context_free);
1586    return effect;
1587 }
1588
1589 ///////////////////////////////////////////////////////////////////////////
1590 //Wipe Effect
1591 ///////////////////////////////////////////////////////////////////////////
1592 typedef struct _Elm_Transit_Effect_Wipe Elm_Transit_Effect_Wipe;
1593
1594 struct _Elm_Transit_Effect_Wipe
1595 {
1596    Elm_Transit_Effect_Wipe_Type type;
1597    Elm_Transit_Effect_Wipe_Dir dir;
1598 };
1599
1600 static void
1601 _elm_fx_wipe_hide(Evas_Map * map, Elm_Transit_Effect_Wipe_Dir dir, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float progress)
1602 {
1603    Evas_Coord w2, h2;
1604
1605    switch (dir)
1606      {
1607       case ELM_TRANSIT_EFFECT_WIPE_DIR_LEFT:
1608          w2 = w - (w * progress);
1609          h2 = (y + h);
1610          evas_map_point_image_uv_set(map, 0, 0, 0);
1611          evas_map_point_image_uv_set(map, 1, w2, 0);
1612          evas_map_point_image_uv_set(map, 2, w2, h);
1613          evas_map_point_image_uv_set(map, 3, 0, h);
1614          evas_map_point_coord_set(map, 0, x, y, 0);
1615          evas_map_point_coord_set(map, 1, x + w2, y, 0);
1616          evas_map_point_coord_set(map, 2, x + w2, h2, 0);
1617          evas_map_point_coord_set(map, 3, x, h2, 0);
1618          break;
1619       case ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT:
1620          w2 = (w * progress);
1621          h2 = (y + h);
1622          evas_map_point_image_uv_set(map, 0, w2, 0);
1623          evas_map_point_image_uv_set(map, 1, w, 0);
1624          evas_map_point_image_uv_set(map, 2, w, h);
1625          evas_map_point_image_uv_set(map, 3, w2, h);
1626          evas_map_point_coord_set(map, 0, x + w2, y, 0);
1627          evas_map_point_coord_set(map, 1, x + w, y, 0);
1628          evas_map_point_coord_set(map, 2, x + w, h2, 0);
1629          evas_map_point_coord_set(map, 3, x + w2, h2, 0);
1630          break;
1631       case ELM_TRANSIT_EFFECT_WIPE_DIR_UP:
1632          w2 = (x + w);
1633          h2 = h - (h * progress);
1634          evas_map_point_image_uv_set(map, 0, 0, 0);
1635          evas_map_point_image_uv_set(map, 1, w, 0);
1636          evas_map_point_image_uv_set(map, 2, w, h2);
1637          evas_map_point_image_uv_set(map, 3, 0, h2);
1638          evas_map_point_coord_set(map, 0, x, y, 0);
1639          evas_map_point_coord_set(map, 1, w2, y, 0);
1640          evas_map_point_coord_set(map, 2, w2, y+h2, 0);
1641          evas_map_point_coord_set(map, 3, x, y+h2, 0);
1642          break;
1643       case ELM_TRANSIT_EFFECT_WIPE_DIR_DOWN:
1644          w2 = (x + w);
1645          h2 = (h * progress);
1646          evas_map_point_image_uv_set(map, 0, 0, h2);
1647          evas_map_point_image_uv_set(map, 1, w, h2);
1648          evas_map_point_image_uv_set(map, 2, w, h);
1649          evas_map_point_image_uv_set(map, 3, 0, h);
1650          evas_map_point_coord_set(map, 0, x, y + h2, 0);
1651          evas_map_point_coord_set(map, 1, w2, y + h2, 0);
1652          evas_map_point_coord_set(map, 2, w2, y + h, 0);
1653          evas_map_point_coord_set(map, 3, x, y + h, 0);
1654          break;
1655       default:
1656          break;
1657      }
1658    evas_map_util_3d_perspective(map, x + (w / 2), y + (h / 2), 0, _TRANSIT_FOCAL);
1659 }
1660
1661 static void
1662 _elm_fx_wipe_show(Evas_Map *map, Elm_Transit_Effect_Wipe_Dir dir, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float progress)
1663 {
1664    Evas_Coord w2, h2;
1665
1666    switch (dir)
1667      {
1668       case ELM_TRANSIT_EFFECT_WIPE_DIR_LEFT:
1669          w2 = (w - (w * progress));
1670          h2 = (y + h);
1671          evas_map_point_image_uv_set(map, 0, w2, 0);
1672          evas_map_point_image_uv_set(map, 1, w, 0);
1673          evas_map_point_image_uv_set(map, 2, w, h);
1674          evas_map_point_image_uv_set(map, 3, w2, h);
1675          evas_map_point_coord_set(map, 0, x + w2, y, 0);
1676          evas_map_point_coord_set(map, 1, w, y, 0);
1677          evas_map_point_coord_set(map, 2, w, h2, 0);
1678          evas_map_point_coord_set(map, 3, x + w2, h2, 0);
1679          break;
1680       case ELM_TRANSIT_EFFECT_WIPE_DIR_RIGHT:
1681          w2 = (w * progress);
1682          h2 = (y + h);
1683          evas_map_point_image_uv_set(map, 0, 0, 0);
1684          evas_map_point_image_uv_set(map, 1, w2, 0);
1685          evas_map_point_image_uv_set(map, 2, w2, h);
1686          evas_map_point_image_uv_set(map, 3, 0, h);
1687          evas_map_point_coord_set(map, 0, x, y, 0);
1688          evas_map_point_coord_set(map, 1, x + w2, y, 0);
1689          evas_map_point_coord_set(map, 2, x + w2, h2, 0);
1690          evas_map_point_coord_set(map, 3, x, h2, 0);
1691          break;
1692       case ELM_TRANSIT_EFFECT_WIPE_DIR_UP:
1693          w2 = (x + w);
1694          h2 = (h - (h * progress));
1695          evas_map_point_image_uv_set(map, 0, 0, h2);
1696          evas_map_point_image_uv_set(map, 1, w, h2);
1697          evas_map_point_image_uv_set(map, 2, w, h);
1698          evas_map_point_image_uv_set(map, 3, 0, h);
1699          evas_map_point_coord_set(map, 0, x, y + h2, 0);
1700          evas_map_point_coord_set(map, 1, w2, y + h2, 0);
1701          evas_map_point_coord_set(map, 2, w2, y + h, 0);
1702          evas_map_point_coord_set(map, 3, x, y + h, 0);
1703          break;
1704       case ELM_TRANSIT_EFFECT_WIPE_DIR_DOWN:
1705          w2 = (x + w);
1706          h2 = (h * progress);
1707          evas_map_point_image_uv_set(map, 0, 0, 0);
1708          evas_map_point_image_uv_set(map, 1, w, 0);
1709          evas_map_point_image_uv_set(map, 2, w, h2);
1710          evas_map_point_image_uv_set(map, 3, 0, h2);
1711          evas_map_point_coord_set(map, 0, x, y, 0);
1712          evas_map_point_coord_set(map, 1, w2, y, 0);
1713          evas_map_point_coord_set(map, 2, w2, y + h2, 0);
1714          evas_map_point_coord_set(map, 3, x, y + h2, 0);
1715          break;
1716       default:
1717          break;
1718      }
1719    evas_map_util_3d_perspective(map, x + (w / 2), y + (h / 2), 0, _TRANSIT_FOCAL);
1720 }
1721
1722 static void
1723 _transit_effect_wipe_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit)
1724 {
1725    EINA_SAFETY_ON_NULL_RETURN(effect);
1726    EINA_SAFETY_ON_NULL_RETURN(transit);
1727    Eina_List *elist;
1728    Evas_Object *obj;
1729    Elm_Transit_Effect_Wipe *wipe = effect;
1730    Eina_Bool reverse = elm_transit_auto_reverse_get(transit);
1731
1732    EINA_LIST_FOREACH(transit->objs, elist, obj)
1733      {
1734         if ((wipe->type == ELM_TRANSIT_EFFECT_WIPE_TYPE_SHOW && !reverse)
1735             || (wipe->type == ELM_TRANSIT_EFFECT_WIPE_TYPE_HIDE && reverse))
1736           evas_object_show(obj);
1737         else evas_object_hide(obj);
1738         evas_object_map_enable_set(obj, EINA_FALSE);
1739      }
1740
1741    free(wipe);
1742 }
1743
1744 static void
1745 _transit_effect_wipe_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
1746 {
1747    EINA_SAFETY_ON_NULL_RETURN(effect);
1748    EINA_SAFETY_ON_NULL_RETURN(transit);
1749    Elm_Transit_Effect_Wipe *wipe = effect;
1750    Evas_Map *map;
1751    Evas_Coord _x, _y, _w, _h;
1752    Eina_List *elist;
1753    Evas_Object *obj;
1754    const char *type;
1755
1756    map = evas_map_new(4);
1757    if (!map) return;
1758
1759    EINA_LIST_FOREACH(transit->objs, elist, obj)
1760      {
1761         type = evas_object_type_get(obj);
1762         if ((!type) || (strcmp(type, "image")) ||
1763             evas_object_image_source_get(obj))
1764           evas_object_geometry_get(obj, &_x, &_y, &_w, &_h);
1765         else
1766           {
1767              evas_object_image_size_get(obj, &_w, &_h);
1768              _x = 0;
1769              _y = 0;
1770           }
1771         if (wipe->type == ELM_TRANSIT_EFFECT_WIPE_TYPE_SHOW)
1772           _elm_fx_wipe_show(map, wipe->dir, _x, _y, _w, _h, (float)progress);
1773         else
1774           _elm_fx_wipe_hide(map, wipe->dir, _x, _y, _w, _h, (float)progress);
1775         if (!transit->smooth) evas_map_smooth_set(map, EINA_FALSE);
1776         evas_object_map_enable_set(obj, EINA_TRUE);
1777         evas_object_map_set(obj, map);
1778      }
1779    evas_map_free(map);
1780 }
1781
1782 static Elm_Transit_Effect *
1783 _transit_effect_wipe_context_new(Elm_Transit_Effect_Wipe_Type type, Elm_Transit_Effect_Wipe_Dir dir)
1784 {
1785    Elm_Transit_Effect_Wipe *wipe;
1786
1787    wipe = ELM_NEW(Elm_Transit_Effect_Wipe);
1788    if (!wipe) return NULL;
1789
1790    wipe->type = type;
1791    wipe->dir = dir;
1792
1793    return wipe;
1794 }
1795
1796 EAPI void *
1797 elm_transit_effect_wipe_add(Elm_Transit *transit, Elm_Transit_Effect_Wipe_Type type, Elm_Transit_Effect_Wipe_Dir dir)
1798 {
1799    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1800    void *effect = _transit_effect_wipe_context_new(type, dir);
1801
1802    if (!effect)
1803      {
1804         ERR("Failed to allocate wipe effect! : transit=%p", transit);
1805         return NULL;
1806      }
1807    elm_transit_effect_add(transit,
1808                           _transit_effect_wipe_op, effect,
1809                           _transit_effect_wipe_context_free);
1810    return effect;
1811 }
1812
1813 ///////////////////////////////////////////////////////////////////////////
1814 //Color Effect
1815 ///////////////////////////////////////////////////////////////////////////
1816 typedef struct _Elm_Transit_Effect_Color Elm_Transit_Effect_Color;
1817
1818 struct _Elm_Transit_Effect_Color
1819 {
1820    struct _unsigned_color {
1821       unsigned int r, g, b, a;
1822    } from;
1823    struct _signed_color {
1824       int r, g, b, a;
1825    } to;
1826 };
1827
1828 static void
1829 _transit_effect_color_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1830 {
1831    Elm_Transit_Effect_Color *color = effect;
1832    free(color);
1833 }
1834
1835 static void
1836 _transit_effect_color_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
1837 {
1838    EINA_SAFETY_ON_NULL_RETURN(effect);
1839    EINA_SAFETY_ON_NULL_RETURN(transit);
1840    Elm_Transit_Effect_Color *color = effect;
1841    Evas_Object *obj;
1842    Eina_List *elist;
1843    unsigned int r, g, b, a;
1844
1845    r = (color->from.r + (int)((float)color->to.r * progress));
1846    g = (color->from.g + (int)((float)color->to.g * progress));
1847    b = (color->from.b + (int)((float)color->to.b * progress));
1848    a = (color->from.a + (int)((float)color->to.a * progress));
1849
1850    EINA_LIST_FOREACH(transit->objs, elist, obj)
1851      evas_object_color_set(obj, r, g, b, a);
1852 }
1853
1854 static Elm_Transit_Effect *
1855 _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)
1856 {
1857    Elm_Transit_Effect_Color *color;
1858
1859    color = ELM_NEW(Elm_Transit_Effect_Color);
1860    if (!color) return NULL;
1861
1862    color->from.r = from_r;
1863    color->from.g = from_g;
1864    color->from.b = from_b;
1865    color->from.a = from_a;
1866    color->to.r = to_r - from_r;
1867    color->to.g = to_g - from_g;
1868    color->to.b = to_b - from_b;
1869    color->to.a = to_a - from_a;
1870
1871    return color;
1872 }
1873
1874 EAPI Elm_Transit_Effect *
1875 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)
1876 {
1877    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
1878    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);
1879
1880    if (!effect)
1881      {
1882         ERR("Failed to allocate color effect! : transit=%p", transit);
1883         return NULL;
1884      }
1885    elm_transit_effect_add(transit,
1886                           _transit_effect_color_op, effect,
1887                           _transit_effect_color_context_free);
1888    return effect;
1889 }
1890
1891 ///////////////////////////////////////////////////////////////////////////
1892 //Fade Effect
1893 ///////////////////////////////////////////////////////////////////////////
1894 typedef struct _Elm_Transit_Effect_Fade Elm_Transit_Effect_Fade;
1895 typedef struct _Elm_Transit_Effect_Fade_Node Elm_Transit_Effect_Fade_Node;
1896
1897 struct _Elm_Transit_Effect_Fade_Node
1898 {
1899    Evas_Object *before;
1900    Evas_Object *after;
1901    struct _signed_color before_color, after_color;
1902    int before_alpha;
1903    int after_alpha;
1904    Eina_Bool inversed : 1;
1905 };
1906
1907 struct _Elm_Transit_Effect_Fade
1908 {
1909    Eina_List *nodes;
1910 };
1911
1912 static void
1913 _fade_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1914 {
1915    Elm_Transit_Effect_Fade *fade = data;
1916    Eina_List *elist;
1917    Elm_Transit_Effect_Fade_Node *fade_node;
1918
1919    EINA_LIST_FOREACH(fade->nodes, elist, fade_node)
1920      {
1921         if (fade_node->before == obj)
1922           evas_object_event_callback_del(fade_node->after,
1923                                          EVAS_CALLBACK_DEL, _fade_object_del_cb);
1924         else if (fade_node->after == obj)
1925           evas_object_event_callback_del(fade_node->before,
1926                                          EVAS_CALLBACK_DEL, _fade_object_del_cb);
1927         else continue;
1928
1929         fade->nodes = eina_list_remove_list(fade->nodes, elist);
1930         free(fade_node);
1931         break;
1932      }
1933 }
1934
1935 static Eina_List *
1936 _fade_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_Fade *fade_data)
1937 {
1938    Elm_Transit_Effect_Fade_Node *fade;
1939    Eina_List *data_list = NULL;
1940    int i, count;
1941
1942    count = eina_list_count(transit->objs);
1943    for (i = 0; i < count; i += 2)
1944      {
1945         fade = ELM_NEW(Elm_Transit_Effect_Fade_Node);
1946         if (!fade)
1947           {
1948              eina_list_free(data_list);
1949              return NULL;
1950           }
1951
1952         fade->before = eina_list_nth(transit->objs, i);
1953         fade->after = eina_list_nth(transit->objs, i+1);
1954
1955         evas_object_color_get(fade->before,
1956                               &fade->before_color.r, &fade->before_color.g,
1957                               &fade->before_color.b, &fade->before_color.a);
1958         evas_object_color_get(fade->after,
1959                               &fade->after_color.r, &fade->after_color.g,
1960                               &fade->after_color.b, &fade->after_color.a);
1961
1962         fade->before_alpha = (255 - fade->before_color.a);
1963         fade->after_alpha = (255 - fade->after_color.a);
1964
1965         data_list = eina_list_append(data_list, fade);
1966
1967         evas_object_event_callback_add(fade->before,
1968                                        EVAS_CALLBACK_DEL, _fade_object_del_cb, fade_data);
1969         evas_object_event_callback_add(fade->after,
1970                                        EVAS_CALLBACK_DEL, _fade_object_del_cb, fade_data);
1971      }
1972    return data_list;
1973 }
1974
1975 static void
1976 _transit_effect_fade_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
1977 {
1978    EINA_SAFETY_ON_NULL_RETURN(effect);
1979    Elm_Transit_Effect_Fade *fade = effect;
1980    Elm_Transit_Effect_Fade_Node *fade_node;
1981    Eina_List *elist, *elist_next;
1982
1983    EINA_LIST_FOREACH_SAFE(fade->nodes, elist, elist_next, fade_node)
1984      {
1985         evas_object_color_set(fade_node->before, fade_node->before_color.r,
1986                               fade_node->before_color.g,
1987                               fade_node->before_color.b,
1988                               fade_node->before_color.a);
1989         evas_object_color_set(fade_node->after, fade_node->after_color.r,
1990                               fade_node->after_color.g,
1991                               fade_node->after_color.b,
1992                               fade_node->after_color.a);
1993
1994         fade->nodes = eina_list_remove_list(fade->nodes, elist);
1995         evas_object_event_callback_del(fade_node->before,
1996                                        EVAS_CALLBACK_DEL, _fade_object_del_cb);
1997         evas_object_event_callback_del(fade_node->after,
1998                                        EVAS_CALLBACK_DEL, _fade_object_del_cb);
1999         free(fade_node);
2000      }
2001
2002    free(fade);
2003 }
2004
2005 static void
2006 _transit_effect_fade_op(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__, double progress)
2007 {
2008    EINA_SAFETY_ON_NULL_RETURN(effect);
2009    Elm_Transit_Effect_Fade *fade = effect;
2010    Eina_List *elist;
2011    Elm_Transit_Effect_Fade_Node *fade_node;
2012    float _progress;
2013
2014    if (!fade->nodes)
2015      fade->nodes = _fade_nodes_build(transit, fade);
2016
2017    EINA_LIST_FOREACH(fade->nodes, elist, fade_node)
2018      {
2019         if (progress < 0.5)
2020           {
2021              if (!fade_node->inversed)
2022                {
2023                   evas_object_hide(fade_node->after);
2024                   evas_object_show(fade_node->before);
2025                   fade_node->inversed = EINA_TRUE;
2026                }
2027
2028              _progress = (1 - (progress * 2));
2029
2030              evas_object_color_set(fade_node->before,
2031                                    fade_node->before_color.r * _progress,
2032                                    fade_node->before_color.g * _progress,
2033                                    fade_node->before_color.b * _progress,
2034                                    fade_node->before_color.a +
2035                                    fade_node->before_alpha * (1 - _progress));
2036           }
2037         else
2038           {
2039              if (fade_node->inversed)
2040                {
2041                   evas_object_hide(fade_node->before);
2042                   evas_object_show(fade_node->after);
2043                   fade_node->inversed = EINA_FALSE;
2044                }
2045
2046              _progress = ((progress - 0.5) * 2);
2047
2048              evas_object_color_set(fade_node->after,
2049                                    fade_node->after_color.r * _progress,
2050                                    fade_node->after_color.g * _progress,
2051                                    fade_node->after_color.b * _progress,
2052                                    fade_node->after_color.a +
2053                                    fade_node->after_alpha * (1 - _progress));
2054           }
2055      }
2056 }
2057
2058 static Elm_Transit_Effect *
2059 _transit_effect_fade_context_new(void)
2060 {
2061    Elm_Transit_Effect_Fade *fade;
2062    fade = ELM_NEW(Elm_Transit_Effect_Fade);
2063    if (!fade) return NULL;
2064    return fade;
2065 }
2066
2067 EAPI Elm_Transit_Effect *
2068 elm_transit_effect_fade_add(Elm_Transit *transit)
2069 {
2070    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2071
2072    Elm_Transit_Effect *effect = _transit_effect_fade_context_new();
2073
2074    if (!effect)
2075      {
2076         ERR("Failed to allocate fade effect! : transit=%p", transit);
2077         return NULL;
2078      }
2079    elm_transit_effect_add(transit,
2080                           _transit_effect_fade_op, effect,
2081                           _transit_effect_fade_context_free);
2082    return effect;
2083 }
2084
2085 ///////////////////////////////////////////////////////////////////////////
2086 //Blend Effect
2087 ///////////////////////////////////////////////////////////////////////////
2088 typedef struct _Elm_Transit_Effect_Blend Elm_Transit_Effect_Blend;
2089 typedef struct _Elm_Transit_Effect_Blend_Node Elm_Transit_Effect_Blend_Node;
2090
2091 struct _Elm_Transit_Effect_Blend_Node
2092 {
2093    Evas_Object *before;
2094    Evas_Object *after;
2095    struct _signed_color from, to;
2096 };
2097
2098 struct _Elm_Transit_Effect_Blend
2099 {
2100    Eina_List *nodes;
2101 };
2102
2103 static void
2104 _blend_object_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
2105 {
2106    Elm_Transit_Effect_Blend *blend = data;
2107    Eina_List *elist;
2108    Elm_Transit_Effect_Blend_Node *blend_node;
2109
2110    EINA_LIST_FOREACH(blend->nodes, elist, blend_node)
2111      {
2112         if (blend_node->after == obj)
2113           evas_object_event_callback_del(blend_node->before,
2114                                          EVAS_CALLBACK_DEL, _blend_object_del_cb);
2115         else if (blend_node->before == obj)
2116           evas_object_event_callback_del(blend_node->after,
2117                                          EVAS_CALLBACK_DEL, _blend_object_del_cb);
2118         else continue;
2119
2120         blend->nodes = eina_list_remove_list(blend->nodes, elist);
2121         free(blend_node);
2122         break;
2123      }
2124 }
2125
2126 static Eina_List *
2127 _blend_nodes_build(Elm_Transit *transit, Elm_Transit_Effect_Blend *blend)
2128 {
2129    Elm_Transit_Effect_Blend_Node *blend_node;
2130    Eina_List *data_list = NULL;
2131    int i, count;
2132
2133    count = eina_list_count(transit->objs);
2134    for (i = 0; i < (count - 1); i += 2)
2135      {
2136         blend_node = ELM_NEW(Elm_Transit_Effect_Blend_Node);
2137         if (!blend_node)
2138           {
2139              eina_list_free(data_list);
2140              return NULL;
2141           }
2142
2143         blend_node->before = eina_list_nth(transit->objs, i);
2144         blend_node->after = eina_list_nth(transit->objs, i + 1);
2145         evas_object_show(blend_node->before);
2146         evas_object_show(blend_node->after);
2147
2148         evas_object_color_get(blend_node->before, &blend_node->from.r,
2149                               &blend_node->from.g, &blend_node->from.b,
2150                               &blend_node->from.a);
2151         evas_object_color_get(blend_node->after, &blend_node->to.r,
2152                               &blend_node->to.g, &blend_node->to.b,
2153                               &blend_node->to.a);
2154
2155         data_list = eina_list_append(data_list, blend_node);
2156
2157         evas_object_event_callback_add(blend_node->before,
2158                                        EVAS_CALLBACK_DEL, _blend_object_del_cb, blend);
2159         evas_object_event_callback_add(blend_node->after,
2160                                        EVAS_CALLBACK_DEL, _blend_object_del_cb, blend);
2161      }
2162    return data_list;
2163 }
2164
2165 void
2166 _transit_effect_blend_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
2167 {
2168    EINA_SAFETY_ON_NULL_RETURN(effect);
2169    Elm_Transit_Effect_Blend *blend = effect;
2170    Elm_Transit_Effect_Blend_Node *blend_node;
2171    Eina_List *elist, *elist_next;
2172
2173    EINA_LIST_FOREACH_SAFE(blend->nodes, elist, elist_next, blend_node)
2174      {
2175         evas_object_color_set(blend_node->before,
2176                               blend_node->from.r, blend_node->from.g,
2177                               blend_node->from.b, blend_node->from.a);
2178         evas_object_color_set(blend_node->after, blend_node->to.r,
2179                               blend_node->to.g, blend_node->to.b,
2180                               blend_node->to.a);
2181
2182         if (elm_transit_auto_reverse_get(transit))
2183           evas_object_hide(blend_node->after);
2184         else
2185           evas_object_hide(blend_node->before);
2186
2187         blend->nodes = eina_list_remove_list(blend->nodes, elist);
2188
2189         evas_object_event_callback_del(blend_node->before,
2190                                        EVAS_CALLBACK_DEL, _blend_object_del_cb);
2191         evas_object_event_callback_del(blend_node->after,
2192                                        EVAS_CALLBACK_DEL, _blend_object_del_cb);
2193         free(blend_node);
2194      }
2195    free(blend);
2196 }
2197
2198 void
2199 _transit_effect_blend_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
2200 {
2201    EINA_SAFETY_ON_NULL_RETURN(effect);
2202    EINA_SAFETY_ON_NULL_RETURN(transit);
2203    Elm_Transit_Effect_Blend *blend = effect;
2204    Elm_Transit_Effect_Blend_Node *blend_node;
2205    Eina_List *elist;
2206
2207    if (!blend->nodes) blend->nodes = _blend_nodes_build(transit, blend);
2208
2209    EINA_LIST_FOREACH(blend->nodes, elist, blend_node)
2210      {
2211         evas_object_color_set(blend_node->before,
2212                               (int)(blend_node->from.r * (1 - progress)),
2213                               (int)(blend_node->from.g * (1 - progress)),
2214                               (int)(blend_node->from.b * (1 - progress)),
2215                               (int)(blend_node->from.a * (1 - progress)));
2216         evas_object_color_set(blend_node->after,
2217                               (int)(blend_node->to.r * progress),
2218                               (int)(blend_node->to.g * progress),
2219                               (int)(blend_node->to.b * progress),
2220                               (int)(blend_node->to.a * progress));
2221      }
2222 }
2223
2224 static Elm_Transit_Effect *
2225 _transit_effect_blend_context_new(void)
2226 {
2227    Elm_Transit_Effect_Blend *blend;
2228
2229    blend = ELM_NEW(Elm_Transit_Effect_Blend);
2230    if (!blend) return NULL;
2231    return blend;
2232 }
2233
2234 EAPI Elm_Transit_Effect *
2235 elm_transit_effect_blend_add(Elm_Transit *transit)
2236 {
2237    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2238    Elm_Transit_Effect *effect = _transit_effect_blend_context_new();
2239
2240    if (!effect)
2241      {
2242         ERR("Failed to allocate blend effect! : transit=%p", transit);
2243         return NULL;
2244      }
2245    elm_transit_effect_add(transit,
2246                           _transit_effect_blend_op, effect,
2247                           _transit_effect_blend_context_free);
2248    return effect;
2249 }
2250
2251 ///////////////////////////////////////////////////////////////////////////
2252 //Rotation Effect
2253 ///////////////////////////////////////////////////////////////////////////
2254 typedef struct _Elm_Transit_Effect_Rotation Elm_Transit_Effect_Rotation;
2255
2256 struct _Elm_Transit_Effect_Rotation
2257 {
2258    float from, to;
2259 };
2260
2261 static void
2262 _transit_effect_rotation_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
2263 {
2264    Elm_Transit_Effect_Rotation *rotation = effect;
2265    free(rotation);
2266 }
2267
2268 static void
2269 _transit_effect_rotation_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
2270 {
2271    EINA_SAFETY_ON_NULL_RETURN(effect);
2272    EINA_SAFETY_ON_NULL_RETURN(transit);
2273    Elm_Transit_Effect_Rotation *rotation = effect;
2274    Evas_Map *map;
2275    Evas_Coord x, y, w, h;
2276    float degree;
2277    float half_w, half_h;
2278    Eina_List *elist;
2279    Evas_Object *obj;
2280
2281    map = evas_map_new(4);
2282    if (!map) return;
2283
2284    EINA_LIST_FOREACH(transit->objs, elist, obj)
2285      {
2286         evas_map_util_points_populate_from_object_full(map, obj, 0);
2287         degree = rotation->from + (float)(progress * rotation->to);
2288
2289         evas_object_geometry_get(obj, &x, &y, &w, &h);
2290
2291         half_w = (float)w * 0.5;
2292         half_h = (float)h * 0.5;
2293
2294         evas_map_util_rotate(map, degree, x + half_w, y + half_h);
2295         if (!transit->smooth) evas_map_smooth_set(map, EINA_FALSE);
2296         evas_object_map_enable_set(obj, EINA_TRUE);
2297         evas_object_map_set(obj, map);
2298      }
2299    evas_map_free(map);
2300 }
2301
2302 static Elm_Transit_Effect *
2303 _transit_effect_rotation_context_new(float from_degree, float to_degree)
2304 {
2305    Elm_Transit_Effect_Rotation *rotation;
2306
2307    rotation = ELM_NEW(Elm_Transit_Effect_Rotation);
2308    if (!rotation) return NULL;
2309
2310    rotation->from = from_degree;
2311    rotation->to = to_degree - from_degree;
2312
2313    return rotation;
2314 }
2315
2316 EAPI Elm_Transit_Effect *
2317 elm_transit_effect_rotation_add(Elm_Transit *transit, float from_degree, float to_degree)
2318 {
2319    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2320    Elm_Transit_Effect *effect = _transit_effect_rotation_context_new(from_degree, to_degree);
2321
2322    if (!effect)
2323      {
2324         ERR("Failed to allocate rotation effect! : transit=%p", transit);
2325         return NULL;
2326      }
2327    elm_transit_effect_add(transit,
2328                           _transit_effect_rotation_op, effect,
2329                           _transit_effect_rotation_context_free);
2330    return effect;
2331 }
2332
2333 ///////////////////////////////////////////////////////////////////////////
2334 //ImageAnimation Effect
2335 ///////////////////////////////////////////////////////////////////////////
2336 typedef struct _Elm_Transit_Effect_Image_Animation Elm_Transit_Effect_Image_Animation;
2337
2338 struct _Elm_Transit_Effect_Image_Animation
2339 {
2340    Eina_List *images;
2341    unsigned int prev_idx;
2342 };
2343
2344 static void
2345 _transit_effect_image_animation_context_free(Elm_Transit_Effect *effect, Elm_Transit *transit __UNUSED__)
2346 {
2347    EINA_SAFETY_ON_NULL_RETURN(effect);
2348    Elm_Transit_Effect_Image_Animation *image_animation = effect;
2349    const char *image;
2350    Eina_List *elist, *elist_next;
2351
2352    EINA_LIST_FOREACH_SAFE(image_animation->images, elist, elist_next, image)
2353      {
2354         image_animation->images =
2355            eina_list_remove_list(image_animation->images, elist);
2356         eina_stringshare_del(image);
2357      }
2358
2359    free(image_animation);
2360 }
2361
2362 static void
2363 _transit_effect_image_animation_op(Elm_Transit_Effect *effect, Elm_Transit *transit, double progress)
2364 {
2365    EINA_SAFETY_ON_NULL_RETURN(effect);
2366    EINA_SAFETY_ON_NULL_RETURN(transit);
2367    Eina_List *elist;
2368    Evas_Object *obj;
2369    const char *type, *type_deprecated;
2370    Elm_Transit_Effect_Image_Animation *image_animation = effect;
2371    unsigned int idx = 0;
2372    int len;
2373
2374    type = eina_stringshare_add("elm_image");
2375    //FIXME: Remove later when elm_icon is cleared.
2376    type_deprecated = eina_stringshare_add("elm_icon");
2377
2378    len = eina_list_count(image_animation->images);
2379    if (len)
2380      {
2381         idx = floor(progress * len);
2382         if (image_animation->prev_idx != idx)
2383           {
2384              EINA_LIST_FOREACH(transit->objs, elist, obj)
2385                {
2386                   if (elm_widget_type_check(obj, type, __func__) ||
2387                       elm_widget_type_check(obj, type_deprecated, __func__))
2388                     {
2389                        const char *file = eina_list_nth(image_animation->images,
2390                                                         idx);
2391
2392                        elm_image_file_set(obj, file, NULL);
2393                        elm_image_preload_disabled_set(obj, EINA_TRUE);
2394                     }
2395                }
2396           }
2397         image_animation->prev_idx = idx;
2398      }
2399
2400    eina_stringshare_del(type);
2401    eina_stringshare_del(type_deprecated);
2402 }
2403
2404 static Elm_Transit_Effect *
2405 _transit_effect_image_animation_context_new(Eina_List *images)
2406 {
2407    Elm_Transit_Effect_Image_Animation *image_animation;
2408    image_animation = ELM_NEW(Elm_Transit_Effect_Image_Animation);
2409
2410    if (!image_animation) return NULL;
2411    image_animation->images = images;
2412    image_animation->prev_idx = -1;
2413    return image_animation;
2414 }
2415
2416 EAPI Elm_Transit_Effect *
2417 elm_transit_effect_image_animation_add(Elm_Transit *transit, Eina_List *images)
2418 {
2419    ELM_TRANSIT_CHECK_OR_RETURN(transit, NULL);
2420    Elm_Transit_Effect *effect = _transit_effect_image_animation_context_new(images);
2421
2422    if (!effect)
2423      {
2424         ERR("Failed to allocate image_animation effect! : transit=%p", transit);
2425         return NULL;
2426      }
2427    elm_transit_effect_add(transit,
2428                           _transit_effect_image_animation_op, effect,
2429                           _transit_effect_image_animation_context_free);
2430    return effect;
2431 }