panel.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package door
  2. import (
  3. "log"
  4. "strings"
  5. )
  6. type BorderStyle int
  7. const (
  8. NONE BorderStyle = iota
  9. SINGLE
  10. DOUBLE
  11. DOUBLE_SINGLE
  12. SINGLE_DOUBLE
  13. )
  14. type Panel struct {
  15. X int
  16. Y int
  17. Width int
  18. Style BorderStyle
  19. BorderColor string
  20. Lines []Line
  21. Title string
  22. TitleOffset int
  23. }
  24. // Output the panel
  25. func (p *Panel) Output() string {
  26. var style int = int(p.Style)
  27. var box_style *BoxStyle
  28. var output string
  29. if style > 0 {
  30. box_style = &BOXES[style-1]
  31. }
  32. row := p.Y
  33. if style > 0 {
  34. // Top line / border
  35. output += Goto(p.X, row) + p.BorderColor + box_style.top_left
  36. if p.Title != "" {
  37. if p.TitleOffset+len(p.Title) > p.Width {
  38. log.Panicf("Panel (not wide enough) Width %d : Title size %d + offset %d = %d\n",
  39. p.Width, len(p.Title), p.TitleOffset, p.TitleOffset+len(p.Title))
  40. }
  41. output += strings.Repeat(box_style.top, p.TitleOffset) + p.Title
  42. }
  43. output += strings.Repeat(box_style.top, p.Width-(p.TitleOffset+len(p.Title))) + box_style.top_right
  44. row++
  45. }
  46. for _, line := range p.Lines {
  47. output += Goto(p.X, row)
  48. var joined bool = false
  49. if style > 0 {
  50. top := box_style.top
  51. if line.Text[0:len(top)] == top {
  52. // Yes, this line needs to be joined...
  53. output += p.BorderColor + box_style.middle_left + line.Output() + p.BorderColor + box_style.middle_right
  54. joined = true
  55. }
  56. }
  57. if !joined {
  58. if style > 0 {
  59. output += p.BorderColor + box_style.side
  60. }
  61. output += line.Output()
  62. if style > 0 {
  63. output += p.BorderColor + box_style.side
  64. }
  65. }
  66. row++
  67. }
  68. if style > 0 {
  69. // Bottom / border
  70. output += Goto(p.X, row) + p.BorderColor + box_style.bottom_left
  71. output += strings.Repeat(box_style.top, p.Width) + box_style.bottom_right
  72. }
  73. return output
  74. }
  75. // Output anything that has updated
  76. func (p *Panel) Update() string {
  77. var output string
  78. var style int = int(p.Style)
  79. row := p.Y
  80. col := p.X
  81. if style > 0 {
  82. row++
  83. col++
  84. }
  85. for idx := range p.Lines {
  86. if p.Lines[idx].Update() {
  87. // Yes, line was updated
  88. output += Goto(col, row) + p.Lines[idx].Output()
  89. }
  90. row++
  91. }
  92. return output
  93. }
  94. // Output the updated line
  95. func (p *Panel) UpdateLine(index int) string {
  96. var output string
  97. var style int = int(p.Style)
  98. p.Lines[index].Update()
  99. row := p.Y + index
  100. col := p.X
  101. if style > 0 {
  102. row++
  103. col++
  104. }
  105. line := &p.Lines[index]
  106. output += Goto(col, row) + line.Output()
  107. return output
  108. }
  109. // Goto the end
  110. func (p *Panel) GotoEnd() string {
  111. row := p.Y
  112. col := p.X
  113. if p.Style > 0 {
  114. row++
  115. col += 2
  116. }
  117. row += len(p.Lines)
  118. col += p.Width
  119. return Goto(col, row)
  120. }
  121. // Is the top line of this style a single line?
  122. func Single(bs BorderStyle) bool {
  123. switch bs {
  124. case SINGLE, SINGLE_DOUBLE:
  125. return true
  126. default:
  127. return false
  128. }
  129. }
  130. // Create a spacer line that will be connected maybe to the sides.
  131. func (p *Panel) Spacer() Line {
  132. l := Line{}
  133. var pos int
  134. if Single(p.Style) {
  135. pos = 0
  136. } else {
  137. pos = 1
  138. }
  139. l.Text = strings.Repeat(BOXES[pos].top, p.Width)
  140. return l
  141. }