summaryrefslogtreecommitdiff
path: root/grid.go
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-07-02 17:13:40 -0400
committerPietro Gagliardi <[email protected]>2014-07-02 17:13:40 -0400
commit5d339e656b66d00356960ae057969532d34245b4 (patch)
tree01f00932aba2a4b996603beeda788995e0f0a382 /grid.go
parent2d7e168e6a350a0cfb52970fbf74c9e37834eaec (diff)
Moved everything out of the way pending rewrite.
Diffstat (limited to 'grid.go')
-rw-r--r--grid.go245
1 files changed, 0 insertions, 245 deletions
diff --git a/grid.go b/grid.go
deleted file mode 100644
index bc58a00..0000000
--- a/grid.go
+++ /dev/null
@@ -1,245 +0,0 @@
-// 25 february 2014
-
-package ui
-
-import (
- "fmt"
-)
-
-// A Grid arranges Controls in a two-dimensional grid.
-// The height of each row and the width of each column is the maximum preferred height and width (respectively) of all the controls in that row or column (respectively).
-// Controls are aligned to the top left corner of each cell.
-// All Controls in a Grid maintain their preferred sizes by default; if a Control is marked as being "filling", it will be sized to fill its cell.
-// Even if a Control is marked as filling, its preferred size is used to calculate cell sizes.
-// One Control can be marked as "stretchy": when the Window containing the Grid is resized, the cell containing that Control resizes to take any remaining space; its row and column are adjusted accordingly (so other filling controls in the same row and column will fill to the new height and width, respectively).
-// A stretchy Control implicitly fills its cell.
-// All cooridnates in a Grid are given in (row,column) form with (0,0) being the top-left cell.
-type Grid struct {
- created bool
- controls [][]Control
- filling [][]bool
- stretchyrow, stretchycol int
- widths, heights [][]int // caches to avoid reallocating each time
- rowheights, colwidths []int
-}
-
-// NewGrid creates a new Grid with the given Controls.
-// NewGrid needs to know the number of Controls in a row (alternatively, the number of columns); it will determine the number in a column from the number of Controls given.
-// NewGrid panics if not given a full grid of Controls.
-// Example:
-// grid := NewGrid(3,
-// control00, control01, control02,
-// control10, control11, control12,
-// control20, control21, control22)
-func NewGrid(nPerRow int, controls ...Control) *Grid {
- if len(controls)%nPerRow != 0 {
- panic(fmt.Errorf("incomplete grid given to NewGrid() (not enough controls to evenly divide %d controls into rows of %d controls each)", len(controls), nPerRow))
- }
- nRows := len(controls) / nPerRow
- cc := make([][]Control, nRows)
- cf := make([][]bool, nRows)
- cw := make([][]int, nRows)
- ch := make([][]int, nRows)
- i := 0
- for row := 0; row < nRows; row++ {
- cc[row] = make([]Control, nPerRow)
- cf[row] = make([]bool, nPerRow)
- cw[row] = make([]int, nPerRow)
- ch[row] = make([]int, nPerRow)
- for x := 0; x < nPerRow; x++ {
- cc[row][x] = controls[i]
- i++
- }
- }
- return &Grid{
- controls: cc,
- filling: cf,
- stretchyrow: -1,
- stretchycol: -1,
- widths: cw,
- heights: ch,
- rowheights: make([]int, nRows),
- colwidths: make([]int, nPerRow),
- }
-}
-
-// SetFilling marks the given Control of the Grid as filling its cell instead of staying at its preferred size.
-// This function cannot be called after the Window that contains the Grid has been created.
-// It panics if the given coordinate is invalid.
-func (g *Grid) SetFilling(row int, column int) {
- if g.created {
- panic(fmt.Errorf("Grid.SetFilling() called after window create"))
- }
- if row < 0 || column < 0 || row > len(g.filling) || column > len(g.filling[row]) {
- panic(fmt.Errorf("coordinate (%d,%d) out of range passed to Grid.SetFilling()", row, column))
- }
- g.filling[row][column] = true
-}
-
-// SetStretchy marks the given Control of the Grid as stretchy.
-// Stretchy implies filling.
-// Only one control can be stretchy per Grid; calling SetStretchy multiple times merely changes which control is stretchy.
-// This function cannot be called after the Window that contains the Grid has been created.
-// It panics if the given coordinate is invalid.
-func (g *Grid) SetStretchy(row int, column int) {
- if g.created {
- panic(fmt.Errorf("Grid.SetFilling() called after window create"))
- }
- if row < 0 || column < 0 || row > len(g.filling) || column > len(g.filling[row]) {
- panic(fmt.Errorf("coordinate (%d,%d) out of range passed to Grid.SetStretchy()", row, column))
- }
- g.stretchyrow = row
- g.stretchycol = column
- // don't set filling here in case we call SetStretchy() multiple times; the filling is committed in make() below
-}
-
-func (g *Grid) make(window *sysData) error {
- // commit filling for the stretchy control now (see SetStretchy() above)
- if g.stretchyrow != -1 && g.stretchycol != -1 {
- g.filling[g.stretchyrow][g.stretchycol] = true
- } else if (g.stretchyrow == -1 && g.stretchycol != -1) || // sanity check
- (g.stretchyrow != -1 && g.stretchycol == -1) {
- panic(fmt.Errorf("internal inconsistency in Grid: stretchy (%d,%d) impossible (one component, not both, is -1/no stretchy control) in Grid.make()", g.stretchyrow, g.stretchycol))
- }
- for row, xcol := range g.controls {
- for col, c := range xcol {
- err := c.make(window)
- if err != nil {
- return fmt.Errorf("error adding control (%d,%d) to Grid: %v", row, col, err)
- }
- }
- }
- g.created = true
- return nil
-}
-
-func (g *Grid) allocate(x int, y int, width int, height int, d *sysSizeData) (allocations []*allocation) {
- max := func(a int, b int) int {
- if a > b {
- return a
- }
- return b
- }
-
- var current *allocation // for neighboring
-
- // TODO return if nControls == 0?
- // before we do anything, steal the margin so nested Stacks/Grids don't double down
- xmargin := d.xmargin
- ymargin := d.ymargin
- d.xmargin = 0
- d.ymargin = 0
- // 0) inset the available rect by the margins and needed padding
- x += xmargin
- y += ymargin
- width -= xmargin * 2
- height -= ymargin * 2
- width -= (len(g.colwidths) - 1) * d.xpadding
- height -= (len(g.rowheights) - 1) * d.ypadding
- // 1) clear data structures
- for i := range g.rowheights {
- g.rowheights[i] = 0
- }
- for i := range g.colwidths {
- g.colwidths[i] = 0
- }
- // 2) get preferred sizes; compute row/column sizes
- for row, xcol := range g.controls {
- for col, c := range xcol {
- w, h := c.preferredSize(d)
- g.widths[row][col] = w
- g.heights[row][col] = h
- g.rowheights[row] = max(g.rowheights[row], h)
- g.colwidths[col] = max(g.colwidths[col], w)
- }
- }
- // 3) handle the stretchy control
- if g.stretchyrow != -1 && g.stretchycol != -1 {
- for i, w := range g.colwidths {
- if i != g.stretchycol {
- width -= w
- }
- }
- for i, h := range g.rowheights {
- if i != g.stretchyrow {
- height -= h
- }
- }
- g.colwidths[g.stretchycol] = width
- g.rowheights[g.stretchyrow] = height
- }
- // 4) draw
- startx := x
- for row, xcol := range g.controls {
- current = nil // reset on new columns
- for col, c := range xcol {
- w := g.widths[row][col]
- h := g.heights[row][col]
- if g.filling[row][col] {
- w = g.colwidths[col]
- h = g.rowheights[row]
- }
- as := c.allocate(x, y, w, h, d)
- if current != nil { // connect first left to first right
- current.neighbor = c
- }
- if len(as) != 0 {
- current = as[0] // next left is first subwidget
- } else {
- current = nil // spaces don't have allocation data
- }
- allocations = append(allocations, as...)
- x += g.colwidths[col] + d.xpadding
- }
- x = startx
- y += g.rowheights[row] + d.ypadding
- }
- return
-}
-
-// filling and stretchy are ignored for preferred size calculation
-// We don't consider the margins here, but will need to if Window.SizeToFit() is ever made a thing.
-func (g *Grid) preferredSize(d *sysSizeData) (width int, height int) {
- max := func(a int, b int) int {
- if a > b {
- return a
- }
- return b
- }
-
- width -= (len(g.colwidths) - 1) * d.xpadding
- height -= (len(g.rowheights) - 1) * d.ypadding
- // 1) clear data structures
- for i := range g.rowheights {
- g.rowheights[i] = 0
- }
- for i := range g.colwidths {
- g.colwidths[i] = 0
- }
- // 2) get preferred sizes; compute row/column sizes
- for row, xcol := range g.controls {
- for col, c := range xcol {
- w, h := c.preferredSize(d)
- g.widths[row][col] = w
- g.heights[row][col] = h
- g.rowheights[row] = max(g.rowheights[row], h)
- g.colwidths[col] = max(g.colwidths[col], w)
- }
- }
- // 3) now compute
- for _, w := range g.colwidths {
- width += w
- }
- for _, h := range g.rowheights {
- height += h
- }
- return width, height
-}
-
-func (g *Grid) commitResize(c *allocation, d *sysSizeData) {
- // this is to satisfy Control; nothing to do here
-}
-
-func (g *Grid) getAuxResizeInfo(d *sysSizeData) {
- // this is to satisfy Control; nothing to do here
-}