diff --git a/docs/details/main-components/animation.rst b/docs/details/main-components/animation.rst index c5888738c..2d538f464 100644 --- a/docs/details/main-components/animation.rst +++ b/docs/details/main-components/animation.rst @@ -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: diff --git a/examples/anim/index.rst b/examples/anim/index.rst index eb6160b3c..5058fa502 100644 --- a/examples/anim/index.rst +++ b/examples/anim/index.rst @@ -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 diff --git a/examples/anim/lv_example_anim.h b/examples/anim/lv_example_anim.h index 48b61b020..cd005c6ea 100644 --- a/examples/anim/lv_example_anim.h +++ b/examples/anim/lv_example_anim.h @@ -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); /********************** diff --git a/examples/anim/lv_example_anim_4.c b/examples/anim/lv_example_anim_4.c new file mode 100644 index 000000000..7f152e8f5 --- /dev/null +++ b/examples/anim/lv_example_anim_4.c @@ -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 diff --git a/src/misc/lv_anim.c b/src/misc/lv_anim.c index 1febdf4f6..fedcd13d2 100644 --- a/src/misc/lv_anim.c +++ b/src/misc/lv_anim.c @@ -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); diff --git a/src/misc/lv_anim.h b/src/misc/lv_anim.h index 901eb9f03..9cd977106 100644 --- a/src/misc/lv_anim.h +++ b/src/misc/lv_anim.h @@ -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; /**