Advertisement
Alex1979

GUI

Oct 5th, 2014
301
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.24 KB | None | 0 0
  1. -------------------------------------------------------------------------------------------
  2. ---Custon drawing API
  3. -------------------------------------------------------------------------------------------
  4. local function drawPixelInternal( target, xPos, yPos )
  5.     target.setCursorPos(xPos, yPos)
  6.     target.write(" ")
  7. end
  8.  
  9. local function drawPixel(target, xPos, yPos, nColour )
  10.     if nColour then
  11.         target.setBackgroundColor( nColour )
  12.     end
  13.     drawPixelInternal( target, xPos, yPos )
  14. end
  15.  
  16. local function drawLine(target, startX, startY, endX, endY, nColour )
  17.     if nColour then
  18.         target.setBackgroundColor( nColour )
  19.     end
  20.    
  21.     startX = math.floor(startX)
  22.     startY = math.floor(startY)
  23.     endX = math.floor(endX)
  24.     endY = math.floor(endY)
  25.    
  26.     if startX == endX and startY == endY then
  27.         drawPixelInternal( target, startX, startY )
  28.         return
  29.     end
  30.    
  31.     local minX = math.min( startX, endX )
  32.     if minX == startX then
  33.         minY = startY
  34.         maxX = endX
  35.         maxY = endY
  36.     else
  37.         minY = endY
  38.         maxX = startX
  39.         maxY = startY
  40.     end
  41.        
  42.     local xDiff = maxX - minX
  43.     local yDiff = maxY - minY
  44.            
  45.     if xDiff > math.abs(yDiff) then
  46.         local y = minY
  47.         local dy = yDiff / xDiff
  48.         for x=minX,maxX do
  49.             drawPixelInternal( target, x, math.floor( y + 0.5 ) )
  50.             y = y + dy
  51.         end
  52.     else
  53.         local x = minX
  54.         local dx = xDiff / yDiff
  55.         if maxY >= minY then
  56.             for y=minY,maxY do
  57.                 drawPixelInternal( target, math.floor( x + 0.5 ), y )
  58.                 x = x + dx
  59.             end
  60.         else
  61.             for y=minY,maxY,-1 do
  62.                 drawPixelInternal( target, math.floor( x + 0.5 ), y )
  63.                 x = x - dx
  64.             end
  65.         end
  66.     end
  67. end
  68.  
  69. local function drawRect(target, x1, y1, x2, y2, nColour)
  70.     for i = 0, y2 - 1 do
  71.         drawLine(target, x1, y1 + i, x1 + x2 - 1, y1 + i, nColour)
  72.     end
  73. end
  74. -------------------------------------------------------------------------------------------
  75. ---End of custom drawing API
  76. -------------------------------------------------------------------------------------------
  77. local peripheralPool = {}
  78. local SELECTED_OBJECT = nil
  79.  
  80. local function getPeripheralName(p)
  81.     return peripheralPool[p]
  82. end
  83.  
  84. function connectPeripheral(name)
  85.     local p = peripheral.wrap(name)
  86.     peripheralPool[p] = name
  87.     return p
  88. end
  89.  
  90. local function getTextLayoutPos(layout, text, x, y, width, height, px, py)
  91.     if layout == "topleft" then
  92.         return x, y
  93.     elseif layout == "top" then
  94.         local cx = x + math.floor( ( width - string.len(text) ) / 2)
  95.         return cx, y
  96.     elseif layout == "topright" then
  97.         local cx = x + ( width - string.len(text) ) + 1
  98.         return cx, y
  99.     elseif layout == "center" then
  100.         local cy = y + math.floor(height / 2)
  101.         local cx = x + math.floor( ( width - string.len(text) ) / 2)
  102.         return cx, cy  
  103.     elseif layout == "left" then
  104.         local cy = y + math.floor(height / 2)
  105.         return x, cy   
  106.     elseif layout == "right" then
  107.         local cx = x +( width - string.len(text) ) + 1
  108.         local cy = y + math.floor(height / 2)
  109.         return cx, cy
  110.     elseif layout == "bottomleft" then
  111.         local cy = y + math.floor(height / 2) + 1
  112.         return x, cy
  113.     elseif layout == "bottom" then
  114.         local cx = x + math.floor( ( width - string.len(text) ) / 2)
  115.         local cy = y + math.floor(height / 2) + 1
  116.         return cx, cy
  117.     elseif layout == "bottomright" then
  118.         local cx = x +( width - string.len(text) ) + 1
  119.         local cy = y + math.floor(height / 2) + 1
  120.         return cx, cy
  121.     end
  122. end
  123.  
  124. local function inBounds(x, y, x1, y1, w, h)
  125.     if ( ( x >= x1 and x <= ( x1 + w) ) and (y >= y1 and y <= ( y1 + h ) ) ) then
  126.         return true
  127.     end
  128.     return false
  129. end
  130.  
  131. --Defaults for all obkects
  132. local function getDefaults()
  133.     local mt = {
  134.         target = term.native,
  135.         x = 1,
  136.         y = 1,
  137.         dynX = 1,
  138.         dynY = 1,
  139.         width = 0,
  140.         height = 0,
  141.         enabled = true,
  142.         visible = true,
  143.         text = "",
  144.         func = nil,
  145.         text_pos = "center",
  146.         color_text = colors.white,
  147.         color_bg = colors.blue,
  148.         color_used = colors.red,
  149.         _PARENT = nil,
  150.         _CHILDREN = {},
  151.        
  152.         addPARENT = function(s, object)
  153.             s._PARENT = object
  154.         end,
  155.        
  156.         addCHILD = function(s, object) end,
  157.        
  158.         enable = function(s)
  159.             s.enabled = true
  160.         end,
  161.        
  162.         disable = function(s)
  163.             s.enabled = false
  164.         end,
  165.        
  166.         show = function(s)
  167.             s.visible = true
  168.         end,
  169.        
  170.         showNDraw = function(s)
  171.             s:show()
  172.             s:draw()
  173.         end,
  174.        
  175.         hide = function(s)
  176.             s.visible = false
  177.         end,
  178.        
  179.         hideNDisable = function(s)
  180.             s:hide()
  181.             s:disable()
  182.         end,
  183.        
  184.         showNEnable = function(s)
  185.             s:showNDraw()
  186.             s:enable()
  187.         end,
  188.        
  189.        
  190.        
  191.         move = function(s, x, y)
  192.             s.x = x
  193.             s.y = y
  194.             s:_dynRefresh()
  195.         end,
  196.        
  197.         resize = function(s, w, h)
  198.             s.width = w
  199.             s.height = h
  200.         end,
  201.        
  202.         _dynRefresh = function(s)
  203.             px, py = 1, 1
  204.             if s._PARENT then
  205.                 px, py = s._PARENT.dynX, s._PARENT.dynY
  206.             end
  207.             s.dynX = s.x + px - 1
  208.             s.dynY = s.y + py - 1
  209.         end,
  210.        
  211.         clickCheck = function(s) return false end,
  212.         draw = function(s) end,
  213.         eventReact = function(s, e) end,
  214.        
  215.         used = function(s)
  216.             if s.func then s:func() end
  217.         end
  218.        
  219.     }
  220.     return {__index = mt}
  221. end
  222.  
  223. --Panel constructor
  224. function NewPanel(x, y, visible, enabled)
  225.     local panel = {
  226.         addCHILD = function(s, ...)
  227.             local args = {...}
  228.             for _, object in pairs(args) do
  229.                 table.insert(s._CHILDREN, object)
  230.                 object:addPARENT(s)
  231.             end
  232.         end,
  233.        
  234.         draw = function(s)
  235.             if not s.visible then return end
  236.             s:_dynRefresh()
  237.             for _, child in pairs(s._CHILDREN) do
  238.                 child:draw()
  239.             end
  240.         end
  241.     }
  242.     panel = setmetatable(panel, getDefaults())
  243.    
  244.     panel.x = x
  245.     panel.y = y
  246.     panel.visible = visible
  247.     panel.enabled = enabled
  248.    
  249.     return panel
  250. end
  251.  
  252. --Button constructor
  253. function NewButton(target, x, y, width, height, text, func, color_bg, color_text, color_used)
  254.     local button = {
  255.         draw = function(s, color)
  256.             if not s.visible then return end
  257.             if not color then color = s.color_bg end
  258.             local cursorX, cursorY = s.target.getCursorPos()
  259.            
  260.             s:_dynRefresh()
  261.            
  262.             drawRect(s.target, s.dynX, s.dynY, s.width, s.height, color)
  263.            
  264.             local cx, cy = getTextLayoutPos(s.text_pos, s.text, s.dynX, s.dynY, s.width, s.height)
  265.             s.target.setTextColor(s.color_text)
  266.             s.target.setCursorPos(cx, cy)
  267.             s.target.write(s.text) 
  268.                
  269.             s.target.setCursorPos(cursorX, cursorY)
  270.         end,
  271.        
  272.         clickCheck = function(s, t)
  273.             if not s.enabled then return end
  274.            
  275.             if t[1] == "monitor_touch" and t[2] ~= getPeripheralName(s.target)
  276.                 or s.target ~= term.native and t[1] == "mouse_click" then
  277.                 return
  278.             end
  279.  
  280.             s:_dynRefresh()
  281.            
  282.             if inBounds(t[3], t[4], s.dynX, s.dynY, s.width - 1, s.height - 1) then
  283.                 s:used()
  284.                 return true
  285.             end
  286.             return false
  287.         end,
  288.        
  289.         used = function(s)
  290.             s:draw(s.color_used)
  291.             sleep(0.01)
  292.             if s.func then s:func() end
  293.             s:draw()
  294.         end,
  295.     }
  296.     button = setmetatable(button, getDefaults())
  297.    
  298.     button.target = target
  299.     button.x = x
  300.     button.y = y
  301.     button.width = width
  302.     button.height = height
  303.     button.text = text
  304.     button.func = func
  305.     button.color_text = color_text
  306.     button.color_bg = color_bg
  307.     button.color_used = color_used
  308.    
  309.     return button
  310. end
  311.  
  312. --CheckBox constructor
  313. function NewCheckBox(target, x, y, width, height, text, func, color_bg, color_text, color_used)
  314.     local chbox = {
  315.         check = false,
  316.        
  317.         draw = function(s, color)
  318.             if not s.visible then return end
  319.             if not color then color = s.color_bg end
  320.             local cursorX, cursorY = s.target.getCursorPos()
  321.            
  322.             s:_dynRefresh()
  323.            
  324.             drawRect(s.target, s.dynX, s.dynY, s.width, s.height, color)
  325.            
  326.             local cx, cy = getTextLayoutPos(s.text_pos, "[ ]-" .. s.text, s.dynX, s.dynY, s.width, s.height)
  327.             s.target.setTextColor(s.color_text)
  328.             s.target.setCursorPos(cx, cy)
  329.             s.target.write("["..( (s.check == true) and "X" or " ") .. "]-"..s.text)   
  330.                
  331.             s.target.setCursorPos(cursorX, cursorY)
  332.         end,
  333.        
  334.         clickCheck = function(s, t)
  335.             if not s.enabled then return end
  336.            
  337.             if t[1] == "monitor_touch" and t[2] ~= getPeripheralName(s.target)
  338.                 or s.target ~= term.native and t[1] == "mouse_click" then
  339.                 return
  340.             end
  341.  
  342.             s:_dynRefresh()
  343.            
  344.             if inBounds(t[3], t[4], s.dynX, s.dynY, s.width - 1, s.height - 1) then
  345.                 s:used()
  346.                 return true
  347.             end
  348.             return false
  349.         end,
  350.        
  351.         used = function(s)
  352.             s.check = not s.check
  353.             s:draw(s.color_used)
  354.             sleep(0.01)
  355.             if s.func then s:func() end
  356.             s:draw()
  357.         end,
  358.     }
  359.     chbox = setmetatable(chbox, getDefaults())
  360.    
  361.     chbox.target = target
  362.     chbox.x = x
  363.     chbox.y = y
  364.     chbox.width = width
  365.     chbox.height = height
  366.     chbox.text = text
  367.     chbox.func = func
  368.     chbox.color_text = color_text
  369.     chbox.color_bg = color_bg
  370.     chbox.color_used = color_used
  371.    
  372.     return chbox
  373. end
  374.  
  375. --Progress Bar constructor
  376. function NewProgressBar(target, x, y, width, height, color_bg, color_used)
  377.     local pbar = {
  378.         step = 0.01,
  379.         progress = 0.0,
  380.        
  381.         setProgress = function(s, np)
  382.             s.progress = (np > 1) and 1 or np
  383.             s:draw()
  384.         end,
  385.        
  386.         clear = function(s)
  387.             s.progress = 0
  388.             s:draw()
  389.         end,
  390.        
  391.         stepIt = function(s)
  392.             s.progress = s.progress + s.step
  393.             if s.progress > 1 then s.progress = 1 end
  394.             s:draw()
  395.         end,
  396.        
  397.         draw = function(s)
  398.             if not s.visible then return end
  399.             local cursorX, cursorY = s.target.getCursorPos()
  400.             s:_dynRefresh()
  401.            
  402.             local pos = s.width * s.progress
  403.             if pos < s.width then
  404.                 drawRect(s.target, s.dynX + pos, s.dynY, s.width - pos, s.height, s.color_bg)
  405.             end
  406.             if pos > 0 and pos ~= s.width then
  407.                 drawRect(s.target, s.dynX, s.dynY, pos+1, s.height, s.color_used)
  408.             end
  409.            
  410.             s.text = tostring( math.floor(s.progress * 100) ).."%"
  411.            
  412.             local cx, cy = getTextLayoutPos(s.text_pos, s.text, s.dynX, s.dynY, s.width, s.height)
  413.             s.target.setTextColor(s.color_text)
  414.             s.target.setCursorPos(cx, cy)
  415.            
  416.             if cx > s.dynX + pos then
  417.                 s.target.setBackgroundColor(s.color_bg)
  418.                 s.target.write(s.text) 
  419.             else
  420.                 s.target.write(string.sub(s.text, 1, math.floor(s.dynX + pos - cx + 1) ) )
  421.                 s.target.setBackgroundColor(s.color_bg)
  422.                 s.target.write(string.sub(s.text, math.floor(s.dynX + pos - cx + 2), #s.text))
  423.             end
  424.            
  425.             s.target.setCursorPos(cursorX, cursorY)
  426.         end,
  427.     }
  428.     pbar = setmetatable(pbar, getDefaults())
  429.     pbar.target = target
  430.     pbar.x = x
  431.     pbar.y = y
  432.     pbar.width = width
  433.     pbar.height = height
  434.     pbar.color_bg = color_bg
  435.     pbar.color_used = color_used
  436.    
  437.     return pbar
  438. end
  439.  
  440. --TextArea constructor
  441. function NewTextArea(target, x, y, width, height, text, color_bg, color_text)
  442.     local textarea = {
  443.         draw = function(s)
  444.             if not s.visible then return end
  445.             local cursorX, cursorY = s.target.getCursorPos()
  446.            
  447.             s:_dynRefresh()
  448.            
  449.             drawRect(s.target, s.dynX, s.dynY, s.width, s.dynY, s.color_bg)
  450.            
  451.             local k = 0
  452.             for i = 1, string.len(s.text), s.width do
  453.                 s.target.setCursorPos(s.dynX, s.dynY + k)
  454.                 k = k + 1
  455.                 s.target.setTextColor(s.color_text)
  456.                 s.target.write(string.sub(s.text, i, i + s.width - 1))
  457.             end
  458.                
  459.             s.target.setCursorPos(cursorX, cursorY)
  460.         end,
  461.        
  462.         clickCheck = function(s, t)
  463.             if not s.enabled then return end
  464.            
  465.             if t[1] == "monitor_touch" and t[2] ~= getPeripheralName(s.target)
  466.                 or s.target ~= term.native and t[1] == "mouse_click" then
  467.                 return
  468.             end
  469.  
  470.             s:_dynRefresh()
  471.            
  472.             if inBounds(t[3], t[4], s.dynX, s.dynY, s.width - 1, s.height - 1) then
  473.                 SELECTED_OBJECT = s
  474.                 return true
  475.             end
  476.             return false
  477.         end,
  478.        
  479.         eventReact = function(s, e)
  480.             if not s.enabled then return end
  481.             if e[1] == "key" then
  482.                 if e[2] == 28 then
  483.                     --testing
  484.                 elseif e[2] == 14 then
  485.                     s.text = string.sub(s.text, 1, #s.text - 1)
  486.                     s:draw()
  487.                 end
  488.             elseif e[1] == "char" then
  489.                 s.text = s.text .. e[2] --testing
  490.                 s:draw()
  491.             end
  492.         end,
  493.     }
  494.     textarea = setmetatable(textarea, getDefaults())
  495.     textarea.target = target
  496.     textarea.x = x
  497.     textarea.y = y
  498.     textarea.width = width
  499.     textarea.height = height
  500.     textarea.text = text
  501.     textarea.color_bg = color_bg
  502.     textarea.color_text = color_text
  503.     return textarea
  504. end
  505.  
  506. --Label constructor
  507. function NewLabel(target, x, y, text, color_bg, color_text)
  508.     local label = {
  509.         draw = function(s)
  510.             if not s.visible then return end
  511.             local cursorX, cursorY = s.target.getCursorPos()
  512.            
  513.             s:_dynRefresh()
  514.    
  515.             drawLine(s.target, s.dynX, s.dynY, s.dynX + string.len(s.text) - 1, s.dynY , s.color_bg)
  516.             s.target.setTextColor(s.color_text)
  517.             s.target.setCursorPos(s.dynX, s.dynY)
  518.             s.target.write(s.text)
  519.            
  520.             s.target.setCursorPos(cursorX, cursorY)
  521.         end,
  522.     }
  523.     label = setmetatable(label, getDefaults())
  524.     label.target = target
  525.     label.x = x
  526.     label.y = y
  527.     label.text = text
  528.     label.color_bg = color_bg
  529.     label.color_text = color_text
  530.     return label
  531. end
  532.  
  533. --click/touch handler
  534. local function exec(event, object)
  535.     if not object.enabled then return end
  536.     for _, child in pairs(object._CHILDREN) do
  537.         exec(event, child)
  538.         if child:clickCheck(event) then
  539.             return true
  540.         end
  541.     end
  542. end
  543.  
  544. MainPanel = NewPanel()
  545.  
  546. --Event handler. Call this if overwrite os.pullEvent()
  547. function eventHandler(e)
  548.     if e[1] == "mouse_click" or e[1] == "monitor_touch" then
  549.         --Check if selected object or its children clicked
  550.         if SELECTED_OBJECT then
  551.             exec(e, SELECTED_OBJECT)
  552.         end
  553.         SELECTED_OBJECT = nil
  554.         exec(e, MainPanel)
  555.     elseif e[1] == "key" or e[1] == "char"then
  556.         if SELECTED_OBJECT then
  557.             SELECTED_OBJECT:eventReact(e)
  558.         end
  559.     end
  560. end
  561.  
  562. function os.pullEvent()
  563.     local e = { os.pullEventRaw() }
  564.     eventHandler(e)
  565.     return e[1], e[2], e[3], e[4], e[5]
  566. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement