139 lines
3.6 KiB
Go
139 lines
3.6 KiB
Go
package gel
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
|
|
l "gioui.org/layout"
|
|
"gioui.org/op"
|
|
"gioui.org/op/clip"
|
|
"gioui.org/op/paint"
|
|
"gioui.org/unit"
|
|
|
|
"git.mleku.dev/mleku/prevara/f32color"
|
|
)
|
|
|
|
type Switch struct {
|
|
*Window
|
|
color struct {
|
|
enabled color.NRGBA
|
|
disabled color.NRGBA
|
|
}
|
|
swtch *Bool
|
|
}
|
|
|
|
// Switch creates a boolean switch widget (basically a checkbox but looks like a switch)
|
|
func (w *Window) Switch(swtch *Bool) *Switch {
|
|
sw := &Switch{
|
|
Window: w,
|
|
swtch: swtch,
|
|
}
|
|
sw.color.enabled = w.Colors.GetNRGBAFromName("Primary")
|
|
sw.color.disabled = w.Colors.GetNRGBAFromName("scrim")
|
|
return sw
|
|
}
|
|
|
|
// EnabledColor sets the color to draw for the enabled state
|
|
func (s *Switch) EnabledColor(color string) *Switch {
|
|
s.color.enabled = s.Theme.Colors.GetNRGBAFromName(color)
|
|
return s
|
|
}
|
|
|
|
// DisabledColor sets the color to draw for the disabled state
|
|
func (s *Switch) DisabledColor(color string) *Switch {
|
|
s.color.disabled = s.Theme.Colors.GetNRGBAFromName(color)
|
|
return s
|
|
}
|
|
|
|
func (s *Switch) SetHook(fn func(b bool)) *Switch {
|
|
s.swtch.SetOnChange(fn)
|
|
return s
|
|
}
|
|
|
|
// Fn updates the switch and displays it.
|
|
func (s *Switch) Fn(gtx l.Context) l.Dimensions {
|
|
return s.Inset(0.25, func(gtx l.Context) l.Dimensions {
|
|
trackWidth := gtx.Dp(unit.Dp(float32(s.Theme.TextSize) * 2.5))
|
|
trackHeight := gtx.Dp(unit.Dp(16))
|
|
thumbSize := gtx.Dp(unit.Dp(20))
|
|
trackOff := (thumbSize - trackHeight) / 2
|
|
|
|
// Draw track.
|
|
trackCorner := trackHeight / 2
|
|
trackRect := image.Rectangle{Max: image.Pt(trackWidth, trackHeight)}
|
|
col := s.color.disabled
|
|
if s.swtch.value {
|
|
col = s.color.enabled
|
|
}
|
|
if !gtx.Source.Enabled() {
|
|
col = f32color.MulAlpha(col, 150)
|
|
}
|
|
trackColor := f32color.MulAlpha(col, 200)
|
|
stack := op.Offset(image.Pt(0, trackOff)).Push(gtx.Ops)
|
|
clip.UniformRRect(trackRect, trackCorner).Push(gtx.Ops).Pop()
|
|
paint.ColorOp{Color: trackColor}.Add(gtx.Ops)
|
|
paint.PaintOp{}.Add(gtx.Ops)
|
|
stack.Pop()
|
|
|
|
// Draw thumb ink.
|
|
inkSize := gtx.Dp(unit.Dp(44))
|
|
rr := inkSize / 2
|
|
inkOff := image.Pt(
|
|
trackWidth/2-rr,
|
|
-rr+trackHeight/2+trackOff,
|
|
)
|
|
stack2 := op.Offset(inkOff).Push(gtx.Ops)
|
|
gtx.Constraints.Min = image.Pt(inkSize, inkSize)
|
|
clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
|
for _, p := range s.swtch.History() {
|
|
drawInk(gtx, p)
|
|
}
|
|
stack2.Pop()
|
|
|
|
// Compute thumb offset and color.
|
|
var stack3 op.TransformStack
|
|
if s.swtch.value {
|
|
off := trackWidth - thumbSize
|
|
stack3 = op.Offset(image.Pt(off, 0)).Push(gtx.Ops)
|
|
} else {
|
|
stack3 = op.Offset(image.Pt(0, 0)).Push(gtx.Ops)
|
|
}
|
|
|
|
// Draw thumb shadow, a translucent disc slightly larger than the
|
|
// thumb itself.
|
|
shadowSize := 2
|
|
// Center shadow horizontally and slightly adjust its Y.
|
|
shadowStack := op.Offset(image.Pt(-shadowSize/2, -1)).Push(gtx.Ops)
|
|
drawDisc(gtx.Ops, thumbSize+shadowSize, color.NRGBA(argb(0x55000000)))
|
|
shadowStack.Pop()
|
|
|
|
// Draw thumb.
|
|
drawDisc(gtx.Ops, thumbSize, col)
|
|
stack3.Pop()
|
|
|
|
// Set up click area.
|
|
clickSize := gtx.Dp(unit.Dp(40))
|
|
clickOff := image.Pt(
|
|
(trackWidth-clickSize)/2,
|
|
(trackHeight-clickSize)/2+trackOff,
|
|
)
|
|
stack4 := op.Offset(clickOff).Push(gtx.Ops)
|
|
sz := image.Pt(clickSize, clickSize)
|
|
defer clip.Ellipse(image.Rectangle{Max: sz}).Push(gtx.Ops).Pop()
|
|
gtx.Constraints.Min = sz
|
|
s.swtch.Fn(gtx)
|
|
stack4.Pop()
|
|
|
|
dims := image.Point{X: trackWidth, Y: thumbSize}
|
|
return l.Dimensions{Size: dims}
|
|
}).Fn(gtx)
|
|
}
|
|
|
|
func drawDisc(ops *op.Ops, sz int, col color.NRGBA) {
|
|
rr := sz / 2
|
|
r := image.Rectangle{Max: image.Pt(sz, sz)}
|
|
defer clip.UniformRRect(r, rr).Push(ops).Pop()
|
|
paint.ColorOp{Color: col}.Add(ops)
|
|
paint.PaintOp{}.Add(ops)
|
|
}
|