From de3f9cfadbaaa15732ad36fff838b5733d572938 Mon Sep 17 00:00:00 2001 From: David Ashby Date: Sat, 3 Jul 2021 10:58:45 -0400 Subject: [PATCH] continue to add more building blocks --- cmd/manage/interface.go | 135 ++++++++++++++++++++++++++++++++++++++++ cmd/manage/main.go | 120 +++++++---------------------------- docker-compose.yml | 2 +- 3 files changed, 160 insertions(+), 97 deletions(-) create mode 100644 cmd/manage/interface.go diff --git a/cmd/manage/interface.go b/cmd/manage/interface.go new file mode 100644 index 0000000..167bbd2 --- /dev/null +++ b/cmd/manage/interface.go @@ -0,0 +1,135 @@ +package main + +import ( + "strings" + + "github.com/gdamore/tcell" +) + +type Drawable interface { + Draw(tcell.Screen) + SetSize(x, y, h, w int) +} + +type offsets struct { + top int + bottom int + left int + right int +} + +type contents []struct { + offsets offsets + container Drawable +} + +type box struct { + x, y int + h, w int + title Drawable + menuItems Drawable + contents []struct { + offsets offsets + container Drawable + } +} + +func NewBox(title string, menuItems []string, contents contents) *box { + return &box{ + title: NewPaddedText(title), + menuItems: NewPaddedText(strings.Join(menuItems, " ")), + contents: contents, + } +} + +func (b *box) SetSize(x, y, h, w int) { + b.x, b.y, b.h, b.w = x, y, h, w + b.title.SetSize(b.x+2, b.y, 0, 0) + b.menuItems.SetSize(b.x+2, b.y+b.h-1, 0, 0) + for c := range b.contents { + x := b.x + b.contents[c].offsets.left + y := b.y + b.contents[c].offsets.top + h := b.h - b.contents[c].offsets.bottom + w := b.w - b.contents[c].offsets.right + b.contents[c].container.SetSize(x, y, h, w) + } +} + +func (b *box) Draw(s tcell.Screen) { + for m := 1; m < 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) + } + for m := 1; m < 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.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) + + if b.title != nil { + b.title.Draw(s) + } + if b.menuItems != nil { + b.menuItems.Draw(s) + } + for c := range b.contents { + b.contents[c].container.Draw(s) + } +} + +type list struct { + x, y int + h, w int + selected int + listItems []string +} + +func NewList(listItems []string, initialSelected int) *list { + return &list{ + listItems: listItems, + selected: initialSelected, + } +} + +func (l *list) SetSize(x, y, h, w int) { + l.x, l.y, l.h, l.w = x, y, h, w +} + +func (l *list) Draw(s tcell.Screen) { + for i := range l.listItems { + for j, r := range l.listItems[i] { + s.SetContent(l.x+j, l.y+i, r, nil, tcell.StyleDefault) + } + if i == l.selected { + s.SetContent(l.x+len(l.listItems[i])+1, l.y+i, '<', nil, tcell.StyleDefault) + } + } +} + +type paddedText struct { + x, y int + h, w int + text string +} + +func NewPaddedText(text string) *paddedText { + return &paddedText{text: text} +} + +func (p *paddedText) SetSize(x, y, _, _ int) { + p.x, p.y, p.h, p.w = x, y, 1, len(p.text)+2 +} + +func (p *paddedText) Draw(s tcell.Screen) { + t := p.x + s.SetContent(t, p.y, ' ', nil, tcell.StyleDefault) + t++ + for _, r := range p.text { + s.SetContent(t, p.y, r, nil, tcell.StyleDefault) + t++ + } + s.SetContent(t, p.y, ' ', nil, tcell.StyleDefault) +} diff --git a/cmd/manage/main.go b/cmd/manage/main.go index 0814b69..43a043f 100644 --- a/cmd/manage/main.go +++ b/cmd/manage/main.go @@ -15,7 +15,6 @@ func main() { if err != nil { log.Fatalln(err) } - screen, err := tcell.NewScreen() if err != nil { log.Fatalln(err) @@ -24,31 +23,31 @@ func main() { if err != nil { log.Fatalln(err) } + + l := NewList([]string{"foo", "bar", "baz"}, 0) + b := NewBox( + "library", + []string{"(e)dit", "(q)uit"}, + contents{{ + offsets: offsets{top: 1, left: 2, bottom: -2, right: -2}, + container: l, + }}, + ) + + // init screen.Clear() w, h := screen.Size() - l := &list{ - w: w - 4, h: h - 4, - x: 2, y: 1, - selected: 2, - listItems: []string{"foo", "bar", "baz"}, - } - b := &box{ - w: w, h: h, - x: 0, y: 0, - title: "library", - menuItems: []string{"(e)dit", "(q)uit"}, - contents: l, - } + b.SetSize(0, 0, h, w) + b.Draw(screen) + screen.Sync() + + // UI loop for { e := screen.PollEvent() switch v := e.(type) { case *tcell.EventError: - screen.Clear() screen.Beep() - b.draw(screen) - screen.SetContent(1, 1, 'E', nil, tcell.StyleDefault) - case *tcell.EventKey: - screen.Clear() + case *tcell.EventKey: // input handling if v.Key() == tcell.KeyUp && l.selected > 0 { l.selected = l.selected - 1 } @@ -60,89 +59,18 @@ func main() { fmt.Printf("Thank you for playing Wing Commander!\n\n") return } - b.draw(screen) - case *tcell.EventResize: screen.Clear() + b.Draw(screen) + case *tcell.EventResize: // screen redraw w, h := screen.Size() - b.w, b.h = w, h - b.draw(screen) + b.SetSize(0, 0, h, w) + screen.Clear() + b.Draw(screen) case *tcell.EventInterrupt: case *tcell.EventMouse: case *tcell.EventTime: default: } - screen.Sync() - } -} - -type drawable interface { - draw(tcell.Screen) -} - -type box struct { - x, y int - h, w int - title string - menuItems []string - contents drawable -} - -func (b *box) draw(s tcell.Screen) { - for m := 1; m < 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) - } - for m := 1; m < 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.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) - - if b.title != "" { - t := b.x + 2 - s.SetContent(t, b.y, ' ', nil, tcell.StyleDefault) - t++ - for _, r := range b.title { - s.SetContent(t, b.y, r, nil, tcell.StyleDefault) - t++ - } - s.SetContent(t, b.y, ' ', nil, tcell.StyleDefault) - } - if len(b.menuItems) != 0 { - t := b.x + 2 - s.SetContent(t, b.h-1, ' ', nil, tcell.StyleDefault) - t++ - for i := range b.menuItems { - for _, r := range b.menuItems[i] { - s.SetContent(t, b.h-1, r, nil, tcell.StyleDefault) - t++ - } - s.SetContent(t, b.h-1, ' ', nil, tcell.StyleDefault) - t++ - } - } - if b.contents != nil { - b.contents.draw(s) - } -} - -type list struct { - x, y int - h, w int - selected int - listItems []string -} - -func (l *list) draw(s tcell.Screen) { - for i := range l.listItems { - for j, r := range l.listItems[i] { - s.SetContent(l.x+j, l.y+i, r, nil, tcell.StyleDefault) - } - if i == l.selected { - s.SetContent(l.x+len(l.listItems[i])+1, l.y+i, '<', nil, tcell.StyleDefault) - } + screen.Sync() // repaint } } diff --git a/docker-compose.yml b/docker-compose.yml index 85b835a..362dc18 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,4 +5,4 @@ services: ports: - 3306:3306 environment: - - MYSQL_ROOT_PASSWORD=KigYBNCT9IU5XyB3ehzMLFWyI + - MYSQL_ROOT_PASSWORD=KigYBNCT9IU5XyB3ehzMLFWyI # for dev testing only, obviously.