2014-02-13 16:04:57 -06:00
// 13 february 2014
2014-02-19 10:41:10 -06:00
package ui
2014-02-13 16:04:57 -06:00
import (
"fmt"
"sync"
)
// Orientation defines the orientation of controls in a Stack.
type Orientation int
const (
Horizontal Orientation = iota
Vertical
)
2014-02-24 09:29:15 -06:00
// A Stack stacks controls horizontally or vertically within the Stack's parent.
// A horizontal Stack gives all controls the same height and their preferred widths.
// A vertical Stack gives all controls the same width and their preferred heights.
// Some controls may be marked as "stretchy": when the Window they are in changes size, stretchy controls resize to take up the remaining space after non-stretchy controls are laid out. If multiple controls are marked stretchy, they are alloted equal distribution of the remaining space.
2014-02-13 16:04:57 -06:00
type Stack struct {
lock sync . Mutex
created bool
orientation Orientation
2014-02-14 09:58:16 -06:00
controls [ ] Control
2014-02-24 09:29:15 -06:00
stretchy [ ] bool
xpos , ypos [ ] int // caches to avoid reallocating these each time
width , height [ ] int
2014-02-13 16:04:57 -06:00
}
// NewStack creates a new Stack with the specified orientation.
2014-02-14 09:58:16 -06:00
func NewStack ( o Orientation , controls ... Control ) * Stack {
2014-02-13 16:04:57 -06:00
if o != Horizontal && o != Vertical {
panic ( fmt . Sprintf ( "invalid orientation %d given to NewStack()" , o ) )
}
return & Stack {
orientation : o ,
2014-02-14 09:58:16 -06:00
controls : controls ,
2014-02-24 09:29:15 -06:00
stretchy : make ( [ ] bool , len ( controls ) ) ,
xpos : make ( [ ] int , len ( controls ) ) ,
ypos : make ( [ ] int , len ( controls ) ) ,
width : make ( [ ] int , len ( controls ) ) ,
height : make ( [ ] int , len ( controls ) ) ,
2014-02-13 16:04:57 -06:00
}
}
2014-02-24 09:29:15 -06:00
// SetStretchy marks a control in a Stack as stretchy.
func ( s * Stack ) SetStretchy ( index int ) {
s . lock . Lock ( )
defer s . lock . Unlock ( )
s [ index ] = true // TODO explicitly check for index out of bounds?
}
2014-02-14 10:12:08 -06:00
func ( s * Stack ) make ( window * sysData ) error {
2014-02-15 14:38:41 -06:00
for i , c := range s . controls {
2014-02-14 10:12:08 -06:00
err := c . make ( window )
2014-02-13 16:04:57 -06:00
if err != nil {
2014-02-24 09:29:15 -06:00
return fmt . Errorf ( "error adding control %d to Stack: %v" , i , err )
2014-02-13 16:04:57 -06:00
}
}
2014-02-14 19:41:36 -06:00
s . created = true
2014-02-13 16:04:57 -06:00
return nil
}
func ( s * Stack ) setRect ( x int , y int , width int , height int ) error {
var dx , dy int
2014-02-14 09:58:16 -06:00
if len ( s . controls ) == 0 { // do nothing if there's nothing to do
2014-02-13 16:04:57 -06:00
return nil
}
switch s . orientation {
case Horizontal :
2014-02-14 09:58:16 -06:00
dx = width / len ( s . controls )
2014-02-13 16:04:57 -06:00
width = dx
case Vertical :
2014-02-14 09:58:16 -06:00
dy = height / len ( s . controls )
2014-02-13 16:04:57 -06:00
height = dy
default :
panic ( fmt . Sprintf ( "invalid orientation %d given to Stack.setRect()" , s . orientation ) )
}
2014-02-15 14:38:41 -06:00
for i , c := range s . controls {
2014-02-13 16:04:57 -06:00
err := c . setRect ( x , y , width , height )
if err != nil {
2014-02-15 14:38:41 -06:00
return fmt . Errorf ( "error setting size of control %d: %v" , i , err )
2014-02-13 16:04:57 -06:00
}
x += dx
y += dy
}
return nil
}