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