last_light/render/render.go

290 lines
5.9 KiB
Go

package render
import (
"mvvasilev/last_light/util"
"strings"
"unicode/utf8"
"github.com/gdamore/tcell/v2"
"github.com/google/uuid"
)
type Drawable interface {
UniqueId() uuid.UUID
Draw(s tcell.Screen)
}
type rectangle struct {
id uuid.UUID
size util.Size
position util.Position
style tcell.Style
northBorder rune
westBorder rune
eastBorder rune
southBorder rune
nwCorner rune
swCorner rune
seCorner rune
neCorner rune
fillRune rune
}
func CreateSimpleRectangle(x uint16, y uint16, width uint16, height uint16, borderRune rune, fillRune rune, style tcell.Style) rectangle {
return CreateRectangle(
x, y, width, height,
borderRune, borderRune, borderRune,
borderRune, fillRune, borderRune,
borderRune, borderRune, borderRune,
style,
)
}
// CreateRectangle(
//
// x, y, width, height,
// '┌', '─', '┐',
// '│', ' ', '│',
// '└', '─', '┘',
// style
//
// )
func CreateRectangle(
x uint16,
y uint16,
width uint16,
height uint16,
nwCorner, northBorder, neCorner,
westBorder, fillRune, eastBorder,
swCorner, southBorder, seCorner rune,
style tcell.Style,
) rectangle {
return rectangle{
id: uuid.New(),
size: util.SizeOf(width, height),
position: util.PositionAt(x, y),
style: style,
northBorder: northBorder,
eastBorder: eastBorder,
southBorder: southBorder,
westBorder: westBorder,
nwCorner: nwCorner,
seCorner: seCorner,
swCorner: swCorner,
neCorner: neCorner,
fillRune: fillRune,
}
}
func (rect rectangle) UniqueId() uuid.UUID {
return rect.id
}
func (rect rectangle) Draw(s tcell.Screen) {
width := rect.size.Width()
height := rect.size.Height()
x := rect.position.X()
y := rect.position.Y()
for h := range height {
for w := range width {
// nw corner
if w == 0 && h == 0 {
s.SetContent(x+w, y+h, rect.nwCorner, nil, rect.style)
continue
}
// ne corner
if w == (width-1) && h == 0 {
s.SetContent(x+w, y+h, rect.neCorner, nil, rect.style)
continue
}
// sw corner
if w == 0 && h == (height-1) {
s.SetContent(x+w, y+h, rect.swCorner, nil, rect.style)
continue
}
// se corner
if w == (width-1) && h == (height-1) {
s.SetContent(x+w, y+h, rect.seCorner, nil, rect.style)
continue
}
// north border
if h == 0 && (w != 0 && w != (width-1)) {
s.SetContent(x+w, y+h, rect.northBorder, nil, rect.style)
continue
}
// south border
if h == (height-1) && (w != 0 && w != (width-1)) {
s.SetContent(x+w, y+h, rect.southBorder, nil, rect.style)
continue
}
// west border
if w == 0 && (h != 0 && h != (height-1)) {
s.SetContent(x+w, y+h, rect.westBorder, nil, rect.style)
continue
}
// east border
if w == (width-1) && (h != 0 && h != (height-1)) {
s.SetContent(x+w, y+h, rect.eastBorder, nil, rect.style)
continue
}
s.SetContent(x+w, y+h, rect.fillRune, nil, rect.style)
}
}
}
type text struct {
id uuid.UUID
content []string
position util.Position
size util.Size
style tcell.Style
}
func CreateText(
x, y uint16,
width, height uint16,
content string,
style tcell.Style,
) text {
return text{
id: uuid.New(),
content: strings.Split(content, " "),
style: style,
size: util.SizeOf(width, height),
position: util.PositionAt(x, y),
}
}
func (t text) UniqueId() uuid.UUID {
return t.id
}
func (t text) Draw(s tcell.Screen) {
width := t.size.Width()
height := t.size.Height()
x := t.position.X()
y := t.position.Y()
currentHPos := 0
currentVPos := 0
drawText := func(text string) {
for i, r := range text {
s.SetContent(x+currentHPos+i, y+currentVPos, r, nil, t.style)
}
}
for _, s := range t.content {
runeCount := utf8.RuneCountInString(s)
if currentVPos > height {
break
}
// The current word cannot fit within the remaining space on the line
if runeCount > (width - currentHPos) {
currentVPos += 1 // next line
currentHPos = 0 // reset to start of line
drawText(s + " ")
currentHPos += runeCount + 1
continue
}
// The current word fits exactly within the remaining space on the line
if runeCount == (width - currentHPos) {
drawText(s)
currentVPos += 1 // next line
currentHPos = 0 // reset to start of line
continue
}
// The current word fits within the remaining space, and there's more space left over
drawText(s + " ")
currentHPos += runeCount + 1 // add +1 to account for space after word
}
}
type grid struct {
id uuid.UUID
internalCellSize util.Size
numCellsHorizontal uint16
numCellsVertical uint16
position util.Position
style tcell.Style
northBorder rune
westBorder rune
eastBorder rune
southBorder rune
nwCorner rune
swCorner rune
seCorner rune
neCorner rune
verticalTJunction rune
horizontalTJunction rune
crossJunction rune
fillRune rune
}
func CreateGrid(
x uint16,
y uint16,
cellWidth uint16,
cellHeight uint16,
numCellsHorizontal uint16,
numCellsVertical uint16,
nwCorner, northBorder, neCorner,
westBorder, fillRune, eastBorder,
swCorner, southBorder, seCorner,
verticalTJunction, horizontalTJunction,
crossJunction rune,
style tcell.Style,
) grid {
return grid{
id: uuid.New(),
internalCellSize: util.SizeOf(cellWidth, cellHeight),
numCellsHorizontal: numCellsHorizontal,
numCellsVertical: numCellsVertical,
position: util.PositionAt(x, y),
style: style,
northBorder: northBorder,
eastBorder: eastBorder,
southBorder: southBorder,
westBorder: westBorder,
nwCorner: nwCorner,
seCorner: seCorner,
swCorner: swCorner,
neCorner: neCorner,
fillRune: fillRune,
verticalTJunction: verticalTJunction,
horizontalTJunction: horizontalTJunction,
crossJunction: crossJunction,
}
}
func (g grid) Draw(s tcell.Screen) {
}