diff --git a/src/core/lv_obj_pos.c b/src/core/lv_obj_pos.c index 7e81215d42..a3f24d5d13 100644 --- a/src/core/lv_obj_pos.c +++ b/src/core/lv_obj_pos.c @@ -23,7 +23,8 @@ /********************** * STATIC PROTOTYPES **********************/ -static void calc_auto_size(lv_obj_t * obj, lv_coord_t * w_out, lv_coord_t * h_out); +static lv_coord_t calc_content_width(lv_obj_t * obj); +static lv_coord_t calc_content_height(lv_obj_t * obj); static void layout_update_core(lv_obj_t * obj); /********************** @@ -91,53 +92,69 @@ bool lv_obj_refr_size(lv_obj_t * obj) lv_obj_t * parent = lv_obj_get_parent(obj); if(parent == NULL) return false; - lv_coord_t w; lv_coord_t sl_ori = lv_obj_get_scroll_left(obj); - bool w_content = false; + bool w_is_content = false; + bool w_is_pct = false; + + lv_coord_t w; if(obj->w_layout) { w = lv_obj_get_width(obj); } else { w = lv_obj_get_style_width(obj, LV_PART_MAIN); - w_content = w == LV_SIZE_CONTENT ? true : false; - - /*Be sure the object is not scrolled when it has auto size*/ - if(w_content) { - lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF); - calc_auto_size(obj, &w, NULL); - } - - /*Calculate the sizes in percentage*/ - bool pct_w = LV_COORD_IS_PCT(w) ? true : false; - + w_is_content = w == LV_SIZE_CONTENT ? true : false; + w_is_pct = LV_COORD_IS_PCT(w) ? true : false; lv_coord_t parent_w = lv_obj_get_content_width(parent); - if(pct_w) w = (LV_COORD_GET_PCT(w) * parent_w) / 100; + + if(w_is_content) { + w = calc_content_width(obj); + } + else if(w_is_pct) { + /*If parent has content size and the child has pct size + *a circular dependency will occur. To solve it keep child size at zero */ + if(parent->w_layout == 0 && lv_obj_get_style_width(parent, 0) == LV_SIZE_CONTENT) { + lv_coord_t border_w = lv_obj_get_style_border_width(obj, 0); + w = lv_obj_get_style_pad_left(obj, 0) + border_w; + w += lv_obj_get_style_pad_right(obj, 0) + border_w; + } + else { + w = (LV_COORD_GET_PCT(w) * parent_w) / 100; + } + } lv_coord_t minw = lv_obj_get_style_min_width(obj, LV_PART_MAIN); lv_coord_t maxw = lv_obj_get_style_max_width(obj, LV_PART_MAIN); w = lv_clamp_width(w, minw, maxw, parent_w); } - lv_coord_t h; lv_coord_t st_ori = lv_obj_get_scroll_top(obj); - bool h_content = false; + lv_coord_t h; + bool h_is_content = false; + bool h_is_pct = false; if(obj->h_layout) { h = lv_obj_get_height(obj); } else { h = lv_obj_get_style_height(obj, LV_PART_MAIN); - h_content = h == LV_SIZE_CONTENT ? true : false; - - /*Be sure the object is not scrolled when it has auto size*/ - if(h_content) { - lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF); - calc_auto_size(obj, NULL, &h); - } - - /*Calculate the sizes in percentage*/ - bool pct_h = LV_COORD_IS_PCT(h) ? true : false; + h_is_content = h == LV_SIZE_CONTENT ? true : false; + h_is_pct = LV_COORD_IS_PCT(h) ? true : false; lv_coord_t parent_h = lv_obj_get_content_height(parent); - if(pct_h) h = (LV_COORD_GET_PCT(h) * parent_h) / 100; + + if(h_is_content) { + h = calc_content_height(obj); + } + else if(h_is_pct) { + /*If parent has content size and the child has pct size + *a circular dependency will occur. To solve it keep child size at zero */ + if(parent->h_layout == 0 && lv_obj_get_style_height(parent, 0) == LV_SIZE_CONTENT) { + lv_coord_t border_w = lv_obj_get_style_border_width(obj, 0); + h = lv_obj_get_style_pad_top(obj, 0) + border_w; + h += lv_obj_get_style_pad_bottom(obj, 0) + border_w; + } + else { + h = (LV_COORD_GET_PCT(h) * parent_h) / 100; + } + } lv_coord_t minh = lv_obj_get_style_min_height(obj, LV_PART_MAIN); lv_coord_t maxh = lv_obj_get_style_max_height(obj, LV_PART_MAIN); @@ -145,7 +162,7 @@ bool lv_obj_refr_size(lv_obj_t * obj) } /*calc_auto_size set the scroll x/y to 0 so revert the original value*/ - if(w_content || h_content) { + if(w_is_content || h_is_content) { lv_obj_scroll_to(obj, sl_ori, st_ori, LV_ANIM_OFF); } @@ -195,10 +212,6 @@ bool lv_obj_refr_size(lv_obj_t * obj) bool on2 = _lv_area_is_in(&obj->coords, &parent_fit_area, 0); if(on1 || (!on1 && on2)) lv_obj_scrollbar_invalidate(parent); - - - - return true; } @@ -917,27 +930,118 @@ lv_coord_t lv_clamp_height(lv_coord_t height, lv_coord_t min_height, lv_coord_t * STATIC FUNCTIONS **********************/ -/** - * Calculate the "auto size". It's `auto_size = max(children_size, self_size)` - * @param obj pointer to an object - * @param w_out store the width here. NULL to not calculate width - * @param h_out store the height here. NULL to not calculate height - */ -static void calc_auto_size(lv_obj_t * obj, lv_coord_t * w_out, lv_coord_t * h_out) +static lv_coord_t calc_content_width(lv_obj_t * obj) { - if(!w_out && !h_out) return; - /*Get the bounding box of the children*/ - if(w_out) { - lv_coord_t scroll_right = lv_obj_get_scroll_right(obj); - lv_coord_t scroll_left = lv_obj_get_scroll_left(obj); - *w_out = lv_obj_get_width(obj) + scroll_right + scroll_left; + lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF); + + lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); + lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN) + border_width; + lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width; + + lv_coord_t self_w; + self_w = lv_obj_get_self_width(obj) + pad_left + pad_right; + + lv_coord_t child_res = LV_COORD_MIN; + uint32_t i; + uint32_t child_cnt = lv_obj_get_child_cnt(obj); + /*With RTL find the left most coordinate*/ + if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) { + for(i = 0; i < child_cnt; i++) { + lv_obj_t * child = obj->spec_attr->children[i]; + if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; + + if(!lv_obj_is_layout_positioned(child)) { + lv_align_t align = lv_obj_get_style_align(child, 0); + switch(align) { + case LV_ALIGN_DEFAULT: + case LV_ALIGN_TOP_RIGHT: + case LV_ALIGN_BOTTOM_RIGHT: + case LV_ALIGN_RIGHT_MID: + /*Normal right aligns. Other are ignored due to possible circular dependencies*/ + child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1); + break; + } + } else { + child_res = LV_MAX(child_res, obj->coords.x2 - child->coords.x1 + 1); + } + } + if(child_res != LV_COORD_MIN) { + child_res += pad_left; + } + } + /*Else find the right most coordinate*/ + else { + for(i = 0; i < child_cnt; i++) { + lv_obj_t * child = obj->spec_attr->children[i]; + if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; + + if(!lv_obj_is_layout_positioned(child)) { + lv_align_t align = lv_obj_get_style_align(child, 0); + switch(align) { + case LV_ALIGN_DEFAULT: + case LV_ALIGN_TOP_LEFT: + case LV_ALIGN_BOTTOM_LEFT: + case LV_ALIGN_LEFT_MID: + /*Normal left aligns. Other are ignored due to possible circular dependencies*/ + child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1); + break; + } + } else { + child_res = LV_MAX(child_res, child->coords.x2 - obj->coords.x1 + 1); + } + } + + if(child_res != LV_COORD_MIN) { + child_res += pad_right; + } } - if(h_out) { - lv_coord_t scroll_bottom = lv_obj_get_scroll_bottom(obj); - lv_coord_t scroll_top = lv_obj_get_scroll_top(obj); - *h_out = lv_obj_get_height(obj) + scroll_bottom + scroll_top; + if(child_res == LV_COORD_MIN) return self_w; + else return LV_MAX(child_res, self_w); +} + +static lv_coord_t calc_content_height(lv_obj_t * obj) +{ + lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF); + + lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); + lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN) + border_width; + lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN) + border_width; + + lv_coord_t self_h; + self_h = lv_obj_get_self_height(obj) + pad_top + pad_bottom; + + lv_coord_t child_res = LV_COORD_MIN; + uint32_t i; + uint32_t child_cnt = lv_obj_get_child_cnt(obj); + for(i = 0; i < child_cnt; i++) { + lv_obj_t * child = obj->spec_attr->children[i]; + if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue; + + + if(!lv_obj_is_layout_positioned(child)) { + lv_align_t align = lv_obj_get_style_align(child, 0); + switch(align) { + case LV_ALIGN_DEFAULT: + case LV_ALIGN_TOP_RIGHT: + case LV_ALIGN_TOP_MID: + case LV_ALIGN_TOP_LEFT: + /*Normal top aligns. Other are ignored due to possible circular dependencies*/ + child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1); + break; + } + } else { + child_res = LV_MAX(child_res, child->coords.y2 - obj->coords.y1 + 1); + } } + + if(child_res != LV_COORD_MIN) { + child_res += pad_bottom; + return LV_MAX(child_res, self_h); + } else { + return self_h; + } + } static void layout_update_core(lv_obj_t * obj)