From 40b4cd36684c80432fe0bbdb0ad80dcb077d2d39 Mon Sep 17 00:00:00 2001 From: David Ashby Date: Sat, 3 Jul 2021 21:25:32 -0400 Subject: [PATCH] fix up boxes to actually work when moved around the screen --- ui/mock.go | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ ui/ui.go | 23 +++++----- ui/ui_test.go | 88 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 10 deletions(-) create mode 100644 ui/mock.go create mode 100644 ui/ui_test.go diff --git a/ui/mock.go b/ui/mock.go new file mode 100644 index 0000000..1df5620 --- /dev/null +++ b/ui/mock.go @@ -0,0 +1,116 @@ +package ui + +import ( + "fmt" + + "github.com/gdamore/tcell" +) + +type coord struct { + x, y int +} + +type MockScreen struct { + x, y, h, w int + content map[coord]rune +} + +func (m *MockScreen) Init() error { + m.content = map[coord]rune{} + return nil +} + +func (m *MockScreen) Fini() {} + +func (m *MockScreen) Clear() { + m.content = map[coord]rune{} +} + +func (m *MockScreen) Fill(rune, tcell.Style) {} + +func (m *MockScreen) SetCell(x int, y int, style tcell.Style, ch ...rune) {} + +func (m *MockScreen) GetContent(x, y int) (mainc rune, combc []rune, style tcell.Style, width int) { + return m.content[coord{x, y}], nil, tcell.StyleDefault, 1 +} + +func (m *MockScreen) SetContent(x int, y int, mainc rune, combc []rune, style tcell.Style) { + m.content[coord{x, y}] = mainc +} + +func (m *MockScreen) SetStyle(style tcell.Style) {} + +func (m *MockScreen) ShowCursor(x int, y int) {} + +func (m *MockScreen) HideCursor() {} + +func (m *MockScreen) Size() (int, int) { + return m.h, m.w +} + +func (m *MockScreen) PollEvent() tcell.Event { + return tcell.NewEventError(fmt.Errorf("mock error")) +} + +func (m *MockScreen) PostEvent(ev tcell.Event) error { + return nil +} + +func (m *MockScreen) PostEventWait(ev tcell.Event) {} + +func (m *MockScreen) EnableMouse() {} + +func (m *MockScreen) DisableMouse() {} + +func (m *MockScreen) HasMouse() bool { + return false +} + +func (m *MockScreen) Colors() int { + return 0 +} + +func (m *MockScreen) Show() {} + +func (m *MockScreen) Sync() {} + +func (m *MockScreen) CharacterSet() string { + return "UTF-8" +} + +func (m *MockScreen) RegisterRuneFallback(r rune, subst string) {} + +func (m *MockScreen) UnregisterRuneFallback(r rune) {} + +func (m *MockScreen) CanDisplay(r rune, checkFallbacks bool) bool { + return true +} + +func (m *MockScreen) Resize(x, y, h, w int) { + m.x, m.y, m.h, m.w = x, y, h, w +} + +func (m *MockScreen) HasKey(tcell.Key) bool { + return true +} + +func (m *MockScreen) Beep() error { + return nil +} + +func (m *MockScreen) DumpContents() string { + var res string + for i := m.y; i < m.h; i++ { + str := []rune{} + for j := m.x; j < m.w; j++ { + r, ok := m.content[coord{x: j, y: i}] + if ok { + str = append(str, r) + } else { + str = append(str, ' ') + } + } + res = res + string(str) + "\n" + } + return res +} diff --git a/ui/ui.go b/ui/ui.go index 3048535..3a0a0ac 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -59,10 +59,10 @@ func (c *Container) SetSize(x, y, h, w int) { if c.layoutMethod == LayoutVerticalEven { num := len(c.contents) for r := range c.contents { - x := c.x - y := c.y + (num * (r + 1)) - h := c.h / num w := c.w + h := c.h / num + x := c.x + y := c.y + (h * r) c.contents[r].Container.SetSize(x, y, h, w) } } else if c.layoutMethod == LayoutHorizontalEven { @@ -124,18 +124,18 @@ func (b *Box) SetSize(x, y, h, w int) { } func (b *Box) Draw(s tcell.Screen) { - for m := 1; m < b.w-1; m++ { + for m := b.x + 1; m < b.x+b.w-1; m++ { s.SetContent(m, b.y, tcell.RuneHLine, nil, tcell.StyleDefault) - s.SetContent(m, b.h-1, tcell.RuneHLine, nil, tcell.StyleDefault) + s.SetContent(m, b.y+b.h-1, tcell.RuneHLine, nil, tcell.StyleDefault) } - for m := 1; m < b.h-1; m++ { + for m := b.y + 1; m < b.y+b.h-1; m++ { s.SetContent(b.x, m, tcell.RuneVLine, nil, tcell.StyleDefault) - s.SetContent(b.w-1, m, tcell.RuneVLine, nil, tcell.StyleDefault) + s.SetContent(b.x+b.w-1, m, tcell.RuneVLine, nil, tcell.StyleDefault) } s.SetContent(b.x, b.y, tcell.RuneULCorner, nil, tcell.StyleDefault) - s.SetContent(b.w-1, b.y, tcell.RuneURCorner, nil, tcell.StyleDefault) - s.SetContent(b.x, b.h-1, tcell.RuneLLCorner, nil, tcell.StyleDefault) - s.SetContent(b.w-1, b.h-1, tcell.RuneLRCorner, nil, tcell.StyleDefault) + s.SetContent(b.x+b.w-1, b.y, tcell.RuneURCorner, nil, tcell.StyleDefault) + s.SetContent(b.x, b.y+b.h-1, tcell.RuneLLCorner, nil, tcell.StyleDefault) + s.SetContent(b.x+b.w-1, b.y+b.h-1, tcell.RuneLRCorner, nil, tcell.StyleDefault) if b.title != nil { b.title.Draw(s) @@ -215,6 +215,9 @@ func (p *PaddedText) SetSize(x, y, _, _ int) { } func (p *PaddedText) Draw(s tcell.Screen) { + if p.text == "" { + return + } t := p.x s.SetContent(t, p.y, ' ', nil, tcell.StyleDefault) t++ diff --git a/ui/ui_test.go b/ui/ui_test.go new file mode 100644 index 0000000..bafb5d9 --- /dev/null +++ b/ui/ui_test.go @@ -0,0 +1,88 @@ +package ui + +import ( + "fmt" + "testing" +) + +func TestContainerOneBox(t *testing.T) { + expect := `┌─ box one ────────┐ +│ │ +│ │ +│ │ +└──────────────────┘ +` + m := &MockScreen{} + one := NewBox("box one", nil, Contents{}) + container := NewContainer( + Contents{{Container: one}}, + LayoutHorizontalEven, + ) + m.Init() + m.Resize(0, 0, 5, 20) + container.SetSize(0, 0, 5, 20) + container.Draw(m) + result := m.DumpContents() + if result != expect { + fmt.Printf("expected:\n%+v", expect) + fmt.Printf("actual:\n%+v", result) + t.Fail() + } +} + +func TestContainerTwoBoxesHStack(t *testing.T) { + expect := `┌─ one ──┐┌─ two ──┐ +│ ││ │ +│ ││ │ +│ ││ │ +└────────┘└────────┘ +` + m := &MockScreen{} + one := NewBox("one", nil, Contents{}) + two := NewBox("two", nil, Contents{}) + container := NewContainer( + Contents{{Container: one}, {Container: two}}, + LayoutHorizontalEven, + ) + m.Init() + m.Resize(0, 0, 5, 20) + container.SetSize(0, 0, 5, 20) + container.Draw(m) + result := m.DumpContents() + if result != expect { + fmt.Printf("expected:\n%+v", expect) + fmt.Printf("actual:\n%+v", result) + t.Fail() + } +} + +func TestContainerTwoBoxesVStack(t *testing.T) { + expect := `┌─ one ──┐ +│ │ +│ │ +│ │ +└────────┘ +┌─ two ──┐ +│ │ +│ │ +│ │ +└────────┘ +` + m := &MockScreen{} + one := NewBox("one", nil, Contents{}) + two := NewBox("two", nil, Contents{}) + container := NewContainer( + Contents{{Container: one}, {Container: two}}, + LayoutVerticalEven, + ) + m.Init() + m.Resize(0, 0, 10, 10) + container.SetSize(0, 0, 10, 10) + container.Draw(m) + result := m.DumpContents() + if result != expect { + fmt.Printf("expected:\n%+v", expect) + fmt.Printf("actual:\n%+v", result) + t.Fail() + } +}