package views import "git.tordarus.net/Tordarus/tui" // 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 Border BorderBox ShowBorder map[tui.Side]bool } var _ tui.Wrapper = &BorderView{} // 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 { v := new(BorderView) v.SetView(view) v.Border = ThinBorder() 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 } } return v } func (g *BorderView) Draw(buf *tui.ViewBuffer) { viewbuf := buf // 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()) } // draw child view g.View().Draw(viewbuf) // 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()}) } } // 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()}) } } // 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()}) } } } func (v *BorderView) Layout() (prefWidth, prefHeight int) { w, h := v.View().Layout() for side, border := range v.ShowBorder { if border { if side.Horizontal() { w++ } else if side.Vertical() { h++ } } } 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: '║', } }