Adjusted Grid to be like new Stack. Automatically made Labels in Grids filling.
This commit is contained in:
parent
1fe7831cb8
commit
d824e549f1
78
redo/grid.go
78
redo/grid.go
|
@ -6,8 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO Grids on GTK+ will not respect non-standalone Labels unless SetFilling()
|
|
||||||
|
|
||||||
// A Grid arranges Controls in a two-dimensional grid.
|
// 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).
|
// 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.
|
// Controls are aligned to the top left corner of each cell.
|
||||||
|
@ -16,8 +14,23 @@ import (
|
||||||
// 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).
|
// 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.
|
// 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.
|
// All cooridnates in a Grid are given in (row,column) form with (0,0) being the top-left cell.
|
||||||
type Grid struct {
|
//
|
||||||
created bool
|
// As a special rule, to ensure proper appearance, non-standalone Labels are automatically made filling.
|
||||||
|
type Grid interface {
|
||||||
|
Control
|
||||||
|
|
||||||
|
// SetFilling marks the given Control of the Grid as filling its cell instead of staying at its preferred size.
|
||||||
|
// It panics if the given coordinate is invalid.
|
||||||
|
SetFilling(row int, column int)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// It panics if the given coordinate is invalid.
|
||||||
|
SetStretchy(row int, column int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type grid struct {
|
||||||
controls [][]Control
|
controls [][]Control
|
||||||
filling [][]bool
|
filling [][]bool
|
||||||
stretchyrow, stretchycol int
|
stretchyrow, stretchycol int
|
||||||
|
@ -33,7 +46,7 @@ type Grid struct {
|
||||||
// control00, control01, control02,
|
// control00, control01, control02,
|
||||||
// control10, control11, control12,
|
// control10, control11, control12,
|
||||||
// control20, control21, control22)
|
// control20, control21, control22)
|
||||||
func NewGrid(nPerRow int, controls ...Control) *Grid {
|
func NewGrid(nPerRow int, controls ...Control) Grid {
|
||||||
if len(controls)%nPerRow != 0 {
|
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))
|
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))
|
||||||
}
|
}
|
||||||
|
@ -50,10 +63,13 @@ func NewGrid(nPerRow int, controls ...Control) *Grid {
|
||||||
ch[row] = make([]int, nPerRow)
|
ch[row] = make([]int, nPerRow)
|
||||||
for x := 0; x < nPerRow; x++ {
|
for x := 0; x < nPerRow; x++ {
|
||||||
cc[row][x] = controls[i]
|
cc[row][x] = controls[i]
|
||||||
|
if l, ok := controls[i].(Label); ok && !l.isStandalone() {
|
||||||
|
cf[row][x] = true
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Grid{
|
return &grid{
|
||||||
controls: cc,
|
controls: cc,
|
||||||
filling: cf,
|
filling: cf,
|
||||||
stretchyrow: -1,
|
stretchyrow: -1,
|
||||||
|
@ -65,28 +81,14 @@ func NewGrid(nPerRow int, controls ...Control) *Grid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFilling marks the given Control of the Grid as filling its cell instead of staying at its preferred size.
|
func (g *grid) SetFilling(row int, column int) {
|
||||||
// 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]) {
|
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))
|
panic(fmt.Errorf("coordinate (%d,%d) out of range passed to Grid.SetFilling()", row, column))
|
||||||
}
|
}
|
||||||
g.filling[row][column] = true
|
g.filling[row][column] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetStretchy marks the given Control of the Grid as stretchy.
|
func (g *grid) SetStretchy(row int, column int) {
|
||||||
// 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]) {
|
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))
|
panic(fmt.Errorf("coordinate (%d,%d) out of range passed to Grid.SetStretchy()", row, column))
|
||||||
}
|
}
|
||||||
|
@ -95,27 +97,15 @@ func (g *Grid) SetStretchy(row int, column int) {
|
||||||
// don't set filling here in case we call SetStretchy() multiple times; the filling is committed in make() below
|
// 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 {
|
func (g *grid) setParent(parent *controlParent) {
|
||||||
// commit filling for the stretchy control now (see SetStretchy() above)
|
for _, col := range s.controls {
|
||||||
if g.stretchyrow != -1 && g.stretchycol != -1 {
|
for _, c := range col {
|
||||||
g.filling[g.stretchyrow][g.stretchycol] = true
|
c.setParent(parent)
|
||||||
} 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) {
|
func (g *grid) allocate(x int, y int, width int, height int, d *sysSizeData) (allocations []*allocation) {
|
||||||
max := func(a int, b int) int {
|
max := func(a int, b int) int {
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
|
@ -125,7 +115,9 @@ func (g *Grid) allocate(x int, y int, width int, height int, d *sysSizeData) (al
|
||||||
|
|
||||||
var current *allocation // for neighboring
|
var current *allocation // for neighboring
|
||||||
|
|
||||||
// TODO return if nControls == 0?
|
if len(controls) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// 0) inset the available rect by the needed padding
|
// 0) inset the available rect by the needed padding
|
||||||
width -= (len(g.colwidths) - 1) * d.xpadding
|
width -= (len(g.colwidths) - 1) * d.xpadding
|
||||||
height -= (len(g.rowheights) - 1) * d.ypadding
|
height -= (len(g.rowheights) - 1) * d.ypadding
|
||||||
|
@ -191,7 +183,7 @@ func (g *Grid) allocate(x int, y int, width int, height int, d *sysSizeData) (al
|
||||||
}
|
}
|
||||||
|
|
||||||
// filling and stretchy are ignored for preferred size calculation
|
// filling and stretchy are ignored for preferred size calculation
|
||||||
func (g *Grid) preferredSize(d *sysSizeData) (width int, height int) {
|
func (g *grid) preferredSize(d *sysSizeData) (width int, height int) {
|
||||||
max := func(a int, b int) int {
|
max := func(a int, b int) int {
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
|
@ -228,10 +220,10 @@ func (g *Grid) preferredSize(d *sysSizeData) (width int, height int) {
|
||||||
return width, height
|
return width, height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Grid) commitResize(c *allocation, d *sysSizeData) {
|
func (g *grid) commitResize(c *allocation, d *sysSizeData) {
|
||||||
// this is to satisfy Control; nothing to do here
|
// this is to satisfy Control; nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Grid) getAuxResizeInfo(d *sysSizeData) {
|
func (g *grid) getAuxResizeInfo(d *sysSizeData) {
|
||||||
// this is to satisfy Control; nothing to do here
|
// this is to satisfy Control; nothing to do here
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue