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