1 /**
2  * @file lv_obj_style.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj_private.h"
10 #include "../misc/lv_anim_private.h"
11 #include "lv_obj_style_private.h"
12 #include "lv_obj_class_private.h"
13 #include "../display/lv_display.h"
14 #include "../display/lv_display_private.h"
15 #include "../misc/lv_color.h"
16 #include "../stdlib/lv_string.h"
17 #include "../core/lv_global.h"
18 /*********************
19  *      DEFINES
20  *********************/
21 #define MY_CLASS (&lv_obj_class)
22 #define style_refr LV_GLOBAL_DEFAULT()->style_refresh
23 #define style_trans_ll_p &(LV_GLOBAL_DEFAULT()->style_trans_ll)
24 #define _style_custom_prop_flag_lookup_table LV_GLOBAL_DEFAULT()->style_custom_prop_flag_lookup_table
25 #define STYLE_PROP_SHIFTED(prop) ((uint32_t)1 << ((prop) >> 3))
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 typedef struct {
32     lv_obj_t * obj;
33     lv_style_prop_t prop;
34     lv_style_selector_t selector;
35     lv_style_value_t start_value;
36     lv_style_value_t end_value;
37 } trans_t;
38 
39 typedef enum {
40     CACHE_ZERO = 0,
41     CACHE_TRUE = 1,
42     CACHE_UNSET = 2,
43     CACHE_255 = 3,
44     CACHE_NEED_CHECK = 4,
45 } cache_t;
46 
47 /**********************
48  *  GLOBAL PROTOTYPES
49  **********************/
50 
51 /**********************
52  *  STATIC PROTOTYPES
53  **********************/
54 static lv_style_t * get_local_style(lv_obj_t * obj, lv_style_selector_t selector);
55 static lv_obj_style_t * get_trans_style(lv_obj_t * obj, lv_part_t part);
56 static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop,
57                                     lv_style_value_t * v);
58 static void report_style_change_core(void * style, lv_obj_t * obj);
59 static void refresh_children_style(lv_obj_t * obj);
60 static bool trans_delete(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit);
61 static void trans_anim_cb(void * _tr, int32_t v);
62 static void trans_anim_start_cb(lv_anim_t * a);
63 static void trans_anim_completed_cb(lv_anim_t * a);
64 static lv_layer_type_t calculate_layer_type(lv_obj_t * obj);
65 static void full_cache_refresh(lv_obj_t * obj, lv_part_t part);
66 static void fade_anim_cb(void * obj, int32_t v);
67 static void fade_in_anim_completed(lv_anim_t * a);
68 static bool style_has_flag(const lv_style_t * style, uint32_t flag);
69 static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop,
70                                               lv_style_value_t * value_act);
71 
72 /**********************
73  *  STATIC VARIABLES
74  **********************/
75 
76 /**********************
77  *      MACROS
78  **********************/
79 
80 /**********************
81  *   GLOBAL FUNCTIONS
82  **********************/
83 
lv_obj_style_init(void)84 void lv_obj_style_init(void)
85 {
86     lv_ll_init(style_trans_ll_p, sizeof(trans_t));
87 }
88 
lv_obj_style_deinit(void)89 void lv_obj_style_deinit(void)
90 {
91     lv_ll_clear(style_trans_ll_p);
92     if(_style_custom_prop_flag_lookup_table != NULL) {
93         lv_free(_style_custom_prop_flag_lookup_table);
94         _style_custom_prop_flag_lookup_table = NULL;
95     }
96 }
97 
lv_obj_add_style(lv_obj_t * obj,const lv_style_t * style,lv_style_selector_t selector)98 void lv_obj_add_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector)
99 {
100     LV_ASSERT(obj->style_cnt < 63);
101 
102     trans_delete(obj, selector, LV_STYLE_PROP_ANY, NULL);
103 
104     lv_part_t part = lv_obj_style_get_selector_part(selector);
105 
106     if(style && part == LV_PART_MAIN && style_has_flag(style, LV_STYLE_PROP_FLAG_TRANSFORM)) {
107         lv_obj_invalidate(obj);
108     }
109 
110     /*Try removing the style first to be sure it won't be added twice*/
111     lv_obj_remove_style(obj, style, selector);
112 
113     uint32_t i;
114     /*Go after the transition and local styles*/
115     for(i = 0; i < obj->style_cnt; i++) {
116         if(obj->styles[i].is_trans) continue;
117         if(obj->styles[i].is_local) continue;
118         break;
119     }
120 
121     /*Now `i` is at the first normal style. Insert the new style before this*/
122 
123     /*Allocate space for the new style and shift the rest of the style to the end*/
124     obj->style_cnt++;
125     LV_ASSERT(obj->style_cnt != 0);
126     obj->styles = lv_realloc(obj->styles, obj->style_cnt * sizeof(lv_obj_style_t));
127     LV_ASSERT_MALLOC(obj->styles);
128 
129     uint32_t j;
130     for(j = obj->style_cnt - 1; j > i ; j--) {
131         obj->styles[j] = obj->styles[j - 1];
132     }
133 
134     lv_memzero(&obj->styles[i], sizeof(lv_obj_style_t));
135     obj->styles[i].style = style;
136     obj->styles[i].selector = selector;
137 
138 #if LV_OBJ_STYLE_CACHE
139     uint32_t * prop_is_set = part == LV_PART_MAIN ? &obj->style_main_prop_is_set : &obj->style_other_prop_is_set;
140     if(lv_style_is_const(style)) {
141         lv_style_const_prop_t * props = style->values_and_props;
142         for(i = 0; props[i].prop != LV_STYLE_PROP_INV; i++) {
143             (*prop_is_set) |= STYLE_PROP_SHIFTED(props[i].prop);
144         }
145     }
146     else {
147         lv_style_prop_t * props = (lv_style_prop_t *)style->values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
148         for(i = 0; i < style->prop_cnt; i++) {
149             (*prop_is_set) |= STYLE_PROP_SHIFTED(props[i]);
150         }
151     }
152 #endif
153 
154     lv_obj_refresh_style(obj, selector, LV_STYLE_PROP_ANY);
155 }
156 
lv_obj_replace_style(lv_obj_t * obj,const lv_style_t * old_style,const lv_style_t * new_style,lv_style_selector_t selector)157 bool lv_obj_replace_style(lv_obj_t * obj, const lv_style_t * old_style, const lv_style_t * new_style,
158                           lv_style_selector_t selector)
159 {
160     lv_state_t state = lv_obj_style_get_selector_state(selector);
161     lv_part_t part = lv_obj_style_get_selector_part(selector);
162 
163     /*All objects must exist*/
164     if(!obj || !old_style || !new_style || (old_style == new_style)) {
165         return false;
166     }
167 
168     /*Similar to lv_obj_add_style, delete transition*/
169     trans_delete(obj, selector, LV_STYLE_PROP_ANY, NULL);
170 
171     bool replaced = false;
172     uint32_t i;
173     for(i = 0; i < obj->style_cnt; i++) {
174         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
175         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
176 
177         /*Skip local styles and transitions*/
178         if(obj->styles[i].is_local || obj->styles[i].is_trans) {
179             continue;
180         }
181 
182         /*Skip non-matching styles*/
183         if((state != LV_STATE_ANY && state_act != state) ||
184            (part != LV_PART_ANY && part_act != part) ||
185            (old_style != obj->styles[i].style)) {
186             continue;
187         }
188 
189         lv_memzero(&obj->styles[i], sizeof(lv_obj_style_t));
190         obj->styles[i].style = new_style;
191         obj->styles[i].selector = selector;
192 
193         replaced = true;
194         /*Don't break and continue replacing other occurrences*/
195     }
196     if(replaced) {
197         full_cache_refresh(obj, part);
198         lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ANY);
199     }
200     return replaced;
201 }
202 
lv_obj_remove_style(lv_obj_t * obj,const lv_style_t * style,lv_style_selector_t selector)203 void lv_obj_remove_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector)
204 {
205     lv_state_t state = lv_obj_style_get_selector_state(selector);
206     lv_part_t part = lv_obj_style_get_selector_part(selector);
207     lv_style_prop_t prop = LV_STYLE_PROP_ANY;
208     if(style && style->prop_cnt == 0) prop = LV_STYLE_PROP_INV;
209 
210     if(style && part == LV_PART_MAIN && style_has_flag(style, LV_STYLE_PROP_FLAG_TRANSFORM)) {
211         lv_obj_invalidate(obj);
212     }
213 
214     uint32_t i = 0;
215     bool deleted = false;
216     while(i <  obj->style_cnt) {
217         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
218         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
219         if((state != LV_STATE_ANY && state_act != state) ||
220            (part != LV_PART_ANY && part_act != part) ||
221            (style != NULL && style != obj->styles[i].style)) {
222             i++;
223             continue;
224         }
225 
226         if(obj->styles[i].is_trans) {
227             trans_delete(obj, part, LV_STYLE_PROP_ANY, NULL);
228         }
229 
230         if(obj->styles[i].is_local || obj->styles[i].is_trans) {
231             if(obj->styles[i].style) lv_style_reset((lv_style_t *)obj->styles[i].style);
232             lv_free((lv_style_t *)obj->styles[i].style);
233             obj->styles[i].style = NULL;
234         }
235 
236         /*Shift the styles after `i` by one*/
237         uint32_t j;
238         for(j = i; j < (uint32_t)obj->style_cnt - 1 ; j++) {
239             obj->styles[j] = obj->styles[j + 1];
240         }
241 
242         obj->style_cnt--;
243         obj->styles = lv_realloc(obj->styles, obj->style_cnt * sizeof(lv_obj_style_t));
244 
245         deleted = true;
246         /*The style from the current `i` index is removed, so `i` points to the next style.
247          *Therefore it doesn't needs to be incremented*/
248     }
249 
250     if(deleted && prop != LV_STYLE_PROP_INV) {
251         full_cache_refresh(obj, part);
252         lv_obj_refresh_style(obj, part, prop);
253     }
254 }
255 
lv_obj_remove_style_all(lv_obj_t * obj)256 void lv_obj_remove_style_all(lv_obj_t * obj)
257 {
258     lv_obj_remove_style(obj, NULL, LV_PART_ANY | LV_STATE_ANY);
259 }
260 
lv_obj_report_style_change(lv_style_t * style)261 void lv_obj_report_style_change(lv_style_t * style)
262 {
263     if(!style_refr) return;
264     lv_display_t * d = lv_display_get_next(NULL);
265 
266     while(d) {
267         uint32_t i;
268         for(i = 0; i < d->screen_cnt; i++) {
269             report_style_change_core(style, d->screens[i]);
270         }
271         d = lv_display_get_next(d);
272     }
273 }
274 
lv_obj_refresh_style(lv_obj_t * obj,lv_style_selector_t selector,lv_style_prop_t prop)275 void lv_obj_refresh_style(lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop)
276 {
277     LV_ASSERT_OBJ(obj, MY_CLASS);
278 
279     if(!style_refr) return;
280 
281     LV_PROFILER_STYLE_BEGIN;
282 
283     lv_obj_invalidate(obj);
284 
285     lv_part_t part = lv_obj_style_get_selector_part(selector);
286 
287     bool is_layout_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_FLAG_LAYOUT_UPDATE);
288     bool is_ext_draw = lv_style_prop_has_flag(prop, LV_STYLE_PROP_FLAG_EXT_DRAW_UPDATE);
289     bool is_inheritable = lv_style_prop_has_flag(prop, LV_STYLE_PROP_FLAG_INHERITABLE);
290     bool is_layer_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_FLAG_LAYER_UPDATE);
291 
292     if(is_layout_refr) {
293         if(part == LV_PART_ANY ||
294            part == LV_PART_MAIN ||
295            lv_obj_get_style_height(obj, 0) == LV_SIZE_CONTENT ||
296            lv_obj_get_style_width(obj, 0) == LV_SIZE_CONTENT) {
297             lv_obj_send_event(obj, LV_EVENT_STYLE_CHANGED, NULL);
298             lv_obj_mark_layout_as_dirty(obj);
299         }
300     }
301     if((part == LV_PART_ANY || part == LV_PART_MAIN) && (prop == LV_STYLE_PROP_ANY || is_layout_refr)) {
302         lv_obj_t * parent = lv_obj_get_parent(obj);
303         if(parent) lv_obj_mark_layout_as_dirty(parent);
304     }
305 
306     /*Cache the layer type*/
307     if((part == LV_PART_ANY || part == LV_PART_MAIN) && is_layer_refr) {
308         lv_obj_update_layer_type(obj);
309     }
310 
311     if(prop == LV_STYLE_PROP_ANY || is_ext_draw) {
312         lv_obj_refresh_ext_draw_size(obj);
313     }
314     lv_obj_invalidate(obj);
315 
316     if(prop == LV_STYLE_PROP_ANY || (is_inheritable && (is_ext_draw || is_layout_refr))) {
317         if(part != LV_PART_SCROLLBAR) {
318             refresh_children_style(obj);
319         }
320     }
321 
322     LV_PROFILER_STYLE_END;
323 }
324 
lv_obj_enable_style_refresh(bool en)325 void lv_obj_enable_style_refresh(bool en)
326 {
327     style_refr = en;
328 }
329 
lv_obj_get_style_prop(const lv_obj_t * obj,lv_part_t part,lv_style_prop_t prop)330 lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop)
331 {
332     LV_ASSERT_NULL(obj)
333 
334     lv_style_selector_t selector = part | obj->state;
335     lv_style_value_t value_act = { .ptr = NULL };
336     lv_style_res_t found;
337 
338     found = get_selector_style_prop(obj, selector, prop, &value_act);
339     if(found == LV_STYLE_RES_FOUND) return value_act;
340 
341     return lv_style_prop_get_default(prop);
342 }
343 
lv_obj_has_style_prop(const lv_obj_t * obj,lv_style_selector_t selector,lv_style_prop_t prop)344 bool lv_obj_has_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop)
345 {
346     LV_ASSERT_NULL(obj)
347 
348     lv_style_value_t value_act = { .ptr = NULL };
349     lv_style_res_t found;
350 
351     found = get_selector_style_prop(obj, selector, prop, &value_act);
352     if(found == LV_STYLE_RES_FOUND) return true;
353 
354     return false;
355 }
356 
lv_obj_set_local_style_prop(lv_obj_t * obj,lv_style_prop_t prop,lv_style_value_t value,lv_style_selector_t selector)357 void lv_obj_set_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value,
358                                  lv_style_selector_t selector)
359 {
360     LV_PROFILER_STYLE_BEGIN;
361 
362     /*Stop running transitions with this property */
363     trans_delete(obj, lv_obj_style_get_selector_part(selector), prop, NULL);
364 
365     lv_style_t * style = get_local_style(obj, selector);
366     if(selector == LV_PART_MAIN && lv_style_prop_has_flag(prop, LV_STYLE_PROP_FLAG_TRANSFORM)) {
367         lv_obj_invalidate(obj);
368     }
369 
370     lv_style_set_prop(style, prop, value);
371 
372 #if LV_OBJ_STYLE_CACHE
373     uint32_t prop_shifted = STYLE_PROP_SHIFTED(prop);
374     if(lv_obj_style_get_selector_part(selector) == LV_PART_MAIN) {
375         obj->style_main_prop_is_set |= prop_shifted;
376     }
377     else {
378         obj->style_other_prop_is_set |= prop_shifted;
379     }
380 #endif
381 
382     lv_obj_refresh_style(obj, selector, prop);
383     LV_PROFILER_STYLE_END;
384 }
385 
lv_obj_get_local_style_prop(lv_obj_t * obj,lv_style_prop_t prop,lv_style_value_t * value,lv_style_selector_t selector)386 lv_style_res_t lv_obj_get_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value,
387                                            lv_style_selector_t selector)
388 {
389     uint32_t i;
390     for(i = 0; i < obj->style_cnt; i++) {
391         if(obj->styles[i].is_local &&
392            obj->styles[i].selector == selector) {
393             return lv_style_get_prop(obj->styles[i].style, prop, value);
394         }
395     }
396 
397     return LV_STYLE_RES_NOT_FOUND;
398 }
399 
lv_obj_remove_local_style_prop(lv_obj_t * obj,lv_style_prop_t prop,lv_style_selector_t selector)400 bool lv_obj_remove_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector)
401 {
402     LV_ASSERT_OBJ(obj, MY_CLASS);
403 
404     uint32_t i;
405     /*Find the style*/
406     for(i = 0; i < obj->style_cnt; i++) {
407         if(obj->styles[i].is_local &&
408            obj->styles[i].selector == selector) {
409             break;
410         }
411     }
412 
413     /*The style is not found*/
414     if(i == obj->style_cnt) return false;
415 
416     lv_result_t res = lv_style_remove_prop((lv_style_t *)obj->styles[i].style, prop);
417     if(res == LV_RESULT_OK) {
418         full_cache_refresh(obj, lv_obj_style_get_selector_part(selector));
419         lv_obj_refresh_style(obj, selector, prop);
420     }
421 
422     return res;
423 }
424 
lv_obj_style_create_transition(lv_obj_t * obj,lv_part_t part,lv_state_t prev_state,lv_state_t new_state,const lv_obj_style_transition_dsc_t * tr_dsc)425 void lv_obj_style_create_transition(lv_obj_t * obj, lv_part_t part, lv_state_t prev_state, lv_state_t new_state,
426                                     const lv_obj_style_transition_dsc_t * tr_dsc)
427 {
428     trans_t * tr;
429 
430     /*Get the previous and current values*/
431     obj->skip_trans = 1;
432     obj->state = prev_state;
433     lv_style_value_t v1 = lv_obj_get_style_prop(obj, part, tr_dsc->prop);
434     obj->state = new_state;
435     lv_style_value_t v2 = lv_obj_get_style_prop(obj, part, tr_dsc->prop);
436     obj->skip_trans = 0;
437 
438     if(v1.ptr == v2.ptr && v1.num == v2.num && lv_color_eq(v1.color, v2.color))  return;
439     obj->state = prev_state;
440     v1 = lv_obj_get_style_prop(obj, part, tr_dsc->prop);
441     obj->state = new_state;
442 
443     lv_obj_style_t * style_trans = get_trans_style(obj, part);
444     lv_style_set_prop((lv_style_t *)style_trans->style, tr_dsc->prop, v1);  /*Be sure `trans_style` has a valid value*/
445     lv_obj_refresh_style(obj, tr_dsc->selector, tr_dsc->prop);
446 
447     if(tr_dsc->prop == LV_STYLE_RADIUS) {
448         if(v1.num == LV_RADIUS_CIRCLE || v2.num == LV_RADIUS_CIRCLE) {
449             int32_t whalf = lv_obj_get_width(obj) / 2;
450             int32_t hhalf = lv_obj_get_height(obj) / 2;
451             if(v1.num == LV_RADIUS_CIRCLE) v1.num = LV_MIN(whalf + 1, hhalf + 1);
452             if(v2.num == LV_RADIUS_CIRCLE) v2.num = LV_MIN(whalf + 1, hhalf + 1);
453         }
454     }
455 
456     tr = lv_ll_ins_head(style_trans_ll_p);
457     LV_ASSERT_MALLOC(tr);
458     if(tr == NULL) return;
459     tr->start_value = v1;
460     tr->end_value = v2;
461     tr->obj = obj;
462     tr->prop = tr_dsc->prop;
463     tr->selector = part;
464 
465     lv_anim_t a;
466     lv_anim_init(&a);
467     lv_anim_set_var(&a, tr);
468     lv_anim_set_exec_cb(&a, trans_anim_cb);
469     lv_anim_set_start_cb(&a, trans_anim_start_cb);
470     lv_anim_set_completed_cb(&a, trans_anim_completed_cb);
471     lv_anim_set_values(&a, 0x00, 0xFF);
472     lv_anim_set_duration(&a, tr_dsc->time);
473     lv_anim_set_delay(&a, tr_dsc->delay);
474     lv_anim_set_path_cb(&a, tr_dsc->path_cb);
475     lv_anim_set_early_apply(&a, false);
476     lv_anim_set_user_data(&a, tr_dsc->user_data);
477     lv_anim_start(&a);
478 }
479 
lv_obj_style_apply_color_filter(const lv_obj_t * obj,lv_part_t part,lv_style_value_t v)480 lv_style_value_t lv_obj_style_apply_color_filter(const lv_obj_t * obj, lv_part_t part, lv_style_value_t v)
481 {
482     if(obj == NULL) return v;
483     const lv_color_filter_dsc_t * f = lv_obj_get_style_color_filter_dsc(obj, part);
484     if(f && f->filter_cb) {
485         lv_opa_t f_opa = lv_obj_get_style_color_filter_opa(obj, part);
486         if(f_opa != 0) v.color = f->filter_cb(f, v.color, f_opa);
487     }
488     return v;
489 }
490 
lv_obj_style_state_compare(lv_obj_t * obj,lv_state_t state1,lv_state_t state2)491 lv_style_state_cmp_t lv_obj_style_state_compare(lv_obj_t * obj, lv_state_t state1, lv_state_t state2)
492 {
493     lv_style_state_cmp_t res = LV_STYLE_STATE_CMP_SAME;
494 
495     /*Are there any new styles for the new state?*/
496     uint32_t i;
497     for(i = 0; i < obj->style_cnt; i++) {
498         if(obj->styles[i].is_trans) continue;
499 
500         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
501         /*The style is valid for a state but not the other*/
502         bool valid1 = state_act & (~state1) ? false : true;
503         bool valid2 = state_act & (~state2) ? false : true;
504         if(valid1 != valid2) {
505             const lv_style_t * style = obj->styles[i].style;
506             lv_style_value_t v;
507             /*If there is layout difference on the main part, return immediately. There is no more serious difference*/
508             bool layout_diff = false;
509             if(lv_style_get_prop(style, LV_STYLE_PAD_TOP, &v))layout_diff = true;
510             else if(lv_style_get_prop(style, LV_STYLE_PAD_BOTTOM, &v)) layout_diff = true;
511             else if(lv_style_get_prop(style, LV_STYLE_PAD_LEFT, &v)) layout_diff = true;
512             else if(lv_style_get_prop(style, LV_STYLE_PAD_RIGHT, &v)) layout_diff = true;
513             else if(lv_style_get_prop(style, LV_STYLE_PAD_COLUMN, &v)) layout_diff = true;
514             else if(lv_style_get_prop(style, LV_STYLE_PAD_ROW, &v)) layout_diff = true;
515             else if(lv_style_get_prop(style, LV_STYLE_LAYOUT, &v)) layout_diff = true;
516             else if(lv_style_get_prop(style, LV_STYLE_TRANSLATE_X, &v)) layout_diff = true;
517             else if(lv_style_get_prop(style, LV_STYLE_TRANSLATE_Y, &v)) layout_diff = true;
518             else if(lv_style_get_prop(style, LV_STYLE_WIDTH, &v)) layout_diff = true;
519             else if(lv_style_get_prop(style, LV_STYLE_HEIGHT, &v)) layout_diff = true;
520             else if(lv_style_get_prop(style, LV_STYLE_MIN_WIDTH, &v)) layout_diff = true;
521             else if(lv_style_get_prop(style, LV_STYLE_MAX_WIDTH, &v)) layout_diff = true;
522             else if(lv_style_get_prop(style, LV_STYLE_MIN_HEIGHT, &v)) layout_diff = true;
523             else if(lv_style_get_prop(style, LV_STYLE_MAX_HEIGHT, &v)) layout_diff = true;
524             else if(lv_style_get_prop(style, LV_STYLE_BORDER_WIDTH, &v)) layout_diff = true;
525 
526             if(layout_diff) {
527                 return LV_STYLE_STATE_CMP_DIFF_LAYOUT;
528             }
529 
530             /*Check for draw pad changes*/
531             if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_WIDTH, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
532             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_HEIGHT, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
533             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ROTATION, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
534             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_SCALE_X, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
535             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_SCALE_Y, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
536             else if(lv_style_get_prop(style, LV_STYLE_OUTLINE_OPA, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
537             else if(lv_style_get_prop(style, LV_STYLE_OUTLINE_PAD, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
538             else if(lv_style_get_prop(style, LV_STYLE_OUTLINE_WIDTH, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
539             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_WIDTH, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
540             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_OPA, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
541             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_OFFSET_X, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
542             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_OFFSET_Y, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
543             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_SPREAD, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
544             else if(lv_style_get_prop(style, LV_STYLE_LINE_WIDTH, &v)) res = LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
545             else if(res == LV_STYLE_STATE_CMP_SAME) res = LV_STYLE_STATE_CMP_DIFF_REDRAW;
546         }
547     }
548 
549     return res;
550 }
551 
lv_obj_fade_in(lv_obj_t * obj,uint32_t time,uint32_t delay)552 void lv_obj_fade_in(lv_obj_t * obj, uint32_t time, uint32_t delay)
553 {
554     lv_anim_t a;
555     lv_anim_init(&a);
556     lv_anim_set_var(&a, obj);
557     lv_anim_set_values(&a, 0, LV_OPA_COVER);
558     lv_anim_set_exec_cb(&a, fade_anim_cb);
559     lv_anim_set_completed_cb(&a, fade_in_anim_completed);
560     lv_anim_set_duration(&a, time);
561     lv_anim_set_delay(&a, delay);
562     lv_anim_start(&a);
563 }
564 
lv_obj_fade_out(lv_obj_t * obj,uint32_t time,uint32_t delay)565 void lv_obj_fade_out(lv_obj_t * obj, uint32_t time, uint32_t delay)
566 {
567     lv_anim_t a;
568     lv_anim_init(&a);
569     lv_anim_set_var(&a, obj);
570     lv_anim_set_values(&a, lv_obj_get_style_opa(obj, 0), LV_OPA_TRANSP);
571     lv_anim_set_exec_cb(&a, fade_anim_cb);
572     lv_anim_set_duration(&a, time);
573     lv_anim_set_delay(&a, delay);
574     lv_anim_start(&a);
575 }
576 
lv_obj_calculate_style_text_align(const lv_obj_t * obj,lv_part_t part,const char * txt)577 lv_text_align_t lv_obj_calculate_style_text_align(const lv_obj_t * obj, lv_part_t part, const char * txt)
578 {
579     lv_text_align_t align = lv_obj_get_style_text_align(obj, part);
580     lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, part);
581     lv_bidi_calculate_align(&align, &base_dir, txt);
582     return align;
583 }
584 
lv_obj_get_style_opa_recursive(const lv_obj_t * obj,lv_part_t part)585 lv_opa_t lv_obj_get_style_opa_recursive(const lv_obj_t * obj, lv_part_t part)
586 {
587     LV_PROFILER_STYLE_BEGIN;
588     lv_opa_t opa_obj = lv_obj_get_style_opa(obj, part);
589     if(opa_obj <= LV_OPA_MIN) {
590         LV_PROFILER_STYLE_END;
591         return LV_OPA_TRANSP;
592     }
593 
594     lv_opa_t opa_final = LV_OPA_COVER;
595     if(opa_obj < LV_OPA_MAX) {
596         opa_final = LV_OPA_MIX2(opa_final, opa_obj);
597     }
598 
599     if(part != LV_PART_MAIN) {
600         part = LV_PART_MAIN;
601     }
602     else {
603         obj = lv_obj_get_parent(obj);
604     }
605 
606     while(obj) {
607         opa_obj = lv_obj_get_style_opa(obj, part);
608         if(opa_obj <= LV_OPA_MIN) {
609             LV_PROFILER_STYLE_END;
610             return LV_OPA_TRANSP;
611         }
612         if(opa_obj < LV_OPA_MAX) {
613             opa_final = LV_OPA_MIX2(opa_final, opa_obj);
614         }
615 
616         obj = lv_obj_get_parent(obj);
617     }
618 
619     if(opa_final <= LV_OPA_MIN) {
620         LV_PROFILER_STYLE_END;
621         return LV_OPA_TRANSP;
622     }
623 
624     if(opa_final >= LV_OPA_MAX) {
625         LV_PROFILER_STYLE_END;
626         return LV_OPA_COVER;
627     }
628 
629     LV_PROFILER_STYLE_END;
630     return opa_final;
631 }
632 
lv_obj_update_layer_type(lv_obj_t * obj)633 void lv_obj_update_layer_type(lv_obj_t * obj)
634 {
635     lv_layer_type_t layer_type = calculate_layer_type(obj);
636     if(obj->spec_attr) obj->spec_attr->layer_type = layer_type;
637     else if(layer_type != LV_LAYER_TYPE_NONE) {
638         lv_obj_allocate_spec_attr(obj);
639         obj->spec_attr->layer_type = layer_type;
640     }
641 }
642 
643 /**********************
644  *   STATIC FUNCTIONS
645  **********************/
646 
647 /**
648  * Get the local style of an object for a given part and for a given state.
649  * If the local style for the part-state pair doesn't exist allocate and return it.
650  * @param obj pointer to an object
651  * @param selector OR-ed value of parts and state for which the style should be get
652  * @return pointer to the local style
653  */
get_local_style(lv_obj_t * obj,lv_style_selector_t selector)654 static lv_style_t * get_local_style(lv_obj_t * obj, lv_style_selector_t selector)
655 {
656     uint32_t i;
657     for(i = 0; i < obj->style_cnt; i++) {
658         if(obj->styles[i].is_local &&
659            obj->styles[i].selector == selector) {
660             return (lv_style_t *)obj->styles[i].style;
661         }
662     }
663 
664     obj->style_cnt++;
665     LV_ASSERT(obj->style_cnt != 0);
666     obj->styles = lv_realloc(obj->styles, obj->style_cnt * sizeof(lv_obj_style_t));
667     LV_ASSERT_MALLOC(obj->styles);
668 
669     for(i = obj->style_cnt - 1; i > 0 ; i--) {
670         /*Copy only normal styles (not local and transition).
671          *The new local style will be added as the last local style*/
672         if(obj->styles[i - 1].is_local || obj->styles[i - 1].is_trans) break;
673         obj->styles[i] = obj->styles[i - 1];
674     }
675 
676     lv_memzero(&obj->styles[i], sizeof(lv_obj_style_t));
677     obj->styles[i].style = lv_malloc_zeroed(sizeof(lv_style_t));
678     lv_style_init((lv_style_t *)obj->styles[i].style);
679 
680     obj->styles[i].is_local = 1;
681     obj->styles[i].selector = selector;
682     return (lv_style_t *)obj->styles[i].style;
683 }
684 
685 /**
686  * Get the transition style of an object for a given part and for a given state.
687  * If the transition style for the part-state pair doesn't exist allocate and return it.
688  * @param obj   pointer to an object
689  * @param selector OR-ed value of parts and state for which the style should be get
690  * @return pointer to the transition style
691  */
get_trans_style(lv_obj_t * obj,lv_style_selector_t selector)692 static lv_obj_style_t * get_trans_style(lv_obj_t * obj,  lv_style_selector_t selector)
693 {
694     uint32_t i;
695     for(i = 0; i < obj->style_cnt; i++) {
696         if(obj->styles[i].is_trans && obj->styles[i].selector == selector) break;
697     }
698 
699     /*Already have a transition style for it*/
700     if(i != obj->style_cnt) return &obj->styles[i];
701 
702     obj->style_cnt++;
703     LV_ASSERT(obj->style_cnt != 0);
704     obj->styles = lv_realloc(obj->styles, obj->style_cnt * sizeof(lv_obj_style_t));
705 
706     for(i = obj->style_cnt - 1; i > 0 ; i--) {
707         obj->styles[i] = obj->styles[i - 1];
708     }
709 
710     lv_memzero(&obj->styles[0], sizeof(lv_obj_style_t));
711     obj->styles[0].style = lv_malloc(sizeof(lv_style_t));
712     lv_style_init((lv_style_t *)obj->styles[0].style);
713 
714     obj->styles[0].is_trans = 1;
715     obj->styles[0].selector = selector;
716     return &obj->styles[0];
717 }
718 
get_prop_core(const lv_obj_t * obj,lv_style_selector_t selector,lv_style_prop_t prop,lv_style_value_t * v)719 static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop,
720                                     lv_style_value_t * v)
721 {
722 
723     const uint32_t group = (uint32_t)1 << lv_style_get_prop_group(prop);
724     const lv_part_t part = lv_obj_style_get_selector_part(selector);
725     const lv_state_t state = lv_obj_style_get_selector_state(selector);
726     const lv_state_t state_inv = ~state;
727     const bool skip_trans = (const bool) obj->skip_trans;
728     int32_t weight = -1;
729     lv_style_res_t found;
730     uint32_t i;
731     for(i = 0; i < obj->style_cnt; i++) {
732         lv_obj_style_t * obj_style = &obj->styles[i];
733         if(obj_style->is_trans == false) break;
734         if(skip_trans) continue;
735 
736         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
737 
738         if(part_act != part) continue;
739         if((obj_style->style->has_group & group) == 0) continue;
740         found = lv_style_get_prop_inlined(obj_style->style, prop, v);
741         if(found == LV_STYLE_RES_FOUND) {
742             return LV_STYLE_RES_FOUND;
743         }
744     }
745 
746     for(; i < obj->style_cnt; i++) {
747         if((obj->styles[i].style->has_group & group) == 0) continue;
748         lv_obj_style_t * obj_style = &obj->styles[i];
749         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
750         if(part_act != part) continue;
751 
752         /*Be sure the style not specifies other state than the requested.
753          *E.g. For HOVER+PRESS object state, HOVER style only is OK, but HOVER+FOCUS style is not*/
754         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
755         if((state_act & state_inv)) continue;
756 
757         /*Check only better candidates*/
758         if(state_act <= weight) continue;
759 
760         found = lv_style_get_prop_inlined(obj_style->style, prop, v);
761         if(found == LV_STYLE_RES_FOUND) {
762             if(state_act == state) {
763                 return LV_STYLE_RES_FOUND;
764             }
765             weight = state_act;
766         }
767     }
768 
769     if(weight >= 0) return LV_STYLE_RES_FOUND;
770     else return LV_STYLE_RES_NOT_FOUND;
771 }
772 
773 /**
774  * Refresh the style of all children of an object. (Called recursively)
775  * @param style refresh objects only with this
776  * @param obj pointer to an object
777  */
report_style_change_core(void * style,lv_obj_t * obj)778 static void report_style_change_core(void * style, lv_obj_t * obj)
779 {
780     uint32_t i;
781     for(i = 0; i < obj->style_cnt; i++) {
782         if(style == NULL || obj->styles[i].style == style) {
783             full_cache_refresh(obj, lv_obj_style_get_selector_part(obj->styles[i].selector));
784             lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY);
785             break;
786         }
787     }
788 
789     uint32_t child_cnt = lv_obj_get_child_count(obj);
790     for(i = 0; i < child_cnt; i++) {
791         report_style_change_core(style, obj->spec_attr->children[i]);
792     }
793 }
794 
795 /**
796  * Recursively refresh the style of the children. Go deeper until a not NULL style is found
797  * because the NULL styles are inherited from the parent
798  * @param obj pointer to an object
799  */
refresh_children_style(lv_obj_t * obj)800 static void refresh_children_style(lv_obj_t * obj)
801 {
802     uint32_t i;
803     uint32_t child_cnt = lv_obj_get_child_count(obj);
804     for(i = 0; i < child_cnt; i++) {
805         lv_obj_t * child = obj->spec_attr->children[i];
806         lv_obj_invalidate(child);
807         lv_obj_send_event(child, LV_EVENT_STYLE_CHANGED, NULL);
808         lv_obj_invalidate(child);
809 
810         refresh_children_style(child); /*Check children too*/
811     }
812 }
813 
814 /**
815  * Remove the transition from object's part's property.
816  * - Remove the transition from `lv_obj_style_trans_ll` and free it
817  * - Delete pending transitions
818  * @param obj pointer to an object which transition(s) should be removed
819  * @param part a part of object or 0xFF to remove from all parts
820  * @param prop a property or 0xFF to remove all properties
821  * @param tr_limit delete transitions only "older" than this. `NULL` if not used
822  */
trans_delete(lv_obj_t * obj,lv_part_t part,lv_style_prop_t prop,trans_t * tr_limit)823 static bool trans_delete(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit)
824 {
825     trans_t * tr;
826     trans_t * tr_prev;
827     bool removed = false;
828     tr = lv_ll_get_tail(style_trans_ll_p);
829     while(tr != NULL) {
830         if(tr == tr_limit) break;
831 
832         /*'tr' might be deleted, so get the next object while 'tr' is valid*/
833         tr_prev = lv_ll_get_prev(style_trans_ll_p, tr);
834 
835         if(tr->obj == obj && (part == tr->selector || part == LV_PART_ANY) && (prop == tr->prop || prop == LV_STYLE_PROP_ANY)) {
836             /*Remove any transitioned properties from the trans. style
837              *to allow changing it by normal styles*/
838             uint32_t i;
839             for(i = 0; i < obj->style_cnt; i++) {
840                 if(obj->styles[i].is_trans && (part == LV_PART_ANY || obj->styles[i].selector == part)) {
841                     lv_style_remove_prop((lv_style_t *)obj->styles[i].style, tr->prop);
842                 }
843             }
844 
845             /*Free the transition descriptor too*/
846             lv_anim_delete(tr, NULL);
847             lv_ll_remove(style_trans_ll_p, tr);
848             lv_free(tr);
849             removed = true;
850 
851         }
852         tr = tr_prev;
853     }
854     return removed;
855 }
856 
trans_anim_cb(void * _tr,int32_t v)857 static void trans_anim_cb(void * _tr, int32_t v)
858 {
859     trans_t * tr = _tr;
860     lv_obj_t * obj = tr->obj;
861 
862     uint32_t i;
863     for(i = 0; i < obj->style_cnt; i++) {
864         if(obj->styles[i].is_trans == 0 || obj->styles[i].selector != tr->selector) continue;
865 
866         lv_style_value_t value_final = {0};
867         switch(tr->prop) {
868 
869             case LV_STYLE_BORDER_SIDE:
870             case LV_STYLE_BORDER_POST:
871             case LV_STYLE_BLEND_MODE:
872                 if(v < 255) value_final.num = tr->start_value.num;
873                 else value_final.num = tr->end_value.num;
874                 break;
875             case LV_STYLE_TRANSITION:
876             case LV_STYLE_TEXT_FONT:
877                 if(v < 255) value_final.ptr = tr->start_value.ptr;
878                 else value_final.ptr = tr->end_value.ptr;
879                 break;
880             case LV_STYLE_COLOR_FILTER_DSC:
881                 if(tr->start_value.ptr == NULL) value_final.ptr = tr->end_value.ptr;
882                 else if(tr->end_value.ptr == NULL) value_final.ptr = tr->start_value.ptr;
883                 else if(v < 128) value_final.ptr = tr->start_value.ptr;
884                 else value_final.ptr = tr->end_value.ptr;
885                 break;
886             case LV_STYLE_BG_COLOR:
887             case LV_STYLE_BG_GRAD_COLOR:
888             case LV_STYLE_BORDER_COLOR:
889             case LV_STYLE_TEXT_COLOR:
890             case LV_STYLE_SHADOW_COLOR:
891             case LV_STYLE_OUTLINE_COLOR:
892             case LV_STYLE_IMAGE_RECOLOR:
893                 if(v <= 0) value_final.color = tr->start_value.color;
894                 else if(v >= 255) value_final.color = tr->end_value.color;
895                 else value_final.color = lv_color_mix(tr->end_value.color, tr->start_value.color, v);
896                 break;
897 
898             default:
899                 if(v == 0) value_final.num = tr->start_value.num;
900                 else if(v == 255) value_final.num = tr->end_value.num;
901                 else value_final.num = tr->start_value.num + ((int32_t)((int32_t)(tr->end_value.num - tr->start_value.num) * v) >> 8);
902                 break;
903         }
904 
905         lv_style_value_t old_value = {0};
906         bool refr = true;
907         if(lv_style_get_prop(obj->styles[i].style, tr->prop, &old_value)) {
908             if(value_final.ptr == old_value.ptr && lv_color_eq(value_final.color, old_value.color) &&
909                value_final.num == old_value.num) {
910                 refr = false;
911             }
912         }
913         lv_style_set_prop((lv_style_t *)obj->styles[i].style, tr->prop, value_final);
914         if(refr) lv_obj_refresh_style(tr->obj, tr->selector, tr->prop);
915         break;
916 
917     }
918 
919 }
920 
trans_anim_start_cb(lv_anim_t * a)921 static void trans_anim_start_cb(lv_anim_t * a)
922 {
923     trans_t * tr = a->var;
924 
925     lv_part_t part = lv_obj_style_get_selector_part(tr->selector);
926     tr->start_value = lv_obj_get_style_prop(tr->obj, part, tr->prop);
927 
928     /*Init prop to an invalid values to be sure `trans_del` won't delete this added `tr`*/
929     lv_style_prop_t prop_tmp = tr->prop;
930     tr->prop = LV_STYLE_PROP_INV;
931 
932     /*Delete the related transitions if any*/
933     trans_delete(tr->obj, part, prop_tmp, tr);
934 
935     tr->prop = prop_tmp;
936 
937     lv_obj_style_t * style_trans = get_trans_style(tr->obj, tr->selector);
938     /*Be sure `trans_style` has a valid value*/
939     lv_style_set_prop((lv_style_t *)style_trans->style, tr->prop, tr->start_value);
940     lv_obj_refresh_style(tr->obj, tr->selector, tr->prop);
941 
942 }
943 
trans_anim_completed_cb(lv_anim_t * a)944 static void trans_anim_completed_cb(lv_anim_t * a)
945 {
946     trans_t * tr = a->var;
947     lv_obj_t * obj = tr->obj;
948     lv_style_prop_t prop = tr->prop;
949 
950     /*Remove the transitioned property from trans. style
951      *if there no more transitions for this property
952      *It allows changing it by normal styles*/
953     bool running = false;
954     trans_t * tr_i;
955     LV_LL_READ(style_trans_ll_p, tr_i) {
956         if(tr_i != tr && tr_i->obj == tr->obj && tr_i->selector == tr->selector && tr_i->prop == tr->prop) {
957             running = true;
958             break;
959         }
960     }
961 
962     if(!running) {
963         uint32_t i;
964         for(i = 0; i < obj->style_cnt; i++) {
965             if(obj->styles[i].is_trans && obj->styles[i].selector == tr->selector) {
966                 lv_ll_remove(style_trans_ll_p, tr);
967                 lv_free(tr);
968 
969                 lv_obj_style_t * obj_style = &obj->styles[i];
970                 lv_style_remove_prop((lv_style_t *)obj_style->style, prop);
971 
972                 if(lv_style_is_empty(obj->styles[i].style)) {
973                     lv_obj_remove_style(obj, (lv_style_t *)obj_style->style, obj_style->selector);
974 
975                 }
976                 break;
977             }
978         }
979     }
980 }
981 
calculate_layer_type(lv_obj_t * obj)982 static lv_layer_type_t calculate_layer_type(lv_obj_t * obj)
983 {
984 #if LV_DRAW_TRANSFORM_USE_MATRIX
985     if(lv_obj_get_transform(obj) != NULL) return LV_LAYER_TYPE_TRANSFORM;
986 #endif
987     if(lv_obj_get_style_transform_rotation(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
988     if(lv_obj_get_style_transform_scale_x(obj, 0) != 256) return LV_LAYER_TYPE_TRANSFORM;
989     if(lv_obj_get_style_transform_scale_y(obj, 0) != 256) return LV_LAYER_TYPE_TRANSFORM;
990     if(lv_obj_get_style_transform_skew_x(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
991     if(lv_obj_get_style_transform_skew_y(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
992     if(lv_obj_get_style_opa_layered(obj, 0) != LV_OPA_COVER) return LV_LAYER_TYPE_SIMPLE;
993     if(lv_obj_get_style_bitmap_mask_src(obj, 0) != NULL) return LV_LAYER_TYPE_SIMPLE;
994     if(lv_obj_get_style_blend_mode(obj, 0) != LV_BLEND_MODE_NORMAL) return LV_LAYER_TYPE_SIMPLE;
995     return LV_LAYER_TYPE_NONE;
996 }
997 
full_cache_refresh(lv_obj_t * obj,lv_part_t part)998 static void full_cache_refresh(lv_obj_t * obj, lv_part_t part)
999 {
1000 #if LV_OBJ_STYLE_CACHE
1001     uint32_t i;
1002     if(part == LV_PART_MAIN || part == LV_PART_ANY) {
1003         obj->style_main_prop_is_set = 0;
1004         for(i = 0; i < obj->style_cnt; i++) {
1005             if(lv_obj_style_get_selector_part(obj->styles[i].selector) != LV_PART_MAIN) continue;
1006             lv_style_t * style = (lv_style_t *)obj->styles[i].style;
1007             uint32_t j;
1008             if(lv_style_is_const(style)) {
1009                 lv_style_const_prop_t * props = style->values_and_props;
1010                 for(j = 0; props[j].prop != LV_STYLE_PROP_INV; j++) {
1011                     obj->style_main_prop_is_set |= STYLE_PROP_SHIFTED(props[j].prop);
1012                 }
1013             }
1014             else {
1015                 lv_style_prop_t * props = (lv_style_prop_t *)style->values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
1016                 for(j = 0; j < style->prop_cnt; j++) {
1017                     obj->style_main_prop_is_set |= STYLE_PROP_SHIFTED(props[j]);
1018                 }
1019             }
1020         }
1021     }
1022     if(part != LV_PART_MAIN || part == LV_PART_ANY) {
1023         obj->style_other_prop_is_set = 0;
1024         for(i = 0; i < obj->style_cnt; i++) {
1025             if(lv_obj_style_get_selector_part(obj->styles[i].selector) == LV_PART_MAIN) continue;
1026             lv_style_t * style = (lv_style_t *)obj->styles[i].style;
1027             uint32_t j;
1028             if(lv_style_is_const(style)) {
1029                 lv_style_const_prop_t * props = style->values_and_props;
1030                 for(j = 0; props[j].prop != LV_STYLE_PROP_INV; j++) {
1031                     obj->style_other_prop_is_set |= STYLE_PROP_SHIFTED(props[j].prop);
1032                 }
1033             }
1034             else {
1035                 lv_style_prop_t * props = (lv_style_prop_t *)style->values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
1036                 for(j = 0; j < style->prop_cnt; j++) {
1037                     obj->style_other_prop_is_set |= STYLE_PROP_SHIFTED(props[j]);
1038                 }
1039             }
1040         }
1041     }
1042 #else
1043     LV_UNUSED(obj);
1044     LV_UNUSED(part);
1045 #endif
1046 }
1047 
fade_anim_cb(void * obj,int32_t v)1048 static void fade_anim_cb(void * obj, int32_t v)
1049 {
1050     lv_obj_set_style_opa(obj, v, 0);
1051 }
1052 
fade_in_anim_completed(lv_anim_t * a)1053 static void fade_in_anim_completed(lv_anim_t * a)
1054 {
1055     lv_obj_remove_local_style_prop(a->var, LV_STYLE_OPA, 0);
1056 }
1057 
style_has_flag(const lv_style_t * style,uint32_t flag)1058 static bool style_has_flag(const lv_style_t * style, uint32_t flag)
1059 {
1060     if(lv_style_is_const(style)) {
1061         lv_style_const_prop_t * props = style->values_and_props;
1062         uint32_t i;
1063         for(i = 0; props[i].prop != LV_STYLE_PROP_INV; i++) {
1064             if(lv_style_prop_has_flag(props[i].prop, flag)) {
1065                 return true;
1066             }
1067         }
1068     }
1069     else {
1070         lv_style_prop_t * props = (lv_style_prop_t *)style->values_and_props + style->prop_cnt * sizeof(lv_style_value_t);
1071         uint32_t i;
1072         for(i = 0; i < style->prop_cnt; i++) {
1073             if(lv_style_prop_has_flag(props[i], flag)) {
1074                 return true;
1075             }
1076         }
1077     }
1078     return false;
1079 }
1080 
get_selector_style_prop(const lv_obj_t * obj,lv_style_selector_t selector,lv_style_prop_t prop,lv_style_value_t * value_act)1081 static lv_style_res_t get_selector_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop,
1082                                               lv_style_value_t * value_act)
1083 {
1084     lv_style_res_t found;
1085     lv_part_t part = lv_obj_style_get_selector_part(selector);
1086 
1087     /*The happy path*/
1088 #if LV_OBJ_STYLE_CACHE
1089     const uint32_t prop_shifted = STYLE_PROP_SHIFTED(prop);
1090     if((part == LV_PART_MAIN ? obj->style_main_prop_is_set : obj->style_other_prop_is_set) & prop_shifted)
1091 #endif
1092     {
1093         found = get_prop_core(obj, selector, prop, value_act);
1094         if(found == LV_STYLE_RES_FOUND) return LV_STYLE_RES_FOUND;
1095     }
1096 
1097     extern const uint8_t lv_style_builtin_prop_flag_lookup_table[];
1098     bool inheritable = false;
1099     if(prop < LV_STYLE_NUM_BUILT_IN_PROPS) {
1100         inheritable = lv_style_builtin_prop_flag_lookup_table[prop] & LV_STYLE_PROP_FLAG_INHERITABLE;
1101     }
1102     else {
1103         if(_style_custom_prop_flag_lookup_table != NULL) {
1104             inheritable = _style_custom_prop_flag_lookup_table[prop - LV_STYLE_NUM_BUILT_IN_PROPS] &
1105                           LV_STYLE_PROP_FLAG_INHERITABLE;
1106         }
1107     }
1108 
1109     if(inheritable) {
1110         /*If not found, check the `MAIN` style first, if already on the MAIN part go to the parent*/
1111         if(part != LV_PART_MAIN) part = LV_PART_MAIN;
1112         else obj = obj->parent;
1113 
1114         while(obj) {
1115 #if LV_OBJ_STYLE_CACHE
1116             if(obj->style_main_prop_is_set & prop_shifted)
1117 #endif
1118             {
1119                 selector = part | obj->state;
1120                 found = get_prop_core(obj, selector, prop, value_act);
1121                 if(found == LV_STYLE_RES_FOUND) return LV_STYLE_RES_FOUND;
1122             }
1123             /*Check the parent too.*/
1124             obj = obj->parent;
1125         }
1126     }
1127     else {
1128         /*Get the width and height from the class.
1129                 * WIDTH and HEIGHT are not inherited so add them in the `else` to skip checking them for inherited properties */
1130         if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) {
1131             const lv_obj_class_t * cls = obj->class_p;
1132             while(cls) {
1133                 if(prop == LV_STYLE_WIDTH) {
1134                     if(cls->width_def != 0)  {
1135                         value_act->num = cls->width_def;
1136                         return LV_STYLE_RES_FOUND;
1137                     }
1138                 }
1139                 else {
1140                     if(cls->height_def != 0) {
1141                         value_act->num = cls->height_def;
1142                         return LV_STYLE_RES_FOUND;
1143                     }
1144                 }
1145                 cls = cls->base_class;
1146             }
1147         }
1148     }
1149 
1150     return LV_STYLE_RES_NOT_FOUND;
1151 }
1152