zntg/ui/dockpanel.go

147 lines
3.1 KiB
Go

package ui
import (
"math"
"opslag.de/schobers/geom"
)
type DockPanel interface {
Container
Append(o Dock, children ...Control) error
AppendCreate(ctx Context, o Dock, children ...Control) error
}
type Dock int
const (
DockLeft Dock = iota
DockTop
DockRight
DockBottom
)
type dockPanel struct {
ContainerBase
docks []Dock
}
func NewDockPanel(parent Container) DockPanel {
return &dockPanel{ContainerBase: ContainerBase{parent: parent}}
}
func (p *dockPanel) Append(d Dock, children ...Control) error {
for _, child := range children {
p.ContainerBase.Append(child)
p.docks = append(p.docks, d)
}
return nil
}
func (p *dockPanel) AppendCreate(ctx Context, d Dock, children ...Control) error {
for _, child := range children {
err := p.ContainerBase.AppendCreate(ctx, child)
if nil != err {
return err
}
p.docks = append(p.docks, d)
}
return nil
}
func (p *dockPanel) DesiredSize(ctx Context) geom.PointF {
var width, height float64 = 0, 0
for i, child := range p.children {
var d = p.docks[i]
var desired = child.DesiredSize(ctx)
switch {
case d == DockLeft || d == DockRight:
if !math.IsNaN(width) {
if math.IsNaN(desired.X) {
width = desired.X
} else {
width += desired.X
}
}
if !math.IsNaN(desired.Y) {
height = math.Max(height, desired.Y)
}
case d == DockTop || d == DockBottom:
if !math.IsNaN(height) {
if math.IsNaN(desired.Y) {
height = desired.Y
} else {
height += desired.Y
}
}
if !math.IsNaN(desired.X) {
width = math.Max(width, desired.X)
}
}
}
return geom.PtF(width, height)
}
func (p *dockPanel) arrangeChildren(ctx Context) []geom.RectangleF {
var n = len(p.children)
var rects = make([]geom.RectangleF, n)
var rem = p.Bounds
var last = n - 1
for i, child := range p.children {
if last == i {
rects[i] = rem
} else {
var d = p.docks[i]
var desired = child.DesiredSize(ctx)
var width, height, top, left float64
switch {
case d == DockLeft || d == DockRight:
width = rem.Dx()
if !math.IsNaN(desired.X) {
width = math.Min(desired.X, width)
}
if d == DockLeft {
left = rem.Min.X
} else {
left = rem.Max.X - width
}
top = rem.Min.Y
height = rem.Dy()
case d == DockTop || d == DockBottom:
height = rem.Dy()
if !math.IsNaN(desired.Y) {
height = math.Min(desired.Y, height)
}
if d == DockTop {
top = rem.Min.Y
} else {
top = rem.Max.Y - height
}
left = rem.Min.X
width = rem.Dx()
}
rects[i] = geom.RectF(left, top, left+width, top+height)
switch d {
case DockLeft:
rem = geom.RectF(rem.Min.X+width, rem.Min.Y, rem.Max.X, rem.Max.Y)
case DockTop:
rem = geom.RectF(rem.Min.X, rem.Min.Y+height, rem.Max.X, rem.Max.Y)
case DockRight:
rem = geom.RectF(rem.Min.X, rem.Min.Y, rem.Max.X-width, rem.Max.Y)
case DockBottom:
rem = geom.RectF(rem.Min.X, rem.Min.Y, rem.Max.X, rem.Max.Y-height)
}
}
}
return rects
}
func (p *dockPanel) Arrange(ctx Context, rect geom.RectangleF) {
p.ContainerBase.SetRect(rect)
var rects = p.arrangeChildren(ctx)
for i, child := range p.children {
Arrange(ctx, child, rects[i])
}
}