Added "cut" layout
This commit is contained in:
parent
992c242ba2
commit
e09761dd98
200
layouts/cut.go
Normal file
200
layouts/cut.go
Normal file
@ -0,0 +1,200 @@
|
||||
package layouts
|
||||
|
||||
import "image"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
|
||||
type Cut struct {
|
||||
branches [2]*Cut
|
||||
expand [2]bool
|
||||
vertical bool
|
||||
}
|
||||
|
||||
func (this *Cut) Vertical () (top, bottom *Cut) {
|
||||
this.fill()
|
||||
this.even()
|
||||
this.vertical = true
|
||||
return this.Branches()
|
||||
}
|
||||
|
||||
func (this *Cut) Top () (top, bottom *Cut) {
|
||||
this.fill()
|
||||
this.first()
|
||||
this.vertical = true
|
||||
return this.Branches()
|
||||
}
|
||||
|
||||
func (this *Cut) Bottom () (top, bottom *Cut) {
|
||||
this.fill()
|
||||
this.second()
|
||||
this.vertical = true
|
||||
return this.Branches()
|
||||
}
|
||||
|
||||
func (this *Cut) Horizontal () (top, bottom *Cut) {
|
||||
this.fill()
|
||||
this.even()
|
||||
return this.Branches()
|
||||
}
|
||||
|
||||
func (this *Cut) Left () (top, bottom *Cut) {
|
||||
this.fill()
|
||||
this.first()
|
||||
return this.Branches()
|
||||
}
|
||||
|
||||
func (this *Cut) Right () (top, bottom *Cut) {
|
||||
this.fill()
|
||||
this.second()
|
||||
return this.Branches()
|
||||
}
|
||||
|
||||
func (this *Cut) Branches () (first, second *Cut) {
|
||||
return this.branches[0], this.branches[1]
|
||||
}
|
||||
|
||||
func (this *Cut) real () bool {
|
||||
return this != nil && this.branches[0] != nil && this.branches[1] != nil
|
||||
}
|
||||
|
||||
func (this *Cut) fill () {
|
||||
this.branches[0] = &Cut { }
|
||||
this.branches[1] = &Cut { }
|
||||
}
|
||||
|
||||
func (this *Cut) first () {
|
||||
this.expand[0] = true
|
||||
this.expand[1] = false
|
||||
}
|
||||
|
||||
func (this *Cut) second () {
|
||||
this.expand[0] = false
|
||||
this.expand[1] = true
|
||||
}
|
||||
|
||||
func (this *Cut) even () {
|
||||
this.expand[0] = true
|
||||
this.expand[1] = true
|
||||
}
|
||||
|
||||
func (this *Cut) MinimumSize (hints tomo.LayoutHints, boxes []tomo.Box) image.Point {
|
||||
size, _ := this.minimumSize(hints, boxes)
|
||||
return size
|
||||
}
|
||||
|
||||
func (this *Cut) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
||||
this.arrange(hints, boxes)
|
||||
}
|
||||
|
||||
func (this *Cut) minimumSize (hints tomo.LayoutHints, boxes []tomo.Box) (image.Point, []tomo.Box) {
|
||||
size := image.Point { }
|
||||
|
||||
for index, branch := range this.branches {
|
||||
if len(boxes) == 0 { break }
|
||||
|
||||
var point image.Point
|
||||
if branch.real() {
|
||||
point, boxes = branch.minimumSize(hints, boxes)
|
||||
} else {
|
||||
point = boxes[0].MinimumSize()
|
||||
boxes = boxes[1:]
|
||||
}
|
||||
|
||||
if this.vertical {
|
||||
if point.X > size.X { size.X = point.X }
|
||||
if index > 0 { size.Y += hints.Gap.Y }
|
||||
size.Y += point.Y
|
||||
} else {
|
||||
if point.Y > size.Y { size.Y = point.Y }
|
||||
if index > 0 { size.X += hints.Gap.X }
|
||||
size.X += point.X
|
||||
}
|
||||
}
|
||||
|
||||
return size, boxes
|
||||
}
|
||||
|
||||
func (this *Cut) arrange (hints tomo.LayoutHints, boxes []tomo.Box) []tomo.Box {
|
||||
// collect minimum sizes and physical endpoints
|
||||
var minimums [2]image.Point
|
||||
var leaves [2]tomo.Box
|
||||
var nBranches int
|
||||
remaining := boxes
|
||||
for index, branch := range this.branches {
|
||||
if branch.real() {
|
||||
minimums[index], remaining = branch.minimumSize(hints, remaining)
|
||||
} else {
|
||||
if len(remaining) == 0 { break }
|
||||
leaves[index] = remaining[0]
|
||||
minimums[index] = remaining[0].MinimumSize()
|
||||
remaining = remaining[1:]
|
||||
}
|
||||
nBranches ++
|
||||
}
|
||||
|
||||
// determine the amount of space to divide among expanding branches
|
||||
gaps := nBranches - 1
|
||||
var freeSpace float64; if this.vertical {
|
||||
freeSpace = float64(hints.Bounds.Dy() - hints.Gap.Y * gaps)
|
||||
} else {
|
||||
freeSpace = float64(hints.Bounds.Dx() - hints.Gap.X * gaps)
|
||||
}
|
||||
var nExpanding float64
|
||||
for index, minimum := range minimums {
|
||||
if this.expand[index] {
|
||||
nExpanding ++
|
||||
} else if this.vertical {
|
||||
freeSpace -= float64(minimum.Y)
|
||||
} else {
|
||||
freeSpace -= float64(minimum.X)
|
||||
}
|
||||
}
|
||||
expandingSize := freeSpace / nExpanding
|
||||
|
||||
// calculate the size and position of branches
|
||||
var bounds [2]image.Rectangle
|
||||
x := float64(hints.Bounds.Min.X)
|
||||
y := float64(hints.Bounds.Min.Y)
|
||||
for index, minimum := range minimums {
|
||||
// get size along significant axis
|
||||
var size float64; if this.expand[index] {
|
||||
size = expandingSize
|
||||
} else if this.vertical {
|
||||
size = float64(minimum.Y)
|
||||
} else {
|
||||
size = float64(minimum.X)
|
||||
}
|
||||
|
||||
// figure out bounds from size
|
||||
if this.vertical {
|
||||
bounds[index].Max = image.Pt (
|
||||
int(hints.Bounds.Dx()),
|
||||
int(size))
|
||||
} else {
|
||||
bounds[index].Max = image.Pt (
|
||||
int(size),
|
||||
int(hints.Bounds.Dy()))
|
||||
}
|
||||
bounds[index] = bounds[index].Add(image.Pt(int(x), int(y)))
|
||||
|
||||
// move along
|
||||
if this.vertical {
|
||||
y += float64(hints.Gap.Y) + size
|
||||
} else {
|
||||
x += float64(hints.Gap.X) + size
|
||||
}
|
||||
}
|
||||
|
||||
// apply the size and position
|
||||
for index, bound := range bounds {
|
||||
if leaves[index] != nil {
|
||||
leaves[index].SetBounds(bound)
|
||||
boxes = boxes[1:]
|
||||
} else if this.branches[index] != nil {
|
||||
newHints := hints
|
||||
newHints.Bounds = bound
|
||||
boxes = this.branches[index].arrange(newHints, boxes)
|
||||
}
|
||||
}
|
||||
|
||||
return boxes
|
||||
}
|
Loading…
Reference in New Issue
Block a user