widget/material: manage widget colors with Palette type

This introduces a new material.Palette type that captures the color information
necessary to render a widget. This type is embedded in the material.Theme to
make it easier to swap to a different palette for part of the UI by reassinging
the Palette field.

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
Chris Waldon
2020-12-05 21:59:49 -05:00
committed by Elias Naur
parent 47ba975899
commit a87a520ae8
10 changed files with 57 additions and 35 deletions
+5 -5
View File
@@ -52,9 +52,9 @@ type IconButtonStyle struct {
func Button(th *Theme, button *widget.Clickable, txt string) ButtonStyle { func Button(th *Theme, button *widget.Clickable, txt string) ButtonStyle {
return ButtonStyle{ return ButtonStyle{
Text: txt, Text: txt,
Color: rgb(0xffffff), Color: th.Palette.ContrastFg,
CornerRadius: unit.Dp(4), CornerRadius: unit.Dp(4),
Background: th.Color.Primary, Background: th.Palette.ContrastBg,
TextSize: th.TextSize.Scale(14.0 / 16.0), TextSize: th.TextSize.Scale(14.0 / 16.0),
Inset: layout.Inset{ Inset: layout.Inset{
Top: unit.Dp(10), Bottom: unit.Dp(10), Top: unit.Dp(10), Bottom: unit.Dp(10),
@@ -68,15 +68,15 @@ func Button(th *Theme, button *widget.Clickable, txt string) ButtonStyle {
func ButtonLayout(th *Theme, button *widget.Clickable) ButtonLayoutStyle { func ButtonLayout(th *Theme, button *widget.Clickable) ButtonLayoutStyle {
return ButtonLayoutStyle{ return ButtonLayoutStyle{
Button: button, Button: button,
Background: th.Color.Primary, Background: th.Palette.ContrastBg,
CornerRadius: unit.Dp(4), CornerRadius: unit.Dp(4),
} }
} }
func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon) IconButtonStyle { func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon) IconButtonStyle {
return IconButtonStyle{ return IconButtonStyle{
Background: th.Color.Primary, Background: th.Palette.ContrastBg,
Color: th.Color.InvText, Color: th.Palette.ContrastFg,
Icon: icon, Icon: icon,
Size: unit.Dp(24), Size: unit.Dp(24),
Inset: layout.UniformInset(unit.Dp(12)), Inset: layout.UniformInset(unit.Dp(12)),
+2 -2
View File
@@ -18,8 +18,8 @@ func CheckBox(th *Theme, checkBox *widget.Bool, label string) CheckBoxStyle {
CheckBox: checkBox, CheckBox: checkBox,
checkable: checkable{ checkable: checkable{
Label: label, Label: label,
Color: th.Color.Text, Color: th.Palette.Fg,
IconColor: th.Color.Primary, IconColor: th.Palette.ContrastBg,
TextSize: th.TextSize.Scale(14.0 / 16.0), TextSize: th.TextSize.Scale(14.0 / 16.0),
Size: unit.Dp(26), Size: unit.Dp(26),
shaper: th.Shaper, shaper: th.Shaper,
+2 -2
View File
@@ -32,10 +32,10 @@ func Editor(th *Theme, editor *widget.Editor, hint string) EditorStyle {
return EditorStyle{ return EditorStyle{
Editor: editor, Editor: editor,
TextSize: th.TextSize, TextSize: th.TextSize,
Color: th.Color.Text, Color: th.Palette.Fg,
shaper: th.Shaper, shaper: th.Shaper,
Hint: hint, Hint: hint,
HintColor: th.Color.Hint, HintColor: f32color.MulAlpha(th.Palette.Fg, 0xbb),
} }
} }
+1 -1
View File
@@ -66,7 +66,7 @@ func Caption(th *Theme, txt string) LabelStyle {
func Label(th *Theme, size unit.Value, txt string) LabelStyle { func Label(th *Theme, size unit.Value, txt string) LabelStyle {
return LabelStyle{ return LabelStyle{
Text: txt, Text: txt,
Color: th.Color.Text, Color: th.Palette.Fg,
TextSize: size, TextSize: size,
shaper: th.Shaper, shaper: th.Shaper,
} }
+1 -1
View File
@@ -22,7 +22,7 @@ type LoaderStyle struct {
func Loader(th *Theme) LoaderStyle { func Loader(th *Theme) LoaderStyle {
return LoaderStyle{ return LoaderStyle{
Color: th.Color.Primary, Color: th.Palette.ContrastBg,
} }
} }
+7 -8
View File
@@ -15,14 +15,16 @@ import (
) )
type ProgressBarStyle struct { type ProgressBarStyle struct {
Color color.NRGBA Color color.NRGBA
Progress int TrackColor color.NRGBA
Progress int
} }
func ProgressBar(th *Theme, progress int) ProgressBarStyle { func ProgressBar(th *Theme, progress int) ProgressBarStyle {
return ProgressBarStyle{ return ProgressBarStyle{
Progress: progress, Progress: progress,
Color: th.Color.Primary, Color: th.Palette.ContrastBg,
TrackColor: f32color.MulAlpha(th.Palette.Fg, 0x88),
} }
} }
@@ -55,10 +57,7 @@ func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions {
return layout.Stack{Alignment: layout.W}.Layout(gtx, return layout.Stack{Alignment: layout.W}.Layout(gtx,
layout.Stacked(func(gtx layout.Context) layout.Dimensions { layout.Stacked(func(gtx layout.Context) layout.Dimensions {
// Use a transparent equivalent of progress color. return shader(progressBarWidth, p.TrackColor)
bgCol := f32color.MulAlpha(p.Color, 150)
return shader(progressBarWidth, bgCol)
}), }),
layout.Stacked(func(gtx layout.Context) layout.Dimensions { layout.Stacked(func(gtx layout.Context) layout.Dimensions {
fillWidth := (progressBarWidth / 100) * float32(progress) fillWidth := (progressBarWidth / 100) * float32(progress)
+2 -2
View File
@@ -22,8 +22,8 @@ func RadioButton(th *Theme, group *widget.Enum, key, label string) RadioButtonSt
checkable: checkable{ checkable: checkable{
Label: label, Label: label,
Color: th.Color.Text, Color: th.Palette.Fg,
IconColor: th.Color.Primary, IconColor: th.Palette.ContrastBg,
TextSize: th.TextSize.Scale(14.0 / 16.0), TextSize: th.TextSize.Scale(14.0 / 16.0),
Size: unit.Dp(26), Size: unit.Dp(26),
shaper: th.Shaper, shaper: th.Shaper,
+1 -1
View File
@@ -21,7 +21,7 @@ func Slider(th *Theme, float *widget.Float, min, max float32) SliderStyle {
return SliderStyle{ return SliderStyle{
Min: min, Min: min,
Max: max, Max: max,
Color: th.Color.Primary, Color: th.Palette.ContrastBg,
Float: float, Float: float,
} }
} }
+5 -3
View File
@@ -21,6 +21,7 @@ type SwitchStyle struct {
Color struct { Color struct {
Enabled color.NRGBA Enabled color.NRGBA
Disabled color.NRGBA Disabled color.NRGBA
Track color.NRGBA
} }
Switch *widget.Bool Switch *widget.Bool
} }
@@ -29,8 +30,9 @@ func Switch(th *Theme, swtch *widget.Bool) SwitchStyle {
sw := SwitchStyle{ sw := SwitchStyle{
Switch: swtch, Switch: swtch,
} }
sw.Color.Enabled = th.Color.Primary sw.Color.Enabled = th.Palette.ContrastBg
sw.Color.Disabled = rgb(0xffffff) sw.Color.Disabled = th.Palette.Bg
sw.Color.Track = f32color.MulAlpha(th.Palette.Fg, 0x88)
return sw return sw
} }
@@ -55,7 +57,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
if gtx.Queue == nil { if gtx.Queue == nil {
col = f32color.MulAlpha(col, 150) col = f32color.MulAlpha(col, 150)
} }
trackColor := f32color.MulAlpha(col, 150) trackColor := s.Color.Track
op.Offset(f32.Point{Y: trackOff}).Add(gtx.Ops) op.Offset(f32.Point{Y: trackOff}).Add(gtx.Ops)
clip.RRect{ clip.RRect{
Rect: trackRect, Rect: trackRect,
+31 -10
View File
@@ -11,14 +11,28 @@ import (
"golang.org/x/exp/shiny/materialdesign/icons" "golang.org/x/exp/shiny/materialdesign/icons"
) )
// Palette contains the minimal set of colors that a widget may need to
// draw itself.
type Palette struct {
// Bg is the background color atop which content is currently being
// drawn.
Bg color.NRGBA
// Fg is a color suitable for drawing on top of Bg.
Fg color.NRGBA
// ContrastBg is a color used to draw attention to active,
// important, interactive widgets such as buttons.
ContrastBg color.NRGBA
// ContrastFg is a color suitable for content drawn on top of
// ContrastBg.
ContrastFg color.NRGBA
}
type Theme struct { type Theme struct {
Shaper text.Shaper Shaper text.Shaper
Color struct { Palette
Primary color.NRGBA
Text color.NRGBA
Hint color.NRGBA
InvText color.NRGBA
}
TextSize unit.Value TextSize unit.Value
Icon struct { Icon struct {
CheckBoxChecked *widget.Icon CheckBoxChecked *widget.Icon
@@ -32,10 +46,12 @@ func NewTheme(fontCollection []text.FontFace) *Theme {
t := &Theme{ t := &Theme{
Shaper: text.NewCache(fontCollection), Shaper: text.NewCache(fontCollection),
} }
t.Color.Primary = rgb(0x3f51b5) t.Palette = Palette{
t.Color.Text = rgb(0x000000) Fg: rgb(0x000000),
t.Color.Hint = rgb(0xbbbbbb) Bg: rgb(0xffffff),
t.Color.InvText = rgb(0xffffff) ContrastBg: rgb(0x3f51b5),
ContrastFg: rgb(0xffffff),
}
t.TextSize = unit.Sp(16) t.TextSize = unit.Sp(16)
t.Icon.CheckBoxChecked = mustIcon(widget.NewIcon(icons.ToggleCheckBox)) t.Icon.CheckBoxChecked = mustIcon(widget.NewIcon(icons.ToggleCheckBox))
@@ -46,6 +62,11 @@ func NewTheme(fontCollection []text.FontFace) *Theme {
return t return t
} }
func (t Theme) WithPalette(p Palette) Theme {
t.Palette = p
return t
}
func mustIcon(ic *widget.Icon, err error) *widget.Icon { func mustIcon(ic *widget.Icon, err error) *widget.Icon {
if err != nil { if err != nil {
panic(err) panic(err)