widget: [API] add child widget argument to Clickable.Layout

To make the semantic relation between the clickable area and its
content clear, it will be important for the clickable clip operation
to cover all of the clickable content.

API change: users of widget.Clickable must now pass the clickable
content to Layout.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-11-29 16:28:19 +01:00
parent a894bd6c9c
commit 665e23693f
6 changed files with 98 additions and 91 deletions
+79 -74
View File
@@ -86,17 +86,18 @@ func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon) IconButt
// Clickable lays out a rectangular clickable widget without further
// decoration.
func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) layout.Dimensions {
return layout.Stack{}.Layout(gtx,
layout.Expanded(button.Layout),
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
for _, c := range button.History() {
drawInk(gtx, c)
}
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(w),
)
return button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Stack{}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
for _, c := range button.History() {
drawInk(gtx, c)
}
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(w),
)
})
}
func (b ButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
@@ -114,74 +115,78 @@ func (b ButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
min := gtx.Constraints.Min
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
rr := float32(gtx.Px(b.CornerRadius))
defer clip.UniformRRect(f32.Rectangle{Max: f32.Point{
X: float32(gtx.Constraints.Min.X),
Y: float32(gtx.Constraints.Min.Y),
}}, rr).Push(gtx.Ops).Pop()
background := b.Background
switch {
case gtx.Queue == nil:
background = f32color.Disabled(b.Background)
case b.Button.Hovered():
background = f32color.Hovered(b.Background)
}
paint.Fill(gtx.Ops, background)
for _, c := range b.Button.History() {
drawInk(gtx, c)
}
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min = min
return layout.Center.Layout(gtx, w)
}),
layout.Expanded(b.Button.Layout),
)
return b.Button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
rr := float32(gtx.Px(b.CornerRadius))
defer clip.UniformRRect(f32.Rectangle{Max: f32.Point{
X: float32(gtx.Constraints.Min.X),
Y: float32(gtx.Constraints.Min.Y),
}}, rr).Push(gtx.Ops).Pop()
background := b.Background
switch {
case gtx.Queue == nil:
background = f32color.Disabled(b.Background)
case b.Button.Hovered():
background = f32color.Hovered(b.Background)
}
paint.Fill(gtx.Ops, background)
for _, c := range b.Button.History() {
drawInk(gtx, c)
}
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min = min
return layout.Center.Layout(gtx, w)
}),
)
})
}
func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
sizex, sizey := gtx.Constraints.Min.X, gtx.Constraints.Min.Y
sizexf, sizeyf := float32(sizex), float32(sizey)
rr := (sizexf + sizeyf) * .25
defer clip.UniformRRect(f32.Rectangle{
Max: f32.Point{X: sizexf, Y: sizeyf},
}, rr).Push(gtx.Ops).Pop()
background := b.Background
switch {
case gtx.Queue == nil:
background = f32color.Disabled(b.Background)
case b.Button.Hovered():
background = f32color.Hovered(b.Background)
}
paint.Fill(gtx.Ops, background)
for _, c := range b.Button.History() {
drawInk(gtx, c)
}
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
size := gtx.Px(b.Size)
if b.Icon != nil {
gtx.Constraints.Min = image.Point{X: size}
b.Icon.Layout(gtx, b.Color)
m := op.Record(gtx.Ops)
dims := b.Button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
sizex, sizey := gtx.Constraints.Min.X, gtx.Constraints.Min.Y
sizexf, sizeyf := float32(sizex), float32(sizey)
rr := (sizexf + sizeyf) * .25
defer clip.UniformRRect(f32.Rectangle{
Max: f32.Point{X: sizexf, Y: sizeyf},
}, rr).Push(gtx.Ops).Pop()
background := b.Background
switch {
case gtx.Queue == nil:
background = f32color.Disabled(b.Background)
case b.Button.Hovered():
background = f32color.Hovered(b.Background)
}
return layout.Dimensions{
Size: image.Point{X: size, Y: size},
paint.Fill(gtx.Ops, background)
for _, c := range b.Button.History() {
drawInk(gtx, c)
}
})
}),
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
bounds := f32.Rectangle{Max: layout.FPt(gtx.Constraints.Min)}
defer clip.Ellipse(bounds).Push(gtx.Ops).Pop()
return b.Button.Layout(gtx)
}),
)
return layout.Dimensions{Size: gtx.Constraints.Min}
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
size := gtx.Px(b.Size)
if b.Icon != nil {
gtx.Constraints.Min = image.Point{X: size}
b.Icon.Layout(gtx, b.Color)
}
return layout.Dimensions{
Size: image.Point{X: size, Y: size},
}
})
}),
)
})
c := m.Stop()
bounds := f32.Rectangle{Max: layout.FPt(dims.Size)}
defer clip.Ellipse(bounds).Push(gtx.Ops).Pop()
c.Add(gtx.Ops)
return dims
}
func drawInk(gtx layout.Context, c widget.Press) {
+3 -8
View File
@@ -3,10 +3,7 @@
package material
import (
"image"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/unit"
"gioui.org/widget"
)
@@ -34,9 +31,7 @@ func CheckBox(th *Theme, checkBox *widget.Bool, label string) CheckBoxStyle {
// Layout updates the checkBox and displays it.
func (c CheckBoxStyle) Layout(gtx layout.Context) layout.Dimensions {
dims := c.layout(gtx, c.CheckBox.Value, c.CheckBox.Hovered())
defer clip.Rect(image.Rectangle{Max: dims.Size}).Push(gtx.Ops).Pop()
gtx.Constraints.Min = dims.Size
c.CheckBox.Layout(gtx)
return dims
return c.CheckBox.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return c.layout(gtx, c.CheckBox.Value, c.CheckBox.Hovered())
})
}
+3 -2
View File
@@ -124,8 +124,9 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
defer op.Offset(clickOff).Push(gtx.Ops).Pop()
sz := image.Pt(clickSize, clickSize)
defer clip.Ellipse(f32.Rectangle{Max: layout.FPt(sz)}).Push(gtx.Ops).Pop()
gtx.Constraints.Min = sz
s.Switch.Layout(gtx)
s.Switch.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Dimensions{Size: sz}
})
dims := image.Point{X: trackWidth, Y: thumbSize}
return layout.Dimensions{Size: dims}