tui/layouts/layout_border.go

176 lines
4.7 KiB
Go
Raw Normal View History

2023-04-24 11:41:38 +02:00
package layouts
2022-04-02 13:01:41 +02:00
import (
2023-04-24 11:55:04 +02:00
"git.milar.in/milarin/tui"
2022-04-02 13:01:41 +02:00
)
2022-04-02 15:21:17 +02:00
// BorderLayout ia a tui.Layout which places its children onto a given tui.Side
type BorderLayout struct {
2022-04-02 13:01:41 +02:00
tui.ViewTmpl
views map[Slot]tui.View
horizontalLayout *LayoutResult
verticalLayout *LayoutResult
viewDims map[Slot]tui.Dimension
2022-04-02 13:01:41 +02:00
}
2022-04-02 15:21:17 +02:00
var _ tui.Layout = &BorderLayout{}
2022-04-02 13:01:41 +02:00
2022-04-02 15:21:17 +02:00
func NewBorderLayout() *BorderLayout {
return &BorderLayout{
views: map[Slot]tui.View{},
viewDims: map[Slot]tui.Dimension{},
2022-04-02 13:01:41 +02:00
}
}
2022-04-02 15:21:17 +02:00
func (g *BorderLayout) Views() []tui.View {
2022-04-02 13:01:41 +02:00
s := make([]tui.View, 0, len(g.views))
for _, view := range g.views {
s = append(s, view)
}
return s
}
2022-04-02 15:21:17 +02:00
func (g *BorderLayout) SetView(v tui.View, slot Slot) {
2022-04-02 13:01:41 +02:00
g.views[slot] = v
}
2022-04-02 15:21:17 +02:00
func (g *BorderLayout) View(slot Slot) tui.View {
2022-04-02 13:01:41 +02:00
return g.views[slot]
}
2022-04-02 15:21:17 +02:00
func (g *BorderLayout) Draw(buf *tui.ViewBuffer) {
2022-04-02 13:01:41 +02:00
g.ViewTmpl.Draw(buf)
if g.verticalLayout == nil {
g.Layout()
}
verticalLayout := g.verticalLayout
if g.horizontalLayout == nil {
g.Layout()
}
horizontalLayout := g.horizontalLayout
remainingVerticalSpacePerView := (buf.Height() - verticalLayout.Sum.Height)
if verticalLayout.VerticalNegativeCount > 0 {
remainingVerticalSpacePerView /= verticalLayout.VerticalNegativeCount
}
remainingHorizontalSpacePerView := (buf.Width() - horizontalLayout.Sum.Width)
if horizontalLayout.HorizontalNegativeCount > 0 {
remainingHorizontalSpacePerView /= horizontalLayout.HorizontalNegativeCount
}
fitsVertically := buf.Height() >= verticalLayout.Sum.Height
fitsHorizontally := buf.Width() >= horizontalLayout.Sum.Width
var topHeight int
var bottomHeight int
var leftWidth int
var rightWidth int
if view, ok := g.views[Top]; ok {
_, topHeight = view.Layout()
if fitsVertically {
topHeight = iff(topHeight < 0, remainingVerticalSpacePerView, topHeight)
} else {
topHeight = int(float64(buf.Height()) * float64(topHeight) / float64(verticalLayout.Sum.Height))
}
g.viewDims[Top] = tui.D(0, 0, buf.Width(), topHeight)
2022-04-02 13:01:41 +02:00
view.Draw(buf.Sub(0, 0, buf.Width(), topHeight))
}
if view, ok := g.views[Bottom]; ok {
_, bottomHeight = view.Layout()
if fitsVertically {
bottomHeight = iff(bottomHeight < 0, remainingVerticalSpacePerView, bottomHeight)
} else {
bottomHeight = int(float64(buf.Height()) * float64(bottomHeight) / float64(verticalLayout.Sum.Height))
}
g.viewDims[Bottom] = tui.D(0, buf.Height()-bottomHeight, buf.Width(), bottomHeight)
2022-04-02 13:01:41 +02:00
view.Draw(buf.Sub(0, buf.Height()-bottomHeight, buf.Width(), bottomHeight))
}
if view, ok := g.views[Left]; ok {
leftWidth, _ = view.Layout()
if fitsHorizontally {
leftWidth = iff(leftWidth < 0, remainingHorizontalSpacePerView, leftWidth)
} else {
leftWidth = int(float64(buf.Width()) * float64(leftWidth) / float64(horizontalLayout.Sum.Width))
}
g.viewDims[Left] = tui.D(0, topHeight, leftWidth, buf.Height()-topHeight-bottomHeight)
2022-04-02 13:01:41 +02:00
view.Draw(buf.Sub(0, topHeight, leftWidth, buf.Height()-topHeight-bottomHeight))
}
if view, ok := g.views[Right]; ok {
rightWidth, _ = view.Layout()
if fitsHorizontally {
rightWidth = iff(rightWidth < 0, remainingHorizontalSpacePerView, rightWidth)
} else {
rightWidth = int(float64(buf.Width()) * float64(rightWidth) / float64(horizontalLayout.Sum.Width))
}
g.viewDims[Right] = tui.D(buf.Width()-rightWidth, topHeight, rightWidth, buf.Height()-topHeight-bottomHeight)
2022-04-02 13:01:41 +02:00
view.Draw(buf.Sub(buf.Width()-rightWidth, topHeight, rightWidth, buf.Height()-topHeight-bottomHeight))
}
if view, ok := g.views[Center]; ok {
g.viewDims[Center] = tui.D(leftWidth, topHeight, buf.Width()-leftWidth-rightWidth, buf.Height()-topHeight-bottomHeight)
2022-04-02 13:01:41 +02:00
view.Draw(buf.Sub(leftWidth, topHeight, buf.Width()-leftWidth-rightWidth, buf.Height()-topHeight-bottomHeight))
}
g.verticalLayout = nil
g.horizontalLayout = nil
}
2022-04-02 15:21:17 +02:00
func (g *BorderLayout) Layout() (prefWidth, prefHeight int) {
2022-04-02 13:01:41 +02:00
g.verticalLayout = CalculateLayoutResult([]tui.View{g.View(Top), g.View(Center), g.View(Bottom)})
g.horizontalLayout = CalculateLayoutResult([]tui.View{g.View(Left), g.View(Center), g.View(Right)})
return -1, -1
}
2022-04-02 15:21:17 +02:00
func (g *BorderLayout) OnKeyPressed(event *tui.KeyEvent) (consumed bool) {
if g.KeyPressed != nil {
return g.KeyPressed(event)
}
2022-04-02 13:01:41 +02:00
for _, view := range g.Views() {
if consumed := view.OnKeyPressed(event); consumed {
2022-04-02 13:01:41 +02:00
return true
}
}
return false
}
2022-05-04 14:16:08 +02:00
func (g *BorderLayout) OnMouseEvent(event *tui.MouseEvent) (consumed bool) {
if g.MouseEvent != nil {
return g.MouseEvent(event)
}
for slot, dim := range g.viewDims {
if event.Position.In(dim) {
2022-05-04 14:16:08 +02:00
g.views[slot].OnMouseEvent(event)
return true
}
}
return false
}
2022-05-04 14:16:08 +02:00
type Slot string
2022-04-02 13:01:41 +02:00
const (
2022-05-04 14:16:08 +02:00
Top Slot = "top"
Bottom Slot = "bottom"
Left Slot = "left"
Right Slot = "right"
Center Slot = "center"
2022-04-02 13:01:41 +02:00
)