daily pastebin goal
29%
SHARE
TWEET

forms

ZNZNCOOP Jul 29th, 2015 (edited) 1,842 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={"┌","─","┐","└","│","┘"}
  37.   elseif self.border==2 then brd={"╔","═","╗","╚","║","╝"}
  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 e.X 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.parent then
  77.     self.visible=false
  78.     self.parent:draw()
  79.   else
  80.     gpu.setBackground(0)
  81.     gpu.fill(self.X,self.Y,self.W,self.H," ")
  82.   end
  83. end
  84.  
  85. function TComponent:show()
  86.   if self.parent then
  87.     self.visible=true
  88.     self.parent:draw()
  89.   else
  90.     self:draw()
  91.   end
  92. end
  93.  
  94. function TComponent:destruct()
  95.   if self.parent then
  96.     for i=1,#self.parent.elements do
  97.       if self.parent.elements[i]==self then table.remove(self.parent.elements,i) break end
  98.     end
  99.   end
  100. end
  101.  
  102. function forms.activeForm() return activeForm end
  103.  
  104. ----------Визуальные компоненты---------
  105. ------------------Form------------------
  106. local TForm=setmetatable({type=function() return "Form" end},TComponent)
  107. TForm.__index=TForm
  108.  
  109. function TForm:isActive() return self==activeForm end
  110.  
  111. function TForm:setActive()
  112.   if activeForm~=self then
  113.     activeForm=self
  114.     self:show()
  115.   end  
  116. end
  117.  
  118. function forms.addForm()
  119.   local obj={}
  120.   TForm.W, TForm.H=gpu.getResolution()
  121.   return setmetatable(obj,TForm)
  122. end
  123.  
  124. ------------------Button----------------
  125. local TButton=setmetatable({W=10, H=1, color=0x606060, type=function() return "Button" end},TComponent)
  126. TButton.__index=TButton
  127.  
  128. function TButton:touch(x, y, btn, user)
  129.   if self.onClick and btn==0 then self:onClick(user) end
  130. end
  131.  
  132. function TButton:paint()
  133.   gpu.set(self.X+(self.W-len(self.caption))/2,self.Y+(self.H-1)/2, self.caption)
  134. end
  135.  
  136. function TComponent:addButton(left, top, caption, onClick)
  137.   local obj={left=left, top=top, caption=caption or "Button", onClick=onClick}
  138.   self:makeChild(obj)
  139.   return setmetatable(obj,TButton)
  140. end
  141.  
  142. ------------------Label-----------------
  143. local TLabel=setmetatable({H=1, centered=false, alignRight=false, autoSize=true, type=function() return "Label" end} ,TComponent)
  144. TLabel.__index=TLabel
  145.  
  146. function TLabel:paint()
  147.  local line
  148.  local value=tostring(self.caption)
  149.  if self.autoSize then
  150.    self.W,self.H=0,0
  151.    for line in value:gmatch("([^\n]+)") do
  152.      self.H=self.H+1
  153.      if len(line)>self.W then self.W=len(line) end
  154.    end
  155.    if self.W<1 then self.W=1 end
  156.    if self.H<1 then self.H=1 end
  157.  end
  158.  for i=0,self.H-1 do
  159.   if not value then break end
  160.   line, value = wrap(value, self.W, self.W)
  161.   if self.centered then gpu.set(self.X+(self.W-len(line))/2,self.Y+i, line)
  162.   else
  163.     if self.alignRight then gpu.set(self.X+self.W-len(line),self.Y+i, line)
  164.     else gpu.set(self.X,self.Y+i, line) end
  165.   end
  166.  end
  167. end
  168.  
  169. function TComponent:addLabel(left, top, caption)
  170.   local obj={left=left, top=top, caption=caption or "Label"}
  171.   obj.W=len(obj.caption)
  172.   self:makeChild(obj)
  173.   return setmetatable(obj,TLabel)
  174. end
  175.  
  176. ------------------Edit------------------
  177. local TEdit=setmetatable({W=20, H=3, text="", border=1, type=function() return "Edit" end},TComponent)
  178. TEdit.__index=TEdit
  179.  
  180. function TEdit:paint()
  181.   if type(self.text)=="table" then
  182.     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
  183.   else gpu.set(self.X+1,self.Y+1, sub(self.text,1,self.W-2))
  184.   end
  185. end
  186.  
  187. local function editText(text,left,top,W,H)
  188. local running=true
  189. local scrollX, scrollY = 0, 0
  190. local posX, posY =1, 1
  191. local writeText
  192.  
  193. local function setCursor(nx,ny)
  194.   posX=nx or posX
  195.   posY=ny or posY
  196.   if #text<1 then text[1]="" end
  197.   if posY>#text then posY=#text end
  198.   if posY<1 then posY=1 end
  199.   if posX>len(text[posY])+1 then posX=len(text[posY])+1 end
  200.   if posX<1 then posX=1 end
  201.   local redraw=false
  202.   if posY<=scrollY then scrollY=posY-1 redraw=true end
  203.   if posY>scrollY+H then scrollY=posY-H redraw=true end
  204.   if posX<=scrollX then scrollX=posX-1 redraw=true end
  205.   if posX>scrollX+W then scrollX=posX-W redraw=true end
  206.   if redraw then writeText()
  207.   else term.setCursor(left+posX-scrollX-1, top+posY-scrollY-1) end
  208. end
  209.  
  210. local function writeLine(n)
  211.   gpu.set(left,top+n-scrollY-1,padRight(sub(text[n] or "",scrollX+1,scrollX+W),W))
  212. end
  213.  
  214. function writeText()
  215.   for i=1,H do writeLine(i+scrollY) end
  216.   setCursor()
  217. end
  218.  
  219. local function insert(value)
  220.   if not value or len(value) < 1 then return end
  221.   text[posY]=sub(text[posY],1,posX-1)..value..sub(text[posY],posX)
  222.   writeLine(posY)
  223.   setCursor(posX+len(value))
  224. end
  225.  
  226. local keys={}
  227. keys[203]=function()    -- Left
  228.   if posX>1 then setCursor(posX-1)
  229.   else if posY>1 then posY=posY-1 setCursor(len(text[posY])+1) end
  230.   end
  231. end
  232. keys[205]=function()   -- Right
  233.   if posX<=len(text[posY]) then setCursor(posX+1)
  234.   else if posY<#text then setCursor(1,posY+1) end
  235.   end
  236. end
  237. keys[199]=function() setCursor(1) end   -- Home
  238. keys[207]=function() setCursor(len(text[posY])+1) end   -- End
  239. keys[211]=function()    -- Del
  240.   if posX<=len(text[posY]) then
  241.     text[posY]=sub(text[posY],1,posX-1)..sub(text[posY],posX+1)
  242.     writeLine(posY)
  243.   else
  244.     if posY<#text then
  245.       text[posY]=text[posY]..text[posY+1]
  246.       table.remove(text,posY+1)
  247.       writeText()
  248.     end
  249.   end
  250. end
  251. keys[14] =function()    -- BackSp
  252.   if posX>1 then
  253.     text[posY]=sub(text[posY],1,posX-2)..sub(text[posY],posX)
  254.     writeLine(posY)
  255.     setCursor(posX-1)
  256.   else
  257.     if posY>1 then
  258.       posX,posY,text[posY-1]=len(text[posY-1])+1,posY-1,text[posY-1]..text[posY]
  259.       table.remove(text,posY+1)
  260.       writeText()
  261.     end
  262.   end
  263. end
  264. keys[15] =function() insert("  ") end   -- Tab
  265.  
  266. local function onKeyDown(char, code)
  267.   if keys[code] then keys[code]()
  268.   else if not isControl(char) then insert(uchar(char)) end
  269.   end
  270. end
  271.  
  272. local function onClipboard(value)
  273. end
  274.  
  275. local function onClick(x,y)
  276.   if x>=left and x<left+W and y>=top and y<top+H then
  277.     setCursor(x+scrollX-left+1,y+scrollY-top+1)
  278.   else running=false
  279.   end
  280. end
  281.  
  282. local function onScroll(direction)
  283. end
  284.  
  285. if type(text)=="table" then
  286.   keys[68] =function() running=false end   -- F10
  287.   keys[200]=function() setCursor(posX,posY-1) end   -- Up
  288.   keys[208]=function() setCursor(posX,posY+1) end   -- Down
  289.   keys[28] =function()   -- Enter
  290.     local n=len(text[posY]:match("^%s*"))
  291.     table.insert(text,posY+1,string.rep(" ",n)..sub(text[posY],posX))
  292.     text[posY]=sub(text[posY],1,posX-1)
  293.     posX,posY=n+1,posY+1
  294.     writeText()
  295.   end
  296. else
  297.   posX=len(text)+1
  298.   text={tostring(text)}
  299.   keys[28] =function() running=false end   -- Enter
  300. end
  301. term.setCursorBlink(true)
  302. writeText()
  303. local event, address, arg1, arg2, arg3
  304. while running do
  305.   event, address, arg1, arg2, arg3 = term.pull()
  306.   if type(address) == "string" and isPrimary(address) then
  307.     term.setCursorBlink(false)
  308.     if event == "key_down" then onKeyDown(arg1, arg2)
  309.     elseif event == "clipboard" then onClipboard(arg1)
  310.     elseif event == "touch" or event == "drag" then onClick(arg1, arg2)
  311.     elseif event == "scroll" then onScroll(arg3)
  312.     end
  313.     term.setCursorBlink(true)
  314.   end
  315. end
  316. if event=="touch" then pushSignal( event, address, arg1, arg2, arg3 ) end
  317. term.setCursorBlink(false)
  318. return text[1]
  319. end
  320.  
  321. function TEdit:touch(x, y, btn, user)
  322.   if btn==0 then
  323.     gpu.setBackground(self.color)
  324.     gpu.setForeground(self.fontColor)
  325.     if type(self.text)=="table" then editText(self.text,self.X+1,self.Y+1,self.W-2,self.H-2)
  326.     else self.text=editText(self.text,self.X+1,self.Y+1,self.W-2,1) end
  327.     self:draw()
  328.     if self.onEnter then self:onEnter(user) end
  329.   end
  330. end
  331.  
  332. function TComponent:addEdit(left, top, onEnter)
  333.   local obj={left=left, top=top, onEnter=onEnter}
  334.   self:makeChild(obj)
  335.   return setmetatable(obj,TEdit)
  336. end
  337.  
  338. ------------------Frame-----------------
  339. local TFrame=setmetatable({W=20, H=10, border=1, type=function() return "Frame" end},TComponent)
  340. TFrame.__index=TFrame
  341.  
  342. function TComponent:addFrame(left, top, border)
  343.   local obj={left=left, top=top, border=border}
  344.   self:makeChild(obj)
  345.   return setmetatable(obj,TFrame)
  346. end
  347.  
  348. ------------------List------------------
  349. local TList=setmetatable({W=20, H=10, border=2, selColor=0x0000ff, sfColor=0xffff00, shift=0, index=0,
  350.   type=function() return "List" end},TComponent)
  351. TList.__index=TList
  352.  
  353. function TList:paint()
  354.   local b= self.border==0 and 0 or 1
  355.   for i=1,self.H-2*b do
  356.     if i+self.shift==self.index then gpu.setForeground(self.sfColor) gpu.setBackground(self.selColor) end
  357.     gpu.set(self.X+b,self.Y+i+b-1, padRight(sub(self.lines[i+self.shift] or "",1,self.W-2*b),self.W-2*b))
  358.     if i+self.shift==self.index then gpu.setForeground(self.fontColor) gpu.setBackground(self.color) end
  359.   end
  360. end
  361.  
  362. function TList:clear()
  363.   self.shift=0 self.index=0 self.lines={} self.items={}
  364.   self:redraw()
  365. end
  366.  
  367. function TList:insert(pos,line,item)
  368.   if type(pos)~="number" then pos,line,item=#self.lines+1,pos,line end
  369.   table.insert(self.lines,pos,line)
  370.   table.insert(self.items,pos,item or false)
  371.   if self.index<1 then self.index=1 end
  372.   if pos<self.shift+self.H-1 then self:redraw() end
  373. end
  374.  
  375. function TList:sort(comp)
  376.   comp=comp or function(list,i,j) return list.lines[j]<list.lines[i] end
  377.   for i=1,#self.lines-1 do
  378.     for j=i+1,#self.lines do
  379.       if comp(self,i,j) then
  380.         if self.index==i then self.index=j
  381.         elseif self.index==j then self.index=i end
  382.         self.lines[i],self.lines[j]=self.lines[j],self.lines[i]
  383.         self.items[i],self.items[j]=self.items[j],self.items[i]
  384.       end
  385.     end
  386.   end
  387.   self:redraw()
  388. end
  389.  
  390. function TList:touch(x, y, btn, user)
  391.   local b= self.border==0 and 0 or 1
  392.   if x>b and x<=self.W-b and y>b and y<=self.H-b and btn==0 then
  393.     local i=self.shift+y-b
  394.     if self.index~=i and self.lines[i] then
  395.       self.index=i
  396.       self:redraw()
  397.       if self.onChange then self:onChange(self.lines[i],self.items[i],user) end
  398.     end
  399.   end
  400. end
  401.  
  402. function TList:scroll(x, y, sh, user)
  403.   local b= self.border==0 and 0 or 1
  404.   self.shift=self.shift-sh
  405.   if self.shift>#(self.lines)-self.H+2*b then self.shift=#(self.lines)-self.H+2*b end
  406.   if self.shift<0 then self.shift=0 end
  407.   self:redraw()
  408. end
  409.  
  410. function TComponent:addList(left, top, onChange)
  411.   local obj={left=left, top=top, lines={}, items={}, onChange=onChange}
  412.   self:makeChild(obj)
  413.   return setmetatable(obj,TList)
  414. end
  415.  
  416. local work
  417. ---------Невизуальные компоненты--------
  418. local TInvisible=setmetatable({W=10, H=3, border=2, draw=function() end},TComponent)
  419. TInvisible.__index=TInvisible
  420. ------------------Event-----------------
  421. local TEvent=setmetatable({type=function() return "Event" end},TInvisible)
  422. TEvent.__index=TEvent
  423.  
  424. function TEvent:run()
  425.   if self.onEvent then forms.listen(self.eventName, self.onEvent) end
  426. end
  427.  
  428. function TEvent:stop()
  429.   forms.ignore(self.eventName, self.onEvent)
  430. end
  431.  
  432. function TComponent:addEvent(eventName, onEvent)
  433.   local obj={eventName=eventName, onEvent=onEvent}
  434.   self:makeChild(obj)
  435.   setmetatable(obj,TEvent)
  436.   obj:run()
  437.   return obj
  438. end
  439.  
  440. ------------------Timer-----------------
  441. local TTimer=setmetatable({Enabled=true, type=function() return "Timer" end},TInvisible)
  442. TTimer.__index=TTimer
  443.  
  444. function TTimer:run()
  445.   self.Enabled=nil
  446.   if self.onTime then
  447.     self.timerId=event.timer(self.interval,
  448.     function ()
  449.       if self.Enabled and work then
  450.         self.onTime(self)
  451.       else
  452.         self:stop()
  453.       end
  454.     end,
  455.     math.huge
  456.     )
  457.   end
  458. end
  459. function TTimer:stop()
  460.   self.Enabled=false
  461.   event.cancel(self.timerId)
  462. end
  463.  
  464. function TComponent:addTimer(interval, onTime)
  465.   local obj={interval=interval, onTime=onTime}
  466.   self:makeChild(obj)
  467.   setmetatable(obj,TTimer)
  468.   obj:run()
  469.   return obj
  470. end
  471.  
  472. -----------Обработчик событий-----------
  473. local listeners={}
  474.  
  475. function forms.listen(name, callback)
  476.   checkArg(1, name, "string")
  477.   checkArg(2, callback, "function")
  478.   if listeners[name] then
  479.     for i = 1, #listeners[name] do
  480.       if listeners[name][i] == callback then
  481.         return false
  482.       end
  483.     end
  484.   else
  485.     listeners[name] = {}
  486.   end
  487.   table.insert(listeners[name], callback)
  488.   return true
  489. end
  490.  
  491. function forms.ignore(name, callback)
  492.   checkArg(1, name, "string")
  493.   checkArg(2, callback, "function")
  494.   if listeners[name] then
  495.     for i = 1, #listeners[name] do
  496.       if listeners[name][i] == callback then
  497.         table.remove(listeners[name], i)
  498.         if #listeners[name] == 0 then
  499.           listeners[name] = nil
  500.         end
  501.         return true
  502.       end
  503.     end
  504.   end
  505.   return false
  506. end
  507.  
  508. function forms.ignoreAll()
  509.   listeners={}
  510. end
  511. ----------------------------------------
  512.  
  513. function forms.run(form)
  514.   work=true
  515.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  516.   activeForm=form
  517.   activeForm:draw()
  518.   while work do
  519.     local ev,adr,x,y,btn,user=event.pull()
  520.     if mouseEv[ev] and adr==gpu.getScreen() then activeForm:mouseEv(ev,x,y,btn,user) end
  521.     if listeners[ev] then
  522.       for i=1,#listeners[ev] do listeners[ev][i](ev,adr,x,y,btn,user) end
  523.     end
  524.     if listeners[""] then
  525.       for i=1,#listeners[""] do listeners[""][i](ev,adr,x,y,btn,user) end
  526.     end
  527.   end
  528.   gpu.setForeground(Fc)
  529.   gpu.setBackground(Bc)
  530.   forms.ignoreAll()
  531. end
  532.  
  533. function forms.stop()
  534.   work=false
  535. end
  536.  
  537. return forms
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top