[elm_animator.c]
[framework/uifw/elementary.git] / src / lib / elm_animator.c
1 #include <Elementary.h>
2
3 /**
4  * @addtogroup Animator Animator
5  * @ingroup Elementary
6  *
7  * Support basic animation functions for Evas_Object
8 */
9
10 struct _Animator
11 {
12    Ecore_Animator *animator;
13    double begin_time;
14    double cur_time;
15    double duration;
16    unsigned int repeat_cnt;
17    unsigned int cur_repeat_cnt;
18    double (*curve_op) (double frame);
19    void (*animator_op) (void *data, Elm_Animator *animator, double frame);
20    void *animator_arg;
21    void (*completion_op) (void *data);
22    void *completion_arg;
23    Eina_Bool auto_reverse:1;
24    Eina_Bool on_animating:1;
25 };
26
27 static double _animator_curve_linear(double frame);
28
29 static double _animator_curve_in_out(double frame);
30
31 static double _animator_curve_in(double frame);
32
33 static double _animator_curve_out(double frame);
34
35 static unsigned int _animator_compute_reverse_repeat_count(unsigned int cnt);
36
37 static unsigned int _animator_compute_no_reverse_repeat_count(unsigned int cnt);
38
39 static int _animator_animate_cb(void *data);
40
41 static void _delete_animator(Elm_Animator *animator);
42
43 static void _animator_parent_del(void *data);
44
45 static unsigned int
46 _animator_compute_reverse_repeat_count(unsigned int cnt)
47 {
48    return ((cnt + 1) * 2) - 1;
49 }
50
51 static unsigned int
52 _animator_compute_no_reverse_repeat_count(unsigned int cnt)
53 {
54    return cnt / 2;
55 }
56
57 static double
58 _animator_curve_linear(double frame)
59 {
60    return frame;
61 }
62
63 static double
64 _animator_curve_in_out(double frame)
65 {
66    if (frame < 0.5)
67       return _animator_curve_out(frame * 2) * 0.5;
68    else
69       return (_animator_curve_in(frame * 2 - 1) * 0.5) + 0.5;
70 }
71
72 static double
73 _animator_curve_in(double frame)
74 {
75    return sqrt(1 - pow(frame - 1, 2));
76 }
77
78 static double
79 _animator_curve_out(double frame)
80 {
81    return 1 - sqrt(1 - pow(frame, 2));
82 }
83
84 static void
85 _delete_animator(Elm_Animator *animator)
86 {
87    if (animator->animator)
88      {
89         ecore_animator_del(animator->animator);
90         animator->animator = NULL;
91      }
92 }
93
94 static int
95 _animator_animate_cb(void *data)
96 {
97    Elm_Animator *animator = (Elm_Animator *) data;
98
99    animator->cur_time = ecore_loop_time_get();
100    double elapsed_time = animator->cur_time - animator->begin_time;
101
102    //TODO: HOW TO MAKE IT PRECIOUS TIME? -> Use Interpolation!!
103    if (elapsed_time > animator->duration)
104       elapsed_time = animator->duration;
105
106    double frame = animator->curve_op(elapsed_time / animator->duration);
107
108    //Reverse?
109    if (animator->auto_reverse == EINA_TRUE)
110      {
111         if ((animator->cur_repeat_cnt % 2) == 0)
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 == 0)
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)
141 {
142    elm_animator_stop(data);
143    elm_animator_del(data);
144 }
145
146 /**
147  * Get the value of reverse mode. 
148  *
149  * @param 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(Elm_Animator *animator)
156 {
157    if (!animator)
158       return EINA_FALSE;
159    return animator->auto_reverse;
160 }
161
162 /**
163  * Get the value of repeat count.
164  *
165  * @param animator Animator object
166  * @return Repeat count
167  *
168  * @ingroup Animator 
169  */
170 EAPI unsigned int
171 elm_animator_repeat_get(Elm_Animator *animator)
172 {
173    if (!animator)
174       return EINA_FALSE;
175    return animator->repeat_cnt;
176 }
177
178 /**
179  * Set auto reverse function.  
180  *
181  * @param animator Animator object
182  * @param 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)
190       return;
191    if (animator->auto_reverse == reverse)
192       return;
193    animator->auto_reverse = reverse;
194    if (reverse == EINA_TRUE)
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 animator Animator object
206  * @param 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)
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 animator Animator object
241  * @param 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)
249       return;
250    if (animator->on_animating == EINA_TRUE)
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 animator Animator object
260  * @param op Callback function pointer 
261  * @param 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)
272       return;
273    if (animator->on_animating == EINA_TRUE)
274       return;
275    animator->animator_op = func;
276    animator->animator_arg = data;
277 }
278
279 /**
280  * Add new animator. 
281  *
282  * @param 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 = calloc(1, sizeof(Elm_Animator));
291
292    if (!animator)
293       return NULL;
294    elm_animator_auto_reverse_set(animator, EINA_FALSE);
295    elm_animator_curve_style_set(animator, ELM_ANIMATOR_CURVE_LINEAR);
296
297    if (parent)
298       evas_object_event_callback_add(parent, EVAS_CALLBACK_DEL,
299                                      _animator_parent_del, animator);
300
301    return animator;
302 }
303
304 /**
305  * Get the status for the animator operation.
306  *
307  * @param animator Animator object 
308  * @return EINA_TRUE is animator is operating. 
309  *
310  * @ingroup Animator
311  */
312 EAPI Eina_Bool
313 elm_animator_operating_get(Elm_Animator *animator)
314 {
315    if (!animator)
316       return EINA_FALSE;
317    return animator->on_animating;
318 }
319
320 /**
321  * Delete animator. 
322  *
323  * @param animator Animator object 
324  *
325  * @ingroup Animator
326  */
327 EAPI void
328 elm_animator_del(Elm_Animator *animator)
329 {
330    if (!animator)
331       return;
332    _delete_animator(animator);
333    free(animator);
334 }
335
336 /**
337  * Set the callback function for the animator end.  
338  *
339  * @param  animator Animator object 
340  * @param  op Callback function pointer
341  * @param  data Callback function user argument 
342  *
343  * @ingroup Animator
344  */
345 EAPI void
346 elm_animator_completion_callback_set(Elm_Animator *animator,
347                                      void (*func) (void *data), void *data)
348 {
349    if (!animator)
350       return;
351    if (animator->on_animating == EINA_TRUE)
352       return;
353    animator->completion_op = func;
354    animator->completion_arg = data;
355 }
356
357 /**
358  * Stop animator.
359  *
360  * @param animator Animator object 
361  *
362  * @ingroup Animator
363  */
364 EAPI void
365 elm_animator_stop(Elm_Animator *animator)
366 {
367    if (!animator)
368       return;
369    animator->on_animating = EINA_FALSE;
370    _delete_animator(animator);
371 }
372
373 /**
374  * Set the animator repeat count.
375  *
376  * @param  animator Animator object
377  * @param  repeat_cnt Repeat count
378  *
379  * @ingroup Animator
380  */
381 EAPI void
382 elm_animator_repeat_set(Elm_Animator *animator, unsigned int repeat_cnt)
383 {
384    if (!animator)
385       return NULL;
386    if (animator->auto_reverse == EINA_FALSE)
387       animator->repeat_cnt = repeat_cnt;
388    else
389       animator->repeat_cnt = _animator_compute_reverse_repeat_count(repeat_cnt);
390 }
391
392 /**
393  * Animate now.
394  *
395  * @param animator Animator object
396  *
397  * @ingroup Animator
398  */
399 EAPI void
400 elm_animator_animate(Elm_Animator *animator)
401 {
402    if (!animator)
403       return;
404    if (!animator->animator_op)
405       return;
406    animator->begin_time = ecore_loop_time_get();
407    animator->on_animating = EINA_TRUE;
408    animator->cur_repeat_cnt = animator->repeat_cnt;
409    if (!animator->animator)
410       animator->animator = ecore_animator_add(_animator_animate_cb, animator);
411    if (!animator->animator)
412       animator->on_animating = EINA_FALSE;
413 }