summaryrefslogtreecommitdiff
path: root/grid.go
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-02-25 18:21:58 -0500
committerPietro Gagliardi <[email protected]>2014-02-25 18:21:58 -0500
commit7ba3c5ac17d5203038ab33b0b207cef274707dad (patch)
tree0851685efd2c1a2538d535c0f9056e85913685b7 /grid.go
parent7bbd50467c663eab9b312b165ae2585e5f955679 (diff)
Added untested initial Grid. Now to write a test.
Diffstat (limited to 'grid.go')
-rw-r--r--grid.go157
1 files changed, 157 insertions, 0 deletions
diff --git a/grid.go b/grid.go
new file mode 100644
index 0000000..b8ecc46
--- /dev/null
+++ b/grid.go
@@ -0,0 +1,157 @@
+// 25 february 2014
+package ui
+
+import (
+ "sync"
+)
+
+// A Grid arranges Controls in a two-dimensional grid.
+// All Controls in a Grid maintain their preferred sizes.
+// 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).
+// Unlike other UI toolkit Grids, this Grid does not (yet?) allow Controls to span multiple rows or columns.
+type Grid struct {
+ lock sync.Mutex
+ created bool
+ controls [][]Control
+ cwidths, cheights [][]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)
+ cw := make([][]int, nRows)
+ ch := make([][]int, nRow)
+ i := 0
+ for row := 0; row < nRows; row++ {
+ cc[row] = make([]Control, 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,
+ widths: cw,
+ heights: ch,
+ rowheights: make([]int, nRows),
+ colwidths: make([]int, nPerRow),
+ }
+}
+
+func (g *Grid) make(window *sysData) error {
+ g.lock.Lock()
+ defer g.lock.Unlock()
+
+ 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) setRect(x int, y int, width int, height int) error {
+ g.lock.Lock()
+ defer g.lock.Unlock()
+
+ max := func(a int, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+ }
+
+ // 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, err := c.preferredSize()
+ if err != nil {
+ return fmt.Errorf("error getting preferred size of control (%d,%d) in Grid.setRect(): %v", row, col, err)
+ }
+ widths[row][col] = w
+ g.heights[row][col] = h
+ g.rowheights[row] = max(g.rowheights[row], h)
+ g.colwidths[col] = max(g.colwidths[row], w)
+ }
+ }
+ // 3) draw
+ startx := x
+ for row, xcol := range g.controls {
+ for col, c := range xcol {
+ err = c.setRect(x, y, g.widths[row][col], g.heights[row][col])
+ if err != nil {
+ return fmt.Errorf("error setting size of control (%d,%d) in Grid.setRect(): %v", row, col, err)
+ }
+ x += colwidths[col]
+ }
+ x = startx
+ y += rowheights[row]
+ }
+ return nil
+}
+
+func (g *Grid) preferredSize() (width int, height int, err error) {
+ g.lock.Lock()
+ defer g.lock.Unlock()
+
+ max := func(a int, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+ }
+
+ // 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, err := c.preferredSize()
+ if err != nil {
+ return fmt.Errorf("error getting preferred size of control (%d,%d) in Grid.setRect(): %v", row, col, err)
+ }
+ widths[row][col] = w
+ g.heights[row][col] = h
+ g.rowheights[row] = max(g.rowheights[row], h)
+ g.colwidths[col] = max(g.colwidths[row], w)
+ }
+ }
+ // 3) now compute
+ for _, w := range g.colwidths {
+ width += w
+ }
+ for _, h := range g.rowheights {
+ height += h
+ }
+ return width, height, nil
+}