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