mirror of
https://github.com/BigJk/crt.git
synced 2026-02-06 10:47:25 +00:00
Added visible cursor support.
This commit is contained in:
parent
c347038c5d
commit
19757d9b62
@ -36,7 +36,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Just pass your tea.Model to the bubbleadapter, and it will render it to the terminal.
|
||||
win, err := bubbleadapter.Window(1000, 600, fonts, someModel{}, color.Black, tea.WithAltScreen())
|
||||
win, _, err := bubbleadapter.Window(1000, 600, fonts, someModel{}, color.Black, tea.WithAltScreen())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ func (f fakeEnviron) Getenv(s string) string {
|
||||
|
||||
// Window creates a new crt based bubbletea window with the given width, height, fonts, model and default background color.
|
||||
// Additional options can be passed to the bubbletea program.
|
||||
func Window(width int, height int, fonts crt.Fonts, model tea.Model, defaultBg color.Color, options ...tea.ProgramOption) (*crt.Window, error) {
|
||||
func Window(width int, height int, fonts crt.Fonts, model tea.Model, defaultBg color.Color, options ...tea.ProgramOption) (*crt.Window, *tea.Program, error) {
|
||||
gameInput := crt.NewConcurrentRW()
|
||||
gameOutput := crt.NewConcurrentRW()
|
||||
|
||||
@ -56,5 +56,6 @@ func Window(width int, height int, fonts crt.Fonts, model tea.Model, defaultBg c
|
||||
crt.SysKill()
|
||||
}()
|
||||
|
||||
return crt.NewGame(width, height, fonts, gameOutput, NewAdapter(prog), defaultBg)
|
||||
win, err := crt.NewGame(width, height, fonts, gameOutput, NewAdapter(prog), defaultBg)
|
||||
return win, prog, err
|
||||
}
|
||||
|
||||
46
crt.go
46
crt.go
@ -30,14 +30,17 @@ type Window struct {
|
||||
tty io.Reader
|
||||
|
||||
// Terminal cursor and color states.
|
||||
cursorX int
|
||||
cursorY int
|
||||
mouseCellX int
|
||||
mouseCellY int
|
||||
defaultBg color.Color
|
||||
curFg color.Color
|
||||
curBg color.Color
|
||||
curWeight FontWeight
|
||||
cursorChar string
|
||||
cursorColor color.Color
|
||||
showCursor bool
|
||||
cursorX int
|
||||
cursorY int
|
||||
mouseCellX int
|
||||
mouseCellY int
|
||||
defaultBg color.Color
|
||||
curFg color.Color
|
||||
curBg color.Color
|
||||
curWeight FontWeight
|
||||
|
||||
// Other
|
||||
showTps bool
|
||||
@ -45,7 +48,6 @@ type Window struct {
|
||||
bgColors *image.RGBA
|
||||
shader []shader.Shader
|
||||
routine sync.Once
|
||||
tick float64
|
||||
}
|
||||
|
||||
// NewGame creates a new terminal game with the given dimensions and font faces.
|
||||
@ -89,6 +91,8 @@ func NewGame(width int, height int, fonts Fonts, tty io.Reader, adapter InputAda
|
||||
grid: grid,
|
||||
tty: tty,
|
||||
bgColors: image.NewRGBA(image.Rect(0, 0, cellsWidth*cellWidth, cellsHeight*cellHeight)),
|
||||
cursorChar: "█",
|
||||
cursorColor: color.RGBA{R: 255, G: 255, B: 255, A: 100},
|
||||
}
|
||||
|
||||
game.inputAdapter.HandleWindowSize(WindowSize{
|
||||
@ -102,6 +106,21 @@ func NewGame(width int, height int, fonts Fonts, tty io.Reader, adapter InputAda
|
||||
return game, nil
|
||||
}
|
||||
|
||||
// SetShowCursor enables or disables the cursor.
|
||||
func (g *Window) SetShowCursor(val bool) {
|
||||
g.showCursor = val
|
||||
}
|
||||
|
||||
// SetCursorChar sets the character that is used for the cursor.
|
||||
func (g *Window) SetCursorChar(char string) {
|
||||
g.cursorChar = char
|
||||
}
|
||||
|
||||
// SetCursorColor sets the color of the cursor.
|
||||
func (g *Window) SetCursorColor(color color.Color) {
|
||||
g.cursorColor = color
|
||||
}
|
||||
|
||||
// SetShader sets a shader that is applied to the whole screen.
|
||||
func (g *Window) SetShader(shader ...shader.Shader) {
|
||||
g.shader = shader
|
||||
@ -215,6 +234,10 @@ func (g *Window) handleCSI(csi any) {
|
||||
g.SetBgPixels(i, g.cursorY, g.defaultBg)
|
||||
}
|
||||
}
|
||||
case CursorShowSeq:
|
||||
g.SetShowCursor(true)
|
||||
case CursorHideSeq:
|
||||
g.SetShowCursor(false)
|
||||
case ScrollUpSeq:
|
||||
fmt.Println("UNSUPPORTED: ScrollUpSeq", seq.Count)
|
||||
case ScrollDownSeq:
|
||||
@ -447,7 +470,10 @@ func (g *Window) Draw(screen *ebiten.Image) {
|
||||
}
|
||||
}
|
||||
|
||||
g.tick += 1 / 60.0
|
||||
if g.showCursor {
|
||||
text.Draw(bufferImage, g.cursorChar, g.fonts.Normal, g.cursorX*g.cellWidth, g.cursorY*g.cellHeight+g.cellOffsetY, g.cursorColor)
|
||||
}
|
||||
|
||||
if g.shader != nil {
|
||||
for i := range g.shader {
|
||||
_ = g.shader[i].Apply(screen, bufferImage)
|
||||
|
||||
11
csi.go
11
csi.go
@ -72,6 +72,10 @@ type DeleteLineSeq struct {
|
||||
Count int
|
||||
}
|
||||
|
||||
type CursorShowSeq struct{}
|
||||
|
||||
type CursorHideSeq struct{}
|
||||
|
||||
// extractCSI extracts a CSI sequence from the beginning of a string.
|
||||
// It returns the sequence without any suffix, and a boolean indicating
|
||||
// whether a sequence was found.
|
||||
@ -105,6 +109,13 @@ func parseCSI(s string) (any, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
switch s {
|
||||
case termenv.ShowCursorSeq:
|
||||
return CursorShowSeq{}, true
|
||||
case termenv.HideCursorSeq:
|
||||
return CursorHideSeq{}, true
|
||||
}
|
||||
|
||||
switch s[len(s)-1] {
|
||||
case 'A':
|
||||
if count, err := strconv.Atoi(s[:len(s)-1]); err == nil {
|
||||
|
||||
@ -15,6 +15,7 @@ func TestCSI(t *testing.T) {
|
||||
testString += fmt.Sprintf(termenv.CSI+termenv.CursorPositionSeq, 1, 2)
|
||||
testString += fmt.Sprintf(termenv.CSI+termenv.CursorPositionSeq, 1, 2)
|
||||
testString += "HELLO WORLD"
|
||||
testString += termenv.CSI + termenv.ShowCursorSeq
|
||||
testString += fmt.Sprintf(termenv.CSI+termenv.CursorPositionSeq, 1, 2)
|
||||
testString += fmt.Sprintf(termenv.CSI+termenv.CursorBackSeq, 5)
|
||||
|
||||
@ -34,6 +35,7 @@ func TestCSI(t *testing.T) {
|
||||
EraseDisplaySeq{Type: 20},
|
||||
CursorPositionSeq{Row: 1, Col: 2},
|
||||
CursorPositionSeq{Row: 1, Col: 2},
|
||||
CursorShowSeq{},
|
||||
CursorPositionSeq{Row: 1, Col: 2},
|
||||
CursorBackSeq{Count: 5},
|
||||
}, sequences)
|
||||
|
||||
@ -43,7 +43,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
win, err := bubbleadapter.Window(Width, Height, fonts, model{}, color.Black)
|
||||
win, _, err := bubbleadapter.Window(Width, Height, fonts, model{}, color.Black)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
win, err := bubbleadapter.Window(Width, Height, fonts, newModel(), color.Black)
|
||||
win, _, err := bubbleadapter.Window(Width, Height, fonts, newModel(), color.Black)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
win, err := bubbleadapter.Window(Width, Height, fonts, newModel(), color.Black)
|
||||
win, _, err := bubbleadapter.Window(Width, Height, fonts, newModel(), color.Black)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -34,11 +34,14 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
win, err := bubbleadapter.Window(Width, Height, fonts, model{}, color.Black, tea.WithAltScreen())
|
||||
win, prog, err := bubbleadapter.Window(Width, Height, fonts, model{}, color.Black, tea.WithAltScreen())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prog.Send(tea.ShowCursor())
|
||||
win.SetCursorChar("_")
|
||||
|
||||
if err := win.Run("Simple"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user