Ecore Animations
Ecore provides a facility for animations called Ecore_Animator. Ecore animators use the Ecore main loop for creating animations, running a specific action on each tick of a timer in the main loop.
To create an Ecore animation:
- Determine the duration of the animation.
- Define a callback function that performs the animation with that duration.
To use Ecore animators in your application, you must include the <Ecore.h> file. This file is included by default if you are already using the <Elementary.h> file in your application. You then declare an Ecore_Animator* variable and use the variable in the ecore_animator_* functions.
The following example shows how to create a simple animation with a finite duration:
static Eina_Bool _do_animation(void *data, double pos) { evas_object_move(data, 100 * pos, 100 * pos); // Do some more animating... } ecore_animator_timeline_add(2, _do_animation, my_evas_object);
In the above example, we create a linear transition to move my_evas_object from position (0,0) to position (100,100) in 2 seconds.
Creating an Animation with a Finite Duration
Most of the time, you will want to create animations that last for a predefined time.
The ecore_animator_timeline_add() function allows you to define an animator that is automatically deleted after the animation is finished:
ecore_animator_timeline_add(double runtime, Ecore_Timeline_Cb func, const void *data)
- The first argument is the duration of the animation in seconds. The duration is not affected by frame rate.
- The second argument is the callback function that performs the animation.
- The third argument is the parameter passed to the callback function. This is usually the Evas object to animate.
Note |
---|
The callback function can return ECORE_CALLBACK_RENEW to keep the animator running or ECORE_CALLBACK_CANCEL to stop the animator and have it be deleted automatically at any time. The callback function is also passed a timeline position parameter with a value between 0.0 (start) to 1.0 (end) to indicate where along the timeline the animator is running. |
The following example performs a linear horizontal translation of 500 pixels in 8 seconds:
static Eina_Bool _my_animation(void *data, double pos) { Evas_Object *obj = data; // Get the target object int x, y, w, h; // Target object geometry evas_object_geometry_get(obj, &x, &y, &w, &h); // Get current object position and size attributes evas_object_move(obj, 500 * pos, y); // Linear translation of the Evas object } ecore_animator_timeline_add(8, _my_animation, my_evas_object);
Position Mappings
The Ecore_Pos_Map position mappings are used to define the evolution of a given position in accordance with the desired effects. The value ranges from 0.0 to 1.0 on a given timeline. This position variation allows you to apply dynamic changes to any attribute of your Evas object, such as position, width, height, scale, angle, and color.
Ecore supports the following position mappings (with the listed v1 and v2 parameters):
-
ECORE_POS_MAP_LINEAR: linear 0.0 - 1.0
- v1: not used
- v2: not used
-
ECORE_POS_MAP_ACCELERATE: start slow, then speed up
- v1: not used
- v2: not used
-
ECORE_POS_MAP_DECELERATE: start fast, then slow down
- v1: not used
- v2: not used
-
ECORE_POS_MAP_SINUSOIDAL: start slow, speed up, then slow down at the end
- v1: not used
- v2: not used
-
ECORE_POS_MAP_ACCELERATE_FACTOR: start slow, then speed up
- v1: power factor: 0.0 is linear, 1.0 is standard acceleration, 2.0 is a much more pronounced acceleration (squared), 4.0 is cubed, and so on
- v2: not used
-
ECORE_POS_MAP_DECELERATE_FACTOR: start fast, then slow down
- v1: power factor: 0.0 is linear, 1.0 is standard deceleration, 2.0 is a much more pronounced deceleration (squared), 3.0 is cubed, and so on
- v2: not used
-
ECORE_POS_MAP_SINUSOIDAL_FACTOR: start slow, speed up, then slow down at the end
- v1: power factor: 0.0 is linear, 1.0 is a standard sinusoidal, 2.1 is a much more pronounced sinusoidal (squared), 3.0 is cubed, and so on
- v2: not used
-
ECORE_POS_MAP_DIVISOR_INTERP: start at gradient * v1, interpolated via power of v2 curve
- v1: multiplication factor for gradient
- v2: curve value
-
ECORE_POS_MAP_BOUNCE: start at 0.0, then "drop" like a ball bouncing to the ground at 1.0, and bounce v2 times, with a decay factor of v1
- v1: bounce decay factor
- v2: number of bounces
-
ECORE_POS_MAP_SPRING: start at 0.0, then "wobble" like a spring until rest position at 1.0, and wobble v2 times, with a decay factor of v1
- v1: wobble decay factor
- v2: number of wobbles
Figure: Position mappings
Using Position Mappings
When using the animation callback function, the animator passes a timeline position parameter with a value between 0.0 (start) and 1.0 (end) to indicate where along the timeline the animator is running.
If you want to create a non-linear animation, map the position value to one of several curves and mappings:
ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2)
- The first argument is the current position value, which ranges from 0.0 to 1.0.
- The second argument is the position mapping you want to apply.
- The third argument is the first parameter (v1) to pass to the position mapping.
- The fourth argument is the second parameter (v2) to pass to the position mapping.
Note |
---|
The v1 and v2 arguments are specific to the chosen position mapping. For example, if you are using ECORE_POS_MAP_BOUNCE, v1 represents the bouncing level and v2 the number of bounces. |
The following example performs a transition that bounces 7 times, diminishing by a factor of 1.8 over 5 seconds:
static Eina_Bool _my_animation_callback(void *data, double pos) { Evas_Object *obj = data; // Get the target object int x, y, w, h; // Target object geometry double frame = pos; // Actual position variation // Get frame relative position depending on desired effect frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7); evas_object_geometry_get(obj, &x, &y, &w, &h); // Get current object position and size attributes evas_object_move(obj, x, 600 * frame); // Move the Evas object according to desired effect return EINA_TRUE; } ecore_animator_timeline_add(5, _my_animation_callback, my_evas_object);
Creating an Infinite Animation
If you want the animation to run for an unspecified amount of time, use the ecore_animator_add() function. This function works the same way as the ecore_animation_timeline_add() function, except its interval is based on frame rate. Using frame rate as the basis benefits performance, especially if you define multiple animations, since you may want to have a different timer for each callback function.
ecore_animator_add(Ecore_Task_Cb func, const void *data)
- The first argument is the callback function that performs the animation.
- The second argument is the parameter passed to the callback function. This is usually the Evas object to animate.
Note |
---|
The function returns a pointer to an Ecore_Animator object, which you can use to adjust the animation. |
The following example creates a rectangle sliding from left to right and back again. When the rectangle hits one edge of the screen, it changes direction.
static Eina_Bool _slide_back_and_forth(void *data) { typedef enum {LEFT, RIGHT} direction_t; // Direction datatype static int x = 0; // Initial position static direction_t direction = RIGHT; // Initial direction if (x >= 250) direction = LEFT; // Change direction else if (x <= 0) direction = RIGHT; // Change direction if (direction == RIGHT) evas_object_move(data, ++x, 350); // Slide to right else if (direction == LEFT) evas_object_move(data, --x, 350); // Slide to left return EINA_TRUE; } int main(int argc, char *argv[]) { // Declarations // Ecore Evas init // Draw Evas objects // Animations go here anim = ecore_animator_add(_slide_back_and_forth, rectangle); // Ecore main loop // Free memory }
Note |
---|
To use this code, you have to merge it with the Ecore transition example above. |
Chaining Animations
You may sometimes want to delay animating an object. This can be useful if, for example, you want to start an animation only after another one has finished.
You can simply set a delay to the second animation equal to the duration of the first animation:
static int runtime = 5; static int delay = runtime; static Eina_Bool _start_fold_animation(void *data) { ecore_animator_timeline_add(runtime, _fold_animation, data); return EINA_FALSE; } static Eina_Bool _start_unfold_animation(void *data) { ecore_animator_timeline_add(runtime, _unfold_animation, data); return EINA_FALSE; } _start_fold_animation(my_evas_object); ecore_timer_add(delay, _start_unfold_animation, my_evas_object);
Pausing and Resuming Animations
You can pause and resume Ecore animations. To pause a running animation, use the ecore_animator_freeze() function:
ecore_animator_freeze(Ecore_Animator *animator)
The parameter is the Ecore_Animator to pause.
To resume the paused animation, use the ecore_animator_thaw() function:
ecore_animation_thaw(Ecore_Animator *animator)
The parameter is the Ecore_Animator to resume.
The following example pauses a transition after 5 seconds and resumes it after 5 more seconds:
static Eina_Bool _freeze_animation(void *data) { ecore_animator_freeze(data); return EINA_FALSE; } static Eina_Bool _thaw_animation(void *data) { ecore_animator_thaw(data); return EINA_FALSE; } ecore_timer_add(5, _freeze_animation, animator); ecore_timer_add(10, _thaw_animation, animator);
Freeing Up Memory
When you create an animation that does not have a timeout, you will have to manually free up the memory allocated to the Ecore_Animator object. By comparison, if the animation has a timeout, Ecore implements the mechanisms to automatically delete the animator from the list of pointers: When your animation callback returns 0 or ECORE_CALLBACK_CANCEL, the animator manager takes care of freeing up the allocated memory.
To manually free up the memory, delete the pointer by using the ecore_animator_del() function:
ecore_animator_del(Ecore_Animator *animator)
The argument is the Ecore_Animator whose memory allocation to free up.
Regardless of the type of animation, it is good practice to always ensure that the allocated memory is freed up before the program exits:
if (animator != NULL) ecore_animator_del(animator);
Frametime
In most cases, you will want to use the default timer ECORE_ANIMATOR_SOURCE_TIMER. This timer ticks every "frametime" seconds and allows you to perform transitions within a predefined timeline. The timer uses the system clock to tick over every Nth second, with the default being 1/30th of a second.
To tweak performance, you can change the frametime value:
ecore_animator_frametime_set(double frametime)
The argument is the new frametime value.
Note |
---|
Too small a value can cause performance issues, whereas too high a value can cause your animation to seem jerky. |
If you want to get the current frametime value, use the ecore_animator_frametime_get() function.
Custom Timer
You may want to specify a custom timer to match your animation to third-party events. For example, the filling speed of a progress bar will mainly depend on the time it takes for a task to complete and the velocity at which the remaining time estimation evolves. This kind of animation requires you to use a custom timer.
To use a custom timer, first set ECORE_ANIMATOR_SOURCE_CUSTOM as the timer source, and then drive the timer based on an input tick source (such as another application via IPC or a vertical blanking interrupt):
ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, const void *data)
The first argument is the callback function to call on the tick start. The second argument is the data to pass to the callback function.
ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data)
The first argument is the callback function to call on the tick end. The second argument is the data to pass to the callback function to set the functions that will be called to start and stop the ticking source.
Next, trigger a tick over one frame:
ecore_animator_custom_tick(void)
The following example supposes a progress bar that will be refreshed every time some progress occurs:
ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM); void _on_progress_update() { // Called when some progress occurs ecore_animator_custom_tick(); // Tick (next frame in progress bar animation) }
Finally, to get the current animator source, use the ecore_animator_source_get() function.
Note |
---|
Except as noted, this content is licensed under LGPLv2.1+. |