mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
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:
+2
-2
@@ -36,8 +36,8 @@ func (b *Bool) History() []Press {
|
||||
return b.clk.History()
|
||||
}
|
||||
|
||||
func (b *Bool) Layout(gtx layout.Context) layout.Dimensions {
|
||||
dims := b.clk.Layout(gtx)
|
||||
func (b *Bool) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
||||
dims := b.clk.Layout(gtx, w)
|
||||
for b.clk.Clicked() {
|
||||
b.Value = !b.Value
|
||||
b.changed = true
|
||||
|
||||
+8
-3
@@ -10,6 +10,7 @@ import (
|
||||
"gioui.org/gesture"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
)
|
||||
|
||||
@@ -90,10 +91,14 @@ func (b *Clickable) History() []Press {
|
||||
}
|
||||
|
||||
// Layout and update the button state
|
||||
func (b *Clickable) Layout(gtx layout.Context) layout.Dimensions {
|
||||
func (b *Clickable) Layout(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
||||
b.update(gtx)
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
|
||||
m := op.Record(gtx.Ops)
|
||||
dims := w(gtx)
|
||||
c := m.Stop()
|
||||
defer clip.Rect(image.Rectangle{Max: dims.Size}).Push(gtx.Ops).Pop()
|
||||
b.click.Add(gtx.Ops)
|
||||
c.Add(gtx.Ops)
|
||||
for len(b.history) > 0 {
|
||||
c := b.history[0]
|
||||
if c.End.IsZero() || gtx.Now.Sub(c.End) < 1*time.Second {
|
||||
@@ -102,7 +107,7 @@ func (b *Clickable) Layout(gtx layout.Context) layout.Dimensions {
|
||||
n := copy(b.history, b.history[1:])
|
||||
b.history = b.history[:n]
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
return dims
|
||||
}
|
||||
|
||||
// update the button state by processing events.
|
||||
|
||||
@@ -28,11 +28,12 @@ func ExampleClickable_passthrough() {
|
||||
|
||||
// widget lays out two buttons on top of each other.
|
||||
widget := func() {
|
||||
button1.Layout(gtx)
|
||||
content := func(gtx layout.Context) layout.Dimensions { return layout.Dimensions{Size: gtx.Constraints.Min} }
|
||||
button1.Layout(gtx, content)
|
||||
// button2 completely covers button1, but pass-through allows pointer
|
||||
// events to pass through to button1.
|
||||
defer pointer.PassOp{}.Push(gtx.Ops).Pop()
|
||||
button2.Layout(gtx)
|
||||
button2.Layout(gtx, content)
|
||||
}
|
||||
|
||||
// The first layout and call to Frame declare the Clickable handlers
|
||||
|
||||
+79
-74
@@ -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,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())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user