package giowrap import ( "image" "gioui.org/ui" "gioui.org/ui/f32" "gioui.org/ui/layout" ) type Grid struct { Cols int Height, Width int macro ui.MacroOp ops *ui.Ops cs layout.Constraints mode gridMode row, col int } type GridChild struct { dims layout.Dimensions macro ui.MacroOp } type gridMode uint8 const ( modeNone gridMode = iota modeBegun ) func (g *Grid) Init(ops *ui.Ops, cs layout.Constraints) layout.Constraints { g.mode = modeBegun g.ops = ops g.cs = cs g.row, g.col = 0, 0 cs.Height.Min = 0 if g.Height != 0 { g.cs.Height.Max = g.Height } if g.Width != 0 { g.cs.Width.Max = g.Width } cs.Width.Max = g.cs.Width.Max / g.Cols if g.Cols > 1 { cs.Width.Min = cs.Width.Max } return cs } func (g *Grid) Begin() { g.macro.Record(g.ops) } func (g *Grid) End(dims layout.Dimensions) GridChild { if g.mode != modeBegun { panic("Must call Grid.Begin() before adding children.") } g.macro.Stop() return GridChild{dims: dims, macro: g.macro} } func (g *Grid) Layout(cs ...GridChild) layout.Dimensions { rowheight := 0 height := 0 var width float32 var maxwidth float32 for _, c := range cs { var stack ui.StackOp stack.Push(g.ops) c.macro.Add(g.ops) stack.Pop() if c.dims.Size.Y > rowheight { rowheight = c.dims.Size.Y } g.col = g.col + 1 var x float32 if g.Cols == 1 { x = float32(c.dims.Size.X) if x > maxwidth { maxwidth = x } } else { x = float32(g.cs.Width.Max / g.Cols) } if g.col < g.Cols { ui.TransformOp{}.Offset(f32.Point{X: x}).Add(g.ops) width = width + x } else { g.col = 0 ui.TransformOp{}.Offset(f32.Point{X: -width, Y: float32(rowheight)}).Add(g.ops) g.row = g.row + 1 height = height + rowheight width = 0 rowheight = 0 } } if height == 0 { height = rowheight } g.mode = modeNone var dwidth int if g.Cols == 1 { dwidth = int(maxwidth) } else { dwidth = g.cs.Width.Max } return layout.Dimensions{Size: image.Point{dwidth, height}} } func toPointF(p image.Point) f32.Point { return f32.Point{X: float32(p.X), Y: float32(p.Y)} } type GridOption interface{ DoGridOption(*Grid) } type HeightOpt struct{ height int } func Height(x int) HeightOpt { return HeightOpt{x} } 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 { ret := &gridWidget{} ret.g = Grid{Cols: cols} for _, gop := range gops { gop.DoGridOption(&ret.g) } ret.gcs = make([]GridChild, 0) return func(ws ...Widget) Widget { ret.ws = ws return ret } } 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] }