acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_obj_style.c (29000B)

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