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_pos.c (35598B)
1 /** 2 * @file lv_obj_pos.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_obj.h" 10 #include "lv_disp.h" 11 #include "lv_refr.h" 12 #include "../misc/lv_gc.h" 13 14 /********************* 15 * DEFINES 16 *********************/ 17 #define MY_CLASS &lv_obj_class 18 19 /********************** 20 * TYPEDEFS 21 **********************/ 22 23 /********************** 24 * STATIC PROTOTYPES 25 **********************/ 26 static lv_coord_t calc_content_width(lv_obj_t * obj); 27 static lv_coord_t calc_content_height(lv_obj_t * obj); 28 static void layout_update_core(lv_obj_t * obj); 29 30 /********************** 31 * STATIC VARIABLES 32 **********************/ 33 static uint32_t layout_cnt; 34 35 /********************** 36 * MACROS 37 **********************/ 38 39 /********************** 40 * GLOBAL FUNCTIONS 41 **********************/ 42 43 void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) 44 { 45 LV_ASSERT_OBJ(obj, MY_CLASS); 46 47 lv_obj_set_x(obj, x); 48 lv_obj_set_y(obj, y); 49 } 50 51 void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x) 52 { 53 LV_ASSERT_OBJ(obj, MY_CLASS); 54 55 lv_res_t res_x; 56 lv_style_value_t v_x; 57 58 res_x = lv_obj_get_local_style_prop(obj, LV_STYLE_X, &v_x, 0); 59 60 if((res_x == LV_RES_OK && v_x.num != x) || res_x == LV_RES_INV) { 61 lv_obj_set_style_x(obj, x, 0); 62 } 63 } 64 65 void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y) 66 { 67 LV_ASSERT_OBJ(obj, MY_CLASS); 68 69 lv_res_t res_y; 70 lv_style_value_t v_y; 71 72 res_y = lv_obj_get_local_style_prop(obj, LV_STYLE_Y, &v_y, 0); 73 74 if((res_y == LV_RES_OK && v_y.num != y) || res_y == LV_RES_INV) { 75 lv_obj_set_style_y(obj, y, 0); 76 } 77 } 78 79 bool lv_obj_refr_size(lv_obj_t * obj) 80 { 81 LV_ASSERT_OBJ(obj, MY_CLASS); 82 83 /*If the width or height is set by a layout do not modify them*/ 84 if(obj->w_layout && obj->h_layout) return false; 85 86 lv_obj_t * parent = lv_obj_get_parent(obj); 87 if(parent == NULL) return false; 88 89 lv_coord_t sl_ori = lv_obj_get_scroll_left(obj); 90 bool w_is_content = false; 91 bool w_is_pct = false; 92 93 lv_coord_t w; 94 if(obj->w_layout) { 95 w = lv_obj_get_width(obj); 96 } 97 else { 98 w = lv_obj_get_style_width(obj, LV_PART_MAIN); 99 w_is_content = w == LV_SIZE_CONTENT ? true : false; 100 w_is_pct = LV_COORD_IS_PCT(w) ? true : false; 101 lv_coord_t parent_w = lv_obj_get_content_width(parent); 102 103 if(w_is_content) { 104 w = calc_content_width(obj); 105 } 106 else if(w_is_pct) { 107 /*If parent has content size and the child has pct size 108 *a circular dependency will occur. To solve it keep child size at zero */ 109 if(parent->w_layout == 0 && lv_obj_get_style_width(parent, 0) == LV_SIZE_CONTENT) { 110 lv_coord_t border_w = lv_obj_get_style_border_width(obj, 0); 111 w = lv_obj_get_style_pad_left(obj, 0) + border_w; 112 w += lv_obj_get_style_pad_right(obj, 0) + border_w; 113 } 114 else { 115 w = (LV_COORD_GET_PCT(w) * parent_w) / 100; 116 } 117 } 118 119 lv_coord_t minw = lv_obj_get_style_min_width(obj, LV_PART_MAIN); 120 lv_coord_t maxw = lv_obj_get_style_max_width(obj, LV_PART_MAIN); 121 w = lv_clamp_width(w, minw, maxw, parent_w); 122 } 123 124 lv_coord_t st_ori = lv_obj_get_scroll_top(obj); 125 lv_coord_t h; 126 bool h_is_content = false; 127 bool h_is_pct = false; 128 if(obj->h_layout) { 129 h = lv_obj_get_height(obj); 130 } 131 else { 132 h = lv_obj_get_style_height(obj, LV_PART_MAIN); 133 h_is_content = h == LV_SIZE_CONTENT ? true : false; 134 h_is_pct = LV_COORD_IS_PCT(h) ? true : false; 135 lv_coord_t parent_h = lv_obj_get_content_height(parent); 136 137 if(h_is_content) { 138 h = calc_content_height(obj); 139 } 140 else if(h_is_pct) { 141 /*If parent has content size and the child has pct size 142 *a circular dependency will occur. To solve it keep child size at zero */ 143 if(parent->h_layout == 0 && lv_obj_get_style_height(parent, 0) == LV_SIZE_CONTENT) { 144 lv_coord_t border_w = lv_obj_get_style_border_width(obj, 0); 145 h = lv_obj_get_style_pad_top(obj, 0) + border_w; 146 h += lv_obj_get_style_pad_bottom(obj, 0) + border_w; 147 } 148 else { 149 h = (LV_COORD_GET_PCT(h) * parent_h) / 100; 150 } 151 } 152 153 lv_coord_t minh = lv_obj_get_style_min_height(obj, LV_PART_MAIN); 154 lv_coord_t maxh = lv_obj_get_style_max_height(obj, LV_PART_MAIN); 155 h = lv_clamp_height(h, minh, maxh, parent_h); 156 } 157 158 /*calc_auto_size set the scroll x/y to 0 so revert the original value*/ 159 if(w_is_content || h_is_content) { 160 lv_obj_scroll_to(obj, sl_ori, st_ori, LV_ANIM_OFF); 161 } 162 163 /*Do nothing if the size is not changed*/ 164 /*It is very important else recursive resizing can occur without size change*/ 165 if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) return false; 166 167 /*Invalidate the original area*/ 168 lv_obj_invalidate(obj); 169 170 /*Save the original coordinates*/ 171 lv_area_t ori; 172 lv_obj_get_coords(obj, &ori); 173 174 /*Check if the object inside the parent or not*/ 175 lv_area_t parent_fit_area; 176 lv_obj_get_content_coords(parent, &parent_fit_area); 177 178 /*If the object is already out of the parent and its position is changes 179 *surely the scrollbars also changes so invalidate them*/ 180 bool on1 = _lv_area_is_in(&ori, &parent_fit_area, 0); 181 if(!on1) lv_obj_scrollbar_invalidate(parent); 182 183 /*Set the length and height 184 *Be sure the content is not scrolled in an invalid position on the new size*/ 185 obj->coords.y2 = obj->coords.y1 + h - 1; 186 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) { 187 obj->coords.x1 = obj->coords.x2 - w + 1; 188 } 189 else { 190 obj->coords.x2 = obj->coords.x1 + w - 1; 191 } 192 193 /*Call the ancestor's event handler to the object with its new coordinates*/ 194 lv_event_send(obj, LV_EVENT_SIZE_CHANGED, &ori); 195 196 /*Call the ancestor's event handler to the parent too*/ 197 lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj); 198 199 /*Invalidate the new area*/ 200 lv_obj_invalidate(obj); 201 202 lv_obj_readjust_scroll(obj, LV_ANIM_OFF); 203 204 /*If the object was out of the parent invalidate the new scrollbar area too. 205 *If it wasn't out of the parent but out now, also invalidate the scrollbars*/ 206 bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0); 207 if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent); 208 209 return true; 210 } 211 212 void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) 213 { 214 LV_ASSERT_OBJ(obj, MY_CLASS); 215 216 lv_obj_set_width(obj, w); 217 lv_obj_set_height(obj, h); 218 } 219 220 void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w) 221 { 222 LV_ASSERT_OBJ(obj, MY_CLASS); 223 lv_res_t res_w; 224 lv_style_value_t v_w; 225 226 res_w = lv_obj_get_local_style_prop(obj, LV_STYLE_WIDTH, &v_w, 0); 227 228 if((res_w == LV_RES_OK && v_w.num != w) || res_w == LV_RES_INV) { 229 lv_obj_set_style_width(obj, w, 0); 230 } 231 } 232 233 void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h) 234 { 235 LV_ASSERT_OBJ(obj, MY_CLASS); 236 lv_res_t res_h; 237 lv_style_value_t v_h; 238 239 res_h = lv_obj_get_local_style_prop(obj, LV_STYLE_HEIGHT, &v_h, 0); 240 241 if((res_h == LV_RES_OK && v_h.num != h) || res_h == LV_RES_INV) { 242 lv_obj_set_style_height(obj, h, 0); 243 } 244 } 245 246 void lv_obj_set_content_width(lv_obj_t * obj, lv_coord_t w) 247 { 248 lv_coord_t pleft = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); 249 lv_coord_t pright = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); 250 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 251 252 lv_obj_set_width(obj, w + pleft + pright + 2 * border_width); 253 } 254 255 void lv_obj_set_content_height(lv_obj_t * obj, lv_coord_t h) 256 { 257 lv_coord_t ptop = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); 258 lv_coord_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); 259 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 260 261 lv_obj_set_height(obj, h + ptop + pbottom + 2 * border_width); 262 } 263 264 void lv_obj_set_layout(lv_obj_t * obj, uint32_t layout) 265 { 266 LV_ASSERT_OBJ(obj, MY_CLASS); 267 268 lv_obj_set_style_layout(obj, layout, 0); 269 270 lv_obj_mark_layout_as_dirty(obj); 271 } 272 273 bool lv_obj_is_layout_positioned(const lv_obj_t * obj) 274 { 275 if(lv_obj_has_flag_any(obj, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_FLOATING)) return false; 276 277 lv_obj_t * parent = lv_obj_get_parent(obj); 278 if(parent == NULL) return false; 279 280 uint32_t layout = lv_obj_get_style_layout(parent, LV_PART_MAIN); 281 if(layout) return true; 282 else return false; 283 } 284 285 void lv_obj_mark_layout_as_dirty(lv_obj_t * obj) 286 { 287 obj->layout_inv = 1; 288 289 /*Mark the screen as dirty too to mark that there is something to do on this screen*/ 290 lv_obj_t * scr = lv_obj_get_screen(obj); 291 scr->scr_layout_inv = 1; 292 293 /*Make the display refreshing*/ 294 lv_disp_t * disp = lv_obj_get_disp(scr); 295 if(disp->refr_timer) lv_timer_resume(disp->refr_timer); 296 } 297 298 void lv_obj_update_layout(const lv_obj_t * obj) 299 { 300 static bool mutex = false; 301 if(mutex) { 302 LV_LOG_TRACE("Already running, returning"); 303 return; 304 } 305 mutex = true; 306 307 lv_obj_t * scr = lv_obj_get_screen(obj); 308 309 /*Repeat until there where layout invalidations*/ 310 while(scr->scr_layout_inv) { 311 LV_LOG_INFO("Layout update begin"); 312 scr->scr_layout_inv = 0; 313 layout_update_core(scr); 314 LV_LOG_TRACE("Layout update end"); 315 } 316 317 mutex = false; 318 } 319 320 uint32_t lv_layout_register(lv_layout_update_cb_t cb, void * user_data) 321 { 322 layout_cnt++; 323 LV_GC_ROOT(_lv_layout_list) = lv_mem_realloc(LV_GC_ROOT(_lv_layout_list), layout_cnt * sizeof(lv_layout_dsc_t)); 324 LV_ASSERT_MALLOC(LV_GC_ROOT(_lv_layout_list)); 325 326 LV_GC_ROOT(_lv_layout_list)[layout_cnt - 1].cb = cb; 327 LV_GC_ROOT(_lv_layout_list)[layout_cnt - 1].user_data = user_data; 328 return layout_cnt; /*No -1 to skip 0th index*/ 329 } 330 331 void lv_obj_set_align(lv_obj_t * obj, lv_align_t align) 332 { 333 lv_obj_set_style_align(obj, align, 0); 334 } 335 336 void lv_obj_align(lv_obj_t * obj, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) 337 { 338 lv_obj_set_style_align(obj, align, 0); 339 lv_obj_set_pos(obj, x_ofs, y_ofs); 340 } 341 342 void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) 343 { 344 LV_ASSERT_OBJ(obj, MY_CLASS); 345 346 lv_obj_update_layout(obj); 347 if(base == NULL) base = lv_obj_get_parent(obj); 348 349 LV_ASSERT_OBJ(base, MY_CLASS); 350 351 lv_coord_t x = 0; 352 lv_coord_t y = 0; 353 354 lv_obj_t * parent = lv_obj_get_parent(obj); 355 lv_coord_t pborder = lv_obj_get_style_border_width(parent, LV_PART_MAIN); 356 lv_coord_t pleft = lv_obj_get_style_pad_left(parent, LV_PART_MAIN) + pborder; 357 lv_coord_t ptop = lv_obj_get_style_pad_top(parent, LV_PART_MAIN) + pborder; 358 359 lv_coord_t bborder = lv_obj_get_style_border_width(base, LV_PART_MAIN); 360 lv_coord_t bleft = lv_obj_get_style_pad_left(base, LV_PART_MAIN) + bborder; 361 lv_coord_t btop = lv_obj_get_style_pad_top(base, LV_PART_MAIN) + bborder; 362 363 if(align == LV_ALIGN_DEFAULT) { 364 if(lv_obj_get_style_base_dir(base, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_ALIGN_TOP_RIGHT; 365 else align = LV_ALIGN_TOP_LEFT; 366 } 367 368 switch(align) { 369 case LV_ALIGN_CENTER: 370 x = lv_obj_get_content_width(base) / 2 - lv_obj_get_width(obj) / 2 + bleft; 371 y = lv_obj_get_content_height(base) / 2 - lv_obj_get_height(obj) / 2 + btop; 372 break; 373 case LV_ALIGN_TOP_LEFT: 374 x = bleft; 375 y = btop; 376 break; 377 case LV_ALIGN_TOP_MID: 378 x = lv_obj_get_content_width(base) / 2 - lv_obj_get_width(obj) / 2 + bleft; 379 y = btop; 380 break; 381 382 case LV_ALIGN_TOP_RIGHT: 383 x = lv_obj_get_content_width(base) - lv_obj_get_width(obj) + bleft; 384 y = btop; 385 break; 386 387 case LV_ALIGN_BOTTOM_LEFT: 388 x = bleft; 389 y = lv_obj_get_content_height(base) - lv_obj_get_height(obj) + btop; 390 break; 391 case LV_ALIGN_BOTTOM_MID: 392 x = lv_obj_get_content_width(base) / 2 - lv_obj_get_width(obj) / 2 + bleft; 393 y = lv_obj_get_content_height(base) - lv_obj_get_height(obj) + btop; 394 break; 395 396 case LV_ALIGN_BOTTOM_RIGHT: 397 x = lv_obj_get_content_width(base) - lv_obj_get_width(obj) + bleft; 398 y = lv_obj_get_content_height(base) - lv_obj_get_height(obj) + btop; 399 break; 400 401 case LV_ALIGN_LEFT_MID: 402 x = bleft; 403 y = lv_obj_get_content_height(base) / 2 - lv_obj_get_height(obj) / 2 + btop; 404 break; 405 406 case LV_ALIGN_RIGHT_MID: 407 x = lv_obj_get_content_width(base) - lv_obj_get_width(obj) + bleft; 408 y = lv_obj_get_content_height(base) / 2 - lv_obj_get_height(obj) / 2 + btop; 409 break; 410 411 case LV_ALIGN_OUT_TOP_LEFT: 412 x = 0; 413 y = -lv_obj_get_height(obj); 414 break; 415 416 case LV_ALIGN_OUT_TOP_MID: 417 x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; 418 y = -lv_obj_get_height(obj); 419 break; 420 421 case LV_ALIGN_OUT_TOP_RIGHT: 422 x = lv_obj_get_width(base) - lv_obj_get_width(obj); 423 y = -lv_obj_get_height(obj); 424 break; 425 426 case LV_ALIGN_OUT_BOTTOM_LEFT: 427 x = 0; 428 y = lv_obj_get_height(base); 429 break; 430 431 case LV_ALIGN_OUT_BOTTOM_MID: 432 x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; 433 y = lv_obj_get_height(base); 434 break; 435 436 case LV_ALIGN_OUT_BOTTOM_RIGHT: 437 x = lv_obj_get_width(base) - lv_obj_get_width(obj); 438 y = lv_obj_get_height(base); 439 break; 440 441 case LV_ALIGN_OUT_LEFT_TOP: 442 x = -lv_obj_get_width(obj); 443 y = 0; 444 break; 445 446 case LV_ALIGN_OUT_LEFT_MID: 447 x = -lv_obj_get_width(obj); 448 y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; 449 break; 450 451 case LV_ALIGN_OUT_LEFT_BOTTOM: 452 x = -lv_obj_get_width(obj); 453 y = lv_obj_get_height(base) - lv_obj_get_height(obj); 454 break; 455 456 case LV_ALIGN_OUT_RIGHT_TOP: 457 x = lv_obj_get_width(base); 458 y = 0; 459 break; 460 461 case LV_ALIGN_OUT_RIGHT_MID: 462 x = lv_obj_get_width(base); 463 y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; 464 break; 465 466 case LV_ALIGN_OUT_RIGHT_BOTTOM: 467 x = lv_obj_get_width(base); 468 y = lv_obj_get_height(base) - lv_obj_get_height(obj); 469 break; 470 } 471 472 if(lv_obj_get_style_base_dir(parent, LV_PART_MAIN) == LV_BASE_DIR_RTL) { 473 x += x_ofs + base->coords.x1 - parent->coords.x1 + lv_obj_get_scroll_right(parent) - pleft; 474 } 475 else { 476 x += x_ofs + base->coords.x1 - parent->coords.x1 + lv_obj_get_scroll_left(parent) - pleft; 477 } 478 y += y_ofs + base->coords.y1 - parent->coords.y1 + lv_obj_get_scroll_top(parent) - ptop; 479 lv_obj_set_style_align(obj, LV_ALIGN_TOP_LEFT, 0); 480 lv_obj_set_pos(obj, x, y); 481 482 } 483 484 void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * coords) 485 { 486 LV_ASSERT_OBJ(obj, MY_CLASS); 487 488 lv_area_copy(coords, &obj->coords); 489 } 490 491 lv_coord_t lv_obj_get_x(const lv_obj_t * obj) 492 { 493 LV_ASSERT_OBJ(obj, MY_CLASS); 494 495 lv_coord_t rel_x; 496 lv_obj_t * parent = lv_obj_get_parent(obj); 497 if(parent) { 498 rel_x = obj->coords.x1 - parent->coords.x1; 499 rel_x += lv_obj_get_scroll_x(parent); 500 rel_x -= lv_obj_get_style_pad_left(parent, LV_PART_MAIN); 501 rel_x -= lv_obj_get_style_border_width(parent, LV_PART_MAIN); 502 } 503 else { 504 rel_x = obj->coords.x1; 505 } 506 return rel_x; 507 } 508 509 lv_coord_t lv_obj_get_x2(const lv_obj_t * obj) 510 { 511 LV_ASSERT_OBJ(obj, MY_CLASS); 512 513 return lv_obj_get_x(obj) + lv_obj_get_width(obj); 514 } 515 516 lv_coord_t lv_obj_get_y(const lv_obj_t * obj) 517 { 518 LV_ASSERT_OBJ(obj, MY_CLASS); 519 520 lv_coord_t rel_y; 521 lv_obj_t * parent = lv_obj_get_parent(obj); 522 if(parent) { 523 rel_y = obj->coords.y1 - parent->coords.y1; 524 rel_y += lv_obj_get_scroll_y(parent); 525 rel_y -= lv_obj_get_style_pad_top(parent, LV_PART_MAIN); 526 rel_y -= lv_obj_get_style_border_width(parent, LV_PART_MAIN); 527 } 528 else { 529 rel_y = obj->coords.y1; 530 } 531 return rel_y; 532 } 533 534 lv_coord_t lv_obj_get_y2(const lv_obj_t * obj) 535 { 536 LV_ASSERT_OBJ(obj, MY_CLASS); 537 538 return lv_obj_get_y(obj) + lv_obj_get_height(obj); 539 } 540 541 lv_coord_t lv_obj_get_x_aligned(const lv_obj_t * obj) 542 { 543 return lv_obj_get_style_x(obj, LV_PART_MAIN); 544 } 545 546 lv_coord_t lv_obj_get_y_aligned(const lv_obj_t * obj) 547 { 548 return lv_obj_get_style_y(obj, LV_PART_MAIN); 549 } 550 551 552 lv_coord_t lv_obj_get_width(const lv_obj_t * obj) 553 { 554 LV_ASSERT_OBJ(obj, MY_CLASS); 555 556 return lv_area_get_width(&obj->coords); 557 } 558 559 lv_coord_t lv_obj_get_height(const lv_obj_t * obj) 560 { 561 LV_ASSERT_OBJ(obj, MY_CLASS); 562 563 return lv_area_get_height(&obj->coords); 564 } 565 566 lv_coord_t lv_obj_get_content_width(const lv_obj_t * obj) 567 { 568 LV_ASSERT_OBJ(obj, MY_CLASS); 569 570 lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); 571 lv_coord_t right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN); 572 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 573 574 return lv_obj_get_width(obj) - left - right - 2 * border_width; 575 } 576 577 lv_coord_t lv_obj_get_content_height(const lv_obj_t * obj) 578 { 579 LV_ASSERT_OBJ(obj, MY_CLASS); 580 581 lv_coord_t top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN); 582 lv_coord_t bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); 583 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 584 585 return lv_obj_get_height(obj) - top - bottom - 2 * border_width; 586 } 587 588 void lv_obj_get_content_coords(const lv_obj_t * obj, lv_area_t * area) 589 { 590 LV_ASSERT_OBJ(obj, MY_CLASS); 591 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 592 593 lv_obj_get_coords(obj, area); 594 lv_area_increase(area, -border_width, -border_width); 595 area->x1 += lv_obj_get_style_pad_left(obj, LV_PART_MAIN); 596 area->x2 -= lv_obj_get_style_pad_right(obj, LV_PART_MAIN); 597 area->y1 += lv_obj_get_style_pad_top(obj, LV_PART_MAIN); 598 area->y2 -= lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN); 599 600 } 601 602 lv_coord_t lv_obj_get_self_width(const lv_obj_t * obj) 603 { 604 lv_point_t p = {0, LV_COORD_MIN}; 605 lv_event_send((lv_obj_t *)obj, LV_EVENT_GET_SELF_SIZE, &p); 606 return p.x; 607 } 608 609 lv_coord_t lv_obj_get_self_height(const lv_obj_t * obj) 610 { 611 lv_point_t p = {LV_COORD_MIN, 0}; 612 lv_event_send((lv_obj_t *)obj, LV_EVENT_GET_SELF_SIZE, &p); 613 return p.y; 614 } 615 616 bool lv_obj_refresh_self_size(lv_obj_t * obj) 617 { 618 lv_coord_t w_set = lv_obj_get_style_width(obj, LV_PART_MAIN); 619 lv_coord_t h_set = lv_obj_get_style_height(obj, LV_PART_MAIN); 620 if(w_set != LV_SIZE_CONTENT && h_set != LV_SIZE_CONTENT) return false; 621 622 lv_obj_mark_layout_as_dirty(obj); 623 return true; 624 } 625 626 void lv_obj_refr_pos(lv_obj_t * obj) 627 { 628 if(lv_obj_is_layout_positioned(obj)) return; 629 630 lv_obj_t * parent = lv_obj_get_parent(obj); 631 lv_coord_t x = lv_obj_get_style_x(obj, LV_PART_MAIN); 632 lv_coord_t y = lv_obj_get_style_y(obj, LV_PART_MAIN); 633 634 if(parent == NULL) { 635 lv_obj_move_to(obj, x, y); 636 return; 637 } 638 639 /*Handle percentage value*/ 640 lv_coord_t pw = lv_obj_get_content_width(parent); 641 lv_coord_t ph = lv_obj_get_content_height(parent); 642 if(LV_COORD_IS_PCT(x)) x = (pw * LV_COORD_GET_PCT(x)) / 100; 643 if(LV_COORD_IS_PCT(y)) y = (ph * LV_COORD_GET_PCT(y)) / 100; 644 645 /*Handle percentage value of translate*/ 646 lv_coord_t tr_x = lv_obj_get_style_translate_x(obj, LV_PART_MAIN); 647 lv_coord_t tr_y = lv_obj_get_style_translate_y(obj, LV_PART_MAIN); 648 lv_coord_t w = lv_obj_get_width(obj); 649 lv_coord_t h = lv_obj_get_height(obj); 650 if(LV_COORD_IS_PCT(tr_x)) tr_x = (w * LV_COORD_GET_PCT(tr_x)) / 100; 651 if(LV_COORD_IS_PCT(tr_y)) tr_y = (h * LV_COORD_GET_PCT(tr_y)) / 100; 652 653 /*Use the translation*/ 654 x += tr_x; 655 y += tr_y; 656 657 lv_align_t align = lv_obj_get_style_align(obj, LV_PART_MAIN); 658 659 if(align == LV_ALIGN_DEFAULT) { 660 if(lv_obj_get_style_base_dir(parent, LV_PART_MAIN) == LV_BASE_DIR_RTL) align = LV_ALIGN_TOP_RIGHT; 661 else align = LV_ALIGN_TOP_LEFT; 662 } 663 664 if(align == LV_ALIGN_TOP_LEFT) { 665 lv_obj_move_to(obj, x, y); 666 } 667 else { 668 669 switch(align) { 670 case LV_ALIGN_TOP_MID: 671 x += pw / 2 - w / 2; 672 break; 673 case LV_ALIGN_TOP_RIGHT: 674 x += pw - w; 675 break; 676 case LV_ALIGN_LEFT_MID: 677 y += ph / 2 - h / 2; 678 break; 679 case LV_ALIGN_BOTTOM_LEFT: 680 y += ph - h; 681 break; 682 case LV_ALIGN_BOTTOM_MID: 683 x += pw / 2 - w / 2; 684 y += ph - h; 685 break; 686 case LV_ALIGN_BOTTOM_RIGHT: 687 x += pw - w; 688 y += ph - h; 689 break; 690 case LV_ALIGN_RIGHT_MID: 691 x += pw - w; 692 y += ph / 2 - h / 2; 693 break; 694 case LV_ALIGN_CENTER: 695 x += pw / 2 - w / 2; 696 y += ph / 2 - h / 2; 697 break; 698 default: 699 break; 700 } 701 lv_obj_move_to(obj, x, y); 702 } 703 } 704 705 void lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) 706 { 707 /*Convert x and y to absolute coordinates*/ 708 lv_obj_t * parent = obj->parent; 709 710 if(parent) { 711 lv_coord_t pad_left = lv_obj_get_style_pad_left(parent, LV_PART_MAIN); 712 lv_coord_t pad_top = lv_obj_get_style_pad_top(parent, LV_PART_MAIN); 713 714 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_FLOATING)) { 715 x += pad_left + parent->coords.x1; 716 y += pad_top + parent->coords.y1; 717 } 718 else { 719 x += pad_left + parent->coords.x1 - lv_obj_get_scroll_x(parent); 720 y += pad_top + parent->coords.y1 - lv_obj_get_scroll_y(parent); 721 } 722 723 lv_coord_t border_width = lv_obj_get_style_border_width(parent, LV_PART_MAIN); 724 x += border_width; 725 y += border_width; 726 } 727 728 /*Calculate and set the movement*/ 729 lv_point_t diff; 730 diff.x = x - obj->coords.x1; 731 diff.y = y - obj->coords.y1; 732 733 /*Do nothing if the position is not changed*/ 734 /*It is very important else recursive positioning can 735 *occur without position change*/ 736 if(diff.x == 0 && diff.y == 0) return; 737 738 /*Invalidate the original area*/ 739 lv_obj_invalidate(obj); 740 741 /*Save the original coordinates*/ 742 lv_area_t ori; 743 lv_obj_get_coords(obj, &ori); 744 745 /*Check if the object inside the parent or not*/ 746 lv_area_t parent_fit_area; 747 bool on1 = false; 748 if(parent) { 749 lv_obj_get_content_coords(parent, &parent_fit_area); 750 751 /*If the object is already out of the parent and its position is changes 752 *surely the scrollbars also changes so invalidate them*/ 753 on1 = _lv_area_is_in(&ori, &parent_fit_area, 0); 754 if(!on1) lv_obj_scrollbar_invalidate(parent); 755 } 756 757 obj->coords.x1 += diff.x; 758 obj->coords.y1 += diff.y; 759 obj->coords.x2 += diff.x; 760 obj->coords.y2 += diff.y; 761 762 lv_obj_move_children_by(obj, diff.x, diff.y, false); 763 764 /*Call the ancestor's event handler to the parent too*/ 765 if(parent) lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj); 766 767 /*Invalidate the new area*/ 768 lv_obj_invalidate(obj); 769 770 /*If the object was out of the parent invalidate the new scrollbar area too. 771 *If it wasn't out of the parent but out now, also invalidate the srollbars*/ 772 if(parent) { 773 bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0); 774 if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent); 775 } 776 } 777 778 void lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff, bool ignore_floating) 779 { 780 uint32_t i; 781 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 782 for(i = 0; i < child_cnt; i++) { 783 lv_obj_t * child = obj->spec_attr->children[i]; 784 if(ignore_floating && lv_obj_has_flag(child, LV_OBJ_FLAG_FLOATING)) continue; 785 child->coords.x1 += x_diff; 786 child->coords.y1 += y_diff; 787 child->coords.x2 += x_diff; 788 child->coords.y2 += y_diff; 789 790 lv_obj_move_children_by(child, x_diff, y_diff, false); 791 } 792 } 793 794 795 void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area) 796 { 797 LV_ASSERT_OBJ(obj, MY_CLASS); 798 799 lv_area_t area_tmp; 800 lv_area_copy(&area_tmp, area); 801 bool visible = lv_obj_area_is_visible(obj, &area_tmp); 802 803 if(visible) _lv_inv_area(lv_obj_get_disp(obj), &area_tmp); 804 } 805 806 void lv_obj_invalidate(const lv_obj_t * obj) 807 { 808 LV_ASSERT_OBJ(obj, MY_CLASS); 809 810 /*If the object has overflow visible it can be drawn anywhere on its parent 811 *It needs to be checked recursively*/ 812 while(lv_obj_get_parent(obj) && lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { 813 obj = lv_obj_get_parent(obj); 814 } 815 816 /*Truncate the area to the object*/ 817 lv_area_t obj_coords; 818 lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); 819 lv_area_copy(&obj_coords, &obj->coords); 820 obj_coords.x1 -= ext_size; 821 obj_coords.y1 -= ext_size; 822 obj_coords.x2 += ext_size; 823 obj_coords.y2 += ext_size; 824 825 lv_obj_invalidate_area(obj, &obj_coords); 826 827 } 828 829 bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) 830 { 831 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return false; 832 833 /*Invalidate the object only if it belongs to the current or previous or one of the layers'*/ 834 lv_obj_t * obj_scr = lv_obj_get_screen(obj); 835 lv_disp_t * disp = lv_obj_get_disp(obj_scr); 836 if(obj_scr != lv_disp_get_scr_act(disp) && 837 obj_scr != lv_disp_get_scr_prev(disp) && 838 obj_scr != lv_disp_get_layer_top(disp) && 839 obj_scr != lv_disp_get_layer_sys(disp)) { 840 return false; 841 } 842 843 /*Truncate the area to the object*/ 844 if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { 845 lv_area_t obj_coords; 846 lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); 847 lv_area_copy(&obj_coords, &obj->coords); 848 obj_coords.x1 -= ext_size; 849 obj_coords.y1 -= ext_size; 850 obj_coords.x2 += ext_size; 851 obj_coords.y2 += ext_size; 852 853 /*The area is not on the object*/ 854 if(!_lv_area_intersect(area, area, &obj_coords)) return false; 855 } 856 857 /*Truncate recursively to the parents*/ 858 lv_obj_t * par = lv_obj_get_parent(obj); 859 while(par != NULL) { 860 /*If the parent is hidden then the child is hidden and won't be drawn*/ 861 if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return false; 862 863 /*Truncate to the parent and if no common parts break*/ 864 if(!lv_obj_has_flag(par, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { 865 if(!_lv_area_intersect(area, area, &par->coords)) return false; 866 } 867 868 par = lv_obj_get_parent(par); 869 } 870 871 return true; 872 } 873 874 bool lv_obj_is_visible(const lv_obj_t * obj) 875 { 876 LV_ASSERT_OBJ(obj, MY_CLASS); 877 878 lv_area_t obj_coords; 879 lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); 880 lv_area_copy(&obj_coords, &obj->coords); 881 obj_coords.x1 -= ext_size; 882 obj_coords.y1 -= ext_size; 883 obj_coords.x2 += ext_size; 884 obj_coords.y2 += ext_size; 885 886 return lv_obj_area_is_visible(obj, &obj_coords); 887 888 } 889 890 void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t size) 891 { 892 LV_ASSERT_OBJ(obj, MY_CLASS); 893 894 lv_obj_allocate_spec_attr(obj); 895 obj->spec_attr->ext_click_pad = size; 896 } 897 898 void lv_obj_get_click_area(const lv_obj_t * obj, lv_area_t * area) 899 { 900 lv_area_copy(area, &obj->coords); 901 if(obj->spec_attr) { 902 area->x1 -= obj->spec_attr->ext_click_pad; 903 area->x2 += obj->spec_attr->ext_click_pad; 904 area->y1 -= obj->spec_attr->ext_click_pad; 905 area->y2 += obj->spec_attr->ext_click_pad; 906 } 907 } 908 909 bool lv_obj_hit_test(lv_obj_t * obj, const lv_point_t * point) 910 { 911 if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE)) return false; 912 if(lv_obj_has_state(obj, LV_STATE_DISABLED)) return false; 913 914 lv_area_t a; 915 lv_obj_get_click_area(obj, &a); 916 bool res = _lv_area_is_point_on(&a, point, 0); 917 if(res == false) return false; 918 919 if(lv_obj_has_flag(obj, LV_OBJ_FLAG_ADV_HITTEST)) { 920 lv_hit_test_info_t hit_info; 921 hit_info.point = point; 922 hit_info.res = true; 923 lv_event_send(obj, LV_EVENT_HIT_TEST, &hit_info); 924 return hit_info.res; 925 } 926 927 return res; 928 } 929 930 lv_coord_t lv_clamp_width(lv_coord_t width, lv_coord_t min_width, lv_coord_t max_width, lv_coord_t ref_width) 931 { 932 if(LV_COORD_IS_PCT(min_width)) min_width = (ref_width * LV_COORD_GET_PCT(min_width)) / 100; 933 if(LV_COORD_IS_PCT(max_width)) max_width = (ref_width * LV_COORD_GET_PCT(max_width)) / 100; 934 return LV_CLAMP(min_width, width, max_width); 935 } 936 937 lv_coord_t lv_clamp_height(lv_coord_t height, lv_coord_t min_height, lv_coord_t max_height, lv_coord_t ref_height) 938 { 939 if(LV_COORD_IS_PCT(min_height)) min_height = (ref_height * LV_COORD_GET_PCT(min_height)) / 100; 940 if(LV_COORD_IS_PCT(max_height)) max_height = (ref_height * LV_COORD_GET_PCT(max_height)) / 100; 941 return LV_CLAMP(min_height, height, max_height); 942 } 943 944 945 946 /********************** 947 * STATIC FUNCTIONS 948 **********************/ 949 950 static lv_coord_t calc_content_width(lv_obj_t * obj) 951 { 952 lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF); 953 954 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 955 lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width; 956 lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width; 957 958 lv_coord_t self_w; 959 self_w = lv_obj_get_self_width(obj) + pad_left + pad_right; 960 961 lv_coord_t child_res = LV_COORD_MIN; 962 uint32_t i; 963 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 964 /*With RTL find the left most coordinate*/ 965 if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) { 966 for(i = 0; i < child_cnt; i++) { 967 lv_obj_t * child = obj->spec_attr->children[i]; 968 if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; 969 970 if(!lv_obj_is_layout_positioned(child)) { 971 lv_align_t align = lv_obj_get_style_align(child, 0); 972 switch(align) { 973 case LV_ALIGN_DEFAULT: 974 case LV_ALIGN_TOP_RIGHT: 975 case LV_ALIGN_BOTTOM_RIGHT: 976 case LV_ALIGN_RIGHT_MID: 977 /*Normal right aligns. Other are ignored due to possible circular dependencies*/ 978 child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1); 979 break; 980 default: 981 /* Consider other cases only if x=0 and use the width of the object. 982 * With x!=0 circular dependency could occur. */ 983 if(lv_obj_get_style_x(child, 0) == 0) { 984 child_res = LV_MAX(child_res, lv_area_get_width(&child->coords) + pad_right); 985 } 986 } 987 } 988 else { 989 child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1); 990 } 991 } 992 if(child_res != LV_COORD_MIN) { 993 child_res += pad_left; 994 } 995 } 996 /*Else find the right most coordinate*/ 997 else { 998 for(i = 0; i < child_cnt; i++) { 999 lv_obj_t * child = obj->spec_attr->children[i]; 1000 if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; 1001 1002 if(!lv_obj_is_layout_positioned(child)) { 1003 lv_align_t align = lv_obj_get_style_align(child, 0); 1004 switch(align) { 1005 case LV_ALIGN_DEFAULT: 1006 case LV_ALIGN_TOP_LEFT: 1007 case LV_ALIGN_BOTTOM_LEFT: 1008 case LV_ALIGN_LEFT_MID: 1009 /*Normal left aligns.*/ 1010 child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1); 1011 break; 1012 default: 1013 /* Consider other cases only if x=0 and use the width of the object. 1014 * With x!=0 circular dependency could occur. */ 1015 if(lv_obj_get_style_y(child, 0) == 0) { 1016 child_res = LV_MAX(child_res, lv_area_get_width(&child->coords) + pad_left); 1017 } 1018 } 1019 } 1020 else { 1021 child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1); 1022 } 1023 } 1024 1025 if(child_res != LV_COORD_MIN) { 1026 child_res += pad_right; 1027 } 1028 } 1029 1030 if(child_res == LV_COORD_MIN) return self_w; 1031 else return LV_MAX(child_res, self_w); 1032 } 1033 1034 static lv_coord_t calc_content_height(lv_obj_t * obj) 1035 { 1036 lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF); 1037 1038 lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); 1039 lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width; 1040 lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width; 1041 1042 lv_coord_t self_h; 1043 self_h = lv_obj_get_self_height(obj) + pad_top + pad_bottom; 1044 1045 lv_coord_t child_res = LV_COORD_MIN; 1046 uint32_t i; 1047 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 1048 for(i = 0; i < child_cnt; i++) { 1049 lv_obj_t * child = obj->spec_attr->children[i]; 1050 if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; 1051 1052 1053 if(!lv_obj_is_layout_positioned(child)) { 1054 lv_align_t align = lv_obj_get_style_align(child, 0); 1055 switch(align) { 1056 case LV_ALIGN_DEFAULT: 1057 case LV_ALIGN_TOP_RIGHT: 1058 case LV_ALIGN_TOP_MID: 1059 case LV_ALIGN_TOP_LEFT: 1060 /*Normal top aligns. */ 1061 child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1); 1062 break; 1063 default: 1064 /* Consider other cases only if y=0 and use the height of the object. 1065 * With y!=0 circular dependency could occur. */ 1066 if(lv_obj_get_style_y(child, 0) == 0) { 1067 child_res = LV_MAX(child_res, lv_area_get_height(&child->coords) + pad_top); 1068 } 1069 break; 1070 } 1071 } 1072 else { 1073 child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1); 1074 } 1075 } 1076 1077 if(child_res != LV_COORD_MIN) { 1078 child_res += pad_bottom; 1079 return LV_MAX(child_res, self_h); 1080 } 1081 else { 1082 return self_h; 1083 } 1084 1085 } 1086 1087 static void layout_update_core(lv_obj_t * obj) 1088 { 1089 uint32_t i; 1090 uint32_t child_cnt = lv_obj_get_child_cnt(obj); 1091 for(i = 0; i < child_cnt; i++) { 1092 lv_obj_t * child = obj->spec_attr->children[i]; 1093 layout_update_core(child); 1094 } 1095 1096 if(obj->layout_inv == 0) return; 1097 1098 obj->layout_inv = 0; 1099 1100 lv_obj_refr_size(obj); 1101 lv_obj_refr_pos(obj); 1102 1103 if(child_cnt > 0) { 1104 uint32_t layout_id = lv_obj_get_style_layout(obj, LV_PART_MAIN); 1105 if(layout_id > 0 && layout_id <= layout_cnt) { 1106 void * user_data = LV_GC_ROOT(_lv_layout_list)[layout_id - 1].user_data; 1107 LV_GC_ROOT(_lv_layout_list)[layout_id - 1].cb(obj, user_data); 1108 } 1109 } 1110 }