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 }