Signed-off-by: Alexander Arin <fralx@yandex.ru>
---
example/kitchen/kitchen.go | 22 ++++++++--
widget/enum.go | 51 ++++++++++++++++++++++
widget/material/checkbox.go | 79 ++++++----------------------------
widget/material/chekable.go | 65 ++++++++++++++++++++++++++++
widget/material/material.go | 12 ++++--
widget/material/radiobutton.go | 42 ++++++++++++++++++
6 files changed, 198 insertions(+), 73 deletions(-)
create mode 100644 widget/enum.go
create mode 100644 widget/material/chekable.go
create mode 100644 widget/material/radiobutton.go
diff --git a/example/kitchen/kitchen.go b/example/kitchen/kitchen.go
index e390761..486924e 100644
--- a/example/kitchen/kitchen.go
+++ b/example/kitchen/kitchen.go
@@ -62,10 +62,11 @@ var (
SingleLine: true,
Submit: true,
}
- button = new(widget.Button)
- greenButton = new(widget.Button)
- iconButton = new(widget.Button)
- list = &layout.List{
+ button = new(widget.Button)
+ greenButton = new(widget.Button)
+ iconButton = new(widget.Button)
+ radioButtonsGroup = new(widget.Enum)
+ list = &layout.List{
Axis: layout.Vertical,
}
green = true
@@ -125,6 +126,19 @@ func kitchen(gtx *layout.Context, th *material.Theme) {
func() {
th.CheckBox("Checkbox").Layout(gtx, checkbox)
},
+ func() {
+ group := layout.Flex{}
+ r1 := group.Rigid(gtx, func() {
+ th.RadioButton("r1", "RadioButton1").Layout(gtx, radioButtonsGroup)
+ })
+ r2 := group.Rigid(gtx, func() {
+ th.RadioButton("r2", "RadioButton2").Layout(gtx, radioButtonsGroup)
+ })
+ r3 := group.Rigid(gtx, func() {
+ th.RadioButton("r3", "RadioButton3").Layout(gtx, radioButtonsGroup)
+ })
+ group.Layout(gtx, r1, r2, r3)
+ },
}
list.Layout(gtx, len(widgets), func(i int) {
layout.UniformInset(unit.Dp(16)).Layout(gtx, widgets[i])
diff --git a/widget/enum.go b/widget/enum.go
new file mode 100644
index 0000000..63e35cb
--- /dev/null
+++ b/widget/enum.go
@@ -0,0 +1,51 @@
+package widget
+
+import (
+ "gioui.org/gesture"
+ "gioui.org/layout"
+)
+
+type Enum struct {
+ clicks []gesture.Click
+ values []string
+ value string
+}
+
+func index(vs []string, t string) int {
+ for i, v := range vs {
+ if v == t {
+ return i
+ }
+ }
+ return -1
+}
+
+// Value processes events and returns the last selected value, or
+// the empty string.
+func (e *Enum) Value(gtx *layout.Context) string {
+ for i := range e.clicks {
+ for _, ev := range e.clicks[i].Events(gtx) {
+ switch ev.Type {
+ case gesture.TypeClick:
+ e.value = e.values[i]
+ }
+ }
+ }
+ return e.value
+}
+
+// Layout adds the event handler for key.
+func (rg *Enum) Layout(gtx *layout.Context, key string) {
+ if index(rg.values, key) == -1 {
+ rg.values = append(rg.values, key)
+ rg.clicks = append(rg.clicks, gesture.Click{})
+ rg.clicks[len(rg.clicks)-1].Add(gtx.Ops)
+ } else {
+ idx := index(rg.values, key)
+ rg.clicks[idx].Add(gtx.Ops)
+ }
+}
+
+func (rg *Enum) SetValue(value string) {
+ rg.value = value
+}
diff --git a/widget/material/checkbox.go b/widget/material/checkbox.go
index 1648891..4d1537d 100644
--- a/widget/material/checkbox.go
+++ b/widget/material/checkbox.go
@@ -4,85 +4,34 @@
package material
import (
- "gioui.org/io/pointer"
"gioui.org/layout"
- "gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
"gioui.org/widget"
- "image"
- "image/color"
)
type CheckBox struct {
- Text string
- // Color is the text color.
- Color color.RGBA
- Font text.Font
- IconColor color.RGBA
- Size unit.Value
- shaper *text.Shaper
- checkedStateIcon *Icon
- uncheckedStateIcon *Icon
+ checkable
}
-func (t *Theme) CheckBox(txt string) CheckBox {
+func (t *Theme) CheckBox(label string) CheckBox {
return CheckBox{
- Text: txt,
- Color: t.Color.Text,
- IconColor: t.Color.Primary,
- Font: text.Font{
- Size: t.TextSize.Scale(14.0 / 16.0),
+ checkable{
+ Label: label,
+ Color: t.Color.Text,
+ IconColor: t.Color.Primary,
+ Font: text.Font{
+ Size: t.TextSize.Scale(14.0 / 16.0),
+ },
+ Size: unit.Dp(26),
+ shaper: t.Shaper,
+ checkedStateIcon: t.checkBoxCheckedIcon,
+ uncheckedStateIcon: t.checkBoxUncheckedIcon,
},
- Size: unit.Dp(26),
- shaper: t.Shaper,
- checkedStateIcon: t.checkedStateIcon,
- uncheckedStateIcon: t.uncheckedStateIcon,
}
}
func (c CheckBox) Layout(gtx *layout.Context, checkBox *widget.CheckBox) {
-
- textColor := c.Color
- iconColor := c.IconColor
-
- var icon *Icon
- if checkBox.Checked(gtx) {
- icon = c.checkedStateIcon
- } else {
- icon = c.uncheckedStateIcon
- }
-
- hmin := gtx.Constraints.Width.Min
- vmin := gtx.Constraints.Height.Min
-
- flex := layout.Flex{Alignment: layout.Middle}
-
- ico := flex.Rigid(gtx, func() {
- layout.Align(layout.Center).Layout(gtx, func() {
- layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
- size := gtx.Px(c.Size)
- icon.Color = iconColor
- icon.Layout(gtx, unit.Px(float32(size)))
- gtx.Dimensions = layout.Dimensions{
- Size: image.Point{X: size, Y: size},
- }
- })
- })
- })
-
- lbl := flex.Rigid(gtx, func() {
- gtx.Constraints.Width.Min = hmin
- gtx.Constraints.Height.Min = vmin
- layout.Align(layout.Start).Layout(gtx, func() {
- layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
- paint.ColorOp{Color: textColor}.Add(gtx.Ops)
- widget.Label{}.Layout(gtx, c.shaper, c.Font, c.Text)
- })
- })
- })
-
- flex.Layout(gtx, ico, lbl)
- pointer.RectAreaOp{Rect: image.Rectangle{Max: gtx.Dimensions.Size}}.Add(gtx.Ops)
+ c.layout(gtx, checkBox.Checked(gtx))
checkBox.Layout(gtx)
}
diff --git a/widget/material/chekable.go b/widget/material/chekable.go
new file mode 100644
index 0000000..278b8d3
--- /dev/null
+++ b/widget/material/chekable.go
@@ -0,0 +1,65 @@
+package material
+
+import (
+ "image"
+ "image/color"
+
+ "gioui.org/io/pointer"
+ "gioui.org/layout"
+ "gioui.org/op/paint"
+ "gioui.org/text"
+ "gioui.org/unit"
+ "gioui.org/widget"
+)
+
+type checkable struct {
+ Label string
+ Color color.RGBA
+ Font text.Font
+ IconColor color.RGBA
+ Size unit.Value
+ shaper *text.Shaper
+ checkedStateIcon *Icon
+ uncheckedStateIcon *Icon
+}
+
+func (c *checkable) layout(gtx *layout.Context, checked bool) {
+
+ var icon *Icon
+ if checked {
+ icon = c.checkedStateIcon
+ } else {
+ icon = c.uncheckedStateIcon
+ }
+
+ hmin := gtx.Constraints.Width.Min
+ vmin := gtx.Constraints.Height.Min
+ flex := layout.Flex{Alignment: layout.Middle}
+
+ ico := flex.Rigid(gtx, func() {
+ layout.Align(layout.Center).Layout(gtx, func() {
+ layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
+ size := gtx.Px(c.Size)
+ icon.Color = c.IconColor
+ icon.Layout(gtx, unit.Px(float32(size)))
+ gtx.Dimensions = layout.Dimensions{
+ Size: image.Point{X: size, Y: size},
+ }
+ })
+ })
+ })
+
+ lbl := flex.Rigid(gtx, func() {
+ gtx.Constraints.Width.Min = hmin
+ gtx.Constraints.Height.Min = vmin
+ layout.Align(layout.Start).Layout(gtx, func() {
+ layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
+ paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
+ widget.Label{}.Layout(gtx, c.shaper, c.Font, c.Label)
+ })
+ })
+ })
+
+ flex.Layout(gtx, ico, lbl)
+ pointer.RectAreaOp{Rect: image.Rectangle{Max: gtx.Dimensions.Size}}.Add(gtx.Ops)
+}
diff --git a/widget/material/material.go b/widget/material/material.go
index d5b70db..1b73af0 100644
--- a/widget/material/material.go
+++ b/widget/material/material.go
@@ -26,8 +26,10 @@ type Theme struct {
InvText color.RGBA
}
TextSize unit.Value
- checkedStateIcon *Icon
- uncheckedStateIcon *Icon
+ checkBoxCheckedIcon *Icon
+ checkBoxUncheckedIcon *Icon
+ radioCheckedIcon *Icon
+ radioUncheckedIcon *Icon
}
func NewTheme() *Theme {
@@ -40,8 +42,10 @@ func NewTheme() *Theme {
t.Color.InvText = rgb(0xffffff)
t.TextSize = unit.Sp(16)
- t.checkedStateIcon = mustIcon(NewIcon(icons.ToggleCheckBox))
- t.uncheckedStateIcon = mustIcon(NewIcon(icons.ToggleCheckBoxOutlineBlank))
+ t.checkBoxCheckedIcon = mustIcon(NewIcon(icons.ToggleCheckBox))
+ t.checkBoxUncheckedIcon = mustIcon(NewIcon(icons.ToggleCheckBoxOutlineBlank))
+ t.radioCheckedIcon = mustIcon(NewIcon(icons.ToggleRadioButtonChecked))
+ t.radioUncheckedIcon = mustIcon(NewIcon(icons.ToggleRadioButtonUnchecked))
return t
}
diff --git a/widget/material/radiobutton.go b/widget/material/radiobutton.go
new file mode 100644
index 0000000..9a9a008
--- /dev/null
+++ b/widget/material/radiobutton.go
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: Unlicense OR MIT
+
+// Package material implements the Material design.
+package material
+
+import (
+ "gioui.org/layout"
+ "gioui.org/text"
+ "gioui.org/unit"
+ "gioui.org/widget"
+)
+
+type RadioButton struct {
+ checkable
+ Key string
+}
+
+// RadioButton returns a RadioButton with a label. The key specifies
+// the value for the Enum.
+func (t *Theme) RadioButton(key, label string) RadioButton {
+ return RadioButton{
+ checkable: checkable{
+ Label: label,
+
+ Color: t.Color.Text,
+ IconColor: t.Color.Primary,
+ Font: text.Font{
+ Size: t.TextSize.Scale(14.0 / 16.0),
+ },
+ Size: unit.Dp(26),
+ shaper: t.Shaper,
+ checkedStateIcon: t.radioCheckedIcon,
+ uncheckedStateIcon: t.radioUncheckedIcon,
+ },
+ Key: key,
+ }
+}
+
+func (r RadioButton) Layout(gtx *layout.Context, enum *widget.Enum) {
+ r.layout(gtx, enum.Value(gtx) == r.Key)
+ enum.Layout(gtx, r.Key)
+}
--
2.18.0.windows.1