summary refs log tree commit diff stats
path: root/ui/grid.go
diff options
context:
space:
mode:
Diffstat (limited to 'ui/grid.go')
-rw-r--r--ui/grid.go83
1 files changed, 75 insertions, 8 deletions
diff --git a/ui/grid.go b/ui/grid.go
index fd0cab7..2183a55 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) {
>254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286