Memory profiling code. Updates to reduce memory footprint.
This commit is contained in:
parent
635655e768
commit
83c9d40500
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
cmd/hello/hello
|
cmd/hello/hello
|
||||||
cmd/cal/cal
|
cmd/cal/cal
|
||||||
cmd/scroll/scroll
|
cmd/scroll/scroll
|
||||||
|
cmd/grid/grid
|
||||||
*.apk
|
*.apk
|
||||||
|
|
|
@ -152,7 +152,7 @@ func eventloop() {
|
||||||
case app.DestroyEvent:
|
case app.DestroyEvent:
|
||||||
return
|
return
|
||||||
case app.UpdateEvent:
|
case app.UpdateEvent:
|
||||||
ctx.Reset(e)
|
ctx.Reset(&e)
|
||||||
|
|
||||||
mth.SetText(fmt.Sprintf("%s %d", sm.Month.String(), sm.Year))
|
mth.SetText(fmt.Sprintf("%s %d", sm.Month.String(), sm.Year))
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"git.wow.st/gmp/giowrap"
|
"git.wow.st/gmp/giowrap"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
|
@ -27,12 +28,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
FPS int = 100
|
FPS int = 100
|
||||||
frames int64
|
frames int64
|
||||||
frametime int64 // nanoseconds
|
frametime int64 // nanoseconds
|
||||||
maxframetime int64
|
maxframetime int64
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
Profile bool = false
|
Profile bool = true
|
||||||
|
RecordMallocs bool = false
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewButton(face text.Face, t string, c color.RGBA) giowrap.Clickable {
|
func NewButton(face text.Face, t string, c color.RGBA) giowrap.Clickable {
|
||||||
|
@ -69,7 +71,7 @@ func main() {
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
log.Fatal(`Usage:
|
log.Fatal(`Usage:
|
||||||
hello [main1|main2]
|
hello [main1|main2|main3|main4]
|
||||||
`)
|
`)
|
||||||
case os.Args[1] == "main1":
|
case os.Args[1] == "main1":
|
||||||
log.Print("main1()")
|
log.Print("main1()")
|
||||||
|
@ -77,10 +79,17 @@ hello [main1|main2]
|
||||||
case os.Args[1] == "main2":
|
case os.Args[1] == "main2":
|
||||||
log.Print("main2()")
|
log.Print("main2()")
|
||||||
go main2()
|
go main2()
|
||||||
|
case os.Args[1] == "main3":
|
||||||
|
log.Print("main3()")
|
||||||
|
go main3()
|
||||||
|
case os.Args[1] == "main4":
|
||||||
|
log.Print("main4()")
|
||||||
|
go main4()
|
||||||
}
|
}
|
||||||
app.Main()
|
app.Main()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Example with functional layout
|
||||||
func main1() {
|
func main1() {
|
||||||
w := app.NewWindow()
|
w := app.NewWindow()
|
||||||
regular, err := sfnt.Parse(goregular.TTF)
|
regular, err := sfnt.Parse(goregular.TTF)
|
||||||
|
@ -108,17 +117,156 @@ func main1() {
|
||||||
profiled := false
|
profiled := false
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
|
page := OuterInset(
|
||||||
|
f1(
|
||||||
|
e1,
|
||||||
|
giowrap.Flexible(0.33),
|
||||||
|
InnerInset(e2),
|
||||||
|
giowrap.Flexible(0.67),
|
||||||
|
f2(
|
||||||
|
InnerInset(btn1),
|
||||||
|
giowrap.Flexible(0.50),
|
||||||
|
InnerInset(btn2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
giowrap.Mallocs("pre-reset")
|
||||||
|
ctx.Reset(&e)
|
||||||
|
giowrap.Mallocs("pre-layout")
|
||||||
|
page.Layout(ctx)
|
||||||
|
giowrap.Mallocs("post-layout")
|
||||||
|
ctx.Update()
|
||||||
|
giowrap.Mallocs("post-update")
|
||||||
|
if btn1.Clicked(ctx) {
|
||||||
|
log.Print("Clicked: " + e1.Text())
|
||||||
|
}
|
||||||
|
if btn2.Clicked(ctx) {
|
||||||
|
log.Print("Clicked: " + e2.Text())
|
||||||
|
}
|
||||||
|
giowrap.Mallocs("post-clicked()")
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example showing use of WidgetCombinators in the main loop.
|
||||||
|
func main2() {
|
||||||
|
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))
|
||||||
|
e1 := giowrap.NewEditor("text 1", giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))
|
||||||
|
e1.Focus()
|
||||||
|
|
||||||
|
e2 := giowrap.NewEditor("text 2", giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))
|
||||||
|
|
||||||
|
f1 := giowrap.NewFlex(giowrap.Axis(layout.Vertical))
|
||||||
|
OuterInset := giowrap.NewInset(giowrap.Size(ui.Dp(10)))
|
||||||
|
InnerInset := giowrap.NewInset(giowrap.Size(ui.Dp(10)))
|
||||||
|
|
||||||
|
f2 := giowrap.NewFlex(giowrap.Axis(layout.Horizontal))
|
||||||
|
|
||||||
|
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 {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
w.Invalidate()
|
w.Invalidate()
|
||||||
case e := <-w.Events():
|
case e := <-w.Events():
|
||||||
|
mux.Lock()
|
||||||
stime := time.Now()
|
stime := time.Now()
|
||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
case app.DestroyEvent:
|
case app.DestroyEvent:
|
||||||
return
|
return
|
||||||
case app.UpdateEvent:
|
case app.UpdateEvent:
|
||||||
ctx.Reset(e)
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
giowrap.Mallocs("pre-reset")
|
||||||
|
ctx.Reset(&e)
|
||||||
|
giowrap.Mallocs("pre-layout")
|
||||||
OuterInset(
|
OuterInset(
|
||||||
f1(
|
f1(
|
||||||
e1,
|
e1,
|
||||||
|
@ -127,9 +275,107 @@ func main1() {
|
||||||
giowrap.Flexible(0.67),
|
giowrap.Flexible(0.67),
|
||||||
f2(
|
f2(
|
||||||
InnerInset(btn1),
|
InnerInset(btn1),
|
||||||
giowrap.Flexible(0.5),
|
giowrap.Flexible(0.50),
|
||||||
InnerInset(btn2),
|
InnerInset(btn2),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
).Layout(ctx)
|
||||||
|
giowrap.Mallocs("post-layout")
|
||||||
|
ctx.Update()
|
||||||
|
giowrap.Mallocs("post-update")
|
||||||
|
if btn1.Clicked(ctx) {
|
||||||
|
log.Print("Clicked: " + e1.Text())
|
||||||
|
}
|
||||||
|
if btn2.Clicked(ctx) {
|
||||||
|
log.Print("Clicked: " + e2.Text())
|
||||||
|
}
|
||||||
|
giowrap.Mallocs("post-clicked()")
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example showing widget allocation within the main loop (causes unnecessary
|
||||||
|
// memory allocations)
|
||||||
|
func main3() {
|
||||||
|
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))
|
||||||
|
e1 := giowrap.NewEditor("text 1", giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))
|
||||||
|
e1.Focus()
|
||||||
|
|
||||||
|
e2 := giowrap.NewEditor("text 2", giowrap.Face(ctx.Faces.For(regular, ui.Sp(24))))
|
||||||
|
|
||||||
|
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:
|
||||||
|
profileNow := false
|
||||||
|
var ms runtime.MemStats
|
||||||
|
if Profile && time.Since(startTime) > time.Second*2 {
|
||||||
|
profileNow = true
|
||||||
|
startTime = time.Now()
|
||||||
|
}
|
||||||
|
if profileNow {
|
||||||
|
if !profiled {
|
||||||
|
prof(0)
|
||||||
|
}
|
||||||
|
runtime.ReadMemStats(&ms)
|
||||||
|
if RecordMallocs {
|
||||||
|
giowrap.RecordMallocs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.Reset(&e)
|
||||||
|
giowrap.NewInset(giowrap.Size(ui.Dp(10)))(
|
||||||
|
giowrap.NewFlex(giowrap.Axis(layout.Vertical))(
|
||||||
|
e1,
|
||||||
|
//giowrap.Flexible(0.33),
|
||||||
|
giowrap.NewInset(giowrap.Size(ui.Dp(10)))(e2),
|
||||||
|
//giowrap.Flexible(0.67),
|
||||||
|
giowrap.NewFlex(giowrap.Axis(layout.Horizontal))(
|
||||||
|
giowrap.NewInset(giowrap.Size(ui.Dp(10)))(btn1),
|
||||||
|
//giowrap.Flexible(0.50),
|
||||||
|
giowrap.NewInset(giowrap.Size(ui.Dp(10)))(btn2),
|
||||||
|
),
|
||||||
)).Layout(ctx)
|
)).Layout(ctx)
|
||||||
ctx.Update()
|
ctx.Update()
|
||||||
if btn1.Clicked(ctx) {
|
if btn1.Clicked(ctx) {
|
||||||
|
@ -138,6 +384,20 @@ func main1() {
|
||||||
if btn2.Clicked(ctx) {
|
if btn2.Clicked(ctx) {
|
||||||
log.Print("Clicked: " + e2.Text())
|
log.Print("Clicked: " + e2.Text())
|
||||||
}
|
}
|
||||||
|
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()
|
dur := time.Since(stime).Nanoseconds()
|
||||||
mux.Lock()
|
mux.Lock()
|
||||||
|
@ -148,28 +408,11 @@ func main1() {
|
||||||
}
|
}
|
||||||
mux.Unlock()
|
mux.Unlock()
|
||||||
}
|
}
|
||||||
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() {
|
// Example using the base Gio API.
|
||||||
|
func main4() {
|
||||||
w := app.NewWindow()
|
w := app.NewWindow()
|
||||||
q := w.Queue()
|
q := w.Queue()
|
||||||
ops := new(ui.Ops)
|
ops := new(ui.Ops)
|
||||||
|
@ -215,6 +458,18 @@ func main2() {
|
||||||
case app.DestroyEvent:
|
case app.DestroyEvent:
|
||||||
return
|
return
|
||||||
case app.UpdateEvent:
|
case app.UpdateEvent:
|
||||||
|
profileNow := false
|
||||||
|
var ms runtime.MemStats
|
||||||
|
if Profile && time.Since(startTime) > time.Second*2 {
|
||||||
|
profileNow = true
|
||||||
|
startTime = time.Now()
|
||||||
|
}
|
||||||
|
if profileNow {
|
||||||
|
if !profiled {
|
||||||
|
prof(0)
|
||||||
|
}
|
||||||
|
runtime.ReadMemStats(&ms)
|
||||||
|
}
|
||||||
c := &e.Config
|
c := &e.Config
|
||||||
ops.Reset()
|
ops.Reset()
|
||||||
faces.Reset(c)
|
faces.Reset(c)
|
||||||
|
@ -257,6 +512,16 @@ func main2() {
|
||||||
dims = ins.End(f1.Layout(c1, c2, c3))
|
dims = ins.End(f1.Layout(c1, c2, c3))
|
||||||
}
|
}
|
||||||
w.Update(ops)
|
w.Update(ops)
|
||||||
|
if profileNow {
|
||||||
|
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()
|
dur := time.Since(stime).Nanoseconds()
|
||||||
mux.Lock()
|
mux.Lock()
|
||||||
|
@ -267,24 +532,6 @@ func main2() {
|
||||||
}
|
}
|
||||||
mux.Unlock()
|
mux.Unlock()
|
||||||
}
|
}
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
gio "git.wow.st/gmp/giowrap"
|
gio "git.wow.st/gmp/giowrap"
|
||||||
|
|
||||||
|
@ -99,18 +101,21 @@ func eventloop() {
|
||||||
lbar := gio.NewLabel(" ", gio.Face(face))
|
lbar := gio.NewLabel(" ", gio.Face(face))
|
||||||
f2 := gio.NewFlex(gio.Axis(layout.Vertical))
|
f2 := gio.NewFlex(gio.Axis(layout.Vertical))
|
||||||
topbar := gio.NewLabel("Scroll X and Y. Click to select", gio.Face(face))
|
topbar := gio.NewLabel("Scroll X and Y. Click to select", gio.Face(face))
|
||||||
|
f3 := gio.NewFlex(gio.Axis(layout.Horizontal))
|
||||||
|
f4 := gio.NewFlex(gio.Axis(layout.Vertical))
|
||||||
|
|
||||||
sh := gio.HScroll(gio.NewFlex(gio.Axis(layout.Horizontal)))
|
sh := gio.HScroll(gio.NewFlex(gio.Axis(layout.Horizontal)))
|
||||||
sv := gio.VScroll(gio.NewFlex(gio.Axis(layout.Vertical)))
|
sv := gio.VScroll(gio.NewFlex(gio.Axis(layout.Vertical)))
|
||||||
|
|
||||||
numlabs := 50
|
numrows := 16
|
||||||
labs := make([][]gio.Widget, numlabs)
|
numcols := 50
|
||||||
sels := make([][]bool, numlabs)
|
labs := make([][]gio.Widget, numrows)
|
||||||
for i := 0; i < 16; i++ {
|
sels := make([][]bool, numrows)
|
||||||
labs[i] = make([]gio.Widget, numlabs)
|
for i := 0; i < numrows; i++ {
|
||||||
sels[i] = make([]bool, numlabs)
|
labs[i] = make([]gio.Widget, numcols)
|
||||||
for j := 0; j < numlabs; j++ {
|
sels[i] = make([]bool, numcols)
|
||||||
labs[i][j] = NewSLabel(fmt.Sprintf("%03d", i*16+j), &sels[i][j])
|
for j := 0; j < numcols; j++ {
|
||||||
|
labs[i][j] = NewSLabel(fmt.Sprintf("%03d", i+j*numrows), &sels[i][j])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +125,30 @@ func eventloop() {
|
||||||
gio.Left(x.Left), gio.Right(x.Right))
|
gio.Left(x.Left), gio.Right(x.Right))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page := sysbg(sysinset(bg(margin(
|
||||||
|
f1(lbar, f2(topbar, sh(sv(f3(
|
||||||
|
f4(labs[0]...),
|
||||||
|
f4(labs[1]...),
|
||||||
|
f4(labs[2]...),
|
||||||
|
f4(labs[3]...),
|
||||||
|
f4(labs[4]...),
|
||||||
|
f4(labs[5]...),
|
||||||
|
f4(labs[6]...),
|
||||||
|
f4(labs[7]...),
|
||||||
|
f4(labs[8]...),
|
||||||
|
f4(labs[9]...),
|
||||||
|
f4(labs[10]...),
|
||||||
|
f4(labs[11]...),
|
||||||
|
f4(labs[12]...),
|
||||||
|
f4(labs[13]...),
|
||||||
|
f4(labs[14]...),
|
||||||
|
f4(labs[15]...),
|
||||||
|
)))))))))
|
||||||
|
|
||||||
var oldInsets app.Insets
|
var oldInsets app.Insets
|
||||||
|
|
||||||
|
stime := time.Now()
|
||||||
|
sm := runtime.MemStats{}
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case e := <-w.Events():
|
case e := <-w.Events():
|
||||||
|
@ -129,32 +156,30 @@ func eventloop() {
|
||||||
case app.DestroyEvent:
|
case app.DestroyEvent:
|
||||||
return
|
return
|
||||||
case app.UpdateEvent:
|
case app.UpdateEvent:
|
||||||
ctx.Reset(e)
|
profileNow := time.Since(stime) > time.Second*2
|
||||||
|
if profileNow {
|
||||||
|
stime = time.Now()
|
||||||
|
//gio.RecordMallocs()
|
||||||
|
runtime.ReadMemStats(&sm)
|
||||||
|
}
|
||||||
|
gio.Mallocs("start")
|
||||||
|
ctx.Reset(&e)
|
||||||
if diffInsets(e.Insets, oldInsets) {
|
if diffInsets(e.Insets, oldInsets) {
|
||||||
oldInsets = e.Insets
|
oldInsets = e.Insets
|
||||||
resetSysinset(e.Insets)
|
resetSysinset(e.Insets)
|
||||||
}
|
}
|
||||||
|
page.Layout(ctx)
|
||||||
sysbg(sysinset(bg(margin(
|
|
||||||
f1(lbar, f2(topbar, sh(
|
|
||||||
sv(labs[0]...),
|
|
||||||
sv(labs[1]...),
|
|
||||||
sv(labs[2]...),
|
|
||||||
sv(labs[3]...),
|
|
||||||
sv(labs[4]...),
|
|
||||||
sv(labs[5]...),
|
|
||||||
sv(labs[6]...),
|
|
||||||
sv(labs[7]...),
|
|
||||||
sv(labs[8]...),
|
|
||||||
sv(labs[9]...),
|
|
||||||
sv(labs[10]...),
|
|
||||||
sv(labs[11]...),
|
|
||||||
sv(labs[12]...),
|
|
||||||
sv(labs[13]...),
|
|
||||||
sv(labs[14]...),
|
|
||||||
sv(labs[15]...),
|
|
||||||
))))))).Layout(ctx)
|
|
||||||
ctx.Update()
|
ctx.Update()
|
||||||
|
gio.Mallocs("end")
|
||||||
|
if profileNow {
|
||||||
|
for _, m := range gio.AllMallocs {
|
||||||
|
fmt.Printf("Mallocs: %d (%s)\n", m.Value, m.Text)
|
||||||
|
}
|
||||||
|
gio.AllMallocs = nil
|
||||||
|
oldMallocs := sm.Mallocs
|
||||||
|
runtime.ReadMemStats(&sm)
|
||||||
|
fmt.Printf("Mallocs = %d\n", sm.Mallocs-oldMallocs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
grid.go
40
grid.go
|
@ -124,24 +124,34 @@ type HeightOpt struct{ height int }
|
||||||
func Height(x int) HeightOpt { return HeightOpt{x} }
|
func Height(x int) HeightOpt { return HeightOpt{x} }
|
||||||
func (x HeightOpt) DoGridOption(g *Grid) { g.Height = x.height }
|
func (x HeightOpt) DoGridOption(g *Grid) { g.Height = x.height }
|
||||||
|
|
||||||
|
type gridWidget struct {
|
||||||
|
g Grid
|
||||||
|
gcs []GridChild
|
||||||
|
ws []Widget
|
||||||
|
}
|
||||||
|
|
||||||
func NewGrid(cols int, gops ...GridOption) WidgetCombinator {
|
func NewGrid(cols int, gops ...GridOption) WidgetCombinator {
|
||||||
g := &Grid{Cols: cols}
|
ret := &gridWidget{}
|
||||||
|
ret.g = Grid{Cols: cols}
|
||||||
for _, gop := range gops {
|
for _, gop := range gops {
|
||||||
gop.DoGridOption(g)
|
gop.DoGridOption(&ret.g)
|
||||||
}
|
}
|
||||||
gcs := make([]GridChild, 0)
|
ret.gcs = make([]GridChild, 0)
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx *Context) {
|
ret.ws = ws
|
||||||
cs := g.Init(ctx.ops, ctx.cs)
|
return ret
|
||||||
ctx.cs = cs
|
|
||||||
for _, w := range ws {
|
|
||||||
g.Begin()
|
|
||||||
w.Layout(ctx)
|
|
||||||
ctx.cs = cs // widget layout can modify constraints...
|
|
||||||
gcs = append(gcs, g.End(ctx.dims))
|
|
||||||
}
|
|
||||||
ctx.dims = g.Layout(gcs...)
|
|
||||||
gcs = gcs[0:0]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gw *gridWidget) Layout(ctx *Context) {
|
||||||
|
cs := gw.g.Init(ctx.ops, ctx.cs)
|
||||||
|
ctx.cs = cs
|
||||||
|
for _, w := range gw.ws {
|
||||||
|
gw.g.Begin()
|
||||||
|
w.Layout(ctx)
|
||||||
|
ctx.cs = cs // widget layout can modify constraints...
|
||||||
|
gw.gcs = append(gw.gcs, gw.g.End(ctx.dims))
|
||||||
|
}
|
||||||
|
ctx.dims = gw.g.Layout(gw.gcs...)
|
||||||
|
gw.gcs = gw.gcs[0:0]
|
||||||
|
}
|
||||||
|
|
222
main.go
222
main.go
|
@ -42,12 +42,13 @@ func (e *Extra) New() int {
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Faces measure.Faces
|
Faces measure.Faces
|
||||||
|
|
||||||
w *app.Window
|
w *app.Window
|
||||||
c *app.Config
|
c *app.Config
|
||||||
q input.Queue
|
q input.Queue
|
||||||
ops *ui.Ops
|
ops *ui.Ops
|
||||||
cs layout.Constraints
|
cs layout.Constraints
|
||||||
dims layout.Dimens
|
dims layout.Dimens
|
||||||
|
container Widget
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext(w *app.Window) *Context {
|
func NewContext(w *app.Window) *Context {
|
||||||
|
@ -58,11 +59,13 @@ func NewContext(w *app.Window) *Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) Reset(e app.UpdateEvent) {
|
func (ctx *Context) Reset(e *app.UpdateEvent) {
|
||||||
|
Mallocs("ctx.Reset() ctx.c")
|
||||||
ctx.c = &e.Config
|
ctx.c = &e.Config
|
||||||
ctx.ops.Reset()
|
ctx.ops.Reset()
|
||||||
ctx.cs = layout.RigidConstraints(e.Size)
|
ctx.cs = layout.RigidConstraints(e.Size)
|
||||||
ctx.Faces.Reset(ctx.c)
|
ctx.Faces.Reset(ctx.c)
|
||||||
|
Mallocs("ctx.Reset() done")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) Update() {
|
func (ctx *Context) Update() {
|
||||||
|
@ -121,6 +124,7 @@ func NewLabel(t string, lops ...LabelOption) *Label {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Label) Layout(ctx *Context) {
|
func (l *Label) Layout(ctx *Context) {
|
||||||
|
Mallocs("Label.Layout()")
|
||||||
ctx.dims = l.l.Layout(ctx.ops, ctx.cs)
|
ctx.dims = l.l.Layout(ctx.ops, ctx.cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +161,7 @@ func NewEditor(t string, eops ...EditorOption) *Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Editor) Layout(ctx *Context) {
|
func (e *Editor) Layout(ctx *Context) {
|
||||||
|
Mallocs("Editor.Layout()")
|
||||||
ctx.dims = e.e.Layout(ctx.c, ctx.q, ctx.ops, ctx.cs)
|
ctx.dims = e.e.Layout(ctx.c, ctx.q, ctx.ops, ctx.cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,38 +169,36 @@ func (e *Editor) Text() string { return e.e.Text() }
|
||||||
func (e *Editor) SetText(s string) { e.e.SetText(s) }
|
func (e *Editor) SetText(s string) { e.e.SetText(s) }
|
||||||
func (e *Editor) Focus() { e.e.Focus() }
|
func (e *Editor) Focus() { e.e.Focus() }
|
||||||
|
|
||||||
type fWidget struct {
|
|
||||||
l Layout
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewfWidget(l Layout) fWidget {
|
|
||||||
return fWidget{l: l}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fw fWidget) Layout(ctx *Context) {
|
|
||||||
fw.l(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stack WidgetCombinator
|
type Stack WidgetCombinator
|
||||||
|
|
||||||
|
type stackWidget struct {
|
||||||
|
s layout.Stack
|
||||||
|
scs []layout.StackChild
|
||||||
|
ws []Widget
|
||||||
|
}
|
||||||
|
|
||||||
func NewStack() Stack {
|
func NewStack() Stack {
|
||||||
s := layout.Stack{Alignment: layout.Center}
|
ret := &stackWidget{}
|
||||||
scs := make([]layout.StackChild, 0)
|
ret.s = layout.Stack{Alignment: layout.Center}
|
||||||
|
ret.scs = make([]layout.StackChild, 0)
|
||||||
|
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx *Context) {
|
ret.ws = ws
|
||||||
s.Init(ctx.ops, ctx.cs)
|
return ret
|
||||||
for _, w := range ws {
|
|
||||||
ctx.cs = s.Rigid()
|
|
||||||
w.Layout(ctx)
|
|
||||||
scs = append(scs, s.End(ctx.dims))
|
|
||||||
}
|
|
||||||
ctx.dims = s.Layout(scs...)
|
|
||||||
scs = scs[0:0]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sw *stackWidget) Layout(ctx *Context) {
|
||||||
|
sw.s.Init(ctx.ops, ctx.cs)
|
||||||
|
for _, w := range sw.ws {
|
||||||
|
ctx.cs = sw.s.Rigid()
|
||||||
|
w.Layout(ctx)
|
||||||
|
sw.scs = append(sw.scs, sw.s.End(ctx.dims))
|
||||||
|
}
|
||||||
|
ctx.dims = sw.s.Layout(sw.scs...)
|
||||||
|
sw.scs = sw.scs[0:0]
|
||||||
|
}
|
||||||
|
|
||||||
type List = WidgetCombinator
|
type List = WidgetCombinator
|
||||||
|
|
||||||
type AxisOpt struct{ axis layout.Axis }
|
type AxisOpt struct{ axis layout.Axis }
|
||||||
|
@ -209,24 +212,34 @@ type ListOption interface{ DoListOption(*ListOpts) }
|
||||||
|
|
||||||
func (x AxisOpt) DoListOption(o *ListOpts) { o.axis = x.axis }
|
func (x AxisOpt) DoListOption(o *ListOpts) { o.axis = x.axis }
|
||||||
|
|
||||||
|
type listWidget struct {
|
||||||
|
l layout.List
|
||||||
|
ws []Widget
|
||||||
|
}
|
||||||
|
|
||||||
func NewList(los ...ListOption) List {
|
func NewList(los ...ListOption) List {
|
||||||
|
ret := &listWidget{}
|
||||||
opts := &ListOpts{}
|
opts := &ListOpts{}
|
||||||
for _, o := range los {
|
for _, o := range los {
|
||||||
o.DoListOption(opts)
|
o.DoListOption(opts)
|
||||||
}
|
}
|
||||||
l := layout.List{Axis: opts.axis}
|
ret.l = layout.List{Axis: opts.axis}
|
||||||
|
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx *Context) {
|
ret.ws = ws
|
||||||
for l.Init(ctx.c, ctx.q, ctx.ops, ctx.cs, len(ws)); l.More(); l.Next() {
|
return ret
|
||||||
ctx.cs = l.Constraints()
|
|
||||||
ws[l.Index()].Layout(ctx)
|
|
||||||
l.End(ctx.dims)
|
|
||||||
}
|
|
||||||
ctx.dims = l.Layout()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lw *listWidget) Layout(ctx *Context) {
|
||||||
|
for lw.l.Init(ctx.c, ctx.q, ctx.ops, ctx.cs, len(lw.ws)); lw.l.More(); lw.l.Next() {
|
||||||
|
ctx.cs = lw.l.Constraints()
|
||||||
|
lw.ws[lw.l.Index()].Layout(ctx)
|
||||||
|
lw.l.End(ctx.dims)
|
||||||
|
}
|
||||||
|
ctx.dims = lw.l.Layout()
|
||||||
|
}
|
||||||
|
|
||||||
func HScroll(c WidgetCombinator) WidgetCombinator {
|
func HScroll(c WidgetCombinator) WidgetCombinator {
|
||||||
return NewList(Axis(layout.Horizontal))
|
return NewList(Axis(layout.Horizontal))
|
||||||
}
|
}
|
||||||
|
@ -237,19 +250,6 @@ func VScroll(c WidgetCombinator) WidgetCombinator {
|
||||||
|
|
||||||
type Flex = WidgetCombinator
|
type Flex = WidgetCombinator
|
||||||
|
|
||||||
// This "Widget" does nothing except set the Flexible field of a FlexOpts
|
|
||||||
// struct within the Extra data structure
|
|
||||||
func Flexible(v float32) Widget {
|
|
||||||
return NewfWidget(func(ctx *Context) {
|
|
||||||
extra.data[extra.cur].(*FlexOpts).flexible = v
|
|
||||||
})
|
|
||||||
}
|
|
||||||
func Rigid() Widget {
|
|
||||||
return NewfWidget(func(ctx *Context) {
|
|
||||||
extra.data[extra.cur].(*FlexOpts).flexible = 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type AlignmentOpt struct{ alignment layout.Alignment }
|
type AlignmentOpt struct{ alignment layout.Alignment }
|
||||||
|
|
||||||
func Alignment(x layout.Alignment) AlignmentOpt { return AlignmentOpt{x} }
|
func Alignment(x layout.Alignment) AlignmentOpt { return AlignmentOpt{x} }
|
||||||
|
@ -265,7 +265,35 @@ type FlexOption interface{ DoFlexOption(*FlexOpts) }
|
||||||
func (x AxisOpt) DoFlexOption(o *FlexOpts) { o.axis = x.axis }
|
func (x AxisOpt) DoFlexOption(o *FlexOpts) { o.axis = x.axis }
|
||||||
func (x AlignmentOpt) DoFlexOption(o *FlexOpts) { o.alignment = x.alignment }
|
func (x AlignmentOpt) DoFlexOption(o *FlexOpts) { o.alignment = x.alignment }
|
||||||
|
|
||||||
|
type flexWidget struct {
|
||||||
|
f func(*Context)
|
||||||
|
flexible float32
|
||||||
|
}
|
||||||
|
|
||||||
|
type flexOptWidget struct {
|
||||||
|
flexible float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fo flexOptWidget) Layout(ctx *Context) {
|
||||||
|
Mallocs("flexOptWidget.Layout()")
|
||||||
|
ctx.container.(*flexWidget).flexible = fo.flexible
|
||||||
|
}
|
||||||
|
|
||||||
|
// This "Widget" does nothing except set the Flexible field of a FlexOpts
|
||||||
|
// struct within the Extra data structure
|
||||||
|
func Flexible(v float32) Widget {
|
||||||
|
return flexOptWidget{v}
|
||||||
|
}
|
||||||
|
func Rigid() Widget {
|
||||||
|
return flexOptWidget{0}
|
||||||
|
}
|
||||||
|
|
||||||
// NewFlex returns a WidgetCombinator that wraps the layout.Flex element.
|
// NewFlex returns a WidgetCombinator that wraps the layout.Flex element.
|
||||||
|
|
||||||
|
func (fw *flexWidget) Layout(ctx *Context) {
|
||||||
|
fw.f(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func NewFlex(fos ...FlexOption) Flex {
|
func NewFlex(fos ...FlexOption) Flex {
|
||||||
opts := &FlexOpts{}
|
opts := &FlexOpts{}
|
||||||
for _, o := range fos {
|
for _, o := range fos {
|
||||||
|
@ -275,29 +303,23 @@ func NewFlex(fos ...FlexOption) Flex {
|
||||||
Axis: opts.axis,
|
Axis: opts.axis,
|
||||||
Alignment: opts.alignment,
|
Alignment: opts.alignment,
|
||||||
}
|
}
|
||||||
index := extra.New()
|
|
||||||
extra.data[index] = opts
|
|
||||||
// do not call "make" inside the Layout function
|
|
||||||
fcs := make([]layout.FlexChild, 0)
|
fcs := make([]layout.FlexChild, 0)
|
||||||
|
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx *Context) {
|
ret := &flexWidget{}
|
||||||
// ensure child widgets write options to the right place
|
ret.f = func(ctx *Context) {
|
||||||
extra.cur = index
|
oldContainer := ctx.container
|
||||||
opts := extra.data[index].(*FlexOpts)
|
ctx.container = ret
|
||||||
f.Init(ctx.ops, ctx.cs)
|
f.Init(ctx.ops, ctx.cs)
|
||||||
for _, w := range ws {
|
for _, w := range ws {
|
||||||
if opts.flexible != 0 {
|
ctx.cs = f.Rigid()
|
||||||
ctx.cs = f.Flexible(opts.flexible)
|
|
||||||
} else {
|
|
||||||
ctx.cs = f.Rigid()
|
|
||||||
}
|
|
||||||
w.Layout(ctx)
|
w.Layout(ctx)
|
||||||
fcs = append(fcs, f.End(ctx.dims))
|
fcs = append(fcs, f.End(ctx.dims))
|
||||||
}
|
}
|
||||||
ctx.dims = f.Layout(fcs...)
|
ctx.dims = f.Layout(fcs...)
|
||||||
fcs = fcs[0:0] // truncate
|
fcs = fcs[0:0]
|
||||||
})
|
ctx.container = oldContainer
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,21 +360,34 @@ func (x SizeOpt) DoInsetOption(o *InsetOpts) {
|
||||||
o.left = x.size
|
o.left = x.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type insetWidget func(*Context)
|
||||||
|
|
||||||
|
func (iw insetWidget) Layout(ctx *Context) {
|
||||||
|
iw(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
//NewInset returns a WidgetCombinator that wraps the layout.Inset element.
|
//NewInset returns a WidgetCombinator that wraps the layout.Inset element.
|
||||||
func NewInset(insos ...InsetOption) WidgetCombinator {
|
func NewInset(insos ...InsetOption) func(...Widget) Widget {
|
||||||
opts := &InsetOpts{}
|
opts := InsetOpts{}
|
||||||
for _, o := range insos {
|
for _, o := range insos {
|
||||||
o.DoInsetOption(opts)
|
o.DoInsetOption(&opts)
|
||||||
}
|
}
|
||||||
ins := layout.Inset{Top: opts.top, Right: opts.right, Bottom: opts.bottom, Left: opts.left}
|
ins := layout.Inset{Top: opts.top, Right: opts.right, Bottom: opts.bottom, Left: opts.left}
|
||||||
|
|
||||||
return func(ws ...Widget) Widget {
|
return func(ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx *Context) {
|
Mallocs("NewInset() return")
|
||||||
|
var ret insetWidget
|
||||||
|
ret = func(ctx *Context) {
|
||||||
|
oldContainer := ctx.container
|
||||||
|
ctx.container = ret
|
||||||
ctx.cs = ins.Begin(ctx.c, ctx.ops, ctx.cs)
|
ctx.cs = ins.Begin(ctx.c, ctx.ops, ctx.cs)
|
||||||
for _, w := range ws {
|
for _, w := range ws {
|
||||||
w.Layout(ctx)
|
w.Layout(ctx)
|
||||||
}
|
}
|
||||||
ctx.dims = ins.End(ctx.dims)
|
ctx.dims = ins.End(ctx.dims)
|
||||||
})
|
ctx.container = oldContainer
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,14 +404,24 @@ type Enclosure interface {
|
||||||
End(*Context)
|
End(*Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type encloseWidget struct {
|
||||||
|
enc Enclosure
|
||||||
|
ws []Widget
|
||||||
|
}
|
||||||
|
|
||||||
func Enclose(e Enclosure, ws ...Widget) Widget {
|
func Enclose(e Enclosure, ws ...Widget) Widget {
|
||||||
return NewfWidget(func(ctx *Context) {
|
return &encloseWidget{e, ws}
|
||||||
e.Begin(ctx)
|
}
|
||||||
for _, w := range ws {
|
|
||||||
w.Layout(ctx)
|
func (e *encloseWidget) Layout(ctx *Context) {
|
||||||
}
|
oldContainer := ctx.container
|
||||||
e.End(ctx)
|
ctx.container = e
|
||||||
})
|
e.enc.Begin(ctx)
|
||||||
|
for _, w := range e.ws {
|
||||||
|
w.Layout(ctx)
|
||||||
|
}
|
||||||
|
e.enc.End(ctx)
|
||||||
|
ctx.container = oldContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
type BackgroundOpts struct {
|
type BackgroundOpts struct {
|
||||||
|
@ -412,11 +457,14 @@ func NewBackground(bos ...BackgroundOption) WidgetCombinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bg *Background) Begin(ctx *Context) {
|
func (bg *Background) Begin(ctx *Context) {
|
||||||
|
Mallocs("Background.Begin()")
|
||||||
bg.macro.Record(ctx.ops)
|
bg.macro.Record(ctx.ops)
|
||||||
ctx.cs = bg.Inset.Begin(ctx.c, ctx.ops, ctx.cs)
|
ctx.cs = bg.Inset.Begin(ctx.c, ctx.ops, ctx.cs)
|
||||||
|
Mallocs("Background.Begin() done")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bg *Background) End(ctx *Context) {
|
func (bg *Background) End(ctx *Context) {
|
||||||
|
Mallocs("Background.End()")
|
||||||
ctx.dims = bg.Inset.End(ctx.dims)
|
ctx.dims = bg.Inset.End(ctx.dims)
|
||||||
bg.macro.Stop()
|
bg.macro.Stop()
|
||||||
var stack ui.StackOp
|
var stack ui.StackOp
|
||||||
|
@ -435,14 +483,19 @@ func (bg *Background) End(ctx *Context) {
|
||||||
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: w, Y: h}}}.Add(ctx.ops)
|
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: w, Y: h}}}.Add(ctx.ops)
|
||||||
bg.macro.Add(ctx.ops)
|
bg.macro.Add(ctx.ops)
|
||||||
stack.Pop()
|
stack.Pop()
|
||||||
|
Mallocs("Background.End() done")
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://pomax.github.io/bezierinfo/#circles_cubic.
|
// https://pomax.github.io/bezierinfo/#circles_cubic.
|
||||||
func Rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
|
func Rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
|
||||||
|
Mallocs("Rrect() start")
|
||||||
w, h := float32(width), float32(height)
|
w, h := float32(width), float32(height)
|
||||||
|
Mallocs("Rrect() const")
|
||||||
const c = 0.55228475 // 4*(sqrt(2)-1)/3
|
const c = 0.55228475 // 4*(sqrt(2)-1)/3
|
||||||
var b paint.PathBuilder
|
var b paint.PathBuilder
|
||||||
|
Mallocs("Rrect() init")
|
||||||
b.Init(ops)
|
b.Init(ops)
|
||||||
|
Mallocs("Rrect() move")
|
||||||
b.Move(f32.Point{X: w, Y: h - se})
|
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.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.Line(f32.Point{X: sw - w + se, Y: 0})
|
||||||
|
@ -452,6 +505,7 @@ func Rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
|
||||||
b.Line(f32.Point{X: w - ne - nw, Y: 0})
|
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.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()
|
b.End()
|
||||||
|
Mallocs("Rrect() end")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Clickable interface {
|
type Clickable interface {
|
||||||
|
@ -465,13 +519,15 @@ type cWidget struct {
|
||||||
click *gesture.Click
|
click *gesture.Click
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w cWidget) Layout(ctx *Context) {
|
func (w *cWidget) Layout(ctx *Context) {
|
||||||
|
Mallocs("cWidget.Layout()")
|
||||||
w.w.Layout(ctx)
|
w.w.Layout(ctx)
|
||||||
pointer.RectAreaOp{image.Rect(0, 0, ctx.dims.Size.X, ctx.dims.Size.Y)}.Add(ctx.ops)
|
pointer.RectAreaOp{image.Rect(0, 0, ctx.dims.Size.X, ctx.dims.Size.Y)}.Add(ctx.ops)
|
||||||
w.click.Add(ctx.ops)
|
w.click.Add(ctx.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w cWidget) Clicked(ctx *Context) bool {
|
func (w cWidget) Clicked(ctx *Context) bool {
|
||||||
|
Mallocs("cWidget.Clicked()")
|
||||||
for e, ok := w.click.Next(ctx.q); ok; e, ok = w.click.Next(ctx.q) {
|
for e, ok := w.click.Next(ctx.q); ok; e, ok = w.click.Next(ctx.q) {
|
||||||
if e.Type == gesture.TypeClick {
|
if e.Type == gesture.TypeClick {
|
||||||
ctx.w.Invalidate()
|
ctx.w.Invalidate()
|
||||||
|
@ -482,6 +538,6 @@ func (w cWidget) Clicked(ctx *Context) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clickable converts any Widget into a clickable Widget.
|
//Clickable converts any Widget into a clickable Widget.
|
||||||
func AsClickable(w Widget) cWidget {
|
func AsClickable(w Widget) *cWidget {
|
||||||
return cWidget{w: w, click: new(gesture.Click)}
|
return &cWidget{w: w, click: new(gesture.Click)}
|
||||||
}
|
}
|
||||||
|
|
34
prof.go
Normal file
34
prof.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package giowrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AllocEntry struct {
|
||||||
|
Value uint64
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
memstats runtime.MemStats
|
||||||
|
oldMallocs uint64
|
||||||
|
AllMallocs []AllocEntry
|
||||||
|
)
|
||||||
|
|
||||||
|
func RecordMallocs() {
|
||||||
|
if AllMallocs == nil {
|
||||||
|
AllMallocs = make([]AllocEntry, 0, 64)
|
||||||
|
} else {
|
||||||
|
AllMallocs = AllMallocs[0:0]
|
||||||
|
}
|
||||||
|
runtime.ReadMemStats(&memstats)
|
||||||
|
oldMallocs = memstats.Mallocs
|
||||||
|
}
|
||||||
|
|
||||||
|
func Mallocs(s string) {
|
||||||
|
if AllMallocs == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runtime.ReadMemStats(&memstats)
|
||||||
|
AllMallocs = append(AllMallocs, AllocEntry{memstats.Mallocs - oldMallocs, s})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user