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