[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);
19    void (*animator_op) (void *, Elm_Animator *, double);
20    void *animator_arg;
21    void (*completion_op) (void *);
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  *
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, Elm_Animator *animator,
267                                                 double frame), void *data)
268 {
269    if (!animator)
270       return;
271    if (animator->on_animating == EINA_TRUE)
272       return;
273    animator->animator_op = func;
274    animator->animator_arg = data;
275 }
276
277 /**
278  * Add new animator. 
279  *
280  * @param parent Parent object
281  * @return animator object 
282  *
283  * @ingroup Animator
284  */
285 EAPI Elm_Animator *
286 elm_animator_add(Evas_Object *parent)
287 {
288    Elm_Animator *animator = calloc(1, sizeof(Elm_Animator));
289
290    if (!animator)
291       return NULL;
292    elm_animator_auto_reverse_set(animator, EINA_FALSE);
293    elm_animator_curve_style_set(animator, ELM_ANIMATOR_CURVE_LINEAR);
294
295    if (parent)
296       evas_object_event_callback_add(parent, EVAS_CALLBACK_DEL,
297                                      _animator_parent_del, animator);
298
299    return animator;
300 }
301
302 /**
303  * Get the status for the animator operation.
304  *
305  * @param animator Animator object 
306  * @return EINA_TRUE is animator is operating. 
307  *
308  * @ingroup Animator
309  */
310 EAPI Eina_Bool
311 elm_animator_operating_get(Elm_Animator *animator)
312 {
313    if (!animator)
314       return EINA_FALSE;
315    return animator->on_animating;
316 }
317
318 /**
319  * Delete animator. 
320  *
321  * @param animator Animator object 
322  *
323  * @ingroup Animator
324  */
325 EAPI void
326 elm_animator_del(Elm_Animator *animator)
327 {
328    if (!animator)
329       return;
330    _delete_animator(animator);
331    free(animator);
332 }
333
334 /**
335  * Set the callback function for the animator end.  
336  *
337  * @param  animator Animator object 
338  * @param  op Callback function pointer
339  * @param  data Callback function user argument 
340  *
341  * @ingroup Animator
342  */
343 EAPI void
344 elm_animator_completion_callback_set(Elm_Animator *animator,
345                                      void (*func) (void *data), void *data)
346 {
347    if (!animator)
348       return;
349    if (animator->on_animating == EINA_TRUE)
350       return;
351    animator->completion_op = func;
352    animator->completion_arg = data;
353 }
354
355 /**
356  * Stop animator.
357  *
358  * @param animator Animator object 
359  *
360  * @ingroup Animator
361  */
362 EAPI void
363 elm_animator_stop(Elm_Animator *animator)
364 {
365    if (!animator)
366       return;
367    animator->on_animating = EINA_FALSE;
368    _delete_animator(animator);
369 }
370
371 /**
372  * Set the animator repeat count.
373  *
374  * @param  animator Animator object
375  * @param  repeat_cnt Repeat count
376  *
377  * @ingroup Animator
378  */
379 EAPI void
380 elm_animator_repeat_set(Elm_Animator *animator, unsigned int repeat_cnt)
381 {
382    if (!animator)
383       return NULL;
384    if (animator->auto_reverse == EINA_FALSE)
385       animator->repeat_cnt = repeat_cnt;
386    else
387       animator->repeat_cnt = _animator_compute_reverse_repeat_count(repeat_cnt);
388 }
389
390 /**
391  * Animate now.
392  *
393  * @param animator Animator object
394  *
395  * @ingroup Animator
396  */
397 EAPI void
398 elm_animator_animate(Elm_Animator *animator)
399 {
400    if (!animator)
401       return;
402    if (!animator->animator_op)
403       return;
404    animator->begin_time = ecore_loop_time_get();
405    animator->on_animating = EINA_TRUE;
406    animator->cur_repeat_cnt = animator->repeat_cnt;
407    if (!animator->animator)
408       animator->animator = ecore_animator_add(_animator_animate_cb, animator);
409    if (!animator->animator)
410       animator->on_animating = EINA_FALSE;
411 }