continue to add more building blocks

This commit is contained in:
David 2021-07-03 10:58:45 -04:00
parent 117c7e0e41
commit de3f9cfadb
3 changed files with 160 additions and 97 deletions

135
cmd/manage/interface.go Normal file
View File

@ -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)
}

View File

@ -15,7 +15,6 @@ func main() {
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
screen, err := tcell.NewScreen() screen, err := tcell.NewScreen()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
@ -24,31 +23,31 @@ func main() {
if err != nil { if err != nil {
log.Fatalln(err) 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() screen.Clear()
w, h := screen.Size() w, h := screen.Size()
l := &list{ b.SetSize(0, 0, h, w)
w: w - 4, h: h - 4, b.Draw(screen)
x: 2, y: 1, screen.Sync()
selected: 2,
listItems: []string{"foo", "bar", "baz"}, // UI loop
}
b := &box{
w: w, h: h,
x: 0, y: 0,
title: "library",
menuItems: []string{"(e)dit", "(q)uit"},
contents: l,
}
for { for {
e := screen.PollEvent() e := screen.PollEvent()
switch v := e.(type) { switch v := e.(type) {
case *tcell.EventError: case *tcell.EventError:
screen.Clear()
screen.Beep() screen.Beep()
b.draw(screen) case *tcell.EventKey: // input handling
screen.SetContent(1, 1, 'E', nil, tcell.StyleDefault)
case *tcell.EventKey:
screen.Clear()
if v.Key() == tcell.KeyUp && l.selected > 0 { if v.Key() == tcell.KeyUp && l.selected > 0 {
l.selected = l.selected - 1 l.selected = l.selected - 1
} }
@ -60,89 +59,18 @@ func main() {
fmt.Printf("Thank you for playing Wing Commander!\n\n") fmt.Printf("Thank you for playing Wing Commander!\n\n")
return return
} }
b.draw(screen)
case *tcell.EventResize:
screen.Clear() screen.Clear()
b.Draw(screen)
case *tcell.EventResize: // screen redraw
w, h := screen.Size() w, h := screen.Size()
b.w, b.h = w, h b.SetSize(0, 0, h, w)
b.draw(screen) screen.Clear()
b.Draw(screen)
case *tcell.EventInterrupt: case *tcell.EventInterrupt:
case *tcell.EventMouse: case *tcell.EventMouse:
case *tcell.EventTime: case *tcell.EventTime:
default: default:
} }
screen.Sync() screen.Sync() // repaint
}
}
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)
}
} }
} }

View File

@ -5,4 +5,4 @@ services:
ports: ports:
- 3306:3306 - 3306:3306
environment: environment:
- MYSQL_ROOT_PASSWORD=KigYBNCT9IU5XyB3ehzMLFWyI - MYSQL_ROOT_PASSWORD=KigYBNCT9IU5XyB3ehzMLFWyI # for dev testing only, obviously.