package main import ( "git.wow.st/gmp/giowrap" "fmt" //"image" "image/color" "log" "os" "runtime" "runtime/pprof" "sync" "time" "gioui.org/ui" "gioui.org/ui/app" "gioui.org/ui/text" "golang.org/x/image/font/gofont/goregular" "golang.org/x/image/font/sfnt" ) var ( FPS int = 100 frames int64 frametime int64 // nanoseconds maxframetime int64 mux sync.Mutex Profile bool = true RecordMallocs bool = false ) func NewButton(face text.Face, t string, c color.RGBA) giowrap.Clickable { lbl := giowrap.NewLabel(t, giowrap.Face(face), giowrap.Align(text.Middle)) bg := giowrap.NewBackground(giowrap.Color(c), giowrap.Radius(ui.Dp(4))) ins := giowrap.NewInset(giowrap.Size(ui.Dp(4))) return giowrap.AsClickable(ins(bg(lbl))) } 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) 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() } }() go main1() app.Main() } func main1() { w := app.NewWindow() regular, err := sfnt.Parse(goregular.TTF) if err != nil { log.Fatal("Cannot parse font.") } ctx := giowrap.NewContext(w) t := time.NewTicker(time.Second / time.Duration(FPS)) graybg := giowrap.NewBackground( giowrap.Color(color.RGBA{A: 0xff, R: 0xd0, G: 0xd0, B: 0xd0}), giowrap.Radius(ui.Dp(4))) whitebg := giowrap.NewBackground( giowrap.Color(color.RGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff}), giowrap.Radius(ui.Dp(4))) margin := giowrap.NewInset(giowrap.Size(ui.Dp(10))) buffer := giowrap.NewInset(giowrap.Bottom(ui.Dp(10))) f1 := giowrap.NewFlex(giowrap.Vertical) row := giowrap.NewFlex(giowrap.Horizontal) more := NewButton(ctx.Faces.For(regular, ui.Sp(24)), "more", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6}) submit := NewButton(ctx.Faces.For(regular, ui.Sp(24)), "submit", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6}) back := NewButton(ctx.Faces.For(regular, ui.Sp(24)), "back", color.RGBA{A: 0xff, R: 0x3c, G: 0x98, B: 0xc6}) numfields := 5 eds := make([]*giowrap.Editor,0) btns := make([]giowrap.Clickable,0) entryrows := make([]giowrap.Widget,0) submitrows := make([]giowrap.Widget,0) var entryPage giowrap.Widget var submitPage giowrap.Widget newRow := func(i int) { eds = append(eds, giowrap.NewEditor(fmt.Sprintf("text %d",i), giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))) btns = append(btns, NewButton(ctx.Faces.For(regular, ui.Sp(18)), "X", color.RGBA{A: 0xff, R: 0x80, G: 0x80, B: 0x80})) } for i := 0; i < numfields; i++ { newRow(i) } updatePages := func() { entryrows = entryrows[0:0] entryrows = append(entryrows, buffer(row(more, submit))) for i := 0; i < len(btns); i++ { entryrows = append(entryrows, row(btns[i], giowrap.FillWidth(whitebg(eds[i])))) } entryPage = graybg(margin(giowrap.VScroll(f1)(entryrows...))) submitrows = submitrows[0:0] submitrows = append(submitrows, buffer(row(back))) for i := 0; i < len(btns); i++ { submitrows = append(submitrows, giowrap.NewLabel(eds[i].Text(), giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))) } submitPage = graybg(margin(giowrap.VScroll(f1)(submitrows...))) } updatePages() page := &entryPage profiled := false startTime := time.Now() for { select { case <-t.C: w.Invalidate() case e := <-w.Events(): mux.Lock() stime := time.Now() switch e := e.(type) { case app.DestroyEvent: return case app.UpdateEvent: profileNow := false var ms runtime.MemStats if Profile && time.Since(startTime) > time.Second*2 { startTime = time.Now() profileNow = true } if profileNow { if !profiled { prof(0) } runtime.ReadMemStats(&ms) if RecordMallocs { giowrap.RecordMallocs() } } ctx.Reset(&e) giowrap.Mallocs("pre-layout") (*page).Layout(ctx) giowrap.Mallocs("post-layout") ctx.Update() for i, w := range btns { if w.Clicked(ctx) { log.Printf("%d clicked\n",i) btns = append(btns[:i], btns[i+1:]...) eds = append(eds[:i], eds[i+1:]...) entryrows = append(entryrows[:i], entryrows[i+1:]...) numfields-- updatePages() } } if more.Clicked(ctx) { log.Print("More") newRow(len(btns)) updatePages() } if submit.Clicked(ctx) { log.Print("Submit") updatePages() page = &submitPage } if back.Clicked(ctx) { page = &entryPage } if profileNow { for _, i := range giowrap.AllMallocs { fmt.Printf("mallocs: %d (%s)\n", i.Value, i.Text) } giowrap.AllMallocs = nil mallocs := ms.Mallocs runtime.ReadMemStats(&ms) mallocs = ms.Mallocs - mallocs log.Printf("Mallocs = %d\n", mallocs) if !profiled { prof(1) profiled = true } } } dur := time.Since(stime).Nanoseconds() frames = frames + 1 frametime = frametime + dur if dur > maxframetime { maxframetime = dur } mux.Unlock() } } } func prof(x int) { names := []string{"memprofile-1.pprof", "memprofile-2.pprof"} f1, err := os.Create(names[x]) if err != nil { log.Fatal("could not create memory profile: ", err) } if err := pprof.WriteHeapProfile(f1); err != nil { log.Fatal("could not write memory profile: ", err) } f1.Close() log.Print("Memory profile written") }