Add ProgressBar widget

This commit is contained in:
Trevor Slocum 2020-01-16 16:53:51 -08:00
parent bb52b8e428
commit eff6577116
5 changed files with 245 additions and 0 deletions

View File

@ -1,3 +1,6 @@
v1.4.1 (WIP)
- Add ProgressBar widget
v1.4.0 (2020-01-16)
- Bump version to resolve issues with "go get"

View File

@ -39,6 +39,7 @@ func main() {
Form,
TextView1,
TextView2,
ProgressBar,
Table,
TreeView,
Flex,

View File

@ -0,0 +1,52 @@
package main
import (
"time"
"git.sr.ht/~tslocum/cview"
)
// ProgressBar demonstrates the ProgressBar.
func ProgressBar(nextSlide func()) (title string, content cview.Primitive) {
grid := cview.NewGrid().SetColumns(-1, 6, 4, 30, -1).SetRows(-1, 12, 4, 4, -1)
verticalProgressBar := cview.NewProgressBar()
verticalProgressBar.SetBorder(true)
verticalProgressBar.Vertical = true
horizontalProgressBar := cview.NewProgressBar()
horizontalProgressBar.SetBorder(true)
horizontalProgressBar.SetMax(150)
padding := cview.NewTextView()
grid.AddItem(padding, 0, 0, 1, 5, 0, 0, false)
grid.AddItem(padding, 1, 0, 1, 1, 0, 0, false)
grid.AddItem(verticalProgressBar, 1, 1, 2, 1, 0, 0, false)
grid.AddItem(padding, 1, 2, 1, 1, 0, 0, false)
grid.AddItem(padding, 2, 0, 1, 5, 0, 0, false)
grid.AddItem(horizontalProgressBar, 3, 3, 1, 1, 0, 0, false)
grid.AddItem(padding, 1, 4, 1, 1, 0, 0, false)
grid.AddItem(padding, 4, 0, 1, 5, 0, 0, false)
go func() {
t := time.NewTicker(100 * time.Millisecond)
for range t.C {
if verticalProgressBar.Complete() {
verticalProgressBar.SetProgress(0)
} else {
verticalProgressBar.AddProgress(1)
}
if horizontalProgressBar.Complete() {
horizontalProgressBar.SetProgress(0)
} else {
horizontalProgressBar.AddProgress(1)
}
// Queue draw
app.QueueUpdateDraw(func() {})
}
}()
return "ProgressBar", grid
}

56
demos/progressbar/main.go Normal file
View File

@ -0,0 +1,56 @@
// Demo code for the ProgressBar primitive.
package main
import (
"time"
"git.sr.ht/~tslocum/cview"
)
func main() {
app := cview.NewApplication()
grid := cview.NewGrid().SetColumns(-1, 6, 4, 30, -1).SetRows(-1, 12, 4, 4, -1)
verticalProgressBar := cview.NewProgressBar()
verticalProgressBar.SetBorder(true)
verticalProgressBar.Vertical = true
horizontalProgressBar := cview.NewProgressBar()
horizontalProgressBar.SetBorder(true)
horizontalProgressBar.SetMax(150)
padding := cview.NewTextView()
grid.AddItem(padding, 0, 0, 1, 5, 0, 0, false)
grid.AddItem(padding, 1, 0, 1, 1, 0, 0, false)
grid.AddItem(verticalProgressBar, 1, 1, 2, 1, 0, 0, false)
grid.AddItem(padding, 1, 2, 1, 1, 0, 0, false)
grid.AddItem(padding, 2, 0, 1, 5, 0, 0, false)
grid.AddItem(horizontalProgressBar, 3, 3, 1, 1, 0, 0, false)
grid.AddItem(padding, 1, 4, 1, 1, 0, 0, false)
grid.AddItem(padding, 4, 0, 1, 5, 0, 0, false)
go func() {
t := time.NewTicker(100 * time.Millisecond)
for range t.C {
if verticalProgressBar.Complete() {
verticalProgressBar.SetProgress(0)
} else {
verticalProgressBar.AddProgress(1)
}
if horizontalProgressBar.Complete() {
horizontalProgressBar.SetProgress(0)
} else {
horizontalProgressBar.AddProgress(1)
}
// Queue draw
app.QueueUpdateDraw(func() {})
}
}()
if err := app.SetRoot(grid, true).Run(); err != nil {
panic(err)
}
}

133
progressbar.go Normal file
View File

@ -0,0 +1,133 @@
package cview
import (
"math"
"sync"
"github.com/gdamore/tcell"
)
// ProgressBar indicates the progress of an operation.
type ProgressBar struct {
*Box
// Rune to use when rendering the empty area of the progress bar.
EmptyRune rune
// Color of the empty area of the progress bar.
EmptyColor tcell.Color
// Rune to use when rendering the filled area of the progress bar.
FilledRune rune
// Color of the filled area of the progress bar.
FilledColor tcell.Color
// If set to true, instead of filling from left to right, the bar is filled
// from bottom to top.
Vertical bool
max int
progress int
*sync.Mutex
}
// NewProgressBar returns a new progress bar.
func NewProgressBar() *ProgressBar {
return &ProgressBar{
Box: NewBox(),
EmptyRune: ' ',
EmptyColor: tcell.ColorDefault,
FilledRune: tcell.RuneBlock,
FilledColor: tcell.ColorDefault,
max: 100,
Mutex: new(sync.Mutex),
}
}
// SetMax sets the progress required to fill the bar.
func (p *ProgressBar) SetMax(max int) {
p.Lock()
defer p.Unlock()
p.max = max
}
// GetMax returns the progress required to fill the bar.
func (p *ProgressBar) GetMax() int {
p.Lock()
defer p.Unlock()
return p.max
}
// AddProgress adds to the current progress.
func (p *ProgressBar) AddProgress(progress int) {
p.Lock()
defer p.Unlock()
p.progress += progress
}
// SetProgress sets the current progress.
func (p *ProgressBar) SetProgress(progress int) {
p.Lock()
defer p.Unlock()
p.progress = progress
}
// GetProgress gets the current progress.
func (p *ProgressBar) GetProgress() int {
p.Lock()
defer p.Unlock()
return p.progress
}
// Complete returns whether the progress bar has been filled.
func (p *ProgressBar) Complete() bool {
p.Lock()
defer p.Unlock()
return p.progress >= p.max
}
// Draw draws this primitive onto the screen.
func (p *ProgressBar) Draw(screen tcell.Screen) {
p.Lock()
defer p.Unlock()
p.Box.Draw(screen)
x, y, width, height := p.GetInnerRect()
barSize := height
maxLength := width
if p.Vertical {
barSize = width
maxLength = height
}
barLength := int(math.RoundToEven(float64(maxLength) * (float64(p.progress) / float64(p.max))))
if barLength > maxLength {
barLength = maxLength
}
for i := 0; i < barSize; i++ {
for j := 0; j < barLength; j++ {
if p.Vertical {
screen.SetContent(x+i, y+(height-1-j), p.FilledRune, nil, tcell.StyleDefault.Foreground(p.FilledColor))
} else {
screen.SetContent(x+j, y+i, p.FilledRune, nil, tcell.StyleDefault.Foreground(p.FilledColor))
}
}
for j := barLength; j < maxLength; j++ {
if p.Vertical {
screen.SetContent(x+i, y+(height-1-j), p.EmptyRune, nil, tcell.StyleDefault.Foreground(p.EmptyColor))
} else {
screen.SetContent(x+j, y+i, p.EmptyRune, nil, tcell.StyleDefault.Foreground(p.EmptyColor))
}
}
}
}