2018-02-19 15:25:02 +08:00
|
|
|
package termui
|
|
|
|
|
2018-02-19 15:51:55 +08:00
|
|
|
import (
|
|
|
|
"image"
|
|
|
|
)
|
2018-02-19 15:25:02 +08:00
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// Cell is a rune with assigned Fg and Bg.
|
2018-02-19 15:25:02 +08:00
|
|
|
type Cell struct {
|
|
|
|
Ch rune
|
2018-02-21 16:46:11 +08:00
|
|
|
Fg Color
|
|
|
|
Bg Color
|
2018-02-19 15:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Buffer is a renderable rectangle cell data container.
|
|
|
|
type Buffer struct {
|
|
|
|
Area image.Rectangle // selected drawing area
|
|
|
|
CellMap map[image.Point]Cell
|
|
|
|
}
|
|
|
|
|
2018-02-21 16:46:11 +08:00
|
|
|
func NewCell(ch rune, Fg, Bg Color) Cell {
|
2018-02-19 15:25:02 +08:00
|
|
|
return Cell{ch, Fg, Bg}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBuffer() *Buffer {
|
|
|
|
return &Buffer{
|
|
|
|
CellMap: make(map[image.Point]Cell),
|
|
|
|
Area: image.Rectangle{}}
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// NewFilledBuffer returns a new Buffer filled with the given Cell.
|
2018-02-19 15:25:02 +08:00
|
|
|
func NewFilledBuffer(x0, y0, x1, y1 int, c Cell) *Buffer {
|
|
|
|
buf := NewBuffer()
|
|
|
|
buf.Area.Min = image.Pt(x0, y0)
|
|
|
|
buf.Area.Max = image.Pt(x1, y1)
|
|
|
|
|
|
|
|
for x := buf.Area.Min.X; x < buf.Area.Max.X; x++ {
|
|
|
|
for y := buf.Area.Min.Y; y < buf.Area.Max.Y; y++ {
|
|
|
|
buf.SetCell(x, y, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// Set assigns a Cell to (x,y).
|
2018-02-19 15:25:02 +08:00
|
|
|
func (b *Buffer) SetCell(x, y int, c Cell) {
|
|
|
|
b.CellMap[image.Pt(x, y)] = c
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// SetString assigns a string to a Buffer starting at (x,y).
|
2018-02-21 16:46:11 +08:00
|
|
|
func (b *Buffer) SetString(x, y int, s string, fg, bg Color) {
|
2018-02-19 15:25:02 +08:00
|
|
|
for i, char := range s {
|
|
|
|
b.SetCell(x+i, y, Cell{char, fg, bg})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// At returns the cell at (x,y).
|
|
|
|
func (b *Buffer) At(x, y int) Cell {
|
|
|
|
return b.CellMap[image.Pt(x, y)]
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetArea assigns a new rect area to Buffer b.
|
|
|
|
func (b *Buffer) SetArea(r image.Rectangle) {
|
|
|
|
b.Area.Max = r.Max
|
|
|
|
b.Area.Min = r.Min
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// SetAreaXY sets the Buffer bounds from (0,0) to (x,y).
|
2018-02-19 15:25:02 +08:00
|
|
|
func (b *Buffer) SetAreaXY(x, y int) {
|
|
|
|
b.Area.Min.Y = 0
|
|
|
|
b.Area.Min.X = 0
|
|
|
|
b.Area.Max.Y = y
|
|
|
|
b.Area.Max.X = x
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// Merge merges the given buffers onto the current Buffer.
|
2018-02-19 15:25:02 +08:00
|
|
|
func (b *Buffer) Merge(bs ...*Buffer) {
|
|
|
|
for _, buf := range bs {
|
|
|
|
for p, c := range buf.CellMap {
|
|
|
|
b.SetCell(p.X, p.Y, c)
|
|
|
|
}
|
|
|
|
b.SetArea(b.Area.Union(buf.Area))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// MergeWithOffset merges the given buffer at a certain position on the given buffer.
|
2018-02-19 15:25:02 +08:00
|
|
|
func (b *Buffer) MergeWithOffset(buf *Buffer, xOffset, yOffset int) {
|
|
|
|
for p, c := range buf.CellMap {
|
|
|
|
b.SetCell(p.X+xOffset, p.Y+yOffset, c)
|
|
|
|
}
|
|
|
|
rect := image.Rect(xOffset, yOffset, buf.Area.Max.X+xOffset, buf.Area.Max.Y+yOffset)
|
|
|
|
b.SetArea(b.Area.Union(rect))
|
|
|
|
}
|
|
|
|
|
2018-02-23 16:42:39 +08:00
|
|
|
// Fill fills the Buffer with a Cell.
|
2018-02-19 15:25:02 +08:00
|
|
|
func (b *Buffer) Fill(c Cell) {
|
|
|
|
for x := b.Area.Min.X; x < b.Area.Max.X; x++ {
|
|
|
|
for y := b.Area.Min.Y; y < b.Area.Max.Y; y++ {
|
|
|
|
b.SetCell(x, y, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|