From e30c8f7141eed662dc4d5a33a05828eb4e994a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 24 Oct 2026 12:24:21 +0200 Subject: [PATCH] UI: Give LinearLayout a working padding setting LinearLayout had a public padding member that only DisplayLayoutScreen set. Make it private with a setter, and fix the measuring: the vertical retry used the horizontal padding, the AT_MOST retries and the weighted children ignored it, and growing to fit weighted children counted it twice. Co-Authored-By: Claude Opus 5.5 (1M context) --- Common/UI/ViewGroup.cpp | 46 +++++++++++++++++++------------------- Common/UI/ViewGroup.h | 6 ++++- UI/DisplayLayoutScreen.cpp | 4 ++-- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 5b90b03333..eec25e53da 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -621,19 +621,19 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec v = vert; if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f) v = MeasureSpec(AT_MOST, measuredHeight_); - view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert() - (float)padding.vert()); - if (horiz.type == AT_MOST && view->GetMeasuredWidth() + margins.horiz() + padding.horiz() > horiz.size - weightZeroSum) { + view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert() - (float)padding_.vert()); + if (horiz.type == AT_MOST && view->GetMeasuredWidth() + margins.horiz() + padding_.horiz() > horiz.size - weightZeroSum) { // Try again, this time with AT_MOST. - view->Measure(dc, horiz, v - (float)margins.vert() - (float)padding.vert()); + view->Measure(dc, horiz - (float)padding_.horiz(), v - (float)margins.vert() - (float)padding_.vert()); } } else if (orientation_ == ORIENT_VERTICAL) { MeasureSpec h = horiz; if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f) h = MeasureSpec(AT_MOST, measuredWidth_); - view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_)); - if (vert.type == AT_MOST && view->GetMeasuredHeight() + margins.vert() + padding.horiz() > vert.size - weightZeroSum) { + view->Measure(dc, h - (float)margins.horiz() - (float)padding_.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_)); + if (vert.type == AT_MOST && view->GetMeasuredHeight() + margins.vert() + padding_.vert() > vert.size - weightZeroSum) { // Try again, this time with AT_MOST. - view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), vert); + view->Measure(dc, h - (float)margins.horiz() - (float)padding_.horiz(), vert - (float)padding_.vert()); } } @@ -657,12 +657,12 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } } - weightZeroSum += spacing_ * (numVisible - 1); // +(orientation_ == ORIENT_HORIZONTAL) ? padding.horiz() : padding.vert(); + weightZeroSum += spacing_ * (numVisible - 1); // Alright, got the sum. Let's take the remaining space after the fixed-size views, // and distribute among the weighted ones. if (orientation_ == ORIENT_HORIZONTAL) { - MeasureBySpec(layoutParams_->width, weightZeroSum + padding.horiz(), horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, weightZeroSum + padding_.horiz(), horiz, &measuredWidth_); // If we've got stretch, allow growing to fill the parent. float allowedWidth = measuredWidth_; @@ -670,7 +670,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v allowedWidth = horiz.size; } - float usedWidth = 0.0f + padding.horiz(); + float usedWidth = 0.0f; // Redistribute the stretchy ones! and remeasure the children! for (View *view : views_) { @@ -688,7 +688,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec v = vert; if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f) v = MeasureSpec(AT_MOST, measuredHeight_); - float unit = (allowedWidth - weightZeroSum) / weightSum; + float unit = (allowedWidth - padding_.horiz() - weightZeroSum) / weightSum; if (weightSum == 0.0f) { // We must have gotten an inf. unit = 1.0f; @@ -697,7 +697,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (horiz.type == EXACTLY) { h.type = EXACTLY; } - view->Measure(dc, h, v - (float)margins.vert() - (float)padding.vert()); + view->Measure(dc, h, v - (float)margins.vert() - (float)padding_.vert()); usedWidth += view->GetMeasuredWidth(); maxOther = std::max(maxOther, view->GetMeasuredHeight() + margins.vert()); } @@ -708,9 +708,9 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } // Measure here in case maxOther moved (can happen due to word wrap.) - MeasureBySpec(layoutParams_->height, maxOther + padding.vert(), vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, maxOther + padding_.vert(), vert, &measuredHeight_); } else { - MeasureBySpec(layoutParams_->height, weightZeroSum + padding.vert(), vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, weightZeroSum + padding_.vert(), vert, &measuredHeight_); // If we've got stretch, allow growing to fill the parent. float allowedHeight = measuredHeight_; @@ -718,7 +718,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v allowedHeight = vert.size; } - float usedHeight = 0.0f + padding.vert(); + float usedHeight = 0.0f; // Redistribute the stretchy ones! and remeasure the children! for (View *view : views_) { @@ -736,7 +736,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec h = horiz; if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f) h = MeasureSpec(AT_MOST, measuredWidth_); - float unit = (allowedHeight - weightZeroSum) / weightSum; + float unit = (allowedHeight - padding_.vert() - weightZeroSum) / weightSum; if (weightSum == 0.0f) { // We must have gotten an inf. unit = 1.0f; @@ -745,7 +745,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v if (vert.type == EXACTLY) { v.type = EXACTLY; } - view->Measure(dc, h - (float)margins.horiz() - (float)padding.horiz(), v); + view->Measure(dc, h - (float)margins.horiz() - (float)padding_.horiz(), v); usedHeight += view->GetMeasuredHeight(); maxOther = std::max(maxOther, view->GetMeasuredWidth() + margins.horiz()); } @@ -756,7 +756,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } // Measure here in case maxOther moved (can happen due to word wrap.) - MeasureBySpec(layoutParams_->width, maxOther + padding.horiz(), horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, maxOther + padding_.horiz(), horiz, &measuredWidth_); } } @@ -768,13 +768,13 @@ void LinearLayout::Layout() { float pos; if (orientation_ == ORIENT_HORIZONTAL) { - pos = bounds.x + padding.left; - itemBounds.y = bounds.y + padding.top; - itemBounds.h = measuredHeight_ - padding.vert(); + pos = bounds.x + padding_.left; + itemBounds.y = bounds.y + padding_.top; + itemBounds.h = measuredHeight_ - padding_.vert(); } else { - pos = bounds.y + padding.top; - itemBounds.x = bounds.x + padding.left; - itemBounds.w = measuredWidth_ - padding.horiz(); + pos = bounds.y + padding_.top; + itemBounds.x = bounds.x + padding_.left; + itemBounds.w = measuredWidth_ - padding_.horiz(); } for (size_t i = 0; i < views_.size(); i++) { diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index fa4d243145..271240ce64 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -227,17 +227,21 @@ public: void SetSpacing(float spacing) { spacing_ = spacing; } + // Space between the layout's edges and its children, on top of the children's own margins. + void SetPadding(const Margins &padding) { + padding_ = padding; + } // Applies rounding to the corners of the child views, based on their position in the layout and the orientation. Masked by the outerCorners. void ApplyRoundCorners(RoundCorners outerCorners = RoundCorners::All); std::string DescribeLog() const override { return (orientation_ == ORIENT_HORIZONTAL ? "LinearLayoutHoriz: " : "LinearLayoutVert: ") + View::DescribeLog(); } - Margins padding; protected: Orientation orientation_; private: Margins defaultMargins_; + Margins padding_; float spacing_ = 10.0f; }; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index a36f0da446..3da84d8aef 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -245,7 +245,7 @@ void DisplayLayoutScreen::CreateViews() { if (!portrait) { ScrollView *leftScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(420.0f, FILL_PARENT, 0.f, 0.f, NONE, 0.f)); leftColumn = new LinearLayout(ORIENT_VERTICAL); - leftColumn->padding.SetAll(8.0f); + leftColumn->SetPadding(Margins(8)); leftScrollView->Add(leftColumn); leftScrollView->SetClickableBackground(true); root_->Add(leftScrollView); @@ -253,7 +253,7 @@ void DisplayLayoutScreen::CreateViews() { ScrollView *rightScrollView = new ScrollView(ORIENT_VERTICAL, new AnchorLayoutParams(300.0f, FILL_PARENT, NONE, 0.f, 0.f, 0.f)); LinearLayout *rightColumn = new LinearLayout(ORIENT_VERTICAL); - rightColumn->padding.SetAll(8.0f); + rightColumn->SetPadding(Margins(8)); rightColumn->SetSpacing(0.0f); rightScrollView->Add(rightColumn); rightScrollView->SetClickableBackground(true);