giowrap/grid.go

158 lines
2.9 KiB
Go

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]
}