From 81d078efc48764494ee56f47339a6cf2d2838152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 24 Oct 2026 12:35:56 +0200 Subject: [PATCH] UI: Fix ScrollView's handling of its child's margins The child was measured inside its margins, then had them subtracted from its bounds again, and the leading margin along the scroll direction was never applied, so the end of the content couldn't be scrolled to. Also include the margins when wrapping the content, and page horizontally by the width rather than the x position. Co-Authored-By: Claude Opus 5.5 (1M context) --- Common/UI/ScrollView.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Common/UI/ScrollView.cpp b/Common/UI/ScrollView.cpp index b6e6d24b48..5ace3d90b7 100644 --- a/Common/UI/ScrollView.cpp +++ b/Common/UI/ScrollView.cpp @@ -63,18 +63,18 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver v.type = UNSPECIFIED; } views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v); - MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight(), vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight() + margins.vert(), vert, &measuredHeight_); if (layoutParams_->width == WRAP_CONTENT) - MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth(), horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth() + margins.horiz(), horiz, &measuredWidth_); } else { MeasureSpec h = MeasureSpec(AT_MOST, measuredWidth_ - margins.horiz()); if (measuredWidth_ == 0.0f && (horiz.type == UNSPECIFIED || layoutParams_->width == WRAP_CONTENT)) { h.type = UNSPECIFIED; } views_[0]->Measure(dc, h, MeasureSpec(UNSPECIFIED, measuredHeight_)); - MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth(), horiz, &measuredWidth_); + MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth() + margins.horiz(), horiz, &measuredWidth_); if (layoutParams_->height == WRAP_CONTENT) - MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight(), vert, &measuredHeight_); + MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight() + margins.vert(), vert, &measuredHeight_); } // The below seems misguided and leads to wrong sized scrollviews. Need to investigate if it's needed somewhere... @@ -96,11 +96,11 @@ void ScrollView::Layout() { return; Bounds scrolled; - // Respect margins + // The child was measured inside its margins. const Margins margins = GetMargins(); - scrolled.w = views_[0]->GetMeasuredWidth() - margins.horiz(); - scrolled.h = views_[0]->GetMeasuredHeight() - margins.vert(); + scrolled.w = views_[0]->GetMeasuredWidth(); + scrolled.h = views_[0]->GetMeasuredHeight(); layoutScrollPos_ = ClampedScrollPos(scrollPos_); @@ -111,7 +111,7 @@ void ScrollView::Layout() { scrollPos_ = *rememberPos_; lastViewSize_ = scrolled.w; } - scrolled.x = bounds_.x - layoutScrollPos_; + scrolled.x = bounds_.x + margins.left - layoutScrollPos_; scrolled.y = bounds_.y + margins.top; break; case ORIENT_VERTICAL: @@ -121,7 +121,7 @@ void ScrollView::Layout() { lastViewSize_ = scrolled.h; } scrolled.x = bounds_.x + margins.left; - scrolled.y = bounds_.y - layoutScrollPos_; + scrolled.y = bounds_.y + margins.top - layoutScrollPos_; break; } @@ -259,7 +259,9 @@ float ScrollView::ChildSize() const { // Avoid division by zero. This shouldn't happen, anyway. return 1.0f; } - return std::max(0.01f, views_[0]->GetBounds().GetSize(orientation_) + extraSpace); + const Margins margins = GetMargins(); + const float marginSize = orientation_ == ORIENT_VERTICAL ? margins.vert() : margins.horiz(); + return std::max(0.01f, views_[0]->GetBounds().GetSize(orientation_) + marginSize + extraSpace); } float ScrollView::ScrollMax() const { @@ -422,7 +424,7 @@ NeighborResult ScrollView::FindScrollNeighbor(View *view, const Point2D &target, if (orientation_ == ORIENT_VERTICAL) targetPos.y += mult * bounds_.h; else - targetPos.x += mult * bounds_.x; + targetPos.x += mult * bounds_.w; // Okay, which subview is closest to that? best = vg->FindScrollNeighbor(view, targetPos, direction, best);