forked from Mirrors/bubbletea
Cmds for scrolling + handle renderer msgs in a renderer method
This commit is contained in:
parent
a492302609
commit
4dc6992767
169
renderer.go
169
renderer.go
|
@ -14,62 +14,6 @@ const (
|
||||||
defaultFramerate = time.Second / 60
|
defaultFramerate = time.Second / 60
|
||||||
)
|
)
|
||||||
|
|
||||||
// RendererIgnoreLinesMsg tells the renderer to skip rendering for the given
|
|
||||||
// range of lines.
|
|
||||||
type ignoreLinesMsg struct {
|
|
||||||
From int
|
|
||||||
To int
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoreLines produces command that sets a range of lines to be ignored
|
|
||||||
// by the renderer. The general use case here is that those lines would be
|
|
||||||
// rendered separately for performance reasons.
|
|
||||||
func IgnoreLines(from int, to int) Cmd {
|
|
||||||
return func() Msg {
|
|
||||||
return ignoreLinesMsg{From: from, To: to}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type resetIgnoreLinesMsg struct {
|
|
||||||
from int
|
|
||||||
to int
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetIngoredLines produces a command that clears any lines set to be ignored
|
|
||||||
// and the sets new ones by the renderer. This is probably a more common use
|
|
||||||
// case than the IgnoreLines command.
|
|
||||||
func ResetIgnoredLines(from int, to int) Cmd {
|
|
||||||
return func() Msg {
|
|
||||||
return resetIgnoreLinesMsg{from: from, to: to}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearIgnoredLinesMsg has the renderer allows the renderer to commence rendering
|
|
||||||
// any lines previously set to be ignored.
|
|
||||||
type clearIgnoredLinesMsg struct{}
|
|
||||||
|
|
||||||
// RendererIgnoreLines is a command that sets a range of lines to be
|
|
||||||
// ignored by the renderer.
|
|
||||||
func ClearIgnoredLines() Msg {
|
|
||||||
return clearIgnoredLinesMsg{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScrollDownMsg is experiemental. There are no guarantees about it persisting
|
|
||||||
// in a future API. It's exposed for high performance scrolling.
|
|
||||||
type ScrollUpMsg struct {
|
|
||||||
NewLines []string
|
|
||||||
TopBoundary int
|
|
||||||
BottomBoundary int
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScrollDownMsg is experiemental. There are no guarantees about it persisting
|
|
||||||
// in a future API. It's exposed for high performance scrolling.
|
|
||||||
type ScrollDownMsg struct {
|
|
||||||
NewLines []string
|
|
||||||
TopBoundary int
|
|
||||||
BottomBoundary int
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderer is a timer-based renderer, updating the view at a given framerate
|
// renderer is a timer-based renderer, updating the view at a given framerate
|
||||||
// to avoid overloading the terminal emulator.
|
// to avoid overloading the terminal emulator.
|
||||||
//
|
//
|
||||||
|
@ -239,6 +183,8 @@ func (r *renderer) clearIgnoredLines() {
|
||||||
// area designated to be a scrollable region, pushing everything else down.
|
// area designated to be a scrollable region, pushing everything else down.
|
||||||
// This is roughly how ncurses does it.
|
// This is roughly how ncurses does it.
|
||||||
//
|
//
|
||||||
|
// To call this function use command ScrollUp().
|
||||||
|
//
|
||||||
// For this to work renderer.ignoreLines must be set to ignore the scrollable
|
// For this to work renderer.ignoreLines must be set to ignore the scrollable
|
||||||
// region since we are bypassing the normal Bubble Tea renderer here.
|
// region since we are bypassing the normal Bubble Tea renderer here.
|
||||||
//
|
//
|
||||||
|
@ -272,11 +218,10 @@ func (r *renderer) insertTop(lines []string, topBoundary, bottomBoundary int) {
|
||||||
// a given area designated to be a scrollable region, pushing everything else
|
// a given area designated to be a scrollable region, pushing everything else
|
||||||
// up. This is roughly how ncurses does it.
|
// up. This is roughly how ncurses does it.
|
||||||
//
|
//
|
||||||
// For this to work renderer.ignoreLines must be set to ignore the scrollable
|
// To call this function use the command ScrollDown().
|
||||||
// region since we are bypassing the normal Bubble Tea renderer here.
|
|
||||||
//
|
//
|
||||||
// See note in insertTop() on how this function only makes sense for
|
// See note in insertTop() for caveats, how this function only makes sense for
|
||||||
// full-window applications and how it differs from the noraml way we do
|
// full-window applications, and how it differs from the noraml way we do
|
||||||
// rendering in Bubble Tea.
|
// rendering in Bubble Tea.
|
||||||
func (r *renderer) insertBottom(lines []string, topBoundary, bottomBoundary int) {
|
func (r *renderer) insertBottom(lines []string, topBoundary, bottomBoundary int) {
|
||||||
r.mtx.Lock()
|
r.mtx.Lock()
|
||||||
|
@ -293,3 +238,107 @@ func (r *renderer) insertBottom(lines []string, topBoundary, bottomBoundary int)
|
||||||
|
|
||||||
r.out.Write(b.Bytes())
|
r.out.Write(b.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleMessages handles internal messages for the renderer. It belongs in the
|
||||||
|
// main update loop at the program level.
|
||||||
|
func (r *renderer) handleMessages(msg Msg) {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case WindowSizeMsg:
|
||||||
|
r.width = msg.Width
|
||||||
|
r.height = msg.Height
|
||||||
|
|
||||||
|
case ignoreLinesMsg:
|
||||||
|
r.setIgnoredLines(msg.from, msg.to)
|
||||||
|
|
||||||
|
case replaceIgnoredLinesMsg:
|
||||||
|
r.clearIgnoredLines()
|
||||||
|
r.setIgnoredLines(msg.from, msg.to)
|
||||||
|
|
||||||
|
case clearIgnoredLinesMsg:
|
||||||
|
r.clearIgnoredLines()
|
||||||
|
|
||||||
|
case scrollUpMsg:
|
||||||
|
r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary)
|
||||||
|
|
||||||
|
case scrollDownMsg:
|
||||||
|
r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HIGH-PERFORMANCE RENDERING STUFF
|
||||||
|
|
||||||
|
// ignoreLinesMsg tells the renderer to skip rendering for the given
|
||||||
|
// range of lines.
|
||||||
|
type ignoreLinesMsg struct {
|
||||||
|
from int
|
||||||
|
to int
|
||||||
|
}
|
||||||
|
|
||||||
|
// IgnoreLines produces command that sets a range of lines to be ignored
|
||||||
|
// by the renderer. The general use case here is that those lines would be
|
||||||
|
// rendered separately for performance reasons.
|
||||||
|
func IgnoreLines(from int, to int) Cmd {
|
||||||
|
return func() Msg {
|
||||||
|
return ignoreLinesMsg{from: from, to: to}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type replaceIgnoredLinesMsg struct {
|
||||||
|
from int
|
||||||
|
to int
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplaceIngoredLines produces a command that clears any lines set to be ignored
|
||||||
|
// and the sets new ones by the renderer. This is probably a more common use
|
||||||
|
// case than the IgnoreLines command.
|
||||||
|
func ReplaceIgnoredLines(from int, to int) Cmd {
|
||||||
|
return func() Msg {
|
||||||
|
return replaceIgnoredLinesMsg{from: from, to: to}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearIgnoredLinesMsg has the renderer allows the renderer to commence rendering
|
||||||
|
// any lines previously set to be ignored.
|
||||||
|
type clearIgnoredLinesMsg struct{}
|
||||||
|
|
||||||
|
// RendererIgnoreLines is a command that sets a range of lines to be
|
||||||
|
// ignored by the renderer.
|
||||||
|
func ClearIgnoredLines() Msg {
|
||||||
|
return clearIgnoredLinesMsg{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollDownMsg is experiemental. There are no guarantees about it persisting
|
||||||
|
// in a future API. It's exposed for high performance scrolling.
|
||||||
|
type scrollUpMsg struct {
|
||||||
|
lines []string
|
||||||
|
topBoundary int
|
||||||
|
bottomBoundary int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScrollUp(newLines []string, topBoundary, bottomBoundary int) Cmd {
|
||||||
|
return func() Msg {
|
||||||
|
return scrollUpMsg{
|
||||||
|
lines: newLines,
|
||||||
|
topBoundary: topBoundary,
|
||||||
|
bottomBoundary: bottomBoundary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollDownMsg is experiemental. There are no guarantees about it persisting
|
||||||
|
// in a future API. It's exposed for high performance scrolling.
|
||||||
|
type scrollDownMsg struct {
|
||||||
|
lines []string
|
||||||
|
topBoundary int
|
||||||
|
bottomBoundary int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScrollDown(newLines []string, topBoundary, bottomBoundary int) Cmd {
|
||||||
|
return func() Msg {
|
||||||
|
return scrollDownMsg{
|
||||||
|
lines: newLines,
|
||||||
|
topBoundary: topBoundary,
|
||||||
|
bottomBoundary: bottomBoundary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
tea.go
28
tea.go
|
@ -171,32 +171,8 @@ func (p *Program) Start() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report resizes to the renderer. Only necessary for special,
|
// Process any internal messages for the renderer
|
||||||
// performance-based rendering.
|
mrRenderer.handleMessages(msg)
|
||||||
if size, ok := msg.(WindowSizeMsg); ok {
|
|
||||||
mrRenderer.width = size.Width
|
|
||||||
mrRenderer.height = size.Height
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle messages telling the main rendering routine to ignore
|
|
||||||
// ranges of lines. Useful for performance-based rendering.
|
|
||||||
if lineRange, ok := msg.(ignoreLinesMsg); ok {
|
|
||||||
mrRenderer.setIgnoredLines(lineRange.from, lineRange.to)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle messages telling the main rendering routine to clear
|
|
||||||
// ranges of lines previously ignored and set a new range of
|
|
||||||
// ignored lines. For use in high-performance rendering.
|
|
||||||
if lineRange, ok := msg.(resetIgnoreLinesMsg); ok {
|
|
||||||
mrRenderer.clearIgnoredLines()
|
|
||||||
mrRenderer.setIgnoredLines(lineRange.from, lineRange.to)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle messages telling the main rendering to stop ignoring
|
|
||||||
// lines. Useful when disabling any performance-based rendering.
|
|
||||||
if _, ok := msg.(clearIgnoredLinesMsg); ok {
|
|
||||||
mrRenderer.clearIgnoredLines()
|
|
||||||
}
|
|
||||||
|
|
||||||
model, cmd = p.update(msg, model) // run update
|
model, cmd = p.update(msg, model) // run update
|
||||||
cmds <- cmd // process command (if any)
|
cmds <- cmd // process command (if any)
|
||||||
|
|
Loading…
Reference in New Issue