Compare commits
4 Commits
23df75fd15
...
fdb655c671
Author | SHA1 | Date | |
---|---|---|---|
fdb655c671 | |||
0f984918ea | |||
49ebf55b15 | |||
455a8960e5 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ cmd/passgo/passgo
|
|||
cmd/passgo-gui/passgo-gui
|
||||
nohup.out
|
||||
*.apk
|
||||
cpuprofile
|
||||
|
|
|
@ -3,20 +3,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gioui.org/ui"
|
||||
"gioui.org/ui/app"
|
||||
"gioui.org/ui/key"
|
||||
"gioui.org/ui/layout"
|
||||
"gioui.org/ui/measure"
|
||||
"gioui.org/ui/text"
|
||||
"gioui.org/app"
|
||||
"gioui.org/io/key"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/text"
|
||||
"gioui.org/text/shape"
|
||||
"gioui.org/unit"
|
||||
|
||||
"golang.org/x/image/font/sfnt"
|
||||
|
||||
|
@ -33,6 +36,24 @@ type conf struct {
|
|||
}
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
f, err := os.Create("cpuprofile")
|
||||
if err != nil {
|
||||
fmt.Printf("Can't create CPU profile\n")
|
||||
os.Exit(-1)
|
||||
}
|
||||
fmt.Printf("Starting CPU profile\n")
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
fmt.Printf("Can't start CPU profile\n")
|
||||
f.Close()
|
||||
os.Exit(-1)
|
||||
}
|
||||
time.Sleep(time.Second * 10)
|
||||
fmt.Printf("Stopping CPU profile\n")
|
||||
pprof.StopCPUProfile()
|
||||
f.Close()
|
||||
fmt.Printf("CPU profile written\n")
|
||||
}()
|
||||
var fd *os.File
|
||||
confFile := path.Join(confDir, "config.yml")
|
||||
if _, err := os.Stat(confFile); os.IsNotExist(err) {
|
||||
|
@ -94,6 +115,7 @@ var (
|
|||
|
||||
func Updater() {
|
||||
update := func() {
|
||||
fmt.Printf("update()\n")
|
||||
ltmp, err := store.List()
|
||||
if err != nil {
|
||||
log(Info, err)
|
||||
|
@ -155,24 +177,21 @@ func saveConf(fds ...*os.File) {
|
|||
|
||||
func eventLoop() {
|
||||
w := app.NewWindow(
|
||||
app.WithWidth(ui.Dp(250)),
|
||||
app.WithTitle("passgo"))
|
||||
q := w.Queue()
|
||||
var c ui.Config
|
||||
ops := new(ui.Ops)
|
||||
var dims layout.Dimensions
|
||||
var cs layout.Constraints
|
||||
app.Size(unit.Dp(250), unit.Dp(500)),
|
||||
app.Title("passgo"))
|
||||
gtx := &layout.Context{Queue: w.Queue()}
|
||||
|
||||
var margincs layout.Constraints
|
||||
var faces measure.Faces
|
||||
family := &shape.Family{Regular: regular}
|
||||
|
||||
var c1 layout.FlexChild // flex child for title bar
|
||||
face := faces.For(regular, ui.Sp(16))
|
||||
|
||||
sysinset := &layout.Inset{}
|
||||
margin := layout.UniformInset(ui.Dp(10))
|
||||
margin := layout.UniformInset(unit.Dp(10))
|
||||
|
||||
title := &text.Label{Face: face, Text: "passgo"}
|
||||
title := &text.Label{Size: unit.Sp(16), Text: "passgo"}
|
||||
dotsBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "\xe2\x8b\xae",
|
||||
Alignment: text.Middle,
|
||||
Color: black,
|
||||
|
@ -185,12 +204,12 @@ func eventLoop() {
|
|||
lst := &layout.List{Axis: layout.Vertical}
|
||||
passBtns := make([]*Button, 0)
|
||||
pathnames := make([]string, 0)
|
||||
copied := &Overlay{Face: face, Text: "copied to clipboard",
|
||||
copied := &Overlay{Size: unit.Sp(16), Text: "copied to clipboard",
|
||||
Color: black,
|
||||
Background: darkgray,
|
||||
Alignment: text.Middle,
|
||||
}
|
||||
cleared := &Overlay{Face: face, Text: "clipboard cleared",
|
||||
cleared := &Overlay{Size: unit.Sp(16), Text: "clipboard cleared",
|
||||
Color: black,
|
||||
Background: darkgray,
|
||||
Alignment: text.Middle,
|
||||
|
@ -210,7 +229,7 @@ func eventLoop() {
|
|||
z = "/"
|
||||
}
|
||||
passBtns = append(passBtns, &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: strings.Join([]string{s, n, z}, ""),
|
||||
Background: gray,
|
||||
})
|
||||
|
@ -231,7 +250,7 @@ func eventLoop() {
|
|||
for i, n := range ids {
|
||||
if i >= len(idBtns) {
|
||||
idBtns = append(idBtns, &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: n,
|
||||
Alignment: text.End,
|
||||
Color: black,
|
||||
|
@ -245,70 +264,70 @@ func eventLoop() {
|
|||
}
|
||||
|
||||
confBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "configure",
|
||||
Alignment: text.Middle,
|
||||
Color: black,
|
||||
Background: gray,
|
||||
}
|
||||
|
||||
storeDirLabel := &text.Label{Face: face, Text: "Store directory"}
|
||||
storeDirEd := &text.Editor{Face: face, SingleLine: true}
|
||||
storeDirLabel := &text.Label{Size: unit.Sp(16), Text: "Store directory"}
|
||||
storeDirEd := &text.Editor{Size: unit.Sp(16), Family: family, SingleLine: true}
|
||||
storeDirEd.SetText(store.Dir)
|
||||
saveBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "save",
|
||||
Alignment: text.End,
|
||||
Color: black,
|
||||
Background: gray,
|
||||
}
|
||||
backBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "back",
|
||||
Alignment: text.End,
|
||||
Color: black,
|
||||
Background: gray,
|
||||
}
|
||||
confirmLabel := &text.Label{Face: face, Text: "Password exists. Overwrite?"}
|
||||
confirmLabel := &text.Label{Size: unit.Sp(16), Text: "Password exists. Overwrite?"}
|
||||
yesBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "yes",
|
||||
Alignment: text.End,
|
||||
Color: black,
|
||||
Background: gray,
|
||||
}
|
||||
|
||||
promptLabel := &text.Label{Face: face, Text: "passphrase"}
|
||||
promptEd := &text.Editor{Face: face, SingleLine: true, Submit: true}
|
||||
promptLabel := &text.Label{Size: unit.Sp(16), Text: "passphrase"}
|
||||
promptEd := &text.Editor{Size: unit.Sp(16), Family: family, SingleLine: true, Submit: true}
|
||||
okBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "ok",
|
||||
Alignment: text.End,
|
||||
Color: black,
|
||||
Background: gray,
|
||||
}
|
||||
plusBtn := &Button{
|
||||
Face: face,
|
||||
Size: unit.Sp(16),
|
||||
Label: "+",
|
||||
Alignment: text.Middle,
|
||||
Color: black,
|
||||
Background: gray,
|
||||
}
|
||||
|
||||
insertLabel := &text.Label{Face: face, Text: "Insert"}
|
||||
passnameLabel := &text.Label{Face: face, Text: "password name:"}
|
||||
passnameEd := &text.Editor{Face: face, SingleLine: true, Submit: true}
|
||||
passvalLabel := &text.Label{Face: face, Text: "password value:"}
|
||||
passvalEd := &text.Editor{Face: face, SingleLine: true, Submit: true}
|
||||
insertLabel := &text.Label{Size: unit.Sp(16), Text: "Insert"}
|
||||
passnameLabel := &text.Label{Size: unit.Sp(16), Text: "password name:"}
|
||||
passnameEd := &text.Editor{Size: unit.Sp(16), Family: family, SingleLine: true, Submit: true}
|
||||
passvalLabel := &text.Label{Size: unit.Sp(16), Text: "password value:"}
|
||||
passvalEd := &text.Editor{Size: unit.Sp(16), Family: family, SingleLine: true, Submit: true}
|
||||
|
||||
noidLabel := &text.Label{Face: face, Text: "No GPG ids available. Please create a private key"}
|
||||
idLabel := &text.Label{Face: face, Text: "Select ID"}
|
||||
noidLabel := &text.Label{Size: unit.Sp(16), Text: "No GPG ids available. Please create a private key"}
|
||||
idLabel := &text.Label{Size: unit.Sp(16), Text: "Select ID"}
|
||||
|
||||
anim := &time.Ticker{}
|
||||
animating := false
|
||||
animOn := func() {
|
||||
log(Info, "animOn()")
|
||||
anim = time.NewTicker(time.Second / 120)
|
||||
anim = time.NewTicker(time.Second / 30)
|
||||
animating = true
|
||||
w.Invalidate()
|
||||
}
|
||||
|
@ -333,30 +352,27 @@ func eventLoop() {
|
|||
start2 := float64(Config.ClearDelay)
|
||||
fade2a, end := start2+1.5, start2+2.0
|
||||
|
||||
cs = flex.Flexible(1.0)
|
||||
c2 := flex.Flex(gtx, 1.0, func() {
|
||||
mux.Lock()
|
||||
if lst.Dragging() {
|
||||
key.HideInputOp{}.Add(ops)
|
||||
key.HideInputOp{}.Add(gtx.Ops)
|
||||
}
|
||||
var c2 layout.FlexChild
|
||||
switch {
|
||||
case store.Empty:
|
||||
c2 = flex.End(confBtn.Layout(c, q, ops, cs))
|
||||
confBtn.Layout(gtx, family)
|
||||
if confBtn.Clicked() {
|
||||
log(Info, "Configure")
|
||||
w.Invalidate()
|
||||
page = confPage
|
||||
}
|
||||
case store.Id == "":
|
||||
c2 = flex.End(idLabel.Layout(ops, cs))
|
||||
idLabel.Layout(gtx, family)
|
||||
w.Invalidate()
|
||||
page = idPage
|
||||
default:
|
||||
for lst.Init(c, q, ops, cs, len(passBtns)); lst.More(); lst.Next() {
|
||||
i := lst.Index()
|
||||
lst.Layout(gtx, len(passBtns), func(i int) {
|
||||
btn := passBtns[i]
|
||||
dims = btn.Layout(c, q, ops, lst.Constraints())
|
||||
lst.End(dims)
|
||||
btn.Layout(gtx, family)
|
||||
if btn.Clicked() {
|
||||
log(Info, "Clicked ", btn.Label)
|
||||
// don't block UI thread on decryption attempt
|
||||
|
@ -385,11 +401,11 @@ func eventLoop() {
|
|||
}
|
||||
}(pathnames[i])
|
||||
}
|
||||
}
|
||||
c2 = flex.End(lst.Layout())
|
||||
})
|
||||
}
|
||||
mux.Unlock()
|
||||
flex.Layout(c1, c2)
|
||||
})
|
||||
flex.Layout(gtx, c1, c2)
|
||||
x := time.Since(overlayStart).Seconds()
|
||||
if x >= fade1b && x < start2 && animating {
|
||||
animOff()
|
||||
|
@ -426,11 +442,12 @@ func eventLoop() {
|
|||
overlay.Color = black
|
||||
overlay.Background = darkgray
|
||||
}
|
||||
cs = margincs
|
||||
al := layout.Align{Alignment: layout.SE}
|
||||
cs = al.Begin(ops, cs)
|
||||
cs.Width.Min = cs.Width.Max
|
||||
dims = al.End(overlay.Layout(c, ops, cs))
|
||||
gtx.Constraints = margincs
|
||||
al := layout.Align(layout.SE)
|
||||
al.Layout(gtx, func() {
|
||||
gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
|
||||
overlay.Layout(gtx, family)
|
||||
})
|
||||
}
|
||||
if x > start2 && x < fade2a {
|
||||
// animOff()
|
||||
|
@ -444,20 +461,21 @@ func eventLoop() {
|
|||
if !animating {
|
||||
animOn()
|
||||
}
|
||||
cs = flex.Rigid()
|
||||
c2 := flex.End(idLabel.Layout(ops, cs))
|
||||
var c3 layout.FlexChild
|
||||
c2 := flex.Rigid(gtx, func() {
|
||||
idLabel.Layout(gtx, family)
|
||||
})
|
||||
//if len(idBtns) == 0 {
|
||||
updateIdBtns()
|
||||
//}
|
||||
cs = flex.Rigid()
|
||||
c3 := flex.Rigid(gtx, func() {
|
||||
if len(idBtns) == 0 { // still zero after update
|
||||
c3 = flex.End(noidLabel.Layout(ops, cs))
|
||||
noidLabel.Layout(gtx, family)
|
||||
} else {
|
||||
for lst.Init(c, q, ops, cs, len(idBtns)); lst.More(); lst.Next() {
|
||||
lst.End(idBtns[lst.Index()].Layout(c, q, ops, lst.Constraints()))
|
||||
for i := 0; i < len(idBtns); i++ {
|
||||
lst.Layout(gtx, len(idBtns), func(i int) {
|
||||
idBtns[i].Layout(gtx, family)
|
||||
})
|
||||
}
|
||||
c3 = flex.End(lst.Layout())
|
||||
for _, btn := range idBtns {
|
||||
if btn.Clicked() {
|
||||
log(Info, "ID selected: ", btn.Label)
|
||||
|
@ -468,20 +486,23 @@ func eventLoop() {
|
|||
}
|
||||
}
|
||||
}
|
||||
flex.Layout(c1, c2, c3)
|
||||
})
|
||||
flex.Layout(gtx, c1, c2, c3)
|
||||
}
|
||||
|
||||
var insName, insValue string
|
||||
genBtn := &SelButton{SelColor: darkgray}
|
||||
genBtn.Button = Button{Face: face, Label: "generate", Background: gray}
|
||||
symBtn := &SelButton{SelColor: gray, Selected: true}
|
||||
numBtn := &SelButton{SelColor: gray, Selected: true}
|
||||
symBtn.Button = Button{Face: face, Label: "@", Background: darkgray}
|
||||
numBtn.Button = Button{Face: face, Label: "#", Background: darkgray}
|
||||
lenEd := &text.Editor{Face: face, SingleLine: true, Alignment: text.End}
|
||||
genBtn := &SelButton{SelColor: gray}
|
||||
genBtn.Button = Button{Size: unit.Sp(16), Label: "generate"}
|
||||
symBtn := &SelButton{SelColor: gray}
|
||||
numBtn := &SelButton{SelColor: gray}
|
||||
symBtn.Button = Button{Size: unit.Sp(16), Label: "@"}
|
||||
numBtn.Button = Button{Size: unit.Sp(16), Label: "#"}
|
||||
symBtn.Select()
|
||||
numBtn.Select()
|
||||
lenEd := &text.Editor{Size: unit.Sp(16), Family: family, SingleLine: true, Alignment: text.End}
|
||||
lenEd.SetText("15")
|
||||
lBtn := &Button{Face: face, Label: "<", Background: gray}
|
||||
rBtn := &Button{Face: face, Label: ">", Background: gray}
|
||||
lBtn := &Button{Size: unit.Sp(16), Label: "<", Background: gray}
|
||||
rBtn := &Button{Size: unit.Sp(16), Label: ">", Background: gray}
|
||||
|
||||
updatePw := func() {
|
||||
if !genBtn.Selected {
|
||||
|
@ -499,40 +520,49 @@ func eventLoop() {
|
|||
default:
|
||||
gen = rand.Letter
|
||||
}
|
||||
l,_ := strconv.Atoi(lenEd.Text())
|
||||
pw,_ := rand.Slice(gen,l)
|
||||
l, _ := strconv.Atoi(lenEd.Text())
|
||||
pw, _ := rand.Slice(gen, l)
|
||||
passvalEd.SetText(string(pw))
|
||||
}
|
||||
|
||||
insertPage = func() {
|
||||
c2 := flex.End(insertLabel.Layout(ops, flex.Rigid()))
|
||||
c2 := flex.Rigid(gtx, func() { insertLabel.Layout(gtx, family) })
|
||||
c3 := flex.Rigid(gtx, func() { passnameLabel.Layout(gtx, family) })
|
||||
c4 := flex.Rigid(gtx, func() { passnameEd.Layout(gtx) })
|
||||
c5 := flex.Rigid(gtx, func() { passvalLabel.Layout(gtx, family) })
|
||||
c6 := flex.Rigid(gtx, func() { passvalEd.Layout(gtx) })
|
||||
|
||||
c3 := flex.End(passnameLabel.Layout(ops, flex.Rigid()))
|
||||
c4 := flex.End(passnameEd.Layout(c, q, ops, flex.Rigid()))
|
||||
c5 := flex.End(passvalLabel.Layout(ops, flex.Rigid()))
|
||||
c6 := flex.End(passvalEd.Layout(c, q, ops, flex.Rigid()))
|
||||
|
||||
al := &layout.Align{Alignment: layout.E}
|
||||
btnflx := &layout.Flex{Axis: layout.Horizontal}
|
||||
btnflx.Init(ops, al.Begin(ops, flex.Rigid()))
|
||||
bc1 := btnflx.End(lBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
cs := btnflx.Rigid()
|
||||
cs.Width.Min = 60
|
||||
bc2 := btnflx.End(lenEd.Layout(c, q, ops, cs))
|
||||
bc3 := btnflx.End(rBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
bc4 := btnflx.End(symBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
bc5 := btnflx.End(numBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
bc6 := btnflx.End(genBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
c7 := flex.End(al.End(btnflx.Layout(bc1, bc2, bc3, bc4, bc5, bc6)))
|
||||
al := layout.Align(layout.E)
|
||||
c7 := flex.Rigid(gtx, func() {
|
||||
bc1 := btnflx.Rigid(gtx, func() { lBtn.Layout(gtx, family) })
|
||||
bc2 := btnflx.Rigid(gtx, func() {
|
||||
gtx.Constraints.Width.Min = 60
|
||||
lenEd.Layout(gtx)
|
||||
})
|
||||
|
||||
btnflx.Init(ops, al.Begin(ops, flex.Rigid()))
|
||||
bc1 = btnflx.End(backBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
bc2 = btnflx.End(saveBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
c8 := flex.End(al.End(btnflx.Layout(bc1, bc2)))
|
||||
flex.Layout(c1, c2, c3, c4, c5, c6, c7, c8)
|
||||
bc3 := btnflx.Rigid(gtx, func() { rBtn.Layout(gtx, family) })
|
||||
bc4 := btnflx.Rigid(gtx, func() { symBtn.Layout(gtx, family) })
|
||||
bc5 := btnflx.Rigid(gtx, func() { numBtn.Layout(gtx, family) })
|
||||
bc6 := btnflx.Rigid(gtx, func() { genBtn.Layout(gtx, family) })
|
||||
|
||||
al.Layout(gtx, func() {
|
||||
btnflx.Layout(gtx, bc1, bc2, bc3, bc4, bc5, bc6)
|
||||
})
|
||||
})
|
||||
|
||||
c8 := flex.Rigid(gtx, func() {
|
||||
bc1 := btnflx.Rigid(gtx, func() { backBtn.Layout(gtx, family) })
|
||||
bc2 := btnflx.Rigid(gtx, func() { saveBtn.Layout(gtx, family) })
|
||||
al.Layout(gtx, func() {
|
||||
btnflx.Layout(gtx, bc1, bc2)
|
||||
})
|
||||
})
|
||||
|
||||
flex.Layout(gtx, c1, c2, c3, c4, c5, c6, c7, c8)
|
||||
|
||||
if lBtn.Clicked() {
|
||||
l,_ := strconv.Atoi(lenEd.Text())
|
||||
l, _ := strconv.Atoi(lenEd.Text())
|
||||
if l > 0 {
|
||||
l -= 1
|
||||
}
|
||||
|
@ -541,8 +571,8 @@ func eventLoop() {
|
|||
w.Invalidate()
|
||||
}
|
||||
if rBtn.Clicked() {
|
||||
l,_ := strconv.Atoi(lenEd.Text())
|
||||
lenEd.SetText(strconv.Itoa(l+1))
|
||||
l, _ := strconv.Atoi(lenEd.Text())
|
||||
lenEd.SetText(strconv.Itoa(l + 1))
|
||||
updatePw()
|
||||
w.Invalidate()
|
||||
}
|
||||
|
@ -580,15 +610,20 @@ func eventLoop() {
|
|||
}
|
||||
|
||||
confirmPage = func() {
|
||||
cs = flex.Rigid()
|
||||
c2 := flex.End(confirmLabel.Layout(ops, cs))
|
||||
al := &layout.Align{Alignment: layout.E}
|
||||
c2 := flex.Rigid(gtx, func() {
|
||||
confirmLabel.Layout(gtx, family)
|
||||
})
|
||||
al := layout.Align(layout.E)
|
||||
btnflx := &layout.Flex{Axis: layout.Horizontal}
|
||||
btnflx.Init(ops, al.Begin(ops, flex.Rigid()))
|
||||
bc1 := btnflx.End(backBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
bc2 := btnflx.End(yesBtn.Layout(c, q, ops, btnflx.Rigid()))
|
||||
c3 := flex.End(al.End(btnflx.Layout(bc1, bc2)))
|
||||
flex.Layout(c1, c2, c3)
|
||||
c3 := flex.Rigid(gtx, func() {
|
||||
bc1 := btnflx.Rigid(gtx, func() { backBtn.Layout(gtx, family) })
|
||||
bc2 := btnflx.Rigid(gtx, func() { yesBtn.Layout(gtx, family) })
|
||||
|
||||
al.Layout(gtx, func() {
|
||||
btnflx.Layout(gtx, bc1, bc2)
|
||||
})
|
||||
})
|
||||
flex.Layout(gtx, c1, c2, c3)
|
||||
|
||||
if backBtn.Clicked() {
|
||||
w.Invalidate()
|
||||
|
@ -602,22 +637,24 @@ func eventLoop() {
|
|||
}
|
||||
|
||||
confPage = func() {
|
||||
cs = flex.Rigid()
|
||||
c2 := flex.End(storeDirLabel.Layout(ops, cs))
|
||||
cs = flex.Rigid()
|
||||
c3 := flex.End(storeDirEd.Layout(c, q, ops, cs))
|
||||
cs = flex.Rigid()
|
||||
al := &layout.Align{Alignment: layout.E}
|
||||
cs = al.Begin(ops, cs)
|
||||
c2 := flex.Rigid(gtx, func() { storeDirLabel.Layout(gtx, family) })
|
||||
c3 := flex.Rigid(gtx, func() { storeDirEd.Layout(gtx) })
|
||||
|
||||
al := layout.Align(layout.E)
|
||||
c4 := flex.Rigid(gtx, func() {
|
||||
btnflx := &layout.Flex{Axis: layout.Horizontal}
|
||||
btnflx.Init(ops, cs)
|
||||
cs = btnflx.Rigid()
|
||||
bc1 := btnflx.End(backBtn.Layout(c, q, ops, cs))
|
||||
cs = btnflx.Rigid()
|
||||
bc2 := btnflx.End(saveBtn.Layout(c, q, ops, cs))
|
||||
dims = btnflx.Layout(bc1, bc2)
|
||||
c4 := flex.End(al.End(dims))
|
||||
flex.Layout(c1, c2, c3, c4)
|
||||
bc1 := btnflx.Rigid(gtx, func() {
|
||||
backBtn.Layout(gtx, family)
|
||||
})
|
||||
bc2 := btnflx.Rigid(gtx, func() {
|
||||
saveBtn.Layout(gtx, family)
|
||||
})
|
||||
al.Layout(gtx, func() {
|
||||
btnflx.Layout(gtx, bc1, bc2)
|
||||
})
|
||||
})
|
||||
flex.Layout(gtx, c1, c2, c3, c4)
|
||||
|
||||
if backBtn.Clicked() {
|
||||
log(Info, "Back")
|
||||
storeDirEd.SetText(store.Dir)
|
||||
|
@ -642,29 +679,30 @@ func eventLoop() {
|
|||
|
||||
promptPage = func() {
|
||||
submit := false
|
||||
for e, ok := promptEd.Next(c, q); ok; e, ok = promptEd.Next(c, q) {
|
||||
for e, ok := promptEd.Event(gtx); ok; e, ok = promptEd.Event(gtx) {
|
||||
switch e.(type) {
|
||||
case text.SubmitEvent:
|
||||
log(Info, "Submit")
|
||||
submit = true
|
||||
}
|
||||
}
|
||||
cs = flex.Rigid()
|
||||
c2 := flex.End(promptLabel.Layout(ops, cs))
|
||||
cs = flex.Rigid()
|
||||
c3 := flex.End(promptEd.Layout(c, q, ops, cs))
|
||||
cs = flex.Rigid()
|
||||
al := &layout.Align{Alignment: layout.E}
|
||||
cs = al.Begin(ops, cs)
|
||||
c2 := flex.Rigid(gtx, func() { promptLabel.Layout(gtx, family) })
|
||||
c3 := flex.Rigid(gtx, func() { promptEd.Layout(gtx) })
|
||||
c4 := flex.Rigid(gtx, func() {
|
||||
al := layout.Align(layout.E)
|
||||
btnflx := &layout.Flex{Axis: layout.Horizontal}
|
||||
btnflx.Init(ops, cs)
|
||||
cs = btnflx.Rigid()
|
||||
bc1 := btnflx.End(backBtn.Layout(c, q, ops, cs))
|
||||
cs = btnflx.Rigid()
|
||||
bc2 := btnflx.End(okBtn.Layout(c, q, ops, cs))
|
||||
dims = btnflx.Layout(bc1, bc2)
|
||||
c4 := flex.End(al.End(dims))
|
||||
flex.Layout(c1, c2, c3, c4)
|
||||
bc1 := btnflx.Rigid(gtx, func() {
|
||||
backBtn.Layout(gtx, family)
|
||||
})
|
||||
bc2 := btnflx.Rigid(gtx, func() {
|
||||
okBtn.Layout(gtx, family)
|
||||
})
|
||||
al.Layout(gtx, func() {
|
||||
btnflx.Layout(gtx, bc1, bc2)
|
||||
})
|
||||
})
|
||||
flex.Layout(gtx, c1, c2, c3, c4)
|
||||
|
||||
if submit || okBtn.Clicked() {
|
||||
log(Info, "Ok")
|
||||
go func() { // do not block UI thread
|
||||
|
@ -685,6 +723,9 @@ func eventLoop() {
|
|||
|
||||
page = listPage
|
||||
|
||||
ms := &runtime.MemStats{}
|
||||
x := 0
|
||||
var mallocs uint64
|
||||
for {
|
||||
select {
|
||||
case <-updated:
|
||||
|
@ -694,36 +735,43 @@ func eventLoop() {
|
|||
case <-anim.C:
|
||||
w.Invalidate()
|
||||
case e := <-w.Events():
|
||||
x++
|
||||
if x == 100 {
|
||||
runtime.ReadMemStats(ms)
|
||||
mallocs = ms.Mallocs
|
||||
}
|
||||
switch e := e.(type) {
|
||||
case app.DestroyEvent:
|
||||
return
|
||||
case app.UpdateEvent:
|
||||
c = &e.Config
|
||||
ops.Reset()
|
||||
faces.Reset(c)
|
||||
cs = layout.RigidConstraints(e.Size)
|
||||
fmt.Printf("UpdateEvent\n")
|
||||
gtx.Reset(&e.Config, e.Size)
|
||||
|
||||
sysinset.Top = e.Insets.Top
|
||||
sysinset.Bottom = e.Insets.Bottom
|
||||
sysinset.Left = e.Insets.Left
|
||||
sysinset.Right = e.Insets.Right
|
||||
cs = sysinset.Begin(c, ops, cs)
|
||||
cs = margin.Begin(c, ops, cs)
|
||||
margincs = cs
|
||||
flex.Init(ops, cs)
|
||||
cs = flex.Rigid()
|
||||
titleflex.Init(ops, cs)
|
||||
cs = titleflex.Rigid()
|
||||
ct2 := titleflex.End(plusBtn.Layout(c, q, ops, cs))
|
||||
cs = titleflex.Rigid()
|
||||
ct3 := titleflex.End(dotsBtn.Layout(c, q, ops, cs))
|
||||
cs = titleflex.Flexible(1.0)
|
||||
cs.Width.Min = cs.Width.Max
|
||||
ct1 := titleflex.End(title.Layout(ops, cs))
|
||||
c1 = flex.End(titleflex.Layout(ct1, ct2, ct3))
|
||||
|
||||
sysinset.Layout(gtx, func() {
|
||||
margin.Layout(gtx, func() {
|
||||
margincs = gtx.Constraints
|
||||
c1 = flex.Rigid(gtx, func() {
|
||||
ct2 := titleflex.Rigid(gtx, func() {
|
||||
plusBtn.Layout(gtx, family)
|
||||
})
|
||||
ct3 := titleflex.Rigid(gtx, func() {
|
||||
dotsBtn.Layout(gtx, family)
|
||||
})
|
||||
ct1 := titleflex.Flex(gtx, 1.0, func() {
|
||||
gtx.Constraints.Width.Min = gtx.Constraints.Width.Max
|
||||
title.Layout(gtx, family)
|
||||
})
|
||||
titleflex.Layout(gtx, ct1, ct2, ct3)
|
||||
})
|
||||
|
||||
page()
|
||||
|
||||
sysinset.End(margin.End(dims))
|
||||
})
|
||||
})
|
||||
|
||||
if dotsBtn.Clicked() {
|
||||
log(Info, "Configure")
|
||||
|
@ -736,7 +784,12 @@ func eventLoop() {
|
|||
insName, insValue = "", ""
|
||||
page = insertPage
|
||||
}
|
||||
w.Update(ops)
|
||||
w.Update(gtx.Ops)
|
||||
}
|
||||
if x == 100 {
|
||||
x = 0
|
||||
runtime.ReadMemStats(ms)
|
||||
fmt.Printf("mallocs: %d\n", ms.Mallocs-mallocs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,14 @@ 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"
|
||||
"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 (
|
||||
|
@ -22,7 +22,7 @@ var (
|
|||
)
|
||||
|
||||
type Overlay struct {
|
||||
Face text.Face
|
||||
Size unit.Value
|
||||
Text string
|
||||
Click gesture.Click
|
||||
Color color.RGBA
|
||||
|
@ -30,30 +30,30 @@ type Overlay struct {
|
|||
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
|
||||
func (b *Overlay) Layout(gtx *layout.Context, family text.Family) {
|
||||
ins := layout.UniformInset(unit.Dp(1))
|
||||
ins.Layout(gtx, func() {
|
||||
st := layout.Stack{}
|
||||
st.Init(ops, cs)
|
||||
{
|
||||
cs = st.Rigid()
|
||||
c2 := st.Rigid(gtx, func() {
|
||||
l := text.Label{
|
||||
Face: b.Face,
|
||||
Size: b.Size,
|
||||
Text: b.Text,
|
||||
Alignment: b.Alignment,
|
||||
}
|
||||
ins := layout.UniformInset(ui.Dp(4))
|
||||
l.Material.Record(ops)
|
||||
paint.ColorOp{Color: b.Color}.Add(ops)
|
||||
ins := layout.UniformInset(unit.Dp(4))
|
||||
l.Material.Record(gtx.Ops)
|
||||
paint.ColorOp{Color: b.Color}.Add(gtx.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)
|
||||
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 {
|
||||
|
@ -63,7 +63,7 @@ type SelButton struct {
|
|||
}
|
||||
|
||||
type Button struct {
|
||||
Face text.Face
|
||||
Size unit.Value
|
||||
Label string
|
||||
Click gesture.Click
|
||||
Color color.RGBA
|
||||
|
@ -72,22 +72,22 @@ type Button struct {
|
|||
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}
|
||||
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(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}
|
||||
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 *ui.Ops, width, height, se, sw, nw, ne float32) {
|
||||
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.PathBuilder
|
||||
b.Init(ops)
|
||||
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})
|
||||
|
@ -99,48 +99,63 @@ func rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
|
|||
b.End()
|
||||
}
|
||||
|
||||
func (b *Button) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimensions {
|
||||
func (b *Button) Layout(gtx *layout.Context, family text.Family) {
|
||||
b.clicked = false
|
||||
for ev, ok := b.Click.Next(q); ok; ev, ok = b.Click.Next(q) {
|
||||
for _, ev := range b.Click.Events(gtx) {
|
||||
if ev.Type == gesture.TypeClick {
|
||||
b.clicked = true
|
||||
}
|
||||
}
|
||||
ins := layout.UniformInset(ui.Dp(1))
|
||||
cs = ins.Begin(c, ops, cs)
|
||||
var dims layout.Dimensions
|
||||
ins := layout.UniformInset(unit.Dp(1))
|
||||
ins.Layout(gtx, func() {
|
||||
st := layout.Stack{}
|
||||
st.Init(ops, cs)
|
||||
{
|
||||
cs = st.Rigid()
|
||||
c2 := st.Rigid(gtx, func() {
|
||||
l := text.Label{
|
||||
Face: b.Face,
|
||||
Size: b.Size,
|
||||
Text: b.Label,
|
||||
Alignment: b.Alignment,
|
||||
}
|
||||
ins := layout.UniformInset(ui.Dp(4))
|
||||
ins := layout.UniformInset(unit.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)
|
||||
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 {
|
||||
func (b *SelButton) Toggle() {
|
||||
b.Selected = !b.Selected
|
||||
b.SelColor, b.Background = b.Background, b.SelColor
|
||||
}
|
||||
|
||||
func (b *SelButton) Select() {
|
||||
if !b.Selected {
|
||||
b.Toggle()
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SelButton) Deselect() {
|
||||
if b.Selected {
|
||||
b.Toggle()
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SelButton) Clicked() bool {
|
||||
if b.clicked {
|
||||
b.Toggle()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.wow.st/gmp/passgo
|
|||
go 1.12
|
||||
|
||||
require (
|
||||
gioui.org/ui v0.0.0-20190918172808-816f0e901fc6
|
||||
gioui.org v0.0.0-20191008122509-6bc55d66c2fe
|
||||
git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5
|
||||
git.wow.st/gmp/rand v0.0.0-20191001220155-a81bebfaf8b0
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
|
|
11
go.sum
11
go.sum
|
@ -1,5 +1,15 @@
|
|||
gioui.org v0.0.0-20191002081212-2a1c203863c3 h1:4ROVjhDrWa/J/O4KbtbCItYHhWnFWbmTyHPrfBeeG0w=
|
||||
gioui.org v0.0.0-20191002081212-2a1c203863c3/go.mod h1:+CEjc9B//HrBfWsQOVxjCyih7HGIj3Pww1xFHVDZyyk=
|
||||
gioui.org v0.0.0-20191002205528-32bda106e7ff h1:pLleCPnIUzrPrjM+kad+jVhU31lzoEfINETZkLcTMRQ=
|
||||
gioui.org v0.0.0-20191002205528-32bda106e7ff/go.mod h1:+CEjc9B//HrBfWsQOVxjCyih7HGIj3Pww1xFHVDZyyk=
|
||||
gioui.org v0.0.0-20191002212946-96d3d74cb33a h1:+VTwpWGLLyLXICY3wn4LQlSLXpwX06PenIutOxYqe+M=
|
||||
gioui.org v0.0.0-20191002212946-96d3d74cb33a/go.mod h1:+CEjc9B//HrBfWsQOVxjCyih7HGIj3Pww1xFHVDZyyk=
|
||||
gioui.org v0.0.0-20191008122509-6bc55d66c2fe h1:N29sMDb1EoJNXSTxGWWb1i+3GymQXbbwLiRc7bEW450=
|
||||
gioui.org v0.0.0-20191008122509-6bc55d66c2fe/go.mod h1:+CEjc9B//HrBfWsQOVxjCyih7HGIj3Pww1xFHVDZyyk=
|
||||
gioui.org/ui v0.0.0-20190918172808-816f0e901fc6 h1:LvHEYxyOW7g+PhOiAm8Delc3AUv9EH219oDvaUMeKBw=
|
||||
gioui.org/ui v0.0.0-20190918172808-816f0e901fc6/go.mod h1:PssKPKlqVIeyaed+0w492Xc2NgX5M3n6oZKOAj5rxoE=
|
||||
gioui.org/ui v0.0.0-20190926171558-ce74bc0cbaea h1:rv21Wx1Inf27NY453rrrP6tuEG65PyWPhnP2Jx+Qb8k=
|
||||
gioui.org/ui v0.0.0-20190926171558-ce74bc0cbaea/go.mod h1:PssKPKlqVIeyaed+0w492Xc2NgX5M3n6oZKOAj5rxoE=
|
||||
git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5 h1:OKeTjZST+/TKvtdA258NXJH+/gIx/xwyZxKrAezNFvk=
|
||||
git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5/go.mod h1:NLdpaBoMQNFqncwP8OVRNWUDw1Kt9XWm3snfT7cXu24=
|
||||
git.wow.st/gmp/rand v0.0.0-20191001220006-66bfa936ad6b h1:yu3SnygEUgkNJ3xBXLkWHws7tki5qveZ6Kk7ybWj1GQ=
|
||||
|
@ -18,6 +28,7 @@ golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R
|
|||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
Loading…
Reference in New Issue
Block a user