tui/views/view_border.go

156 lines
3.6 KiB
Go
Raw Permalink Normal View History

2022-04-02 13:01:41 +02:00
package views
2023-04-24 11:55:04 +02:00
import "git.milar.in/milarin/tui"
2022-04-02 13:01:41 +02:00
// BorderView is a tui.Wrapper which draws an ASCII border around its view.
// Be aware that box drawing characters must share the same tui.Style with the next character.
// This can lead to color artifacts when using BorderView with colored styles.
type BorderView struct {
tui.WrapperTmpl
2022-05-03 17:49:25 +02:00
Border BorderBox
2022-05-04 10:17:16 +02:00
ShowBorder map[tui.Side]bool
2022-04-02 13:01:41 +02:00
}
var _ tui.Wrapper = &BorderView{}
2022-04-02 13:01:41 +02:00
2022-05-04 10:17:16 +02:00
// NewBorderView create a new BorderView which show borders on the given sides around its view.
// If no sides are given, all sides will have a border by default
func NewBorderView(view tui.View, showBorders ...tui.Side) *BorderView {
2022-04-02 13:01:41 +02:00
v := new(BorderView)
v.SetView(view)
v.Border = ThinBorder()
2022-05-04 10:17:16 +02:00
if len(showBorders) == 0 {
v.ShowBorder = map[tui.Side]bool{
tui.SideBottom: true,
tui.SideTop: true,
tui.SideLeft: true,
tui.SideRight: true,
}
} else {
v.ShowBorder = map[tui.Side]bool{}
for _, border := range showBorders {
v.ShowBorder[border] = true
}
}
2022-04-02 13:01:41 +02:00
return v
}
func (g *BorderView) Draw(buf *tui.ViewBuffer) {
2022-05-04 10:17:16 +02:00
viewbuf := buf
2022-05-03 17:49:25 +02:00
2022-05-04 10:17:16 +02:00
// limit view buffer for child view
if g.ShowBorder[tui.SideTop] {
viewbuf = viewbuf.Sub(0, 1, viewbuf.Width(), viewbuf.Height())
}
if g.ShowBorder[tui.SideBottom] {
viewbuf = viewbuf.Sub(0, 0, viewbuf.Width(), viewbuf.Height()-1)
}
if g.ShowBorder[tui.SideLeft] {
viewbuf = viewbuf.Sub(1, 0, viewbuf.Width(), viewbuf.Height())
}
if g.ShowBorder[tui.SideRight] {
viewbuf = viewbuf.Sub(0, 0, viewbuf.Width()-1, viewbuf.Height())
}
2022-04-02 13:01:41 +02:00
2022-05-04 10:17:16 +02:00
// draw child view
g.View().Draw(viewbuf)
2022-04-02 13:01:41 +02:00
2022-05-04 10:17:16 +02:00
// draw horizontal lines
for x := 0; x < buf.Width(); x++ {
if g.ShowBorder[tui.SideTop] {
buf.Set(x, 0, tui.Rune{Rn: g.Border.Horizontal, Style: g.Style()})
}
if g.ShowBorder[tui.SideBottom] {
buf.Set(x, buf.Height()-1, tui.Rune{Rn: g.Border.Horizontal, Style: g.Style()})
}
}
2022-04-02 13:01:41 +02:00
2022-05-04 10:17:16 +02:00
// draw vertical lines
for y := 0; y < buf.Height(); y++ {
if g.ShowBorder[tui.SideLeft] {
buf.Set(0, y, tui.Rune{Rn: g.Border.Vertical, Style: g.Style()})
}
if g.ShowBorder[tui.SideRight] {
buf.Set(buf.Width()-1, y, tui.Rune{Rn: g.Border.Vertical, Style: g.Style()})
}
2022-04-02 13:01:41 +02:00
}
2022-05-04 10:17:16 +02:00
// draw corners
if g.ShowBorder[tui.SideTop] {
if g.ShowBorder[tui.SideLeft] {
buf.Set(0, 0, tui.Rune{Rn: g.Border.TopLeft, Style: g.Style()})
}
if g.ShowBorder[tui.SideRight] {
buf.Set(buf.Width()-1, 0, tui.Rune{Rn: g.Border.TopRight, Style: g.Style()})
}
}
if g.ShowBorder[tui.SideBottom] {
if g.ShowBorder[tui.SideLeft] {
buf.Set(0, buf.Height()-1, tui.Rune{Rn: g.Border.BottomLeft, Style: g.Style()})
}
if g.ShowBorder[tui.SideRight] {
buf.Set(buf.Width()-1, buf.Height()-1, tui.Rune{Rn: g.Border.BottomRight, Style: g.Style()})
}
2022-04-02 13:01:41 +02:00
}
}
func (v *BorderView) Layout() (prefWidth, prefHeight int) {
w, h := v.View().Layout()
2022-05-04 10:17:16 +02:00
for side, border := range v.ShowBorder {
if border {
2023-04-24 13:03:16 +02:00
if side.Horizontal() && w >= 0 {
2022-05-04 10:17:16 +02:00
w++
2023-04-24 13:03:16 +02:00
} else if side.Vertical() && h >= 0 {
2022-05-04 10:17:16 +02:00
h++
}
}
}
2022-04-02 13:01:41 +02:00
return w, h
}
type BorderBox struct {
TopLeft rune
TopRight rune
BottomLeft rune
BottomRight rune
Horizontal rune
Vertical rune
}
func ThickBorder() BorderBox {
return BorderBox{
TopLeft: '┏',
TopRight: '┓',
BottomLeft: '┗',
BottomRight: '┛',
Horizontal: '━',
Vertical: '┃',
}
}
func ThinBorder() BorderBox {
return BorderBox{
TopLeft: '┌',
TopRight: '┐',
BottomLeft: '└',
BottomRight: '┘',
Horizontal: '─',
Vertical: '│',
}
}
func DoubleBorder() BorderBox {
return BorderBox{
TopLeft: '╔',
TopRight: '╗',
BottomLeft: '╚',
BottomRight: '╝',
Horizontal: '═',
Vertical: '║',
}
}