mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 17:35:36 +00:00
widgets, widgets/material: add RadioButton & Enum
Signed-off-by: Alexander Arin <fralx@yandex.ru>
This commit is contained in:
committed by
Elias Naur
parent
82e51019e1
commit
089ae31f0c
@@ -62,10 +62,11 @@ var (
|
|||||||
SingleLine: true,
|
SingleLine: true,
|
||||||
Submit: true,
|
Submit: true,
|
||||||
}
|
}
|
||||||
button = new(widget.Button)
|
button = new(widget.Button)
|
||||||
greenButton = new(widget.Button)
|
greenButton = new(widget.Button)
|
||||||
iconButton = new(widget.Button)
|
iconButton = new(widget.Button)
|
||||||
list = &layout.List{
|
radioButtonsGroup = new(widget.Enum)
|
||||||
|
list = &layout.List{
|
||||||
Axis: layout.Vertical,
|
Axis: layout.Vertical,
|
||||||
}
|
}
|
||||||
green = true
|
green = true
|
||||||
@@ -125,6 +126,19 @@ func kitchen(gtx *layout.Context, th *material.Theme) {
|
|||||||
func() {
|
func() {
|
||||||
th.CheckBox("Checkbox").Layout(gtx, checkbox)
|
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) {
|
list.Layout(gtx, len(widgets), func(i int) {
|
||||||
layout.UniformInset(unit.Dp(16)).Layout(gtx, widgets[i])
|
layout.UniformInset(unit.Dp(16)).Layout(gtx, widgets[i])
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
+14
-65
@@ -4,85 +4,34 @@
|
|||||||
package material
|
package material
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gioui.org/io/pointer"
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op/paint"
|
|
||||||
"gioui.org/text"
|
"gioui.org/text"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CheckBox struct {
|
type CheckBox struct {
|
||||||
Text string
|
checkable
|
||||||
// Color is the text color.
|
|
||||||
Color color.RGBA
|
|
||||||
Font text.Font
|
|
||||||
IconColor color.RGBA
|
|
||||||
Size unit.Value
|
|
||||||
shaper *text.Shaper
|
|
||||||
checkedStateIcon *Icon
|
|
||||||
uncheckedStateIcon *Icon
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Theme) CheckBox(txt string) CheckBox {
|
func (t *Theme) CheckBox(label string) CheckBox {
|
||||||
return CheckBox{
|
return CheckBox{
|
||||||
Text: txt,
|
checkable{
|
||||||
Color: t.Color.Text,
|
Label: label,
|
||||||
IconColor: t.Color.Primary,
|
Color: t.Color.Text,
|
||||||
Font: text.Font{
|
IconColor: t.Color.Primary,
|
||||||
Size: t.TextSize.Scale(14.0 / 16.0),
|
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) {
|
func (c CheckBox) Layout(gtx *layout.Context, checkBox *widget.CheckBox) {
|
||||||
|
c.layout(gtx, checkBox.Checked(gtx))
|
||||||
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)
|
|
||||||
checkBox.Layout(gtx)
|
checkBox.Layout(gtx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -25,8 +25,10 @@ type Theme struct {
|
|||||||
InvText color.RGBA
|
InvText color.RGBA
|
||||||
}
|
}
|
||||||
TextSize unit.Value
|
TextSize unit.Value
|
||||||
checkedStateIcon *Icon
|
checkBoxCheckedIcon *Icon
|
||||||
uncheckedStateIcon *Icon
|
checkBoxUncheckedIcon *Icon
|
||||||
|
radioCheckedIcon *Icon
|
||||||
|
radioUncheckedIcon *Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTheme() *Theme {
|
func NewTheme() *Theme {
|
||||||
@@ -39,8 +41,10 @@ func NewTheme() *Theme {
|
|||||||
t.Color.InvText = rgb(0xffffff)
|
t.Color.InvText = rgb(0xffffff)
|
||||||
t.TextSize = unit.Sp(16)
|
t.TextSize = unit.Sp(16)
|
||||||
|
|
||||||
t.checkedStateIcon = mustIcon(NewIcon(icons.ToggleCheckBox))
|
t.checkBoxCheckedIcon = mustIcon(NewIcon(icons.ToggleCheckBox))
|
||||||
t.uncheckedStateIcon = mustIcon(NewIcon(icons.ToggleCheckBoxOutlineBlank))
|
t.checkBoxUncheckedIcon = mustIcon(NewIcon(icons.ToggleCheckBoxOutlineBlank))
|
||||||
|
t.radioCheckedIcon = mustIcon(NewIcon(icons.ToggleRadioButtonChecked))
|
||||||
|
t.radioUncheckedIcon = mustIcon(NewIcon(icons.ToggleRadioButtonUnchecked))
|
||||||
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user