1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-03 15:02:52 +02:00
lazygit/pkg/gui/dimensions.go

137 lines
3.5 KiB
Go
Raw Normal View History

2020-05-16 12:35:19 +10:00
package gui
import "math"
2020-05-17 21:32:17 +10:00
type dimensions struct {
x0 int
x1 int
y0 int
y1 int
}
2020-05-16 12:35:19 +10:00
const (
ROW = iota
COLUMN
)
type box struct {
// direction decides how the children boxes are laid out. ROW means the children will each form a row i.e. that they will be stacked on top of eachother.
direction int // ROW or COLUMN
// function which takes the width and height assigned to the box and decides which orientation it will have
conditionalDirection func(width int, height int) int
children []*box
2020-05-17 21:32:17 +10:00
// function which takes the width and height assigned to the box and decides the layout of the children.
conditionalChildren func(width int, height int) []*box
2020-05-16 12:35:19 +10:00
// viewName refers to the name of the view this box represents, if there is one
viewName string
// static size. If parent box's direction is ROW this refers to height, otherwise width
size int
// dynamic size. Once all statically sized children have been considered, weight decides how much of the remaining space will be taken up by the box
// TODO: consider making there be one int and a type enum so we can't have size and weight simultaneously defined
weight int
}
func (b *box) isStatic() bool {
return b.size > 0
}
func (b *box) getDirection(width int, height int) int {
if b.conditionalDirection != nil {
return b.conditionalDirection(width, height)
}
return b.direction
}
2020-05-17 21:32:17 +10:00
func (b *box) getChildren(width int, height int) []*box {
if b.conditionalChildren != nil {
return b.conditionalChildren(width, height)
}
return b.children
}
2020-05-16 12:35:19 +10:00
func (gui *Gui) layoutViews(root *box, x0, y0, width, height int) map[string]dimensions {
gui.Log.Warn(x0, y0, width, height)
if len(root.children) == 0 {
// leaf node
if root.viewName != "" {
dimensionsForView := dimensions{x0: x0, y0: y0, x1: x0 + width - 1, y1: y0 + height - 1}
return map[string]dimensions{root.viewName: dimensionsForView}
}
return map[string]dimensions{}
}
direction := root.getDirection(width, height)
var availableSize int
if direction == COLUMN {
availableSize = width
} else {
availableSize = height
}
// work out size taken up by children
reservedSize := 0
totalWeight := 0
for _, child := range root.children {
// assuming either size or weight are non-zero
reservedSize += child.size
totalWeight += child.weight
}
remainingSize := availableSize - reservedSize
if remainingSize < 0 {
remainingSize = 0
}
unitSize := 0
extraSize := 0
if totalWeight > 0 {
unitSize = remainingSize / totalWeight
extraSize = remainingSize % totalWeight
}
result := map[string]dimensions{}
offset := 0
for _, child := range root.children {
var boxSize int
if child.isStatic() {
boxSize = child.size
} else {
// TODO: consider more evenly distributing the remainder
boxSize = unitSize * child.weight
boxExtraSize := int(math.Min(float64(extraSize), float64(child.weight)))
boxSize += boxExtraSize
extraSize -= boxExtraSize
}
var resultForChild map[string]dimensions
if direction == COLUMN {
resultForChild = gui.layoutViews(child, x0+offset, y0, boxSize, height)
} else {
resultForChild = gui.layoutViews(child, x0, y0+offset, width, boxSize)
}
result = gui.mergeDimensionMaps(result, resultForChild)
offset += boxSize
}
return result
}
func (gui *Gui) mergeDimensionMaps(a map[string]dimensions, b map[string]dimensions) map[string]dimensions {
result := map[string]dimensions{}
for _, dimensionMap := range []map[string]dimensions{a, b} {
for k, v := range dimensionMap {
result[k] = v
}
}
return result
}