1 #include "e_efx_private.h"
2 
3 typedef struct E_Efx_Rotate_Data
4 {
5    E_EFX *e;
6    Ecore_Animator *anim;
7    E_Efx_Effect_Speed speed;
8    double start_degrees;
9    double degrees;
10    E_Efx_End_Cb cb;
11    void *data;
12 } E_Efx_Rotate_Data;
13 
14 static void
_obj_del(E_Efx_Rotate_Data * erd,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)15 _obj_del(E_Efx_Rotate_Data *erd, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
16 {
17    if (erd->anim) ecore_animator_del(erd->anim);
18    erd->e->rotate_data = NULL;
19    if ((!erd->e->owner) && (!erd->e->followers)) e_efx_free(erd->e);
20    free(erd);
21 }
22 
23 static Eina_Bool
_rotate_cb(E_Efx_Rotate_Data * erd,double pos)24 _rotate_cb(E_Efx_Rotate_Data *erd, double pos)
25 {
26    double degrees;
27    Eina_List *l;
28    E_EFX *e;
29 
30    degrees = ecore_animator_pos_map(pos, (Ecore_Pos_Map)erd->speed, 0, 0);
31    erd->e->map_data.rotation = degrees * erd->degrees + erd->start_degrees;
32    //DBG("erd->e->map_data.rotation=%g,erd->degrees=%g,erd->start_degrees=%g", erd->e->map_data.rotation, erd->degrees, erd->start_degrees);
33    e_efx_maps_apply(erd->e, erd->e->obj, NULL, E_EFX_MAPS_APPLY_ALL);
34    EINA_LIST_FOREACH(erd->e->followers, l, e)
35      e_efx_maps_apply(e, e->obj, NULL, E_EFX_MAPS_APPLY_ALL);
36 
37    if (pos < 1.0) return EINA_TRUE;
38 
39    erd->anim = NULL;
40    E_EFX_QUEUE_CHECK(erd);
41    return EINA_TRUE;
42 }
43 
44 static void
_rotate_stop(Evas_Object * obj,Eina_Bool reset)45 _rotate_stop(Evas_Object *obj, Eina_Bool reset)
46 {
47    E_EFX *e;
48    E_Efx_Rotate_Data *erd;
49 
50    e = evas_object_data_get(obj, "e_efx-data");
51    if ((!e) || (!e->rotate_data)) return;
52    erd = e->rotate_data;
53    if (reset)
54      {
55         erd->start_degrees = 0;
56         _rotate_cb(erd, 0);
57         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, erd);
58         erd->e->map_data.rotation = 0;
59         if (e_efx_queue_complete(erd->e, erd))
60           e_efx_queue_process(erd->e);
61         _obj_del(erd, NULL, NULL, NULL);
62         INF("reset rotating object %p", obj);
63      }
64    else
65      {
66         if (erd->anim) ecore_animator_del(erd->anim);
67         erd->anim = NULL;
68         INF("stopped rotating object %p", obj);
69         if (e_efx_queue_complete(erd->e, erd))
70           e_efx_queue_process(erd->e);
71      }
72 }
73 
74 void
_e_efx_rotate_calc(void * data,void * owner,Evas_Object * obj,Evas_Map * map)75 _e_efx_rotate_calc(void *data, void *owner, Evas_Object *obj, Evas_Map *map)
76 {
77    E_Efx_Rotate_Data *erd = data;
78    E_Efx_Rotate_Data *erd2 = owner;
79    e_efx_rotate_helper(erd2 ? erd2->e : (erd ? erd->e : NULL), obj, map, (erd ? erd->e->map_data.rotation : 0) + (erd2 ? erd2->e->map_data.rotation : 0));
80 }
81 
82 EAPI Eina_Bool
e_efx_rotate(Evas_Object * obj,E_Efx_Effect_Speed speed,double degrees,const Evas_Point * center,double total_time,E_Efx_End_Cb cb,const void * data)83 e_efx_rotate(Evas_Object *obj, E_Efx_Effect_Speed speed, double degrees, const Evas_Point *center, double total_time, E_Efx_End_Cb cb, const void *data)
84 {
85    E_EFX *e;
86    E_Efx_Rotate_Data *erd;
87 
88    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
89    if (eina_dbl_exact(degrees, 0)) return EINA_FALSE;
90    if (total_time < 0.0) return EINA_FALSE;
91    if (speed > E_EFX_EFFECT_SPEED_SINUSOIDAL) return EINA_FALSE;
92    /* can't rotate a spinning object, so we stop it first */
93    e = evas_object_data_get(obj, "e_efx-data");
94    if (e)
95      {
96         if (e->spin_data) e_efx_spin_stop(obj);
97         if (e->rotate_data)
98           {
99              erd = e->rotate_data;
100              if (erd->anim) e_efx_rotate_stop(obj);
101           }
102      }
103    else
104      {
105          e = e_efx_new(obj);
106          EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE);
107      }
108 
109    if (!e_efx_rotate_center_init(e, center)) return EINA_FALSE;
110    INF("rotate: %p - %g degrees over %gs: %s", obj, degrees, total_time, e_efx_speed_str[speed]);
111    if (!e->rotate_data)
112      {
113         e->rotate_data = calloc(1, sizeof(E_Efx_Rotate_Data));
114         EINA_SAFETY_ON_NULL_RETURN_VAL(e->rotate_data, EINA_FALSE);
115         evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->rotate_data);
116      }
117    erd = e->rotate_data;
118    erd->e = e;
119    erd->speed = speed;
120    erd->degrees = degrees;
121    erd->start_degrees = e->map_data.rotation;
122    erd->cb = cb;
123    erd->data = (void*)data;
124    if (eina_dbl_exact(total_time, 0))
125      {
126         e->map_data.rotation += degrees;
127         _rotate_cb(erd, 1.0);
128         return EINA_TRUE;
129      }
130    if (erd->anim) ecore_animator_del(erd->anim);
131    erd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_rotate_cb, erd);
132    return EINA_TRUE;
133 }
134 
135 EAPI void
e_efx_rotate_reset(Evas_Object * obj)136 e_efx_rotate_reset(Evas_Object *obj)
137 {
138    _rotate_stop(obj, EINA_TRUE);
139 }
140 
141 EAPI void
e_efx_rotate_stop(Evas_Object * obj)142 e_efx_rotate_stop(Evas_Object *obj)
143 {
144    _rotate_stop(obj, EINA_FALSE);
145 }
146