about summary refs log tree commit diff stats
path: root/ui
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-02-17 15:21:22 -0500
committerDrew DeVault <sir@cmpwn.com>2018-02-17 15:21:31 -0500
commit1892d73161a006182d7ef467e2bfc03c11587cb6 (patch)
tree8c785e6cfbe5f7dfeda988e5cebded269791a60e /ui
parent8c8c21f3ffef1a7083405c45221576858d1af5d5 (diff)
downloadaerc-1892d73161a006182d7ef467e2bfc03c11587cb6.tar.gz
Add grid rendering, probably
Diffstat (limited to 'ui')
-rw-r--r--ui/drawable.go2
-rw-r--r--ui/grid.go83
2 files changed, 76 insertions, 9 deletions
diff --git a/ui/drawable.go b/ui/drawable.go
index eb60463..a61c020 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 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) {