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