1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

feat(anim): add a pause method (#7583)

This commit is contained in:
André Costa 2025-01-15 08:57:30 +01:00 committed by GitHub
parent 124b2e268d
commit e028ee985c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 234 additions and 2 deletions

View File

@ -293,6 +293,18 @@ This function returns a Boolean value indicating whether any *live, running*
Animations were deleted.
.. _animation_pause:
Pausing Animations
******************
If you kept a copy of the pointer returned by :cpp:func:`lv_anim_start`,
you can pause the running animation using :cpp:expr:`lv_anim_pause(animation)` and then resume it
using :cpp:expr:`lv_anim_resume(animation)`.
:cpp:expr:`lv_anim_pause_for(animation, milliseconds)`
is also available if you wish for the animation to resume automatically after.
.. _animations_timeline:

View File

@ -15,6 +15,11 @@ Cubic Bezier animation
.. lv_example:: anim/lv_example_anim_3
:language: c
Pause animation
----------------------
.. lv_example:: anim/lv_example_anim_4
:language: c
Animation timeline
------------------
.. lv_example:: anim/lv_example_anim_timeline_1

View File

@ -28,6 +28,7 @@ extern "C" {
void lv_example_anim_1(void);
void lv_example_anim_2(void);
void lv_example_anim_3(void);
void lv_example_anim_4(void);
void lv_example_anim_timeline_1(void);
/**********************

View File

@ -0,0 +1,60 @@
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
static void anim_x_cb(void * var, int32_t v)
{
lv_obj_set_x(var, v);
}
static void timer_cb(lv_timer_t * timer)
{
lv_anim_t * anim = lv_timer_get_user_data(timer);
lv_anim_pause_for(anim, 1000);
lv_timer_delete(timer);
}
static void sw_event_cb(lv_event_t * e)
{
lv_obj_t * sw = lv_event_get_target(e);
lv_obj_t * label = lv_event_get_user_data(e);
if(lv_obj_has_state(sw, LV_STATE_CHECKED)) {
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, label);
lv_anim_set_values(&a, lv_obj_get_x(label), 100);
lv_anim_set_duration(&a, 500);
lv_anim_set_exec_cb(&a, anim_x_cb);
lv_anim_set_path_cb(&a, lv_anim_path_overshoot);
lv_timer_create(timer_cb, 200, lv_anim_start(&a));
}
else {
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, label);
lv_anim_set_values(&a, lv_obj_get_x(label), -lv_obj_get_width(label));
lv_anim_set_duration(&a, 500);
lv_anim_set_exec_cb(&a, anim_x_cb);
lv_anim_set_path_cb(&a, lv_anim_path_ease_in);
lv_timer_create(timer_cb, 200, lv_anim_start(&a));
}
}
/**
* Start animation on an event
*/
void lv_example_anim_4(void)
{
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello animations!");
lv_obj_set_pos(label, 100, 10);
lv_obj_t * sw = lv_switch_create(lv_screen_active());
lv_obj_center(sw);
lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, sw_event_cb, LV_EVENT_VALUE_CHANGED, label);
}
#endif

View File

@ -44,6 +44,7 @@ static void anim_mark_list_change(void);
static void anim_completed_handler(lv_anim_t * a);
static int32_t lv_anim_path_cubic_bezier(const lv_anim_t * a, int32_t x1,
int32_t y1, int32_t x2, int32_t y2);
static void lv_anim_pause_for_internal(lv_anim_t * a, uint32_t ms);
static void resolve_time(lv_anim_t * a);
static bool remove_concurrent_anims(lv_anim_t * a_current);
static void remove_anim(void * a);
@ -104,6 +105,7 @@ lv_anim_t * lv_anim_start(const lv_anim_t * a)
if(a->var == a) new_anim->var = new_anim;
new_anim->run_round = state.anim_run_round;
new_anim->last_timer_run = lv_tick_get();
new_anim->is_paused = false;
/*Set the start value*/
if(new_anim->early_apply) {
@ -499,6 +501,31 @@ uint32_t lv_anim_resolve_speed(uint32_t speed_or_time, int32_t start, int32_t en
return LV_CLAMP(min_time * 10, time, max_time * 10);
}
bool lv_anim_is_paused(lv_anim_t * a)
{
LV_ASSERT_NULL(a);
return a->is_paused;
}
void lv_anim_pause(lv_anim_t * a)
{
LV_ASSERT_NULL(a);
lv_anim_pause_for_internal(a, LV_ANIM_PAUSE_FOREVER);
}
void lv_anim_pause_for(lv_anim_t * a, uint32_t ms)
{
LV_ASSERT_NULL(a);
lv_anim_pause_for_internal(a, ms);
}
void lv_anim_resume(lv_anim_t * a)
{
LV_ASSERT_NULL(a);
a->is_paused = false;
a->pause_duration = 0;
}
/**********************
* STATIC FUNCTIONS
@ -519,8 +546,20 @@ static void anim_timer(lv_timer_t * param)
while(a != NULL) {
uint32_t elaps = lv_tick_elaps(a->last_timer_run);
a->act_time += elaps;
if(a->is_paused) {
const uint32_t time_paused = lv_tick_elaps(a->pause_time);
const bool is_pause_over = a->pause_duration != LV_ANIM_PAUSE_FOREVER && time_paused >= a->pause_duration;
if(is_pause_over) {
const uint32_t pause_overrun = time_paused - a->pause_duration;
a->is_paused = false;
a->act_time += pause_overrun;
}
}
else {
a->act_time += elaps;
}
a->last_timer_run = lv_tick_get();
/*It can be set by `lv_anim_delete()` typically in `end_cb`. If set then an animation delete
@ -529,7 +568,7 @@ static void anim_timer(lv_timer_t * param)
*/
state.anim_list_changed = false;
if(a->run_round != state.anim_run_round) {
if(!a->is_paused && a->run_round != state.anim_run_round) {
a->run_round = state.anim_run_round; /*The list readying might be reset so need to know which anim has run already*/
/*The animation will run now for the first time. Call `start_cb`*/
@ -664,6 +703,14 @@ static int32_t lv_anim_path_cubic_bezier(const lv_anim_t * a, int32_t x1, int32_
return new_value;
}
static void lv_anim_pause_for_internal(lv_anim_t * a, uint32_t ms)
{
a->is_paused = true;
a->pause_time = lv_tick_get();
a->pause_duration = ms;
}
static void resolve_time(lv_anim_t * a)
{
a->duration = lv_anim_resolve_speed(a->duration, a->start_value, a->end_value);

View File

@ -25,6 +25,7 @@ extern "C" {
#define LV_ANIM_REPEAT_INFINITE 0xFFFFFFFF
#define LV_ANIM_PLAYTIME_INFINITE 0xFFFFFFFF
#define LV_ANIM_PAUSE_FOREVER 0xFFFFFFFF
/*
* Macros used to set cubic-bezier anim parameter.
@ -146,6 +147,9 @@ struct _lv_anim_t {
/* Animation system use these - user shouldn't set */
uint32_t last_timer_run;
uint32_t pause_time; /**<The time when the animation was paused*/
uint32_t pause_duration; /**<The amount of the time the animation must stay paused for*/
uint8_t is_paused : 1; /**<Indicates that the animation is paused */
uint8_t reverse_play_in_progress : 1; /**< Reverse play is in progress */
uint8_t run_round : 1; /**< When not equal to global.anim_state.anim_run_round (which toggles each
* time animation timer executes), indicates this animation needs to be updated. */
@ -198,6 +202,32 @@ void lv_anim_set_duration(lv_anim_t * a, uint32_t duration);
*/
void lv_anim_set_delay(lv_anim_t * a, uint32_t delay);
/**
* Resumes a paused animation
* @param a pointer to an initialized `lv_anim_t` variable
*/
void lv_anim_resume(lv_anim_t * a);
/**
* Pauses the animation
* @param a pointer to an initialized `lv_anim_t` variable
*/
void lv_anim_pause(lv_anim_t * a);
/**
* Pauses the animation for ms milliseconds
* @param a pointer to an initialized `lv_anim_t` variable
* @param ms the pause time in milliseconds
*/
void lv_anim_pause_for(lv_anim_t * a, uint32_t ms);
/**
* Check if the animation is paused
* @param a pointer to an initialized `lv_anim_t` variable
* @return true if the animation is paused else false
*/
bool lv_anim_is_paused(lv_anim_t * a);
/**
* Set the start and end values of an animation
* @param a pointer to an initialized `lv_anim_t` variable

View File

@ -90,5 +90,82 @@ void test_anim_delete_custom(void)
lv_test_wait(20);
TEST_ASSERT_EQUAL(39, var);
}
void test_anim_pause(void)
{
int32_t var;
/*Start an animation*/
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, &var);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_exec_cb(&a, exec_cb);
lv_anim_set_duration(&a, 100);
lv_anim_t * animation = lv_anim_start(&a);
lv_test_wait(40);
TEST_ASSERT_EQUAL(39, var);
lv_anim_pause(animation);
lv_test_wait(40);
TEST_ASSERT_EQUAL(39, var);
lv_anim_resume(animation);
lv_test_wait(20);
TEST_ASSERT_EQUAL(59, var);
lv_test_wait(41);
TEST_ASSERT_EQUAL(100, var);
}
void test_anim_pause_for(void)
{
int32_t var;
/*Start an animation*/
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, &var);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_exec_cb(&a, exec_cb);
lv_anim_set_duration(&a, 100);
lv_anim_t * animation = lv_anim_start(&a);
lv_anim_pause_for(animation, 20);
lv_test_wait(40);
TEST_ASSERT_EQUAL(19, var);
lv_anim_pause_for(animation, 20);
lv_test_wait(40);
lv_test_wait(40);
TEST_ASSERT_EQUAL(79, var);
}
void test_anim_pause_for_resume(void)
{
int32_t var;
/*Start an animation*/
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, &var);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_exec_cb(&a, exec_cb);
lv_anim_set_duration(&a, 100);
lv_anim_t * animation = lv_anim_start(&a);
lv_anim_pause_for(animation, 40);
lv_test_wait(20);
lv_anim_resume(animation);
lv_test_wait(20);
TEST_ASSERT_EQUAL(19, var);
}
#endif