diff --git a/widget/material/button.go b/widget/material/button.go index f5e6dce3..41be9ee6 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -52,9 +52,9 @@ type IconButtonStyle struct { func Button(th *Theme, button *widget.Clickable, txt string) ButtonStyle { return ButtonStyle{ Text: txt, - Color: rgb(0xffffff), + Color: th.Palette.ContrastFg, CornerRadius: unit.Dp(4), - Background: th.Color.Primary, + Background: th.Palette.ContrastBg, TextSize: th.TextSize.Scale(14.0 / 16.0), Inset: layout.Inset{ 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 { return ButtonLayoutStyle{ Button: button, - Background: th.Color.Primary, + Background: th.Palette.ContrastBg, CornerRadius: unit.Dp(4), } } func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon) IconButtonStyle { return IconButtonStyle{ - Background: th.Color.Primary, - Color: th.Color.InvText, + Background: th.Palette.ContrastBg, + Color: th.Palette.ContrastFg, Icon: icon, Size: unit.Dp(24), Inset: layout.UniformInset(unit.Dp(12)), diff --git a/widget/material/checkbox.go b/widget/material/checkbox.go index 720fc1cc..914c208e 100644 --- a/widget/material/checkbox.go +++ b/widget/material/checkbox.go @@ -18,8 +18,8 @@ func CheckBox(th *Theme, checkBox *widget.Bool, label string) CheckBoxStyle { CheckBox: checkBox, checkable: checkable{ Label: label, - Color: th.Color.Text, - IconColor: th.Color.Primary, + Color: th.Palette.Fg, + IconColor: th.Palette.ContrastBg, TextSize: th.TextSize.Scale(14.0 / 16.0), Size: unit.Dp(26), shaper: th.Shaper, diff --git a/widget/material/editor.go b/widget/material/editor.go index ae6805d5..9e8a33e0 100644 --- a/widget/material/editor.go +++ b/widget/material/editor.go @@ -32,10 +32,10 @@ func Editor(th *Theme, editor *widget.Editor, hint string) EditorStyle { return EditorStyle{ Editor: editor, TextSize: th.TextSize, - Color: th.Color.Text, + Color: th.Palette.Fg, shaper: th.Shaper, Hint: hint, - HintColor: th.Color.Hint, + HintColor: f32color.MulAlpha(th.Palette.Fg, 0xbb), } } diff --git a/widget/material/label.go b/widget/material/label.go index 256dcfd5..89bbc538 100644 --- a/widget/material/label.go +++ b/widget/material/label.go @@ -66,7 +66,7 @@ func Caption(th *Theme, txt string) LabelStyle { func Label(th *Theme, size unit.Value, txt string) LabelStyle { return LabelStyle{ Text: txt, - Color: th.Color.Text, + Color: th.Palette.Fg, TextSize: size, shaper: th.Shaper, } diff --git a/widget/material/loader.go b/widget/material/loader.go index 48a4b6f2..05fe508d 100644 --- a/widget/material/loader.go +++ b/widget/material/loader.go @@ -22,7 +22,7 @@ type LoaderStyle struct { func Loader(th *Theme) LoaderStyle { return LoaderStyle{ - Color: th.Color.Primary, + Color: th.Palette.ContrastBg, } } diff --git a/widget/material/progressbar.go b/widget/material/progressbar.go index 5cba9baf..6f2fa51f 100644 --- a/widget/material/progressbar.go +++ b/widget/material/progressbar.go @@ -15,14 +15,16 @@ import ( ) type ProgressBarStyle struct { - Color color.NRGBA - Progress int + Color color.NRGBA + TrackColor color.NRGBA + Progress int } func ProgressBar(th *Theme, progress int) ProgressBarStyle { return ProgressBarStyle{ - Progress: progress, - Color: th.Color.Primary, + Progress: progress, + 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, layout.Stacked(func(gtx layout.Context) layout.Dimensions { - // Use a transparent equivalent of progress color. - bgCol := f32color.MulAlpha(p.Color, 150) - - return shader(progressBarWidth, bgCol) + return shader(progressBarWidth, p.TrackColor) }), layout.Stacked(func(gtx layout.Context) layout.Dimensions { fillWidth := (progressBarWidth / 100) * float32(progress) diff --git a/widget/material/radiobutton.go b/widget/material/radiobutton.go index bde6976e..1546fc3a 100644 --- a/widget/material/radiobutton.go +++ b/widget/material/radiobutton.go @@ -22,8 +22,8 @@ func RadioButton(th *Theme, group *widget.Enum, key, label string) RadioButtonSt checkable: checkable{ Label: label, - Color: th.Color.Text, - IconColor: th.Color.Primary, + Color: th.Palette.Fg, + IconColor: th.Palette.ContrastBg, TextSize: th.TextSize.Scale(14.0 / 16.0), Size: unit.Dp(26), shaper: th.Shaper, diff --git a/widget/material/slider.go b/widget/material/slider.go index 4756c23c..fca46049 100644 --- a/widget/material/slider.go +++ b/widget/material/slider.go @@ -21,7 +21,7 @@ func Slider(th *Theme, float *widget.Float, min, max float32) SliderStyle { return SliderStyle{ Min: min, Max: max, - Color: th.Color.Primary, + Color: th.Palette.ContrastBg, Float: float, } } diff --git a/widget/material/switch.go b/widget/material/switch.go index 93c22a17..c0f6eff9 100644 --- a/widget/material/switch.go +++ b/widget/material/switch.go @@ -21,6 +21,7 @@ type SwitchStyle struct { Color struct { Enabled color.NRGBA Disabled color.NRGBA + Track color.NRGBA } Switch *widget.Bool } @@ -29,8 +30,9 @@ func Switch(th *Theme, swtch *widget.Bool) SwitchStyle { sw := SwitchStyle{ Switch: swtch, } - sw.Color.Enabled = th.Color.Primary - sw.Color.Disabled = rgb(0xffffff) + sw.Color.Enabled = th.Palette.ContrastBg + sw.Color.Disabled = th.Palette.Bg + sw.Color.Track = f32color.MulAlpha(th.Palette.Fg, 0x88) return sw } @@ -55,7 +57,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions { if gtx.Queue == nil { col = f32color.MulAlpha(col, 150) } - trackColor := f32color.MulAlpha(col, 150) + trackColor := s.Color.Track op.Offset(f32.Point{Y: trackOff}).Add(gtx.Ops) clip.RRect{ Rect: trackRect, diff --git a/widget/material/theme.go b/widget/material/theme.go index b55af125..d37a2331 100644 --- a/widget/material/theme.go +++ b/widget/material/theme.go @@ -11,14 +11,28 @@ import ( "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 { Shaper text.Shaper - Color struct { - Primary color.NRGBA - Text color.NRGBA - Hint color.NRGBA - InvText color.NRGBA - } + Palette TextSize unit.Value Icon struct { CheckBoxChecked *widget.Icon @@ -32,10 +46,12 @@ func NewTheme(fontCollection []text.FontFace) *Theme { t := &Theme{ Shaper: text.NewCache(fontCollection), } - t.Color.Primary = rgb(0x3f51b5) - t.Color.Text = rgb(0x000000) - t.Color.Hint = rgb(0xbbbbbb) - t.Color.InvText = rgb(0xffffff) + t.Palette = Palette{ + Fg: rgb(0x000000), + Bg: rgb(0xffffff), + ContrastBg: rgb(0x3f51b5), + ContrastFg: rgb(0xffffff), + } t.TextSize = unit.Sp(16) t.Icon.CheckBoxChecked = mustIcon(widget.NewIcon(icons.ToggleCheckBox)) @@ -46,6 +62,11 @@ func NewTheme(fontCollection []text.FontFace) *Theme { return t } +func (t Theme) WithPalette(p Palette) Theme { + t.Palette = p + return t +} + func mustIcon(ic *widget.Icon, err error) *widget.Icon { if err != nil { panic(err)