package main import ( "log" "time" "gioui.org/ui" "gioui.org/ui/app" "gioui.org/ui/input" "gioui.org/ui/layout" "gioui.org/ui/measure" "gioui.org/ui/text" "golang.org/x/image/font/gofont/goregular" "golang.org/x/image/font/sfnt" ) type Context struct { w *app.Window c *app.Config q input.Queue ops *ui.Ops cs layout.Constraints dims layout.Dimens faces measure.Faces } func NewContext(w *app.Window) *Context { return &Context{ ops: new(ui.Ops), q: w.Queue(), } } func (ctx *Context) Reset(e app.DrawEvent) { ctx.c = &e.Config ctx.ops.Reset() ctx.cs = layout.RigidConstraints(e.Size) ctx.faces.Reset(ctx.c) } func (fw fWidget) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimens { return fw.l(c, q, ops, cs) } type Widget interface { Layout(ui.Config, input.Queue, *ui.Ops, layout.Constraints) layout.Dimens } type fWidget struct { l Layout } type WidgetCombinator func(...Widget) Widget type Layout func(ui.Config, input.Queue, *ui.Ops, layout.Constraints) layout.Dimens type LayoutCombinator func(...Layout) Layout func (ctx *Context) Do(ls ...Layout) { for _, l := range ls { ctx.dims = l(ctx.c, ctx.q, ctx.ops, ctx.cs) } } type Label struct { l *text.Label } func (l *Label) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimens { return l.l.Layout(ops, cs) } func main() { go func() { w := app.NewWindow(nil) regular, err := sfnt.Parse(goregular.TTF) if err != nil { log.Fatal("Cannot parse font.") } ctx := NewContext(w) t := time.NewTicker(time.Second/30) e1 := &text.Editor{ Face: ctx.faces.For(regular, ui.Sp(24)), SingleLine: true, } e1.SetText("hi there") e1.Focus() e2 := &text.Editor{ Face: ctx.faces.For(regular, ui.Sp(24)), SingleLine: true, } e2.SetText("ok bye") f := Flex(layout.Vertical, layout.Start, layout.Start) ins10a := Inset(ui.Dp(10),ui.Dp(10),ui.Dp(10),ui.Dp(10)) ins10b := Inset(ui.Dp(10),ui.Dp(10),ui.Dp(10),ui.Dp(10)) btn := &Label{} btn.l = &text.Label{ Face: ctx.faces.For(regular, ui.Sp(24)), Text: "centered", Alignment: text.Center, } for { select { case <-t.C: w.Invalidate() case e := <-w.Events(): switch e := e.(type) { case app.DestroyEvent: return case app.DrawEvent: ctx.Reset(e) ctx.Do( ins10a(f( FlexChild{10,e1}, FlexChild{5,ins10b(e2)}, FlexChild{1,btn}, )).Layout) w.Draw(ctx.ops) } } } }() app.Main() } type FlexChild struct { x float32 w Widget } func Flex(axis layout.Axis, mainAxisAlignment layout.MainAxisAlignment, crossAxisAlignment layout.CrossAxisAlignment) func(...FlexChild) Widget { f := layout.Flex{ Axis: axis, MainAxisAlignment: mainAxisAlignment, CrossAxisAlignment: crossAxisAlignment, } return func(ws ...FlexChild) Widget { ret := fWidget{} ret.l = func(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimens { f.Init(ops, cs) cs = f.Rigid() var dims layout.Dimens fcs := make([]layout.FlexChild,len(ws)) for i, w := range ws { if i > 0 { cs = f.Flexible(w.x) } dims = w.w.Layout(c, q, ops, cs) fcs[i] = f.End(dims) } return f.Layout(fcs...) } return ret } } func Inset(top, right, bottom, left ui.Value) WidgetCombinator { ins := layout.Inset{ Top: top, Right: right, Bottom: bottom, Left: left } return func(ws ...Widget) Widget { ret := fWidget{} ret.l = func(c ui.Config, q input.Queue, ops *ui.Ops, cs layout.Constraints) layout.Dimens { cs = ins.Begin(c, ops, cs) var dims layout.Dimens for _, w := range ws { dims = w.Layout(c, q, ops, cs) } return ins.End(dims) } return ret } }