Support for solid (non-gradient) fills too

This commit is contained in:
Christian Rocha 2020-11-18 17:47:58 -05:00 committed by Christian Rocha
parent 1e16eca939
commit 0f06d78b92

View File

@ -15,6 +15,7 @@ var color func(string) termenv.Color = termenv.ColorProfile().Color
// //
// progress := NewModel( // progress := NewModel(
// WithRamp("#ff0000", "#0000ff"), // WithRamp("#ff0000", "#0000ff"),
// WithoutPercentage(),
// ) // )
type Option func(*Model) type Option func(*Model)
@ -29,35 +30,51 @@ func WithRamp(colorA, colorB string) Option {
b, _ := colorful.Hex(colorB) b, _ := colorful.Hex(colorB)
return func(m *Model) { return func(m *Model) {
m.useRamp = true m.useRamp = true
m.colorA = a m.rampColorA = a
m.colorB = b m.rampColorB = b
}
}
// WithScaledRamp scales the gradient to fit the width of the filled portion of
// the progress bar.
func WithScaledRamp() Option {
return func(m *Model) {
m.scaleRamp = true
}
}
// WithoutPercentage hides the numeric percentage.
func WithoutPercentage() Option {
return func(m *Model) {
m.ShowPercentage = false
} }
} }
type Model struct { type Model struct {
// Left side color of progress bar. By default, it's #00dbde
colorA colorful.Color
// Left side color of progress bar. By default, it's #fc00ff
colorB colorful.Color
// Total width of the progress bar, including percentage, if set. // Total width of the progress bar, including percentage, if set.
Width int Width int
// Rune for "filled" sections of the progress bar. // "Filled" sections of the progress bar
Full rune Full rune
FullColor string
// Rune for "empty" sections of progress bar. // "Empty" sections of progress bar
Empty rune Empty rune
EmptyColor string
// if true, gradient will be setted from start to end of filled part. Instead, it'll work // Settings for rendering the numeric percentage
// on all proggress bar length ShowPercentage bool
FullGradientMode bool PercentFormat string // a fmt string for a float
ShowPercent bool
PercentFormat string
useRamp bool useRamp bool
rampColorA colorful.Color
rampColorB colorful.Color
// When true, we scale the gradient to fit the width of the filled section
// of the progress bar. When false, the width of the gradient will be set
// to the full width of the progress bar.
scaleRamp bool
} }
// NewModel returns a model with default values. // NewModel returns a model with default values.
@ -65,8 +82,10 @@ func NewModel(opts ...Option) *Model {
m := &Model{ m := &Model{
Width: 40, Width: 40,
Full: '█', Full: '█',
FullColor: "#7571F9",
Empty: '░', Empty: '░',
ShowPercent: true, EmptyColor: "#606060",
ShowPercentage: true,
PercentFormat: " %3.0f%%", PercentFormat: " %3.0f%%",
} }
@ -78,7 +97,7 @@ func NewModel(opts ...Option) *Model {
} }
func (m Model) View(percent float64) string { func (m Model) View(percent float64) string {
if m.ShowPercent { if m.ShowPercentage {
s := fmt.Sprintf(m.PercentFormat, percent*100) s := fmt.Sprintf(m.PercentFormat, percent*100)
w := ansi.PrintableRuneWidth(s) w := ansi.PrintableRuneWidth(s)
return m.bar(percent, w) + s return m.bar(percent, w) + s
@ -87,24 +106,37 @@ func (m Model) View(percent float64) string {
} }
func (m Model) bar(percent float64, textWidth int) string { func (m Model) bar(percent float64, textWidth int) string {
w := m.Width - textWidth var (
b = strings.Builder{}
tw = m.Width - textWidth // total width
fw = int(float64(tw) * percent) // filled width
p float64
)
ramp := make([]string, int(float64(w)*percent)) if m.useRamp {
for i := 0; i < len(ramp); i++ { // Gradient fill
gradientPart := float64(w) for i := 0; i < fw; i++ {
if m.FullGradientMode { if m.scaleRamp {
gradientPart = float64(len(ramp)) p = float64(i) / float64(fw)
} else {
p = float64(i) / float64(tw)
} }
percent := float64(i) / gradientPart c := m.rampColorA.BlendLuv(m.rampColorB, p).Hex()
c := m.colorA.BlendLuv(m.colorB, percent) b.WriteString(termenv.
ramp[i] = c.Hex() String(string(m.Full)).
Foreground(color(c)).
String(),
)
}
} else {
// Solid fill
s := termenv.String(string(m.Full)).Foreground(color(m.FullColor)).String()
b.WriteString(strings.Repeat(s, fw))
} }
var fullCells string // Empty fill
for i := 0; i < len(ramp); i++ { e := termenv.String(string(m.Empty)).Foreground(color(m.EmptyColor)).String()
fullCells += termenv.String(string(m.Full)).Foreground(color(ramp[i])).String() b.WriteString(strings.Repeat(e, tw-fw))
}
fullCells += strings.Repeat(string(m.Empty), w-len(ramp)) return b.String()
return fullCells
} }