Compare commits

...

2 Commits

Author SHA1 Message Date
f134a1f21e Add form example, add /examples directory. 2019-08-30 14:51:08 -04:00
dfc3f618c0 Add FillWidth and FillHeight enclosures. 2019-08-30 13:35:56 -04:00
5 changed files with 291 additions and 3 deletions

2
.gitignore vendored
View File

@ -2,4 +2,6 @@ cmd/hello/hello
cmd/cal/cal
cmd/scroll/scroll
cmd/grid/grid
cmd/form/form
*.apk
memprofile*

View File

@ -20,7 +20,6 @@ import (
)
var (
sel int32
face text.Face
)

227
cmd/form/main.go Normal file
View File

@ -0,0 +1,227 @@
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 = ctx.Reset(&e)
giowrap.Mallocs("pre-layout")
ctx = (*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")
}

36
examples/ctx.go Normal file
View File

@ -0,0 +1,36 @@
{
ctx.Reset(&e) // ctx keeps a pointer to e.Config, so we can do...
ctx.RigidConstraints()
{
f1 := layout.Flex{Axis: layout.Vertical} // maybe pass ctx in here?
ins := layout.UniformInset(ui.Dp(10))
ins.Begin(ctx) // containers like Insets and Flex keep a pointer to ctx
f1.Init(ctx)
f1.Rigid()
editor1.Layout(ctx)
f1.End()
{
f1.Flexible(0.33)
ins := layout.UniformInset(ui.Dp(10))
ins.Begin(ctx)
editor2.Layout(ctx)
ins.End()
}
f1.End()
{
f1.Flexible(0.67)
f2 := layout.Flex{Axis: layout.Horizontal}
f2.Init(ctx)
f2.Rigid()
button1.Layout(ctx)
c1 := f2.End()
f2.Flexible(0.5)
button2.Layout(ctx)
c2 := f2.End()
f2.Layout(c1, c2)
}
c3 := f1.End()
f1.Layout(c1, c2, c3)
ins.End()
}
}

24
main.go
View File

@ -204,6 +204,7 @@ type List = WidgetCombinator
type AxisOpt struct{ axis layout.Axis }
func Axis(x layout.Axis) AxisOpt { return AxisOpt{x} }
var Horizontal = AxisOpt{layout.Horizontal}
var Vertical = AxisOpt{layout.Vertical}
@ -510,6 +511,29 @@ func Rrect(ops *ui.Ops, width, height, se, sw, nw, ne float32) {
Mallocs("Rrect() end")
}
type fillWidget struct {
axis layout.Axis
}
func FillWidth(ws ...Widget) Widget {
return Enclose(fillWidget{layout.Horizontal}, ws...)
}
func FillHeight(ws ...Widget) Widget {
return Enclose(fillWidget{layout.Vertical}, ws...)
}
func (fw fillWidget) Begin(ctx *Context) {
switch fw.axis {
case layout.Horizontal:
ctx.cs.Width.Min = ctx.cs.Width.Max
case layout.Vertical:
ctx.cs.Height.Min = ctx.cs.Height.Max
}
}
func (fw fillWidget) End(*Context) {
}
type Clickable interface {
Widget
Clicked(*Context) bool