SergOmarov

forms

Sep 18th, 2015
76
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local gpu=require("component").gpu
  2. local isPrimary=require("component").isPrimary
  3. local event=require("event")
  4. local len=require("unicode").len
  5. local sub=require("unicode").sub
  6. local uchar=require("unicode").char
  7. local term=require("term")
  8. local pushSignal=require("computer").pushSignal
  9. local kbd  = require("component").keyboard
  10. local wrap = require("text").wrap
  11. local padRight=require("text").padRight
  12. local isControl= require("keyboard").isControl
  13.  
  14. local forms={}
  15. local mouseEv={touch=true, scroll=true, drag=true, drop=true}
  16. local activeForm
  17.  
  18. local TComponent={left=1,top=1, color=0, fontColor=0xffffff, border=0, visible=true, tag=0, type=function() return "unknown" end}
  19. TComponent.__index=TComponent
  20.  
  21. function TComponent:paint() end
  22.  
  23. function TComponent:isVisible()
  24.   if not self.visible then return false end
  25.   if self.parent then return self.parent:isVisible()
  26.   else return self==activeForm
  27.   end
  28. end
  29.  
  30. function TComponent:draw()
  31.   if self.parent then self.X=self.parent.X+self.left-1 self.Y=self.parent.Y+self.top-1
  32.   else self.X=self.left self.Y=self.top end
  33.   gpu.setBackground(self.color)
  34.   gpu.setForeground(self.fontColor)
  35.   local brd=nil
  36.   if self.border==1 then brd={"-","-","¬","L","¦","-"}
  37.   elseif self.border==2 then brd={"г","=","¬","L","¦","-"}
  38.   end
  39.   if brd then
  40.     gpu.set(self.X,self.Y, brd[1]..string.rep(brd[2],self.W-2)..brd[3])
  41.     for i=self.Y+1,self.Y+self.H-2 do
  42.       gpu.set(self.X,i, brd[5]..string.rep(" ",self.W-2)..brd[5])
  43.     end
  44.     gpu.set(self.X,self.Y+self.H-1, brd[4]..string.rep(brd[2],self.W-2)..brd[6])
  45.   else gpu.fill(self.X,self.Y,self.W,self.H," ") end
  46.   self:paint()
  47.   if self.elements then
  48.     for i=1,#self.elements do
  49.       if self.elements[i].visible then self.elements[i]:draw() end
  50.         end
  51.   end
  52. end
  53.  
  54. function TComponent:redraw() if self:isVisible() then self:draw() end end
  55.  
  56. function TComponent:makeChild(el)
  57.   if not self.elements then self.elements={} end
  58.   el.parent=self
  59.   table.insert(self.elements,el)
  60. end
  61.  
  62. function TComponent:mouseEv(ev,x,y,btn,user)
  63.   if self.elements then
  64.     for i=#self.elements,1,-1 do
  65.       local e=self.elements[i]
  66.           if e.visible and x>=e.X and x<e.X+e.W and y>=e.Y and y<e.Y+e.H then
  67.         e:mouseEv(ev,x,y,btn,user)
  68.         return
  69.       end
  70.     end
  71.   end  
  72.   if self[ev] then self[ev](self, x-self.X+1,y-self.Y+1,btn,user) end
  73. end
  74.  
  75. function TComponent:hide()
  76.   if self.visible then
  77.     self.visible=false
  78.         self.parent:draw()
  79.   end
  80. end
  81.  
  82. function TComponent:show()
  83.   if not self.visible then
  84.     self.visible=true
  85.         self.parent:draw()
  86.   end
  87. end
  88.  
  89. function TComponent:destruct()
  90.   if self.parent then
  91.     for i=1,#self.parent.elements do
  92.       if self.parent.elements[i]==self then table.remove(self.parent.elements,i) break end
  93.         end
  94.   end
  95. end
  96.  
  97. ------------------Form------------------
  98. local TForm=setmetatable({type=function() return "Form" end},TComponent)
  99. TForm.__index=TForm
  100.  
  101. function TForm:isActive() return self==activeForm end
  102.  
  103. function TForm:setActive()
  104.   if activeForm~=self then
  105.     activeForm=self
  106.     self:draw()
  107.   end  
  108. end
  109.  
  110. function forms.addForm()
  111.   local obj={}
  112.   TForm.W, TForm.H=gpu.getResolution()
  113.   return setmetatable(obj,TForm)
  114. end
  115.  
  116. ------------------Button----------------
  117. local TButton=setmetatable({W=10, H=1, color=0x606060, type=function() return "Button" end},TComponent)
  118. TButton.__index=TButton
  119.  
  120. function TButton:touch(x, y, btn, user)
  121.   if self.onClick and btn==0 then self:onClick(user) end
  122. end
  123.  
  124. function TButton:paint()
  125.   gpu.set(self.X+(self.W-len(self.caption))/2,self.Y+(self.H-1)/2, self.caption)
  126. end
  127.  
  128. function TComponent:addButton(left, top, caption, onClick)
  129.   local obj={left=left, top=top, caption=caption or "Button", onClick=onClick}
  130.   self:makeChild(obj)
  131.   return setmetatable(obj,TButton)
  132. end
  133.  
  134. ------------------Label-----------------
  135. local TLabel=setmetatable({H=1, centered=false, autoSize=true, type=function() return "Label" end} ,TComponent)
  136. TLabel.__index=TLabel
  137.  
  138. function TLabel:paint()
  139.  local line
  140.  local value=tostring(self.caption)
  141.  if self.autoSize then
  142.    self.W,self.H=0,0
  143.    for line in value:gmatch("([^\n]+)") do
  144.      self.H=self.H+1
  145.          if len(line)>self.W then self.W=len(line) end
  146.    end
  147.    if self.W<1 then self.W=1 end
  148.    if self.H<1 then self.H=1 end
  149.  end
  150.  for i=0,self.H-1 do
  151.   if not value then break end
  152.   line, value = wrap(value, self.W, self.W)
  153.   if self.centered then gpu.set(self.X+(self.W-len(line))/2,self.Y+i, line)
  154.   else gpu.set(self.X,self.Y+i, line) end
  155.  end
  156. end
  157.  
  158. function TComponent:addLabel(left, top, caption)
  159.   local obj={left=left, top=top, caption=caption or "Label"}
  160.   obj.W=len(obj.caption)
  161.   self:makeChild(obj)
  162.   return setmetatable(obj,TLabel)
  163. end
  164.  
  165. ------------------Edit------------------
  166. local TEdit=setmetatable({W=20, H=3, text="", border=1, type=function() return "Edit" end},TComponent)
  167. TEdit.__index=TEdit
  168.  
  169. function TEdit:paint()
  170.   if type(self.text)=="table" then
  171.     for i=1,self.H-2 do gpu.set(self.X+1,self.Y+i,sub(self.text[i] or "",1,self.W-2)) end
  172.   else gpu.set(self.X+1,self.Y+1, sub(self.text,1,self.W-2))
  173.   end
  174. end
  175.  
  176. local function editText(text,left,top,W,H)
  177. local running=true
  178. local scrollX, scrollY = 0, 0
  179. local posX, posY =1, 1
  180. local writeText
  181.  
  182. local function setCursor(nx,ny)
  183.   posX=nx or posX
  184.   posY=ny or posY
  185.   if #text<1 then text[1]="" end
  186.   if posY>#text then posY=#text end
  187.   if posY<1 then posY=1 end
  188.   if posX>len(text[posY])+1 then posX=len(text[posY])+1 end
  189.   if posX<1 then posX=1 end
  190.   local redraw=false
  191.   if posY<=scrollY then scrollY=posY-1 redraw=true end
  192.   if posY>scrollY+H then scrollY=posY-H redraw=true end
  193.   if posX<=scrollX then scrollX=posX-1 redraw=true end
  194.   if posX>scrollX+W then scrollX=posX-W redraw=true end
  195.   if redraw then writeText()
  196.   else term.setCursor(left+posX-scrollX-1, top+posY-scrollY-1) end
  197. end
  198.  
  199. local function writeLine(n)
  200.   gpu.set(left,top+n-scrollY-1,padRight(sub(text[n] or "",scrollX+1,scrollX+W),W))
  201. end
  202.  
  203. function writeText()
  204.   for i=1,H do writeLine(i+scrollY) end
  205.   setCursor()
  206. end
  207.  
  208. local function insert(value)
  209.   if not value or len(value) < 1 then return end
  210.   text[posY]=sub(text[posY],1,posX-1)..value..sub(text[posY],posX)
  211.   writeLine(posY)
  212.   setCursor(posX+len(value))
  213. end
  214.  
  215. local keys={}
  216. keys[203]=function()    -- Left
  217.   if posX>1 then setCursor(posX-1)
  218.   else if posY>1 then posY=posY-1 setCursor(len(text[posY])+1) end
  219.   end
  220. end
  221. keys[205]=function()   -- Right
  222.   if posX<=len(text[posY]) then setCursor(posX+1)
  223.   else if posY<#text then setCursor(1,posY+1) end
  224.   end
  225. end
  226. keys[199]=function() setCursor(1) end   -- Home
  227. keys[207]=function() setCursor(len(text[posY])+1) end   -- End
  228. keys[211]=function()    -- Del
  229.   if posX<=len(text[posY]) then
  230.     text[posY]=sub(text[posY],1,posX-1)..sub(text[posY],posX+1)
  231.     writeLine(posY)
  232.   else
  233.     if posY<#text then
  234.           text[posY]=text[posY]..text[posY+1]
  235.           table.remove(text,posY+1)
  236.           writeText()
  237.     end
  238.   end
  239. end
  240. keys[14] =function()    -- BackSp
  241.   if posX>1 then
  242.     text[posY]=sub(text[posY],1,posX-2)..sub(text[posY],posX)
  243.     writeLine(posY)
  244.     setCursor(posX-1)
  245.   else
  246.     if posY>1 then
  247.       posX,posY,text[posY-1]=len(text[posY-1])+1,posY-1,text[posY-1]..text[posY]
  248.           table.remove(text,posY+1)
  249.           writeText()
  250.     end
  251.   end
  252. end
  253. keys[15] =function() insert("  ") end   -- Tab
  254.  
  255. local function onKeyDown(char, code)
  256.   if keys[code] then keys[code]()
  257.   else if not isControl(char) then insert(uchar(char)) end
  258.   end
  259. end
  260.  
  261. local function onClipboard(value)
  262. end
  263.  
  264. local function onClick(x,y)
  265.   if x>=left and x<left+W and y>=top and y<top+H then
  266.     setCursor(x+scrollX-left+1,y+scrollY-top+1)
  267.   else running=false
  268.   end
  269. end
  270.  
  271. local function onScroll(direction)
  272. end
  273.  
  274. if type(text)=="table" then
  275.   keys[68] =function() running=false end   -- F10
  276.   keys[200]=function() setCursor(posX,posY-1) end   -- Up
  277.   keys[208]=function() setCursor(posX,posY+1) end   -- Down
  278.   keys[28] =function()   -- Enter
  279.     local n=len(text[posY]:match("^%s*"))
  280.     table.insert(text,posY+1,string.rep(" ",n)..sub(text[posY],posX))
  281.         text[posY]=sub(text[posY],1,posX-1)
  282.         posX,posY=n+1,posY+1
  283.         writeText()
  284.   end
  285. else
  286.   posX=len(text)+1
  287.   text={tostring(text)}
  288.   keys[28] =function() running=false end   -- Enter
  289. end
  290. term.setCursorBlink(true)
  291. writeText()
  292. while running do
  293.   local event, address, arg1, arg2, arg3 = event.pull()
  294.   if type(address) == "string" and isPrimary(address) then
  295.     term.setCursorBlink(false)
  296.     if event == "key_down" then onKeyDown(arg1, arg2)
  297.     elseif event == "clipboard" then onClipboard(arg1)
  298.     elseif event == "touch" or event == "drag" then onClick(arg1, arg2)
  299.     elseif event == "scroll" then onScroll(arg3)
  300.     end
  301.     term.setCursorBlink(true)
  302.   end
  303. end
  304. term.setCursorBlink(false)
  305. return text[1]
  306. end
  307.  
  308. function TEdit:touch(x, y, btn, user)
  309.   if btn==0 then
  310.     gpu.setBackground(self.color)
  311.     gpu.setForeground(self.fontColor)
  312.         if type(self.text)=="table" then editText(self.text,self.X+1,self.Y+1,self.W-2,self.H-2)
  313.         else self.text=editText(self.text,self.X+1,self.Y+1,self.W-2,1) end
  314.         self:draw()
  315.     if self.onEnter then self:onEnter(user) end
  316.   end
  317. end
  318.  
  319. function TComponent:addEdit(left, top, onEnter)
  320.   local obj={left=left, top=top, onEnter=onEnter}
  321.   self:makeChild(obj)
  322.   return setmetatable(obj,TEdit)
  323. end
  324.  
  325. ------------------Frame-----------------
  326. local TFrame=setmetatable({W=20, H=10, border=1, type=function() return "Frame" end},TComponent)
  327. TFrame.__index=TFrame
  328.  
  329. function TComponent:addFrame(left, top, border)
  330.   local obj={left=left, top=top, border=border}
  331.   self:makeChild(obj)
  332.   return setmetatable(obj,TFrame)
  333. end
  334.  
  335. ------------------List------------------
  336. local TList=setmetatable({W=20, H=10, selColor=0x0000ff, sfColor=0xffff00,
  337.   type=function() return "List" end},TComponent)
  338. TList.__index=TList
  339.  
  340. function TList:paint()
  341. gpu.setForeground(self.sfColor)
  342. gpu.setBackground(self.selColor)
  343. local items=self.items
  344. local y=self.top-1
  345. local x=self.left
  346. for i=1,#items do
  347. gpu.set(x,y+i,items[i].text)
  348.  
  349. end
  350. end
  351.  
  352. function TList:clear()
  353.   self.items={}
  354.   self:redraw()
  355. end
  356.  
  357. function TList:insert(pos,line,item)
  358. end
  359.  
  360. function TList:sort(comp)
  361. end
  362.  
  363. function TList:touch(x, y, btn, user)
  364. self:hide()
  365.     self.items[y].func()
  366. end
  367.  
  368. function TList:scroll(x, y, sh, user)
  369. end
  370.  
  371. function TComponent:addList(left, top, onChange)
  372.   local obj={left=left, top=top, lines={}, items={}, onChange=onChange}
  373.   self:makeChild(obj)
  374.   return setmetatable(obj,TList)
  375. end
  376. ----------------------------------------
  377. local work,Fc,Bc
  378.  
  379. function forms.run(form)
  380.   work, Fc, Bc = true, gpu.getForeground(), gpu.getBackground()
  381.   activeForm=form
  382.   activeForm:draw()
  383.   while work do
  384.     local ev,adr,x,y,btn,user=event.pull()
  385.     if mouseEv[ev] and adr==gpu.getScreen() then activeForm:mouseEv(ev,x,y,btn,user) end
  386.   end
  387. end
  388.  
  389. function forms.stop()
  390.   work=false
  391.   gpu.setForeground(Fc)
  392.   gpu.setBackground(Bc)
  393. end
  394.  
  395. function forms.pull(...)
  396.   local ev
  397.   while true do
  398.     ev={event.pull(...)}
  399.     if mouseEv[ev[1]] and ev[2]==gpu.getScreen() then activeForm:mouseEv(ev[1],ev[3],ev[4],ev[5],ev[6])
  400.         else  return unpack(ev)
  401.         end
  402.   end
  403. end
  404.  
  405. return forms
RAW Paste Data