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 <pierre.curto@gmail.com>
This commit is contained in:
pierre
2021-07-01 11:52:39 +02:00
committed by Elias Naur
parent cf778ecd06
commit 2e991f31be
4 changed files with 67 additions and 8 deletions
+17 -4
View File
@@ -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{
+46 -2
View File
@@ -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)
}
}
})
}
}
+2 -1
View File
@@ -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},
+2 -1
View File
@@ -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},
}