From 1892d73161a006182d7ef467e2bfc03c11587cb6 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 17 Feb 2018 15:21:22 -0500 Subject: Add grid rendering, probably --- ui/drawable.go | 2 +- ui/grid.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/ui/drawable.go b/ui/drawable.go index eb60463b..a61c0203 100644 --- a/ui/drawable.go +++ b/ui/drawable.go @@ -2,7 +2,7 @@ package ui type Drawable interface { // Called when this renderable should draw itself - Draw(ctx Context) + Draw(ctx *Context) // Specifies a function to call when this cell needs to be redrawn OnInvalidate(callback func(d Drawable)) } diff --git a/ui/grid.go b/ui/grid.go index fd0cab7b..2183a557 100644 --- a/ui/grid.go +++ b/ui/grid.go @@ -4,9 +4,12 @@ import "fmt" type Grid struct { Rows []DimSpec + rowLayout []dimLayout Columns []DimSpec + columnLayout []dimLayout Cells []*GridCell onInvalidate func(d Drawable) + invalid bool } const ( @@ -17,24 +20,86 @@ const ( // Specifies the layout of a single row or column type DimSpec struct { // One of SIZE_EXACT or SIZE_WEIGHT - Strategy uint + Strategy int // If Strategy = SIZE_EXACT, this is the number of cells this dim shall // occupy. If SIZE_WEIGHT, the space left after all exact dims are measured // is distributed amonst the remaining dims weighted by this value. - Size *uint + Size int +} + +// Used to cache layout of each row/column +type dimLayout struct { + Offset int + Size int } type GridCell struct { - Row uint - Column uint - RowSpan uint - ColSpan uint + Row int + Column int + RowSpan int + ColSpan int Content Drawable invalid bool } -func (grid *Grid) Draw(ctx Context) { - // TODO +func (grid *Grid) Draw(ctx *Context) { + invalid := grid.invalid + if invalid { + grid.reflow(ctx) + } + for _, cell := range grid.Cells { + if !cell.invalid && !invalid { + continue + } + rows := grid.rowLayout[cell.Row:cell.RowSpan] + cols := grid.columnLayout[cell.Column:cell.ColSpan] + x := cols[0].Offset + y := rows[0].Offset + width := 0 + height := 0 + for _, row := range rows { + width += row.Size + } + for _, col := range cols { + height += col.Size + } + subctx := ctx.Subcontext(x, y, width, height) + cell.Content.Draw(subctx) + } +} + +func (grid *Grid) reflow(ctx *Context) { + grid.rowLayout = nil + grid.columnLayout = nil + flow := func(specs *[]DimSpec, layouts *[]dimLayout, extent int) { + exact := 0 + weight := 0 + for _, dim := range *specs { + if dim.Strategy == SIZE_EXACT { + exact += dim.Size + } else if dim.Strategy == SIZE_WEIGHT { + weight += dim.Size + } + } + offset := 0 + for _, dim := range *specs { + layout := dimLayout{Offset: offset} + if dim.Strategy == SIZE_EXACT { + layout.Size = dim.Size + } else if dim.Strategy == SIZE_WEIGHT { + size := float64(dim.Size) / float64(weight) * float64(extent) + layout.Size = int(size) + } + *layouts = append(*layouts, layout) + } + } + flow(&grid.Rows, &grid.rowLayout, ctx.Width()) + flow(&grid.Columns, &grid.columnLayout, ctx.Height()) + grid.invalid = false +} + +func (grid *Grid) InvalidateLayout() { + grid.invalid = true } func (grid *Grid) OnInvalidate(onInvalidate func(d Drawable)) { @@ -45,6 +110,7 @@ func (grid *Grid) AddChild(cell *GridCell) { grid.Cells = append(grid.Cells, cell) cell.Content.OnInvalidate(grid.cellInvalidated) cell.invalid = true + grid.InvalidateLayout() } func (grid *Grid) RemoveChild(cell *GridCell) { @@ -54,6 +120,7 @@ func (grid *Grid) RemoveChild(cell *GridCell) { break } } + grid.InvalidateLayout() } func (grid *Grid) cellInvalidated(drawable Drawable) { -- cgit