diff --git a/layouts/flow.go b/layouts/flow.go index 10411cb..8baa762 100644 --- a/layouts/flow.go +++ b/layouts/flow.go @@ -119,9 +119,5 @@ func (flow Flow) deltaMinor (rectangle image.Rectangle) int { } } func (flow Flow) fallback () tomo.Layout { - if flow.v() { - return Column { } - } else { - return Row { } - } + return Contract(flow) } diff --git a/layouts/layouts.go b/layouts/layouts.go index b6da5f9..f92b74c 100644 --- a/layouts/layouts.go +++ b/layouts/layouts.go @@ -3,86 +3,93 @@ package layouts import "image" import "git.tebibyte.media/tomo/tomo" -type Row struct { } +// Contract is a layout that arranges boxes in a simple row or column according +// to their minimum sizes. +type Contract bool -func (Row) MinimumSize (hints tomo.LayoutHints, boxes []tomo.Box) image.Point { - dot := image.Point { } - for _, box := range boxes { - minimum := box.MinimumSize() - dot.X += minimum.X - if dot.Y < minimum.Y { - dot.Y = minimum.Y +// ContractVertical is a vertical contracted layout. +const ContractVertical Contract = true + +// ContractHorizontal is a horizontal contracted layout. +const ContractHorizontal Contract = false + +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 + } +} + +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 + } + + 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))) } } - dot.X += hints.Gap.X * (len(boxes) - 1) - return dot } -func (Row) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) { - // TODO respect alignment value - 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 - } - - 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))) - } -} - -type Column struct { } - -func (Column) MinimumSize (hints tomo.LayoutHints, boxes []tomo.Box) image.Point { - 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 -} - -func (Column) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) { - // TODO respect alignment value - 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))) - } -} +func (contract Contract) v () bool { return contract == ContractVertical } +func (contract Contract) h () bool { return contract == ContractHorizontal }