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

195 lines
3.1 KiB
Go
Raw Normal View History

package exhibit
import (
"image"
"sync"
)
type ListEntry interface {
2017-12-27 16:49:20 -07:00
String() string
Attributes() Attributes
}
type ListWidget struct {
2017-12-30 12:25:56 -07:00
blockLock sync.Mutex
block Block
2017-12-30 12:24:00 -07:00
rightAlignLock sync.Mutex
rightAlign bool
borderLock sync.Mutex
border Border
listLock sync.Mutex
list [][]Cell
listBuf [][]Cell
}
2017-12-30 12:24:00 -07:00
func (l *ListWidget) Size() image.Point {
l.blockLock.Lock()
defer l.blockLock.Unlock()
return l.block.Rect.Size()
}
func (l *ListWidget) SetSize(p image.Point) {
2017-12-30 12:24:00 -07:00
l.blockLock.Lock()
defer l.blockLock.Unlock()
l.block.SetSize(p)
}
func (l *ListWidget) Origin() image.Point {
l.blockLock.Lock()
defer l.blockLock.Unlock()
return l.block.Rect.Min
}
func (l *ListWidget) SetOrigin(p image.Point) {
l.blockLock.Lock()
defer l.blockLock.Unlock()
l.block.SetOrigin(p)
}
func (l *ListWidget) Render(origin image.Point) Block {
l.blockLock.Lock()
defer l.blockLock.Unlock()
b := NewBlock(0, 0, 0, 0)
b.Rect = l.block.Rect.Add(origin)
for k, v := range l.block.Cells {
k = k.Add(origin)
b.Cells[k] = v
}
return b
}
func (l *ListWidget) AddEntry(entry ListEntry) {
l.listLock.Lock()
defer l.listLock.Unlock()
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) Border() Border {
l.borderLock.Lock()
defer l.borderLock.Unlock()
return l.border
}
func (l *ListWidget) SetBorder(b Border) {
l.borderLock.Lock()
if l.border == b {
return
}
l.border = b
l.borderLock.Unlock()
l.recalculateCells()
}
func (l *ListWidget) RightAlign() bool {
l.rightAlignLock.Lock()
defer l.rightAlignLock.Unlock()
return l.rightAlign
}
func (l *ListWidget) SetRightAlign(b bool) {
l.rightAlignLock.Lock()
if l.rightAlign == b {
return
}
l.rightAlign = b
l.rightAlignLock.Unlock()
l.recalculateCells()
}
func (l *ListWidget) recalculateCells() {
l.listLock.Lock()
defer l.listLock.Unlock()
l.blockLock.Lock()
rect := l.block.Rect
l.blockLock.Unlock()
origin := rect.Min
size := rect.Size()
rightAlign := l.RightAlign()
border := l.Border()
cells := make(map[image.Point]Cell)
var i, bx, by int
if border.Visible {
size = size.Add(image.Point{2, 2})
bx = 1
by = 1
}
for x := 0; x < size.X; x++ {
for y := 0; y < size.Y; y++ {
c := Cell{Value: ' '}
point := image.Pt(x, y).Add(origin)
cell, ok := border.Cell(point, rect)
if ok {
cells[point] = cell
continue
}
if y < len(l.list)+by {
length := len(l.list[y-by])
if rightAlign {
i = (size.X - x - length - bx) * -1
} else {
i = x - bx
}
if i < length && i >= 0 {
c = l.list[y-by][i]
}
cells[point] = c
}
}
}
l.blockLock.Lock()
l.block.Cells = cells
l.blockLock.Unlock()
}