textbuffer.lua 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. --This library is create for programming code editors in liko-12 more easly by using premade text buffer with horizental and vertical scrolling support--
  2. local lume = require("libraries.lume")
  3. local tb = _Class("liko12.textBuffer")
  4. local recalculate_x_after_scroll = function(self, is_repeat)
  5. if is_repeat then
  6. self.cursorX = self.lastCX
  7. else
  8. self.lastCX = self.cursorX
  9. end
  10. if self.cursorX > self.buffer[self.cursorY]:len()+1 then
  11. self.cursorX = self.buffer[self.cursorY]:len()+1
  12. end
  13. end
  14. --Args: grid x, grid Y, draw width in grid, draw height in grid, lines Limit, length Limit, min length, cursor color, blinktime--
  15. --0 blinktime disables cursor, 0 lines limit, 0 length disables all that..--
  16. --TODO: add real lines & length & mlength limits.--
  17. function tb:initialize(gx,gy,gw,gh,linel,lengthl,mlength,curcol,blinktime)
  18. self.gx, self.gy, self.linel, self.lenl, self.minl, self.curcol, self.blinktime = gx or 1, gy or 1, linel or 16, lengthl or 47, mlength or 0, curcol or 5, blinktime or 0.5
  19. self.gw, self.gh = gw or self.lenl, gh or self.linel
  20. self.buffer = {""} --Start with an empty line
  21. self.blinktimer = 0
  22. self.blinkstate = 0
  23. self.cursorX, self.cursorY = 1,1
  24. self.lastCX = 1 --Last cursor x when scrolling up or down
  25. self.shiftRight = 0
  26. self.shiftTop = 0
  27. self.keymap = {
  28. ["return"] = function(self,ir)
  29. self:shiftDown(self.cursorY+1)
  30. self.buffer[self.cursorY+1] = self.buffer[self.cursorY]:sub(self.cursorX,-1)
  31. self.buffer[self.cursorY] = self.buffer[self.cursorY]:sub(0,self.cursorX-1)
  32. self.cursorY = self.cursorY+1
  33. self.cursorX = 1
  34. end,
  35. ["backspace"] = function(self,ir)
  36. if self.cursorX == 1 then --If it's at the start of the line
  37. if self.buffer[self.cursorY-1] then
  38. self.cursorX = self.buffer[self.cursorY-1]:len()+1
  39. self.buffer[self.cursorY-1] = self.buffer[self.cursorY-1]..self.buffer[self.cursorY]
  40. self:shiftUp(self.cursorY+1)
  41. self.cursorY = self.cursorY-1
  42. end
  43. else
  44. self.buffer[self.cursorY] = self.buffer[self.cursorY]:sub(0,self.cursorX-2)..self.buffer[self.cursorY]:sub(self.cursorX,-1)
  45. self.cursorX = self.cursorX-1
  46. end
  47. end,
  48. ["delete"] = function(self,ir)
  49. if self.cursorX == self.buffer[self.cursorY]:len()+1 then --If it's at the end of the line
  50. if self.buffer[self.cursorY+1] then
  51. self.buffer[self.cursorY] = self.buffer[self.cursorY]..self.buffer[self.cursorY+1] --Copies next line
  52. self.buffer[self.cursorY+1] = "" --Deletes next line
  53. self:shiftUp(self.cursorY+2)
  54. self.cursorY = self.cursorY
  55. end
  56. else
  57. self.buffer[self.cursorY] = self.buffer[self.cursorY]:sub(0,self.cursorX-1)..self.buffer[self.cursorY]:sub(self.cursorX+1,self.buffer[self.cursorY]:len())
  58. self.cursorX = self.cursorX
  59. end
  60. end,
  61. ["left"] = function(self,ir)
  62. self.cursorX = self.cursorX-1
  63. if self.cursorX < 1 then
  64. if self.buffer[self.cursorY-1] then
  65. self.cursorX = self.buffer[self.cursorY-1]:len()+1
  66. self.keymap["up"](self,false)
  67. else
  68. self.cursorX = 1
  69. end
  70. end
  71. end,
  72. ["right"] = function(self,ir)
  73. self.cursorX = self.cursorX+1
  74. if self.cursorX > self.buffer[self.cursorY]:len()+1 then
  75. if self.buffer[self.cursorY+1] then
  76. self.cursorX = 1
  77. self.keymap["down"](self,false)
  78. else
  79. self.cursorX = self.buffer[self.cursorY]:len()+1
  80. end
  81. end
  82. end,
  83. ["up"] = function(self,ir)
  84. if self.buffer[self.cursorY-1] then
  85. self.cursorY = self.cursorY-1
  86. recalculate_x_after_scroll(self, ir)
  87. end
  88. end,
  89. ["down"] = function(self,ir)
  90. if self.buffer[self.cursorY+1] then
  91. self.cursorY = self.cursorY+1
  92. recalculate_x_after_scroll(self, ir)
  93. end
  94. end,
  95. ["home"] = function(self,ir)
  96. self.cursorX = 1
  97. end,
  98. ["end"] = function(self,ir)
  99. self.cursorX = self.buffer[self.cursorY]:len()+1
  100. end,
  101. ["pageup"] = function(self,is_repeat)
  102. self.cursorY = math.max(1, self.cursorY-self.gh)
  103. recalculate_x_after_scroll(self, is_repeat)
  104. end,
  105. ["pagedown"] = function(self,is_repeat)
  106. self.cursorY = math.min(#self.buffer, self.cursorY+self.gh)
  107. recalculate_x_after_scroll(self, is_repeat)
  108. end
  109. }
  110. self.keymap["kpenter"] = self.keymap["return"] --Add numpad enter key as the return key
  111. end
  112. function tb:_update(dt)
  113. if self.blinktime == 0 then return end
  114. self.blinktimer = self.blinktimer+dt if self.blinktimer > self.blinktime then self.blinktimer = self.blinktimer - self.blinktime self.blinkstate = not self.blinkstate end
  115. local curlen = self.buffer[self.cursorY]:len()
  116. if self.blinkstate then api.rect((self.cursorX-1-self.shiftRight)*4+2,(self.cursorY-self.shiftTop)*8+2,4,5,self.curcol) else self:_redraw() end
  117. end
  118. function tb:_redraw()
  119. local dbuff = self:getDrawBuffer()
  120. for line,text in ipairs(debuff) do
  121. api.print_grid(line,self.gx,self.gy)
  122. end
  123. end
  124. function tb:_tinput(t)
  125. self:forceBlink()
  126. --print(self.buffer[self.cursorY]:sub(0,self.cursorX-1)..t..self.buffer[self.cursorY]:sub(self.cursorX,-1))
  127. if self.lenl > 0 and self.buffer[self.cursorY]:len()-1 > self.lenl then return end
  128. self.buffer[self.cursorY] = self.buffer[self.cursorY]:sub(0,self.cursorX-1)..t..self.buffer[self.cursorY]:sub(self.cursorX,-1)
  129. self.cursorX = self.cursorX + t:len()
  130. self:_redraw()
  131. end
  132. --Returns a table containing the lines of code.
  133. function tb:getBuffer()
  134. return lume.clone(self.buffer)
  135. end
  136. --Returns a table of the lines to draw, and the gridx, gridy pos to draw on, how much letters toshift right.
  137. function tb:getLinesBuffer()
  138. self:fixShifts()
  139. local dbuff = {}
  140. for y=self.shiftTop+1,self.shiftTop+1+self.gh do
  141. if self.buffer[y] then
  142. table.insert(dbuff,self.buffer[y])
  143. end
  144. end
  145. return dbuff, self.gx, self.gy, self.shiftRight
  146. end
  147. --Returns a table of the visible text to draw, and the gridx, gridy pos to draw on.
  148. function tb:getDrawBuffer()
  149. self:fixShifts()
  150. local dbuff = {}
  151. for y=self.shiftTop+1,self.shiftTop+1+self.gh do
  152. if self.buffer[y] then
  153. table.insert(dbuff,self.buffer[y]:sub(self.shiftRight,self.shiftRight+self.gw))
  154. end
  155. end
  156. return dbuff, self.gx, self.gy
  157. end
  158. --Update the visible text offsets(shifts).
  159. function tb:fixShifts()
  160. if self.cursorX > self.shiftRight+self.gw then self.shiftRight = self.cursorX - self.gw end
  161. if self.cursorY > self.shiftTop+self.gh then self.shiftTop = self.cursorY - self.gh end
  162. if self.cursorX <= self.shiftRight then self.shiftRight = self.cursorX-1 end
  163. if self.cursorY <= self.shiftTop then self.shiftTop = self.cursorY-1 end
  164. self.shiftRight = api.floor(self.shiftRight)
  165. self.shiftTop = api.floor(self.shiftTop)
  166. end
  167. --Force the cursor to blink
  168. function tb:forceBlink() self.blinktimer, self.blinkstate = 0, true end
  169. --Shift the text down
  170. function tb:shiftDown(sline) --Note: the sline is shifted
  171. if sline > #self.buffer then table.insert(self.buffer,"") return end
  172. table.insert(self.buffer,"") -- Insert a new line
  173. for i=#self.buffer-1,sline,-1 do
  174. self.buffer[i+1] = self.buffer[i]
  175. end
  176. self.buffer[sline] = "" --Clear the start line
  177. return self
  178. end
  179. --Shift text up
  180. function tb:shiftUp(sline)
  181. if sline == 1 then return end
  182. for i=sline,#self.buffer do --Note: the sline is shifted
  183. self.buffer[i-1] = self.buffer[i]
  184. end
  185. table.remove(self.buffer,#self.buffer) --Remove the last line
  186. end
  187. return tb