package buf2d import ( "strings" ) // Buffer is a 2-dimensional rune buffer type Buffer struct { data [][]rune width int height int parent *Buffer } // NewBuffer makes a new buffer with the given dimensions func NewBuffer(width, height int) *Buffer { b := make([][]rune, width) for x := range b { b[x] = make([]rune, height) for y := range b[x] { b[x][y] = ' ' } } return &Buffer{ data: b, width: width, height: height, parent: nil, } } func (b *Buffer) Set(x, y int, c rune) { b.data[x][y] = c } func (b *Buffer) Get(x, y int) rune { return b.data[x][y] } func (b *Buffer) Size() (w, h int) { return b.width, b.height } func (b *Buffer) Width() int { return b.width } func (b *Buffer) Height() int { return b.height } // Draw calls drawFunc for every rune in this buffer func (b *Buffer) Draw(drawFunc func(x, y int, c rune)) { for x, row := range b.data { for y, char := range row { drawFunc(x, y, char) } } } func (b *Buffer) String() string { s := new(strings.Builder) for ri, row := range b.data { for _, char := range row { s.WriteRune(char) } if ri != len(b.data)-1 { s.WriteRune('\n') } } return s.String() } // Sub returns a buffer which is completely contained in this buffer // Modifying the main buffer or the sub buffer will modify the other one as well // This method can be used recursively // If the given dimensions don't fit in the parent buffer, it will be truncated func (b *Buffer) Sub(x, y, w, h int) *Buffer { // sanitize inputs x = limit(x, 0, b.width-1) y = limit(y, 0, b.height-1) w = limit(w, 1, b.width-x) h = limit(h, 1, b.height-y) // make slice references data := make([][]rune, w) for dx := x; dx < x+w-1; dx++ { row := b.data[dx] data[dx] = row[y : y+w] } // make buffer return &Buffer{ data: data, width: w, height: h, parent: b, } }