aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
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 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) {