textarea.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package UI
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/veandco/go-sdl2/sdl"
  6. "github.com/veandco/go-sdl2/ttf"
  7. "github.com/cuu/gogame/color"
  8. "github.com/cuu/gogame/draw"
  9. "github.com/cuu/gogame/font"
  10. "github.com/cuu/gogame/rect"
  11. "github.com/cuu/gogame/surface"
  12. )
  13. type Textarea struct {
  14. Widget
  15. BackgroundColor *color.Color
  16. CanvasHWND *sdl.Surface
  17. MyWords []string
  18. BlitWords []string
  19. FontObj *ttf.Font
  20. LineNumber int
  21. TextLimit int
  22. TextFull bool
  23. TextIndex int
  24. BlitIndex int
  25. }
  26. func NewTextarea() *Textarea {
  27. p := &Textarea{}
  28. p.TextLimit = 63
  29. p.TextFull = false
  30. p.MyWords = make([]string, 0)
  31. p.BlitWords = make([]string, 0)
  32. p.BackgroundColor = &color.Color{228, 228, 228, 255}
  33. return p
  34. }
  35. func (self *Textarea) Init() {
  36. self.FontObj = Fonts["veramono24"]
  37. }
  38. func (self *Textarea) SubTextIndex() {
  39. self.TextIndex -= 1
  40. if self.TextIndex < 0 {
  41. self.TextIndex = 0
  42. }
  43. }
  44. func (self *Textarea) AddTextIndex() {
  45. self.TextIndex += 1
  46. if self.TextIndex > len(self.MyWords) {
  47. self.TextIndex = len(self.MyWords)
  48. }
  49. }
  50. func (self *Textarea) ResetMyWords() {
  51. self.MyWords = nil
  52. self.TextIndex = 0
  53. }
  54. func (self *Textarea) RemoveFromLastText() []string {
  55. if len(self.MyWords) > 0 {
  56. self.SubTextIndex()
  57. if self.TextIndex < len(self.MyWords) {
  58. self.MyWords = append(self.MyWords[:self.TextIndex], self.MyWords[(self.TextIndex+1):]...)
  59. }
  60. }
  61. return self.MyWords
  62. }
  63. func (self *Textarea) AppendText(alphabet string) {
  64. self.AppendAndBlitText(alphabet)
  65. }
  66. func (self *Textarea) AppendAndBlitText(alphabet string) {
  67. if self.TextFull == false {
  68. if self.TextIndex <= len(self.MyWords) {
  69. self.MyWords = append(self.MyWords[:self.TextIndex],
  70. append([]string{alphabet}, self.MyWords[self.TextIndex:]...)...)
  71. self.BlitText()
  72. self.AddTextIndex()
  73. }
  74. } else {
  75. fmt.Printf("is Full %s\n", strings.Join(self.MyWords, ""))
  76. }
  77. }
  78. func (self *Textarea) BuildBlitText() {
  79. blit_rows := make([][]string, 0)
  80. blit_rows = append(blit_rows, []string{})
  81. w := 0
  82. // xmargin := 5
  83. endmargin := 15
  84. linenumber := 0
  85. cursor_row := 0
  86. for i, v := range self.MyWords {
  87. t := font.Render(self.FontObj, v, true, &color.Color{8, 135, 174, 255}, nil)
  88. t_width := surface.GetWidth(t)
  89. w += t_width
  90. blit_rows[linenumber] = append(blit_rows[linenumber], v)
  91. if i == self.TextIndex-1 {
  92. cursor_row = linenumber
  93. }
  94. if w+t_width >= self.Width-endmargin {
  95. w = 0
  96. linenumber += 1
  97. blit_rows = append(blit_rows, []string{})
  98. }
  99. t.Free()
  100. }
  101. if len(blit_rows) == 1 {
  102. self.BlitWords = blit_rows[0]
  103. self.BlitIndex = self.TextIndex
  104. } else if len(blit_rows) == 2 || cursor_row < 2 {
  105. self.BlitWords = append(blit_rows[0], blit_rows[1]...)
  106. self.BlitIndex = self.TextIndex
  107. } else {
  108. self.BlitWords = append(blit_rows[cursor_row-1], blit_rows[cursor_row]...)
  109. self.BlitIndex = self.TextIndex
  110. for i, v := range blit_rows {
  111. if i == cursor_row-1 {
  112. break
  113. }
  114. self.BlitIndex -= len(v)
  115. }
  116. }
  117. }
  118. func (self *Textarea) BlitText() {
  119. //blit every single word into surface and calc the width ,check multi line
  120. self.BuildBlitText()
  121. w := 0
  122. xmargin := 5
  123. endmargin := 15
  124. x := self.PosX + xmargin
  125. y := self.PosY
  126. linenumber := 0
  127. if len(self.MyWords) > self.TextLimit {
  128. self.TextFull = true
  129. } else {
  130. self.TextFull = false
  131. }
  132. for _, v := range self.BlitWords {
  133. t := font.Render(self.FontObj, v, true, &color.Color{8, 135, 174, 255}, nil)
  134. w += surface.GetWidth(t)
  135. if w >= self.Width-endmargin && linenumber == 0 {
  136. linenumber += 1
  137. x = self.PosX + xmargin
  138. y = self.PosY + surface.GetHeight(t)*linenumber
  139. w = 0
  140. }
  141. rect_ := rect.Rect(x, y, 0, 0)
  142. surface.Blit(self.CanvasHWND, t, &rect_, nil)
  143. x += surface.GetWidth(t)
  144. t.Free()
  145. }
  146. }
  147. func (self *Textarea) Cursor() {
  148. w := 0
  149. xmargin := 5
  150. endmargin := 15
  151. x := self.PosX + xmargin
  152. y := self.PosY
  153. linenumber := 0
  154. for _, v := range self.BlitWords[:self.BlitIndex] {
  155. t := font.Render(self.FontObj, v, true, &color.Color{8, 135, 174, 255}, nil)
  156. w += surface.GetWidth(t)
  157. if w >= self.Width-endmargin && linenumber == 0 {
  158. x = self.PosX + xmargin
  159. y = self.PosY + surface.GetHeight(t)
  160. w = 0
  161. linenumber += 1
  162. }
  163. if w >= self.Width-endmargin*3 && linenumber > 0 {
  164. x += surface.GetWidth(t)
  165. break
  166. }
  167. x += surface.GetWidth(t)
  168. t.Free()
  169. }
  170. c_t := font.Render(self.FontObj, "_", true, &color.Color{0, 0, 0, 255}, nil)
  171. rect_ := rect.Rect(x+1, y-2, 0, 0)
  172. surface.Blit(self.CanvasHWND, c_t, &rect_, nil)
  173. c_t.Free()
  174. }
  175. func (self *Textarea) Draw() {
  176. rect_ := rect.Rect(self.PosX, self.PosY, self.Width, self.Height)
  177. draw.AARoundRect(self.CanvasHWND, &rect_, self.BackgroundColor, 4, 0, self.BackgroundColor)
  178. self.BlitText()
  179. self.Cursor()
  180. }