stone/buffer.go

166 lines
4.5 KiB
Go
Raw Normal View History

2022-10-31 13:51:28 -06:00
package stone
2022-11-14 22:22:01 -07:00
// Color represents all the different colors a cell can be.
2022-10-31 13:51:28 -06:00
type Color uint8
const (
ColorBackground Color = 0x0
2022-11-15 09:16:29 -07:00
ColorForeground Color = 0x1
ColorRed Color = 0x2
ColorOrange Color = 0x3
ColorYellow Color = 0x4
ColorGreen Color = 0x5
ColorBlue Color = 0x6
ColorPurple Color = 0x7
2022-10-31 13:51:28 -06:00
)
2022-11-14 22:22:01 -07:00
// Style contains styling information about cells. These properties can be or'd
// together to combine them.
2022-10-31 13:51:28 -06:00
type Style uint8
const (
StyleNormal Style = iota
StyleBold Style = iota >> 1
StyleItalic
StyleBoldItalic Style = StyleBold | StyleItalic
)
2022-11-14 22:22:01 -07:00
// Cell is a grid-aligned rune in a buffer with associated styling and color
// informaiton.
2022-10-31 13:51:28 -06:00
type Cell struct {
color Color
style Style
content rune
}
2022-11-14 22:22:01 -07:00
// Color returns the cell's color.
2022-11-15 09:16:29 -07:00
func (cell Cell) Color () (color Color) {
2022-10-31 13:51:28 -06:00
color = cell.color
return
}
2022-11-14 22:22:01 -07:00
// Style returns the styling information associated with the cell
2022-10-31 13:51:28 -06:00
func (cell Cell) Style (style Style) {
style = cell.style
return
}
2022-11-14 22:22:01 -07:00
// Rune returns the rune in the cell
2022-11-02 16:51:33 -06:00
func (cell Cell) Rune () (content rune) {
2022-10-31 13:51:28 -06:00
content = cell.content
return
}
2022-11-15 15:36:41 -07:00
// Buffer is a two dimensional text buffer that stores a grid of cells, as well
// as information stating whether each cell is clean or dirty. Cells are dirty
// by default, are only clean when marked as clean, and become dirty again when
// they are altered in some way.
2022-10-31 13:51:28 -06:00
type Buffer struct {
content []Cell
2022-11-15 15:36:41 -07:00
clean []bool
2022-10-31 13:51:28 -06:00
width int
height int
Dot struct {
X int
Y int
}
2022-10-31 13:51:28 -06:00
}
2022-11-06 13:25:55 -07:00
func (buffer *Buffer) isOutOfBounds (x, y int) (outOfBounds bool) {
outOfBounds =
x < 0 ||
y < 0 ||
x >= buffer.width ||
y >= buffer.height
return
}
2022-11-14 22:22:01 -07:00
// Size returns the width and height of the buffer.
2022-10-31 13:51:28 -06:00
func (buffer *Buffer) Size () (width, height int) {
width = buffer.width
height = buffer.height
return
}
2022-11-15 15:36:41 -07:00
// ResetDot is a convenience method to reset the dot to the buffer origin point
// (0, 0).
func (buffer *Buffer) ResetDot () {
buffer.Dot.X = 0
buffer.Dot.Y = 0
2022-10-31 13:51:28 -06:00
}
2022-11-14 22:22:01 -07:00
// Cell returns the cell at the specified x and y coordinates. If the
// coordinates are out of bounds, this method will return a blank cell.
2022-10-31 13:51:28 -06:00
func (buffer *Buffer) Cell (x, y int) (cell Cell) {
2022-11-06 13:25:55 -07:00
if buffer.isOutOfBounds(x, y) { return }
2022-10-31 13:51:28 -06:00
cell = buffer.content[x + y * buffer.width]
return
}
2022-11-14 22:22:01 -07:00
// SetColor sets the color of the cell at the specified x and y coordinates.
2022-10-31 13:51:28 -06:00
func (buffer *Buffer) SetColor (x, y int, color Color) {
2022-11-06 13:25:55 -07:00
if buffer.isOutOfBounds(x, y) { return }
2022-11-15 15:36:41 -07:00
index := x + y * buffer.width
buffer.clean[index] = buffer.content[index].color == color
buffer.content[index].color = color
2022-10-31 13:51:28 -06:00
}
2022-11-14 22:22:01 -07:00
// SetSize sets the width and height of the buffer. This clears all data in the
// buffer. If the width or height is negative, this method does nothing.
2022-11-15 15:36:41 -07:00
func (buffer *Buffer) SetSize (width, height int) {
2022-11-06 13:59:06 -07:00
if width < 0 || height < 0 { return }
2022-11-15 15:36:41 -07:00
buffer.width = width
buffer.height = height
buffer.content = make([]Cell, width * height)
buffer.clean = make([]bool, width * height)
for index := 0; index < len(buffer.content); index ++ {
buffer.content[index].color = ColorForeground
}
2022-10-31 13:51:28 -06:00
}
2022-11-14 22:22:01 -07:00
// SetStyle sets the style of the cell at the specified x and y coordinates.
2022-11-15 15:36:41 -07:00
func (buffer *Buffer) SetStyle (x, y int, style Style) {
2022-11-06 13:25:55 -07:00
if buffer.isOutOfBounds(x, y) { return }
index := x + y * buffer.width
buffer.clean[index] = buffer.content[index].style == style
2022-11-15 15:36:41 -07:00
buffer.content[index].style = style
2022-10-31 13:51:28 -06:00
}
2022-11-14 22:22:01 -07:00
// SetRune sets the rune of the cell at the specified x and y coordinates.
2022-11-15 15:36:41 -07:00
func (buffer *Buffer) SetRune (x, y int, content rune) {
2022-11-06 13:25:55 -07:00
if buffer.isOutOfBounds(x, y) { return }
index := x + y * buffer.width
buffer.clean[index] = buffer.content[index].content == content
2022-11-15 15:36:41 -07:00
buffer.content[index].content = content
2022-10-31 13:51:28 -06:00
}
2022-11-14 22:22:01 -07:00
// Write writes data stored in a byte slice to the buffer at the current dot
2022-11-15 15:36:41 -07:00
// position. This makes Buffer an io.Writer.
func (buffer *Buffer) Write (bytes []byte) (bytesWritten int, err error) {
text := string(bytes)
bytesWritten = len(bytes)
for _, character := range text {
buffer.SetRune(buffer.Dot.X, buffer.Dot.Y, character)
buffer.Dot.X ++
if buffer.Dot.X > buffer.width { break }
}
return
}
2022-11-14 22:22:01 -07:00
// Clean returns whether or not the cell at the specified x and y coordinates is
// clean.
2022-11-15 15:36:41 -07:00
func (buffer *Buffer) Clean (x, y int) (clean bool) {
2022-11-06 13:25:55 -07:00
if buffer.isOutOfBounds(x, y) { return }
2022-10-31 13:51:28 -06:00
clean = buffer.clean[x + y * buffer.width]
return
}
2022-11-14 22:22:01 -07:00
// MarkClean marks the cell at the specified x and y coordinates as clean.
2022-11-15 15:36:41 -07:00
func (buffer *Buffer) MarkClean (x, y int) {
2022-11-06 13:25:55 -07:00
if buffer.isOutOfBounds(x, y) { return }
2022-10-31 13:51:28 -06:00
buffer.clean[x + y * buffer.width] = true
}