3 changed files with 160 additions and 97 deletions
@ -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) |
||||
} |
Loading…
Reference in new issue