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

feat(anim): save custom_exec_cb in its own field

It allows deleting custom exec animations based on var an callbacks
This commit is contained in:
Gabor Kiss-Vamosi 2023-11-23 21:34:33 +01:00
parent 1320f4fc02
commit ce99983d4f
3 changed files with 140 additions and 33 deletions

View File

@ -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;
}

View File

@ -134,8 +134,10 @@ typedef struct _lv_anim_bezier3_para_t {
/** Describes an animation*/
typedef struct _lv_anim_t {
void * var; /**<Variable to animate*/
lv_anim_exec_xcb_t exec_cb; /**< Function to execute to animate*/
void * var; /**<Variable to animate*/
lv_anim_exec_xcb_t exec_cb; /**< Function to execute to animate*/
lv_anim_custom_exec_cb_t custom_exec_cb;/**< Function to execute to animate,
same purpose as exec_cb but different parameters*/
lv_anim_start_cb_t start_cb; /**< Call it when the animation is starts (considering `delay`)*/
lv_anim_ready_cb_t ready_cb; /**< Call it when the animation is ready*/
lv_anim_deleted_cb_t deleted_cb; /**< Call it when the animation is deleted*/
@ -249,14 +251,12 @@ static inline void lv_anim_set_values(lv_anim_t * a, int32_t start, int32_t end)
* `lv_anim_t * ` as its first parameter instead of `void *`.
* This function might be used when LVGL is bound to other languages because
* it's more consistent to have `lv_anim_t *` as first parameter.
* The variable to animate can be stored in the animation's `user_data`
* @param a pointer to an initialized `lv_anim_t` variable
* @param exec_cb a function to execute.
*/
static inline void lv_anim_set_custom_exec_cb(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb)
{
a->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

View File

@ -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