Add spinner widget.

Signed-off-by: Andreas Krennmair <ak@synflood.at>
This commit is contained in:
Andreas Krennmair 2022-10-23 15:03:17 +02:00
parent 02e3c8f9d9
commit f1d2fee386
5 changed files with 170 additions and 0 deletions

View File

@ -56,3 +56,4 @@ func main() {
* percentage mode gauge
* utilisation mode gauge
* message dialog (info and error)
* spinner

1
demos/spinner/README.md Normal file
View File

@ -0,0 +1 @@
![Screenshot](screenshot.png)

67
demos/spinner/main.go Normal file
View File

@ -0,0 +1,67 @@
package main
import (
"time"
"github.com/navidys/tvxwidgets"
"github.com/rivo/tview"
)
func main() {
app := tview.NewApplication()
grid := tview.NewGrid()
grid.SetBorder(true).SetTitle("Spinners")
spinners := [][]*tvxwidgets.Spinner{
{
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerDotsCircling),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerDotsUpDown),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerBounce),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerLine),
},
{
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCircleQuarters),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerSquareCorners),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCircleHalves),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerCorners),
},
{
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerArrows),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerHamburger),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerStack),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerStar),
},
{
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerGrowHorizontal),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerGrowVertical),
tvxwidgets.NewSpinner().SetStyle(tvxwidgets.SpinnerBoxBounce),
tvxwidgets.NewSpinner().SetCustomStyle([]rune{'🕛', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚'}),
},
}
for rowIdx, row := range spinners {
for colIdx, spinner := range row {
grid.AddItem(spinner, rowIdx, colIdx, 1, 1, 1, 1, false)
}
}
update := func() {
tick := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-tick.C:
for _, row := range spinners {
for _, spinner := range row {
spinner.Pulse()
}
}
app.Draw()
}
}
}
go update()
if err := app.SetRoot(grid, false).EnableMouse(true).Run(); err != nil {
panic(err)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

101
spinner.go Normal file
View File

@ -0,0 +1,101 @@
package tvxwidgets
import (
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
// Spinner represents a spinner widget
type Spinner struct {
*tview.Box
counter int
currentStyle SpinnerStyle
styles map[SpinnerStyle][]rune
}
type SpinnerStyle int
const (
SpinnerDotsCircling SpinnerStyle = iota
SpinnerDotsUpDown
SpinnerBounce
SpinnerLine
SpinnerCircleQuarters
SpinnerSquareCorners
SpinnerCircleHalves
SpinnerCorners
SpinnerArrows
SpinnerHamburger
SpinnerStack
SpinnerGrowHorizontal
SpinnerGrowVertical
SpinnerStar
SpinnerBoxBounce
spinnerCustom // non-public constant to indicate that a custom style has been set by the user.
)
// NewSpinner returns a new spinner widget.
func NewSpinner() *Spinner {
return &Spinner{
Box: tview.NewBox(),
currentStyle: SpinnerDotsCircling,
styles: map[SpinnerStyle][]rune{
SpinnerDotsCircling: []rune(`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`),
SpinnerDotsUpDown: []rune(`⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓`),
SpinnerBounce: []rune(`⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆`),
SpinnerLine: []rune(`|/-\`),
SpinnerCircleQuarters: []rune(`◴◷◶◵`),
SpinnerSquareCorners: []rune(`◰◳◲◱`),
SpinnerCircleHalves: []rune(`◐◓◑◒`),
SpinnerCorners: []rune(`⌜⌝⌟⌞`),
SpinnerArrows: []rune(`⇑⇗⇒⇘⇓⇙⇐⇖`),
SpinnerHamburger: []rune(`☰☱☳☷☶☴`),
SpinnerStack: []rune(`䷀䷪䷡䷊䷒䷗䷁䷖䷓䷋䷠䷫`),
SpinnerGrowHorizontal: []rune(`▉▊▋▌▍▎▏▎▍▌▋▊▉`),
SpinnerGrowVertical: []rune(`▁▃▄▅▆▇▆▅▄▃`),
SpinnerStar: []rune(`✶✸✹✺✹✷`),
SpinnerBoxBounce: []rune(`▌▀▐▄`),
},
}
}
// Draw draws this primitive onto the screen.
func (s *Spinner) Draw(screen tcell.Screen) {
s.Box.DrawForSubclass(screen, s)
x, y, width, _ := s.Box.GetInnerRect()
tview.Print(screen, s.getCurrentFrame(), x, y, width, tview.AlignLeft, tcell.ColorDefault)
}
// Pulse updates the spinner to the next frame.
func (s *Spinner) Pulse() {
s.counter++
}
// Reset sets the frame counter to 0.
func (s *Spinner) Reset() {
s.counter = 0
}
// SetStyle sets the spinner style.
func (s *Spinner) SetStyle(style SpinnerStyle) *Spinner {
s.currentStyle = style
return s
}
func (s *Spinner) getCurrentFrame() string {
frames := s.styles[s.currentStyle]
if len(frames) == 0 {
return ""
}
return string(frames[s.counter%len(frames)])
}
// SetCustomStyle sets a list of runes as custom frames to show as the spinner.
func (s *Spinner) SetCustomStyle(frames []rune) *Spinner {
s.styles[spinnerCustom] = frames
s.currentStyle = spinnerCustom
return s
}