diff --git a/go.mod b/go.mod index ada84ff..4ecd0b2 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( git.tordarus.net/Tordarus/adverr v0.2.0 - git.tordarus.net/Tordarus/buf2d v1.1.2 + git.tordarus.net/Tordarus/buf2d v1.1.4 github.com/gdamore/tcell v1.4.0 github.com/mattn/go-runewidth v0.0.7 ) diff --git a/go.sum b/go.sum index f944f67..59a3769 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ git.tordarus.net/Tordarus/adverr v0.2.0 h1:kLYjR2/Vb2GHiSAMvAv+WPNaHR9BRphKanf8H/pCZdA= git.tordarus.net/Tordarus/adverr v0.2.0/go.mod h1:XRf0+7nhOkIEr0gi9DUG4RvV2KaOFB0fYPDaR1KLenw= -git.tordarus.net/Tordarus/buf2d v1.1.2 h1:mmK3tARa30gCh4WaYoSEF5e7qk0C+1ODhxerUcfXN5M= -git.tordarus.net/Tordarus/buf2d v1.1.2/go.mod h1:XXPpS8nQK0gUI0ki7ftV/qlprsGCRWFVSD4ybvDuUL8= +git.tordarus.net/Tordarus/buf2d v1.1.4 h1:5R33Bq/no3uQIk7Tql6z55LI635DHeXQ7STNz0R7FQQ= +git.tordarus.net/Tordarus/buf2d v1.1.4/go.mod h1:XXPpS8nQK0gUI0ki7ftV/qlprsGCRWFVSD4ybvDuUL8= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU= diff --git a/tests/screen_test.go b/tests/screen_test.go index 8c6099c..302932a 100644 --- a/tests/screen_test.go +++ b/tests/screen_test.go @@ -82,6 +82,22 @@ func TestScrollView(t *testing.T) { fmt.Println(err) } +func TestBorderView(t *testing.T) { + textView := views.NewTextView("hello world!") + borderView := views.NewBorderView(textView) + //borderView2 := views.NewBorderView(borderView) + + screen, err := tui.NewScreen(borderView) + if err != nil { + t.Error(err) + return + } + + if err := screen.Start(); err != nil { + fmt.Println(err) + } +} + func TestFlowLayout(t *testing.T) { textView := views.NewTextView("hello world!") textView.SetStyle(tui.StyleDefault.Background(tcell.ColorRed).Foreground(tcell.ColorBlack)) diff --git a/types.go b/types.go index 5aa75ba..9e7fa83 100644 --- a/types.go +++ b/types.go @@ -41,6 +41,16 @@ const ( SideRight ) +// Horizontal returns true if s is either SideLeft or SideRight +func (s Side) Horizontal() bool { + return s == SideLeft || s == SideRight +} + +// Vertical returns true if s is either SideTop or SideBottom +func (s Side) Vertical() bool { + return s == SideTop || s == SideBottom +} + type Anchor uint8 const ( diff --git a/views/layout_flow.go b/views/layout_flow.go index 0751821..6574f19 100644 --- a/views/layout_flow.go +++ b/views/layout_flow.go @@ -49,10 +49,7 @@ func (g *FlowLayout) removeView(v tui.View) { } func (g *FlowLayout) RemoveViews(v ...tui.View) { - views := make([]tui.View, 0, len(v)) - for _, view := range v { - views = append(views, view) - } + views := append(make([]tui.View, 0, len(v)), v...) for _, view := range views { g.removeView(view) } diff --git a/views/view_border.go b/views/view_border.go index e4dcbae..465a74a 100644 --- a/views/view_border.go +++ b/views/view_border.go @@ -8,47 +8,107 @@ import "git.tordarus.net/Tordarus/tui" type BorderView struct { tui.WrapperTmpl Border BorderBox - HideBorder bool + ShowBorder map[tui.Side]bool } var _ tui.Wrapper = &BorderView{} -func NewBorderView(view tui.View) *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) { - if g.HideBorder { - g.View().Draw(buf) - return + 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()) } - g.View().Draw(buf.Sub(1, 1, buf.Width()-2, buf.Height()-2)) + // draw child view + g.View().Draw(viewbuf) - buf.Set(0, 0, tui.Rune{Rn: g.Border.TopLeft, Style: g.Style()}) - buf.Set(buf.Width()-1, 0, tui.Rune{Rn: g.Border.TopRight, Style: g.Style()}) - - buf.Set(0, buf.Height()-1, tui.Rune{Rn: g.Border.BottomLeft, Style: g.Style()}) - buf.Set(buf.Width()-1, buf.Height()-1, tui.Rune{Rn: g.Border.BottomRight, Style: g.Style()}) - - for x := 1; x < buf.Width()-1; x++ { - buf.Set(x, 0, tui.Rune{Rn: g.Border.Horizontal, Style: g.Style()}) - buf.Set(x, buf.Height()-1, tui.Rune{Rn: g.Border.Horizontal, Style: g.Style()}) + // 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()}) + } } - for y := 1; y < buf.Height()-1; y++ { - buf.Set(0, y, tui.Rune{Rn: g.Border.Vertical, Style: g.Style()}) - buf.Set(buf.Width()-1, y, tui.Rune{Rn: g.Border.Vertical, 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() - w = iff(w > 0, w+2, w) - h = iff(h > 0, h+2, h) + + for side, border := range v.ShowBorder { + if border { + if side.Horizontal() { + w++ + } else if side.Vertical() { + h++ + } + } + } + return w, h }