1 #include "e_efx_private.h"
2 
3 typedef enum
4 {
5    NONE,
6    TOP_RIGHT,
7    BOTTOM_LEFT,
8    BOTTOM_RIGHT
9 } Anchor;
10 
11 typedef struct E_Efx_Resize_Data
12 {
13    E_EFX *e;
14    E_Efx_Effect_Speed speed;
15    Ecore_Animator *anim;
16    int w, h;
17    int start_w, start_h;
18    E_Efx_End_Cb cb;
19    void *data;
20    Anchor anchor_type;
21    Evas_Point anchor;
22    Eina_Bool moving : 1;
23 } E_Efx_Resize_Data;
24 
25 static void
_obj_del(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)26 _obj_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
27 {
28    E_Efx_Resize_Data *erd = data;
29 
30    if (erd->anim) ecore_animator_del(erd->anim);
31    erd->e->resize_data = NULL;
32    if ((!erd->e->owner) && (!erd->e->followers)) e_efx_free(erd->e);
33    free(erd);
34 }
35 
36 static void
_resize_anchor(E_Efx_Resize_Data * erd)37 _resize_anchor(E_Efx_Resize_Data *erd)
38 {
39    int x = 0, y = 0;
40    int cx, cy;
41 
42    if (!erd->anchor_type) return;
43 
44    _e_efx_resize_adjust(erd->e, &x, &y);
45    if ((!x) && (!y)) return;
46 
47    if (erd->e->move_data)
48      cx = erd->e->x, cy = erd->e->y;
49    else
50      evas_object_geometry_get(erd->e->obj, &cx, &cy, NULL, NULL);
51    x += cx, y += cy;
52    evas_object_move(erd->e->obj, x, y);
53 }
54 
55 static Eina_Bool
_resize_cb(E_Efx_Resize_Data * erd,double pos)56 _resize_cb(E_Efx_Resize_Data *erd, double pos)
57 {
58    double factor;
59 
60    if (pos < 1.0)
61      {
62         int w, h;
63 
64         factor = ecore_animator_pos_map(pos, (Ecore_Pos_Map)erd->speed, 0, 0);
65         w = lround(factor * (erd->w - erd->start_w)) + erd->start_w;
66         h = lround(factor * (erd->h - erd->start_h)) + erd->start_h;
67         //DBG("%p to (%dx%d)", erd->e->obj, w, h);
68         erd->e->w = w, erd->e->h = h;
69         evas_object_resize(erd->e->obj, w, h);
70         _resize_anchor(erd);
71         return EINA_TRUE;
72      }
73    /* lround will usually be off by 1 at the end, so we manually set this here */
74    erd->e->w = erd->w, erd->e->h = erd->h;
75    evas_object_resize(erd->e->obj, erd->w, erd->h);
76    _resize_anchor(erd);
77 
78    erd->anim = NULL;
79    E_EFX_QUEUE_CHECK(erd);
80    return EINA_TRUE;
81 }
82 
83 static void
_resize_stop(Evas_Object * obj,Eina_Bool reset)84 _resize_stop(Evas_Object *obj, Eina_Bool reset)
85 {
86    E_EFX *e;
87    E_Efx_Resize_Data *erd;
88 
89    e = evas_object_data_get(obj, "e_efx-data");
90    if ((!e) || (!e->resize_data)) return;
91    erd = e->resize_data;
92    if (reset)
93      {
94         erd->e->w = erd->start_w, erd->e->h = erd->start_h;
95         evas_object_resize(obj, erd->start_w, erd->start_h);
96         evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, erd);
97         if (erd->moving)
98           {
99              erd->moving = 0;
100              e_efx_move_reset(obj);
101           }
102         else if (e_efx_queue_complete(erd->e, erd))
103           e_efx_queue_process(erd->e);
104         _obj_del(erd, NULL, NULL, NULL);
105         INF("reset resized object %p", obj);
106      }
107    else
108      {
109         INF("stopped resized object %p", obj);
110         if (erd->anim) ecore_animator_del(erd->anim);
111         erd->anim = NULL;
112         if (erd->moving)
113           {
114              erd->moving = 0;
115              e_efx_move_stop(obj);
116           }
117         if (e_efx_queue_complete(erd->e, erd))
118           e_efx_queue_process(erd->e);
119      }
120 }
121 
122 void
_e_efx_resize_adjust(E_EFX * e,int * ax,int * ay)123 _e_efx_resize_adjust(E_EFX *e, int *ax, int *ay)
124 {
125    E_Efx_Resize_Data *erd = e->resize_data;
126    int x, y, w, h;
127 
128    if ((!erd) || (!erd->anim)) return;
129    if (e->move_data)
130      x = e->x, y = e->y;
131    else
132      evas_object_geometry_get(e->obj, &x, &y, NULL, NULL);
133    w = e->w, h = e->h;
134    switch (erd->anchor_type)
135      {
136       case TOP_RIGHT:
137         *ax = erd->anchor.x - (x + w);
138         *ay = erd->anchor.y - y;
139         break;
140       case BOTTOM_LEFT:
141         *ax = erd->anchor.x - x;
142         *ay = erd->anchor.y - (y + h);
143         break;
144       case BOTTOM_RIGHT:
145         *ax = erd->anchor.x - (x + w);
146         *ay = erd->anchor.y - (y + h);
147         break;
148       default: break;
149      }
150 }
151 
152 EAPI Eina_Bool
e_efx_resize(Evas_Object * obj,E_Efx_Effect_Speed speed,const Evas_Point * position,int w,int h,double total_time,E_Efx_End_Cb cb,const void * data)153 e_efx_resize(Evas_Object *obj, E_Efx_Effect_Speed speed, const Evas_Point *position, int w, int h, double total_time, E_Efx_End_Cb cb, const void *data)
154 {
155    E_EFX *e;
156    E_Efx_Resize_Data *erd;
157    int x, y;
158 
159    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
160    EINA_SAFETY_ON_TRUE_RETURN_VAL(w < 0, EINA_FALSE);
161    EINA_SAFETY_ON_TRUE_RETURN_VAL(h < 0, EINA_FALSE);
162    e = evas_object_data_get(obj, "e_efx-data");
163    if (!e) e = e_efx_new(obj);
164    EINA_SAFETY_ON_NULL_RETURN_VAL(e, EINA_FALSE);
165    erd = e->resize_data;
166    if (!erd)
167      {
168         e->resize_data = erd = calloc(1, sizeof(E_Efx_Resize_Data));
169         EINA_SAFETY_ON_NULL_RETURN_VAL(erd, EINA_FALSE);
170         evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->resize_data);
171      }
172 
173    erd->e = e;
174    erd->anchor_type = NONE;
175    erd->w = w;
176    erd->h = h;
177    erd->cb = cb;
178    erd->data = (void*)data;
179    evas_object_geometry_get(obj, &x, &y, &erd->start_w, &erd->start_h);
180    e->w = erd->start_w;
181    e->h = erd->start_h;
182    if (e->move_data)
183      x = e->x, y = e->y;
184    INF("resize: %p || %dx%d => %dx%d %s over %gs", obj, erd->start_w, erd->start_h, w, h, e_efx_speed_str[speed], total_time);
185    if (position)
186      {
187         if ((position->x != x) || (position->y != y))
188           {
189              Evas_Point tr, bl, br;
190              Evas_Point atr, abl, abr;
191 
192              tr = (Evas_Point){x + erd->start_w, y};
193              bl = (Evas_Point){x, y + erd->start_h};
194              br = (Evas_Point){x + erd->start_w, y + erd->start_h};
195              atr = (Evas_Point){position->x + w, position->y};
196              abl = (Evas_Point){position->x, position->y + h};
197              abr = (Evas_Point){position->x + w, position->y + h};
198              if (!memcmp(&tr, &atr, sizeof(Evas_Point)))
199                {
200                   erd->anchor_type = TOP_RIGHT;
201                   erd->anchor = tr;
202                }
203              else if (!memcmp(&bl, &abl, sizeof(Evas_Point)))
204                {
205                   erd->anchor_type = BOTTOM_LEFT;
206                   erd->anchor = bl;
207                }
208              else if (!memcmp(&br, &abr, sizeof(Evas_Point)))
209                {
210                   erd->anchor_type = BOTTOM_RIGHT;
211                   erd->anchor = br;
212                }
213 
214              if (!e_efx_move(obj, speed, position, total_time, NULL, NULL))
215                {
216                   evas_object_event_callback_del_full(obj, EVAS_CALLBACK_FREE, (Evas_Object_Event_Cb)_obj_del, e->resize_data);
217                   free(erd);
218                   e->resize_data = NULL;
219                   e_efx_free(e);
220                   return EINA_FALSE;
221                }
222              else
223                erd->moving = 1;
224           }
225         else
226           evas_object_move(obj, position->x, position->y);
227      }
228    if (!eina_dbl_exact(total_time, 0))
229      erd->anim = ecore_animator_timeline_add(total_time, (Ecore_Timeline_Cb)_resize_cb, erd);
230    else
231      _resize_cb(erd, 1.0);
232 
233    return EINA_TRUE;
234 }
235 
236 EAPI void
e_efx_resize_reset(Evas_Object * obj)237 e_efx_resize_reset(Evas_Object *obj)
238 {
239    _resize_stop(obj, EINA_TRUE);
240 }
241 
242 EAPI void
e_efx_resize_stop(Evas_Object * obj)243 e_efx_resize_stop(Evas_Object *obj)
244 {
245    _resize_stop(obj, EINA_FALSE);
246 }
247