From b3918ce40fc3b125dbb58e210dace715e53096b3 Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Tue, 13 Jul 2021 09:28:38 -0400 Subject: [PATCH] widget/material: ensure List accounts for scrollbar size in dims This commit ensures that the dimensions returned by material.List include the size of the scrollbar when the scrollbar is set to the Occupy AnchorStrategy. Signed-off-by: Chris Waldon --- widget/material/list.go | 12 +++++-- widget/material/list_test.go | 66 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 widget/material/list_test.go diff --git a/widget/material/list.go b/widget/material/list.go index 75183a46..220671e4 100644 --- a/widget/material/list.go +++ b/widget/material/list.go @@ -247,9 +247,10 @@ func List(th *Theme, state *widget.List) ListStyle { func (l ListStyle) Layout(gtx layout.Context, length int, w layout.ListElement) layout.Dimensions { originalConstraints := gtx.Constraints + // Determine how much space the scrollbar occupies. + barWidth := gtx.Px(l.Width(gtx.Metric)) + if l.AnchorStrategy == Occupy { - // Determine how much space the scrollbar occupies. - barWidth := gtx.Px(l.Width(gtx.Metric)) // Reserve space for the scrollbar using the gtx constraints. max := l.state.Axis.Convert(gtx.Constraints.Max) @@ -290,5 +291,12 @@ func (l ListStyle) Layout(gtx layout.Context, length int, w layout.ListElement) l.state.List.Position.BeforeEnd = true } + if l.AnchorStrategy == Occupy { + // Increase the width to account for the space occupied by the scrollbar. + cross := l.state.Axis.Convert(listDims.Size) + cross.Y += barWidth + listDims.Size = l.state.Axis.Convert(cross) + } + return listDims } diff --git a/widget/material/list_test.go b/widget/material/list_test.go new file mode 100644 index 00000000..2a5866b4 --- /dev/null +++ b/widget/material/list_test.go @@ -0,0 +1,66 @@ +package material_test + +import ( + "image" + "testing" + "time" + + "gioui.org/font/gofont" + "gioui.org/io/system" + "gioui.org/layout" + "gioui.org/op" + "gioui.org/unit" + "gioui.org/widget" + "gioui.org/widget/material" +) + +func TestListAnchorStrategies(t *testing.T) { + var ops op.Ops + gtx := layout.NewContext(&ops, system.FrameEvent{ + Metric: unit.Metric{ + PxPerDp: 1, + PxPerSp: 1, + }, + Now: time.Now(), + Size: image.Point{ + X: 500, + Y: 500, + }, + }) + + var spaceConstraints layout.Constraints + space := func(gtx layout.Context, index int) layout.Dimensions { + spaceConstraints = gtx.Constraints + return layout.Dimensions{Size: image.Point{ + X: gtx.Constraints.Max.X, + Y: gtx.Px(unit.Dp(20)), + }} + } + + var list widget.List + list.Axis = layout.Vertical + elements := 100 + th := material.NewTheme(gofont.Collection()) + materialList := material.List(th, &list) + indicatorWidth := gtx.Px(materialList.Width(gtx.Metric)) + + materialList.AnchorStrategy = material.Occupy + occupyDims := materialList.Layout(gtx, elements, space) + occupyConstraints := spaceConstraints + + materialList.AnchorStrategy = material.Overlay + overlayDims := materialList.Layout(gtx, elements, space) + overlayConstraints := spaceConstraints + + // Both anchor strategies should use all space available if their elements do. + if occupyDims != overlayDims { + t.Errorf("expected occupy dims (%v) to be equal to overlay dims (%v)", occupyDims, overlayDims) + } + // The overlay strategy should not reserve any space for the scroll indicator, + // so the constraints that it presents to its elements should be larger than + // those presented by the occupy strategy. + if overlayConstraints.Max.X != occupyConstraints.Max.X+indicatorWidth { + t.Errorf("overlay max width (%d) != occupy max width (%d) + indicator width (%d)", + overlayConstraints.Max.X, occupyConstraints.Max.X, indicatorWidth) + } +}