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:
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.
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* ecore_animator_timeline_add(double runtime, Ecore_Timeline_Cb func, const void *data )
runtime
is the duration of the animation in seconds. The duration is not affected by frame rate.func
is the callback function that performs the animation.data
is the parameter passed to the callback function. This is usually the Evas object to animate.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);
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.0ECORE_POS_MAP_ACCELERATE
: start slow, then speed upECORE_POS_MAP_DECELERATE
: start fast, then slow downECORE_POS_MAP_SINUSOIDAL
: start slow, speed up, then slow down at the endECORE_POS_MAP_ACCELERATE_FACTOR
: start slow, then speed upECORE_POS_MAP_DECELERATE_FACTOR
: start fast, then slow downECORE_POS_MAP_SINUSOIDAL_FACTOR
: start slow, speed up, then slow down at the endECORE_POS_MAP_DIVISOR_INTERP
: start at gradient * v1, interpolated via power of v2 curveECORE_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 v1ECORE_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 v1When 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:
double ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2 )
pos
is the current position value, which ranges from 0.0 to 1.0.map
is the position mapping you want to apply.v1
is the first parameter (v1) to pass to the position mapping.v2
is the second parameter (v2) to pass to the position mapping.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 frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7); //Get frame relative position depending on desired effect 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);
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* ecore_animator_add(Ecore_Task_Cb func, const void *data )
func
is the callback function that performs the animation.data
is the parameter passed to the callback function. This is usually the Evas object to animate.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 }
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);
You can pause and resume Ecore animations. To pause a running animation, use
the ecore_animator_freeze()
function:
The parameter is the Ecore_Animator
to pause.
ecore_animator_freeze(Ecore_Animator *animator)
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);
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);
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:
The argument is the new frametime value.
ecore_animator_frametime_set(double frametime)
If you want to get the current frametime value, use the
ecore_animator_frametime_get()
function.
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):
void ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, const void *data )
func
is the callback function to call on the tick start.data
is the data to pass to the callback function.void ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data )
func
is the callback function to call on the tick end.data
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.