2023-08-10 15:52:01 -06:00
|
|
|
package layouts
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
import "git.tebibyte.media/tomo/tomo"
|
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
// Contract is a layout that arranges boxes in a simple row or column according
|
|
|
|
// to their minimum sizes.
|
|
|
|
type Contract bool
|
2023-08-10 15:52:01 -06:00
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
// ContractVertical is a vertical contracted layout.
|
|
|
|
const ContractVertical Contract = true
|
2023-08-10 15:52:01 -06:00
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
// ContractHorizontal is a horizontal contracted layout.
|
|
|
|
const ContractHorizontal Contract = false
|
2023-08-10 15:52:01 -06:00
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
func (contract Contract) MinimumSize (hints tomo.LayoutHints, boxes []tomo.Box) image.Point {
|
|
|
|
if contract.v() {
|
|
|
|
dot := image.Point { }
|
|
|
|
for _, box := range boxes {
|
|
|
|
minimum := box.MinimumSize()
|
|
|
|
dot.Y += minimum.Y
|
|
|
|
if dot.X < minimum.X {
|
|
|
|
dot.X = minimum.X
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dot.Y += hints.Gap.Y * (len(boxes) - 1)
|
|
|
|
return dot
|
|
|
|
} else {
|
|
|
|
dot := image.Point { }
|
|
|
|
for _, box := range boxes {
|
|
|
|
minimum := box.MinimumSize()
|
|
|
|
dot.X += minimum.X
|
|
|
|
if dot.Y < minimum.Y {
|
|
|
|
dot.Y = minimum.Y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dot.X += hints.Gap.X * (len(boxes) - 1)
|
|
|
|
return dot
|
2023-08-10 15:52:01 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
func (contract Contract) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
|
|
|
if contract.v() {
|
|
|
|
dot := hints.Bounds.Min
|
|
|
|
for index, box := range boxes {
|
|
|
|
if index > 0 { dot.Y += hints.Gap.Y }
|
|
|
|
minimum := box.MinimumSize()
|
|
|
|
box.SetBounds(image.Rectangle {
|
|
|
|
Min: dot,
|
|
|
|
Max: dot.Add(image.Pt(hints.Bounds.Dx(), minimum.Y)),
|
|
|
|
})
|
|
|
|
dot.Y += minimum.Y
|
|
|
|
}
|
|
|
|
|
|
|
|
height := dot.Y - hints.Bounds.Min.Y
|
|
|
|
offset := 0
|
|
|
|
|
|
|
|
switch hints.AlignY {
|
|
|
|
case tomo.AlignMiddle:
|
|
|
|
offset = (hints.Bounds.Dy() - height) / 2
|
|
|
|
case tomo.AlignEnd:
|
|
|
|
offset = hints.Bounds.Dy() - height
|
|
|
|
}
|
|
|
|
for _, box := range boxes {
|
|
|
|
box.SetBounds(box.Bounds().Add(image.Pt(0, offset)))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dot := hints.Bounds.Min
|
|
|
|
for index, box := range boxes {
|
|
|
|
if index > 0 { dot.X += hints.Gap.X }
|
|
|
|
minimum := box.MinimumSize()
|
|
|
|
box.SetBounds(image.Rectangle {
|
|
|
|
Min: dot,
|
|
|
|
Max: dot.Add(image.Pt(minimum.X, hints.Bounds.Dy())),
|
|
|
|
})
|
|
|
|
dot.X += minimum.X
|
|
|
|
}
|
2023-08-10 15:52:01 -06:00
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
width := dot.X - hints.Bounds.Min.X
|
|
|
|
offset := 0
|
|
|
|
|
|
|
|
switch hints.AlignX {
|
|
|
|
case tomo.AlignMiddle:
|
|
|
|
offset = (hints.Bounds.Dx() - width) / 2
|
|
|
|
case tomo.AlignEnd:
|
|
|
|
offset = hints.Bounds.Dx() - width
|
|
|
|
}
|
|
|
|
for _, box := range boxes {
|
|
|
|
box.SetBounds(box.Bounds().Add(image.Pt(offset, 0)))
|
2023-08-10 15:52:01 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-17 01:56:49 -06:00
|
|
|
func (contract Contract) v () bool { return contract == ContractVertical }
|
|
|
|
func (contract Contract) h () bool { return contract == ContractHorizontal }
|