1 /**
2  * @file lv_style.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj.h"
10 #include "../lv_misc/lv_mem.h"
11 #include "../lv_misc/lv_anim.h"
12 
13 /*********************
14  *      DEFINES
15  *********************/
16 #define STYLE_MIX_MAX 256
17 #define STYLE_MIX_SHIFT 8 /*log2(STYLE_MIX_MAX)*/
18 
19 #define VAL_PROP(v1, v2, r) v1 + (((v2 - v1) * r) >> STYLE_MIX_SHIFT)
20 #define STYLE_ATTR_MIX(attr, r)                                                                                        \
21     if(start->attr != end->attr) {                                                                                     \
22         res->attr = VAL_PROP(start->attr, end->attr, r);                                                               \
23     } else {                                                                                                           \
24         res->attr = start->attr;                                                                                       \
25     }
26 
27 #define LV_STYLE_PROP_TO_ID(prop) (prop & 0xFF);
28 #define LV_STYLE_PROP_GET_TYPE(prop) ((prop >> 8) & 0xFF);
29 
30 /**********************
31  *      TYPEDEFS
32  **********************/
33 
34 /**********************
35  *  STATIC PROTOTYPES
36  **********************/
37 LV_ATTRIBUTE_FAST_MEM static inline int32_t get_property_index(const lv_style_t * style, lv_style_property_t prop);
38 static lv_style_t * get_alloc_local_style(lv_style_list_t * list);
39 static inline void style_resize(lv_style_t * style, size_t sz);
40 static inline lv_style_property_t get_style_prop(const lv_style_t * style, size_t idx);
41 static inline uint8_t get_style_prop_id(const lv_style_t * style, size_t idx);
42 static inline uint8_t get_style_prop_attr(const lv_style_t * style, size_t idx);
43 static inline size_t get_prop_size(uint8_t prop_id);
44 static inline size_t get_next_prop_index(uint8_t prop_id, size_t id);
45 
46 /**********************
47  *  GLOABAL VARIABLES
48  **********************/
49 
50 /**********************
51  *  STATIC VARIABLES
52  **********************/
53 
54 /**********************
55  *      MACROS
56  **********************/
57 
58 /**********************
59  *   GLOBAL FUNCTIONS
60  **********************/
61 
62 /**
63  * Initialize a style
64  * @param style pointer to a style to initialize
65  */
lv_style_init(lv_style_t * style)66 void lv_style_init(lv_style_t * style)
67 {
68     _lv_memset_00(style, sizeof(lv_style_t));
69 #if LV_USE_ASSERT_STYLE
70     style->sentinel = LV_DEBUG_STYLE_SENTINEL_VALUE;
71 #endif
72 }
73 
74 /**
75  * Copy a style with all its properties
76  * @param style_dest pointer to the destination style. (Should be initialized with `lv_style_init()`)
77  * @param style_src pointer to the source (to copy )style
78  */
lv_style_copy(lv_style_t * style_dest,const lv_style_t * style_src)79 void lv_style_copy(lv_style_t * style_dest, const lv_style_t * style_src)
80 {
81     if(style_src == NULL) return;
82 
83     LV_ASSERT_STYLE(style_dest);
84     LV_ASSERT_STYLE(style_src);
85 
86     if(style_src->map == NULL) return;
87 
88     uint16_t size = _lv_style_get_mem_size(style_src);
89     style_dest->map = lv_mem_alloc(size);
90     _lv_memcpy(style_dest->map, style_src->map, size);
91 }
92 
93 /**
94  * Remove a property from a style
95  * @param style pointer to a style
96  * @param prop  a style property ORed with a state.
97  * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
98  * @return true: the property was found and removed; false: the property wasn't found
99  */
lv_style_remove_prop(lv_style_t * style,lv_style_property_t prop)100 bool lv_style_remove_prop(lv_style_t * style, lv_style_property_t prop)
101 {
102     if(style == NULL) return false;
103     LV_ASSERT_STYLE(style);
104 
105     int32_t id = get_property_index(style, prop);
106     /*The property exists but not sure it's state is the same*/
107     if(id >= 0) {
108         lv_style_attr_t attr_found;
109         lv_style_attr_t attr_goal;
110 
111         attr_found = get_style_prop_attr(style, id);
112         attr_goal = (prop >> 8) & 0xFFU;
113 
114         if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
115             uint32_t map_size = _lv_style_get_mem_size(style);
116             uint8_t prop_size = get_prop_size(prop);
117 
118             /*Move the props to fill the space of the property to delete*/
119             uint32_t i;
120             for(i = id; i < map_size - prop_size; i++) {
121                 style->map[i] = style->map[i + prop_size];
122             }
123 
124             style_resize(style, map_size - prop_size);
125 
126             return true;
127         }
128     }
129 
130     return false;
131 }
132 
133 /**
134  * Initialize a style list
135  * @param list a style list to initialize
136  */
lv_style_list_init(lv_style_list_t * list)137 void lv_style_list_init(lv_style_list_t * list)
138 {
139     _lv_memset_00(list, sizeof(lv_style_list_t));
140 #if LV_USE_ASSERT_STYLE
141     list->sentinel = LV_DEBUG_STYLE_LIST_SENTINEL_VALUE;
142 #endif
143 }
144 
145 /**
146  * Copy a style list with all its styles and local style properties
147  * @param list_dest pointer to the destination style list. (should be initialized with `lv_style_list_init()`)
148  * @param list_src pointer to the source (to copy) style list.
149  */
lv_style_list_copy(lv_style_list_t * list_dest,const lv_style_list_t * list_src)150 void lv_style_list_copy(lv_style_list_t * list_dest, const lv_style_list_t * list_src)
151 {
152     LV_ASSERT_STYLE_LIST(list_dest);
153     LV_ASSERT_STYLE_LIST(list_src);
154 
155     _lv_style_list_reset(list_dest);
156 
157     if(list_src->style_list == NULL) return;
158 
159     /*Copy the styles but skip the transitions*/
160     if(list_src->has_local == 0) {
161         if(list_src->has_trans) {
162             list_dest->style_list = lv_mem_alloc((list_src->style_cnt - 1) * sizeof(lv_style_t *));
163             _lv_memcpy(list_dest->style_list, list_src->style_list + 1, (list_src->style_cnt - 1) * sizeof(lv_style_t *));
164             list_dest->style_cnt = list_src->style_cnt - 1;
165         }
166         else {
167             list_dest->style_list = lv_mem_alloc(list_src->style_cnt * sizeof(lv_style_t *));
168             _lv_memcpy(list_dest->style_list, list_src->style_list, list_src->style_cnt * sizeof(lv_style_t *));
169             list_dest->style_cnt = list_src->style_cnt;
170         }
171     }
172     else {
173         if(list_src->has_trans) {
174             list_dest->style_list = lv_mem_alloc((list_src->style_cnt - 2) * sizeof(lv_style_t *));
175             _lv_memcpy(list_dest->style_list, list_src->style_list + 2, (list_src->style_cnt - 2) * sizeof(lv_style_t *));
176             list_dest->style_cnt = list_src->style_cnt - 2;
177         }
178         else {
179             list_dest->style_list = lv_mem_alloc((list_src->style_cnt - 1) * sizeof(lv_style_t *));
180             _lv_memcpy(list_dest->style_list, list_src->style_list + 1, (list_src->style_cnt - 1) * sizeof(lv_style_t *));
181             list_dest->style_cnt = list_src->style_cnt - 1;
182         }
183 
184         lv_style_t * local_style = get_alloc_local_style(list_dest);
185         lv_style_copy(local_style, get_alloc_local_style((lv_style_list_t *)list_src));
186     }
187 }
188 
189 /**
190  * Add a style to a style list.
191  * Only the the style pointer will be saved so the shouldn't be a local variable.
192  * (It should be static, global or dynamically allocated)
193  * @param list pointer to a style list
194  * @param style pointer to a style to add
195  */
_lv_style_list_add_style(lv_style_list_t * list,lv_style_t * style)196 void _lv_style_list_add_style(lv_style_list_t * list, lv_style_t * style)
197 {
198     LV_ASSERT_STYLE_LIST(list);
199     LV_ASSERT_STYLE(style);
200 
201     if(list == NULL) return;
202 
203     /*Remove the style first if already exists*/
204     _lv_style_list_remove_style(list, style);
205 
206     lv_style_t ** new_classes;
207     if(list->style_cnt == 0) new_classes = lv_mem_alloc(sizeof(lv_style_t *));
208     else new_classes = lv_mem_realloc(list->style_list, sizeof(lv_style_t *) * (list->style_cnt + 1));
209     LV_ASSERT_MEM(new_classes);
210     if(new_classes == NULL) {
211         LV_LOG_WARN("lv_style_list_add_style: couldn't add the class");
212         return;
213     }
214 
215     /*Make space for the new style at the beginning. Leave local and trans style if exists*/
216     uint8_t i;
217     uint8_t first_style = 0;
218     if(list->has_trans) first_style++;
219     if(list->has_local) first_style++;
220     for(i = list->style_cnt; i > first_style; i--) {
221         new_classes[i] = new_classes[i - 1];
222     }
223 
224     new_classes[first_style] = style;
225     list->style_cnt++;
226     list->style_list = new_classes;
227 }
228 
229 /**
230  * Remove a style from a style list
231  * @param style_list pointer to a style list
232  * @param style pointer to a style to remove
233  */
_lv_style_list_remove_style(lv_style_list_t * list,lv_style_t * style)234 void _lv_style_list_remove_style(lv_style_list_t * list, lv_style_t * style)
235 {
236     LV_ASSERT_STYLE_LIST(list);
237     LV_ASSERT_STYLE(style);
238 
239     if(list->style_cnt == 0) return;
240 
241     /*Check if the style really exists here*/
242     uint8_t i;
243     bool found = false;
244     for(i = 0; i < list->style_cnt; i++) {
245         if(list->style_list[i] == style) {
246             found = true;
247             break;
248         }
249     }
250     if(found == false) return;
251 
252     if(list->style_cnt == 1) {
253         lv_mem_free(list->style_list);
254         list->style_list = NULL;
255         list->style_cnt = 0;
256         list->has_local = 0;
257         return;
258     }
259 
260     lv_style_t ** new_classes = lv_mem_alloc(sizeof(lv_style_t *) * (list->style_cnt - 1));
261     LV_ASSERT_MEM(new_classes);
262     if(new_classes == NULL) {
263         LV_LOG_WARN("lv_style_list_remove_style: couldn't reallocate class list");
264         return;
265     }
266     uint8_t j;
267     for(i = 0, j = 0; i < list->style_cnt; i++) {
268         if(list->style_list[i] == style) continue;
269         new_classes[j] = list->style_list[i];
270         j++;
271 
272     }
273 
274     lv_mem_free(list->style_list);
275 
276     list->style_cnt--;
277     list->style_list = new_classes;
278 }
279 
280 /**
281  * Remove all styles added from style list, clear the local style, transition style and free all allocated memories.
282  * Leave `ignore_trans` flag as it is.
283  * @param list pointer to a style list.
284  */
_lv_style_list_reset(lv_style_list_t * list)285 void _lv_style_list_reset(lv_style_list_t * list)
286 {
287     LV_ASSERT_STYLE_LIST(list);
288 
289     if(list == NULL) return;
290 
291     if(list->has_local) {
292         lv_style_t * local = lv_style_list_get_local_style(list);
293         if(local) {
294             lv_style_reset(local);
295             lv_mem_free(local);
296         }
297     }
298 
299     if(list->has_trans) {
300         lv_style_t * trans = _lv_style_list_get_transition_style(list);
301         if(trans) {
302             lv_style_reset(trans);
303             lv_mem_free(trans);
304         }
305     }
306 
307     if(list->style_cnt > 0) lv_mem_free(list->style_list);
308     list->style_list = NULL;
309     list->style_cnt = 0;
310     list->has_local = 0;
311     list->has_trans = 0;
312     list->skip_trans = 0;
313 
314     /* Intentionally leave `ignore_trans` as it is,
315      * because it's independent from the styles in the list*/
316 }
317 
318 /**
319  * Clear all properties from a style and all allocated memories.
320  * @param style pointer to a style
321  */
lv_style_reset(lv_style_t * style)322 void lv_style_reset(lv_style_t * style)
323 {
324     LV_ASSERT_STYLE(style);
325 
326     lv_mem_free(style->map);
327     style->map = NULL;
328 }
329 
330 /**
331  * Get the size of the properties in a style in bytes
332  * @param style pointer to a style
333  * @return size of the properties in bytes
334  */
_lv_style_get_mem_size(const lv_style_t * style)335 uint16_t _lv_style_get_mem_size(const lv_style_t * style)
336 {
337     LV_ASSERT_STYLE(style);
338 
339     if(style->map == NULL) return 0;
340 
341     size_t i = 0;
342     uint8_t prop_id;
343     while((prop_id = get_style_prop_id(style, i)) != _LV_STYLE_CLOSEING_PROP) {
344         i = get_next_prop_index(prop_id, i);
345     }
346 
347     return i + sizeof(lv_style_property_t);
348 }
349 
350 /**
351  * Set an integer typed property in a style.
352  * @param style pointer to a style where the property should be set
353  * @param prop a style property ORed with a state.
354  * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
355  * @param value the value to set
356  * @note shouldn't be used directly. Use the specific property set functions instead.
357  *       For example: `lv_style_set_border_width()`
358  * @note for performance reasons it's not checked if the property really has integer type
359  */
_lv_style_set_int(lv_style_t * style,lv_style_property_t prop,lv_style_int_t value)360 void _lv_style_set_int(lv_style_t * style, lv_style_property_t prop, lv_style_int_t value)
361 {
362     LV_ASSERT_STYLE(style);
363 
364     int32_t id = get_property_index(style, prop);
365     /*The property already exists but not sure it's state is the same*/
366     if(id >= 0) {
367         lv_style_attr_t attr_found;
368         lv_style_attr_t attr_goal;
369 
370         attr_found = get_style_prop_attr(style, id);
371         attr_goal = (prop >> 8) & 0xFFU;
372 
373         if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
374             _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &value, sizeof(lv_style_int_t));
375             return;
376         }
377     }
378 
379     /*Add new property if not exists yet*/
380     uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(lv_style_int_t));
381     lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
382     uint8_t end_mark_size = sizeof(end_mark);
383 
384     uint16_t size = _lv_style_get_mem_size(style);
385     if(size == 0) size += end_mark_size;
386     size += sizeof(lv_style_property_t) + sizeof(lv_style_int_t);
387     style_resize(style, size);
388     LV_ASSERT_MEM(style->map);
389     if(style == NULL) return;
390 
391     _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
392     _lv_memcpy_small(style->map + size - sizeof(lv_style_int_t) - end_mark_size, &value, sizeof(lv_style_int_t));
393     _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
394 }
395 
396 /**
397  * Set a color typed property in a style.
398  * @param style pointer to a style where the property should be set
399  * @param prop a style property ORed with a state.
400  * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
401  * @param value the value to set
402  * @note shouldn't be used directly. Use the specific property set functions instead.
403  *       For example: `lv_style_set_border_color()`
404  * @note for performance reasons it's not checked if the property really has color type
405  */
_lv_style_set_color(lv_style_t * style,lv_style_property_t prop,lv_color_t color)406 void _lv_style_set_color(lv_style_t * style, lv_style_property_t prop, lv_color_t color)
407 {
408     LV_ASSERT_STYLE(style);
409 
410     int32_t id = get_property_index(style, prop);
411     /*The property already exists but not sure it's state is the same*/
412     if(id >= 0) {
413         lv_style_attr_t attr_found;
414         lv_style_attr_t attr_goal;
415 
416         attr_found = get_style_prop_attr(style, id);
417         attr_goal = (prop >> 8) & 0xFFU;
418 
419         if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
420             _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &color, sizeof(lv_color_t));
421             return;
422         }
423     }
424 
425     /*Add new property if not exists yet*/
426     uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(lv_color_t));
427     lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
428     uint8_t end_mark_size = sizeof(end_mark);
429 
430     uint16_t size = _lv_style_get_mem_size(style);
431     if(size == 0) size += end_mark_size;
432 
433     size += sizeof(lv_style_property_t) + sizeof(lv_color_t);
434     style_resize(style, size);
435     LV_ASSERT_MEM(style->map);
436     if(style == NULL) return;
437 
438     _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
439     _lv_memcpy_small(style->map + size - sizeof(lv_color_t) - end_mark_size, &color, sizeof(lv_color_t));
440     _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
441 }
442 
443 /**
444  * Set an opacity typed property in a style.
445  * @param style pointer to a style where the property should be set
446  * @param prop a style property ORed with a state.
447  * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
448  * @param value the value to set
449  * @note shouldn't be used directly. Use the specific property set functions instead.
450  *       For example: `lv_style_set_border_opa()`
451  * @note for performance reasons it's not checked if the property really has opacity type
452  */
_lv_style_set_opa(lv_style_t * style,lv_style_property_t prop,lv_opa_t opa)453 void _lv_style_set_opa(lv_style_t * style, lv_style_property_t prop, lv_opa_t opa)
454 {
455     LV_ASSERT_STYLE(style);
456 
457     int32_t id = get_property_index(style, prop);
458     /*The property already exists but not sure it's state is the same*/
459     if(id >= 0) {
460         lv_style_attr_t attr_found;
461         lv_style_attr_t attr_goal;
462 
463         attr_found = get_style_prop_attr(style, id);
464         attr_goal = (prop >> 8) & 0xFFU;
465 
466         if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
467             _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &opa, sizeof(lv_opa_t));
468             return;
469         }
470     }
471 
472     /*Add new property if not exists yet*/
473     uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(lv_opa_t));
474     lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
475     uint8_t end_mark_size = sizeof(end_mark);
476 
477     uint16_t size = _lv_style_get_mem_size(style);
478     if(size == 0) size += end_mark_size;
479 
480     size += sizeof(lv_style_property_t) + sizeof(lv_opa_t);
481     style_resize(style, size);
482     LV_ASSERT_MEM(style->map);
483     if(style == NULL) return;
484 
485     _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
486     _lv_memcpy_small(style->map + size - sizeof(lv_opa_t) - end_mark_size, &opa, sizeof(lv_opa_t));
487     _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
488 }
489 
490 /**
491  * Set a pointer typed property in a style.
492  * @param style pointer to a style where the property should be set
493  * @param prop a style property ORed with a state.
494  * E.g. `LV_STYLE_TEXT_POINTER | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
495  * @param value the value to set
496  * @note shouldn't be used directly. Use the specific property set functions instead.
497  *       For example: `lv_style_set_border_width()`
498  * @note for performance reasons it's not checked if the property is really has pointer type
499  */
_lv_style_set_ptr(lv_style_t * style,lv_style_property_t prop,const void * p)500 void _lv_style_set_ptr(lv_style_t * style, lv_style_property_t prop, const void * p)
501 {
502     LV_ASSERT_STYLE(style);
503 
504     int32_t id = get_property_index(style, prop);
505     /*The property already exists but not sure it's state is the same*/
506     if(id >= 0) {
507         lv_style_attr_t attr_found;
508         lv_style_attr_t attr_goal;
509 
510         attr_found = get_style_prop_attr(style, id);
511         attr_goal = (prop >> 8) & 0xFFU;
512 
513         if(LV_STYLE_ATTR_GET_STATE(attr_found) == LV_STYLE_ATTR_GET_STATE(attr_goal)) {
514             _lv_memcpy_small(style->map + id + sizeof(lv_style_property_t), &p, sizeof(const void *));
515             return;
516         }
517     }
518 
519     /*Add new property if not exists yet*/
520     uint8_t new_prop_size = (sizeof(lv_style_property_t) + sizeof(const void *));
521     lv_style_property_t end_mark = _LV_STYLE_CLOSEING_PROP;
522     uint8_t end_mark_size = sizeof(end_mark);
523 
524     uint16_t size = _lv_style_get_mem_size(style);
525     if(size == 0) size += end_mark_size;
526 
527     size += sizeof(lv_style_property_t) + sizeof(const void *);
528     style_resize(style, size);
529     LV_ASSERT_MEM(style->map);
530     if(style == NULL) return;
531 
532     _lv_memcpy_small(style->map + size - new_prop_size - end_mark_size, &prop, sizeof(lv_style_property_t));
533     _lv_memcpy_small(style->map + size - sizeof(const void *) - end_mark_size, &p, sizeof(const void *));
534     _lv_memcpy_small(style->map + size - end_mark_size, &end_mark, sizeof(end_mark));
535 }
536 
537 /**
538  * Get the a property from a style.
539  * Take into account the style state and return the property which matches the best.
540  * @param style pointer to a style where to search
541  * @param prop the property, might contain ORed style states too
542  * @param res buffer to store the result
543  * @return the weight of the found property (how well it fits to the style state).
544  *         Higher number is means better fit
545  *         -1 if the not found (`res` will be undefined)
546  */
_lv_style_get_int(const lv_style_t * style,lv_style_property_t prop,void * v_res)547 int16_t _lv_style_get_int(const lv_style_t * style, lv_style_property_t prop, void * v_res)
548 {
549     lv_style_int_t * res = (lv_style_int_t *)v_res;
550     LV_ASSERT_STYLE(style);
551 
552     if(style == NULL) return -1;
553     if(style->map == NULL) return -1;
554 
555     int32_t id = get_property_index(style, prop);
556     if(id < 0) {
557         return -1;
558     }
559     else {
560         _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(lv_style_int_t));
561         lv_style_attr_t attr_act;
562         attr_act = get_style_prop_attr(style, id);
563 
564         lv_style_attr_t attr_goal;
565         attr_goal = (prop >> 8) & 0xFF;
566 
567         return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
568     }
569 }
570 
571 /**
572  * Get an opacity typed property from a style.
573  * @param style pointer to a style from where the property should be get
574  * @param prop a style property ORed with a state.
575  * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
576  * @param res pointer to a buffer to store the result value
577  * @return -1: the property wasn't found in the style.
578  *         The matching state bits of the desired state (in `prop`) and the best matching property's state
579  *         Higher value means match in higher precedence state.
580  * @note shouldn't be used directly. Use the specific property get functions instead.
581  *       For example: `lv_style_get_border_opa()`
582  * @note for performance reasons it's not checked if the property really has opacity type
583  */
_lv_style_get_opa(const lv_style_t * style,lv_style_property_t prop,void * v_res)584 int16_t _lv_style_get_opa(const lv_style_t * style, lv_style_property_t prop, void * v_res)
585 {
586     lv_opa_t * res = (lv_opa_t *)v_res;
587     LV_ASSERT_STYLE(style);
588 
589     if(style == NULL) return -1;
590     if(style->map == NULL) return -1;
591 
592     int32_t id = get_property_index(style, prop);
593     if(id < 0) {
594         return -1;
595     }
596     else {
597         _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(lv_opa_t));
598         lv_style_attr_t attr_act;
599         attr_act = get_style_prop_attr(style, id);
600 
601         lv_style_attr_t attr_goal;
602         attr_goal = (prop >> 8) & 0xFF;
603 
604         return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
605     }
606 }
607 
608 /**
609  * Get a color typed property from a style.
610  * @param style pointer to a style from where the property should be get
611  * @param prop a style property ORed with a state.
612  * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
613  * @param res pointer to a buffer to store the result value
614  * @return -1: the property wasn't found in the style.
615  *         The matching state bits of the desired state (in `prop`) and the best matching property's state
616  *         Higher value means match in higher precedence state.
617  * @note shouldn't be used directly. Use the specific property get functions instead.
618  *       For example: `lv_style_get_border_color()`
619  * @note for performance reasons it's not checked if the property really has color type
620  */
_lv_style_get_color(const lv_style_t * style,lv_style_property_t prop,void * v_res)621 int16_t _lv_style_get_color(const lv_style_t * style, lv_style_property_t prop, void * v_res)
622 {
623     lv_color_t * res = (lv_color_t *)v_res;
624     if(style == NULL) return -1;
625     if(style->map == NULL) return -1;
626     int32_t id = get_property_index(style, prop);
627     if(id < 0) {
628         return -1;
629     }
630     else {
631         _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(lv_color_t));
632         lv_style_attr_t attr_act;
633         attr_act = get_style_prop_attr(style, id);
634 
635         lv_style_attr_t attr_goal;
636         attr_goal = (prop >> 8) & 0xFF;
637 
638         return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
639     }
640 }
641 
642 /**
643  * Get a pointer typed property from a style.
644  * @param style pointer to a style from where the property should be get
645  * @param prop a style property ORed with a state.
646  * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
647  * @param res pointer to a buffer to store the result value
648  * @return -1: the property wasn't found in the style.
649  *         The matching state bits of the desired state (in `prop`) and the best matching property's state
650  *         Higher value means match in higher precedence state.
651  * @note shouldn't be used directly. Use the specific property get functions instead.
652  *       For example: `lv_style_get_text_font()`
653  * @note for performance reasons it's not checked if the property really has pointer type
654  */
_lv_style_get_ptr(const lv_style_t * style,lv_style_property_t prop,void * v_res)655 int16_t _lv_style_get_ptr(const lv_style_t * style, lv_style_property_t prop, void * v_res)
656 {
657     const void ** res = (const void **)v_res;
658     if(style == NULL) return -1;
659     if(style->map == NULL) return -1;
660 
661     int32_t id = get_property_index(style, prop);
662     if(id < 0) {
663         return -1;
664     }
665     else {
666         _lv_memcpy_small(res, &style->map[id + sizeof(lv_style_property_t)], sizeof(const void *));
667         lv_style_attr_t attr_act;
668         attr_act = get_style_prop_attr(style, id);
669 
670         lv_style_attr_t attr_goal;
671         attr_goal = (prop >> 8) & 0xFF;
672 
673         return LV_STYLE_ATTR_GET_STATE(attr_act) & LV_STYLE_ATTR_GET_STATE(attr_goal);
674     }
675 }
676 
677 /**
678  * Get the local style of a style list
679  * @param list pointer to a style list where the local property should be set
680  * @return pointer to the local style if exists else `NULL`.
681  */
lv_style_list_get_local_style(lv_style_list_t * list)682 lv_style_t * lv_style_list_get_local_style(lv_style_list_t * list)
683 {
684     LV_ASSERT_STYLE_LIST(list);
685 
686     if(!list->has_local) return NULL;
687     if(list->has_trans) return list->style_list[1];
688     else return list->style_list[0];
689 }
690 
691 /**
692  * Get the transition style of a style list
693  * @param list pointer to a style list where the local property should be set
694  * @return pointer to the transition style if exists else `NULL`.
695  */
_lv_style_list_get_transition_style(lv_style_list_t * list)696 lv_style_t * _lv_style_list_get_transition_style(lv_style_list_t * list)
697 {
698     LV_ASSERT_STYLE_LIST(list);
699 
700     if(!list->has_trans) return NULL;
701     return list->style_list[0];
702 }
703 
704 /**
705  * Allocate the transition style in a style list. If already exists simply return it.
706  * @param list pointer to a style list
707  * @return the transition style of a style list
708  */
_lv_style_list_add_trans_style(lv_style_list_t * list)709 lv_style_t * _lv_style_list_add_trans_style(lv_style_list_t * list)
710 {
711     LV_ASSERT_STYLE_LIST(list);
712     if(list->has_trans) return _lv_style_list_get_transition_style(list);
713 
714     lv_style_t * trans_style = lv_mem_alloc(sizeof(lv_style_t));
715     LV_ASSERT_MEM(trans_style);
716     if(trans_style == NULL) {
717         LV_LOG_WARN("lv_style_list_add_trans_style: couldn't create transition style");
718         return NULL;
719     }
720 
721     lv_style_init(trans_style);
722 
723     _lv_style_list_add_style(list, trans_style);
724     list->has_trans = 1;
725 
726     /*If the list has local style trans was added after it. But trans should be the first so swap them*/
727     if(list->has_local) {
728         lv_style_t * tmp = list->style_list[0];
729         list->style_list[0] = list->style_list[1];
730         list->style_list[1] = tmp;
731     }
732     return trans_style;
733 }
734 
735 
736 /**
737  * Set a local integer typed property in a style list.
738  * @param list pointer to a style list where the local property should be set
739  * @param prop a style property ORed with a state.
740  * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
741  * @param value the value to set
742  * @note for performance reasons it's not checked if the property really has integer type
743  */
_lv_style_list_set_local_int(lv_style_list_t * list,lv_style_property_t prop,lv_style_int_t value)744 void _lv_style_list_set_local_int(lv_style_list_t * list, lv_style_property_t prop, lv_style_int_t value)
745 {
746     LV_ASSERT_STYLE_LIST(list);
747 
748     lv_style_t * local = get_alloc_local_style(list);
749     _lv_style_set_int(local, prop, value);
750 }
751 
752 /**
753  * Set a local opacity typed property in a style list.
754  * @param list pointer to a style list where the local property should be set
755  * @param prop a style property ORed with a state.
756  * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
757  * @param value the value to set
758  * @note for performance reasons it's not checked if the property really has opacity type
759  */
_lv_style_list_set_local_opa(lv_style_list_t * list,lv_style_property_t prop,lv_opa_t value)760 void _lv_style_list_set_local_opa(lv_style_list_t * list, lv_style_property_t prop, lv_opa_t value)
761 {
762     LV_ASSERT_STYLE_LIST(list);
763 
764     lv_style_t * local = get_alloc_local_style(list);
765     _lv_style_set_opa(local, prop, value);
766 }
767 
768 /**
769  * Set a local color typed property in a style list.
770  * @param list pointer to a style list where the local property should be set
771  * @param prop a style property ORed with a state.
772  * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
773  * @param value the value to set
774  * @note for performance reasons it's not checked if the property really has color type
775  */
_lv_style_list_set_local_color(lv_style_list_t * list,lv_style_property_t prop,lv_color_t value)776 void _lv_style_list_set_local_color(lv_style_list_t * list, lv_style_property_t prop, lv_color_t value)
777 {
778     LV_ASSERT_STYLE_LIST(list);
779 
780     lv_style_t * local = get_alloc_local_style(list);
781     _lv_style_set_color(local, prop, value);
782 }
783 
784 /**
785  * Set a local pointer typed property in a style list.
786  * @param list pointer to a style list where the local property should be set
787  * @param prop a style property ORed with a state.
788  * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
789  * @param value the value to set
790  * @note for performance reasons it's not checked if the property really has pointer type
791  */
_lv_style_list_set_local_ptr(lv_style_list_t * list,lv_style_property_t prop,const void * value)792 void _lv_style_list_set_local_ptr(lv_style_list_t * list, lv_style_property_t prop, const void * value)
793 {
794     LV_ASSERT_STYLE_LIST(list);
795 
796     lv_style_t * local = get_alloc_local_style(list);
797     _lv_style_set_ptr(local, prop, value);
798 }
799 
800 
801 
802 /**
803  * Get an integer typed property from a style list.
804  * It will return the property which match best with given state.
805  * @param list pointer to a style list from where the property should be get
806  * @param prop a style property ORed with a state.
807  * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
808  * @param res pointer to a buffer to store the result
809  * @return LV_RES_OK: there was a matching property in the list
810  *         LV_RES_INV: there was NO matching property in the list
811  * @note for performance reasons it's not checked if the property really has integer type
812  */
_lv_style_list_get_int(lv_style_list_t * list,lv_style_property_t prop,lv_style_int_t * res)813 lv_res_t _lv_style_list_get_int(lv_style_list_t * list, lv_style_property_t prop, lv_style_int_t * res)
814 {
815     LV_ASSERT_STYLE_LIST(list);
816 
817     if(list == NULL) return LV_RES_INV;
818     if(list->style_list == NULL) return LV_RES_INV;
819 
820     lv_style_attr_t attr;
821     attr = prop >> 8;
822     int16_t weight_goal = attr;
823 
824     int16_t weight = -1;
825 
826     lv_style_int_t value_act = 0;
827 
828     int16_t ci;
829     for(ci = 0; ci < list->style_cnt; ci++) {
830         lv_style_t * class = lv_style_list_get_style(list, ci);
831         int16_t weight_act = _lv_style_get_int(class, prop, &value_act);
832 
833         /*On perfect match return the value immediately*/
834         if(weight_act == weight_goal) {
835             *res = value_act;
836             return LV_RES_OK;
837         }
838         else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
839             *res = value_act;
840             return LV_RES_OK;
841         }
842         /*If the found ID is better the current candidate then use it*/
843         else if(weight_act > weight) {
844             weight =  weight_act;
845             *res = value_act;
846         }
847     }
848 
849     if(weight >= 0) return LV_RES_OK;
850     else return LV_RES_INV;
851 
852 }
853 
854 /**
855  * Get a color typed property from a style list.
856  * It will return the property which match best with given state.
857  * @param list pointer to a style list from where the property should be get
858  * @param prop a style property ORed with a state.
859  * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
860  * @param res pointer to a buffer to store the result
861  * @return LV_RES_OK: there was a matching property in the list
862  *         LV_RES_INV: there was NO matching property in the list
863  * @note for performance reasons it's not checked if the property really has color type
864  */
_lv_style_list_get_color(lv_style_list_t * list,lv_style_property_t prop,lv_color_t * res)865 lv_res_t _lv_style_list_get_color(lv_style_list_t * list, lv_style_property_t prop, lv_color_t * res)
866 {
867     LV_ASSERT_STYLE_LIST(list);
868 
869     if(list == NULL) return LV_RES_INV;
870     if(list->style_list == NULL) return LV_RES_INV;
871 
872     lv_style_attr_t attr;
873     attr = prop >> 8;
874     int16_t weight_goal = attr;
875 
876     int16_t weight = -1;
877 
878     lv_color_t value_act;
879     value_act.full = 0;
880 
881     int16_t ci;
882     for(ci = 0; ci < list->style_cnt; ci++) {
883         lv_style_t * class = lv_style_list_get_style(list, ci);
884         int16_t weight_act = _lv_style_get_color(class, prop, &value_act);
885         /*On perfect match return the value immediately*/
886         if(weight_act == weight_goal) {
887             *res = value_act;
888             return LV_RES_OK;
889         }
890         else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
891             *res = value_act;
892             return LV_RES_OK;
893         }
894         /*If the found ID is better the current candidate then use it*/
895         else if(weight_act > weight) {
896             weight =  weight_act;
897             *res = value_act;
898         }
899     }
900 
901     if(weight >= 0)  return LV_RES_OK;
902     else return LV_RES_INV;
903 }
904 
905 /**
906  * Get an opacity typed property from a style list.
907  * It will return the property which match best with given state.
908  * @param list pointer to a style list from where the property should be get
909  * @param prop a style property ORed with a state.
910  * E.g. `LV_STYLE_BORDER_OPA| (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
911  * @param res pointer to a buffer to store the result
912  * @return LV_RES_OK: there was a matching property in the list
913  *         LV_RES_INV: there was NO matching property in the list
914  * @note for performance reasons it's not checked if the property really has opacity type
915  */
_lv_style_list_get_opa(lv_style_list_t * list,lv_style_property_t prop,lv_opa_t * res)916 lv_res_t _lv_style_list_get_opa(lv_style_list_t * list, lv_style_property_t prop, lv_opa_t * res)
917 {
918     LV_ASSERT_STYLE_LIST(list);
919 
920     if(list == NULL) return LV_RES_INV;
921     if(list->style_list == NULL) return LV_RES_INV;
922 
923     lv_style_attr_t attr;
924     attr = prop >> 8;
925     int16_t weight_goal = attr;
926 
927     int16_t weight = -1;
928 
929     lv_opa_t value_act = LV_OPA_TRANSP;
930 
931     int16_t ci;
932     for(ci = 0; ci < list->style_cnt; ci++) {
933         lv_style_t * class = lv_style_list_get_style(list, ci);
934         int16_t weight_act = _lv_style_get_opa(class, prop, &value_act);
935         /*On perfect match return the value immediately*/
936         if(weight_act == weight_goal) {
937             *res = value_act;
938             return LV_RES_OK;
939         }
940         else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
941             *res = value_act;
942             return LV_RES_OK;
943         }
944         /*If the found ID is better the current candidate then use it*/
945         else if(weight_act > weight) {
946             weight =  weight_act;
947             *res = value_act;
948         }
949     }
950 
951     if(weight >= 0)  return LV_RES_OK;
952     else return LV_RES_INV;
953 }
954 
955 /**
956  * Get a pointer typed property from a style list.
957  * It will return the property which match best with given state.
958  * @param list pointer to a style list from where the property should be get
959  * @param prop a style property ORed with a state.
960  * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
961  * @param res pointer to a buffer to store the result
962  * @return LV_RES_OK: there was a matching property in the list
963  *         LV_RES_INV: there was NO matching property in the list
964  * @note for performance reasons it's not checked if the property really has pointer type
965  */
_lv_style_list_get_ptr(lv_style_list_t * list,lv_style_property_t prop,const void ** res)966 lv_res_t _lv_style_list_get_ptr(lv_style_list_t * list, lv_style_property_t prop, const void ** res)
967 {
968     LV_ASSERT_STYLE_LIST(list);
969 
970     if(list == NULL) return LV_RES_INV;
971     if(list->style_list == NULL) return LV_RES_INV;
972 
973     lv_style_attr_t attr;
974     attr = prop >> 8;
975     int16_t weight_goal = attr;
976 
977     int16_t weight = -1;
978 
979     const void * value_act;
980 
981     int16_t ci;
982     for(ci = 0; ci < list->style_cnt; ci++) {
983         lv_style_t * class = lv_style_list_get_style(list, ci);
984         int16_t weight_act = _lv_style_get_ptr(class, prop, &value_act);
985         /*On perfect match return the value immediately*/
986         if(weight_act == weight_goal) {
987             *res = value_act;
988             return LV_RES_OK;
989         }
990         else if(list->has_trans && weight_act >= 0 && ci == 0 && !list->skip_trans) {
991             *res = value_act;
992             return LV_RES_OK;
993         }
994         /*If the found ID is better the current candidate then use it*/
995         else if(weight_act > weight) {
996             weight =  weight_act;
997             *res = value_act;
998         }
999     }
1000 
1001     if(weight >= 0)  return LV_RES_OK;
1002     else return LV_RES_INV;
1003 }
1004 
1005 /**
1006  * Check whether a style is valid (initialized correctly)
1007  * @param style pointer to a style
1008  * @return true: valid
1009  */
lv_debug_check_style(const lv_style_t * style)1010 bool lv_debug_check_style(const lv_style_t * style)
1011 {
1012     if(style == NULL) return true;  /*NULL style is still valid*/
1013 
1014 #if LV_USE_ASSERT_STYLE
1015     if(style->sentinel != LV_DEBUG_STYLE_SENTINEL_VALUE) {
1016         LV_LOG_WARN("Invalid style (local variable or not initialized?)");
1017         return false;
1018     }
1019 #endif
1020 
1021     return true;
1022 }
1023 
1024 /**
1025  * Check whether a style list is valid (initialized correctly)
1026  * @param style pointer to a style
1027  * @return true: valid
1028  */
lv_debug_check_style_list(const lv_style_list_t * list)1029 bool lv_debug_check_style_list(const lv_style_list_t * list)
1030 {
1031     if(list == NULL) return true;  /*NULL list is still valid*/
1032 
1033 #if LV_USE_ASSERT_STYLE
1034     if(list->sentinel != LV_DEBUG_STYLE_LIST_SENTINEL_VALUE) {
1035         LV_LOG_WARN("Invalid style (local variable or not initialized?)");
1036         return false;
1037     }
1038 #endif
1039 
1040     return true;
1041 }
1042 
1043 /**********************
1044  *   STATIC FUNCTIONS
1045  **********************/
1046 
1047 /**
1048  * Get a property's index (byte index in `style->map`) from a style.
1049  * Return best matching property's index considering the state of `prop`
1050  * @param style pointer to a style
1051  * @param prop a style property ORed with a state.
1052  * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
1053  * @return
1054  */
get_property_index(const lv_style_t * style,lv_style_property_t prop)1055 LV_ATTRIBUTE_FAST_MEM static inline int32_t get_property_index(const lv_style_t * style, lv_style_property_t prop)
1056 {
1057     LV_ASSERT_STYLE(style);
1058 
1059     if(style->map == NULL) return -1;
1060 
1061     uint8_t id_to_find = prop & 0xFF;
1062     lv_style_attr_t attr;
1063     attr = (prop >> 8) & 0xFF;
1064 
1065     int16_t weight = -1;
1066     int16_t id_guess = -1;
1067 
1068     size_t i = 0;
1069 
1070     uint8_t prop_id;
1071     while((prop_id = get_style_prop_id(style, i)) != _LV_STYLE_CLOSEING_PROP) {
1072         if(prop_id == id_to_find) {
1073             lv_style_attr_t attr_i;
1074             attr_i = get_style_prop_attr(style, i);
1075 
1076             /*If the state perfectly matches return this property*/
1077             if(LV_STYLE_ATTR_GET_STATE(attr_i) == LV_STYLE_ATTR_GET_STATE(attr)) {
1078                 return i;
1079             }
1080             /* Be sure the property not specifies other state than the requested.
1081              * E.g. For HOVER+PRESS, HOVER only is OK, but HOVER+FOCUS not*/
1082             else if((LV_STYLE_ATTR_GET_STATE(attr_i) & (~LV_STYLE_ATTR_GET_STATE(attr))) == 0) {
1083                 /* Use this property if it describes better the requested state than the current candidate.
1084                  * E.g. for HOVER+FOCUS+PRESS prefer HOVER+FOCUS over FOCUS*/
1085                 if(LV_STYLE_ATTR_GET_STATE(attr_i) > weight) {
1086                     weight = LV_STYLE_ATTR_GET_STATE(attr_i);
1087                     id_guess = i;
1088                 }
1089             }
1090         }
1091 
1092         i = get_next_prop_index(prop_id, i);
1093     }
1094 
1095     return id_guess;
1096 }
1097 
1098 /**
1099  * Get he local style from a style list. Allocate it if not exists yet.
1100  * @param list pointer to a style list
1101  * @return pointer to the local style
1102  */
get_alloc_local_style(lv_style_list_t * list)1103 static lv_style_t * get_alloc_local_style(lv_style_list_t * list)
1104 {
1105     LV_ASSERT_STYLE_LIST(list);
1106 
1107     if(list->has_local) return lv_style_list_get_style(list, list->has_trans ? 1 : 0);
1108 
1109     lv_style_t * local_style = lv_mem_alloc(sizeof(lv_style_t));
1110     LV_ASSERT_MEM(local_style);
1111     if(local_style == NULL) {
1112         LV_LOG_WARN("get_local_style: couldn't create local style");
1113         return NULL;
1114     }
1115     lv_style_init(local_style);
1116 
1117     /*Add the local style to the first place*/
1118     _lv_style_list_add_style(list, local_style);
1119     list->has_local = 1;
1120 
1121     return local_style;
1122 }
1123 
1124 /**
1125  * Resizes a style map. Useful entry point for debugging.
1126  * @param style pointer to the style to be resized.
1127  * @param size new size
1128  */
style_resize(lv_style_t * style,size_t sz)1129 static inline void style_resize(lv_style_t * style, size_t sz)
1130 {
1131     style->map = lv_mem_realloc(style->map, sz);
1132 }
1133 
1134 /**
1135  * Get style property in index.
1136  * @param style pointer to style.
1137  * @param idx index of the style in style->map
1138  * @return property in style->map + idx
1139  */
get_style_prop(const lv_style_t * style,size_t idx)1140 static inline lv_style_property_t get_style_prop(const lv_style_t * style, size_t idx)
1141 {
1142     lv_style_property_t prop;
1143     uint8_t * prop_p = (uint8_t *)&prop;
1144     prop_p[0] = style->map[idx];
1145     prop_p[1] = style->map[idx + 1];
1146     return prop;
1147 }
1148 
1149 /**
1150  * Get style property id in index.
1151  * @param style pointer to style.
1152  * @param idx index of the style in style->map
1153  * @return id of property in style->map + idx
1154  */
get_style_prop_id(const lv_style_t * style,size_t idx)1155 static inline uint8_t get_style_prop_id(const lv_style_t * style, size_t idx)
1156 {
1157     return get_style_prop(style, idx) & 0xFF;
1158 }
1159 
1160 /**
1161  * Get style property attributes for index.
1162  * @param style pointer to style.
1163  * @param idx index of the style in style->map
1164  * @return attribute of property in style->map + idx
1165  */
get_style_prop_attr(const lv_style_t * style,size_t idx)1166 static inline uint8_t get_style_prop_attr(const lv_style_t * style, size_t idx)
1167 {
1168     return ((get_style_prop(style, idx) >> 8) & 0xFFU);
1169 }
1170 
1171 
1172 /**
1173  * Get property size.
1174  * @param prop_id property id.
1175  * @param idx index of the style in style->map
1176  * @return attribute of property in style->map + idx
1177  */
get_prop_size(uint8_t prop_id)1178 static inline size_t get_prop_size(uint8_t prop_id)
1179 {
1180     prop_id &= 0xF;
1181     size_t size = sizeof(lv_style_property_t);
1182     if(prop_id < LV_STYLE_ID_COLOR) size += sizeof(lv_style_int_t);
1183     else if(prop_id < LV_STYLE_ID_OPA) size += sizeof(lv_color_t);
1184     else if(prop_id < LV_STYLE_ID_PTR) size += sizeof(lv_opa_t);
1185     else size += sizeof(const void *);
1186     return size;
1187 }
1188 
1189 /**
1190  * Get next property index, given current property and index.
1191  * @param prop_id property id.
1192  * @param idx index of the style in style->map
1193  * @return index of next property in style->map
1194  */
get_next_prop_index(uint8_t prop_id,size_t idx)1195 static inline size_t get_next_prop_index(uint8_t prop_id, size_t idx)
1196 {
1197     return idx + get_prop_size(prop_id);
1198 }
1199