diff --git a/cmd/passgo-gui/main.go b/cmd/passgo-gui/main.go index 24043c0..e8f2b5d 100644 --- a/cmd/passgo-gui/main.go +++ b/cmd/passgo-gui/main.go @@ -3,8 +3,6 @@ package main import ( - "image" - "image/color" "io/ioutil" "os" "path" @@ -14,14 +12,9 @@ import ( "gioui.org/ui" "gioui.org/ui/app" - "gioui.org/ui/f32" - "gioui.org/ui/gesture" - "gioui.org/ui/input" "gioui.org/ui/key" "gioui.org/ui/layout" "gioui.org/ui/measure" - "gioui.org/ui/paint" - "gioui.org/ui/pointer" "gioui.org/ui/text" "github.com/fsnotify/fsnotify" @@ -82,10 +75,6 @@ var ( reload chan struct{} updated chan struct{} passch chan []byte - 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} ) func Updater() { @@ -129,6 +118,7 @@ func saveConf(fds ...*os.File) { log(Fatal, "Cannot open config file: ", err) } } + defer fd.Close() confbytes, err := yaml.Marshal(Config) if err != nil { @@ -140,113 +130,6 @@ func saveConf(fds ...*os.File) { } } -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 -} - func eventLoop() { w := app.NewWindow(app.WithWidth(ui.Dp(250))) q := w.Queue() diff --git a/cmd/passgo-gui/ui.go b/cmd/passgo-gui/ui.go new file mode 100644 index 0000000..cd9b161 --- /dev/null +++ b/cmd/passgo-gui/ui.go @@ -0,0 +1,130 @@ +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 +} +