96 lines
2.2 KiB
Go
96 lines
2.2 KiB
Go
|
|
package game
|
||
|
|
|
||
|
|
import (
|
||
|
|
tea "github.com/charmbracelet/bubbletea"
|
||
|
|
"github.com/charmbracelet/lipgloss"
|
||
|
|
)
|
||
|
|
|
||
|
|
var inkPalette = []string{"#ff6b6b", "#feca57", "#1dd1a1", "#54a0ff", "#ff9ff3", "#48dbfb", "#f368e0", "#ffffff"}
|
||
|
|
var charPalette = []rune{'█', '▓', '▒', '░', '#', '*', '.', '@', 'o', '+'}
|
||
|
|
|
||
|
|
type state int
|
||
|
|
|
||
|
|
const (
|
||
|
|
stateIntro state = iota
|
||
|
|
stateCanvas
|
||
|
|
)
|
||
|
|
|
||
|
|
type Model struct {
|
||
|
|
canvas *Canvas
|
||
|
|
id string
|
||
|
|
label string
|
||
|
|
state state
|
||
|
|
renderer *lipgloss.Renderer
|
||
|
|
|
||
|
|
inkColorIdx int
|
||
|
|
charIdx int
|
||
|
|
|
||
|
|
width, height int
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewModel(canvas *Canvas, id, label string, renderer *lipgloss.Renderer) Model {
|
||
|
|
return Model{canvas: canvas, id: id, label: label, state: stateIntro, renderer: renderer}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m Model) Init() tea.Cmd { return nil }
|
||
|
|
|
||
|
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||
|
|
switch msg := msg.(type) {
|
||
|
|
case tea.WindowSizeMsg:
|
||
|
|
m.width, m.height = msg.Width, msg.Height
|
||
|
|
return m, nil
|
||
|
|
|
||
|
|
case canvasUpdatedMsg:
|
||
|
|
// Someone (possibly this session) changed the shared state --
|
||
|
|
// nothing to do here but re-render; View() always reads a fresh
|
||
|
|
// snapshot from the canvas.
|
||
|
|
return m, nil
|
||
|
|
|
||
|
|
case tea.KeyMsg:
|
||
|
|
if m.state == stateIntro {
|
||
|
|
m.state = stateCanvas
|
||
|
|
return m, nil
|
||
|
|
}
|
||
|
|
return m.handleKey(msg)
|
||
|
|
}
|
||
|
|
return m, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m Model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||
|
|
switch msg.String() {
|
||
|
|
case "ctrl+c", "q":
|
||
|
|
return m, tea.Quit
|
||
|
|
|
||
|
|
case "up", "k":
|
||
|
|
m.canvas.MoveCursor(m.id, 0, -1)
|
||
|
|
case "down", "j":
|
||
|
|
m.canvas.MoveCursor(m.id, 0, 1)
|
||
|
|
case "left", "h":
|
||
|
|
m.canvas.MoveCursor(m.id, -1, 0)
|
||
|
|
case "right", "l":
|
||
|
|
m.canvas.MoveCursor(m.id, 1, 0)
|
||
|
|
|
||
|
|
case " ", "enter":
|
||
|
|
if cur, ok := m.canvas.CursorsSnapshot()[m.id]; ok {
|
||
|
|
m.canvas.Paint(cur.X, cur.Y, charPalette[m.charIdx], inkPalette[m.inkColorIdx])
|
||
|
|
}
|
||
|
|
|
||
|
|
case "backspace", "delete":
|
||
|
|
if cur, ok := m.canvas.CursorsSnapshot()[m.id]; ok {
|
||
|
|
m.canvas.Paint(cur.X, cur.Y, ' ', "")
|
||
|
|
}
|
||
|
|
|
||
|
|
case "[":
|
||
|
|
m.charIdx = (m.charIdx - 1 + len(charPalette)) % len(charPalette)
|
||
|
|
case "]":
|
||
|
|
m.charIdx = (m.charIdx + 1) % len(charPalette)
|
||
|
|
|
||
|
|
case "1", "2", "3", "4", "5", "6", "7", "8":
|
||
|
|
m.inkColorIdx = int(msg.String()[0] - '1')
|
||
|
|
|
||
|
|
case "c":
|
||
|
|
m.canvas.Clear()
|
||
|
|
}
|
||
|
|
return m, nil
|
||
|
|
}
|