From c18a3883bf1a95f62b78f31472efcaf3a9acacd3 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Tue, 10 Jan 2023 23:20:42 -0500 Subject: [PATCH] Added a horizontal layout --- elements/layouts/horizontal.go | 93 +++++++++++++++++++++++++++++++ elements/layouts/vertical.go | 6 +- examples/horizontalLayout/main.go | 25 +++++++++ 3 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 elements/layouts/horizontal.go create mode 100644 examples/horizontalLayout/main.go diff --git a/elements/layouts/horizontal.go b/elements/layouts/horizontal.go new file mode 100644 index 0000000..0f08a24 --- /dev/null +++ b/elements/layouts/horizontal.go @@ -0,0 +1,93 @@ +package layouts + +import "image" +import "git.tebibyte.media/sashakoshka/tomo" +import "git.tebibyte.media/sashakoshka/tomo/theme" + +// Horizontal arranges elements horizontally. Elements at the start of the entry +// list will be positioned on the left, and elements at the end of the entry +// list will positioned on the right. All elements have the same height. +type Horizontal struct { + // If Gap is true, a gap will be placed between each element. + Gap bool + + // If Pad is true, there will be padding running along the inside of the + // layout's border. + Pad bool +} + +// Arrange arranges a list of entries horizontally. +func (layout Horizontal) Arrange (entries []tomo.LayoutEntry, width, height int) { + if layout.Pad { + width -= theme.Padding() * 2 + height -= theme.Padding() * 2 + } + freeSpace := width + expandingElements := 0 + + // count the number of expanding elements and the amount of free space + // for them to collectively occupy + for index, entry := range entries { + if entry.Expand { + expandingElements ++ + } else { + entryMinWidth, _ := entry.MinimumSize() + freeSpace -= entryMinWidth + } + if index > 0 && layout.Gap { + freeSpace -= theme.Padding() + } + } + expandingElementWidth := 0 + if expandingElements > 0 { + expandingElementWidth = freeSpace / expandingElements + } + + x, y := 0, 0 + if layout.Pad { + x += theme.Padding() + y += theme.Padding() + } + + // set the size and position of each element + for index, entry := range entries { + if index > 0 && layout.Gap { x += theme.Padding() } + + entries[index].Position = image.Pt(x, y) + entryWidth := 0 + if entry.Expand { + entryWidth = expandingElementWidth + } else { + entryWidth, _ = entry.MinimumSize() + } + x += entryWidth + entryBounds := entry.Bounds() + if entryBounds.Dy() != height || entryBounds.Dx() != entryWidth { + entry.Handle (tomo.EventResize { + Width: entryWidth, + Height: height, + }) + } + } +} + +// MinimumSize returns the minimum width and height that will be needed to +// arrange the given list of entries. +func (layout Horizontal) MinimumSize (entries []tomo.LayoutEntry) (width, height int) { + for index, entry := range entries { + entryWidth, entryHeight := entry.MinimumSize() + if entryHeight > height { + height = entryHeight + } + width += entryWidth + if layout.Gap && index > 0 { + width += theme.Padding() + } + } + + if layout.Pad { + width += theme.Padding() * 2 + height += theme.Padding() * 2 + } + return +} diff --git a/elements/layouts/vertical.go b/elements/layouts/vertical.go index 3e3741a..81783f1 100644 --- a/elements/layouts/vertical.go +++ b/elements/layouts/vertical.go @@ -34,7 +34,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, width, height int) { _, entryMinHeight := entry.MinimumSize() freeSpace -= entryMinHeight } - if index > 0 { + if index > 0 && layout.Gap { freeSpace -= theme.Padding() } } @@ -71,8 +71,8 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, width, height int) { } } -// MinimumSize returns the minimum width and height will be needed to arrange -// the given list of entries. +// MinimumSize returns the minimum width and height that will be needed to +// arrange the given list of entries. func (layout Vertical) MinimumSize (entries []tomo.LayoutEntry) (width, height int) { for index, entry := range entries { entryWidth, entryHeight := entry.MinimumSize() diff --git a/examples/horizontalLayout/main.go b/examples/horizontalLayout/main.go new file mode 100644 index 0000000..e7cf116 --- /dev/null +++ b/examples/horizontalLayout/main.go @@ -0,0 +1,25 @@ +package main + +import "git.tebibyte.media/sashakoshka/tomo" +import "git.tebibyte.media/sashakoshka/tomo/elements/basic" +import "git.tebibyte.media/sashakoshka/tomo/elements/layouts" +import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" + +func main () { + tomo.Run(run) +} + +func run () { + window, _ := tomo.NewWindow(2, 2) + window.SetTitle("vertical stack") + + container := basic.NewContainer(layouts.Horizontal { true, true }) + window.Adopt(container) + + container.Adopt(basic.NewTest(), true) + container.Adopt(basic.NewLabel("<- left\nright ->", false), false) + container.Adopt(basic.NewTest(), true) + + window.OnClose(tomo.Stop) + window.Show() +}