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