tui/views/layout_flow.go

148 lines
3.4 KiB
Go
Raw Permalink Normal View History

2022-04-02 13:01:41 +02:00
package views
import (
"git.tordarus.net/Tordarus/tui"
)
2022-04-02 15:21:17 +02:00
// FlowLayout ia a tui.Layout which places its children in a linear layout
type FlowLayout struct {
2022-04-02 13:01:41 +02:00
tui.ViewTmpl
views []tui.View
lastLayoutPhase *LayoutResult
// Orientation defines in which direction the children will be placed
Orientation tui.Orientation
}
2022-04-02 15:21:17 +02:00
var _ tui.Layout = &FlowLayout{}
2022-04-02 13:01:41 +02:00
2022-04-02 15:21:17 +02:00
func NewFlowLayout(orientation tui.Orientation) *FlowLayout {
return &FlowLayout{
2022-04-02 13:01:41 +02:00
views: make([]tui.View, 0),
Orientation: orientation,
}
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) Views() []tui.View {
2022-04-03 17:31:46 +02:00
return g.views
2022-04-02 13:01:41 +02:00
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) AppendViews(v ...tui.View) {
2022-04-02 13:01:41 +02:00
g.views = append(g.views, v...)
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) PrependViews(v ...tui.View) {
2022-04-02 13:01:41 +02:00
g.views = append(v, g.views...)
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) InsertView(v tui.View, index int) {
2022-04-02 13:01:41 +02:00
g.views = append(g.views[:index], append([]tui.View{v}, g.views[index:]...)...)
}
2022-04-03 17:07:15 +02:00
func (g *FlowLayout) removeView(v tui.View) {
2022-04-02 15:09:52 +02:00
for index, view := range g.Views() {
2022-04-03 17:07:15 +02:00
if v == view {
g.views = append(g.views[:index], g.views[index+1:]...)
2022-04-02 15:09:52 +02:00
return
}
}
}
2022-04-03 17:07:15 +02:00
func (g *FlowLayout) RemoveViews(v ...tui.View) {
2022-04-03 17:31:46 +02:00
views := make([]tui.View, 0, len(v))
2022-04-03 17:07:15 +02:00
for _, view := range v {
2022-04-03 17:31:46 +02:00
views = append(views, view)
}
for _, view := range views {
2022-04-03 17:07:15 +02:00
g.removeView(view)
}
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) Draw(buf *tui.ViewBuffer) {
2022-04-02 13:01:41 +02:00
g.ViewTmpl.Draw(buf)
if g.lastLayoutPhase == nil {
g.Layout()
}
layout := g.lastLayoutPhase
if g.Orientation == tui.Horizontal {
remainingSpacePerView := buf.Width() - layout.Sum.Width
if remainingSpacePerView < 0 {
remainingSpacePerView = 0
}
2022-04-02 13:01:41 +02:00
if layout.HorizontalNegativeCount > 0 {
remainingSpacePerView /= layout.HorizontalNegativeCount
}
x := 0
for _, view := range g.views {
size := layout.Sizes[view]
size.Height = iff(size.Height < 0, buf.Height(), size.Height)
if size.Width < 0 {
size.Width = iff(layout.Sum.Width > buf.Width(), 0, remainingSpacePerView)
}
view.Draw(buf.Sub(x, 0, size.Width, size.Height))
2022-04-02 13:01:41 +02:00
x += size.Width
if x >= buf.Width() {
break
}
2022-04-02 13:01:41 +02:00
}
} else if g.Orientation == tui.Vertical {
remainingSpacePerView := buf.Height() - layout.Sum.Height
if remainingSpacePerView < 0 {
remainingSpacePerView = 0
}
2022-04-02 13:01:41 +02:00
if layout.VerticalNegativeCount > 0 {
remainingSpacePerView /= layout.VerticalNegativeCount
}
y := 0
for _, view := range g.views {
size := layout.Sizes[view]
size.Width = iff(size.Width < 0, buf.Width(), size.Width)
if size.Height < 0 {
size.Height = iff(layout.Sum.Height > buf.Height(), 0, remainingSpacePerView)
}
view.Draw(buf.Sub(0, y, size.Width, size.Height))
2022-04-02 13:01:41 +02:00
y += size.Height
if y >= buf.Height() {
break
}
2022-04-02 13:01:41 +02:00
}
}
g.lastLayoutPhase = nil
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) Layout() (prefWidth, prefHeight int) {
2022-04-02 13:01:41 +02:00
layout := CalculateLayoutResult(g.Views())
g.lastLayoutPhase = layout
if g.Orientation == tui.Horizontal {
prefWidth = iff(layout.HorizontalNegativeCount == 0, layout.Sum.Width, -1)
prefHeight = iff(layout.VerticalNegativeCount == 0, layout.Max.Height, -1)
} else if g.Orientation == tui.Vertical {
prefWidth = iff(layout.HorizontalNegativeCount == 0, layout.Max.Width, -1)
prefHeight = iff(layout.VerticalNegativeCount == 0, layout.Sum.Height, -1)
2022-04-02 13:01:41 +02:00
}
layout.Pref = tui.Size{Width: prefWidth, Height: prefHeight}
return
}
2022-04-02 15:21:17 +02:00
func (g *FlowLayout) OnKeyPressed(event *tui.KeyEvent) (consumed bool) {
2022-04-02 13:01:41 +02:00
for _, view := range g.Views() {
if view.OnKeyPressed(event) {
return true
}
}
return false
}