passgo/cmd/passgo-gui/ui.go

146 lines
3.7 KiB
Go

package main
import (
"image"
"image/color"
"gioui.org/f32"
"gioui.org/gesture"
"gioui.org/io/pointer"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/unit"
)
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 {
Size unit.Value
Text string
Click gesture.Click
Color color.RGBA
Background color.RGBA
Alignment text.Alignment
}
func (b *Overlay) Layout(gtx *layout.Context, family text.Family) {
ins := layout.UniformInset(unit.Dp(1))
ins.Layout(gtx, func() {
st := layout.Stack{}
c2 := st.Rigid(gtx, func() {
l := text.Label{
Size: b.Size,
Text: b.Text,
Alignment: b.Alignment,
}
ins := layout.UniformInset(unit.Dp(4))
l.Material.Record(gtx.Ops)
paint.ColorOp{Color: b.Color}.Add(gtx.Ops)
l.Material.Stop()
ins.Layout(gtx, func() {
l.Layout(gtx, family)
})
pointer.RectAreaOp{image.Rect(0, 0, gtx.Dimensions.Size.X, gtx.Dimensions.Size.Y)}.Add(gtx.Ops)
})
c1 := st.Expand(gtx, func() {
layoutRRect(b.Background, gtx)
})
st.Layout(gtx, c1, c2)
})
}
type SelButton struct {
Button
SelColor color.RGBA
Selected bool
}
type Button struct {
Size unit.Value
Label string
Click gesture.Click
Color color.RGBA
Background color.RGBA
Alignment text.Alignment
clicked bool
}
func layoutRRect(col color.RGBA, gtx *layout.Context) {
r := float32(gtx.Config.Px(unit.Dp(4)))
sz := image.Point{X: gtx.Constraints.Width.Min, Y: gtx.Constraints.Height.Min}
w, h := float32(sz.X), float32(sz.Y)
rrect(gtx.Ops, w, h, r, r, r, r)
paint.ColorOp{Color: col}.Add(gtx.Ops)
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: w, Y: h}}}.Add(gtx.Ops)
gtx.Dimensions = layout.Dimensions{Size: sz}
}
// https://pomax.github.io/bezierinfo/#circles_cubic.
func rrect(ops *op.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.Path
b.Begin(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(gtx *layout.Context, family text.Family) {
b.clicked = false
for _, ev := range b.Click.Events(gtx) {
if ev.Type == gesture.TypeClick {
b.clicked = true
}
}
ins := layout.UniformInset(unit.Dp(1))
ins.Layout(gtx, func() {
st := layout.Stack{}
c2 := st.Rigid(gtx, func() {
l := text.Label{
Size: b.Size,
Text: b.Label,
Alignment: b.Alignment,
}
ins := layout.UniformInset(unit.Dp(4))
//paint.ColorOp{Color: b.Color}.Add(ops)
ins.Layout(gtx, func() {
l.Layout(gtx, family)
})
pointer.RectAreaOp{image.Rect(0, 0, gtx.Dimensions.Size.X, gtx.Dimensions.Size.Y)}.Add(gtx.Ops)
b.Click.Add(gtx.Ops)
})
c1 := st.Expand(gtx, func() {
layoutRRect(b.Background, gtx)
})
st.Layout(gtx, c1, c2)
})
}
func (b *Button) Clicked() bool {
return b.clicked
}
func (b *SelButton) Clicked() bool {
if b.clicked {
b.Selected = !b.Selected
b.SelColor, b.Background = b.Background, b.SelColor
return true
} else {
return false
}
}