137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
// Standard layout components.
|
|
|
|
package ui
|
|
|
|
// Instance of a component.
|
|
type componentInstance struct {
|
|
component UiComponent
|
|
x, y int // X and Y offset of this component
|
|
height int // Height allocated to the component
|
|
width int // Width allocated to the component
|
|
}
|
|
|
|
// A layout component.
|
|
type LinearLayout struct {
|
|
// The set of components that this layout component contains
|
|
subcomponents []*componentInstance
|
|
}
|
|
|
|
// Adds a component to the end of the component list managed by this layout.
|
|
func (l *LinearLayout) Append(component UiComponent) {
|
|
l.subcomponents = append(l.subcomponents, &componentInstance{component, 0, 0, 0, 0})
|
|
}
|
|
|
|
|
|
// A vertical layout component.
|
|
type VertLinearLayout struct {
|
|
LinearLayout
|
|
maxHeight int
|
|
}
|
|
|
|
|
|
// Request from the manager for the component to draw itself. This is given a drawable context.
|
|
func (vl *VertLinearLayout) Redraw(context *DrawContext) {
|
|
for _, ci := range vl.LinearLayout.subcomponents {
|
|
subContext := context.NewSubContext(ci.x, ci.y, ci.width, ci.height)
|
|
ci.component.Redraw(subContext)
|
|
}
|
|
}
|
|
|
|
// Remeasures the components currently managed within this layout.
|
|
func (vl *VertLinearLayout) Remeasure(w, h int) (int, int) {
|
|
posy := 0
|
|
|
|
// TODO: At the moment, this simply takes the minimum and maximum dimensions requested
|
|
// by the components. This needs to be extended to allow for "special" components which
|
|
// take up dynamic space.
|
|
for _, ci := range vl.LinearLayout.subcomponents {
|
|
_, rh := ci.component.Remeasure(w, h - posy)
|
|
|
|
// All components within this layer are given the full width of the screen.
|
|
ci.x = 0
|
|
ci.width = w
|
|
ci.y = posy
|
|
ci.height = rh
|
|
|
|
// Put the next component directly below the previous one
|
|
posy += rh
|
|
}
|
|
|
|
return w, posy
|
|
}
|
|
|
|
|
|
|
|
// A layout component which defers calls to the nested component. If no control is defined,
|
|
// will not draw itself. Used for switching controls dynamically.
|
|
type ProxyLayout struct {
|
|
Component UiComponent
|
|
}
|
|
|
|
func (pl *ProxyLayout) Remeasure(w, h int) (int, int) {
|
|
if pl.Component != nil {
|
|
return pl.Component.Remeasure(w, h)
|
|
} else {
|
|
return 0, 0
|
|
}
|
|
}
|
|
|
|
func (pl *ProxyLayout) Redraw(context *DrawContext) {
|
|
if pl.Component != nil {
|
|
pl.Component.Redraw(context)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// A relative layout component. This has a "client" component, bordered by a north,
|
|
// south, east and west component. The N,S,E,W components will be provided with the full dimensions
|
|
// whereas the client component will be provided with the remaining size. Each one of the components
|
|
// can be null.
|
|
type RelativeLayout struct {
|
|
North, South, East, West, Client UiComponent
|
|
|
|
// Measured client borders
|
|
ct, cb, cl, cr, ch, cw int
|
|
|
|
// North/south heights and east/west widths
|
|
nh, sh int
|
|
ew, ww int
|
|
}
|
|
|
|
func (rl *RelativeLayout) Remeasure(w, h int) (int, int) {
|
|
if rl.North != nil {
|
|
_, rl.nh = rl.North.Remeasure(w, h)
|
|
rl.ct = rl.nh
|
|
} else {
|
|
rl.ct = 0
|
|
}
|
|
|
|
if rl.South != nil {
|
|
_, rl.sh = rl.South.Remeasure(w, h - rl.nh)
|
|
rl.cb = h - rl.sh
|
|
} else {
|
|
rl.cb = h
|
|
}
|
|
|
|
// TODO: East and west
|
|
rl.cl = 0
|
|
rl.cr = w
|
|
|
|
rl.ch = h - rl.nh - rl.sh
|
|
rl.cw = w
|
|
|
|
return w, h
|
|
}
|
|
|
|
func (vl *RelativeLayout) Redraw(context *DrawContext) {
|
|
if vl.North != nil {
|
|
vl.North.Redraw(context.NewSubContext(0, 0, context.W, vl.nh))
|
|
}
|
|
if vl.South != nil {
|
|
vl.South.Redraw(context.NewSubContext(0, vl.cb, context.W, vl.sh))
|
|
}
|
|
if vl.Client != nil {
|
|
vl.Client.Redraw(context.NewSubContext(vl.cl, vl.ct, vl.cw, vl.ch))
|
|
}
|
|
} |