giowrap/cmd/hello/main.go

329 lines
7.4 KiB
Go
Raw Normal View History

2019-08-15 09:16:00 -04:00
package main
import (
"git.wow.st/gmp/giowrap"
"image"
2019-08-15 18:32:01 -04:00
"image/color"
2019-08-15 09:16:00 -04:00
"log"
"os"
"runtime"
"runtime/pprof"
"sync"
2019-08-15 09:16:00 -04:00
"time"
"gioui.org/ui"
"gioui.org/ui/app"
"gioui.org/ui/f32"
"gioui.org/ui/gesture"
2019-08-15 09:16:00 -04:00
"gioui.org/ui/layout"
"gioui.org/ui/measure"
2019-08-27 09:24:30 -04:00
"gioui.org/ui/paint"
"gioui.org/ui/pointer"
2019-08-15 09:16:00 -04:00
"gioui.org/ui/text"
"golang.org/x/image/font/gofont/goregular"
2019-08-27 09:24:30 -04:00
"golang.org/x/image/font/sfnt"
2019-08-15 09:16:00 -04:00
)
var (
2019-08-27 09:24:30 -04:00
FPS int = 100
frames int64
frametime int64 // nanoseconds
maxframetime int64
2019-08-27 09:24:30 -04:00
mux sync.Mutex
Profile bool = false
)
2019-08-16 16:38:49 -04:00
func NewButton(face text.Face, t string, c color.RGBA) giowrap.Clickable {
lbl := giowrap.NewLabel(t, giowrap.Face(face), giowrap.Align(text.Middle))
2019-08-20 12:39:28 -04:00
bg := giowrap.NewBackground(giowrap.Color(c), giowrap.Radius(ui.Dp(4)))
2019-08-16 16:38:49 -04:00
return giowrap.AsClickable(bg(lbl))
}
2019-08-15 09:16:00 -04:00
func main() {
go func() {
ms := &runtime.MemStats{}
var a1 uint64
for {
time.Sleep(time.Second * 3)
mux.Lock()
if frames == 0 {
mux.Unlock()
continue
}
runtime.ReadMemStats(ms)
a1 = ms.Alloc
runtime.GC()
runtime.ReadMemStats(ms)
2019-08-27 09:24:30 -04:00
log.Printf("Alloc: %d - %d = %d (%d per frame)", a1, ms.Alloc, a1-ms.Alloc, (a1-ms.Alloc)/(3*uint64(FPS)))
log.Printf("Frametime: %d max Frametime: %d us\n", frametime/(frames*1000), maxframetime/1000)
frames = 0
frametime = 0
maxframetime = 0
mux.Unlock()
2019-08-15 09:16:00 -04:00
}
}()
switch {
case len(os.Args) < 2:
fallthrough
default:
log.Fatal(`Usage:
hello [main1|main2]
`)
case os.Args[1] == "main1":
log.Print("main1()")
go main1()
case os.Args[1] == "main2":
log.Print("main2()")
go main2()
}
app.Main()
}
2019-08-15 09:16:00 -04:00
func main1() {
w := app.NewWindow()
regular, err := sfnt.Parse(goregular.TTF)
if err != nil {
log.Fatal("Cannot parse font.")
}
ctx := giowrap.NewContext(w)
2019-08-27 09:24:30 -04:00
t := time.NewTicker(time.Second / time.Duration(FPS))
e1 := giowrap.NewEditor("text 1", giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))
e1.Focus()
2019-08-15 09:16:00 -04:00
2019-08-27 09:24:30 -04:00
e2 := giowrap.NewEditor("text 2", giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))
2019-08-15 09:16:00 -04:00
2019-08-20 12:39:28 -04:00
f1 := giowrap.NewFlex(giowrap.Axis(layout.Vertical))
OuterInset := giowrap.NewInset(giowrap.Size(ui.Dp(10)))
InnerInset := giowrap.NewInset(giowrap.Size(ui.Dp(10)))
2019-08-16 16:38:49 -04:00
2019-08-20 12:39:28 -04:00
f2 := giowrap.NewFlex(giowrap.Axis(layout.Horizontal))
2019-08-15 09:16:00 -04:00
btn1 := NewButton(ctx.Faces.For(regular, ui.Sp(24)),
"push1", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6})
btn2 := NewButton(ctx.Faces.For(regular, ui.Sp(24)),
"push2", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6})
profiled := false
startTime := time.Now()
for {
select {
case <-t.C:
w.Invalidate()
case e := <-w.Events():
stime := time.Now()
switch e := e.(type) {
case app.DestroyEvent:
return
case app.UpdateEvent:
ctx.Reset(e)
OuterInset(
2019-08-27 09:24:30 -04:00
f1(
e1,
giowrap.Flexible(0.33),
InnerInset(e2),
giowrap.Flexible(0.67),
f2(
InnerInset(btn1),
giowrap.Flexible(0.5),
InnerInset(btn2),
),
)).Layout(ctx)
ctx.Update()
if btn1.Clicked(ctx) {
2019-08-27 09:24:30 -04:00
log.Print("Clicked: " + e1.Text())
}
if btn2.Clicked(ctx) {
2019-08-27 09:24:30 -04:00
log.Print("Clicked: " + e2.Text())
}
}
dur := time.Since(stime).Nanoseconds()
mux.Lock()
frames = frames + 1
frametime = frametime + dur
2019-08-27 09:24:30 -04:00
if dur > maxframetime {
maxframetime = dur
}
mux.Unlock()
}
2019-08-27 09:24:30 -04:00
if profiled {
continue
}
if time.Since(startTime) < time.Second*10 {
continue
}
if Profile {
profiled = true
f, err := os.Create("memprofile.pprof")
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write memory profile: ", err)
}
log.Print("Memory profile written")
f.Close()
}
}
}
func main2() {
w := app.NewWindow()
q := w.Queue()
ops := new(ui.Ops)
var faces measure.Faces
regular, err := sfnt.Parse(goregular.TTF)
if err != nil {
log.Fatal("Cannot parse font.")
}
2019-08-27 09:24:30 -04:00
t := time.NewTicker(time.Second / time.Duration(FPS))
e1 := &text.Editor{
2019-08-27 09:24:30 -04:00
Face: faces.For(regular, ui.Sp(24)),
SingleLine: true,
}
e1.Focus()
e1.SetText("text 1")
e2 := &text.Editor{
2019-08-27 09:24:30 -04:00
Face: faces.For(regular, ui.Sp(24)),
SingleLine: true,
}
e2.Focus()
e2.SetText("text 2")
btn1 := &Button{
Face: faces.For(regular, ui.Sp(24)),
Label: "push1",
}
btn2 := &Button{
Face: faces.For(regular, ui.Sp(24)),
Label: "push2",
}
profiled := false
startTime := time.Now()
for {
select {
case <-t.C:
w.Invalidate()
case e := <-w.Events():
stime := time.Now()
switch e := e.(type) {
case app.DestroyEvent:
return
case app.UpdateEvent:
c := &e.Config
ops.Reset()
faces.Reset(c)
for ev, ok := btn1.Click.Next(q); ok; ev, ok = btn1.Click.Next(q) {
if ev.Type == gesture.TypeClick {
2019-08-27 09:24:30 -04:00
log.Print("Clicked: " + e1.Text())
2019-08-16 16:38:49 -04:00
}
}
for ev, ok := btn2.Click.Next(q); ok; ev, ok = btn2.Click.Next(q) {
if ev.Type == gesture.TypeClick {
2019-08-27 09:24:30 -04:00
log.Print("Clicked: " + e2.Text())
2019-08-15 09:16:00 -04:00
}
}
var dims layout.Dimens
cs := layout.RigidConstraints(e.Size)
{
f1 := layout.Flex{Axis: layout.Vertical}
ins := layout.UniformInset(ui.Dp(10))
f1.Init(ops, ins.Begin(c, ops, cs))
c1 := f1.End(e1.Layout(c, q, ops, f1.Rigid()))
{
cs = f1.Flexible(0.33)
ins := layout.UniformInset(ui.Dp(10))
dims = ins.End(e2.Layout(c, q, ops, ins.Begin(c, ops, cs)))
}
c2 := f1.End(dims)
{
cs = f1.Flexible(0.67)
f2 := layout.Flex{Axis: layout.Horizontal}
f2.Init(ops, cs)
c1 := f2.End(btn1.Layout(c, ops, f2.Rigid()))
c2 := f2.End(btn2.Layout(c, ops, f2.Flexible(0.5)))
dims = f2.Layout(c1, c2)
}
c3 := f1.End(dims)
dims = ins.End(f1.Layout(c1, c2, c3))
}
w.Update(ops)
2019-08-15 09:16:00 -04:00
}
dur := time.Since(stime).Nanoseconds()
mux.Lock()
frames = frames + 1
frametime = frametime + dur
2019-08-27 09:24:30 -04:00
if dur > maxframetime {
maxframetime = dur
}
mux.Unlock()
2019-08-15 09:16:00 -04:00
}
2019-08-27 09:24:30 -04:00
if profiled {
continue
}
if time.Since(startTime) < time.Second*10 {
continue
}
if Profile {
profiled = true
f, err := os.Create("memprofile.pprof")
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write memory profile: ", err)
}
log.Print("Memory profile written")
f.Close()
}
}
2019-08-15 09:16:00 -04:00
}
func layoutRRect(c ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimens {
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)
giowrap.Rrect(ops, w, h, r, r, r, r)
paint.ColorOp{Color: color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6}}.Add(ops)
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: w, Y: h}}}.Add(ops)
return layout.Dimens{Size: sz}
}
type Button struct {
Face text.Face
Label string
Click gesture.Click
}
func (b *Button) Layout(c ui.Config, ops *ui.Ops, cs layout.Constraints) layout.Dimens {
ins := layout.UniformInset(ui.Dp(10))
cs = ins.Begin(c, ops, cs)
var dims layout.Dimens
st := layout.Stack{}
st.Init(ops, cs)
{
cs = st.Rigid()
l := text.Label{
Face: b.Face,
Text: b.Label,
}
ins := layout.UniformInset(ui.Dp(4))
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(c, ops, st.Expand()))
dims = st.Layout(c1, c2)
return ins.End(dims)
}