bar.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package door
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // TODO: Break out the progress bar characters into stuctures.
  7. // Write tests to verify that CP437 matches Unicode.
  8. // See box_test. ;)
  9. type BarStyle int8
  10. const (
  11. SOLID BarStyle = iota
  12. HALF_STEP
  13. GRADIENT
  14. )
  15. type Percent_Style int8
  16. const (
  17. PERCENT_NONE Percent_Style = iota
  18. PERCENT
  19. PERCENT_SPACE
  20. )
  21. type BarRange struct {
  22. Percent int64
  23. Color string
  24. }
  25. type BarLine struct {
  26. Width int
  27. Style BarStyle
  28. Percent int64 // percentage * 100
  29. PercentStyle Percent_Style
  30. ColorRange []BarRange
  31. UpdateP func() int64
  32. Line
  33. }
  34. type BarCharacters struct {
  35. solid string
  36. half [2]string
  37. gradient [4]string
  38. }
  39. var BARS BarCharacters
  40. var BARS_CP437 = BarCharacters{
  41. "\xdb",
  42. [2]string{"\xdb", "\xdd"},
  43. [4]string{"\xdb", "\xb0", "\xb1", "\xb2"},
  44. }
  45. var BARS_UNICODE = BarCharacters{
  46. "\u2588",
  47. [2]string{"\u2588", "\u258c"},
  48. [4]string{"\u2588", "\u2591", "\u2592", "\u2593"},
  49. }
  50. func (bl *BarLine) CheckRange() {
  51. if len(bl.ColorRange) != 0 {
  52. // Ok, there is a color range. Get checking
  53. for _, br := range bl.ColorRange {
  54. if bl.Percent <= br.Percent {
  55. bl.DefaultColor = br.Color
  56. break
  57. }
  58. }
  59. }
  60. }
  61. func (bl *BarLine) Output() string {
  62. var output string
  63. var step_width int64
  64. if bl.UpdateP != nil {
  65. bl.Percent = bl.UpdateP()
  66. }
  67. bl.CheckRange()
  68. switch bl.Style {
  69. case SOLID:
  70. step_width = int64(100 * 100 / bl.Width)
  71. var steps int = int(bl.Percent / step_width)
  72. output += strings.Repeat(BARS.solid, steps)
  73. // This will work, because we aren't trying to len(output) with unicode.
  74. output += strings.Repeat(" ", int(bl.Width-steps))
  75. case HALF_STEP:
  76. step_width = int64(100 * 100 / bl.Width)
  77. var steps int = int(bl.Percent * 2 / step_width)
  78. output += strings.Repeat(BARS.half[0], steps/2)
  79. if steps%2 == 1 {
  80. output += BARS.half[1]
  81. steps++
  82. }
  83. output += strings.Repeat(" ", bl.Width-(steps/2))
  84. case GRADIENT:
  85. step_width = int64(100 * 100 / bl.Width)
  86. var steps int = int(bl.Percent * 4 / step_width)
  87. output += strings.Repeat(BARS.gradient[0], steps/4)
  88. if steps%4 != 0 {
  89. switch steps % 4 {
  90. case 1, 2, 3:
  91. output += BARS.gradient[steps%4]
  92. }
  93. for steps%4 != 0 {
  94. steps++
  95. }
  96. }
  97. output += strings.Repeat(" ", bl.Width-(steps/4))
  98. }
  99. if bl.PercentStyle != PERCENT_NONE {
  100. percent := fmt.Sprintf("%d", bl.Percent/100)
  101. var pos int = bl.Width/2 - 1
  102. if percent != "100" {
  103. percent += "%"
  104. if len(percent) < 3 {
  105. percent = " " + percent
  106. }
  107. }
  108. if bl.PercentStyle == PERCENT_SPACE {
  109. percent = " " + percent + " "
  110. pos--
  111. }
  112. // to process/slice the string (with unicode) do this:
  113. // convert to []rune, slice that, convert back to string
  114. //
  115. // sliceable := []rune(output)
  116. // newString := string(sliceable[:5]) + " new content " + (sliceable[10:])
  117. // fmt.Printf("%d %d [%s] %d [%s]\n", bl.Width, pos, percent, len(output), output)
  118. if Unicode {
  119. runes := []rune(output)
  120. output = string(runes[:pos]) + percent + string(runes[pos+len(percent):])
  121. } else {
  122. output = output[:pos] + percent + output[pos+len(percent):]
  123. }
  124. }
  125. return bl.DefaultColor + output
  126. }