panel.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. TitleColor string
  23. TitleOffset int
  24. }
  25. func (p *Panel) Range(withBorder bool) (sx, sy, ex, ey int) {
  26. sx = p.X
  27. sy = p.Y
  28. ex = p.X + p.Width
  29. ey = p.Y + len(p.Lines)
  30. if p.Style > 0 {
  31. if withBorder {
  32. ex += 2
  33. ey += 2
  34. } else {
  35. sx += 1
  36. sy += 1
  37. }
  38. }
  39. return
  40. }
  41. // Output the panel
  42. func (p *Panel) Output() string {
  43. var style int = int(p.Style)
  44. var box_style *BoxStyle
  45. var output string
  46. if style > 0 {
  47. box_style = &BOXES[style-1]
  48. }
  49. var row int = p.Y
  50. if style > 0 {
  51. // Top line / border
  52. output += Goto(p.X, row) + p.BorderColor + box_style.Top_Left
  53. if p.Title != "" {
  54. if p.TitleOffset+len(p.Title) > p.Width {
  55. log.Panicf("Panel (not wide enough) Width %d : Title size %d + offset %d = %d\n",
  56. p.Width, len(p.Title), p.TitleOffset, p.TitleOffset+len(p.Title))
  57. }
  58. output += strings.Repeat(box_style.Top, p.TitleOffset) + p.TitleColor + p.Title + p.BorderColor
  59. }
  60. output += strings.Repeat(box_style.Top, p.Width-(p.TitleOffset+len(p.Title))) + box_style.Top_Right
  61. row++
  62. }
  63. for _, line := range p.Lines {
  64. output += Goto(p.X, row)
  65. line.LineLength(&line.Text)
  66. var joined bool = false
  67. if style > 0 {
  68. top := box_style.Top
  69. if line.Text[0:len(top)] == top {
  70. // Yes, this line needs to be joined...
  71. output += p.BorderColor + box_style.Middle_Left + line.Output() + p.BorderColor + box_style.Middle_Right
  72. joined = true
  73. }
  74. }
  75. if !joined {
  76. if style > 0 {
  77. output += p.BorderColor + box_style.Side
  78. }
  79. output += line.Output()
  80. if style > 0 {
  81. output += p.BorderColor + box_style.Side
  82. }
  83. }
  84. row++
  85. }
  86. if style > 0 {
  87. // Bottom / border
  88. output += Goto(p.X, row) + p.BorderColor + box_style.Bottom_Left
  89. output += strings.Repeat(box_style.Top, p.Width) + box_style.Bottom_Right
  90. }
  91. return output
  92. }
  93. // Output anything that has updated
  94. func (p *Panel) Update() string {
  95. var output string
  96. var style int = int(p.Style)
  97. var row, col int
  98. row = p.Y
  99. col = p.X
  100. if style > 0 {
  101. row++
  102. col++
  103. }
  104. for idx := range p.Lines {
  105. if p.Lines[idx].Update() {
  106. // Yes, line was updated
  107. output += Goto(col, row) + p.Lines[idx].Output()
  108. }
  109. row++
  110. }
  111. return output
  112. }
  113. // Output the updated line
  114. func (p *Panel) UpdateLine(index int) string {
  115. var output string
  116. var style int = int(p.Style)
  117. p.Lines[index].Update()
  118. var row, col int
  119. row = p.Y + index
  120. col = p.X
  121. if style > 0 {
  122. row++
  123. col++
  124. }
  125. var line *Line = &p.Lines[index]
  126. output += Goto(col, row) + line.Output()
  127. return output
  128. }
  129. // Position Cursor at the "end" of the panel
  130. func (p *Panel) GotoEnd() string {
  131. var row, col int
  132. row = p.Y
  133. col = p.X
  134. if p.Style > 0 {
  135. row++
  136. col += 2
  137. }
  138. row += len(p.Lines)
  139. col += p.Width
  140. return Goto(col, row)
  141. }
  142. // Is the top line of this style a single line?
  143. func Single(bs BorderStyle) bool {
  144. switch bs {
  145. case SINGLE, SINGLE_DOUBLE:
  146. return true
  147. default:
  148. return false
  149. }
  150. }
  151. // Create a spacer line that will be connected maybe to the sides.
  152. func (p *Panel) Spacer() Line {
  153. var l Line = Line{}
  154. var pos int
  155. if Single(p.Style) {
  156. pos = 0
  157. } else {
  158. pos = 1
  159. }
  160. l.Text = strings.Repeat(BOXES[pos].Top, p.Width)
  161. return l
  162. }
  163. func (p *Panel) Center() {
  164. p.CenterX()
  165. p.CenterY()
  166. }
  167. func (p *Panel) CenterX() {
  168. p.X = (Width - p.Width) / 2
  169. }
  170. func (p *Panel) CenterY() {
  171. p.Y = (Height - len(p.Lines)) / 2
  172. }
  173. // Panel Clicked?
  174. // If onBorder == true, returns true, 0 for border click.
  175. // Otherwise true, line clicked on (starting with 1)/
  176. func (p *Panel) Clicked(m Mouse, onBorder bool) (bool, int) {
  177. var sx, sy, ex, ey = p.Range(onBorder)
  178. var mx = int(m.X)
  179. var my = int(m.Y)
  180. if (mx >= sx) && (mx <= ex) {
  181. if (my >= sy) && (my <= ey) {
  182. if onBorder {
  183. if my == sy || my == ey {
  184. return true, 0
  185. }
  186. return true, my - sy
  187. } else {
  188. return true, (my - sy) + 1
  189. }
  190. }
  191. }
  192. return false, 0
  193. }