1 /**
2 * @file lv_anim_timeline.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_anim_private.h"
10 #include "lv_assert.h"
11 #include "lv_anim_timeline.h"
12 #include "../stdlib/lv_mem.h"
13 #include "../stdlib/lv_string.h"
14
15 /*********************
16 * DEFINES
17 *********************/
18
19 /**********************
20 * TYPEDEFS
21 **********************/
22 /*Data of anim_timeline_dsc*/
23 typedef struct {
24 lv_anim_t anim;
25 uint32_t start_time;
26 uint8_t is_started : 1;
27 uint8_t is_completed : 1;
28 } lv_anim_timeline_dsc_t;
29
30 /*Data of anim_timeline*/
31 struct _lv_anim_timeline_t {
32 lv_anim_timeline_dsc_t * anim_dsc; /**< Dynamically allocated anim dsc array*/
33 uint32_t anim_dsc_cnt; /**< The length of anim dsc array*/
34 uint32_t act_time; /**< Current time of the animation*/
35 bool reverse; /**< Reverse playback*/
36 uint32_t repeat_count; /**< Repeat count*/
37 uint32_t repeat_delay; /**< Wait before repeat*/
38 };
39
40 /**********************
41 * STATIC PROTOTYPES
42 **********************/
43 static void anim_timeline_exec_cb(void * var, int32_t v);
44 static void anim_timeline_set_act_time(lv_anim_timeline_t * at, uint32_t act_time);
45 static int32_t anim_timeline_path_cb(const lv_anim_t * a);
46
47 /**********************
48 * STATIC VARIABLES
49 **********************/
50
51 /**********************
52 * MACROS
53 **********************/
54
55 /**********************
56 * GLOBAL FUNCTIONS
57 **********************/
58
lv_anim_timeline_create(void)59 lv_anim_timeline_t * lv_anim_timeline_create(void)
60 {
61 lv_anim_timeline_t * at = lv_malloc_zeroed(sizeof(lv_anim_timeline_t));
62 LV_ASSERT_MALLOC(at);
63 return at;
64 }
65
lv_anim_timeline_delete(lv_anim_timeline_t * at)66 void lv_anim_timeline_delete(lv_anim_timeline_t * at)
67 {
68 LV_ASSERT_NULL(at);
69
70 lv_anim_timeline_pause(at);
71
72 lv_free(at->anim_dsc);
73 lv_free(at);
74 }
75
lv_anim_timeline_add(lv_anim_timeline_t * at,uint32_t start_time,const lv_anim_t * a)76 void lv_anim_timeline_add(lv_anim_timeline_t * at, uint32_t start_time, const lv_anim_t * a)
77 {
78 LV_ASSERT_NULL(at);
79
80 at->anim_dsc_cnt++;
81 at->anim_dsc = lv_realloc(at->anim_dsc, at->anim_dsc_cnt * sizeof(lv_anim_timeline_dsc_t));
82
83 LV_ASSERT_MALLOC(at->anim_dsc);
84
85 at->anim_dsc[at->anim_dsc_cnt - 1].anim = *a;
86 at->anim_dsc[at->anim_dsc_cnt - 1].start_time = start_time;
87 }
88
lv_anim_timeline_start(lv_anim_timeline_t * at)89 uint32_t lv_anim_timeline_start(lv_anim_timeline_t * at)
90 {
91 LV_ASSERT_NULL(at);
92
93 uint32_t playtime = lv_anim_timeline_get_playtime(at);
94 uint32_t repeat = at->repeat_count;
95 uint32_t delay = at->repeat_delay;
96 uint32_t start = at->act_time;
97 uint32_t end = at->reverse ? 0 : playtime;
98 uint32_t duration = end > start ? end - start : start - end;
99
100 if((!at->reverse && at->act_time == 0) || (at->reverse && at->act_time == playtime)) {
101 for(uint32_t i = 0; i < at->anim_dsc_cnt; i++) {
102 at->anim_dsc[i].is_started = 0;
103 at->anim_dsc[i].is_completed = 0;
104 }
105 }
106
107 lv_anim_t a;
108 lv_anim_init(&a);
109 lv_anim_set_var(&a, at);
110 lv_anim_set_exec_cb(&a, anim_timeline_exec_cb);
111 lv_anim_set_values(&a, start, end);
112 lv_anim_set_duration(&a, duration);
113 lv_anim_set_path_cb(&a, anim_timeline_path_cb);
114 lv_anim_set_repeat_count(&a, repeat);
115 lv_anim_set_repeat_delay(&a, delay);
116 lv_anim_start(&a);
117 return playtime;
118 }
119
lv_anim_timeline_pause(lv_anim_timeline_t * at)120 void lv_anim_timeline_pause(lv_anim_timeline_t * at)
121 {
122 LV_ASSERT_NULL(at);
123
124 lv_anim_delete(at, anim_timeline_exec_cb);
125 }
126
lv_anim_timeline_set_reverse(lv_anim_timeline_t * at,bool reverse)127 void lv_anim_timeline_set_reverse(lv_anim_timeline_t * at, bool reverse)
128 {
129 LV_ASSERT_NULL(at);
130 at->reverse = reverse;
131 }
132
lv_anim_timeline_set_repeat_count(lv_anim_timeline_t * at,uint32_t cnt)133 void lv_anim_timeline_set_repeat_count(lv_anim_timeline_t * at, uint32_t cnt)
134 {
135 LV_ASSERT_NULL(at);
136 at->repeat_count = cnt;
137 }
138
lv_anim_timeline_set_repeat_delay(lv_anim_timeline_t * at,uint32_t delay)139 void lv_anim_timeline_set_repeat_delay(lv_anim_timeline_t * at, uint32_t delay)
140 {
141 LV_ASSERT_NULL(at);
142 at->repeat_delay = delay;
143 }
144
lv_anim_timeline_set_progress(lv_anim_timeline_t * at,uint16_t progress)145 void lv_anim_timeline_set_progress(lv_anim_timeline_t * at, uint16_t progress)
146 {
147 LV_ASSERT_NULL(at);
148
149 uint32_t playtime = lv_anim_timeline_get_playtime(at);
150 uint32_t act_time = lv_map(progress, 0, LV_ANIM_TIMELINE_PROGRESS_MAX, 0, playtime);
151 anim_timeline_set_act_time(at, act_time);
152 }
153
lv_anim_timeline_get_playtime(lv_anim_timeline_t * at)154 uint32_t lv_anim_timeline_get_playtime(lv_anim_timeline_t * at)
155 {
156 LV_ASSERT_NULL(at);
157
158 uint32_t playtime = 0;
159 for(uint32_t i = 0; i < at->anim_dsc_cnt; i++) {
160 uint32_t end = lv_anim_get_playtime(&at->anim_dsc[i].anim);
161 if(end == LV_ANIM_PLAYTIME_INFINITE)
162 return end;
163 end += at->anim_dsc[i].start_time;
164 if(end > playtime) {
165 playtime = end;
166 }
167 }
168
169 return playtime;
170 }
171
lv_anim_timeline_get_reverse(lv_anim_timeline_t * at)172 bool lv_anim_timeline_get_reverse(lv_anim_timeline_t * at)
173 {
174 LV_ASSERT_NULL(at);
175 return at->reverse;
176 }
177
lv_anim_timeline_get_progress(lv_anim_timeline_t * at)178 uint16_t lv_anim_timeline_get_progress(lv_anim_timeline_t * at)
179 {
180 LV_ASSERT_NULL(at);
181 uint32_t playtime = lv_anim_timeline_get_playtime(at);
182 return lv_map(at->act_time, 0, playtime, 0, LV_ANIM_TIMELINE_PROGRESS_MAX);
183 }
184
lv_anim_timeline_get_repeat_count(lv_anim_timeline_t * at)185 uint32_t lv_anim_timeline_get_repeat_count(lv_anim_timeline_t * at)
186 {
187 LV_ASSERT_NULL(at);
188 return at->repeat_count;
189 }
190
lv_anim_timeline_get_repeat_delay(lv_anim_timeline_t * at)191 uint32_t lv_anim_timeline_get_repeat_delay(lv_anim_timeline_t * at)
192 {
193 LV_ASSERT_NULL(at);
194 return at->repeat_delay;
195 }
196
197 /**********************
198 * STATIC FUNCTIONS
199 **********************/
200
anim_timeline_set_act_time(lv_anim_timeline_t * at,uint32_t act_time)201 static void anim_timeline_set_act_time(lv_anim_timeline_t * at, uint32_t act_time)
202 {
203 at->act_time = act_time;
204 bool anim_timeline_is_started = (lv_anim_get(at, anim_timeline_exec_cb) != NULL);
205 for(uint32_t i = 0; i < at->anim_dsc_cnt; i++) {
206 lv_anim_timeline_dsc_t * anim_dsc = &(at->anim_dsc[i]);
207 lv_anim_t * a = &(anim_dsc->anim);
208
209 uint32_t start_time = anim_dsc->start_time;
210 int32_t value = 0;
211
212 if(act_time < start_time && a->early_apply) {
213 if(anim_timeline_is_started) {
214 if(at->reverse) {
215 if(!anim_dsc->is_started && a->start_cb) a->start_cb(a);
216 anim_dsc->is_started = 1;
217 }
218 else {
219 anim_dsc->is_started = 0;
220 }
221 }
222
223 value = a->start_value;
224 if(a->exec_cb) a->exec_cb(a->var, value);
225 if(a->custom_exec_cb) a->custom_exec_cb(a, value);
226
227 if(anim_timeline_is_started) {
228 if(at->reverse) {
229 if(!anim_dsc->is_completed && a->completed_cb) a->completed_cb(a);
230 anim_dsc->is_completed = 1;
231 }
232 else {
233 anim_dsc->is_completed = 0;
234 }
235 }
236 }
237 else if(act_time >= start_time && act_time <= (start_time + a->duration)) {
238 if(anim_timeline_is_started) {
239 if(!anim_dsc->is_started && a->start_cb) a->start_cb(a);
240 anim_dsc->is_started = 1;
241 }
242
243 a->act_time = act_time - start_time;
244 value = a->path_cb(a);
245 if(a->exec_cb) a->exec_cb(a->var, value);
246 if(a->custom_exec_cb) a->custom_exec_cb(a, value);
247
248 if(anim_timeline_is_started) {
249 if(at->reverse) {
250 if(act_time == start_time) {
251 if(!anim_dsc->is_completed && a->completed_cb) a->completed_cb(a);
252 anim_dsc->is_completed = 1;
253 }
254 else {
255 anim_dsc->is_completed = 0;
256 }
257 }
258 else {
259 if(act_time == (start_time + a->duration)) {
260 if(!anim_dsc->is_completed && a->completed_cb) a->completed_cb(a);
261 anim_dsc->is_completed = 1;
262 }
263 else {
264 anim_dsc->is_completed = 0;
265 }
266 }
267 }
268 }
269 else if(act_time > start_time + a->duration) {
270 if(anim_timeline_is_started) {
271 if(at->reverse) {
272 anim_dsc->is_started = 0;
273 }
274 else {
275 if(!anim_dsc->is_started && a->start_cb) a->start_cb(a);
276 anim_dsc->is_started = 1;
277 }
278 }
279
280 value = a->end_value;
281 if(a->exec_cb) a->exec_cb(a->var, value);
282 if(a->custom_exec_cb) a->custom_exec_cb(a, value);
283
284 if(anim_timeline_is_started) {
285 if(at->reverse) {
286 anim_dsc->is_completed = 0;
287 }
288 else {
289 if(!anim_dsc->is_completed && a->completed_cb) a->completed_cb(a);
290 anim_dsc->is_completed = 1;
291 }
292 }
293 }
294 }
295 }
296
anim_timeline_path_cb(const lv_anim_t * a)297 static int32_t anim_timeline_path_cb(const lv_anim_t * a)
298 {
299 /* Directly map original timestamps to avoid loss of accuracy */
300 return lv_map(a->act_time, 0, a->duration, a->start_value, a->end_value);
301 }
302
anim_timeline_exec_cb(void * var,int32_t v)303 static void anim_timeline_exec_cb(void * var, int32_t v)
304 {
305 lv_anim_timeline_t * at = var;
306 anim_timeline_set_act_time(at, v);
307 }
308