1 /**
2  * @file lv_obj_style.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_obj.h"
10 #include "lv_disp.h"
11 #include "../misc/lv_gc.h"
12 
13 /*********************
14  *      DEFINES
15  *********************/
16 #define MY_CLASS &lv_obj_class
17 
18 /**********************
19  *      TYPEDEFS
20  **********************/
21 
22 typedef struct {
23     lv_obj_t * obj;
24     lv_style_prop_t prop;
25     lv_style_selector_t selector;
26     lv_style_value_t start_value;
27     lv_style_value_t end_value;
28 } trans_t;
29 
30 typedef enum {
31     CACHE_ZERO = 0,
32     CACHE_TRUE = 1,
33     CACHE_UNSET = 2,
34     CACHE_255 = 3,
35     CACHE_NEED_CHECK = 4,
36 } cache_t;
37 
38 /**********************
39  *  GLOBAL PROTOTYPES
40  **********************/
41 
42 /**********************
43  *  STATIC PROTOTYPES
44  **********************/
45 static lv_style_t * get_local_style(lv_obj_t * obj, lv_style_selector_t selector);
46 static _lv_obj_style_t * get_trans_style(lv_obj_t * obj, uint32_t part);
47 static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, lv_style_value_t * v);
48 static void report_style_change_core(void * style, lv_obj_t * obj);
49 static void refresh_children_style(lv_obj_t * obj);
50 static bool trans_del(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit);
51 static void trans_anim_cb(void * _tr, int32_t v);
52 static void trans_anim_start_cb(lv_anim_t * a);
53 static void trans_anim_ready_cb(lv_anim_t * a);
54 static lv_layer_type_t calculate_layer_type(lv_obj_t * obj);
55 static void fade_anim_cb(void * obj, int32_t v);
56 static void fade_in_anim_ready(lv_anim_t * a);
57 
58 /**********************
59  *  STATIC VARIABLES
60  **********************/
61 static bool style_refr = true;
62 
63 /**********************
64  *      MACROS
65  **********************/
66 
67 /**********************
68  *   GLOBAL FUNCTIONS
69  **********************/
70 
_lv_obj_style_init(void)71 void _lv_obj_style_init(void)
72 {
73     _lv_ll_init(&LV_GC_ROOT(_lv_obj_style_trans_ll), sizeof(trans_t));
74 }
75 
lv_obj_add_style(lv_obj_t * obj,lv_style_t * style,lv_style_selector_t selector)76 void lv_obj_add_style(lv_obj_t * obj, lv_style_t * style, lv_style_selector_t selector)
77 {
78     trans_del(obj, selector, LV_STYLE_PROP_ANY, NULL);
79 
80     uint32_t i;
81     /*Go after the transition and local styles*/
82     for(i = 0; i < obj->style_cnt; i++) {
83         if(obj->styles[i].is_trans) continue;
84         if(obj->styles[i].is_local) continue;
85         break;
86     }
87 
88     /*Now `i` is at the first normal style. Insert the new style before this*/
89 
90     /*Allocate space for the new style and shift the rest of the style to the end*/
91     obj->style_cnt++;
92     obj->styles = lv_mem_realloc(obj->styles, obj->style_cnt * sizeof(_lv_obj_style_t));
93 
94     uint32_t j;
95     for(j = obj->style_cnt - 1; j > i ; j--) {
96         obj->styles[j] = obj->styles[j - 1];
97     }
98 
99     lv_memset_00(&obj->styles[i], sizeof(_lv_obj_style_t));
100     obj->styles[i].style = style;
101     obj->styles[i].selector = selector;
102 
103     lv_obj_refresh_style(obj, selector, LV_STYLE_PROP_ANY);
104 }
105 
lv_obj_remove_style(lv_obj_t * obj,lv_style_t * style,lv_style_selector_t selector)106 void lv_obj_remove_style(lv_obj_t * obj, lv_style_t * style, lv_style_selector_t selector)
107 {
108     lv_state_t state = lv_obj_style_get_selector_state(selector);
109     lv_part_t part = lv_obj_style_get_selector_part(selector);
110     lv_style_prop_t prop = LV_STYLE_PROP_ANY;
111     if(style && style->prop_cnt == 0) prop = LV_STYLE_PROP_INV;
112 
113     uint32_t i = 0;
114     bool deleted = false;
115     while(i <  obj->style_cnt) {
116         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
117         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
118         if((state != LV_STATE_ANY && state_act != state) ||
119            (part != LV_PART_ANY && part_act != part) ||
120            (style != NULL && style != obj->styles[i].style)) {
121             i++;
122             continue;
123         }
124 
125         if(obj->styles[i].is_trans) {
126             trans_del(obj, part, LV_STYLE_PROP_ANY, NULL);
127         }
128 
129         if(obj->styles[i].is_local || obj->styles[i].is_trans) {
130             lv_style_reset(obj->styles[i].style);
131             lv_mem_free(obj->styles[i].style);
132             obj->styles[i].style = NULL;
133         }
134 
135         /*Shift the styles after `i` by one*/
136         uint32_t j;
137         for(j = i; j < (uint32_t)obj->style_cnt - 1 ; j++) {
138             obj->styles[j] = obj->styles[j + 1];
139         }
140 
141         obj->style_cnt--;
142         obj->styles = lv_mem_realloc(obj->styles, obj->style_cnt * sizeof(_lv_obj_style_t));
143 
144         deleted = true;
145         /*The style from the current `i` index is removed, so `i` points to the next style.
146          *Therefore it doesn't needs to be incremented*/
147     }
148     if(deleted && prop != LV_STYLE_PROP_INV) {
149         lv_obj_refresh_style(obj, part, prop);
150     }
151 }
152 
lv_obj_report_style_change(lv_style_t * style)153 void lv_obj_report_style_change(lv_style_t * style)
154 {
155     if(!style_refr) return;
156     lv_disp_t * d = lv_disp_get_next(NULL);
157 
158     while(d) {
159         uint32_t i;
160         for(i = 0; i < d->screen_cnt; i++) {
161             report_style_change_core(style, d->screens[i]);
162         }
163         d = lv_disp_get_next(d);
164     }
165 }
166 
lv_obj_refresh_style(lv_obj_t * obj,lv_style_selector_t selector,lv_style_prop_t prop)167 void lv_obj_refresh_style(lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop)
168 {
169     LV_ASSERT_OBJ(obj, MY_CLASS);
170 
171     if(!style_refr) return;
172 
173     lv_obj_invalidate(obj);
174 
175     lv_part_t part = lv_obj_style_get_selector_part(selector);
176 
177     bool is_layout_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_LAYOUT_REFR);
178     bool is_ext_draw = lv_style_prop_has_flag(prop, LV_STYLE_PROP_EXT_DRAW);
179     bool is_inheritable = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT);
180     bool is_layer_refr = lv_style_prop_has_flag(prop, LV_STYLE_PROP_LAYER_REFR);
181 
182     if(is_layout_refr) {
183         if(part == LV_PART_ANY ||
184            part == LV_PART_MAIN ||
185            lv_obj_get_style_height(obj, 0) == LV_SIZE_CONTENT ||
186            lv_obj_get_style_width(obj, 0) == LV_SIZE_CONTENT) {
187             lv_event_send(obj, LV_EVENT_STYLE_CHANGED, NULL);
188             lv_obj_mark_layout_as_dirty(obj);
189         }
190     }
191     if((part == LV_PART_ANY || part == LV_PART_MAIN) && (prop == LV_STYLE_PROP_ANY || is_layout_refr)) {
192         lv_obj_t * parent = lv_obj_get_parent(obj);
193         if(parent) lv_obj_mark_layout_as_dirty(parent);
194     }
195 
196     /*Cache the layer type*/
197     if((part == LV_PART_ANY || part == LV_PART_MAIN) && is_layer_refr) {
198         lv_layer_type_t layer_type = calculate_layer_type(obj);
199         if(obj->spec_attr) obj->spec_attr->layer_type = layer_type;
200         else if(layer_type != LV_LAYER_TYPE_NONE) {
201             lv_obj_allocate_spec_attr(obj);
202             obj->spec_attr->layer_type = layer_type;
203         }
204     }
205 
206     if(prop == LV_STYLE_PROP_ANY || is_ext_draw) {
207         lv_obj_refresh_ext_draw_size(obj);
208     }
209     lv_obj_invalidate(obj);
210 
211     if(prop == LV_STYLE_PROP_ANY || (is_inheritable && (is_ext_draw || is_layout_refr))) {
212         if(part != LV_PART_SCROLLBAR) {
213             refresh_children_style(obj);
214         }
215     }
216 }
217 
lv_obj_enable_style_refresh(bool en)218 void lv_obj_enable_style_refresh(bool en)
219 {
220     style_refr = en;
221 }
222 
lv_obj_get_style_prop(const lv_obj_t * obj,lv_part_t part,lv_style_prop_t prop)223 lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop)
224 {
225     lv_style_value_t value_act;
226     bool inheritable = lv_style_prop_has_flag(prop, LV_STYLE_PROP_INHERIT);
227     lv_style_res_t found = LV_STYLE_RES_NOT_FOUND;
228     while(obj) {
229         found = get_prop_core(obj, part, prop, &value_act);
230         if(found == LV_STYLE_RES_FOUND) break;
231         if(!inheritable) break;
232 
233         /*If not found, check the `MAIN` style first*/
234         if(found != LV_STYLE_RES_INHERIT && part != LV_PART_MAIN) {
235             part = LV_PART_MAIN;
236             continue;
237         }
238 
239         /*Check the parent too.*/
240         obj = lv_obj_get_parent(obj);
241     }
242 
243     if(found != LV_STYLE_RES_FOUND) {
244         if(part == LV_PART_MAIN && (prop == LV_STYLE_WIDTH || prop == LV_STYLE_HEIGHT)) {
245             const lv_obj_class_t * cls = obj->class_p;
246             while(cls) {
247                 if(prop == LV_STYLE_WIDTH) {
248                     if(cls->width_def != 0) break;
249                 }
250                 else {
251                     if(cls->height_def != 0) break;
252                 }
253                 cls = cls->base_class;
254             }
255 
256             if(cls) {
257                 value_act.num = prop == LV_STYLE_WIDTH ? cls->width_def : cls->height_def;
258             }
259             else {
260                 value_act.num = 0;
261             }
262         }
263         else {
264             value_act = lv_style_prop_get_default(prop);
265         }
266     }
267     return value_act;
268 }
269 
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)270 void lv_obj_set_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value,
271                                  lv_style_selector_t selector)
272 {
273     lv_style_t * style = get_local_style(obj, selector);
274     lv_style_set_prop(style, prop, value);
275     lv_obj_refresh_style(obj, selector, prop);
276 }
277 
lv_obj_set_local_style_prop_meta(lv_obj_t * obj,lv_style_prop_t prop,uint16_t meta,lv_style_selector_t selector)278 void lv_obj_set_local_style_prop_meta(lv_obj_t * obj, lv_style_prop_t prop, uint16_t meta,
279                                       lv_style_selector_t selector)
280 {
281     lv_style_t * style = get_local_style(obj, selector);
282     lv_style_set_prop_meta(style, prop, meta);
283     lv_obj_refresh_style(obj, selector, prop);
284 }
285 
286 
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)287 lv_style_res_t lv_obj_get_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value,
288                                            lv_style_selector_t selector)
289 {
290     uint32_t i;
291     for(i = 0; i < obj->style_cnt; i++) {
292         if(obj->styles[i].is_local &&
293            obj->styles[i].selector == selector) {
294             return lv_style_get_prop(obj->styles[i].style, prop, value);
295         }
296     }
297 
298     return LV_STYLE_RES_NOT_FOUND;
299 }
300 
lv_obj_remove_local_style_prop(lv_obj_t * obj,lv_style_prop_t prop,lv_style_selector_t selector)301 bool lv_obj_remove_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector)
302 {
303     LV_ASSERT_OBJ(obj, MY_CLASS);
304 
305     uint32_t i;
306     /*Find the style*/
307     for(i = 0; i < obj->style_cnt; i++) {
308         if(obj->styles[i].is_local &&
309            obj->styles[i].selector == selector) {
310             break;
311         }
312     }
313 
314     /*The style is not found*/
315     if(i == obj->style_cnt) return false;
316 
317     lv_res_t res = lv_style_remove_prop(obj->styles[i].style, prop);
318     if(res == LV_RES_OK) {
319         lv_obj_refresh_style(obj, selector, prop);
320     }
321 
322     return res;
323 }
324 
_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)325 void _lv_obj_style_create_transition(lv_obj_t * obj, lv_part_t part, lv_state_t prev_state, lv_state_t new_state,
326                                      const _lv_obj_style_transition_dsc_t * tr_dsc)
327 {
328     trans_t * tr;
329 
330     /*Get the previous and current values*/
331     obj->skip_trans = 1;
332     obj->state = prev_state;
333     lv_style_value_t v1 = lv_obj_get_style_prop(obj, part, tr_dsc->prop);
334     obj->state = new_state;
335     lv_style_value_t v2 = lv_obj_get_style_prop(obj, part, tr_dsc->prop);
336     obj->skip_trans = 0;
337 
338     if(v1.ptr == v2.ptr && v1.num == v2.num && v1.color.full == v2.color.full)  return;
339     obj->state = prev_state;
340     v1 = lv_obj_get_style_prop(obj, part, tr_dsc->prop);
341     obj->state = new_state;
342 
343     _lv_obj_style_t * style_trans = get_trans_style(obj, part);
344     lv_style_set_prop(style_trans->style, tr_dsc->prop, v1);   /*Be sure `trans_style` has a valid value*/
345 
346     if(tr_dsc->prop == LV_STYLE_RADIUS) {
347         if(v1.num == LV_RADIUS_CIRCLE || v2.num == LV_RADIUS_CIRCLE) {
348             lv_coord_t whalf = lv_obj_get_width(obj) / 2;
349             lv_coord_t hhalf = lv_obj_get_height(obj) / 2;
350             if(v1.num == LV_RADIUS_CIRCLE) v1.num = LV_MIN(whalf + 1, hhalf + 1);
351             if(v2.num == LV_RADIUS_CIRCLE) v2.num = LV_MIN(whalf + 1, hhalf + 1);
352         }
353     }
354 
355     tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll));
356     LV_ASSERT_MALLOC(tr);
357     if(tr == NULL) return;
358     tr->start_value = v1;
359     tr->end_value = v2;
360     tr->obj = obj;
361     tr->prop = tr_dsc->prop;
362     tr->selector = part;
363 
364     lv_anim_t a;
365     lv_anim_init(&a);
366     lv_anim_set_var(&a, tr);
367     lv_anim_set_exec_cb(&a, trans_anim_cb);
368     lv_anim_set_start_cb(&a, trans_anim_start_cb);
369     lv_anim_set_ready_cb(&a, trans_anim_ready_cb);
370     lv_anim_set_values(&a, 0x00, 0xFF);
371     lv_anim_set_time(&a, tr_dsc->time);
372     lv_anim_set_delay(&a, tr_dsc->delay);
373     lv_anim_set_path_cb(&a, tr_dsc->path_cb);
374     lv_anim_set_early_apply(&a, false);
375 #if LV_USE_USER_DATA
376     a.user_data = tr_dsc->user_data;
377 #endif
378     lv_anim_start(&a);
379 }
380 
381 
_lv_obj_style_apply_color_filter(const lv_obj_t * obj,uint32_t part,lv_style_value_t v)382 lv_style_value_t _lv_obj_style_apply_color_filter(const lv_obj_t * obj, uint32_t part, lv_style_value_t v)
383 {
384     if(obj == NULL) return v;
385     const lv_color_filter_dsc_t * f = lv_obj_get_style_color_filter_dsc(obj, part);
386     if(f && f->filter_cb) {
387         lv_opa_t f_opa = lv_obj_get_style_color_filter_opa(obj, part);
388         if(f_opa != 0) v.color = f->filter_cb(f, v.color, f_opa);
389     }
390     return v;
391 }
392 
_lv_obj_style_state_compare(lv_obj_t * obj,lv_state_t state1,lv_state_t state2)393 _lv_style_state_cmp_t _lv_obj_style_state_compare(lv_obj_t * obj, lv_state_t state1, lv_state_t state2)
394 {
395     _lv_style_state_cmp_t res = _LV_STYLE_STATE_CMP_SAME;
396 
397     /*Are there any new styles for the new state?*/
398     uint32_t i;
399     for(i = 0; i < obj->style_cnt; i++) {
400         if(obj->styles[i].is_trans) continue;
401 
402         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
403         /*The style is valid for a state but not the other*/
404         bool valid1 = state_act & (~state1) ? false : true;
405         bool valid2 = state_act & (~state2) ? false : true;
406         if(valid1 != valid2) {
407             lv_style_t * style = obj->styles[i].style;
408             lv_style_value_t v;
409             /*If there is layout difference on the main part, return immediately. There is no more serious difference*/
410             bool layout_diff = false;
411             if(lv_style_get_prop(style, LV_STYLE_PAD_TOP, &v))layout_diff = true;
412             else if(lv_style_get_prop(style, LV_STYLE_PAD_BOTTOM, &v)) layout_diff = true;
413             else if(lv_style_get_prop(style, LV_STYLE_PAD_LEFT, &v)) layout_diff = true;
414             else if(lv_style_get_prop(style, LV_STYLE_PAD_RIGHT, &v)) layout_diff = true;
415             else if(lv_style_get_prop(style, LV_STYLE_PAD_COLUMN, &v)) layout_diff = true;
416             else if(lv_style_get_prop(style, LV_STYLE_PAD_ROW, &v)) layout_diff = true;
417             else if(lv_style_get_prop(style, LV_STYLE_LAYOUT, &v)) layout_diff = true;
418             else if(lv_style_get_prop(style, LV_STYLE_TRANSLATE_X, &v)) layout_diff = true;
419             else if(lv_style_get_prop(style, LV_STYLE_TRANSLATE_Y, &v)) layout_diff = true;
420             else if(lv_style_get_prop(style, LV_STYLE_WIDTH, &v)) layout_diff = true;
421             else if(lv_style_get_prop(style, LV_STYLE_HEIGHT, &v)) layout_diff = true;
422             else if(lv_style_get_prop(style, LV_STYLE_MIN_WIDTH, &v)) layout_diff = true;
423             else if(lv_style_get_prop(style, LV_STYLE_MAX_WIDTH, &v)) layout_diff = true;
424             else if(lv_style_get_prop(style, LV_STYLE_MIN_HEIGHT, &v)) layout_diff = true;
425             else if(lv_style_get_prop(style, LV_STYLE_MAX_HEIGHT, &v)) layout_diff = true;
426             else if(lv_style_get_prop(style, LV_STYLE_BORDER_WIDTH, &v)) layout_diff = true;
427             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ANGLE, &v)) layout_diff = true;
428             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ZOOM, &v)) layout_diff = true;
429 
430             if(layout_diff) {
431                 return _LV_STYLE_STATE_CMP_DIFF_LAYOUT;
432             }
433 
434             /*Check for draw pad changes*/
435             if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_WIDTH, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
436             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_HEIGHT, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
437             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ANGLE, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
438             else if(lv_style_get_prop(style, LV_STYLE_TRANSFORM_ZOOM, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
439             else if(lv_style_get_prop(style, LV_STYLE_OUTLINE_OPA, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
440             else if(lv_style_get_prop(style, LV_STYLE_OUTLINE_PAD, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
441             else if(lv_style_get_prop(style, LV_STYLE_OUTLINE_WIDTH, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
442             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_WIDTH, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
443             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_OPA, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
444             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_OFS_X, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
445             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_OFS_Y, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
446             else if(lv_style_get_prop(style, LV_STYLE_SHADOW_SPREAD, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
447             else if(lv_style_get_prop(style, LV_STYLE_LINE_WIDTH, &v)) res = _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD;
448             else if(res == _LV_STYLE_STATE_CMP_SAME) res = _LV_STYLE_STATE_CMP_DIFF_REDRAW;
449         }
450     }
451 
452     return res;
453 }
454 
lv_obj_fade_in(lv_obj_t * obj,uint32_t time,uint32_t delay)455 void lv_obj_fade_in(lv_obj_t * obj, uint32_t time, uint32_t delay)
456 {
457     lv_anim_t a;
458     lv_anim_init(&a);
459     lv_anim_set_var(&a, obj);
460     lv_anim_set_values(&a, 0, LV_OPA_COVER);
461     lv_anim_set_exec_cb(&a, fade_anim_cb);
462     lv_anim_set_ready_cb(&a, fade_in_anim_ready);
463     lv_anim_set_time(&a, time);
464     lv_anim_set_delay(&a, delay);
465     lv_anim_start(&a);
466 }
467 
lv_obj_fade_out(lv_obj_t * obj,uint32_t time,uint32_t delay)468 void lv_obj_fade_out(lv_obj_t * obj, uint32_t time, uint32_t delay)
469 {
470     lv_anim_t a;
471     lv_anim_init(&a);
472     lv_anim_set_var(&a, obj);
473     lv_anim_set_values(&a, lv_obj_get_style_opa(obj, 0), LV_OPA_TRANSP);
474     lv_anim_set_exec_cb(&a, fade_anim_cb);
475     lv_anim_set_time(&a, time);
476     lv_anim_set_delay(&a, delay);
477     lv_anim_start(&a);
478 }
479 
lv_obj_style_get_selector_state(lv_style_selector_t selector)480 lv_state_t lv_obj_style_get_selector_state(lv_style_selector_t selector)
481 {
482     return selector & 0xFFFF;
483 }
484 
lv_obj_style_get_selector_part(lv_style_selector_t selector)485 lv_part_t lv_obj_style_get_selector_part(lv_style_selector_t selector)
486 {
487     return selector & 0xFF0000;
488 }
489 
490 
lv_obj_calculate_style_text_align(const struct _lv_obj_t * obj,lv_part_t part,const char * txt)491 lv_text_align_t lv_obj_calculate_style_text_align(const struct _lv_obj_t * obj, lv_part_t part, const char * txt)
492 {
493     lv_text_align_t align = lv_obj_get_style_text_align(obj, part);
494     lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, part);
495     lv_bidi_calculate_align(&align, &base_dir, txt);
496     return align;
497 }
498 
lv_obj_get_style_opa_recursive(const lv_obj_t * obj,lv_part_t part)499 lv_opa_t lv_obj_get_style_opa_recursive(const lv_obj_t * obj, lv_part_t part)
500 {
501 
502     lv_opa_t opa_obj = lv_obj_get_style_opa(obj, part);
503     if(opa_obj <= LV_OPA_MIN) return LV_OPA_TRANSP;
504 
505     lv_opa_t opa_final = LV_OPA_COVER;
506     if(opa_obj < LV_OPA_MAX) {
507         opa_final = ((uint32_t)opa_final * opa_obj) >> 8;
508     }
509 
510     if(part != LV_PART_MAIN) {
511         part = LV_PART_MAIN;
512     }
513     else {
514         obj = lv_obj_get_parent(obj);
515     }
516 
517     while(obj) {
518         opa_obj = lv_obj_get_style_opa(obj, part);
519         if(opa_obj <= LV_OPA_MIN) return LV_OPA_TRANSP;
520         if(opa_obj < LV_OPA_MAX) {
521             opa_final = ((uint32_t)opa_final * opa_obj) >> 8;
522         }
523 
524         obj = lv_obj_get_parent(obj);
525     }
526 
527     if(opa_final <= LV_OPA_MIN) return LV_OPA_TRANSP;
528     if(opa_final >= LV_OPA_MAX) return LV_OPA_COVER;
529     return opa_final;
530 }
531 
532 
533 /**********************
534  *   STATIC FUNCTIONS
535  **********************/
536 
537 /**
538  * Get the local style of an object for a given part and for a given state.
539  * If the local style for the part-state pair doesn't exist allocate and return it.
540  * @param obj pointer to an object
541  * @param selector OR-ed value of parts and state for which the style should be get
542  * @return pointer to the local style
543  */
get_local_style(lv_obj_t * obj,lv_style_selector_t selector)544 static lv_style_t * get_local_style(lv_obj_t * obj, lv_style_selector_t selector)
545 {
546     uint32_t i;
547     for(i = 0; i < obj->style_cnt; i++) {
548         if(obj->styles[i].is_local &&
549            obj->styles[i].selector == selector) {
550             return obj->styles[i].style;
551         }
552     }
553 
554     obj->style_cnt++;
555     obj->styles = lv_mem_realloc(obj->styles, obj->style_cnt * sizeof(_lv_obj_style_t));
556     LV_ASSERT_MALLOC(obj->styles);
557 
558     for(i = obj->style_cnt - 1; i > 0 ; i--) {
559         /*Copy only normal styles (not local and transition).
560          *The new local style will be added as the last local style*/
561         if(obj->styles[i - 1].is_local || obj->styles[i - 1].is_trans) break;
562         obj->styles[i] = obj->styles[i - 1];
563     }
564 
565     lv_memset_00(&obj->styles[i], sizeof(_lv_obj_style_t));
566     obj->styles[i].style = lv_mem_alloc(sizeof(lv_style_t));
567     lv_style_init(obj->styles[i].style);
568     obj->styles[i].is_local = 1;
569     obj->styles[i].selector = selector;
570     return obj->styles[i].style;
571 }
572 
573 /**
574  * Get the transition style of an object for a given part and for a given state.
575  * If the transition style for the part-state pair doesn't exist allocate and return it.
576  * @param obj   pointer to an object
577  * @param selector OR-ed value of parts and state for which the style should be get
578  * @return pointer to the transition style
579  */
get_trans_style(lv_obj_t * obj,lv_style_selector_t selector)580 static _lv_obj_style_t * get_trans_style(lv_obj_t * obj,  lv_style_selector_t selector)
581 {
582     uint32_t i;
583     for(i = 0; i < obj->style_cnt; i++) {
584         if(obj->styles[i].is_trans && obj->styles[i].selector == selector) break;
585     }
586 
587     /*Already have a transition style for it*/
588     if(i != obj->style_cnt) return &obj->styles[i];
589 
590     obj->style_cnt++;
591     obj->styles = lv_mem_realloc(obj->styles, obj->style_cnt * sizeof(_lv_obj_style_t));
592 
593     for(i = obj->style_cnt - 1; i > 0 ; i--) {
594         obj->styles[i] = obj->styles[i - 1];
595     }
596 
597     lv_memset_00(&obj->styles[0], sizeof(_lv_obj_style_t));
598     obj->styles[0].style = lv_mem_alloc(sizeof(lv_style_t));
599     lv_style_init(obj->styles[0].style);
600     obj->styles[0].is_trans = 1;
601     obj->styles[0].selector = selector;
602     return &obj->styles[0];
603 }
604 
605 
get_prop_core(const lv_obj_t * obj,lv_part_t part,lv_style_prop_t prop,lv_style_value_t * v)606 static lv_style_res_t get_prop_core(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, lv_style_value_t * v)
607 {
608     uint8_t group = 1 << _lv_style_get_prop_group(prop);
609     int32_t weight = -1;
610     lv_state_t state = obj->state;
611     lv_state_t state_inv = ~state;
612     lv_style_value_t value_tmp;
613     bool skip_trans = obj->skip_trans;
614     uint32_t i;
615     lv_style_res_t found;
616     for(i = 0; i < obj->style_cnt; i++) {
617         _lv_obj_style_t * obj_style = &obj->styles[i];
618         if(obj_style->is_trans == false) break;
619         if(skip_trans) continue;
620 
621         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
622 
623         if(part_act != part) continue;
624         if((obj_style->style->has_group & group) == 0) continue;
625         found = lv_style_get_prop(obj_style->style, prop, &value_tmp);
626         if(found == LV_STYLE_RES_FOUND) {
627             *v = value_tmp;
628             return LV_STYLE_RES_FOUND;
629         }
630         else if(found == LV_STYLE_RES_INHERIT) {
631             return LV_STYLE_RES_INHERIT;
632         }
633     }
634 
635     for(; i < obj->style_cnt; i++) {
636         if((obj->styles[i].style->has_group & group) == 0) continue;
637         _lv_obj_style_t * obj_style = &obj->styles[i];
638         lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector);
639         lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector);
640         if(part_act != part) continue;
641 
642         /*Be sure the style not specifies other state than the requested.
643          *E.g. For HOVER+PRESS object state, HOVER style only is OK, but HOVER+FOCUS style is not*/
644         if((state_act & state_inv)) continue;
645 
646         /*Check only better candidates*/
647         if(state_act <= weight) continue;
648 
649         found = lv_style_get_prop(obj_style->style, prop, &value_tmp);
650 
651         if(found == LV_STYLE_RES_FOUND) {
652             if(state_act == state) {
653                 *v = value_tmp;
654                 return LV_STYLE_RES_FOUND;
655             }
656             if(weight < state_act) {
657                 weight = state_act;
658                 *v = value_tmp;
659             }
660         }
661         else if(found == LV_STYLE_RES_INHERIT) {
662             return LV_STYLE_RES_INHERIT;
663         }
664     }
665 
666     if(weight >= 0) {
667         *v = value_tmp;
668         return LV_STYLE_RES_FOUND;
669     }
670     else return LV_STYLE_RES_NOT_FOUND;
671 }
672 
673 /**
674  * Refresh the style of all children of an object. (Called recursively)
675  * @param style refresh objects only with this
676  * @param obj pointer to an object
677  */
report_style_change_core(void * style,lv_obj_t * obj)678 static void report_style_change_core(void * style, lv_obj_t * obj)
679 {
680     uint32_t i;
681     for(i = 0; i < obj->style_cnt; i++) {
682         if(style == NULL || obj->styles[i].style == style) {
683             lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY);
684             break;
685         }
686     }
687 
688     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
689     for(i = 0; i < child_cnt; i++) {
690         report_style_change_core(style, obj->spec_attr->children[i]);
691     }
692 }
693 
694 /**
695  * Recursively refresh the style of the children. Go deeper until a not NULL style is found
696  * because the NULL styles are inherited from the parent
697  * @param obj pointer to an object
698  */
refresh_children_style(lv_obj_t * obj)699 static void refresh_children_style(lv_obj_t * obj)
700 {
701     uint32_t i;
702     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
703     for(i = 0; i < child_cnt; i++) {
704         lv_obj_t * child = obj->spec_attr->children[i];
705         lv_obj_invalidate(child);
706         lv_event_send(child, LV_EVENT_STYLE_CHANGED, NULL);
707         lv_obj_invalidate(child);
708 
709         refresh_children_style(child); /*Check children too*/
710     }
711 }
712 
713 /**
714  * Remove the transition from object's part's property.
715  * - Remove the transition from `_lv_obj_style_trans_ll` and free it
716  * - Delete pending transitions
717  * @param obj pointer to an object which transition(s) should be removed
718  * @param part a part of object or 0xFF to remove from all parts
719  * @param prop a property or 0xFF to remove all properties
720  * @param tr_limit delete transitions only "older" than this. `NULL` if not used
721  */
trans_del(lv_obj_t * obj,lv_part_t part,lv_style_prop_t prop,trans_t * tr_limit)722 static bool trans_del(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop, trans_t * tr_limit)
723 {
724     trans_t * tr;
725     trans_t * tr_prev;
726     bool removed = false;
727     tr = _lv_ll_get_tail(&LV_GC_ROOT(_lv_obj_style_trans_ll));
728     while(tr != NULL) {
729         if(tr == tr_limit) break;
730 
731         /*'tr' might be deleted, so get the next object while 'tr' is valid*/
732         tr_prev = _lv_ll_get_prev(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr);
733 
734         if(tr->obj == obj && (part == tr->selector || part == LV_PART_ANY) && (prop == tr->prop || prop == LV_STYLE_PROP_ANY)) {
735             /*Remove any transitioned properties from the trans. style
736              *to allow changing it by normal styles*/
737             uint32_t i;
738             for(i = 0; i < obj->style_cnt; i++) {
739                 if(obj->styles[i].is_trans && (part == LV_PART_ANY || obj->styles[i].selector == part)) {
740                     lv_style_remove_prop(obj->styles[i].style, tr->prop);
741                 }
742             }
743 
744             /*Free the transition descriptor too*/
745             lv_anim_del(tr, NULL);
746             _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr);
747             lv_mem_free(tr);
748             removed = true;
749 
750         }
751         tr = tr_prev;
752     }
753     return removed;
754 }
755 
trans_anim_cb(void * _tr,int32_t v)756 static void trans_anim_cb(void * _tr, int32_t v)
757 {
758     trans_t * tr = _tr;
759     lv_obj_t * obj = tr->obj;
760 
761     uint32_t i;
762     for(i = 0; i < obj->style_cnt; i++) {
763         if(obj->styles[i].is_trans == 0 || obj->styles[i].selector != tr->selector) continue;
764 
765         lv_style_value_t value_final;
766         switch(tr->prop) {
767 
768             case LV_STYLE_BORDER_SIDE:
769             case LV_STYLE_BORDER_POST:
770             case LV_STYLE_BLEND_MODE:
771                 if(v < 255) value_final.num = tr->start_value.num;
772                 else value_final.num = tr->end_value.num;
773                 break;
774             case LV_STYLE_TRANSITION:
775             case LV_STYLE_TEXT_FONT:
776                 if(v < 255) value_final.ptr = tr->start_value.ptr;
777                 else value_final.ptr = tr->end_value.ptr;
778                 break;
779             case LV_STYLE_COLOR_FILTER_DSC:
780                 if(tr->start_value.ptr == NULL) value_final.ptr = tr->end_value.ptr;
781                 else if(tr->end_value.ptr == NULL) value_final.ptr = tr->start_value.ptr;
782                 else if(v < 128) value_final.ptr = tr->start_value.ptr;
783                 else value_final.ptr = tr->end_value.ptr;
784                 break;
785             case LV_STYLE_BG_COLOR:
786             case LV_STYLE_BG_GRAD_COLOR:
787             case LV_STYLE_BORDER_COLOR:
788             case LV_STYLE_TEXT_COLOR:
789             case LV_STYLE_SHADOW_COLOR:
790             case LV_STYLE_OUTLINE_COLOR:
791             case LV_STYLE_IMG_RECOLOR:
792                 if(v <= 0) value_final.color = tr->start_value.color;
793                 else if(v >= 255) value_final.color = tr->end_value.color;
794                 else value_final.color = lv_color_mix(tr->end_value.color, tr->start_value.color, v);
795                 break;
796 
797             default:
798                 if(v == 0) value_final.num = tr->start_value.num;
799                 else if(v == 255) value_final.num = tr->end_value.num;
800                 else value_final.num = tr->start_value.num + ((int32_t)((int32_t)(tr->end_value.num - tr->start_value.num) * v) >> 8);
801                 break;
802         }
803 
804         lv_style_value_t old_value;
805         bool refr = true;
806         if(lv_style_get_prop(obj->styles[i].style, tr->prop, &old_value)) {
807             if(value_final.ptr == old_value.ptr && value_final.color.full == old_value.color.full &&
808                value_final.num == old_value.num) {
809                 refr = false;
810             }
811         }
812         lv_style_set_prop(obj->styles[i].style, tr->prop, value_final);
813         if(refr) lv_obj_refresh_style(tr->obj, tr->selector, tr->prop);
814         break;
815 
816     }
817 
818 }
819 
trans_anim_start_cb(lv_anim_t * a)820 static void trans_anim_start_cb(lv_anim_t * a)
821 {
822     trans_t * tr = a->var;
823 
824     lv_part_t part = lv_obj_style_get_selector_part(tr->selector);
825     tr->start_value = lv_obj_get_style_prop(tr->obj, part, tr->prop);
826 
827     /*Init prop to an invalid values to be sure `trans_del` won't delete this added `tr`*/
828     lv_style_prop_t prop_tmp = tr->prop;
829     tr->prop = LV_STYLE_PROP_INV;
830 
831     /*Delete the related transitions if any*/
832     trans_del(tr->obj, part, prop_tmp, tr);
833 
834     tr->prop = prop_tmp;
835 
836     _lv_obj_style_t * style_trans = get_trans_style(tr->obj, tr->selector);
837     lv_style_set_prop(style_trans->style, tr->prop, tr->start_value);   /*Be sure `trans_style` has a valid value*/
838 
839 }
840 
trans_anim_ready_cb(lv_anim_t * a)841 static void trans_anim_ready_cb(lv_anim_t * a)
842 {
843     trans_t * tr = a->var;
844     lv_obj_t * obj = tr->obj;
845     lv_style_prop_t prop = tr->prop;
846 
847     /*Remove the transitioned property from trans. style
848      *if there no more transitions for this property
849      *It allows changing it by normal styles*/
850     bool running = false;
851     trans_t * tr_i;
852     _LV_LL_READ(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr_i) {
853         if(tr_i != tr && tr_i->obj == tr->obj && tr_i->selector == tr->selector && tr_i->prop == tr->prop) {
854             running = true;
855             break;
856         }
857     }
858 
859     if(!running) {
860         uint32_t i;
861         for(i = 0; i < obj->style_cnt; i++) {
862             if(obj->styles[i].is_trans && obj->styles[i].selector == tr->selector) {
863                 _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr);
864                 lv_mem_free(tr);
865 
866                 _lv_obj_style_t * obj_style = &obj->styles[i];
867                 lv_style_remove_prop(obj_style->style, prop);
868 
869                 if(lv_style_is_empty(obj->styles[i].style)) {
870                     lv_obj_remove_style(obj, obj_style->style, obj_style->selector);
871 
872                 }
873                 break;
874             }
875         }
876     }
877 }
878 
calculate_layer_type(lv_obj_t * obj)879 static lv_layer_type_t calculate_layer_type(lv_obj_t * obj)
880 {
881     if(lv_obj_get_style_transform_angle(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
882     if(lv_obj_get_style_transform_zoom(obj, 0) != 256) return LV_LAYER_TYPE_TRANSFORM;
883     if(lv_obj_get_style_opa_layered(obj, 0) != LV_OPA_COVER) return LV_LAYER_TYPE_SIMPLE;
884 #if LV_DRAW_COMPLEX
885     if(lv_obj_get_style_blend_mode(obj, 0) != LV_BLEND_MODE_NORMAL) return LV_LAYER_TYPE_SIMPLE;
886 #endif
887     return LV_LAYER_TYPE_NONE;
888 }
889 
fade_anim_cb(void * obj,int32_t v)890 static void fade_anim_cb(void * obj, int32_t v)
891 {
892     lv_obj_set_style_opa(obj, v, 0);
893 }
894 
fade_in_anim_ready(lv_anim_t * a)895 static void fade_in_anim_ready(lv_anim_t * a)
896 {
897     lv_obj_remove_local_style_prop(a->var, LV_STYLE_OPA, 0);
898 }
899 
900 
901