From c526653822615329b9b55cf21db0aeeb088ffb1a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 18 Nov 2023 19:01:31 +0100 Subject: [PATCH] fix(anim_timeline): fix special cases of anim timeline and add tests --- examples/anim/lv_example_anim_3.c | 2 +- src/dev/sdl/lv_sdl_window.c | 2 +- src/misc/lv_anim.c | 84 +++++++--- src/misc/lv_anim.h | 8 +- src/misc/lv_anim_timeline.c | 13 +- src/widgets/label/lv_label.c | 12 +- tests/CMakeLists.txt | 1 + tests/src/lv_test_helpers.c | 12 ++ tests/src/lv_test_helpers.h | 3 + tests/src/test_cases/test_anim_timeline.c | 178 ++++++++++++++++++++++ 10 files changed, 278 insertions(+), 37 deletions(-) create mode 100644 tests/src/lv_test_helpers.c diff --git a/examples/anim/lv_example_anim_3.c b/examples/anim/lv_example_anim_3.c index cd9d64215..fb033a055 100644 --- a/examples/anim/lv_example_anim_3.c +++ b/examples/anim/lv_example_anim_3.c @@ -64,7 +64,7 @@ void lv_example_anim_3(void) static int32_t anim_path_bezier3_cb(const lv_anim_t * a) { - uint32_t t = lv_map(a->act_time, 0, a->time, 0, 1024); + uint32_t t = lv_map(a->act_time, 0, a->duration, 0, 1024); int32_t step = lv_bezier3(t, 0, ginfo.p1, ginfo.p2, 1024); int32_t new_value; new_value = step * (a->end_value - a->start_value); diff --git a/src/dev/sdl/lv_sdl_window.c b/src/dev/sdl/lv_sdl_window.c index 4cc52de36..7faf86681 100644 --- a/src/dev/sdl/lv_sdl_window.c +++ b/src/dev/sdl/lv_sdl_window.c @@ -77,7 +77,7 @@ lv_display_t * lv_sdl_window_create(int32_t hor_res, int32_t ver_res) SDL_Init(SDL_INIT_VIDEO); SDL_StartTextInput(); event_handler_timer = lv_timer_create(sdl_event_handler, 5, NULL); - lv_tick_set_cb(SDL_GetTicks); + // lv_tick_set_cb(SDL_GetTicks); #if LV_USE_DRAW_SDL if(!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) { diff --git a/src/misc/lv_anim.c b/src/misc/lv_anim.c index 41b7653b4..3f51c07b8 100644 --- a/src/misc/lv_anim.c +++ b/src/misc/lv_anim.c @@ -38,6 +38,7 @@ 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 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 VARIABLES @@ -73,7 +74,7 @@ void _lv_anim_core_deinit(void) void lv_anim_init(lv_anim_t * a) { lv_memzero(a, sizeof(lv_anim_t)); - a->time = 500; + a->duration = 500; a->start_value = 0; a->end_value = 100; a->repeat_cnt = 1; @@ -85,9 +86,6 @@ lv_anim_t * lv_anim_start(const lv_anim_t * a) { LV_TRACE_ANIM("begin"); - /*Do not let two animations for the same 'var' with the same 'exec_cb'*/ - if(a->exec_cb != NULL) lv_anim_delete(a->var, a->exec_cb); /*exec_cb == NULL would delete all animations of var*/ - /*Add the new animation to the animation linked list*/ lv_anim_t * new_anim = _lv_ll_ins_head(anim_ll_p); LV_ASSERT_MALLOC(new_anim); @@ -105,6 +103,9 @@ lv_anim_t * lv_anim_start(const lv_anim_t * a) int32_t v_ofs = new_anim->get_value_cb(new_anim); new_anim->start_value += v_ofs; 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); } resolve_time(new_anim); @@ -129,7 +130,7 @@ uint32_t lv_anim_get_playtime(lv_anim_t * a) uint32_t repeate_cnt = a->repeat_cnt; if(repeate_cnt < 1) repeate_cnt = 1; - uint32_t playtime = a->repeat_delay + a->time + a->playback_delay + a->playback_time; + uint32_t playtime = a->repeat_delay + a->duration + a->playback_delay + a->playback_time; playtime = playtime * a->repeat_cnt; return playtime; } @@ -229,7 +230,7 @@ void lv_anim_refr_now(void) int32_t lv_anim_path_linear(const lv_anim_t * a) { /*Calculate the current step*/ - int32_t step = lv_map(a->act_time, 0, a->time, 0, LV_ANIM_RESOLUTION); + int32_t step = lv_map(a->act_time, 0, a->duration, 0, LV_ANIM_RESOLUTION); /*Get the new value which will be proportional to `step` *and the `start` and `end` values*/ @@ -267,7 +268,7 @@ int32_t lv_anim_path_overshoot(const lv_anim_t * a) int32_t lv_anim_path_bounce(const lv_anim_t * a) { /*Calculate the current step*/ - int32_t t = lv_map(a->act_time, 0, a->time, 0, LV_BEZIER_VAL_MAX); + int32_t t = lv_map(a->act_time, 0, a->duration, 0, LV_BEZIER_VAL_MAX); int32_t diff = (a->end_value - a->start_value); /*3 bounces has 5 parts: 3 down and 2 up. One part is t / 5 long*/ @@ -317,7 +318,7 @@ int32_t lv_anim_path_bounce(const lv_anim_t * a) int32_t lv_anim_path_step(const lv_anim_t * a) { - if(a->act_time >= a->time) + if(a->act_time >= a->duration) return a->end_value; else return a->start_value; @@ -332,7 +333,7 @@ int32_t lv_anim_path_custom_bezier3(const lv_anim_t * a) /********************** * STATIC FUNCTIONS **********************/ - +#include /** * Periodically handle the animations. * @param param unused @@ -347,8 +348,14 @@ static void anim_timer(lv_timer_t * param) lv_anim_t * a = _lv_ll_get_head(anim_ll_p); while(a != NULL) { + + // printf("%p, %d\n", a, a->start_value); + uint32_t elaps = lv_tick_elaps(a->last_timer_run); + 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 * happened in `anim_ready_handler` which could make this linked list reading corrupt * because the list is changed meanwhile @@ -359,8 +366,8 @@ static void anim_timer(lv_timer_t * param) 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`*/ - int32_t new_act_time = a->act_time + elaps; - if(!a->start_cb_called && a->act_time <= 0 && new_act_time >= 0) { + if(!a->start_cb_called && a->act_time >= 0) { + if(a->early_apply == 0 && a->get_value_cb) { int32_t v_ofs = a->get_value_cb(a); a->start_value += v_ofs; @@ -371,10 +378,13 @@ static void anim_timer(lv_timer_t * param) if(a->start_cb) a->start_cb(a); a->start_cb_called = 1; + + /*Do not let two animations for the same 'var' with the same 'exec_cb'*/ + remove_concurrent_anims(a); } - a->act_time += elaps; + if(a->act_time >= 0) { - if(a->act_time > a->time) a->act_time = a->time; + if(a->act_time > a->duration) a->act_time = a->duration; int32_t new_value; new_value = a->path_cb(a); @@ -386,7 +396,7 @@ static void anim_timer(lv_timer_t * param) } /*If the time is elapsed the animation is ready*/ - if(a->act_time >= a->time) { + if(a->act_time >= a->duration) { anim_ready_handler(a); } } @@ -445,8 +455,8 @@ static void anim_ready_handler(lv_anim_t * a) a->start_value = a->end_value; a->end_value = tmp; /*Swap the time and playback_time*/ - tmp = a->time; - a->time = a->playback_time; + tmp = a->duration; + a->duration = a->playback_time; a->playback_time = tmp; } } @@ -464,7 +474,7 @@ static void anim_mark_list_change(void) 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) { /*Calculate the current step*/ - uint32_t t = lv_map(a->act_time, 0, a->time, 0, LV_BEZIER_VAL_MAX); + uint32_t t = lv_map(a->act_time, 0, a->duration, 0, LV_BEZIER_VAL_MAX); int32_t step = lv_cubic_bezier(t, x1, y1, x2, y2); int32_t new_value; @@ -491,9 +501,45 @@ static uint32_t convert_speed_to_time(uint32_t speed_or_time, int32_t start, int static void resolve_time(lv_anim_t * a) { - a->time = convert_speed_to_time(a->time, a->start_value, a->end_value); - a->act_time = -convert_speed_to_time(- a->act_time, a->start_value, a->end_value); + a->duration = convert_speed_to_time(a->duration, a->start_value, a->end_value); a->playback_time = convert_speed_to_time(a->playback_time, a->start_value, a->end_value); a->playback_delay = convert_speed_to_time(a->playback_delay, a->start_value, a->end_value); a->repeat_delay = convert_speed_to_time(a->repeat_delay, a->start_value, a->end_value); } + +/** + * Remove animations which are animating the same var with the same exec_cb + * and they are already running or they have early_apply + * @param a_current the current animation, use its var and exec_cb as reference to know what to remove + * @return true: at least one animation was delete + */ +static bool remove_concurrent_anims(lv_anim_t * a_current) +{ + if(a_current->exec_cb == NULL) return false; + + lv_anim_t * a; + bool del_any = false; + a = _lv_ll_get_head(anim_ll_p); + while(a != NULL) { + bool del = false; + if(a != a_current && + (a->act_time >= 0 || a->early_apply) && + (a->var == a_current->var) && + (a->exec_cb == a_current->exec_cb)) { + _lv_ll_remove(anim_ll_p, a); + if(a->deleted_cb != NULL) a->deleted_cb(a); + lv_free(a); + /*Read by `anim_timer`. It need to know if a delete occurred in the linked list*/ + anim_mark_list_change(); + + 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 ec6ac3cc2..d3a694eab 100644 --- a/src/misc/lv_anim.h +++ b/src/misc/lv_anim.h @@ -145,7 +145,7 @@ typedef struct _lv_anim_t { int32_t start_value; /**< Start value*/ int32_t current_value; /**< Current value*/ int32_t end_value; /**< End value*/ - int32_t time; /**< Animation time in ms*/ + int32_t duration; /**< Animation time in ms*/ int32_t act_time; /**< Current time in animation. Set to negative to make delay.*/ uint32_t playback_delay; /**< Wait before play back*/ uint32_t playback_time; /**< Duration of playback animation*/ @@ -218,7 +218,7 @@ static inline void lv_anim_set_exec_cb(lv_anim_t * a, lv_anim_exec_xcb_t exec_cb */ static inline void lv_anim_set_time(lv_anim_t * a, uint32_t duration) { - a->time = duration; + a->duration = duration; } /** @@ -240,7 +240,7 @@ static inline void lv_anim_set_delay(lv_anim_t * a, uint32_t delay) static inline void lv_anim_set_values(lv_anim_t * a, int32_t start, int32_t end) { a->start_value = start; - a->current_value = start; + a->current_value = INT32_MIN; a->end_value = end; } @@ -419,7 +419,7 @@ uint32_t lv_anim_get_playtime(lv_anim_t * a); */ static inline uint32_t lv_anim_get_time(lv_anim_t * a) { - return a->time; + return a->duration; } /** diff --git a/src/misc/lv_anim_timeline.c b/src/misc/lv_anim_timeline.c index 382bfc1fa..f9d0e65ad 100644 --- a/src/misc/lv_anim_timeline.c +++ b/src/misc/lv_anim_timeline.c @@ -87,7 +87,7 @@ uint32_t lv_anim_timeline_start(lv_anim_timeline_t * at) int32_t temp = a.start_value; a.start_value = a.end_value; a.end_value = temp; - lv_anim_set_delay(&a, playtime - (start_time + a.time)); + lv_anim_set_delay(&a, playtime - (start_time + a.duration)); } else { lv_anim_set_delay(&a, start_time); @@ -131,19 +131,20 @@ void lv_anim_timeline_set_progress(lv_anim_timeline_t * at, uint16_t progress) uint32_t start_time = at->anim_dsc[i].start_time; int32_t value = 0; - - if(act_time < start_time) { + if(act_time < start_time && a->early_apply) { value = a->start_value; + a->exec_cb(a->var, value); } - else if(act_time < (start_time + a->time)) { + else if(act_time >= start_time && act_time <= (start_time + a->duration)) { a->act_time = act_time - start_time; value = a->path_cb(a); + a->exec_cb(a->var, value); } - else { + else if(act_time > start_time + a->duration) { value = a->end_value; + a->exec_cb(a->var, value); } - a->exec_cb(a->var, value); } } diff --git a/src/widgets/label/lv_label.c b/src/widgets/label/lv_label.c index 83a66da2f..7b5846ac8 100644 --- a/src/widgets/label/lv_label.c +++ b/src/widgets/label/lv_label.c @@ -903,7 +903,7 @@ static void lv_label_refr_text(lv_obj_t * obj) act_time = anim_cur->act_time; playback_now = anim_cur->playback_now; } - if(act_time < a.time) { + if(act_time < a.duration) { a.act_time = act_time; /*To keep the old position*/ a.early_apply = 0; if(playback_now) { @@ -917,7 +917,7 @@ static void lv_label_refr_text(lv_obj_t * obj) } lv_anim_set_time(&a, anim_time); - lv_anim_set_playback_time(&a, a.time); + lv_anim_set_playback_time(&a, a.duration); /*If a template animation exists, overwrite some property*/ if(anim_template) @@ -942,7 +942,7 @@ static void lv_label_refr_text(lv_obj_t * obj) act_time = anim_cur->act_time; playback_now = anim_cur->playback_now; } - if(act_time < a.time) { + if(act_time < a.duration) { a.act_time = act_time; /*To keep the old position*/ a.early_apply = 0; if(playback_now) { @@ -956,7 +956,7 @@ static void lv_label_refr_text(lv_obj_t * obj) } lv_anim_set_time(&a, anim_time); - lv_anim_set_playback_time(&a, a.time); + lv_anim_set_playback_time(&a, a.duration); /*If a template animation exists, overwrite some property*/ if(anim_template) @@ -1011,7 +1011,7 @@ static void lv_label_refr_text(lv_obj_t * obj) if(anim_template) { overwrite_anim_property(&a, anim_template, label->long_mode); } - else if(act_time < a.time) { + else if(act_time < a.duration) { a.act_time = act_time; /*To keep the old position when the label text is updated mid-scrolling*/ a.early_apply = 0; } @@ -1037,7 +1037,7 @@ static void lv_label_refr_text(lv_obj_t * obj) if(anim_template) { overwrite_anim_property(&a, anim_template, label->long_mode); } - else if(act_time < a.time) { + else if(act_time < a.duration) { a.act_time = act_time; /*To keep the old position when the label text is updated mid-scrolling*/ a.early_apply = 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2756b5afe..ebbeb7c61 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -176,6 +176,7 @@ add_library(test_common STATIC src/lv_test_indev.c src/lv_test_init.c + src/lv_test_helpers.c src/test_assets/test_animimg001.c src/test_assets/test_animimg002.c src/test_assets/test_animimg003.c diff --git a/tests/src/lv_test_helpers.c b/tests/src/lv_test_helpers.c new file mode 100644 index 000000000..7362bfd68 --- /dev/null +++ b/tests/src/lv_test_helpers.c @@ -0,0 +1,12 @@ +#if LV_BUILD_TEST + +#include "lv_test_helpers.h" + +void lv_test_wait(uint32_t ms) +{ + lv_tick_inc(ms); + lv_timer_handler(); + lv_refr_now(NULL); +} + +#endif diff --git a/tests/src/lv_test_helpers.h b/tests/src/lv_test_helpers.h index 6377f09d4..c24d85957 100644 --- a/tests/src/lv_test_helpers.h +++ b/tests/src/lv_test_helpers.h @@ -2,6 +2,7 @@ #define LV_TEST_HELPERS_H #include "lv_test_conf.h" +#include "../lvgl.h" #ifdef LVGL_CI_USING_SYS_HEAP /* Skip checking heap as we don't have the info available */ @@ -21,4 +22,6 @@ static inline uint32_t lv_test_get_free_mem(void) #define CANVAS_WIDTH_TO_STRIDE(w, px_size) ((((w) * (px_size) + (LV_DRAW_BUF_STRIDE_ALIGN - 1)) / LV_DRAW_BUF_STRIDE_ALIGN) * LV_DRAW_BUF_STRIDE_ALIGN) +void lv_test_wait(uint32_t ms); + #endif /*LV_TEST_HELPERS_H*/ diff --git a/tests/src/test_cases/test_anim_timeline.c b/tests/src/test_cases/test_anim_timeline.c index 6ac472acd..a1fabf4b5 100644 --- a/tests/src/test_cases/test_anim_timeline.c +++ b/tests/src/test_cases/test_anim_timeline.c @@ -3,6 +3,7 @@ #include "../lvgl.h" #include "unity/unity.h" +#include "lv_test_helpers.h" static lv_anim_timeline_t * anim_timeline; @@ -144,4 +145,181 @@ void test_anim_timeline_progress_2(void) TEST_ASSERT_EQUAL(300, lv_obj_get_y(obj)); } +void test_anim_timeline_start(void) +{ + lv_obj_t * obj = lv_obj_create(lv_scr_act()); + lv_obj_set_size(obj, 100, 100); + + lv_obj_set_pos(obj, 70, 70); + + /* + * |------1------| + * |-----Y-----| + * |--------Z--------| + * 0 200 1000 1500 2000 2500 3500 ms + * ? 50 100 200 400 700 value (px) + */ + + anim_timeline = lv_anim_timeline_create(); + + lv_anim_t a1; + lv_anim_init(&a1); + lv_anim_set_exec_cb(&a1, (lv_anim_exec_xcb_t)lv_obj_set_x); + lv_anim_set_var(&a1, obj); + lv_anim_set_values(&a1, 50, 100); + lv_anim_set_time(&a1, 800); + lv_anim_set_early_apply(&a1, false); + lv_anim_timeline_add(anim_timeline, 200, &a1); + + lv_anim_set_values(&a1, 200, 300); + lv_anim_set_time(&a1, 1000); + lv_anim_timeline_add(anim_timeline, 1500, &a1); + + /*Overlap with the previous*/ + lv_anim_set_values(&a1, 400, 700); + lv_anim_set_time(&a1, 1500); + lv_anim_timeline_add(anim_timeline, 2000, &a1); + + lv_anim_timeline_start(anim_timeline); + + /*As doesn't start at the beginning keep the original value*/ + lv_refr_now(NULL); + TEST_ASSERT_EQUAL(70, lv_obj_get_x(obj)); + + lv_test_wait(199); + TEST_ASSERT_EQUAL(70, lv_obj_get_x(obj)); + + lv_test_wait(1); /*200*/ + TEST_ASSERT_EQUAL(50, lv_obj_get_x(obj)); + + lv_test_wait(400); /*600*/ + TEST_ASSERT_EQUAL(75, lv_obj_get_x(obj)); + + lv_test_wait(400); /*1000*/ + TEST_ASSERT_EQUAL(100, lv_obj_get_x(obj)); + + /*There is a gap*/ + lv_test_wait(100); /*1100*/ + TEST_ASSERT_EQUAL(100, lv_obj_get_x(obj)); + + /*Nothing should change it*/ + lv_obj_set_x(obj, 10); + + lv_test_wait(100); /*1200*/ + TEST_ASSERT_EQUAL(10, lv_obj_get_x(obj)); + + lv_test_wait(300); /*1500*/ + TEST_ASSERT_EQUAL(200, lv_obj_get_x(obj)); + + lv_test_wait(499); /*1999*/ + TEST_ASSERT_EQUAL(249, lv_obj_get_x(obj)); + + lv_test_wait(1); /*2000*/ + TEST_ASSERT_EQUAL(400, lv_obj_get_x(obj)); + + lv_test_wait(500); /*2500*/ + TEST_ASSERT_EQUAL(499, lv_obj_get_x(obj)); + + lv_test_wait(500); /*3000*/ + TEST_ASSERT_EQUAL(599, lv_obj_get_x(obj)); + + lv_test_wait(500); /*3500*/ + TEST_ASSERT_EQUAL(700, lv_obj_get_x(obj)); + + lv_test_wait(500); /*3500*/ + TEST_ASSERT_EQUAL(700, lv_obj_get_x(obj)); + + /*Nothing should change it*/ + lv_obj_set_x(obj, 20); + + lv_test_wait(100); /*3600*/ + TEST_ASSERT_EQUAL(20, lv_obj_get_x(obj)); +} + +void test_anim_timeline_reverse(void) +{ + lv_obj_t * obj = lv_obj_create(lv_scr_act()); + lv_obj_set_size(obj, 100, 100); + + lv_obj_set_pos(obj, 70, 70); + + /* Reverse this: + * |------1------| + * |-----Y-----| + * |--------Z--------| + * 0 200 1000 1500 2000 2500 3500 ms + * ? 50 100 200 300 700 value (px) + */ + + anim_timeline = lv_anim_timeline_create(); + lv_anim_timeline_set_reverse(anim_timeline, true); + + lv_anim_t a1; + lv_anim_init(&a1); + lv_anim_set_exec_cb(&a1, (lv_anim_exec_xcb_t)lv_obj_set_x); + lv_anim_set_var(&a1, obj); + lv_anim_set_values(&a1, 50, 100); + lv_anim_set_time(&a1, 800); + lv_anim_set_early_apply(&a1, false); + lv_anim_timeline_add(anim_timeline, 200, &a1); + + lv_anim_set_values(&a1, 200, 300); + lv_anim_set_time(&a1, 1000); + lv_anim_timeline_add(anim_timeline, 1500, &a1); + + /*Overlap with the previous*/ + lv_anim_set_values(&a1, 400, 700); + lv_anim_set_time(&a1, 1500); + lv_anim_timeline_add(anim_timeline, 2000, &a1); + + lv_anim_timeline_set_reverse(anim_timeline, true); + lv_anim_timeline_start(anim_timeline); /*0 (3500)*/ + + lv_refr_now(NULL); + TEST_ASSERT_EQUAL(700, lv_obj_get_x(obj)); + + lv_test_wait(999); /*999 (2501)*/ + TEST_ASSERT_EQUAL(500, lv_obj_get_x(obj)); + + lv_test_wait(201); /*1200 (2300)*/ + TEST_ASSERT_EQUAL(280, lv_obj_get_x(obj)); + + lv_test_wait(300); /*1500 (2000)*/ + TEST_ASSERT_EQUAL(250, lv_obj_get_x(obj)); + + lv_test_wait(500); /*2000 (1500)*/ + TEST_ASSERT_EQUAL(200, lv_obj_get_x(obj)); + + /*There is a gap*/ + lv_test_wait(100); /*2100 (1400)*/ + TEST_ASSERT_EQUAL(200, lv_obj_get_x(obj)); + + /*Nothing should change it*/ + lv_obj_set_x(obj, 10); + + lv_test_wait(100); /*2200 (1300)*/ + TEST_ASSERT_EQUAL(10, lv_obj_get_x(obj)); + + lv_test_wait(300); /*2500 (1000)*/ + TEST_ASSERT_EQUAL(100, lv_obj_get_x(obj)); + + lv_test_wait(400); /*2900 (600)*/ + TEST_ASSERT_EQUAL(75, lv_obj_get_x(obj)); + + lv_test_wait(400); /*3300 (200)*/ + TEST_ASSERT_EQUAL(50, lv_obj_get_x(obj)); + + /*There is a gap*/ + lv_test_wait(100); /*3400 (100)*/ + TEST_ASSERT_EQUAL(50, lv_obj_get_x(obj)); + + /*Nothing should change it*/ + lv_obj_set_x(obj, 20); + lv_test_wait(100); + TEST_ASSERT_EQUAL(20, lv_obj_get_x(obj)); + + lv_test_wait(1000); + TEST_ASSERT_EQUAL(20, lv_obj_get_x(obj)); +} + #endif