mirror of
https://github.com/mvvasilev/last_light.git
synced 2025-04-19 12:49:52 +03:00
Fix layering
This commit is contained in:
parent
6d576939db
commit
c2cd1dcf97
6 changed files with 377 additions and 317 deletions
2
main.go
2
main.go
|
@ -45,7 +45,7 @@ func main() {
|
||||||
layers.Insert(0, rect)
|
layers.Insert(0, rect)
|
||||||
layers.Insert(1, text)
|
layers.Insert(1, text)
|
||||||
|
|
||||||
layers.Remove(text.UniqueId())
|
//layers.Remove(text.UniqueId())
|
||||||
|
|
||||||
events := make(chan tcell.Event)
|
events := make(chan tcell.Event)
|
||||||
quit := make(chan struct{})
|
quit := make(chan struct{})
|
||||||
|
|
78
render/grid.go
Normal file
78
render/grid.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package render
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mvvasilev/last_light/util"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
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) UniqueId() uuid.UUID {
|
||||||
|
return g.id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g grid) Draw(s tcell.Screen) {
|
||||||
|
|
||||||
|
}
|
|
@ -5,50 +5,95 @@ import (
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/tidwall/btree"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type layer struct {
|
||||||
|
zIndex uint8
|
||||||
|
contents []Drawable
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeLayer(zIndex uint8) *layer {
|
||||||
|
l := new(layer)
|
||||||
|
|
||||||
|
l.zIndex = zIndex
|
||||||
|
l.contents = make([]Drawable, 0, 1)
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *layer) push(drawable Drawable) {
|
||||||
|
l.contents = append(l.contents, drawable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *layer) remove(uuid uuid.UUID) {
|
||||||
|
l.contents = slices.DeleteFunc(l.contents, func(d Drawable) bool {
|
||||||
|
return d.UniqueId() == uuid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *layer) draw(s tcell.Screen) {
|
||||||
|
for _, d := range l.contents {
|
||||||
|
d.Draw(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type layeredDrawContainer struct {
|
type layeredDrawContainer struct {
|
||||||
id uuid.UUID
|
id uuid.UUID
|
||||||
layers *btree.Map[uint8, []Drawable]
|
layers []*layer
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateLayeredDrawContainer() *layeredDrawContainer {
|
func CreateLayeredDrawContainer() *layeredDrawContainer {
|
||||||
container := new(layeredDrawContainer)
|
container := new(layeredDrawContainer)
|
||||||
|
|
||||||
container.layers = btree.NewMap[uint8, []Drawable](2)
|
container.layers = make([]*layer, 0, 32)
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldc *layeredDrawContainer) Insert(zLevel uint8, drawable Drawable) {
|
func (ldc *layeredDrawContainer) Insert(zLevel uint8, drawable Drawable) {
|
||||||
arr, found := ldc.layers.Get(zLevel)
|
// if no layers exist, just insert a new one
|
||||||
|
if len(ldc.layers) == 0 {
|
||||||
|
l := makeLayer(zLevel)
|
||||||
|
l.push(drawable)
|
||||||
|
ldc.layers = append(ldc.layers, l)
|
||||||
|
|
||||||
if !found {
|
return
|
||||||
arr = make([]Drawable, 1, 2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arr = append(arr, drawable)
|
// find a layer with this z-index
|
||||||
|
i := slices.IndexFunc(ldc.layers, func(l *layer) bool {
|
||||||
|
return l.zIndex == zLevel
|
||||||
|
})
|
||||||
|
|
||||||
ldc.layers.Set(zLevel, arr)
|
// z index already exists
|
||||||
|
if i > 0 {
|
||||||
|
l := ldc.layers[i]
|
||||||
|
l.push(drawable)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldc *layeredDrawContainer) Remove(id uuid.UUID) {
|
// no such layer exists, create it
|
||||||
ldc.layers.ScanMut(func(key uint8, value []Drawable) bool {
|
|
||||||
newSlices := slices.DeleteFunc(value, func(v Drawable) bool { return v.UniqueId() == id })
|
|
||||||
|
|
||||||
ldc.layers.Set(key, newSlices)
|
l := makeLayer(zLevel)
|
||||||
|
l.push(drawable)
|
||||||
|
|
||||||
if len(newSlices) != len(value) {
|
ldc.layers = append(ldc.layers, l)
|
||||||
return false // the slice has been modified, we have found the drawable. Return false to stop iteration.
|
|
||||||
} else {
|
// order layers ascending
|
||||||
return true // we haven't found it yet, keep going
|
slices.SortFunc(ldc.layers, func(l1 *layer, l2 *layer) int {
|
||||||
}
|
return int(l1.zIndex) - int(l2.zIndex)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ldc *layeredDrawContainer) Remove(id uuid.UUID) {
|
||||||
|
for _, l := range ldc.layers {
|
||||||
|
l.remove(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ldc *layeredDrawContainer) Clear() {
|
func (ldc *layeredDrawContainer) Clear() {
|
||||||
ldc.layers = btree.NewMap[uint8, []Drawable](2)
|
ldc.layers = make([]*layer, 0, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldc *layeredDrawContainer) UniqueId() uuid.UUID {
|
func (ldc *layeredDrawContainer) UniqueId() uuid.UUID {
|
||||||
|
@ -56,11 +101,7 @@ func (ldc *layeredDrawContainer) UniqueId() uuid.UUID {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldc *layeredDrawContainer) Draw(s tcell.Screen) {
|
func (ldc *layeredDrawContainer) Draw(s tcell.Screen) {
|
||||||
ldc.layers.Ascend(0, func(key uint8, value []Drawable) bool {
|
for _, d := range ldc.layers {
|
||||||
for _, d := range value {
|
d.draw(s)
|
||||||
d.Draw(s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
140
render/rectangle.go
Normal file
140
render/rectangle.go
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
package render
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mvvasilev/last_light/util"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
290
render/render.go
290
render/render.go
|
@ -1,290 +0,0 @@
|
||||||
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) {
|
|
||||||
|
|
||||||
}
|
|
91
render/text.go
Normal file
91
render/text.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue