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.c (31366B)
1 /** 2 * @file lv_obj.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_obj.h" 10 #include "lv_indev.h" 11 #include "lv_refr.h" 12 #include "lv_group.h" 13 #include "lv_disp.h" 14 #include "lv_theme.h" 15 #include "../misc/lv_assert.h" 16 #include "../draw/lv_draw.h" 17 #include "../misc/lv_anim.h" 18 #include "../misc/lv_timer.h" 19 #include "../misc/lv_async.h" 20 #include "../misc/lv_fs.h" 21 #include "../misc/lv_gc.h" 22 #include "../misc/lv_math.h" 23 #include "../misc/lv_log.h" 24 #include "../hal/lv_hal.h" 25 #include "../extra/lv_extra.h" 26 #include <stdint.h> 27 #include <string.h> 28 29 #if LV_USE_GPU_STM32_DMA2D 30 #include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h" 31 #endif 32 33 #if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT 34 #include "../gpu/lv_gpu_nxp_pxp.h" 35 #include "../gpu/lv_gpu_nxp_pxp_osa.h" 36 #endif 37 38 /********************* 39 * DEFINES 40 *********************/ 41 #define MY_CLASS &lv_obj_class 42 #define LV_OBJ_DEF_WIDTH (LV_DPX(100)) 43 #define LV_OBJ_DEF_HEIGHT (LV_DPX(50)) 44 #define STYLE_TRANSITION_MAX 32 45 46 /********************** 47 * TYPEDEFS 48 **********************/ 49 50 /********************** 51 * STATIC PROTOTYPES 52 **********************/ 53 static void lv_obj_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 54 static void lv_obj_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 55 static void lv_obj_draw(lv_event_t * e); 56 static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e); 57 static void draw_scrollbar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); 58 static lv_res_t scrollbar_init_draw_dsc(lv_obj_t * obj, lv_draw_rect_dsc_t * dsc); 59 static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find); 60 static void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state); 61 62 /********************** 63 * STATIC VARIABLES 64 **********************/ 65 static bool lv_initialized = false; 66 const lv_obj_class_t lv_obj_class = { 67 .constructor_cb = lv_obj_constructor, 68 .destructor_cb = lv_obj_destructor, 69 .event_cb = lv_obj_event, 70 .width_def = LV_DPI_DEF, 71 .height_def = LV_DPI_DEF, 72 .editable = LV_OBJ_CLASS_EDITABLE_FALSE, 73 .group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE, 74 .instance_size = (sizeof(lv_obj_t)), 75 .base_class = NULL, 76 }; 77 78 /********************** 79 * MACROS 80 **********************/ 81 82 /********************** 83 * GLOBAL FUNCTIONS 84 **********************/ 85 86 bool lv_is_initialized(void) 87 { 88 return lv_initialized; 89 } 90 91 void lv_init(void) 92 { 93 /*Do nothing if already initialized*/ 94 if(lv_initialized) { 95 LV_LOG_WARN("lv_init: already inited"); 96 return; 97 } 98 99 LV_LOG_INFO("begin"); 100 101 /*Initialize the misc modules*/ 102 lv_mem_init(); 103 104 _lv_timer_core_init(); 105 106 _lv_fs_init(); 107 108 _lv_anim_core_init(); 109 110 _lv_group_init(); 111 112 lv_draw_init(); 113 114 #if LV_USE_GPU_STM32_DMA2D 115 /*Initialize DMA2D GPU*/ 116 lv_draw_stm32_dma2d_init(); 117 #endif 118 119 #if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT 120 if(lv_gpu_nxp_pxp_init(&pxp_default_cfg) != LV_RES_OK) { 121 LV_LOG_ERROR("PXP init error. STOP.\n"); 122 for(; ;) ; 123 } 124 #endif 125 126 _lv_obj_style_init(); 127 _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); 128 _lv_ll_init(&LV_GC_ROOT(_lv_indev_ll), sizeof(lv_indev_t)); 129 130 /*Initialize the screen refresh system*/ 131 _lv_refr_init(); 132 133 _lv_img_decoder_init(); 134 #if LV_IMG_CACHE_DEF_SIZE 135 lv_img_cache_set_size(LV_IMG_CACHE_DEF_SIZE); 136 #endif 137 /*Test if the IDE has UTF-8 encoding*/ 138 char * txt = "Á"; 139 140 uint8_t * txt_u8 = (uint8_t *)txt; 141 if(txt_u8[0] != 0xc3 || txt_u8[1] != 0x81 || txt_u8[2] != 0x00) { 142 LV_LOG_WARN("The strings have no UTF-8 encoding. Non-ASCII characters won't be displayed."); 143 } 144 145 uint32_t endianess_test = 0x11223344; 146 uint8_t * endianess_test_p = (uint8_t *) &endianess_test; 147 bool big_endian = endianess_test_p[0] == 0x11 ? true : false; 148 149 if(big_endian) { 150 LV_ASSERT_MSG(LV_BIG_ENDIAN_SYSTEM == 1, 151 "It's a big endian system but LV_BIG_ENDIAN_SYSTEM is not enabled in lv_conf.h"); 152 } 153 else { 154 LV_ASSERT_MSG(LV_BIG_ENDIAN_SYSTEM == 0, 155 "It's a little endian system but LV_BIG_ENDIAN_SYSTEM is enabled in lv_conf.h"); 156 } 157 158 #if LV_USE_ASSERT_MEM_INTEGRITY 159 LV_LOG_WARN("Memory integrity checks are enabled via LV_USE_ASSERT_MEM_INTEGRITY which makes LVGL much slower"); 160 #endif 161 162 #if LV_USE_ASSERT_OBJ 163 LV_LOG_WARN("Object sanity checks are enabled via LV_USE_ASSERT_OBJ which makes LVGL much slower"); 164 #endif 165 166 #if LV_USE_ASSERT_STYLE 167 LV_LOG_WARN("Style sanity checks are enabled that uses more RAM"); 168 #endif 169 170 #if LV_LOG_LEVEL == LV_LOG_LEVEL_TRACE 171 LV_LOG_WARN("Log level is set to 'Trace' which makes LVGL much slower"); 172 #endif 173 174 lv_extra_init(); 175 176 lv_initialized = true; 177 178 LV_LOG_TRACE("finished"); 179 } 180 181 #if LV_ENABLE_GC || !LV_MEM_CUSTOM 182 183 void lv_deinit(void) 184 { 185 _lv_gc_clear_roots(); 186 187 lv_disp_set_default(NULL); 188 lv_mem_deinit(); 189 lv_initialized = false; 190 191 LV_LOG_INFO("lv_deinit done"); 192 193 #if LV_USE_LOG 194 lv_log_register_print_cb(NULL); 195 #endif 196 } 197 #endif 198 199 lv_obj_t * lv_obj_create(lv_obj_t * parent) 200 { 201 LV_LOG_INFO("begin"); 202 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent); 203 lv_obj_class_init_obj(obj); 204 return obj; 205 } 206 207 /*===================== 208 * Setter functions 209 *====================*/ 210 211 /*----------------- 212 * Attribute set 213 *----------------*/ 214 215 void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f) 216 { 217 LV_ASSERT_OBJ(obj, MY_CLASS); 218 219 bool was_on_layout = lv_obj_is_layout_positioned(obj); 220 221 if(f & LV_OBJ_FLAG_HIDDEN) lv_obj_invalidate(obj); 222 223 obj->flags |= f; 224 225 if(f & LV_OBJ_FLAG_HIDDEN) { 226 lv_obj_invalidate(obj); 227 } 228 229 if((was_on_layout != lv_obj_is_layout_positioned(obj)) || (f & (LV_OBJ_FLAG_LAYOUT_1 | LV_OBJ_FLAG_LAYOUT_2))) { 230 lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj)); 231 lv_obj_mark_layout_as_dirty(obj); 232 } 233 234 if(f & LV_OBJ_FLAG_SCROLLABLE) { 235 lv_area_t hor_area, ver_area; 236 lv_obj_get_scrollbar_area(obj, &hor_area, &ver_area); 237 lv_obj_invalidate_area(obj, &hor_area); 238 lv_obj_invalidate_area(obj, &ver_area); 239 } 240 } 241 242 void lv_obj_clear_flag(lv_obj_t * obj, lv_obj_flag_t f) 243 { 244 LV_ASSERT_OBJ(obj, MY_CLASS); 245 246 bool was_on_layout = lv_obj_is_layout_positioned(obj); 247 if(f & LV_OBJ_FLAG_SCROLLABLE) { 248 lv_area_t hor_area, ver_area; 249 lv_obj_get_scrollbar_area(obj, &hor_area, &ver_area); 250 lv_obj_invalidate_area(obj, &hor_area); 251 lv_obj_invalidate_area(obj, &ver_area); 252 } 253 254 obj->flags &= (~f); 255 256 if(f & LV_OBJ_FLAG_HIDDEN) { 257 lv_obj_invalidate(obj); 258 if(lv_obj_is_layout_positioned(obj)) { 259 lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj)); 260 lv_obj_mark_layout_as_dirty(obj); 261 } 262 } 263 264 if((was_on_layout != lv_obj_is_layout_positioned(obj)) || (f & (LV_OBJ_FLAG_LAYOUT_1 | LV_OBJ_FLAG_LAYOUT_2))) { 265 lv_obj_mark_layout_as_dirty(lv_obj_get_parent(obj)); 266 } 267 } 268 269 void lv_obj_add_state(lv_obj_t * obj, lv_state_t state) 270 { 271 LV_ASSERT_OBJ(obj, MY_CLASS); 272 273 lv_state_t new_state = obj->state | state; 274 if(obj->state != new_state) { 275 lv_obj_set_state(obj, new_state); 276 } 277 } 278 279 void lv_obj_clear_state(lv_obj_t * obj, lv_state_t state) 280 { 281 LV_ASSERT_OBJ(obj, MY_CLASS); 282 283 lv_state_t new_state = obj->state & (~state); 284 if(obj->state != new_state) { 285 lv_obj_set_state(obj, new_state); 286 } 287 } 288 289 /*======================= 290 * Getter functions 291 *======================*/ 292 293 bool lv_obj_has_flag(const lv_obj_t * obj, lv_obj_flag_t f) 294 { 295 LV_ASSERT_OBJ(obj, MY_CLASS); 296 297 return (obj->flags & f) == f ? true : false; 298 } 299 300 bool lv_obj_has_flag_any(const lv_obj_t * obj, lv_obj_flag_t f) 301 { 302 LV_ASSERT_OBJ(obj, MY_CLASS); 303 304 return (obj->flags & f) ? true : false; 305 } 306 307 lv_state_t lv_obj_get_state(const lv_obj_t * obj) 308 { 309 LV_ASSERT_OBJ(obj, MY_CLASS); 310 311 return obj->state; 312 } 313 314 bool lv_obj_has_state(const lv_obj_t * obj, lv_state_t state) 315 { 316 LV_ASSERT_OBJ(obj, MY_CLASS); 317 318 return obj->state & state ? true : false; 319 } 320 321 void * lv_obj_get_group(const lv_obj_t * obj) 322 { 323 LV_ASSERT_OBJ(obj, MY_CLASS); 324 325 if(obj->spec_attr) return obj->spec_attr->group_p; 326 else return NULL; 327 } 328 329 /*------------------- 330 * OTHER FUNCTIONS 331 *------------------*/ 332 333 void lv_obj_allocate_spec_attr(lv_obj_t * obj) 334 { 335 LV_ASSERT_OBJ(obj, MY_CLASS); 336 337 if(obj->spec_attr == NULL) { 338 static uint32_t x = 0; 339 x++; 340 obj->spec_attr = lv_mem_alloc(sizeof(_lv_obj_spec_attr_t)); 341 LV_ASSERT_MALLOC(obj->spec_attr); 342 if(obj->spec_attr == NULL) return; 343 344 lv_memset_00(obj->spec_attr, sizeof(_lv_obj_spec_attr_t)); 345 346 obj->spec_attr->scroll_dir = LV_DIR_ALL; 347 obj->spec_attr->scrollbar_mode = LV_SCROLLBAR_MODE_AUTO; 348 } 349 } 350 351 bool lv_obj_check_type(const lv_obj_t * obj, const lv_obj_class_t * class_p) 352 { 353 if(obj == NULL) return false; 354 return obj->class_p == class_p ? true : false; 355 } 356 357 bool lv_obj_has_class(const lv_obj_t * obj, const lv_obj_class_t * class_p) 358 { 359 const lv_obj_class_t * obj_class = obj->class_p; 360 while(obj_class) { 361 if(obj_class == class_p) return true; 362 obj_class = obj_class->base_class; 363 } 364 365 return false; 366 } 367 368 const lv_obj_class_t * lv_obj_get_class(const lv_obj_t * obj) 369 { 370 return obj->class_p; 371 } 372 373 bool lv_obj_is_valid(const lv_obj_t * obj) 374 { 375 lv_disp_t * disp = lv_disp_get_next(NULL); 376 while(disp) { 377 uint32_t i; 378 for(i = 0; i < disp->screen_cnt; i++) { 379 if(disp->screens[i] == obj) return true; 380 bool found = obj_valid_child(disp->screens[i], obj); 381 if(found) return true; 382 } 383 384 disp = lv_disp_get_next(disp); 385 } 386 387 return false; 388 } 389 390 /********************** 391 * STATIC FUNCTIONS 392 **********************/ 393 394 static void lv_obj_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 395 { 396 LV_UNUSED(class_p); 397 LV_TRACE_OBJ_CREATE("begin"); 398 399 lv_obj_t * parent = obj->parent; 400 if(parent) { 401 lv_coord_t sl = lv_obj_get_scroll_left(parent); 402 lv_coord_t st = lv_obj_get_scroll_top(parent); 403 404 obj->coords.y1 = parent->coords.y1 + lv_obj_get_style_pad_top(parent, LV_PART_MAIN) - st; 405 obj->coords.y2 = obj->coords.y1 - 1; 406 obj->coords.x1 = parent->coords.x1 + lv_obj_get_style_pad_left(parent, LV_PART_MAIN) - sl; 407 obj->coords.x2 = obj->coords.x1 - 1; 408 } 409 410 /*Set attributes*/ 411 obj->flags = LV_OBJ_FLAG_CLICKABLE; 412 obj->flags |= LV_OBJ_FLAG_SNAPPABLE; 413 if(parent) obj->flags |= LV_OBJ_FLAG_PRESS_LOCK; 414 if(parent) obj->flags |= LV_OBJ_FLAG_SCROLL_CHAIN; 415 obj->flags |= LV_OBJ_FLAG_CLICK_FOCUSABLE; 416 obj->flags |= LV_OBJ_FLAG_SCROLLABLE; 417 obj->flags |= LV_OBJ_FLAG_SCROLL_ELASTIC; 418 obj->flags |= LV_OBJ_FLAG_SCROLL_MOMENTUM; 419 obj->flags |= LV_OBJ_FLAG_SCROLL_WITH_ARROW; 420 if(parent) obj->flags |= LV_OBJ_FLAG_GESTURE_BUBBLE; 421 422 LV_TRACE_OBJ_CREATE("finished"); 423 } 424 425 static void lv_obj_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 426 { 427 LV_UNUSED(class_p); 428 429 _lv_event_mark_deleted(obj); 430 431 /*Remove all style*/ 432 lv_obj_enable_style_refresh(false); /*No need to refresh the style because the object will be deleted*/ 433 lv_obj_remove_style_all(obj); 434 lv_obj_enable_style_refresh(true); 435 436 /*Remove the animations from this object*/ 437 lv_anim_del(obj, NULL); 438 439 /*Delete from the group*/ 440 lv_group_t * group = lv_obj_get_group(obj); 441 if(group) lv_group_remove_obj(obj); 442 443 if(obj->spec_attr) { 444 if(obj->spec_attr->children) { 445 lv_mem_free(obj->spec_attr->children); 446 obj->spec_attr->children = NULL; 447 } 448 if(obj->spec_attr->event_dsc) { 449 lv_mem_free(obj->spec_attr->event_dsc); 450 obj->spec_attr->event_dsc = NULL; 451 } 452 453 lv_mem_free(obj->spec_attr); 454 obj->spec_attr = NULL; 455 } 456 } 457 458 static void lv_obj_draw(lv_event_t * e) 459 { 460 lv_event_code_t code = lv_event_get_code(e); 461 lv_obj_t * obj = lv_event_get_target(e); 462 if(code == LV_EVENT_COVER_CHECK) { 463 lv_cover_check_info_t * info = lv_event_get_param(e); 464 if(info->res == LV_COVER_RES_MASKED) return; 465 if(lv_obj_get_style_clip_corner(obj, LV_PART_MAIN)) { 466 info->res = LV_COVER_RES_MASKED; 467 return; 468 } 469 470 /*Most trivial test. Is the mask fully IN the object? If no it surely doesn't cover it*/ 471 lv_coord_t r = lv_obj_get_style_radius(obj, LV_PART_MAIN); 472 lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_PART_MAIN); 473 lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_PART_MAIN); 474 lv_area_t coords; 475 lv_area_copy(&coords, &obj->coords); 476 coords.x1 -= w; 477 coords.x2 += w; 478 coords.y1 -= h; 479 coords.y2 += h; 480 481 if(_lv_area_is_in(info->area, &coords, r) == false) { 482 info->res = LV_COVER_RES_NOT_COVER; 483 return; 484 } 485 486 if(lv_obj_get_style_bg_opa(obj, LV_PART_MAIN) < LV_OPA_MAX) { 487 info->res = LV_COVER_RES_NOT_COVER; 488 return; 489 } 490 491 #if LV_DRAW_COMPLEX 492 if(lv_obj_get_style_blend_mode(obj, LV_PART_MAIN) != LV_BLEND_MODE_NORMAL) { 493 info->res = LV_COVER_RES_NOT_COVER; 494 return; 495 } 496 #endif 497 if(lv_obj_get_style_opa(obj, LV_PART_MAIN) < LV_OPA_MAX) { 498 info->res = LV_COVER_RES_NOT_COVER; 499 return; 500 } 501 502 info->res = LV_COVER_RES_COVER; 503 504 } 505 else if(code == LV_EVENT_DRAW_MAIN) { 506 lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); 507 lv_draw_rect_dsc_t draw_dsc; 508 lv_draw_rect_dsc_init(&draw_dsc); 509 /*If the border is drawn later disable loading its properties*/ 510 if(lv_obj_get_style_border_post(obj, LV_PART_MAIN)) { 511 draw_dsc.border_post = 1; 512 } 513 514 lv_obj_init_draw_rect_dsc(obj, LV_PART_MAIN, &draw_dsc); 515 lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_PART_MAIN); 516 lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_PART_MAIN); 517 lv_area_t coords; 518 lv_area_copy(&coords, &obj->coords); 519 coords.x1 -= w; 520 coords.x2 += w; 521 coords.y1 -= h; 522 coords.y2 += h; 523 524 lv_obj_draw_part_dsc_t part_dsc; 525 lv_obj_draw_dsc_init(&part_dsc, draw_ctx); 526 part_dsc.class_p = MY_CLASS; 527 part_dsc.type = LV_OBJ_DRAW_PART_RECTANGLE; 528 part_dsc.rect_dsc = &draw_dsc; 529 part_dsc.draw_area = &coords; 530 part_dsc.part = LV_PART_MAIN; 531 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); 532 533 534 #if LV_DRAW_COMPLEX 535 /*With clip corner enabled draw the bg img separately to make it clipped*/ 536 bool clip_corner = (lv_obj_get_style_clip_corner(obj, LV_PART_MAIN) && draw_dsc.radius != 0) ? true : false; 537 const void * bg_img_src = draw_dsc.bg_img_src; 538 if(clip_corner) { 539 draw_dsc.bg_img_src = NULL; 540 } 541 #endif 542 543 lv_draw_rect(draw_ctx, &draw_dsc, &coords); 544 545 546 #if LV_DRAW_COMPLEX 547 if(clip_corner) { 548 lv_draw_mask_radius_param_t * mp = lv_mem_buf_get(sizeof(lv_draw_mask_radius_param_t)); 549 lv_draw_mask_radius_init(mp, &obj->coords, draw_dsc.radius, false); 550 /*Add the mask and use `obj+8` as custom id. Don't use `obj` directly because it might be used by the user*/ 551 lv_draw_mask_add(mp, obj + 8); 552 553 if(bg_img_src) { 554 draw_dsc.bg_opa = LV_OPA_TRANSP; 555 draw_dsc.border_opa = LV_OPA_TRANSP; 556 draw_dsc.outline_opa = LV_OPA_TRANSP; 557 draw_dsc.shadow_opa = LV_OPA_TRANSP; 558 draw_dsc.bg_img_src = bg_img_src; 559 lv_draw_rect(draw_ctx, &draw_dsc, &coords); 560 } 561 562 } 563 #endif 564 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); 565 } 566 else if(code == LV_EVENT_DRAW_POST) { 567 lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); 568 draw_scrollbar(obj, draw_ctx); 569 570 #if LV_DRAW_COMPLEX 571 if(lv_obj_get_style_clip_corner(obj, LV_PART_MAIN)) { 572 lv_draw_mask_radius_param_t * param = lv_draw_mask_remove_custom(obj + 8); 573 if(param) { 574 lv_draw_mask_free_param(param); 575 lv_mem_buf_release(param); 576 } 577 } 578 #endif 579 580 /*If the border is drawn later disable loading other properties*/ 581 if(lv_obj_get_style_border_post(obj, LV_PART_MAIN)) { 582 lv_draw_rect_dsc_t draw_dsc; 583 lv_draw_rect_dsc_init(&draw_dsc); 584 draw_dsc.bg_opa = LV_OPA_TRANSP; 585 draw_dsc.bg_img_opa = LV_OPA_TRANSP; 586 draw_dsc.outline_opa = LV_OPA_TRANSP; 587 draw_dsc.shadow_opa = LV_OPA_TRANSP; 588 lv_obj_init_draw_rect_dsc(obj, LV_PART_MAIN, &draw_dsc); 589 590 lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_PART_MAIN); 591 lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_PART_MAIN); 592 lv_area_t coords; 593 lv_area_copy(&coords, &obj->coords); 594 coords.x1 -= w; 595 coords.x2 += w; 596 coords.y1 -= h; 597 coords.y2 += h; 598 599 lv_obj_draw_part_dsc_t part_dsc; 600 lv_obj_draw_dsc_init(&part_dsc, draw_ctx); 601 part_dsc.class_p = MY_CLASS; 602 part_dsc.type = LV_OBJ_DRAW_PART_BORDER_POST; 603 part_dsc.rect_dsc = &draw_dsc; 604 part_dsc.draw_area = &coords; 605 part_dsc.part = LV_PART_MAIN; 606 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); 607 608 lv_draw_rect(draw_ctx, &draw_dsc, &coords); 609 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); 610 } 611 } 612 } 613 614 static void draw_scrollbar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) 615 { 616 617 lv_area_t hor_area; 618 lv_area_t ver_area; 619 lv_obj_get_scrollbar_area(obj, &hor_area, &ver_area); 620 621 if(lv_area_get_size(&hor_area) <= 0 && lv_area_get_size(&ver_area) <= 0) return; 622 623 lv_draw_rect_dsc_t draw_dsc; 624 lv_res_t sb_res = scrollbar_init_draw_dsc(obj, &draw_dsc); 625 if(sb_res != LV_RES_OK) return; 626 627 lv_obj_draw_part_dsc_t part_dsc; 628 lv_obj_draw_dsc_init(&part_dsc, draw_ctx); 629 part_dsc.class_p = MY_CLASS; 630 part_dsc.type = LV_OBJ_DRAW_PART_SCROLLBAR; 631 part_dsc.rect_dsc = &draw_dsc; 632 part_dsc.part = LV_PART_SCROLLBAR; 633 634 if(lv_area_get_size(&hor_area) > 0) { 635 part_dsc.draw_area = &hor_area; 636 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); 637 lv_draw_rect(draw_ctx, &draw_dsc, &hor_area); 638 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); 639 } 640 if(lv_area_get_size(&ver_area) > 0) { 641 part_dsc.draw_area = &ver_area; 642 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); 643 part_dsc.draw_area = &ver_area; 644 lv_draw_rect(draw_ctx, &draw_dsc, &ver_area); 645 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); 646 } 647 } 648 649 /** 650 * Initialize the draw descriptor for the scrollbar 651 * @param obj pointer to an object 652 * @param dsc the draw descriptor to initialize 653 * @return LV_RES_OK: the scrollbar is visible; LV_RES_INV: the scrollbar is not visible 654 */ 655 static lv_res_t scrollbar_init_draw_dsc(lv_obj_t * obj, lv_draw_rect_dsc_t * dsc) 656 { 657 lv_draw_rect_dsc_init(dsc); 658 dsc->bg_opa = lv_obj_get_style_bg_opa(obj, LV_PART_SCROLLBAR); 659 if(dsc->bg_opa > LV_OPA_MIN) { 660 dsc->bg_color = lv_obj_get_style_bg_color(obj, LV_PART_SCROLLBAR); 661 } 662 663 dsc->border_opa = lv_obj_get_style_border_opa(obj, LV_PART_SCROLLBAR); 664 if(dsc->border_opa > LV_OPA_MIN) { 665 dsc->border_width = lv_obj_get_style_border_width(obj, LV_PART_SCROLLBAR); 666 if(dsc->border_width > 0) { 667 dsc->border_color = lv_obj_get_style_border_color(obj, LV_PART_SCROLLBAR); 668 } 669 else { 670 dsc->border_opa = LV_OPA_TRANSP; 671 } 672 } 673 674 #if LV_DRAW_COMPLEX 675 dsc->shadow_opa = lv_obj_get_style_shadow_opa(obj, LV_PART_SCROLLBAR); 676 if(dsc->shadow_opa > LV_OPA_MIN) { 677 dsc->shadow_width = lv_obj_get_style_shadow_width(obj, LV_PART_SCROLLBAR); 678 if(dsc->shadow_width > 0) { 679 dsc->shadow_spread = lv_obj_get_style_shadow_spread(obj, LV_PART_SCROLLBAR); 680 dsc->shadow_color = lv_obj_get_style_shadow_color(obj, LV_PART_SCROLLBAR); 681 } 682 else { 683 dsc->shadow_opa = LV_OPA_TRANSP; 684 } 685 } 686 687 lv_opa_t opa = lv_obj_get_style_opa(obj, LV_PART_SCROLLBAR); 688 if(opa < LV_OPA_MAX) { 689 dsc->bg_opa = (dsc->bg_opa * opa) >> 8; 690 dsc->border_opa = (dsc->bg_opa * opa) >> 8; 691 dsc->shadow_opa = (dsc->bg_opa * opa) >> 8; 692 } 693 694 if(dsc->bg_opa != LV_OPA_TRANSP || dsc->border_opa != LV_OPA_TRANSP || dsc->shadow_opa != LV_OPA_TRANSP) { 695 dsc->radius = lv_obj_get_style_radius(obj, LV_PART_SCROLLBAR); 696 return LV_RES_OK; 697 } 698 else { 699 return LV_RES_INV; 700 } 701 #else 702 if(dsc->bg_opa != LV_OPA_TRANSP || dsc->border_opa != LV_OPA_TRANSP) return LV_RES_OK; 703 else return LV_RES_INV; 704 #endif 705 } 706 707 static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e) 708 { 709 LV_UNUSED(class_p); 710 711 lv_event_code_t code = lv_event_get_code(e); 712 lv_obj_t * obj = lv_event_get_current_target(e); 713 if(code == LV_EVENT_PRESSED) { 714 lv_obj_add_state(obj, LV_STATE_PRESSED); 715 } 716 else if(code == LV_EVENT_RELEASED) { 717 lv_obj_clear_state(obj, LV_STATE_PRESSED); 718 void * param = lv_event_get_param(e); 719 /*Go the checked state if enabled*/ 720 if(lv_indev_get_scroll_obj(param) == NULL && lv_obj_has_flag(obj, LV_OBJ_FLAG_CHECKABLE)) { 721 if(!(lv_obj_get_state(obj) & LV_STATE_CHECKED)) lv_obj_add_state(obj, LV_STATE_CHECKED); 722 else lv_obj_clear_state(obj, LV_STATE_CHECKED); 723 724 lv_res_t res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); 725 if(res != LV_RES_OK) return; 726 } 727 } 728 else if(code == LV_EVENT_PRESS_LOST) { 729 lv_obj_clear_state(obj, LV_STATE_PRESSED); 730 } 731 else if(code == LV_EVENT_STYLE_CHANGED) { 732 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 733 for(uint32_t i = 0; i < child_cnt; i++) { 734 lv_obj_t * child = obj->spec_attr->children[i]; 735 lv_obj_mark_layout_as_dirty(child); 736 } 737 } 738 else if(code == LV_EVENT_KEY) { 739 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_CHECKABLE)) { 740 char c = *((char *)lv_event_get_param(e)); 741 if(c == LV_KEY_RIGHT || c == LV_KEY_UP) { 742 lv_obj_add_state(obj, LV_STATE_CHECKED); 743 } 744 else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) { 745 lv_obj_clear_state(obj, LV_STATE_CHECKED); 746 } 747 748 /*With Enter LV_EVENT_RELEASED will send VALUE_CHANGE event*/ 749 if(c != LV_KEY_ENTER) { 750 lv_res_t res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); 751 if(res != LV_RES_OK) return; 752 } 753 } 754 else if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_WITH_ARROW) && !lv_obj_is_editable(obj)) { 755 /*scroll by keypad or encoder*/ 756 lv_anim_enable_t anim_enable = LV_ANIM_OFF; 757 lv_coord_t sl = lv_obj_get_scroll_left(obj); 758 lv_coord_t sr = lv_obj_get_scroll_right(obj); 759 char c = *((char *)lv_event_get_param(e)); 760 if(c == LV_KEY_DOWN) { 761 /*use scroll_to_x/y functions to enforce scroll limits*/ 762 lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) + lv_obj_get_height(obj) / 4, anim_enable); 763 } 764 else if(c == LV_KEY_UP) { 765 lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) - lv_obj_get_height(obj) / 4, anim_enable); 766 } 767 else if(c == LV_KEY_RIGHT) { 768 /*If the object can't be scrolled horizontally then scroll it vertically*/ 769 if(!((lv_obj_get_scroll_dir(obj) & LV_DIR_HOR) && (sl > 0 || sr > 0))) 770 lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) + lv_obj_get_height(obj) / 4, anim_enable); 771 else 772 lv_obj_scroll_to_x(obj, lv_obj_get_scroll_x(obj) + lv_obj_get_width(obj) / 4, anim_enable); 773 } 774 else if(c == LV_KEY_LEFT) { 775 /*If the object can't be scrolled horizontally then scroll it vertically*/ 776 if(!((lv_obj_get_scroll_dir(obj) & LV_DIR_HOR) && (sl > 0 || sr > 0))) 777 lv_obj_scroll_to_y(obj, lv_obj_get_scroll_y(obj) - lv_obj_get_height(obj) / 4, anim_enable); 778 else 779 lv_obj_scroll_to_x(obj, lv_obj_get_scroll_x(obj) - lv_obj_get_width(obj) / 4, anim_enable); 780 } 781 } 782 } 783 else if(code == LV_EVENT_FOCUSED) { 784 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS)) { 785 lv_obj_scroll_to_view_recursive(obj, LV_ANIM_ON); 786 } 787 788 bool editing = false; 789 editing = lv_group_get_editing(lv_obj_get_group(obj)); 790 lv_state_t state = LV_STATE_FOCUSED; 791 792 /* Use the indev for then indev handler. 793 * But if the obj was focused manually it returns NULL so try to 794 * use the indev from the event*/ 795 lv_indev_t * indev = lv_indev_get_act(); 796 if(indev == NULL) indev = lv_event_get_indev(e); 797 798 lv_indev_type_t indev_type = lv_indev_get_type(indev); 799 if(indev_type == LV_INDEV_TYPE_KEYPAD || indev_type == LV_INDEV_TYPE_ENCODER) state |= LV_STATE_FOCUS_KEY; 800 if(editing) { 801 state |= LV_STATE_EDITED; 802 lv_obj_add_state(obj, state); 803 } 804 else { 805 lv_obj_add_state(obj, state); 806 lv_obj_clear_state(obj, LV_STATE_EDITED); 807 } 808 } 809 else if(code == LV_EVENT_SCROLL_BEGIN) { 810 lv_obj_add_state(obj, LV_STATE_SCROLLED); 811 } 812 else if(code == LV_EVENT_SCROLL_END) { 813 lv_obj_clear_state(obj, LV_STATE_SCROLLED); 814 if(lv_obj_get_scrollbar_mode(obj) == LV_SCROLLBAR_MODE_ACTIVE) { 815 lv_area_t hor_area, ver_area; 816 lv_obj_get_scrollbar_area(obj, &hor_area, &ver_area); 817 lv_obj_invalidate_area(obj, &hor_area); 818 lv_obj_invalidate_area(obj, &ver_area); 819 } 820 } 821 else if(code == LV_EVENT_DEFOCUSED) { 822 lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED | LV_STATE_FOCUS_KEY); 823 } 824 else if(code == LV_EVENT_SIZE_CHANGED) { 825 lv_coord_t align = lv_obj_get_style_align(obj, LV_PART_MAIN); 826 uint16_t layout = lv_obj_get_style_layout(obj, LV_PART_MAIN); 827 if(layout || align) { 828 lv_obj_mark_layout_as_dirty(obj); 829 } 830 831 uint32_t i; 832 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 833 for(i = 0; i < child_cnt; i++) { 834 lv_obj_t * child = obj->spec_attr->children[i]; 835 lv_obj_mark_layout_as_dirty(child); 836 } 837 } 838 else if(code == LV_EVENT_CHILD_CHANGED) { 839 lv_coord_t w = lv_obj_get_style_width(obj, LV_PART_MAIN); 840 lv_coord_t h = lv_obj_get_style_height(obj, LV_PART_MAIN); 841 lv_coord_t align = lv_obj_get_style_align(obj, LV_PART_MAIN); 842 uint16_t layout = lv_obj_get_style_layout(obj, LV_PART_MAIN); 843 if(layout || align || w == LV_SIZE_CONTENT || h == LV_SIZE_CONTENT) { 844 lv_obj_mark_layout_as_dirty(obj); 845 } 846 } 847 else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) { 848 lv_coord_t * s = lv_event_get_param(e); 849 lv_coord_t d = lv_obj_calculate_ext_draw_size(obj, LV_PART_MAIN); 850 *s = LV_MAX(*s, d); 851 } 852 else if(code == LV_EVENT_DRAW_MAIN || code == LV_EVENT_DRAW_POST || code == LV_EVENT_COVER_CHECK) { 853 lv_obj_draw(e); 854 } 855 } 856 857 /** 858 * Set the state (fully overwrite) of an object. 859 * If specified in the styles, transition animations will be started from the previous state to the current. 860 * @param obj pointer to an object 861 * @param state the new state 862 */ 863 static void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state) 864 { 865 if(obj->state == new_state) return; 866 867 LV_ASSERT_OBJ(obj, MY_CLASS); 868 869 lv_state_t prev_state = obj->state; 870 obj->state = new_state; 871 872 _lv_style_state_cmp_t cmp_res = _lv_obj_style_state_compare(obj, prev_state, new_state); 873 /*If there is no difference in styles there is nothing else to do*/ 874 if(cmp_res == _LV_STYLE_STATE_CMP_SAME) return; 875 876 _lv_obj_style_transition_dsc_t * ts = lv_mem_buf_get(sizeof(_lv_obj_style_transition_dsc_t) * STYLE_TRANSITION_MAX); 877 lv_memset_00(ts, sizeof(_lv_obj_style_transition_dsc_t) * STYLE_TRANSITION_MAX); 878 uint32_t tsi = 0; 879 uint32_t i; 880 for(i = 0; i < obj->style_cnt && tsi < STYLE_TRANSITION_MAX; i++) { 881 _lv_obj_style_t * obj_style = &obj->styles[i]; 882 lv_state_t state_act = lv_obj_style_get_selector_state(obj->styles[i].selector); 883 lv_part_t part_act = lv_obj_style_get_selector_part(obj->styles[i].selector); 884 if(state_act & (~new_state)) continue; /*Skip unrelated styles*/ 885 if(obj_style->is_trans) continue; 886 887 lv_style_value_t v; 888 if(lv_style_get_prop_inlined(obj_style->style, LV_STYLE_TRANSITION, &v) == false) continue; 889 const lv_style_transition_dsc_t * tr = v.ptr; 890 891 /*Add the props to the set if not added yet or added but with smaller weight*/ 892 uint32_t j; 893 for(j = 0; tr->props[j] != 0 && tsi < STYLE_TRANSITION_MAX; j++) { 894 uint32_t t; 895 for(t = 0; t < tsi; t++) { 896 lv_style_selector_t selector = ts[t].selector; 897 lv_state_t state_ts = lv_obj_style_get_selector_state(selector); 898 lv_part_t part_ts = lv_obj_style_get_selector_part(selector); 899 if(ts[t].prop == tr->props[j] && part_ts == part_act && state_ts >= state_act) break; 900 } 901 902 /*If not found add it*/ 903 if(t == tsi) { 904 ts[tsi].time = tr->time; 905 ts[tsi].delay = tr->delay; 906 ts[tsi].path_cb = tr->path_xcb; 907 ts[tsi].prop = tr->props[j]; 908 #if LV_USE_USER_DATA 909 ts[tsi].user_data = tr->user_data; 910 #endif 911 ts[tsi].selector = obj_style->selector; 912 tsi++; 913 } 914 } 915 } 916 917 for(i = 0; i < tsi; i++) { 918 lv_part_t part_act = lv_obj_style_get_selector_part(ts[i].selector); 919 _lv_obj_style_create_transition(obj, part_act, prev_state, new_state, &ts[i]); 920 } 921 922 lv_mem_buf_release(ts); 923 924 if(cmp_res == _LV_STYLE_STATE_CMP_DIFF_REDRAW) { 925 lv_obj_invalidate(obj); 926 } 927 else if(cmp_res == _LV_STYLE_STATE_CMP_DIFF_LAYOUT) { 928 lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY); 929 } 930 else if(cmp_res == _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD) { 931 lv_obj_invalidate(obj); 932 lv_obj_refresh_ext_draw_size(obj); 933 } 934 } 935 936 static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find) 937 { 938 /*Check all children of `parent`*/ 939 uint32_t child_cnt = 0; 940 if(parent->spec_attr) child_cnt = parent->spec_attr->child_cnt; 941 uint32_t i; 942 for(i = 0; i < child_cnt; i++) { 943 lv_obj_t * child = parent->spec_attr->children[i]; 944 if(child == obj_to_find) { 945 return true; 946 } 947 948 /*Check the children*/ 949 bool found = obj_valid_child(child, obj_to_find); 950 if(found) { 951 return true; 952 } 953 } 954 return false; 955 }