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