From 2e991f31be10c31b28a8b8629d85e7a84ced2487 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 1 Jul 2021 11:52:39 +0200 Subject: [PATCH] widget: make Icon honour its constraints This is a breaking change as Icon.Layout no longer requests a size. Before: sz := unit.Dp(20) ic.Layout(gtx, sz) After: sz := gtx.Metric.Px(unit.Dp(20)) gtx.Constraints.Min = image.Pt(sz, 0) ic.Layout(gtx) Fixes gio#240 Signed-off-by: pierre --- widget/icon.go | 21 +++++++++++++--- widget/icon_test.go | 48 ++++++++++++++++++++++++++++++++++-- widget/material/button.go | 3 ++- widget/material/checkable.go | 3 ++- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/widget/icon.go b/widget/icon.go index 4e6350d8..6c01b184 100644 --- a/widget/icon.go +++ b/widget/icon.go @@ -7,12 +7,14 @@ import ( "image/color" "image/draw" - "golang.org/x/exp/shiny/iconvg" - "gioui.org/internal/f32color" "gioui.org/layout" + "gioui.org/op" + "gioui.org/op/clip" "gioui.org/op/paint" "gioui.org/unit" + + "golang.org/x/exp/shiny/iconvg" ) type Icon struct { @@ -24,6 +26,8 @@ type Icon struct { imgColor color.NRGBA } +var defaultIconSize = unit.Dp(24) + // NewIcon returns a new Icon from IconVG data. func NewIcon(data []byte) (*Icon, error) { _, err := iconvg.DecodeMetadata(data) @@ -33,8 +37,17 @@ func NewIcon(data []byte) (*Icon, error) { return &Icon{src: data, Color: color.NRGBA{A: 0xff}}, nil } -func (ic *Icon) Layout(gtx layout.Context, sz unit.Value) layout.Dimensions { - ico := ic.image(gtx.Px(sz)) +// Layout displays the icon with its size set to the X minimum constraint. +func (ic *Icon) Layout(gtx layout.Context) layout.Dimensions { + sz := gtx.Constraints.Min.X + if sz == 0 { + sz = gtx.Metric.Px(defaultIconSize) + } + size := gtx.Constraints.Constrain(image.Pt(sz, sz)) + defer op.Save(gtx.Ops).Load() + clip.Rect{Max: size}.Add(gtx.Ops) + + ico := ic.image(size.X) ico.Add(gtx.Ops) paint.PaintOp{}.Add(gtx.Ops) return layout.Dimensions{ diff --git a/widget/icon_test.go b/widget/icon_test.go index dd927f7a..6bc56ba4 100644 --- a/widget/icon_test.go +++ b/widget/icon_test.go @@ -9,7 +9,7 @@ import ( "gioui.org/layout" "gioui.org/op" - "gioui.org/unit" + "golang.org/x/exp/shiny/materialdesign/icons" ) @@ -26,5 +26,49 @@ func TestIcon_Alpha(t *testing.T) { Constraints: layout.Exact(image.Pt(100, 100)), } - _ = icon.Layout(gtx, unit.Sp(18)) + _ = icon.Layout(gtx) +} + +// TestWidgetConstraints tests that widgets returns dimensions within their constraints. +func TestWidgetConstraints(t *testing.T) { + _cs := func(v ...layout.Constraints) []layout.Constraints { return v } + for _, tc := range []struct { + label string + widget layout.Widget + constraints []layout.Constraints + }{ + { + label: "Icon", + widget: func(gtx layout.Context) layout.Dimensions { + ic, _ := NewIcon(icons.ToggleCheckBox) + return ic.Layout(gtx) + }, + constraints: _cs( + layout.Constraints{ + Min: image.Pt(20, 0), + Max: image.Pt(100, 100), + }, + layout.Constraints{ + Max: image.Pt(100, 100), + }, + ), + }, + } { + t.Run(tc.label, func(t *testing.T) { + for _, cs := range tc.constraints { + gtx := layout.Context{ + Constraints: cs, + Ops: new(op.Ops), + } + dims := tc.widget(gtx) + csr := image.Rectangle{ + Min: cs.Min, + Max: cs.Max, + } + if !dims.Size.In(csr) { + t.Errorf("dims size %v not within constraints %v", dims.Size, csr) + } + } + }) + } } diff --git a/widget/material/button.go b/widget/material/button.go index 86752448..7228238b 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -170,7 +170,8 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions { size := gtx.Px(b.Size) if b.Icon != nil { b.Icon.Color = b.Color - b.Icon.Layout(gtx, unit.Px(float32(size))) + gtx.Constraints.Min = image.Point{X: size} + b.Icon.Layout(gtx) } return layout.Dimensions{ Size: image.Point{X: size, Y: size}, diff --git a/widget/material/checkable.go b/widget/material/checkable.go index 38c0563f..08935a33 100644 --- a/widget/material/checkable.go +++ b/widget/material/checkable.go @@ -67,7 +67,8 @@ func (c *checkable) layout(gtx layout.Context, checked, hovered bool) layout.Dim if gtx.Queue == nil { icon.Color = f32color.Disabled(icon.Color) } - icon.Layout(gtx, unit.Px(float32(size))) + gtx.Constraints.Min = image.Point{X: size} + icon.Layout(gtx) return layout.Dimensions{ Size: image.Point{X: size, Y: size}, }