123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- package door
- import (
- "bytes"
- "fmt"
- "strings"
- )
- // TODO: Break out the progress bar characters into structures.
- // Write tests to verify that CP437 matches Unicode.
- // See box_test. ;)
- type BarStyle int8
- const (
- SOLID BarStyle = iota
- HALF_STEP
- GRADIENT
- )
- type Percent_Style int8
- const (
- PERCENT_NONE Percent_Style = iota
- PERCENT
- PERCENT_SPACE
- )
- type BarRange struct {
- Percent int64
- Color []byte
- }
- type BarLine struct {
- Width int
- Style BarStyle
- Percent int64 // percentage * 100
- PercentStyle Percent_Style
- ColorRange []BarRange
- UpdateP func() int64
- Line
- }
- type BarCharacters struct {
- Solid string
- Half [2]string
- Gradient [4]string
- }
- var BARS_CP437 = BarCharacters{
- "\xdb",
- [2]string{"\xdb", "\xdd"},
- [4]string{"\xdb", "\xb0", "\xb1", "\xb2"},
- }
- var BARS_UNICODE = BarCharacters{
- "\u2588",
- [2]string{"\u2588", "\u258c"},
- [4]string{"\u2588", "\u2591", "\u2592", "\u2593"},
- }
- var BARS *BarCharacters = &BARS_CP437
- func (bl *BarLine) CheckRange() {
- if len(bl.ColorRange) != 0 {
- // Ok, there is a color range. Get checking
- for _, br := range bl.ColorRange {
- if bl.Percent <= br.Percent {
- bl.DefaultColor = br.Color
- break
- }
- }
- }
- }
- func (bl *BarLine) Output() []byte {
- // bl.Text & bl.render & bl.update
- if bl.render == nil {
- bl.render = &bytes.Buffer{}
- }
- bl.render.Reset()
- var step_width int64
- if bl.UpdateP != nil {
- bl.Percent = bl.UpdateP()
- }
- bl.CheckRange()
- // CheckRange can change the DefaultColor.
- bl.render.Write(bl.DefaultColor)
- if bl.update == nil {
- bl.update = &bytes.Buffer{}
- }
- bl.update.Reset()
- switch bl.Style {
- case SOLID:
- step_width = int64(100 * 100 / bl.Width)
- var steps int = int(bl.Percent / step_width)
- bl.update.WriteString(strings.Repeat(BARS.Solid, steps))
- // This will work, because we aren't trying to len(output) with unicode.
- bl.update.WriteString(strings.Repeat(" ", int(bl.Width-steps)))
- case HALF_STEP:
- step_width = int64(100 * 100 / bl.Width)
- var steps int = int(bl.Percent * 2 / step_width)
- bl.update.WriteString(strings.Repeat(BARS.Half[0], steps/2))
- if steps%2 == 1 {
- bl.update.WriteString(BARS.Half[1])
- steps++
- }
- bl.update.WriteString(strings.Repeat(" ", bl.Width-(steps/2)))
- case GRADIENT:
- step_width = int64(100 * 100 / bl.Width)
- var steps int = int(bl.Percent * 4 / step_width)
- bl.update.WriteString(strings.Repeat(BARS.Gradient[0], steps/4))
- if steps%4 != 0 {
- switch steps % 4 {
- case 1, 2, 3:
- bl.update.WriteString(BARS.Gradient[steps%4])
- }
- for steps%4 != 0 {
- steps++
- }
- }
- bl.update.WriteString(strings.Repeat(" ", bl.Width-(steps/4)))
- }
- if bl.PercentStyle != PERCENT_NONE {
- var pctbuff [10]byte
- var percent = pctbuff[0:0]
- percent = fmt.Appendf(percent, "%d", bl.Percent/100)
- var pos int = bl.Width/2 - 1
- if bytes.Compare(percent, []byte("100")) != 0 {
- percent = append(percent, '%')
- if len(percent) < 3 {
- percent = append(percent, ' ')
- copy(percent[1:], percent[0:])
- percent[0] = ' '
- // percent = " " + percent
- }
- }
- if bl.PercentStyle == PERCENT_SPACE {
- percent = append(percent, ' ')
- copy(percent[1:], percent[0:])
- percent = append(percent, ' ')
- percent[0] = ' '
- // percent = " " + percent + " "
- pos--
- }
- // to process/slice the string (with unicode) do this:
- // convert to []rune, slice that, convert back to string
- //
- // sliceable := []rune(output)
- // newString := string(sliceable[:5]) + " new content " + (sliceable[10:])
- // fmt.Printf("%d %d [%s] %d [%s]\n", bl.Width, pos, percent, len(output), output)
- // The % part -- isn't working at the moment.
- // I need to insert the percent into the buffer. (but how)?
- // and unicode? hmm!
- // Note: This takes ownership of update.
- bl.Text = bytes.NewBuffer(bl.update.Bytes())
- var idx int = 0
- if Unicode {
- for {
- rune, _, err := bl.Text.ReadRune()
- if err != nil {
- break
- }
- if (idx >= pos) && (idx < len(percent)+pos) {
- bl.render.WriteByte(percent[idx-pos])
- } else {
- bl.render.WriteRune(rune)
- }
- idx++
- }
- /*
- runes := []rune(output)
- for idx, b := range percent {
- runes[pos+idx] = rune(b)
- }
- output = string(runes[:pos]) + percent + string(runes[pos+len(percent):])
- */
- } else {
- for {
- b, err := bl.Text.ReadByte()
- if err != nil {
- break
- }
- if (idx >= pos) && (idx < len(percent)+pos) {
- bl.render.WriteByte(percent[idx-pos])
- } else {
- bl.render.WriteByte(b)
- }
- idx++
- }
- /*
- for idx, b := range percent {
- render[pos+idx] = b
- }
- */
- // output = output[:pos] + percent + output[pos+len(percent):]
- }
- _ = idx
- } else {
- bl.render.Write(bl.update.Bytes())
- }
- // return bl.DefaultColor + output
- return bl.render.Bytes()
- }
|