From 2a06f3d3b26115786b3c6994dc92789911b7ae85 Mon Sep 17 00:00:00 2001 From: Alexander Arin Date: Sun, 3 Nov 2019 18:11:18 +0300 Subject: [PATCH] widget/material: move Icon to its own file and add Color; add CornerRadius to Button --- widget/material/button.go | 62 +++++------------------------------ widget/material/icon.go | 64 +++++++++++++++++++++++++++++++++++++ widget/material/material.go | 18 ++++++++++- 3 files changed, 89 insertions(+), 55 deletions(-) create mode 100644 widget/material/icon.go diff --git a/widget/material/button.go b/widget/material/button.go index 30fbc323..10cc26c6 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -6,7 +6,6 @@ package material import ( "image" "image/color" - "image/draw" "gioui.org/f32" "gioui.org/io/pointer" @@ -16,35 +15,26 @@ import ( "gioui.org/text" "gioui.org/unit" "gioui.org/widget" - "golang.org/x/exp/shiny/iconvg" ) type Button struct { Text string // Color is the text color. - Color color.RGBA - Font text.Font - Background color.RGBA - - shaper *text.Shaper + Color color.RGBA + Font text.Font + Background color.RGBA + CornerRadius unit.Value + shaper *text.Shaper } type IconButton struct { Background color.RGBA + Color color.RGBA Icon *Icon Size unit.Value Padding unit.Value } -type Icon struct { - src []byte - size unit.Value - - // Cached values. - op paint.ImageOp - imgSize int -} - func (t *Theme) Button(txt string) Button { return Button{ Text: txt, @@ -57,18 +47,10 @@ func (t *Theme) Button(txt string) Button { } } -// NewIcon returns a new Icon from IconVG data. -func NewIcon(data []byte) (*Icon, error) { - _, err := iconvg.DecodeMetadata(data) - if err != nil { - return nil, err - } - return &Icon{src: data}, nil -} - func (t *Theme) IconButton(icon *Icon) IconButton { return IconButton{ Background: t.Color.Primary, + Color: t.Color.InvText, Icon: icon, Size: unit.Dp(56), Padding: unit.Dp(16), @@ -114,6 +96,7 @@ func (b IconButton) Layout(gtx *layout.Context, button *widget.Button) { layout.UniformInset(b.Padding).Layout(gtx, func() { size := gtx.Px(b.Size) - 2*gtx.Px(b.Padding) if b.Icon != nil { + b.Icon.Color = b.Color b.Icon.Layout(gtx, unit.Px(float32(size))) } gtx.Dimensions = layout.Dimensions{ @@ -140,35 +123,6 @@ func (b IconButton) Layout(gtx *layout.Context, button *widget.Button) { st.Layout(gtx, bg, ico) } -func (ic *Icon) Layout(gtx *layout.Context, sz unit.Value) { - ico := ic.image(gtx.Px(sz)) - ico.Add(gtx.Ops) - paint.PaintOp{ - Rect: f32.Rectangle{ - Max: toPointF(ico.Size()), - }, - }.Add(gtx.Ops) -} - -func (ic *Icon) image(sz int) paint.ImageOp { - if sz == ic.imgSize { - return ic.op - } - m, _ := iconvg.DecodeMetadata(ic.src) - dx, dy := m.ViewBox.AspectRatio() - img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz, Y: int(float32(sz) * dy / dx)}}) - var ico iconvg.Rasterizer - ico.SetDstImage(img, img.Bounds(), draw.Src) - // Use white for icons. - m.Palette[0] = color.RGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff} - iconvg.Decode(&ico, ic.src, &iconvg.DecodeOptions{ - Palette: &m.Palette, - }) - ic.op = paint.NewImageOp(img) - ic.imgSize = sz - return ic.op -} - func toPointF(p image.Point) f32.Point { return f32.Point{X: float32(p.X), Y: float32(p.Y)} } diff --git a/widget/material/icon.go b/widget/material/icon.go new file mode 100644 index 00000000..24df0e98 --- /dev/null +++ b/widget/material/icon.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// Package material implements the Material design. +package material + +import ( + "image" + "image/color" + "image/draw" + + "gioui.org/f32" + "gioui.org/layout" + "gioui.org/op/paint" + "gioui.org/unit" + "golang.org/x/exp/shiny/iconvg" +) + +type Icon struct { + Color color.RGBA + src []byte + size unit.Value + // Cached values. + op paint.ImageOp + imgSize int + imgColor color.RGBA +} + +// NewIcon returns a new Icon from IconVG data. +func NewIcon(data []byte) (*Icon, error) { + _, err := iconvg.DecodeMetadata(data) + if err != nil { + return nil, err + } + return &Icon{src: data, Color: rgb(0x000000)}, nil +} + +func (ic *Icon) Layout(gtx *layout.Context, sz unit.Value) { + ico := ic.image(gtx.Px(sz)) + ico.Add(gtx.Ops) + paint.PaintOp{ + Rect: f32.Rectangle{ + Max: toPointF(ico.Size()), + }, + }.Add(gtx.Ops) +} + +func (ic *Icon) image(sz int) paint.ImageOp { + if sz == ic.imgSize && ic.Color == ic.imgColor { + return ic.op + } + m, _ := iconvg.DecodeMetadata(ic.src) + dx, dy := m.ViewBox.AspectRatio() + img := image.NewRGBA(image.Rectangle{Max: image.Point{X: sz, Y: int(float32(sz) * dy / dx)}}) + var ico iconvg.Rasterizer + ico.SetDstImage(img, img.Bounds(), draw.Src) + m.Palette[0] = ic.Color + iconvg.Decode(&ico, ic.src, &iconvg.DecodeOptions{ + Palette: &m.Palette, + }) + ic.op = paint.NewImageOp(img) + ic.imgSize = sz + ic.imgColor = ic.Color + return ic.op +} diff --git a/widget/material/material.go b/widget/material/material.go index 4bd44c23..d5b70dba 100644 --- a/widget/material/material.go +++ b/widget/material/material.go @@ -14,6 +14,7 @@ import ( "gioui.org/op/paint" "gioui.org/text" "gioui.org/unit" + "golang.org/x/exp/shiny/materialdesign/icons" ) type Theme struct { @@ -22,8 +23,11 @@ type Theme struct { Primary color.RGBA Text color.RGBA Hint color.RGBA + InvText color.RGBA } - TextSize unit.Value + TextSize unit.Value + checkedStateIcon *Icon + uncheckedStateIcon *Icon } func NewTheme() *Theme { @@ -33,10 +37,22 @@ func NewTheme() *Theme { t.Color.Primary = rgb(0x3f51b5) t.Color.Text = rgb(0x000000) t.Color.Hint = rgb(0xbbbbbb) + t.Color.InvText = rgb(0xffffff) t.TextSize = unit.Sp(16) + + t.checkedStateIcon = mustIcon(NewIcon(icons.ToggleCheckBox)) + t.uncheckedStateIcon = mustIcon(NewIcon(icons.ToggleCheckBoxOutlineBlank)) + return t } +func mustIcon(ic *Icon, err error) *Icon { + if err != nil { + panic(err) + } + return ic +} + func rgb(c uint32) color.RGBA { return argb(0xff000000 | c) }