Fix a bug where segment display text appears to be jumping.

This commit is contained in:
Jakub Sobon 2020-11-14 02:26:46 -05:00
parent df912f226b
commit b30352e642
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
1 changed files with 31 additions and 7 deletions

View File

@ -20,6 +20,7 @@ import (
"context" "context"
"flag" "flag"
"fmt" "fmt"
"image"
"log" "log"
"math" "math"
"math/rand" "math/rand"
@ -69,9 +70,9 @@ type widgets struct {
} }
// newWidgets creates all widgets used by this demo. // newWidgets creates all widgets used by this demo.
func newWidgets(ctx context.Context, c *container.Container) (*widgets, error) { func newWidgets(ctx context.Context, t terminalapi.Terminal, c *container.Container) (*widgets, error) {
updateText := make(chan string) updateText := make(chan string)
sd, err := newSegmentDisplay(ctx, updateText) sd, err := newSegmentDisplay(ctx, t, updateText)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -504,7 +505,7 @@ func main() {
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
w, err := newWidgets(ctx, c) w, err := newWidgets(ctx, t, c)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -562,7 +563,9 @@ func textState(text string, capacity, step int) []rune {
} }
state = append(state, []rune(text)...) state = append(state, []rune(text)...)
step = step % len(state) step = step % len(state)
return rotateRunes(state, step)
res := rotateRunes(state, step)
return res
} }
// newTextInput creates a new TextInput field that changes the text on the // newTextInput creates a new TextInput field that changes the text on the
@ -586,7 +589,7 @@ func newTextInput(updateText chan<- string) (*textinput.TextInput, error) {
// newSegmentDisplay creates a new SegmentDisplay that initially shows the // newSegmentDisplay creates a new SegmentDisplay that initially shows the
// Termdash name. Shows any text that is sent over the channel. // Termdash name. Shows any text that is sent over the channel.
func newSegmentDisplay(ctx context.Context, updateText <-chan string) (*segmentdisplay.SegmentDisplay, error) { func newSegmentDisplay(ctx context.Context, t terminalapi.Terminal, updateText <-chan string) (*segmentdisplay.SegmentDisplay, error) {
sd, err := segmentdisplay.New() sd, err := segmentdisplay.New()
if err != nil { if err != nil {
return nil, err return nil, err
@ -609,12 +612,33 @@ func newSegmentDisplay(ctx context.Context, updateText <-chan string) (*segmentd
go func() { go func() {
ticker := time.NewTicker(500 * time.Millisecond) ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop() defer ticker.Stop()
capacity := 0
termSize := t.Size()
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
state := textState(text, sd.Capacity(), step) if capacity == 0 {
// The segment display only knows its capacity after both
// text size and terminal size are known.
capacity = sd.Capacity()
}
if t.Size().Eq(image.ZP) || !t.Size().Eq(termSize) {
// Update the capacity initially the first time the
// terminal reports a non-zero size and then every time the
// terminal resizes.
//
// This is better than updating the capacity on every
// iteration since that leads to edge cases - segment
// display capacity depends on the length of text and here
// we are trying to adjust the text length to the capacity.
termSize = t.Size()
capacity = sd.Capacity()
}
state := textState(text, capacity, step)
var chunks []*segmentdisplay.TextChunk var chunks []*segmentdisplay.TextChunk
for i := 0; i < sd.Capacity(); i++ { for i := 0; i < capacity; i++ {
if i >= len(state) { if i >= len(state) {
break break
} }