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