234 lines
5.9 KiB
Go
234 lines
5.9 KiB
Go
package clui
|
|
|
|
import (
|
|
xs "github.com/huandu/xstrings"
|
|
term "github.com/nsf/termbox-go"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
/*
|
|
ProgressBar control visualizes the progression of extended operation.
|
|
|
|
The control has two sets of colors(almost all other controls have only
|
|
one set: foreground and background colors): for filled part and for
|
|
empty one. By default colors are the same.
|
|
*/
|
|
type ProgressBar struct {
|
|
BaseControl
|
|
direction Direction
|
|
min, max int
|
|
value int
|
|
emptyFg, emptyBg term.Attribute
|
|
titleFg term.Attribute
|
|
}
|
|
|
|
/*
|
|
NewProgressBar creates a new ProgressBar.
|
|
parent - is container that keeps the control.
|
|
width and heigth - are minimal size of the control.
|
|
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
|
|
control should keep its original size.
|
|
*/
|
|
func CreateProgressBar(parent Control, width, height int, scale int) *ProgressBar {
|
|
b := new(ProgressBar)
|
|
|
|
if height == AutoSize {
|
|
height = 1
|
|
}
|
|
if width == AutoSize {
|
|
width = 10
|
|
}
|
|
|
|
b.SetSize(width, height)
|
|
b.SetConstraints(width, height)
|
|
b.SetTabStop(false)
|
|
b.SetScale(scale)
|
|
b.min = 0
|
|
b.max = 10
|
|
b.direction = Horizontal
|
|
b.parent = parent
|
|
b.align = AlignCenter
|
|
|
|
if parent != nil {
|
|
parent.AddChild(b)
|
|
}
|
|
|
|
return b
|
|
}
|
|
|
|
// Repaint draws the control on its View surface.
|
|
// Horizontal ProgressBar supports custom title over the bar.
|
|
// One can set title using method SetTitle. There are a few
|
|
// predefined variables that can be used inside title to
|
|
// show value or total progress. Variable must be enclosed
|
|
// with double curly brackets. Available variables:
|
|
// percent - the current percentage rounded to closest integer
|
|
// value - raw ProgressBar value
|
|
// min - lower ProgressBar limit
|
|
// max - upper ProgressBar limit
|
|
// Examples:
|
|
// pb.SetTitle("{{value}} of {{max}}")
|
|
// pb.SetTitle("{{percent}}%")
|
|
func (b *ProgressBar) Draw() {
|
|
if b.max <= b.min {
|
|
return
|
|
}
|
|
|
|
PushAttributes()
|
|
defer PopAttributes()
|
|
|
|
fgOff, fgOn := RealColor(b.fg, ColorProgressText), RealColor(b.fgActive, ColorProgressActiveText)
|
|
bgOff, bgOn := RealColor(b.bg, ColorProgressBack), RealColor(b.bgActive, ColorProgressActiveBack)
|
|
|
|
parts := []rune(SysObject(ObjProgressBar))
|
|
cFilled, cEmpty := parts[0], parts[1]
|
|
|
|
prc := 0
|
|
if b.value >= b.max {
|
|
prc = 100
|
|
} else if b.value < b.max && b.value > b.min {
|
|
prc = (100 * (b.value - b.min)) / (b.max - b.min)
|
|
}
|
|
|
|
var title string
|
|
if b.direction == Horizontal && b.Title() != "" {
|
|
title = b.Title()
|
|
title = strings.Replace(title, "{{percent}}", strconv.Itoa(prc), -1)
|
|
title = strings.Replace(title, "{{value}}", strconv.Itoa(b.value), -1)
|
|
title = strings.Replace(title, "{{min}}", strconv.Itoa(b.min), -1)
|
|
title = strings.Replace(title, "{{max}}", strconv.Itoa(b.max), -1)
|
|
}
|
|
|
|
x, y := b.Pos()
|
|
w, h := b.Size()
|
|
|
|
if b.direction == Horizontal {
|
|
filled := prc * w / 100
|
|
sFilled := strings.Repeat(string(cFilled), filled)
|
|
sEmpty := strings.Repeat(string(cEmpty), w-filled)
|
|
|
|
for yy := y; yy < y+h; yy++ {
|
|
SetTextColor(fgOn)
|
|
SetBackColor(bgOn)
|
|
DrawRawText(x, yy, sFilled)
|
|
SetTextColor(fgOff)
|
|
SetBackColor(bgOff)
|
|
DrawRawText(x+filled, yy, sEmpty)
|
|
}
|
|
|
|
if title != "" {
|
|
shift, str := AlignText(title, w, b.align)
|
|
titleClr := RealColor(b.titleFg, ColorProgressTitleText)
|
|
var sOn, sOff string
|
|
if filled == 0 || shift >= filled {
|
|
sOff = str
|
|
} else if w == filled || shift+xs.Len(str) < filled {
|
|
sOn = str
|
|
} else {
|
|
r := filled - shift
|
|
sOn = xs.Slice(str, 0, r)
|
|
sOff = xs.Slice(str, r, -1)
|
|
}
|
|
SetTextColor(titleClr)
|
|
if sOn != "" {
|
|
SetBackColor(bgOn)
|
|
DrawRawText(x+shift, y, sOn)
|
|
}
|
|
if sOff != "" {
|
|
SetBackColor(bgOff)
|
|
DrawRawText(x+shift+xs.Len(sOn), y, sOff)
|
|
}
|
|
}
|
|
} else {
|
|
filled := prc * h / 100
|
|
sFilled := strings.Repeat(string(cFilled), w)
|
|
sEmpty := strings.Repeat(string(cEmpty), w)
|
|
for yy := y; yy < y+h-filled; yy++ {
|
|
SetTextColor(fgOff)
|
|
SetBackColor(bgOff)
|
|
DrawRawText(x, yy, sEmpty)
|
|
}
|
|
for yy := y + h - filled; yy < y+h; yy++ {
|
|
SetTextColor(fgOff)
|
|
SetBackColor(bgOff)
|
|
DrawRawText(x, yy, sFilled)
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------- own methods -------------------------
|
|
|
|
// SetValue sets new progress value. If value exceeds ProgressBar
|
|
// limits then the limit value is used
|
|
func (b *ProgressBar) SetValue(pos int) {
|
|
if pos < b.min {
|
|
b.value = b.min
|
|
} else if pos > b.max {
|
|
b.value = b.max
|
|
} else {
|
|
b.value = pos
|
|
}
|
|
}
|
|
|
|
// Value returns the current ProgressBar value
|
|
func (b *ProgressBar) Value() int {
|
|
return b.value
|
|
}
|
|
|
|
// Limits returns current minimal and maximal values of ProgressBar
|
|
func (b *ProgressBar) Limits() (int, int) {
|
|
return b.min, b.max
|
|
}
|
|
|
|
// SetLimits set new ProgressBar limits. The current value
|
|
// is adjusted if it exceeds new limits
|
|
func (b *ProgressBar) SetLimits(min, max int) {
|
|
b.min = min
|
|
b.max = max
|
|
|
|
if b.value < b.min {
|
|
b.value = min
|
|
}
|
|
if b.value > b.max {
|
|
b.value = max
|
|
}
|
|
}
|
|
|
|
// Step increases ProgressBar value by 1 if the value is less
|
|
// than ProgressBar high limit
|
|
func (b *ProgressBar) Step() int {
|
|
b.value++
|
|
|
|
if b.value > b.max {
|
|
b.value = b.max
|
|
}
|
|
|
|
return b.value
|
|
}
|
|
|
|
// SecondaryColors returns text and background colors for empty
|
|
// part of the ProgressBar
|
|
func (b *ProgressBar) SecondaryColors() (term.Attribute, term.Attribute) {
|
|
return b.emptyFg, b.emptyBg
|
|
}
|
|
|
|
// SetSecondaryColors sets new text and background colors for
|
|
// empty part of the ProgressBar
|
|
func (b *ProgressBar) SetSecondaryColors(fg, bg term.Attribute) {
|
|
b.emptyFg, b.emptyBg = fg, bg
|
|
}
|
|
|
|
// TitleColor returns text color of ProgressBar's title. Title
|
|
// background color always equals background color of the
|
|
// part of the ProgressBar on which it is displayed. In other
|
|
// words, background color of title is transparent
|
|
func (b *ProgressBar) TitleColor() term.Attribute {
|
|
return b.titleFg
|
|
}
|
|
|
|
// SetTitleColor sets text color of ProgressBar's title
|
|
func (b *ProgressBar) SetTitleColor(clr term.Attribute) {
|
|
b.titleFg = clr
|
|
}
|