shiny/widget/theme: add a Color type.
Change-Id: I333ab9ea0f7b4a488c09bc47398d049810d71082
Reviewed-on: https://go-review.googlesource.com/25162
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/shiny/example/basicgl/main.go b/shiny/example/basicgl/main.go
index 0433dca..3542e37 100644
--- a/shiny/example/basicgl/main.go
+++ b/shiny/example/basicgl/main.go
@@ -25,12 +25,13 @@
"golang.org/x/exp/shiny/widget"
"golang.org/x/exp/shiny/widget/flex"
"golang.org/x/exp/shiny/widget/glwidget"
+ "golang.org/x/exp/shiny/widget/theme"
"golang.org/x/image/colornames"
"golang.org/x/mobile/gl"
)
func colorPatch(c color.Color, w, h unit.Value) *widget.Sizer {
- return widget.NewSizer(w, h, widget.NewUniform(c, nil))
+ return widget.NewSizer(w, h, widget.NewUniform(theme.StaticColor(c), nil))
}
func main() {
diff --git a/shiny/example/layout/main.go b/shiny/example/layout/main.go
index 5c78f43..a04cd83 100644
--- a/shiny/example/layout/main.go
+++ b/shiny/example/layout/main.go
@@ -34,7 +34,7 @@
var px = unit.Pixels
func colorPatch(c color.Color, w, h unit.Value) *widget.Sizer {
- return widget.NewSizer(w, h, widget.NewUniform(c, nil))
+ return widget.NewSizer(w, h, widget.NewUniform(theme.StaticColor(c), nil))
}
func main() {
@@ -76,7 +76,7 @@
// Make the RGBA image.
rgba := image.NewRGBA(image.Rect(0, 0, 640, 480))
- draw.Draw(rgba, rgba.Bounds(), t.GetPalette().Neutral, image.Point{}, draw.Src)
+ draw.Draw(rgba, rgba.Bounds(), t.GetPalette().Neutral(), image.Point{}, draw.Src)
// Measure, layout and paint.
vf.Measure(t)
diff --git a/shiny/widget/flex/flex_test.go b/shiny/widget/flex/flex_test.go
index 85cc29b..247c7a7 100644
--- a/shiny/widget/flex/flex_test.go
+++ b/shiny/widget/flex/flex_test.go
@@ -14,6 +14,7 @@
"golang.org/x/exp/shiny/unit"
"golang.org/x/exp/shiny/widget"
"golang.org/x/exp/shiny/widget/node"
+ "golang.org/x/exp/shiny/widget/theme"
)
type layoutTest struct {
@@ -382,7 +383,8 @@
for testNum, test := range layoutTests {
var children []node.Node
for i, sz := range test.measured {
- n := widget.NewSizer(unit.Pixels(sz[0]), unit.Pixels(sz[1]), widget.NewUniform(colors[i], nil))
+ u := widget.NewUniform(theme.StaticColor(colors[i]), nil)
+ n := widget.NewSizer(unit.Pixels(sz[0]), unit.Pixels(sz[1]), u)
if test.layoutData != nil {
n.LayoutData = test.layoutData[i]
}
diff --git a/shiny/widget/label.go b/shiny/widget/label.go
index d3a24d1..858ba15 100644
--- a/shiny/widget/label.go
+++ b/shiny/widget/label.go
@@ -16,7 +16,8 @@
// Label is a leaf widget that holds a text label.
type Label struct {
node.LeafEmbed
- Text string
+ Text string
+ ThemeColor theme.Color
}
// NewLabel returns a new Label widget.
@@ -51,9 +52,14 @@
m := face.Metrics()
ascent := m.Ascent.Ceil()
+ tc := w.ThemeColor
+ if tc == nil {
+ tc = theme.Foreground
+ }
+
d := font.Drawer{
Dst: dst,
- Src: t.GetPalette().Foreground,
+ Src: tc.Uniform(t),
Face: face,
Dot: fixed.Point26_6{
X: fixed.I(origin.X + w.Rect.Min.X),
diff --git a/shiny/widget/text.go b/shiny/widget/text.go
index 8aa30cd..e5b386e 100644
--- a/shiny/widget/text.go
+++ b/shiny/widget/text.go
@@ -80,7 +80,7 @@
padding := t.Pixels(unit.Ems(0.5)).Ceil()
- draw.Draw(dst, dst.Bounds(), t.GetPalette().Background, image.Point{}, draw.Src)
+ draw.Draw(dst, dst.Bounds(), t.GetPalette().Background(), image.Point{}, draw.Src)
minDotY := fixed.I(dst.Bounds().Min.Y - descent)
maxDotY := fixed.I(dst.Bounds().Max.Y + ascent)
@@ -88,7 +88,7 @@
x0 := fixed.I(origin.X + w.Rect.Min.X + padding)
d := font.Drawer{
Dst: dst,
- Src: t.GetPalette().Foreground,
+ Src: t.GetPalette().Foreground(),
Face: face,
Dot: fixed.Point26_6{
X: x0,
diff --git a/shiny/widget/theme/theme.go b/shiny/widget/theme/theme.go
index 3483a96..073bace 100644
--- a/shiny/widget/theme/theme.go
+++ b/shiny/widget/theme/theme.go
@@ -43,27 +43,64 @@
// TODO: add a "Metrics(FontFaceOptions) font.Metrics" method?
}
-// Palette provides a theme's color palette.
+// Color is a theme-dependent color, such as "the foreground color". Combining
+// a Color with a Theme results in a color.Color in the sense of the standard
+// library's image/color package. It can also result in an *image.Uniform,
+// suitable for passing as the src argument to image/draw functions.
+type Color interface {
+ Color(*Theme) color.Color
+ Uniform(*Theme) *image.Uniform
+}
+
+// StaticColor adapts a color.Color to a theme Color.
+func StaticColor(c color.Color) Color { return staticColor{image.Uniform{c}} }
+
+type staticColor struct {
+ u image.Uniform
+}
+
+func (s staticColor) Color(*Theme) color.Color { return s.u.C }
+func (s staticColor) Uniform(*Theme) *image.Uniform { return &s.u }
+
+// Palette provides a theme's color palette. The array is indexed by
+// PaletteIndex constants such as Accent and Foreground.
//
-// The colors are expressed as *image.Uniform values so that they can be easily
+// The colors are expressed as image.Uniform values so that they can be easily
// passed as the src argument to image/draw functions.
-type Palette struct {
+type Palette [PaletteLen]image.Uniform
+
+func (p *Palette) Light() *image.Uniform { return &p[Light] }
+func (p *Palette) Neutral() *image.Uniform { return &p[Neutral] }
+func (p *Palette) Dark() *image.Uniform { return &p[Dark] }
+func (p *Palette) Accent() *image.Uniform { return &p[Accent] }
+func (p *Palette) Foreground() *image.Uniform { return &p[Foreground] }
+func (p *Palette) Background() *image.Uniform { return &p[Background] }
+
+// PaletteIndex is both an integer index into a Palette array and a Color.
+type PaletteIndex int
+
+func (i PaletteIndex) Color(t *Theme) color.Color { return t.GetPalette()[i].C }
+func (i PaletteIndex) Uniform(t *Theme) *image.Uniform { return &t.GetPalette()[i] }
+
+const (
// Light, Neutral and Dark are three color tones used to fill in widgets
// such as buttons, menu bars and panels.
- Light *image.Uniform
- Neutral *image.Uniform
- Dark *image.Uniform
+ Light = PaletteIndex(0)
+ Neutral = PaletteIndex(1)
+ Dark = PaletteIndex(2)
// Accent is the color used to accentuate selections or suggestions.
- Accent *image.Uniform
+ Accent = PaletteIndex(3)
// Foreground is the color used for text, dividers and icons.
- Foreground *image.Uniform
+ Foreground = PaletteIndex(4)
// Background is the color used behind large blocks of text. Short,
// non-editable label text will typically be on the Neutral color.
- Background *image.Uniform
-}
+ Background = PaletteIndex(5)
+
+ PaletteLen = 6
+)
// DefaultDPI is the fallback value of a theme's DPI, if the underlying context
// does not provide a DPI value.
@@ -75,12 +112,12 @@
// DefaultPalette is the default theme's palette.
DefaultPalette = Palette{
- Light: &image.Uniform{C: color.RGBA{0xf5, 0xf5, 0xf5, 0xff}}, // Material Design "Grey 100".
- Neutral: &image.Uniform{C: color.RGBA{0xee, 0xee, 0xee, 0xff}}, // Material Design "Grey 200".
- Dark: &image.Uniform{C: color.RGBA{0xe0, 0xe0, 0xe0, 0xff}}, // Material Design "Grey 300".
- Accent: &image.Uniform{C: color.RGBA{0x21, 0x96, 0xf3, 0xff}}, // Material Design "Blue 500".
- Foreground: &image.Uniform{C: color.RGBA{0x00, 0x00, 0x00, 0xff}}, // Material Design "Black".
- Background: &image.Uniform{C: color.RGBA{0xff, 0xff, 0xff, 0xff}}, // Material Design "White".
+ Light: image.Uniform{C: color.RGBA{0xf5, 0xf5, 0xf5, 0xff}}, // Material Design "Grey 100".
+ Neutral: image.Uniform{C: color.RGBA{0xee, 0xee, 0xee, 0xff}}, // Material Design "Grey 200".
+ Dark: image.Uniform{C: color.RGBA{0xe0, 0xe0, 0xe0, 0xff}}, // Material Design "Grey 300".
+ Accent: image.Uniform{C: color.RGBA{0x21, 0x96, 0xf3, 0xff}}, // Material Design "Blue 500".
+ Foreground: image.Uniform{C: color.RGBA{0x00, 0x00, 0x00, 0xff}}, // Material Design "Black".
+ Background: image.Uniform{C: color.RGBA{0xff, 0xff, 0xff, 0xff}}, // Material Design "White".
}
// Default uses the default DPI, FontFaceCatalog and Palette.
diff --git a/shiny/widget/uniform.go b/shiny/widget/uniform.go
index 5597cde..175aad9 100644
--- a/shiny/widget/uniform.go
+++ b/shiny/widget/uniform.go
@@ -6,7 +6,6 @@
import (
"image"
- "image/color"
"image/draw"
"golang.org/x/exp/shiny/widget/node"
@@ -17,13 +16,13 @@
// image.Uniform.
type Uniform struct {
node.ShellEmbed
- Uniform image.Uniform
+ ThemeColor theme.Color
}
// NewUniform returns a new Uniform widget of the given color.
-func NewUniform(c color.Color, inner node.Node) *Uniform {
+func NewUniform(c theme.Color, inner node.Node) *Uniform {
w := &Uniform{
- Uniform: image.Uniform{c},
+ ThemeColor: c,
}
w.Wrapper = w
if inner != nil {
@@ -34,9 +33,9 @@
func (w *Uniform) Paint(t *theme.Theme, dst *image.RGBA, origin image.Point) {
w.Marks.UnmarkNeedsPaint()
- if w.Uniform.C != nil {
+ if w.ThemeColor != nil {
// TODO: should draw.Src be draw.Over?
- draw.Draw(dst, w.Rect.Add(origin), &w.Uniform, image.Point{}, draw.Src)
+ draw.Draw(dst, w.Rect.Add(origin), w.ThemeColor.Uniform(t), image.Point{}, draw.Src)
}
if c := w.FirstChild; c != nil {
c.Wrapper.Paint(t, dst, origin.Add(w.Rect.Min))