diff --git a/hrm/go.mod b/hrm/go.mod index 2ec8495..52ee08c 100644 --- a/hrm/go.mod +++ b/hrm/go.mod @@ -1,11 +1,9 @@ -module git.wow.st/gmp/hrm +module st.wow.git/gmp/hrm/hrm -go 1.13 +go 1.14 require ( - gioui.org v0.0.0-20191126175243-2ca2e5462f16 - git.wow.st/gmp/ble v0.0.0-20200204223639-7a583419c528 - github.com/google/go-github/v24 v24.0.1 // indirect - golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c // indirect - gopkg.in/yaml.v2 v2.2.7 + gioui.org v0.0.0-20200612151431-2dc19a36959c + git.wow.st/gmp/ble v0.0.0-20200612201046-f5cc27a30de7 + gopkg.in/yaml.v2 v2.3.0 ) diff --git a/hrm/go.sum b/hrm/go.sum index 86c678c..21f9bab 100644 --- a/hrm/go.sum +++ b/hrm/go.sum @@ -2,6 +2,8 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20191126175243-2ca2e5462f16 h1:p31rtmKm51xpj2QtqGNlljAyHEP1oStU8MDRl2Dv7Gs= gioui.org v0.0.0-20191126175243-2ca2e5462f16/go.mod h1:KqFFi2Dq5gYA3FJ0sDOt8OBXoMsuxMtE8v2f0JExXAY= +gioui.org v0.0.0-20200612151431-2dc19a36959c h1:sGUKyRMv2bbfbsRyG8ghOI12l+WCGta+PivmznjuLgo= +gioui.org v0.0.0-20200612151431-2dc19a36959c/go.mod h1:AHI9rFr6AEEHCb8EPVtb/p5M+NMJRKH58IOp8O3Je04= git.wow.st/gmp/ble v0.0.0-20191127164604-2af636b9461a h1:Nr6kwAliHs2EsGv4Q1EgQACfbb/hVnTYq0CkWfqIj+g= git.wow.st/gmp/ble v0.0.0-20191127164604-2af636b9461a/go.mod h1:Fh9BYe6AckJS7dzv2LFPr/wSYVMROUwmtc01VyQmuZo= git.wow.st/gmp/ble v0.0.0-20191204220614-4cdaceda7601 h1:lgoKiQ1MzXfh4+sl601d0RR6/Kt182MiegqLtdVBy1I= @@ -25,6 +27,8 @@ git.wow.st/gmp/ble v0.0.0-20191230162624-2d7594514cb3 h1:rMmx9qz3lb6kdzKzU2cJgb9 git.wow.st/gmp/ble v0.0.0-20191230162624-2d7594514cb3/go.mod h1:Fh9BYe6AckJS7dzv2LFPr/wSYVMROUwmtc01VyQmuZo= git.wow.st/gmp/ble v0.0.0-20200204223639-7a583419c528 h1:jXHDwWWs11Qua2DSdgU1WBW2HNDPQU9/IjoZ4d5oAsI= git.wow.st/gmp/ble v0.0.0-20200204223639-7a583419c528/go.mod h1:Fh9BYe6AckJS7dzv2LFPr/wSYVMROUwmtc01VyQmuZo= +git.wow.st/gmp/ble v0.0.0-20200612201046-f5cc27a30de7 h1:RoWGPgYpz5szRySgT6/Vykxw0nBMH39Mv2+ghsMy82I= +git.wow.st/gmp/ble v0.0.0-20200612201046-f5cc27a30de7/go.mod h1:CpPW2hELyNbPdD2I6XvJsu3PQ23iPYtlLTydJ+KZMbQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -62,6 +66,8 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w 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= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -71,3 +77,5 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/hrm/main.go b/hrm/main.go index 6db40c2..2c6f04f 100644 --- a/hrm/main.go +++ b/hrm/main.go @@ -30,6 +30,11 @@ import ( "gioui.org/font/gofont" ) +type ( + D = layout.Dimensions + C = layout.Context +) + type conf struct { Autoconnect string } @@ -82,15 +87,15 @@ type Stopwatch struct { lasttime time.Time elapsed time.Time running bool - startstopBtn *widget.Button - resetBtn *widget.Button + startstopBtn *widget.Clickable + resetBtn *widget.Clickable h, m, s int } func NewStopwatch() Stopwatch { return Stopwatch{ - startstopBtn: &widget.Button{}, - resetBtn: &widget.Button{}, + startstopBtn: &widget.Clickable{}, + resetBtn: &widget.Clickable{}, } } @@ -99,10 +104,9 @@ func eventloop() { app.Size(unit.Dp(350), unit.Dp(600)), app.Title("HRM"), ) - gofont.Register() - th := material.NewTheme() + th := material.NewTheme(gofont.Collection()) th.TextSize = unit.Sp(fontSize) - gtx := &layout.Context{Queue: w.Queue()} + var ops op.Ops sysinset := &layout.Inset{} resetSysinset := func(x system.Insets) { @@ -121,56 +125,58 @@ func eventloop() { var periph ble.Peripheral var wide bool periphs := make([]ble.Peripheral, 0) - btns := make([]*widget.Button, 0) - backBtn := &widget.Button{} + btns := make([]*widget.Clickable, 0) + backBtn := &widget.Clickable{} - var page, offpage, scanpage, connpage, hrpage func() + var page, offpage, scanpage, connpage, hrpage func(gtx C) D f := &layout.Flex{Axis: layout.Vertical} - offpage = func() { - f.Layout(gtx, - f.Rigid(gtx, func() { - th.Body1("Heart Rate Monitor").Layout(gtx) + offpage = func(gtx C) D { + return f.Layout(gtx, + layout.Rigid(func(gtx C) D { + return material.Body1(th, "Heart Rate Monitor").Layout(gtx) }), - f.Rigid(gtx, func() { - th.Body1("Bluetooth is Powered Off").Layout(gtx) + layout.Rigid(func(gtx C) D { + return material.Body1(th, "Bluetooth is Powered Off").Layout(gtx) }), ) } - appname := func() { - layout.Align(layout.Center).Layout(gtx, func() { - th.Body1("Heart Rate Monitor").Layout(gtx) + appname := func(gtx C) D { + return layout.Center.Layout(gtx, func(gtx C) D { + return material.Body1(th, "Heart Rate Monitor").Layout(gtx) }) } - appstate := func() { - layout.Align(layout.Center).Layout(gtx, func() { - th.Body1(state).Layout(gtx) + appstate := func(gtx C) D { + return layout.Center.Layout(gtx, func(gtx C) D { + return material.Body1(th, state).Layout(gtx) }) } - periphname := func() { - layout.Align(layout.Center).Layout(gtx, func() { - th.Body1(periph.Name).Layout(gtx) + periphname := func(gtx C) D { + return layout.Center.Layout(gtx, func(gtx C) D { + return material.Body1(th, periph.Name).Layout(gtx) }) } - leftbar := func() { + leftbar := func(gtx C) D { f := &layout.Flex{Axis: layout.Vertical} - f.Layout(gtx, - f.Rigid(gtx, appname), - f.Rigid(gtx, func() { th.Body1("").Layout(gtx) }), - f.Rigid(gtx, appstate), + return f.Layout(gtx, + layout.Rigid(appname), + layout.Rigid(func(gtx C) D { + return material.Body1(th, "").Layout(gtx) + }), + layout.Rigid(appstate), ) } - scanlist := func() { + scanlist := func(gtx C) D { lst := &layout.List{Axis: layout.Vertical} - lst.Layout(gtx, len(periphs), func(i int) { - gtx.Constraints.Width.Min = gtx.Constraints.Width.Max - layout.UniformInset(unit.Dp(2)).Layout(gtx, func() { - th.Button(periphs[i].Name).Layout(gtx, btns[i]) + return lst.Layout(gtx, len(periphs), func(gtx C, i int) D { + gtx.Constraints.Min.X = gtx.Constraints.Max.X + ret := layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx C) D { + return material.Button(th, btns[i], periphs[i].Name).Layout(gtx) }) - if btns[i].Clicked(gtx) { + if btns[i].Clicked() { b.StopScan() periph = periphs[i] b.Connect(periph) @@ -178,33 +184,34 @@ func eventloop() { page = connpage w.Invalidate() } + return ret }) } - scanpage = func() { + scanpage = func(gtx C) D { if wide { f2 := &layout.Flex{Axis: layout.Horizontal} - f2.Layout(gtx, - f2.Flex(gtx, 0.2, leftbar), - f2.Rigid(gtx, scanlist), + return f2.Layout(gtx, + layout.Rigid(leftbar), + layout.Flexed(1, scanlist), ) } else { - f.Layout(gtx, - f.Rigid(gtx, appname), - f.Rigid(gtx, appstate), - f.Rigid(gtx, scanlist), + return f.Layout(gtx, + layout.Rigid(appname), + layout.Rigid(appstate), + layout.Rigid(scanlist), ) } } - connpage = func() { - f.Layout(gtx, - f.Rigid(gtx, appname), - f.Rigid(gtx, appstate), - f.Rigid(gtx, periphname), - f.Rigid(gtx, func() { - th.Button("Cancel").Layout(gtx, backBtn) - if backBtn.Clicked(gtx) { + connpage = func(gtx C) D { + return f.Layout(gtx, + layout.Rigid(appname), + layout.Rigid(appstate), + layout.Rigid(periphname), + layout.Rigid(func(gtx C) D { + ret := material.Button(th, backBtn, "Cancel").Layout(gtx) + if backBtn.Clicked() { ble.CancelConnection(periph) periphs = periphs[:0] Config.Autoconnect = "" @@ -213,16 +220,17 @@ func eventloop() { state = "scanning" page = scanpage } + return ret }), ) } - hrcircle := func() int { + hrcircle := func(gtx C) (int, D) { var w, h1 float32 - layout.Align(layout.Center).Layout(gtx, func() { + ret := layout.Center.Layout(gtx, func(gtx C) D { blue := color.RGBA{0x3f, 0x51, 0xb5, 255} white := color.RGBA{255, 255, 255, 255} - w, h1 = float32(gtx.Constraints.Width.Max), float32(gtx.Constraints.Height.Max) + w, h1 = float32(gtx.Constraints.Max.X), float32(gtx.Constraints.Max.Y) if w < h1 { h1 = w } @@ -238,23 +246,25 @@ func eventloop() { paint.ColorOp{Color: white}.Add(gtx.Ops) paint.PaintOp{Rect: r2}.Add(gtx.Ops) op.TransformOp{}.Offset(p2a).Add(gtx.Ops) - gtx.Constraints.Width.Max = int(s2) - gtx.Constraints.Height.Max = int(s2) - gtx.Constraints.Width.Min = int(s2) - gtx.Constraints.Height.Min = int(s2) - l := th.H1(fmt.Sprintf("%d", hr)) + gtx.Constraints.Max.X = int(s2) + gtx.Constraints.Max.Y = int(s2) + gtx.Constraints.Min.X = int(s2) + gtx.Constraints.Min.Y = int(s2) + l := material.H1(th, fmt.Sprintf("%d", hr)) l.Alignment = text.Middle - layout.Align(layout.Center).Layout(gtx, func() { - l.Layout(gtx) + layout.Center.Layout(gtx, func(gtx C) D { + return l.Layout(gtx) }) - gtx.Dimensions.Size = image.Point{int(h1), int(h1)} + var ret D + ret.Size = image.Point{int(h1), int(h1)} + return ret }) - return int(h1) + return int(h1), ret } sw := NewStopwatch() - stopwatch := func() { + stopwatch := func(gtx C) D { startstoptxt := "start" if sw.running { sw.elapsed = sw.elapsed.Add(time.Since(sw.lasttime)) @@ -262,124 +272,139 @@ func eventloop() { } sw.lasttime = time.Now() f := layout.Flex{Axis: layout.Vertical} - f.Layout(gtx, - f.Rigid(gtx, func() { - layout.Align(layout.Center).Layout(gtx, func() { - gtx.Constraints.Width.Max = 1e6 - th.H4(sw.elapsed.Format("15:04:05.00")).Layout(gtx) + return f.Layout(gtx, + layout.Rigid(func(gtx C) D { + return layout.Center.Layout(gtx, func(gtx C) D { + gtx.Constraints.Max.X = 1e6 + return material.H4(th, sw.elapsed.Format("15:04:05.00")).Layout(gtx) }) }), - f.Rigid(gtx, func() { + layout.Rigid(func(gtx C) D { f2 := layout.Flex{Axis: layout.Horizontal} - gtx.Constraints.Height.Min = 100 - f2.Layout(gtx, - f2.Flex(gtx, 0.5, func() { - layout.UniformInset(unit.Dp(2)).Layout(gtx, func() { - th.Button(startstoptxt).Layout(gtx, sw.startstopBtn) + gtx.Constraints.Min.Y = 100 + ret := f2.Layout(gtx, + layout.Flexed(0.5, func(gtx C) D { + return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx C) D { + return material.Button(th, sw.startstopBtn, startstoptxt).Layout(gtx) }) }), - f2.Flex(gtx, 0.5, func() { - layout.UniformInset(unit.Dp(2)).Layout(gtx, func() { - th.Button("reset").Layout(gtx, sw.resetBtn) + layout.Flexed(0.5, func(gtx C) D { + return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx C) D { + return material.Button(th, sw.resetBtn, "reset").Layout(gtx) }) }), ) - if sw.startstopBtn.Clicked(gtx) { + if sw.startstopBtn.Clicked() { if sw.running { sw.running = false } else { sw.running = true } } - if sw.resetBtn.Clicked(gtx) { + if sw.resetBtn.Clicked() { sw.elapsed = time.Time{} sw.running = false } + return ret }), ) } swidth := new(int) - hrpage = func() { - stopbtn := func() { - gtx.Constraints.Height.Min = 100 - layout.UniformInset(unit.Dp(2)).Layout(gtx, func() { - th.Button("Disconnect").Layout(gtx, backBtn) + hrpage = func(gtx C) D { + var ret, ret2 D + stopbtn := func(gtx C) D { + gtx.Constraints.Min.Y = 100 + return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx C) D { + return material.Button(th, backBtn, "Disconnect").Layout(gtx) }) } if wide { f2 := &layout.Flex{Axis: layout.Horizontal} - f2.Layout(gtx, - f2.Flex(gtx, 0.4, func() { + ret = f2.Layout(gtx, + layout.Flexed(0.4, func(gtx C) D { f3 := &layout.Flex{Axis: layout.Vertical} - c1 := f3.Rigid(gtx, func() { - appname() - *swidth = gtx.Dimensions.Size.X + c1 := layout.Rigid(func(gtx C) D { + ret2 = appname(gtx) + *swidth = ret2.Size.X + return ret2 }) - c2 := f3.Rigid(gtx, func() { - periphname() - s2 := gtx.Dimensions.Size.X + c2 := layout.Rigid(func(gtx C) D { + ret2 = periphname(gtx) + s2 := ret2.Size.X if s2 > *swidth { *swidth = s2 } + return ret2 }) var c3 layout.FlexChild - if gtx.Constraints.Width.Max > 370 { - c3 = f3.Rigid(gtx, stopwatch) + if gtx.Constraints.Max.X > 370 { + c3 = layout.Rigid(stopwatch) + } else { + c3 = layout.Rigid(func(gtx C) D { + return D{} + }) } - c4 := f3.Rigid(gtx, stopbtn) - f3.Layout(gtx, + c4 := layout.Rigid(stopbtn) + return f3.Layout(gtx, c1, - f3.Rigid(gtx, appstate), + layout.Rigid(appstate), c2, - f3.Flex(gtx, 1.0, func() { th.Body1("").Layout(gtx) }), + layout.Flexed(1.0, func(gtx C) D { + return material.Body1(th, "").Layout(gtx) + }), c3, c4, ) }), - f2.Flex(gtx, 0.6, func() { hrcircle() }), + layout.Flexed(0.6, func(gtx C) D { + _, ret := hrcircle(gtx) + return ret + }), ) } else { // !wide - c1 := f.Rigid(gtx, func() { - layout.Align(layout.Center).Layout(gtx, func() { - gtx.Constraints.Width.Min = *swidth - gtx.Constraints.Width.Max = *swidth - stopwatch() + c1 := layout.Rigid(func(gtx C) D { + return layout.Center.Layout(gtx, func(gtx C) D { + gtx.Constraints.Min.X = *swidth + gtx.Constraints.Max.X = *swidth + return stopwatch(gtx) }) }) - swheight := gtx.Dimensions.Size.Y - c2 := f.Rigid(gtx, func() { - layout.Align(layout.Center).Layout(gtx, func() { - gtx.Constraints.Width.Min = *swidth - gtx.Constraints.Width.Max = *swidth - stopbtn() + //swheight := gtx.Dimensions.Size.Y + c2 := layout.Rigid(func(gtx C) D { + return layout.Center.Layout(gtx, func(gtx C) D { + gtx.Constraints.Min.X = *swidth + gtx.Constraints.Max.X = *swidth + return stopbtn(gtx) }) }) - if gtx.Constraints.Height.Max < 775 { - gtx.Constraints.Height.Max += swheight - f.Layout(gtx, - f.Rigid(gtx, appname), - f.Rigid(gtx, appstate), - f.Rigid(gtx, periphname), - f.Flex(gtx, 1.0, func() { - *swidth = hrcircle() + if gtx.Constraints.Max.Y < 775 { + //gtx.Constraints.Max.Y += swheight + ret = f.Layout(gtx, + layout.Rigid(appname), + layout.Rigid(appstate), + layout.Rigid(periphname), + layout.Flexed(1.0, func(gtx C) D { + *swidth, ret2 = hrcircle(gtx) + return ret2 }), c2, ) } else { - f.Layout(gtx, - f.Rigid(gtx, appname), - f.Rigid(gtx, appstate), - f.Rigid(gtx, periphname), - f.Flex(gtx, 1.0, func() { - *swidth = hrcircle() + ret = f.Layout(gtx, + layout.Rigid(appname), + layout.Rigid(appstate), + layout.Rigid(periphname), + layout.Flexed(1.0, func(gtx C) D { + *swidth, ret2 = hrcircle(gtx) + return ret2 }), c1, c2, ) } } - if backBtn.Clicked(gtx) { + if backBtn.Clicked() { ble.Disconnect(periph) periphs = periphs[:0] Config.Autoconnect = "" @@ -388,6 +413,7 @@ func eventloop() { state = "scanning" page = scanpage } + return ret } page = offpage @@ -420,7 +446,7 @@ func eventloop() { case ble.DiscoverPeripheralEvent: fmt.Printf("found %s (%s)\n", e.Peripheral.Name, e.Peripheral.Identifier) periphs = append(periphs, e.Peripheral) - btns = append(btns, &widget.Button{}) + btns = append(btns, &widget.Clickable{}) if e.Peripheral.Identifier == Config.Autoconnect && b.Connect(e.Peripheral) { state = "connecting" page = connpage @@ -465,15 +491,15 @@ func eventloop() { case system.DestroyEvent: return case system.FrameEvent: - gtx.Reset(e.Config, e.Size) + gtx := layout.NewContext(&ops, e) if e.Size.X > e.Size.Y { wide = true } else { wide = false } resetSysinset(e.Insets) - sysinset.Layout(gtx, func() { - margin.Layout(gtx, page) + sysinset.Layout(gtx, func(gtx C) D { + return margin.Layout(gtx, page) }) e.Frame(gtx.Ops) }