This repository has been archived on 2022-11-30. You can view files and clone it, but cannot push or open issues or pull requests.
spectator/exhibit/list_widget.go

215 lines
3.5 KiB
Go

package exhibit
import (
"sync"
)
type ListEntry interface {
String() string
Attributes() Attributes
}
type ListWidget struct {
constraints Constraints
attributes Attributes
size Size
cellLock sync.Mutex
cells [][]Cell
rightAlign bool
border bool
listLock sync.Mutex
list [][]Cell
listBuf [][]Cell
lastSize Size
}
func (l ListWidget) Attributes() Attributes {
return l.attributes
}
func (l *ListWidget) SetAttributes(a Attributes) {
l.attributes = a
l.recalculateCells()
}
func (l ListWidget) Constraints() Constraints {
return l.constraints
}
func (l *ListWidget) SetConstraints(c Constraints) {
l.constraints = c
}
func (l ListWidget) Size() Size {
return l.size
}
func (l *ListWidget) SetSize(s Size) {
l.size = s
}
func (l *ListWidget) Render() [][]Cell {
l.cellLock.Lock()
defer l.cellLock.Unlock()
var sx int
sy := len(l.cells)
if sy > 0 {
sx = len(l.cells[0])
} else {
return make([][]Cell, 0)
}
dx := 0
dy := 0
if l.lastSize.X > sx {
dx = l.lastSize.X - sx
}
if l.lastSize.Y > sy {
dy = l.lastSize.Y - sy
}
for y := 0; y < sy+dy; y++ {
if y >= sy {
l.cells = append(l.cells, []Cell{})
}
for x := 0; x < sx+dx; x++ {
if x >= sx || y >= sy {
c := Cell{}
c.Pos.X = x
c.Pos.Y = y
c.Value = ' '
l.cells[y] = append(l.cells[y], c)
} else {
l.cells[y][x].Pos.X = x
l.cells[y][x].Pos.Y = y
}
}
}
l.lastSize.X = sx
l.lastSize.Y = sy
return append([][]Cell(nil), l.cells...)
}
func (l *ListWidget) AddEntry(entry ListEntry) {
if l.listBuf == nil {
l.listBuf = make([][]Cell, 1)
} else {
l.listBuf = append(l.listBuf, []Cell{})
}
index := len(l.listBuf) - 1
for _, r := range entry.String() {
cell := Cell{}
cell.Value = r
cell.Attrs = entry.Attributes()
l.listBuf[index] = append(l.listBuf[index], cell)
}
}
func (l *ListWidget) Commit() {
l.listLock.Lock()
l.list = append([][]Cell{}, l.listBuf...)
l.listLock.Unlock()
l.listBuf = nil
l.recalculateCells()
}
func (l *ListWidget) SetBorder(b bool) {
if l.border == b {
return
}
l.border = b
l.recalculateCells()
}
func (l *ListWidget) SetRightAlign(b bool) {
if l.rightAlign == b {
return
}
l.rightAlign = b
l.recalculateCells()
}
func (l *ListWidget) recalculateCells() {
l.listLock.Lock()
defer l.listLock.Unlock()
var longest int
var border int
for _, s := range l.list {
if longest < len(s) {
longest = len(s)
}
}
cells := make([][]Cell, len(l.list))
if l.border {
border = 1
top := make([]Cell, longest+2)
top[0] = Cell{Value: '┏', Attrs: l.Attributes()}
top[longest+1] = Cell{Value: '┓', Attrs: l.Attributes()}
for i := 1; i <= longest; i++ {
top[i] = Cell{Value: '━', Attrs: l.Attributes()}
}
bottom := append([]Cell(nil), top...)
bottom[0] = Cell{Value: '┗', Attrs: l.Attributes()}
bottom[longest+1] = Cell{Value: '┛', Attrs: l.Attributes()}
cells = append([][]Cell{top}, cells...)
cells = append(cells, bottom)
}
for i, s := range l.list {
cells[i+border] = make([]Cell, longest+border+border)
var start int
if l.rightAlign {
start = longest - len(s)
} else {
start = 0
}
if l.border {
c := Cell{Value: '┃', Attrs: l.Attributes()}
cells[i+border][0] = c
cells[i+border][longest+1] = c
}
for j := 0; j < longest; j++ {
c := Cell{}
if j > start+len(s)-1 || j < start {
c.Value = ' '
} else {
c = s[j-start]
}
cells[i+border][j+border] = c
}
}
l.cellLock.Lock()
defer l.cellLock.Unlock()
l.cells = cells
}