From ce99983d4f519ac303b63ee8f758ed2b0fe6bc91 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 23 Nov 2023 21:34:33 +0100 Subject: [PATCH] feat(anim): save custom_exec_cb in its own field It allows deleting custom exec animations based on var an callbacks --- src/misc/lv_anim.c | 68 +++++++++++++---------- src/misc/lv_anim.h | 12 ++--- tests/src/test_cases/test_anim.c | 93 ++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 33 deletions(-) create mode 100644 tests/src/test_cases/test_anim.c diff --git a/src/misc/lv_anim.c b/src/misc/lv_anim.c index 70aa9826d..1901146ce 100644 --- a/src/misc/lv_anim.c +++ b/src/misc/lv_anim.c @@ -39,6 +39,7 @@ static int32_t lv_anim_path_cubic_bezier(const lv_anim_t * a, int32_t x1, static uint32_t convert_speed_to_time(uint32_t speed, int32_t start, int32_t end); static void resolve_time(lv_anim_t * a); static bool remove_concurrent_anims(lv_anim_t * a_current); +static bool delete_core(void * var, void * cb, bool custom_exec_cb); /********************** * STATIC VARIABLES @@ -105,12 +106,17 @@ lv_anim_t * lv_anim_start(const lv_anim_t * a) new_anim->end_value += v_ofs; /*Do not let two animations for the same 'var' with the same 'exec_cb'*/ - if(a->exec_cb != NULL) remove_concurrent_anims(new_anim); + if(a->exec_cb || a->custom_exec_cb) remove_concurrent_anims(new_anim); } resolve_time(new_anim); - if(new_anim->exec_cb && new_anim->var) new_anim->exec_cb(new_anim->var, new_anim->start_value); + if(new_anim->exec_cb && new_anim->var) { + new_anim->exec_cb(new_anim->var, new_anim->start_value); + } + if(new_anim->custom_exec_cb && new_anim->var) { + new_anim->custom_exec_cb(new_anim, new_anim->start_value); + } } /*Creating an animation changed the linked list. @@ -123,9 +129,9 @@ lv_anim_t * lv_anim_start(const lv_anim_t * a) uint32_t lv_anim_get_playtime(lv_anim_t * a) { - - if(a->repeat_cnt == LV_ANIM_REPEAT_INFINITE) + if(a->repeat_cnt == LV_ANIM_REPEAT_INFINITE) { return LV_ANIM_PLAYTIME_INFINITE; + } uint32_t repeate_cnt = a->repeat_cnt; if(repeate_cnt < 1) repeate_cnt = 1; @@ -137,27 +143,7 @@ uint32_t lv_anim_get_playtime(lv_anim_t * a) bool lv_anim_delete(void * var, lv_anim_exec_xcb_t exec_cb) { - lv_anim_t * a; - bool del_any = false; - a = _lv_ll_get_head(anim_ll_p); - while(a != NULL) { - bool del = false; - if((a->var == var || var == NULL) && (a->exec_cb == exec_cb || exec_cb == NULL)) { - _lv_ll_remove(anim_ll_p, a); - if(a->deleted_cb != NULL) a->deleted_cb(a); - lv_free(a); - anim_mark_list_change(); /*Read by `anim_timer`. It need to know if a delete occurred in - the linked list*/ - del_any = true; - del = true; - } - - /*Always start from the head on delete, because we don't know - *how `anim_ll_p` was changes in `a->deleted_cb` */ - a = del ? _lv_ll_get_head(anim_ll_p) : _lv_ll_get_next(anim_ll_p, a); - } - - return del_any; + return delete_core(var, exec_cb, false); } void lv_anim_delete_all(void) @@ -392,6 +378,7 @@ static void anim_timer(lv_timer_t * param) a->current_value = new_value; /*Apply the calculated value*/ if(a->exec_cb) a->exec_cb(a->var, new_value); + if(a->custom_exec_cb) a->custom_exec_cb(a, new_value); } /*If the time is elapsed the animation is ready*/ @@ -514,7 +501,7 @@ static void resolve_time(lv_anim_t * a) */ static bool remove_concurrent_anims(lv_anim_t * a_current) { - if(a_current->exec_cb == NULL) return false; + if(a_current->exec_cb == NULL && a_current->custom_exec_cb == NULL) return false; lv_anim_t * a; bool del_any = false; @@ -524,7 +511,8 @@ static bool remove_concurrent_anims(lv_anim_t * a_current) if(a != a_current && (a->act_time >= 0 || a->early_apply) && (a->var == a_current->var) && - (a->exec_cb == a_current->exec_cb)) { + ((a->exec_cb && a->exec_cb == a_current->exec_cb) || + (a->custom_exec_cb && a->custom_exec_cb == a_current->custom_exec_cb))) { _lv_ll_remove(anim_ll_p, a); if(a->deleted_cb != NULL) a->deleted_cb(a); lv_free(a); @@ -542,3 +530,29 @@ static bool remove_concurrent_anims(lv_anim_t * a_current) return del_any; } + +static bool delete_core(void * var, void * cb, bool custom_exec_cb) +{ + lv_anim_t * a; + bool del_any = false; + a = _lv_ll_get_head(anim_ll_p); + while(a != NULL) { + bool del = false; + void * a_cb = custom_exec_cb ? (void *)a->custom_exec_cb : (void *)a->exec_cb; + if((a->var == var || var == NULL) && (a_cb == cb || cb == NULL)) { + _lv_ll_remove(anim_ll_p, a); + if(a->deleted_cb != NULL) a->deleted_cb(a); + lv_free(a); + anim_mark_list_change(); /*Read by `anim_timer`. It need to know if a delete occurred in + the linked list*/ + del_any = true; + del = true; + } + + /*Always start from the head on delete, because we don't know + *how `anim_ll_p` was changes in `a->deleted_cb` */ + a = del ? _lv_ll_get_head(anim_ll_p) : _lv_ll_get_next(anim_ll_p, a); + } + + return del_any; +} diff --git a/src/misc/lv_anim.h b/src/misc/lv_anim.h index d3a694eab..35055d620 100644 --- a/src/misc/lv_anim.h +++ b/src/misc/lv_anim.h @@ -134,8 +134,10 @@ typedef struct _lv_anim_bezier3_para_t { /** Describes an animation*/ typedef struct _lv_anim_t { - void * var; /**var = a; - a->exec_cb = (lv_anim_exec_xcb_t)exec_cb; + a->custom_exec_cb = exec_cb; } /** @@ -443,7 +443,7 @@ static inline void * lv_anim_get_user_data(lv_anim_t * a) } /** - * Delete an animation of a variable with a given animator function + * Delete animation(s) of a variable with a given animator function * @param var pointer to variable * @param exec_cb a function pointer which is animating 'var', * or NULL to ignore it and delete all the animations of 'var diff --git a/tests/src/test_cases/test_anim.c b/tests/src/test_cases/test_anim.c new file mode 100644 index 000000000..c8fc87d83 --- /dev/null +++ b/tests/src/test_cases/test_anim.c @@ -0,0 +1,93 @@ +#if LV_BUILD_TEST || 1 +#include "../lvgl.h" + +#include "unity/unity.h" +#include "lv_test_helpers.h" + +void setUp(void) +{ + /* Function run before every test */ +} + +void tearDown(void) +{ + /* Function run after every test */ +} + +static void exec_cb(void * var, int32_t v) +{ + int32_t * var_i32 = var; + *var_i32 = v; +} + +static void custom_exec_cb(lv_anim_t * a, int32_t v) +{ + int32_t * var_i32 = a->var; + *var_i32 = v; +} + +void test_anim_delete(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_time(&a, 100); + lv_anim_start(&a); + + lv_test_wait(20); + TEST_ASSERT_EQUAL(19, var); + + bool deleted; + /*Wrong variable, nothing should happen*/ + deleted = lv_anim_delete(&a, exec_cb); + TEST_ASSERT_FALSE(deleted); + + lv_test_wait(20); + TEST_ASSERT_EQUAL(39, var); + + /*The value shouldn't change after delete*/ + deleted = lv_anim_delete(&var, exec_cb); + TEST_ASSERT_TRUE(deleted); + + lv_test_wait(20); + TEST_ASSERT_EQUAL(39, var); +} + +void test_anim_delete_custom(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_custom_exec_cb(&a, custom_exec_cb); + lv_anim_set_time(&a, 100); + lv_anim_start(&a); + + lv_test_wait(20); + TEST_ASSERT_EQUAL(19, var); + + bool deleted; + /*Wrong callback, nothing should happen*/ + deleted = lv_anim_delete(&var, exec_cb); + TEST_ASSERT_FALSE(deleted); + + lv_test_wait(20); + TEST_ASSERT_EQUAL(39, var); + + /*The value shouldn't change after delete*/ + deleted = lv_anim_delete(&var, NULL); + TEST_ASSERT_TRUE(deleted); + + lv_test_wait(20); + TEST_ASSERT_EQUAL(39, var); +} + +#endif