[Elementary.h.in] added elm_animator_pause, elm_animator_resume
[framework/uifw/elementary.git] / src / lib / elm_animator.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @addtogroup Animator Animator
6  * @ingroup Elementary
7  *
8  * Support normalized frame value for animation.  
9 */
10 #define MAGIC_OBJ_ANIMATOR 0x40777770
11
12 struct _Animator
13 {
14    Evas_Object *parent;
15    Ecore_Animator *animator;
16    double begin_time;
17    double cur_time;
18    double duration;
19    unsigned int repeat_cnt;
20    unsigned int cur_repeat_cnt;
21    double (*curve_op) (double frame);
22    void (*animator_op) (void *data, Elm_Animator *animator, double frame);
23    void *animator_arg;
24    void (*completion_op) (void *data);
25    void *completion_arg;
26    int magic;
27    Eina_Bool auto_reverse:1;
28    Eina_Bool on_animating:1;
29 };
30
31 static double _animator_curve_linear(double frame);
32 static double _animator_curve_in_out(double frame);
33 static double _animator_curve_in(double frame);
34 static double _animator_curve_out(double frame);
35 static unsigned int _animator_compute_reverse_repeat_count(unsigned int cnt);
36 static unsigned int _animator_compute_no_reverse_repeat_count(unsigned int cnt);
37 static Eina_Bool _animator_animate_cb(void *data);
38 static void _delete_animator(Elm_Animator *animator);
39 static void _animator_parent_del(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__);
40
41 static unsigned int
42 _animator_compute_reverse_repeat_count(unsigned int cnt)
43 {
44    return ((cnt + 1) * 2) - 1;
45 }
46
47 static unsigned int
48 _animator_compute_no_reverse_repeat_count(unsigned int cnt)
49 {
50    return cnt / 2;
51 }
52
53 static double
54 _animator_curve_linear(double frame)
55 {
56    return frame;
57 }
58
59 static double
60 _animator_curve_in_out(double frame)
61 {
62    if (frame < 0.5)
63       return _animator_curve_in(frame * 2) * 0.5;
64    else
65       return (_animator_curve_out(frame * 2 - 1) * 0.5) + 0.5;
66 }
67
68 static double
69 _animator_curve_in(double frame)
70 {
71    return 1 - sqrt(1 - pow(frame, 2));
72 }
73
74 static double
75 _animator_curve_out(double frame)
76 {
77    return sqrt(1 - pow(frame - 1, 2));
78 }
79
80 static void
81 _delete_animator(Elm_Animator *animator)
82 {
83         if (animator->animator)
84      {
85                  ecore_animator_del(animator->animator);
86                 animator->animator = NULL;
87      }
88 }
89
90 static Eina_Bool
91 _animator_animate_cb(void *data)
92 {
93    Elm_Animator *animator = (Elm_Animator *) data;
94    double elapsed_time, frame;
95
96    animator->cur_time = ecore_loop_time_get();
97
98    elapsed_time = animator->cur_time - animator->begin_time;
99
100    if(elapsed_time > animator->duration)
101            elapsed_time = animator->duration;
102
103    frame = animator->curve_op(elapsed_time / animator->duration);
104
105    //Reverse?
106    if (animator->auto_reverse)
107      {
108         if ((animator->cur_repeat_cnt % 2) == 0)
109            frame = 1 - frame;
110      }
111
112    if (animator->duration > 0)
113       animator->animator_op(animator->animator_arg, animator, frame);
114
115    //Not end. Keep going.
116    if (elapsed_time < animator->duration)
117       return ECORE_CALLBACK_RENEW;
118
119    //Repeat and reverse and time done! 
120    if (animator->cur_repeat_cnt == 0)
121      {
122         animator->on_animating = EINA_FALSE;
123         _delete_animator(animator);
124         if (animator->completion_op)
125            animator->completion_op(animator->completion_arg);
126         return ECORE_CALLBACK_CANCEL;
127      }
128
129    //Repeat Case
130    --animator->cur_repeat_cnt;
131    animator->begin_time = ecore_loop_time_get();
132
133    return ECORE_CALLBACK_RENEW;
134 }
135
136 static void
137 _animator_parent_del(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
138 {
139         Elm_Animator *animator = data; 
140         elm_animator_del(data);
141 }
142
143 /**
144  * Get the value of reverse mode. 
145  *
146  * @param animator Animator object
147  * @return EINA_TRUE is reverse mode 
148  *
149  * @ingroup Animator 
150  */
151 EAPI Eina_Bool
152 elm_animator_auto_reverse_get(Elm_Animator *animator)
153 {
154    if (animator->magic != MAGIC_OBJ_ANIMATOR)
155       return EINA_FALSE;
156    return animator->auto_reverse;
157 }
158
159 /**
160  * Get the value of repeat count.
161  *
162  * @param animator Animator object
163  * @return Repeat count
164  *
165  * @ingroup Animator 
166  */
167 EAPI unsigned int
168 elm_animator_repeat_get(Elm_Animator *animator)
169 {
170         if (animator->magic != MAGIC_OBJ_ANIMATOR)
171       return 0;
172    return animator->repeat_cnt;
173 }
174
175 /**
176  * Set auto reverse function.  
177  *
178  * @param animator Animator object
179  * @param reverse Reverse or not
180  * 
181  * @ingroup Animator 
182  */
183 EAPI void
184 elm_animator_auto_reverse_set(Elm_Animator *animator, Eina_Bool reverse)
185 {
186         if (animator->magic != MAGIC_OBJ_ANIMATOR)
187       return;
188    if (animator->auto_reverse == reverse)
189       return;
190    animator->auto_reverse = reverse;
191    if (reverse)
192       animator->repeat_cnt =
193          _animator_compute_reverse_repeat_count(animator->repeat_cnt);
194    else
195       animator->repeat_cnt =
196          _animator_compute_no_reverse_repeat_count(animator->repeat_cnt);
197 }
198
199 /**
200  * Set the animation acceleration style. 
201  *
202  * @param animator Animator object
203  * @param cs Curve style. Default is ELM_ANIMATOR_CURVE_LINEAR 
204  *
205  * @ingroup Animator
206  */
207 EAPI void
208 elm_animator_curve_style_set(Elm_Animator *animator,
209                              Elm_Animator_Curve_Style cs)
210 {
211         if (animator->magic != MAGIC_OBJ_ANIMATOR)
212       return;
213
214    switch (cs)
215      {
216      case ELM_ANIMATOR_CURVE_LINEAR:
217         animator->curve_op = _animator_curve_linear;
218         break;
219      case ELM_ANIMATOR_CURVE_IN_OUT:
220         animator->curve_op = _animator_curve_in_out;
221         break;
222      case ELM_ANIMATOR_CURVE_IN:
223         animator->curve_op = _animator_curve_in;
224         break;
225      case ELM_ANIMATOR_CURVE_OUT:
226         animator->curve_op = _animator_curve_out;
227         break;
228      default:
229         animator->curve_op = _animator_curve_linear;
230         break;
231      }
232 }
233
234 /**
235  * Set the operation duration.  
236  *
237  * @param animator Animator object
238  * @param duration Duration in second 
239  *
240  * @ingroup Animator
241  */
242 EAPI void
243 elm_animator_duration_set(Elm_Animator *animator, double duration)
244 {
245         if (animator->magic != MAGIC_OBJ_ANIMATOR)
246       return;
247    if (animator->on_animating)
248       return;
249    animator->duration = duration;
250 }
251
252 /**
253  * Set the callback function for animator operation.  
254  * The range of callback function frame data is to 0 ~ 1
255  * User can refer this frame value for one's animation frame data. 
256  * @param animator Animator object
257  * @param op Callback function pointer 
258  * @param data Callback function user argument 
259  *
260  * @ingroup Animator
261  */
262 EAPI void
263 elm_animator_operation_callback_set(Elm_Animator *animator,
264                                     void (*func) (void *data,
265                                                   Elm_Animator *animator,
266                                                   double frame), void *data)
267 {
268         if (animator->magic != MAGIC_OBJ_ANIMATOR)
269       return;
270    if (animator->on_animating)
271       return;
272    animator->animator_op = func;
273    animator->animator_arg = data;
274 }
275
276 /**
277  * Add new animator. 
278  *
279  * @param parent Parent object
280  * @return animator object 
281  *
282  * @ingroup Animator
283  */
284 EAPI Elm_Animator *
285 elm_animator_add(Evas_Object *parent)
286 {
287    Elm_Animator *animator = ELM_NEW(Elm_Animator);
288
289    if (!animator)
290       return NULL;
291
292    animator->parent = parent;
293    animator->magic = MAGIC_OBJ_ANIMATOR;
294
295    elm_animator_auto_reverse_set(animator, EINA_FALSE);
296    elm_animator_curve_style_set(animator, ELM_ANIMATOR_CURVE_LINEAR);
297
298    if (parent) {
299                 evas_object_event_callback_add(parent, EVAS_CALLBACK_DEL,
300                                      _animator_parent_del, animator);
301         }
302
303    return animator;
304 }
305
306 /**
307  * Get the status for the animator operation.
308  *
309  * @param animator Animator object 
310  * @return EINA_TRUE is animator is operating. 
311  *
312  * @ingroup Animator
313  */
314 EAPI Eina_Bool
315 elm_animator_operating_get(Elm_Animator *animator)
316 {
317         if (animator->magic != MAGIC_OBJ_ANIMATOR)
318       return EINA_FALSE;
319    return animator->on_animating;
320 }
321
322 /**
323  * Delete animator. 
324  *
325  * @param animator Animator object 
326  *
327  * @ingroup Animator
328  */
329 EAPI void
330 elm_animator_del(Elm_Animator *animator)
331 {
332    if(animator->magic != MAGIC_OBJ_ANIMATOR) {
333            return;
334    }
335
336         _delete_animator(animator);
337
338    if(animator->parent) {
339         evas_object_event_callback_del(animator->parent, EVAS_CALLBACK_DEL, _animator_parent_del);
340         }
341
342    memset(animator, 0x0, sizeof(Elm_Animator));
343    free(animator);
344 }
345
346 /**
347  * Set the callback function for the animator end.  
348  *
349  * @param  animator Animator object 
350  * @param  op Callback function pointer
351  * @param  data Callback function user argument 
352  *
353  * @ingroup Animator
354  */
355 EAPI void
356 elm_animator_completion_callback_set(Elm_Animator *animator,
357                                      void (*func) (void *data), void *data)
358 {
359         if (animator->magic != MAGIC_OBJ_ANIMATOR)
360       return;
361    if (animator->on_animating)
362       return;
363    animator->completion_op = func;
364    animator->completion_arg = data;
365 }
366
367 /**
368  * Pause the animator.
369  *
370  * @param  animator Animator object
371  *
372  * @ingroup Animator
373  */
374 EAPI void
375 elm_animator_pause(Elm_Animator *animator)
376 {
377         if (animator->magic != MAGIC_OBJ_ANIMATOR)
378                 return;
379
380         if(!animator->on_animating)
381                 return;
382
383         ecore_animator_freeze(animator->animator);
384 }
385
386 /**
387  * Resume the animator.
388  *
389  * @param  animator Animator object
390  *
391  * @ingroup Animator
392  */
393 EAPI void
394 elm_animator_resume(Elm_Animator *animator)
395 {
396         if (animator->magic != MAGIC_OBJ_ANIMATOR)
397                 return;
398
399         if(!animator->on_animating)
400                 return;
401
402         ecore_animator_thaw(animator->animator);
403 }
404
405 /**
406  * Stop animator.
407  *
408  * @param animator Animator object 
409  *
410  * @ingroup Animator
411  */
412 EAPI void
413 elm_animator_stop(Elm_Animator *animator)
414 {
415         if (animator->magic != MAGIC_OBJ_ANIMATOR)
416       return;
417    animator->on_animating = EINA_FALSE;
418         _delete_animator(animator);
419 }
420
421 /**
422  * Set the animator repeat count.
423  *
424  * @param  animator Animator object
425  * @param  repeat_cnt Repeat count
426  *
427  * @ingroup Animator
428  */
429 EAPI void
430 elm_animator_repeat_set(Elm_Animator *animator, unsigned int repeat_cnt)
431 {
432         if (animator->magic != MAGIC_OBJ_ANIMATOR)
433       return;
434    if (!animator->auto_reverse)
435       animator->repeat_cnt = repeat_cnt;
436    else
437       animator->repeat_cnt = _animator_compute_reverse_repeat_count(repeat_cnt);
438 }
439
440 /**
441  * Animate now.
442  *
443  * @param animator Animator object
444  *
445  * @ingroup Animator
446  */
447 EAPI void
448 elm_animator_animate(Elm_Animator *animator)
449 {
450         if (animator->magic != MAGIC_OBJ_ANIMATOR)
451       return;
452    if (!animator->animator_op)
453       return;
454    animator->begin_time = ecore_loop_time_get();
455    animator->cur_repeat_cnt = animator->repeat_cnt;
456    if (!animator->animator) {
457       animator->animator = ecore_animator_add(_animator_animate_cb, animator);
458         }
459    if (animator->animator)
460       animator->on_animating = EINA_TRUE;
461 }