widget/material: move widget state object from Layout methods to constructors

Instead of, say,

	var th *material.Theme
	var btn *widget.Clickable

	material.Button(th, "Click me").Layout(gtx, btn)

move the widget state objects to the constructor:

	material.Button(th, btn, "Click me").Layout(gtx)

The advatage is that several widgets can now be used without
wrapping them in function literals. For example,

	layout.Inset{}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
		material.Button(th, "Click me").Layout(gtx, btn)
	})

collapses to just

	layout.Inset{}.Layout(gtx, material.Button(th, btn, "Click me").Layout)

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-05-23 20:09:08 +02:00
parent 3af01a3f43
commit 2451750782
6 changed files with 62 additions and 44 deletions
+20 -13
View File
@@ -26,6 +26,7 @@ type ButtonStyle struct {
Background color.RGBA
CornerRadius unit.Value
Inset layout.Inset
Button *widget.Clickable
shaper text.Shaper
}
@@ -33,6 +34,7 @@ type ButtonLayoutStyle struct {
Background color.RGBA
CornerRadius unit.Value
Inset layout.Inset
Button *widget.Clickable
}
type IconButtonStyle struct {
@@ -41,11 +43,12 @@ type IconButtonStyle struct {
Color color.RGBA
Icon *widget.Icon
// Size is the icon size.
Size unit.Value
Inset layout.Inset
Size unit.Value
Inset layout.Inset
Button *widget.Clickable
}
func Button(th *Theme, txt string) ButtonStyle {
func Button(th *Theme, button *widget.Clickable, txt string) ButtonStyle {
return ButtonStyle{
Text: txt,
Color: rgb(0xffffff),
@@ -56,25 +59,28 @@ func Button(th *Theme, txt string) ButtonStyle {
Top: unit.Dp(10), Bottom: unit.Dp(10),
Left: unit.Dp(12), Right: unit.Dp(12),
},
Button: button,
shaper: th.Shaper,
}
}
func ButtonLayout(th *Theme) ButtonLayoutStyle {
func ButtonLayout(th *Theme, button *widget.Clickable) ButtonLayoutStyle {
return ButtonLayoutStyle{
Button: button,
Background: th.Color.Primary,
CornerRadius: unit.Dp(4),
Inset: layout.UniformInset(unit.Dp(12)),
}
}
func IconButton(th *Theme, icon *widget.Icon) IconButtonStyle {
func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon) IconButtonStyle {
return IconButtonStyle{
Background: th.Color.Primary,
Color: th.Color.InvText,
Icon: icon,
Size: unit.Dp(24),
Inset: layout.UniformInset(unit.Dp(12)),
Button: button,
}
}
@@ -99,18 +105,19 @@ func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) la
)
}
func (b ButtonStyle) Layout(gtx layout.Context, button *widget.Clickable) layout.Dimensions {
func (b ButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
return ButtonLayoutStyle{
Background: b.Background,
CornerRadius: b.CornerRadius,
Inset: b.Inset,
}.Layout(gtx, button, func(gtx layout.Context) layout.Dimensions {
Button: b.Button,
}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
paint.ColorOp{Color: b.Color}.Add(gtx.Ops)
return widget.Label{Alignment: text.Middle}.Layout(gtx, b.shaper, b.Font, b.TextSize, b.Text)
})
}
func (b ButtonLayoutStyle) Layout(gtx layout.Context, button *widget.Clickable, w layout.Widget) 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 {
@@ -123,7 +130,7 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, button *widget.Clickable,
NE: rr, NW: rr, SE: rr, SW: rr,
}.Op(gtx.Ops).Add(gtx.Ops)
dims := fill(gtx, b.Background)
for _, c := range button.History() {
for _, c := range b.Button.History() {
drawInk(gtx, c)
}
return dims
@@ -134,11 +141,11 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, button *widget.Clickable,
return b.Inset.Layout(gtx, w)
})
}),
layout.Expanded(button.Layout),
layout.Expanded(b.Button.Layout),
)
}
func (b IconButtonStyle) Layout(gtx layout.Context, button *widget.Clickable) layout.Dimensions {
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 {
size := gtx.Constraints.Min.X
@@ -149,7 +156,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context, button *widget.Clickable) la
NE: rr, NW: rr, SE: rr, SW: rr,
}.Op(gtx.Ops).Add(gtx.Ops)
dims := fill(gtx, b.Background)
for _, c := range button.History() {
for _, c := range b.Button.History() {
drawInk(gtx, c)
}
return dims
@@ -168,7 +175,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context, button *widget.Clickable) la
}),
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
pointer.Ellipse(image.Rectangle{Max: gtx.Constraints.Min}).Add(gtx.Ops)
return button.Layout(gtx)
return b.Button.Layout(gtx)
}),
)
}
+8 -6
View File
@@ -10,11 +10,13 @@ import (
type CheckBoxStyle struct {
checkable
CheckBox *widget.Bool
}
func CheckBox(th *Theme, label string) CheckBoxStyle {
func CheckBox(th *Theme, checkBox *widget.Bool, label string) CheckBoxStyle {
return CheckBoxStyle{
checkable{
CheckBox: checkBox,
checkable: checkable{
Label: label,
Color: th.Color.Text,
IconColor: th.Color.Primary,
@@ -28,9 +30,9 @@ func CheckBox(th *Theme, label string) CheckBoxStyle {
}
// Layout updates the checkBox and displays it.
func (c CheckBoxStyle) Layout(gtx layout.Context, checkBox *widget.Bool) layout.Dimensions {
checkBox.Update(gtx)
dims := c.layout(gtx, checkBox.Value)
checkBox.Layout(gtx)
func (c CheckBoxStyle) Layout(gtx layout.Context) layout.Dimensions {
c.CheckBox.Update(gtx)
dims := c.layout(gtx, c.CheckBox.Value)
c.CheckBox.Layout(gtx)
return dims
}
+9 -7
View File
@@ -22,12 +22,14 @@ type EditorStyle struct {
Hint string
// HintColor is the color of hint text.
HintColor color.RGBA
Editor *widget.Editor
shaper text.Shaper
}
func Editor(th *Theme, hint string) EditorStyle {
func Editor(th *Theme, editor *widget.Editor, hint string) EditorStyle {
return EditorStyle{
Editor: editor,
TextSize: th.TextSize,
Color: th.Color.Text,
shaper: th.Shaper,
@@ -36,13 +38,13 @@ func Editor(th *Theme, hint string) EditorStyle {
}
}
func (e EditorStyle) Layout(gtx layout.Context, editor *widget.Editor) layout.Dimensions {
func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions {
var stack op.StackOp
stack.Push(gtx.Ops)
var macro op.MacroOp
macro.Record(gtx.Ops)
paint.ColorOp{Color: e.HintColor}.Add(gtx.Ops)
tl := widget.Label{Alignment: editor.Alignment}
tl := widget.Label{Alignment: e.Editor.Alignment}
dims := tl.Layout(gtx, e.shaper, e.Font, e.TextSize, e.Hint)
macro.Stop()
if w := dims.Size.X; gtx.Constraints.Min.X < w {
@@ -51,15 +53,15 @@ func (e EditorStyle) Layout(gtx layout.Context, editor *widget.Editor) layout.Di
if h := dims.Size.Y; gtx.Constraints.Min.Y < h {
gtx.Constraints.Min.Y = h
}
dims = editor.Layout(gtx, e.shaper, e.Font, e.TextSize)
if editor.Len() > 0 {
dims = e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize)
if e.Editor.Len() > 0 {
paint.ColorOp{Color: e.Color}.Add(gtx.Ops)
editor.PaintText(gtx)
e.Editor.PaintText(gtx)
} else {
macro.Add()
}
paint.ColorOp{Color: e.Color}.Add(gtx.Ops)
editor.PaintCaret(gtx)
e.Editor.PaintCaret(gtx)
stack.Pop()
return dims
}
+7 -4
View File
@@ -14,16 +14,18 @@ import (
)
type ProgressBarStyle struct {
Color color.RGBA
Color color.RGBA
Progress int
}
func ProgressBar(th *Theme) ProgressBarStyle {
func ProgressBar(th *Theme, progress int) ProgressBarStyle {
return ProgressBarStyle{
Color: th.Color.Primary,
Progress: progress,
Color: th.Color.Primary,
}
}
func (p ProgressBarStyle) Layout(gtx layout.Context, progress int) layout.Dimensions {
func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions {
shader := func(width float32, color color.RGBA) layout.Dimensions {
maxHeight := unit.Dp(4)
rr := float32(gtx.Px(unit.Dp(2)))
@@ -44,6 +46,7 @@ func (p ProgressBarStyle) Layout(gtx layout.Context, progress int) layout.Dimens
return layout.Dimensions{Size: d}
}
progress := p.Progress
if progress > 100 {
progress = 100
} else if progress < 0 {
+8 -6
View File
@@ -10,13 +10,15 @@ import (
type RadioButtonStyle struct {
checkable
Key string
Key string
Group *widget.Enum
}
// RadioButton returns a RadioButton with a label. The key specifies
// the value for the Enum.
func RadioButton(th *Theme, key, label string) RadioButtonStyle {
func RadioButton(th *Theme, group *widget.Enum, key, label string) RadioButtonStyle {
return RadioButtonStyle{
Group: group,
checkable: checkable{
Label: label,
@@ -33,9 +35,9 @@ func RadioButton(th *Theme, key, label string) RadioButtonStyle {
}
// Layout updates enum and displays the radio button.
func (r RadioButtonStyle) Layout(gtx layout.Context, enum *widget.Enum) layout.Dimensions {
enum.Update(gtx)
dims := r.layout(gtx, enum.Value == r.Key)
enum.Layout(gtx, r.Key)
func (r RadioButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
r.Group.Update(gtx)
dims := r.layout(gtx, r.Group.Value == r.Key)
r.Group.Layout(gtx, r.Key)
return dims
}
+10 -8
View File
@@ -17,18 +17,20 @@ import (
)
type SwitchStyle struct {
Color color.RGBA
Color color.RGBA
Switch *widget.Bool
}
func Switch(th *Theme) SwitchStyle {
func Switch(th *Theme, swtch *widget.Bool) SwitchStyle {
return SwitchStyle{
Color: th.Color.Primary,
Switch: swtch,
Color: th.Color.Primary,
}
}
// Layout updates the checkBox and displays it.
func (s SwitchStyle) Layout(gtx layout.Context, swtch *widget.Bool) layout.Dimensions {
swtch.Update(gtx)
func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
s.Switch.Update(gtx)
trackWidth := gtx.Px(unit.Dp(36))
trackHeight := gtx.Px(unit.Dp(16))
@@ -55,7 +57,7 @@ func (s SwitchStyle) Layout(gtx layout.Context, swtch *widget.Bool) layout.Dimen
// Compute thumb offset and color.
stack.Push(gtx.Ops)
col := rgb(0xffffff)
if swtch.Value {
if s.Switch.Value {
off := trackWidth - thumbSize
op.TransformOp{}.Offset(f32.Point{X: float32(off)}).Add(gtx.Ops)
col = s.Color
@@ -93,7 +95,7 @@ func (s SwitchStyle) Layout(gtx layout.Context, swtch *widget.Bool) layout.Dimen
},
NE: rr, NW: rr, SE: rr, SW: rr,
}.Op(gtx.Ops).Add(gtx.Ops)
drawInk(gtx, swtch.Last)
drawInk(gtx, s.Switch.Last)
stack.Pop()
// Set up click area.
@@ -109,7 +111,7 @@ func (s SwitchStyle) Layout(gtx layout.Context, swtch *widget.Bool) layout.Dimen
X: clickSize, Y: clickSize,
},
}).Add(gtx.Ops)
swtch.Layout(gtx)
s.Switch.Layout(gtx)
stack.Pop()
return layout.Dimensions{