passgo/cmd/passgo-gui/ui.go

130 lines
3.6 KiB
Go

package main
import (
"image"
"image/color"
"gioui.org/ui"
"gioui.org/ui/f32"
"gioui.org/ui/gesture"
"gioui.org/ui/input"
"gioui.org/ui/layout"
"gioui.org/ui/paint"
"gioui.org/ui/pointer"
"gioui.org/ui/text"
)
var (
black = color.RGBA{A: 0xff, R: 0, G: 0, B: 0}
white = color.RGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}
gray = color.RGBA{A: 0xff, R: 0xf0, G: 0xf0, B: 0xf0}
darkgray = color.RGBA{A: 0xff, R: 0xa0, G: 0xa0, B: 0xa0}
)
type Overlay struct {
Face text.Face
Text string
Click gesture.Click
Color color.RGBA
Background color.RGBA
Alignment text.Alignment
}
func (b *Overlay) Layout(c ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
ins := layout.UniformInset(ui.Dp(1))
cs = ins.Begin(c, ops, cs)
var dims layout.Dimensions
st := layout.Stack{}
st.Init(ops, cs)
{
cs = st.Rigid()
l := text.Label{
Face: b.Face,
Text: b.Text,
Alignment: b.Alignment,
}
ins := layout.UniformInset(ui.Dp(4))
l.Material.Record(ops)
paint.ColorOp{Color: b.Color}.Add(ops)
l.Material.Stop()
dims = ins.End(l.Layout(ops, ins.Begin(c, ops, cs)))
pointer.RectAreaOp{image.Rect(0, 0, dims.Size.X, dims.Size.Y)}.Add(ops)
}
c2 := st.End(dims)
c1 := st.End(layoutRRect(b.Background, c, ops, st.Expand()))
dims = st.Layout(c1, c2)
return ins.End(dims)
}
type Button struct {
Face text.Face
Label string
Click gesture.Click
Color color.RGBA
Background color.RGBA
Alignment text.Alignment
clicked bool
}
func layoutRRect(col color.RGBA, c ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
r := float32(c.Px(ui.Dp(4)))
sz := image.Point{X: cs.Width.Min, Y: cs.Height.Min}
w, h := float32(sz.X), float32(sz.Y)
rrect(ops, w, h, r, r, r, r)
paint.ColorOp{Color: col}.Add(ops)
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: w, Y: h}}}.Add(ops)
return layout.Dimensions{Size: sz}
}
// https://pomax.github.io/bezierinfo/#circles_cubic.
func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
w, h := float32(width), float32(height)
const c = 0.55228475 // 4*(sqrt(2)-1)/3
var b paint.PathBuilder
b.Init(ops)
b.Move(f32.Point{X: w, Y: h - se})
b.Cube(f32.Point{X: 0, Y: se * c}, f32.Point{X: -se + se*c, Y: se}, f32.Point{X: -se, Y: se}) // SE
b.Line(f32.Point{X: sw - w + se, Y: 0})
b.Cube(f32.Point{X: -sw * c, Y: 0}, f32.Point{X: -sw, Y: -sw + sw*c}, f32.Point{X: -sw, Y: -sw}) // SW
b.Line(f32.Point{X: 0, Y: nw - h + sw})
b.Cube(f32.Point{X: 0, Y: -nw * c}, f32.Point{X: nw - nw*c, Y: -nw}, f32.Point{X: nw, Y: -nw}) // NW
b.Line(f32.Point{X: w - ne - nw, Y: 0})
b.Cube(f32.Point{X: ne * c, Y: 0}, f32.Point{X: ne, Y: ne - ne*c}, f32.Point{X: ne, Y: ne}) // NE
b.End()
}
func (b *Button) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
b.clicked = false
for ev, ok := b.Click.Next(q); ok; ev, ok = b.Click.Next(q) {
if ev.Type == gesture.TypeClick {
b.clicked = true
}
}
ins := layout.UniformInset(ui.Dp(1))
cs = ins.Begin(c, ops, cs)
var dims layout.Dimensions
st := layout.Stack{}
st.Init(ops, cs)
{
cs = st.Rigid()
l := text.Label{
Face: b.Face,
Text: b.Label,
Alignment: b.Alignment,
}
ins := layout.UniformInset(ui.Dp(4))
//paint.ColorOp{Color: b.Color}.Add(ops)
dims = ins.End(l.Layout(ops, ins.Begin(c, ops, cs)))
pointer.RectAreaOp{image.Rect(0, 0, dims.Size.X, dims.Size.Y)}.Add(ops)
b.Click.Add(ops)
}
c2 := st.End(dims)
c1 := st.End(layoutRRect(b.Background, c, ops, st.Expand()))
dims = st.Layout(c1, c2)
return ins.End(dims)
}
func (b *Button) Clicked() bool {
return b.clicked
}