Advertisement
blunty666

multiglass_0_4

Sep 21st, 2015
420
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 42.00 KB | None | 0 0
  1. local tArgs = {...}
  2. local bridge
  3. if type(tArgs[1]) == "string" and peripheral.getType(tArgs[1]) == "openperipheral_bridge" then
  4.     bridge = peripheral.wrap(tArgs[1])
  5.     bridge.clear()
  6. else
  7.     error("could not find bridge on side: "..tostring(tArgs[1]))
  8. end
  9.  
  10. local colourToRGB = {
  11.     [colours.white] = 0xf0f0f0,
  12.     [colours.orange] = 0xf2b233,
  13.     [colours.magenta] = 0xe57fd8,
  14.     [colours.lightBlue] = 0x99b2f2,
  15.     [colours.yellow] = 0xdede6c,
  16.     [colours.lime] = 0x7fcc19,
  17.     [colours.pink] = 0xf2b2cc,
  18.     [colours.grey] = 0x4c4c4c,
  19.     [colours.lightGrey] = 0x999999,
  20.     [colours.cyan] = 0x4c99b2,
  21.     [colours.purple] = 0xb266e5,
  22.     [colours.blue] = 0x3366cc,
  23.     [colours.brown] = 0x7f664c,
  24.     [colours.green] = 0x57a64e,
  25.     [colours.red] = 0xcc4c4c,
  26.     [colours.black] = 0x000000,
  27. }
  28.  
  29. local rgbToColour = {}
  30. for ccColour, glassesHex in pairs(colourToRGB) do
  31.     rgbToColour[glassesHex] = ccColour
  32. end
  33.  
  34. local hexValues = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}
  35. local hexToColour = {}
  36. for i = 1, 16 do
  37.     hexToColour[hexValues[i]] = colourToRGB[2^(i-1)]
  38. end
  39.  
  40. local charOffset = {
  41.     ["!"] = 2, ["'"] = 2, ["("] = 1, [")"] = 1, ["*"] = 1, [","] = 2, ["."] = 2, [":"] = 2,
  42.     [";"] = 2,  ["<"] = 1, [">"] = 1, ["I"] = 1, ["["] = 1, ["["] = 1, ["`"] = 2, ["f"] = 1,
  43.     ["i"] = 2, ["k"] = 1, ["l"] = 2, ["t"] = 1, ["{"] = 1, ["|"] = 2, ["}"] = 1,
  44. }
  45.  
  46. local function newGlassesRedirect(surface, width, height, xOffset, yOffset, zOffset, opacity)
  47.     local surface = surface
  48.    
  49.     local width, height = width or 51, height or 19
  50.     local xOffset, yOffset, zOffset = xOffset or -(math.floor(width*6/2)), yOffset or -(math.floor(height*9/2)), zOffset or 1
  51.    
  52.     local map = {}
  53.    
  54.     local clickCatcherID = false
  55.     local clickCatcherObject = false
  56.    
  57.     local cursorX, cursorY = 1, 1
  58.     local cursorBlink = false
  59.     local cursorObject = false
  60.    
  61.     local currentTextColour = colourToRGB[colours.white]
  62.     local currentBackgroundColour = colourToRGB[colours.black]
  63.    
  64.     local isDrawn = false
  65.     local isVisible = false
  66.     local opacity = opacity or 1
  67.     local hasChanged = false
  68.     local horizontalAlign, verticalAlign = "MIDDLE", "MIDDLE"
  69.    
  70.     local bezelDrawn = false
  71.     local topBezel, bottomBezel, leftBezel, rightBezel = false, false, false, false
  72.    
  73.     local function drawBezel()
  74.         topBezel = surface.addBox(xOffset - 6, yOffset - 9, (width + 2)*6, 9, 0xdcd56c, opacity)
  75.         topBezel.setScreenAnchor(horizontalAlign, verticalAlign)
  76.         topBezel.setVisible(isVisible)
  77.         topBezel.setZ(zOffset)
  78.         bottomBezel = surface.addBox(xOffset - 6, yOffset + height*9, (width + 2)*6, 9, 0xdcd56c, opacity)
  79.         bottomBezel.setScreenAnchor(horizontalAlign, verticalAlign)
  80.         bottomBezel.setVisible(isVisible)
  81.         bottomBezel.setZ(zOffset)
  82.         leftBezel = surface.addBox(xOffset - 6, yOffset, 6, height*9, 0xdcd56c, opacity)
  83.         leftBezel.setScreenAnchor(horizontalAlign, verticalAlign)
  84.         leftBezel.setVisible(isVisible)
  85.         leftBezel.setZ(zOffset)
  86.         rightBezel = surface.addBox(xOffset + (width*6), yOffset, 6, height*9, 0xdcd56c, opacity)
  87.         rightBezel.setScreenAnchor(horizontalAlign, verticalAlign)
  88.         rightBezel.setVisible(isVisible)
  89.         rightBezel.setZ(zOffset)
  90.     end
  91.    
  92.     local function eraseBezel()
  93.         if topBezel then
  94.             topBezel.delete()
  95.             topBezel = false
  96.         end
  97.         if bottomBezel then
  98.             bottomBezel.delete()
  99.             bottomBezel = false
  100.         end
  101.         if leftBezel then
  102.             leftBezel.delete()
  103.             leftBezel = false
  104.         end
  105.         if rightBezel then
  106.             rightBezel.delete()
  107.             rightBezel = false
  108.         end
  109.     end
  110.    
  111.     local function drawClickCatcher()
  112.         clickCatcherObject = surface.addBox(xOffset, yOffset, width*6, height*9, 0x000000, 0)
  113.         clickCatcherObject.setScreenAnchor(horizontalAlign, verticalAlign)
  114.         clickCatcherObject.setVisible(isVisible)
  115.         clickCatcherObject.setZ(zOffset + 3)
  116.         clickCatcherID = clickCatcherObject.getId()
  117.     end
  118.    
  119.     local function eraseClickCatcher()
  120.         if clickCatcherObject then
  121.             clickCatcherObject.delete()
  122.             clickCatcherObject = false
  123.         end
  124.         clickCatcherID = false
  125.     end
  126.    
  127.     local function drawText(xPos, yPos, text, textColour)
  128.         local textObject = surface.addText((xPos-1)*6 + xOffset + (charOffset[text] or 0), (yPos-1)*9 + yOffset, text, textColour)
  129.         textObject.setScreenAnchor(horizontalAlign, verticalAlign)
  130.         textObject.setVisible(isVisible)
  131.         textObject.setZ(zOffset + 1)
  132.         return textObject
  133.     end
  134.    
  135.     local function drawBackground(xPos, yPos, backgroundColour)
  136.         local backgroundObject = surface.addBox((xPos-1)*6 + xOffset, (yPos-1)*9 + yOffset, 6, 9, backgroundColour, opacity)
  137.         backgroundObject.setScreenAnchor(horizontalAlign, verticalAlign)
  138.         backgroundObject.setVisible(isVisible)
  139.         backgroundObject.setZ(zOffset)
  140.         return backgroundObject
  141.     end
  142.    
  143.     local function drawCursor()
  144.         cursorObject = surface.addText((cursorX-1)*6 + xOffset, (cursorY-1)*9 + yOffset, "_", currentTextColour)
  145.         cursorObject.setScreenAnchor(horizontalAlign, verticalAlign)
  146.         cursorObject.setVisible((isVisible and cursorBlink and (map[cursorY] and map[cursorY][cursorX]) and true) or false)
  147.         cursorObject.setZ(zOffset + 2)
  148.     end
  149.    
  150.     local function createCoord(xPos, yPos, text, textColour, backgroundColour)
  151.         local coord = {
  152.             text = text,
  153.             textCol = textColour,
  154.             backCol = backgroundColour,
  155.             textObj = false,
  156.             backObj = false,
  157.         }
  158.         if isDrawn then
  159.             coord.textObj = drawText(xPos, yPos, text, textColour)
  160.             coord.backObj = drawBackground(xPos, yPos, backgroundColour)
  161.         end
  162.         return coord
  163.     end
  164.    
  165.     local updateTextObj
  166.     local function updateCoord(xPos, yPos, text, textColour, backgroundColour)
  167.         local coord = map[yPos] and map[yPos][xPos]
  168.         if coord then
  169.             if coord.text ~= text or coord.textCol ~= textColour or coord.backCol ~= backgroundColour then
  170.                 coord.text = text
  171.                 coord.textCol = textColour
  172.                 coord.backCol = backgroundColour
  173.            
  174.                 if isDrawn then
  175.                     updateTextObj = coord.textObj
  176.                     updateTextObj.setText(text)
  177.                     updateTextObj.setColor(textColour)
  178.                     updateTextObj.setX((xPos-1)*6 + xOffset + (charOffset[text] or 0))
  179.            
  180.                     coord.backObj.setColor(backgroundColour)
  181.                 end
  182.            
  183.                 hasChanged = true
  184.             end
  185.         end
  186.     end
  187.    
  188.     local function updateCursor()
  189.         if isDrawn and cursorObject then
  190.             cursorObject.setX((cursorX-1)*6 + xOffset)
  191.             cursorObject.setY((cursorY-1)*9 + yOffset)
  192.             cursorObject.setZ(zOffset + 2)
  193.             cursorObject.setVisible((isVisible and cursorBlink and (map[cursorY] and map[cursorY][cursorX]) and true) or false)
  194.             cursorObject.setColor(currentTextColour)
  195.         end
  196.     end
  197.    
  198.     local redirect = {}
  199.    
  200.     redirect.getDrawn = function()
  201.         return isDrawn
  202.     end
  203.     redirect.setDrawn = function(setDrawn)
  204.         if type(setDrawn) == "boolean" and isDrawn ~= setDrawn then
  205.             if setDrawn == true then
  206.                 local coord
  207.                 for yPos = 1, height do
  208.                     for xPos = 1,width do
  209.                         coord = map[yPos][xPos]
  210.                         coord.textObj = drawText(xPos, yPos, coord.text, coord.textCol)
  211.                         coord.backObj = drawBackground(xPos, yPos, coord.backCol)
  212.                     end
  213.                 end
  214.                 if bezelDrawn then
  215.                     drawBezel()
  216.                 end
  217.                 drawClickCatcher()
  218.                 drawCursor()
  219.             else
  220.                 local coord
  221.                 for yPos = 1, height do
  222.                     for xPos = 1,width do
  223.                         coord = map[yPos][xPos]
  224.                         coord.textObj.delete()
  225.                         coord.backObj.delete()
  226.                         coord.textObj = false
  227.                         coord.backObj = false
  228.                     end
  229.                 end
  230.                 cursorObject.delete()
  231.                 cursorObject = false
  232.                 eraseClickCatcher()
  233.                 eraseBezel()
  234.             end
  235.             isDrawn = setDrawn
  236.             hasChanged = true
  237.             return true
  238.         end
  239.         return false
  240.     end
  241.    
  242.     redirect.getAlignment = function()
  243.         return horizontalAlign, verticalAlign
  244.     end
  245.     redirect.setAlignment = function(horizontal, vertical)
  246.         --if check args then
  247.             if isDrawn then
  248.                 local coord
  249.                 for yPos = 1, height do
  250.                     for xPos = 1,width do
  251.                         coord = map[yPos][xPos]
  252.                         coord.textObj.setScreenAnchor(horizontal, vertical)
  253.                         coord.backObj.setScreenAnchor(horizontal, vertical)
  254.                     end
  255.                 end
  256.                 if bezelDrawn then
  257.                     topBezel.setScreenAnchor(horizontal, vertical)
  258.                     bottomBezel.setScreenAnchor(horizontal, vertical)
  259.                     leftBezel.setScreenAnchor(horizontal, vertical)
  260.                     rightBezel.setScreenAnchor(horizontal, vertical)
  261.                 end
  262.                 clickCatcherObject.setScreenAnchor(horizontal, vertical)
  263.                 cursorObject.setScreenAnchor(horizontal, vertical)
  264.                 hasChanged = true
  265.             end
  266.             horizontalAlign, verticalAlign = horizontal, vertical
  267.             return true
  268.         --end
  269.         --return false
  270.     end
  271.    
  272.     redirect.getVisible = function()
  273.         return isVisible
  274.     end
  275.     redirect.setVisible = function(setVisible)
  276.         if type(setVisible) == "boolean" and isVisible ~= setVisible then
  277.             if isDrawn then
  278.                 local coord
  279.                 for yPos = 1, height do
  280.                     for xPos = 1,width do
  281.                         coord = map[yPos][xPos]
  282.                         coord.textObj.setVisible(setVisible)
  283.                         coord.backObj.setVisible(setVisible)
  284.                     end
  285.                 end
  286.                 if bezelDrawn then
  287.                     topBezel.setVisible(setVisible)
  288.                     bottomBezel.setVisible(setVisible)
  289.                     leftBezel.setVisible(setVisible)
  290.                     rightBezel.setVisible(setVisible)
  291.                 end
  292.                 clickCatcherObject.setVisible(setVisible)
  293.                 cursorObject.setVisible(setVisible and cursorBlink)
  294.                 hasChanged = true
  295.             end
  296.             isVisible = setVisible
  297.             return true
  298.         end
  299.         return false
  300.     end
  301.    
  302.     redirect.getOpacity = function()
  303.         return opacity
  304.     end
  305.     redirect.setOpacity = function(newOpacity)
  306.         if type(newOpacity) == "number" and newOpacity >= 0 and newOpacity <= 1 then
  307.             if isDrawn then
  308.                 local coord
  309.                 for yPos = 1, height do
  310.                     for xPos = 1,width do
  311.                         coord = map[yPos][xPos]
  312.                         coord.backObj.setOpacity(newOpacity)
  313.                     end
  314.                 end
  315.                 if bezelDrawn then
  316.                     topBezel.setOpacity(newOpacity)
  317.                     bottomBezel.setOpacity(newOpacity)
  318.                     leftBezel.setOpacity(newOpacity)
  319.                     rightBezel.setOpacity(newOpacity)
  320.                 end
  321.                 hasChanged = true
  322.             end
  323.             opacity = newOpacity
  324.             return true
  325.         end
  326.         return false
  327.     end
  328.    
  329.     redirect.getSurface = function()
  330.         return surface
  331.     end
  332.     redirect.setSurface = function(newSurface, redraw)
  333.         surface = newSurface
  334.         if redraw == true and isDrawn then
  335.             redirect.setDrawn(false)
  336.             redirect.setDrawn(true)
  337.         end
  338.     end
  339.    
  340.     redirect.getOffset = function()
  341.         return xOffset, yOffset, zOffset
  342.     end
  343.     redirect.setOffset = function(xOffsetNew, yOffsetNew, zOffsetNew)
  344.         xOffset = math.floor(tonumber(xOffsetNew) or xOffset)
  345.         yOffset = math.floor(tonumber(yOffsetNew) or yOffset)
  346.         zOffset = math.min(250, math.max(1, math.floor(tonumber(zOffsetNew) or zOffset)))
  347.         if isDrawn then
  348.             for yPos, line in ipairs(map) do
  349.                 for xPos, coord in ipairs(line) do
  350.                     coord.textObj.setX((xPos-1)*6 + xOffset + (charOffset[coord.curText] or 0))
  351.                     coord.textObj.setY((yPos-1)*9 + yOffset)
  352.                     coord.textObj.setZ(zOffset + 1)
  353.  
  354.                     coord.backObj.setX((xPos-1)*6 + xOffset)
  355.                     coord.backObj.setY((yPos-1)*9 + yOffset)
  356.                     coord.backObj.setZ(zOffset)
  357.                 end
  358.             end
  359.             clickCatcherObject.setX(xOffset)
  360.             clickCatcherObject.setY(yOffset)
  361.             clickCatcherObject.setZ(zOffset + 3)
  362.             if bezelDrawn then
  363.                 eraseBezel()
  364.                 drawBezel()
  365.             end
  366.             updateCursor()
  367.             hasChanged = true
  368.         end
  369.         return true
  370.     end
  371.    
  372.     redirect.getSize = function()
  373.         return width, height
  374.     end
  375.     redirect.setSize = function(newWidth, newHeight)
  376.         for yPos = 1, math.max(newHeight, height) do
  377.             if yPos <= newHeight then
  378.                 map[yPos] = map[yPos] or {}
  379.                 for xPos = 1, math.max(newWidth, width) do
  380.                     if xPos <= newWidth then
  381.                         if not map[yPos][xPos] then
  382.                             map[yPos][xPos] = createCoord(xPos, yPos, " ", currentTextColour, currentBackgroundColour)
  383.                         end
  384.                     elseif map[yPos][xPos] then
  385.                         local coord = map[yPos][xPos]
  386.                         if coord.textObj then
  387.                             coord.textObj.delete()
  388.                         end
  389.                         if coord.backObj then
  390.                             coord.backObj.delete()
  391.                         end
  392.                         map[yPos][xPos] = nil
  393.                     end
  394.                 end
  395.             elseif map[yPos] then
  396.                 for xPos = 1, math.max(newWidth, width) do
  397.                     if map[yPos][xPos] then
  398.                         local coord = map[yPos][xPos]
  399.                         if coord.textObj then
  400.                             coord.textObj.delete()
  401.                         end
  402.                         if coord.backObj then
  403.                             coord.backObj.delete()
  404.                         end
  405.                         map[yPos][xPos] = nil
  406.                     end
  407.                 end
  408.                 map[yPos] = nil
  409.             end
  410.         end
  411.         width, height = newWidth, newHeight
  412.         if isDrawn then
  413.             clickCatcherObject.delete()
  414.             drawClickCatcher()
  415.             if bezelDrawn then
  416.                 eraseBezel()
  417.                 drawBezel()
  418.             end
  419.         end
  420.         updateCursor()
  421.         hasChanged = true
  422.     end
  423.    
  424.     redirect.getClick = function(objectID, xPos, yPos)
  425.         if objectID == clickCatcherID then
  426.             return math.ceil((xPos+1)/6), math.ceil((yPos+1)/9)
  427.         else
  428.             return false, false
  429.         end
  430.     end
  431.    
  432.     redirect.getBezelDrawn = function()
  433.         return bezelDrawn
  434.     end
  435.     redirect.setBezelDrawn = function(isBezelDrawn)
  436.         if type(isBezelDrawn) == "boolean" and bezelDrawn ~= isBezelDrawn then
  437.             bezelDrawn = isBezelDrawn
  438.             if isDrawn then
  439.                 if isBezelDrawn then
  440.                     drawBezel()
  441.                 else
  442.                     eraseBezel()
  443.                 end
  444.                 hasChanged = true
  445.             end
  446.             return true
  447.         end
  448.         return false
  449.     end
  450.    
  451.     redirect.hasChanged = function()
  452.         return hasChanged
  453.     end
  454.     redirect.reset = function()
  455.         hasChanged = false
  456.     end
  457.        
  458.     local newTerm = {
  459.         write = function(text)
  460.             local textType = type(text)
  461.             if textType == "string" or textType == "number" then
  462.                 local text = string.gsub(text, "%c", " ")
  463.                 local length = string.len(text)
  464.                 if length > 0 then
  465.                     if map[cursorY] then
  466.                         for xPos = 1, length do
  467.                             updateCoord(xPos - 1 + cursorX, cursorY, string.sub(text, xPos, xPos), currentTextColour, currentBackgroundColour)
  468.                         end
  469.                     end
  470.                     cursorX = cursorX + length
  471.                     updateCursor()
  472.                 end
  473.             end
  474.         end,
  475.         blit = function(text, textColour, backgroundColour)
  476.             if type(text) ~= "string" or type(textColour) ~= "string" or type(backgroundColour) ~= "string" then
  477.                 error("Expected string, string, string", 2)
  478.             end
  479.             if #text ~= #textColour or #text ~= #backgroundColour then
  480.                 error("Arguments must be the same length", 2)
  481.             end
  482.             local text = string.gsub(text, "%c", " ")
  483.             local length = string.len(text)
  484.             if length > 0 then
  485.                 if map[cursorY] then
  486.                     for xPos = 1, length do
  487.                         updateCoord(xPos - 1 + cursorX, cursorY, string.sub(text, xPos, xPos), hexToColour[string.sub(textColour, xPos, xPos)] or currentTextColour, hexToColour[string.sub(backgroundColour, xPos, xPos)] or currentBackgroundColour)
  488.                     end
  489.                 end
  490.                 cursorX = cursorX + length
  491.                 updateCursor()
  492.             end
  493.         end,
  494.         clear = function()
  495.             for yPos = 1, height do
  496.                 for xPos = 1, width do
  497.                     updateCoord(xPos, yPos, " ", currentTextColour, currentBackgroundColour)
  498.                 end
  499.             end
  500.         end,
  501.         clearLine = function()
  502.             if map[cursorY] then
  503.                 for xPos = 1, width do
  504.                     updateCoord(xPos, cursorY, " ", currentTextColour, currentBackgroundColour)
  505.                 end
  506.             end
  507.         end,
  508.         getCursorPos = function()
  509.             return cursorX, cursorY
  510.         end,
  511.         setCursorPos = function(xPos, yPos)
  512.             cursorX = math.floor(tonumber(xPos) or cursorX)
  513.             cursorY = math.floor(tonumber(yPos) or cursorY)
  514.             updateCursor()
  515.         end,
  516.         setCursorBlink = function(blink)
  517.             if type(blink) == "boolean" then
  518.                 cursorBlink = blink
  519.                 updateCursor()
  520.             end
  521.         end,
  522.         isColour = function()
  523.             return true
  524.         end,
  525.         getSize = function()
  526.             return width, height
  527.         end,
  528.         scroll = function(noOfLines)
  529.             local n = math.floor(tonumber(noOfLines) or 0)
  530.             if n ~= 0 and height > 0 then
  531.                 for yPos = (n > 0 and 1) or height, (n < 0 and 1) or height, n/math.abs(n) do
  532.                     for xPos = 1, width do
  533.                         if map[yPos + n] then
  534.                             local coord = map[yPos + n][xPos].data
  535.                             updateCoord(xPos, yPos, coord.text, coord.textColour, coord.backgroundColour)
  536.                         else
  537.                             updateCoord(xPos, yPos, " ", currentTextColour, currentBackgroundColour)
  538.                         end
  539.                     end
  540.                 end
  541.             end
  542.         end,
  543.         setTextColour = function(colour)
  544.             local newColour = colourToRGB[tonumber(colour)]
  545.             if newColour then
  546.                 currentTextColour = newColour
  547.                 updateCursor()
  548.             end
  549.         end,
  550.         getTextColour = function()
  551.             return rgbToColour[currentTextColour]
  552.         end,
  553.         setBackgroundColour = function(colour)
  554.             local newColour = colourToRGB[tonumber(colour)]
  555.             if newColour then
  556.                 currentBackgroundColour = newColour
  557.             end
  558.         end,
  559.         getBackgroundColour = function()
  560.             return rgbToColour[currentBackgroundColour]
  561.         end,
  562.     }
  563.     newTerm.isColor = newTerm.isColour
  564.     newTerm.setTextColor = newTerm.setTextColour
  565.     newTerm.getTextColor = newTerm.getTextColour
  566.     newTerm.setBackgroundColor = newTerm.setBackgroundColour
  567.     newTerm.getBackgroundColor = newTerm.getBackgroundColour
  568.    
  569.     redirect.term = newTerm
  570.    
  571.     redirect.setSize(width, height)
  572.    
  573.     return redirect
  574. end
  575.  
  576. local function setupLabel(buttonLen, minY, maxY, name)
  577.     local labelTable = {}
  578.     if type(name) == "table" then
  579.         for i = 1, #name do
  580.             labelTable[i] = name[i]
  581.         end
  582.         name = name.label
  583.     elseif type(name) == "string" then
  584.         local buttonText = string.sub(name, 1, buttonLen - 2)
  585.         if #buttonText < #name then
  586.             buttonText = " "..buttonText.." "
  587.         else
  588.             local labelLine = string.rep(" ", math.floor((buttonLen - #buttonText) / 2))..buttonText
  589.             buttonText = labelLine..string.rep(" ", buttonLen - #labelLine)
  590.         end
  591.         for i = 1, maxY - minY + 1 do
  592.             if maxY == minY or i == math.floor((maxY - minY) / 2) + 1 then
  593.                 labelTable[i] = buttonText
  594.             else
  595.                 labelTable[i] = string.rep(" ", buttonLen)
  596.             end
  597.         end
  598.     end
  599.     return labelTable, name
  600. end
  601.  
  602. local Button = {
  603.     draw = function(self)
  604.         local old = term.redirect(self.mon)
  605.         term.setTextColor(colors.white)
  606.         term.setBackgroundColor(colors.black)
  607.         term.clear()
  608.         for name, buttonData in pairs(self.buttonList) do
  609.             if buttonData.active then
  610.                 term.setBackgroundColor(buttonData.activeColor)
  611.                 term.setTextColor(buttonData.activeText)
  612.             else
  613.                 term.setBackgroundColor(buttonData.inactiveColor)
  614.                 term.setTextColor(buttonData.inactiveText)
  615.             end
  616.             for i = buttonData.yMin, buttonData.yMax do
  617.                 term.setCursorPos(buttonData.xMin, i)
  618.                 term.write(buttonData.label[i - buttonData.yMin + 1])
  619.             end
  620.         end
  621.         if old then
  622.             term.redirect(old)
  623.         else
  624.             term.restore()
  625.         end
  626.     end,
  627.     add = function(self, name, func, xMin, yMin, xMax, yMax, inactiveColor, activeColor, inactiveText, activeText)
  628.         local label, name = setupLabel(xMax - xMin + 1, yMin, yMax, name)
  629.         if self.buttonList[name] then error("button already exists", 2) end
  630.         local x, y = self.mon.getSize()
  631.         if xMin < 1 or yMin < 1 or xMax > x or yMax > y then error("button out of bounds", 2) end
  632.         self.buttonList[name] = {
  633.             func = func,
  634.             xMin = xMin,
  635.             yMin = yMin,
  636.             xMax = xMax,
  637.             yMax = yMax,
  638.             active = false,
  639.             inactiveColor = inactiveColor or colors.red,
  640.             activeColor = activeColor or colors.lime,
  641.             inactiveText = inactiveText or colors.white,
  642.             activeText = activeText or colors.white,
  643.             label = label,
  644.         }
  645.         for i = xMin, xMax do
  646.             for j = yMin, yMax do
  647.                 if self.clickMap[i][j] ~= nil then
  648.                     --undo changes
  649.                     for k = xMin, xMax do
  650.                         for l = yMin, yMax do
  651.                             if self.clickMap[k][l] == name then
  652.                                 self.clickMap[k][l] = nil
  653.                             end
  654.                         end
  655.                     end
  656.                     self.buttonList[name] = nil
  657.                     error("overlapping button", 2)
  658.                 end
  659.                 self.clickMap[i][j] = name
  660.             end
  661.         end
  662.     end,
  663.     remove = function(self, name)
  664.         if self.buttonList[name] then
  665.             local button = self.buttonList[name]
  666.             for i = button.xMin, button.xMax do
  667.                 for j = button.yMin, button.yMax do
  668.                     self.clickMap[i][j] = nil
  669.                 end
  670.             end
  671.             self.buttonList[name] = nil
  672.         end
  673.     end,
  674.     run = function(self)
  675.         while true do
  676.             self:draw()
  677.             local event = {self:handleEvents(os.pullEvent(self.side == "term" and "mouse_click" or "monitor_touch"))}
  678.             if event[1] == "button_click" then
  679.                 self.buttonList[event[2]].func()
  680.             end
  681.         end
  682.     end,
  683.     handleEvents = function(self, ...)
  684.         local event = {...}
  685.         if #event == 0 then event = {os.pullEvent()} end
  686.         if (self.side == "term" and event[1] == "mouse_click") or (self.side ~= "term" and event[1] == "monitor_touch" and event[2] == self.side) then
  687.             local clicked = self.clickMap[event[3]][event[4]]
  688.             if clicked and self.buttonList[clicked] then
  689.                 return "button_click", clicked
  690.             end
  691.         end
  692.         return unpack(event)
  693.     end,
  694.     toggleButton = function(self, name, noDraw)
  695.         self.buttonList[name].active = not self.buttonList[name].active
  696.         if not noDraw then self:draw() end
  697.     end,
  698.     flash = function(self, name, duration)
  699.         self:toggleButton(name)
  700.         sleep(tonumber(duration) or 0.15)
  701.         self:toggleButton(name)
  702.     end,
  703.     rename = function(self, name, newName)
  704.         self.buttonList[name].label, newName = setupLabel(self.buttonList[name].xMax - self.buttonList[name].xMin + 1, self.buttonList[name].yMin, self.buttonList[name].yMax, newName)
  705.         if not self.buttonList[name] then error("no such button", 2) end
  706.         if name ~= newName then
  707.             self.buttonList[newName] = self.buttonList[name]
  708.             self.buttonList[name] = nil
  709.             for i = self.buttonList[newName].xMin, self.buttonList[newName].xMax do
  710.                 for j = self.buttonList[newName].yMin, self.buttonList[newName].yMax do
  711.                     self.clickMap[i][j] = newName
  712.                 end
  713.             end
  714.         end
  715.         self:draw()
  716.     end,
  717. }
  718.  
  719. local function newTouchpoint(monSide)
  720.     local buttonInstance = {
  721.         side = monSide or "term",
  722.         mon = monSide and peripheral.wrap(monSide) or term.current(),
  723.         buttonList = {},
  724.         clickMap = {},
  725.     }
  726.     local x, y = buttonInstance.mon.getSize()
  727.     for i = 1, x do
  728.         buttonInstance.clickMap[i] = {}
  729.     end
  730.     setmetatable(buttonInstance, {__index = Button})
  731.     return buttonInstance
  732. end
  733.  
  734. local function resumeThread(threadInfo, eventType, ...)
  735.     if threadInfo.running then
  736.         if not threadInfo.filter or eventType == threadInfo.filter or eventType == "terminate" then
  737.             threadInfo.filter = nil
  738.  
  739.             local prevTerm = term.redirect(threadInfo.term)
  740.             local ok, passback = coroutine.resume(threadInfo.thread, eventType, ...)
  741.             term.redirect(prevTerm)
  742.  
  743.             if not ok then
  744.                 threadInfo.running = false
  745.                 printError(passback)
  746.             elseif coroutine.status(threadInfo.thread) == "dead" then
  747.                 threadInfo.running = false
  748.             else
  749.                 threadInfo.filter = passback
  750.             end
  751.         end
  752.     end
  753. end
  754.  
  755. local function createThread(func, terminal)
  756.     local thread = {
  757.         running = true,
  758.         filter = nil,
  759.         thread = coroutine.create(func),
  760.         term = terminal,
  761.     }
  762.     resumeThread(thread, nil)
  763.     return thread
  764. end
  765.  
  766. local function newSurfaceHandler(playerUUID, capture, programRedirect, toolbarRedirect, settingRedirect)
  767.     return coroutine.create(
  768.         function()
  769.             local programThread
  770.             local fnFile, err = loadfile("rom/programs/advanced/multishell")
  771.             if fnFile then
  772.                 local tEnv = {
  773.                     shell = shell,
  774.                 }
  775.                 setmetatable( tEnv, { __index = _G } )
  776.                 setfenv( fnFile, tEnv )
  777.                 programThread = createThread(fnFile, programRedirect.term)
  778.             else
  779.                 error(err)
  780.             end
  781.            
  782.             local isLocked = false
  783.             local forceSettingsDrawn = false
  784.             local function toolbarFunc()
  785.                 local tPoint = newTouchpoint()
  786.                
  787.                 local lockButtonLabel = {
  788.                     "L",
  789.                     label = "lock",
  790.                 }
  791.                 local function lockFunc()
  792.                     isLocked = not isLocked
  793.                     tPoint:toggleButton("lock")
  794.                 end
  795.                 tPoint:add(lockButtonLabel, lockFunc, 1, 1, 1, 1, colours.green, colours.red, colours.lime, colours.orange)
  796.                
  797.                 local settingButtonLabel = {
  798.                     "S",
  799.                     label = "setting",
  800.                 }
  801.                 local function settingFunc()
  802.                     settingRedirect.setDrawn(not settingRedirect.getDrawn())
  803.                     tPoint:flash("setting", 0.1)
  804.                 end
  805.                 tPoint:add(settingButtonLabel, settingFunc, 2, 1, 2, 1, colours.yellow, colours.green, colours.black, colours.black)
  806.                
  807.                 local terminateButtonLabel = {
  808.                     "T",
  809.                     label = "terminate",
  810.                 }
  811.                 local function terminateFunc()
  812.                     tPoint:flash("terminate", 0.1)
  813.                     resumeThread(programThread, "terminate")
  814.                 end
  815.                 tPoint:add(terminateButtonLabel, terminateFunc, 3, 1, 3, 1, colours.red, colours.yellow, colours.orange, colours.orange)
  816.                
  817.                 tPoint:run()
  818.             end
  819.             local toolbarThread = createThread(toolbarFunc, toolbarRedirect.term)
  820.            
  821.             local function settingFunc()
  822.                 local tPoint = newTouchpoint()
  823.                
  824.                 local width, height = term.getSize()
  825.                
  826.                 local alignLeftButtonLabel = {}
  827.                 for i = 2, height - 1 do
  828.                     table.insert(alignLeftButtonLabel, "<")
  829.                 end
  830.                 alignLeftButtonLabel.label = "alignLeft"
  831.                 local function alignLeftFunc()
  832.                     tPoint:flash("alignLeft", 0.1)
  833.                     local horizontal, vertical = settingRedirect.getAlignment()
  834.                     settingRedirect.setAlignment("LEFT", vertical)
  835.                     local xOffset, yOffset = settingRedirect.getOffset()
  836.                     settingRedirect.setOffset(20, yOffset)
  837.                 end
  838.                 tPoint:add(alignLeftButtonLabel, alignLeftFunc, 1, 2, 1, height - 1, colours.lightGrey, colours.green, colours.black, colours.white)
  839.                
  840.                 local alignRightButtonLabel = {}
  841.                 for i = 2, height - 1 do
  842.                     table.insert(alignRightButtonLabel, ">")
  843.                 end
  844.                 alignRightButtonLabel.label = "alignRight"
  845.                 local function alignRightFunc()
  846.                     tPoint:flash("alignRight", 0.1)
  847.                     local horizontal, vertical = settingRedirect.getAlignment()
  848.                     settingRedirect.setAlignment("RIGHT", vertical)
  849.                     local xOffset, yOffset = settingRedirect.getOffset()
  850.                     settingRedirect.setOffset(-(15*6 + 20), yOffset)
  851.                 end
  852.                 tPoint:add(alignRightButtonLabel, alignRightFunc, width, 2, width, height - 1, colours.lightGrey, colours.green, colours.black, colours.white)
  853.                
  854.                 local alignTopButtonLabel = {
  855.                     string.rep("^", width - 2),
  856.                     label = "alignTop",
  857.                 }
  858.                 local function alignTopFunc()
  859.                     tPoint:flash("alignTop", 0.1)
  860.                     local horizontal, vertical = settingRedirect.getAlignment()
  861.                     settingRedirect.setAlignment(horizontal, "TOP")
  862.                     local xOffset, yOffset = settingRedirect.getOffset()
  863.                     settingRedirect.setOffset(xOffset, 20)
  864.                 end
  865.                 tPoint:add(alignTopButtonLabel, alignTopFunc, 2, 1, width - 1, 1, colours.lightGrey, colours.green, colours.black, colours.white)
  866.                
  867.                 local alignBottomButtonLabel = {
  868.                     string.rep("v", width - 2),
  869.                     label = "alignBottom",
  870.                 }
  871.                 local function alignBottomFunc()
  872.                     tPoint:flash("alignBottom", 0.1)
  873.                     local horizontal, vertical = settingRedirect.getAlignment()
  874.                     settingRedirect.setAlignment(horizontal, "BOTTOM")
  875.                     local xOffset, yOffset = settingRedirect.getOffset()
  876.                     local width, height = settingRedirect.getSize()
  877.                     settingRedirect.setOffset(xOffset, -(height*9 + 20))
  878.                 end
  879.                 tPoint:add(alignBottomButtonLabel, alignBottomFunc, 2, height, width - 1, height, colours.lightGrey, colours.green, colours.black, colours.white)
  880.                
  881.                 local opacityLabel = {
  882.                     "Opacity",
  883.                     label = "opacity",
  884.                 }
  885.                 tPoint:add(opacityLabel, nil, 5, 3, 11, 3, colours.black, colours.black, colours.white, colours.white)
  886.                 local opacityValues = {
  887.                     [0] = "0.0", [0.1] = "0.1", [0.2] = "0.2", [0.3] = "0.3", [0.4] = "0.4", [0.5] = "0.5",
  888.                     [0.6] = "0.6", [0.7] = "0.7", [0.8] = "0.8", [0.9] = "0.9", [1] = "1.0",
  889.                 }
  890.                 local opacityValueLabel = {
  891.                     "1.0",
  892.                     label = "opacityValue",
  893.                 }
  894.                 tPoint:add(opacityValueLabel, nil, 7, 4, 9, 4, colours.black, colours.black, colours.white, colours.white)
  895.                 local decreaseOpacityLabel = {
  896.                     "<<",
  897.                     label = "decreaseOpacity",
  898.                 }
  899.                 local function decreaseOpacityFunc()
  900.                     local currOpacity = programRedirect.getOpacity()
  901.                     currOpacity = math.max(0, math.floor((currOpacity - 0.1)*10)/10)
  902.                     programRedirect.setOpacity(currOpacity)
  903.                     toolbarRedirect.setOpacity(currOpacity)
  904.                     opacityValueLabel[1] = opacityValues[currOpacity]
  905.                     tPoint:rename("opacityValue", opacityValueLabel)
  906.                     tPoint:flash("decreaseOpacity", 0.1)
  907.                 end
  908.                 tPoint:add(decreaseOpacityLabel, decreaseOpacityFunc, 4, 4, 5, 4, colours.grey, colours.green, colours.white, colours.white)
  909.                 local increaseOpacityLabel = {
  910.                     ">>",
  911.                     label = "increaseOpacity",
  912.                 }
  913.                 local function increaseOpacityFunc()
  914.                     local currOpacity = programRedirect.getOpacity()
  915.                     currOpacity = math.min(1, math.ceil((currOpacity + 0.1)*10)/10)
  916.                     programRedirect.setOpacity(currOpacity)
  917.                     toolbarRedirect.setOpacity(currOpacity)
  918.                     opacityValueLabel[1] = opacityValues[currOpacity]
  919.                     tPoint:rename("opacityValue", opacityValueLabel)
  920.                     tPoint:flash("increaseOpacity", 0.1)
  921.                 end
  922.                 tPoint:add(increaseOpacityLabel, increaseOpacityFunc, 11, 4, 12, 4, colours.grey, colours.green, colours.white, colours.white)
  923.                 local resetOpacityLabel = {
  924.                     "RESET",
  925.                     label = "resetOpacity",
  926.                 }
  927.                 local function resetOpacityFunc()
  928.                     programRedirect.setOpacity(1)
  929.                     toolbarRedirect.setOpacity(1)
  930.                     opacityValueLabel[1] = "1.0"
  931.                     tPoint:rename("opacityValue", opacityValueLabel)
  932.                     tPoint:flash("resetOpacity", 0.1)
  933.                 end
  934.                 tPoint:add(resetOpacityLabel, resetOpacityFunc, 6, 5, 10, 5, colours.grey, colours.green, colours.white, colours.white)
  935.                
  936.                 local widthLabel = {
  937.                     "Width",
  938.                     label = "width",
  939.                 }
  940.                 tPoint:add(widthLabel, nil, 6, 7, 10, 7, colours.black, colours.black, colours.white, colours.white)
  941.                 local widthValueLabel = {
  942.                     " 51",
  943.                     label = "widthValue",
  944.                 }
  945.                 tPoint:add(widthValueLabel, nil, 7, 8, 9, 8, colours.black, colours.black, colours.white, colours.white)
  946.                 local decreaseWidthLabel = {
  947.                     "<<",
  948.                     label = "decreaseWidth",
  949.                 }
  950.                 local function decreaseWidthFunc()
  951.                     local currWidth, currHeight = programRedirect.getSize()
  952.                     currWidth = math.max(1, currWidth - 1)
  953.                     programRedirect.setSize(currWidth, currHeight)
  954.                     programRedirect.setOffset(-(math.floor(currWidth*6/2)))
  955.                     resumeThread(programThread, "term_resize")
  956.                     widthValueLabel[1] = string.rep(" ", 3 - string.len(currWidth))..tostring(currWidth)
  957.                     tPoint:rename("widthValue", widthValueLabel)
  958.                     tPoint:flash("decreaseWidth", 0.1)
  959.                 end
  960.                 tPoint:add(decreaseWidthLabel, decreaseWidthFunc, 4, 8, 5, 8, colours.grey, colours.green, colours.white, colours.white)
  961.                 local increaseWidthLabel = {
  962.                     ">>",
  963.                     label = "increaseWidth",
  964.                 }
  965.                 local function increaseWidthFunc()
  966.                     local currWidth, currHeight = programRedirect.getSize()
  967.                     currWidth = math.min(999, currWidth + 1)
  968.                     programRedirect.setSize(currWidth, currHeight)
  969.                     programRedirect.setOffset(-(math.floor(currWidth*6/2)))
  970.                     resumeThread(programThread, "term_resize")
  971.                     widthValueLabel[1] = string.rep(" ", 3 - string.len(currWidth))..tostring(currWidth)
  972.                     tPoint:rename("widthValue", widthValueLabel)
  973.                     tPoint:flash("increaseWidth", 0.1)
  974.                 end
  975.                 tPoint:add(increaseWidthLabel, increaseWidthFunc, 11, 8, 12, 8, colours.grey, colours.green, colours.white, colours.white)
  976.                 local resetWidthLabel = {
  977.                     "RESET",
  978.                     label = "resetWidth",
  979.                 }
  980.                 local function resetWidthFunc()
  981.                     local currWidth, currHeight = programRedirect.getSize()
  982.                     currWidth = 51
  983.                     programRedirect.setSize(currWidth, currHeight)
  984.                     programRedirect.setOffset(-(math.floor(currWidth*6/2)))
  985.                     resumeThread(programThread, "term_resize")
  986.                     widthValueLabel[1] = string.rep(" ", 3 - string.len(currWidth))..tostring(currWidth)
  987.                     tPoint:rename("widthValue", widthValueLabel)
  988.                     tPoint:flash("resetWidth", 0.1)
  989.                 end
  990.                 tPoint:add(resetWidthLabel, resetWidthFunc, 6, 9, 10, 9, colours.grey, colours.green, colours.white, colours.white)
  991.                
  992.                 local heightLabel = {
  993.                     "Height",
  994.                     label = "height",
  995.                 }
  996.                 tPoint:add(heightLabel, nil, 6, 11, 10, 11, colours.black, colours.black, colours.white, colours.white)
  997.                 local heightValueLabel = {
  998.                     " 19",
  999.                     label = "heightValue",
  1000.                 }
  1001.                 tPoint:add(heightValueLabel, nil, 7, 12, 9, 12, colours.black, colours.black, colours.white, colours.white)
  1002.                 local decreaseHeightLabel = {
  1003.                     "<<",
  1004.                     label = "decreaseHeight",
  1005.                 }
  1006.                 local function decreaseHeightFunc()
  1007.                     local currWidth, currHeight = programRedirect.getSize()
  1008.                     currHeight = math.max(1, currHeight - 1)
  1009.                     programRedirect.setSize(currWidth, currHeight)
  1010.                     programRedirect.setOffset(nil, -(math.floor(currHeight*9/2)))
  1011.                     toolbarRedirect.setOffset(nil, -(math.floor(currHeight*9/2)) + (currHeight+1)*9)
  1012.                     resumeThread(programThread, "term_resize")
  1013.                     heightValueLabel[1] = string.rep(" ", 3 - string.len(currHeight))..tostring(currHeight)
  1014.                     tPoint:rename("heightValue", heightValueLabel)
  1015.                     tPoint:flash("decreaseHeight", 0.1)
  1016.                 end
  1017.                 tPoint:add(decreaseHeightLabel, decreaseHeightFunc, 4, 12, 5, 12, colours.grey, colours.green, colours.white, colours.white)
  1018.                 local increaseHeightLabel = {
  1019.                     ">>",
  1020.                     label = "increaseHeight",
  1021.                 }
  1022.                 local function increaseHeightFunc()
  1023.                     local currWidth, currHeight = programRedirect.getSize()
  1024.                     currHeight = math.min(999, currHeight + 1)
  1025.                     programRedirect.setSize(currWidth, currHeight)
  1026.                     programRedirect.setOffset(nil, -(math.floor(currHeight*9/2)))
  1027.                     toolbarRedirect.setOffset(nil, -(math.floor(currHeight*9/2)) + (currHeight+1)*9)
  1028.                     resumeThread(programThread, "term_resize")
  1029.                     heightValueLabel[1] = string.rep(" ", 3 - string.len(currHeight))..tostring(currHeight)
  1030.                     tPoint:rename("heightValue", heightValueLabel)
  1031.                     tPoint:flash("increaseHeight", 0.1)
  1032.                 end
  1033.                 tPoint:add(increaseHeightLabel, increaseHeightFunc, 11, 12, 12, 12, colours.grey, colours.green, colours.white, colours.white)
  1034.                 local resetHeightLabel = {
  1035.                     "RESET",
  1036.                     label = "resetHeight",
  1037.                 }
  1038.                 local function resetHeightFunc()
  1039.                     local currWidth, currHeight = programRedirect.getSize()
  1040.                     currHeight = 19
  1041.                     programRedirect.setSize(currWidth, currHeight)
  1042.                     programRedirect.setOffset(nil, -(math.floor(currHeight*9/2)))
  1043.                     toolbarRedirect.setOffset(nil, -(math.floor(currHeight*9/2)) + (currHeight+1)*9)
  1044.                     resumeThread(programThread, "term_resize")
  1045.                     heightValueLabel[1] = string.rep(" ", 3 - string.len(currHeight))..tostring(currHeight)
  1046.                     tPoint:rename("heightValue", heightValueLabel)
  1047.                     tPoint:flash("resetHeight", 0.1)
  1048.                 end
  1049.                 tPoint:add(resetHeightLabel, resetHeightFunc, 6, 13, 10, 13, colours.grey, colours.green, colours.white, colours.white)
  1050.                
  1051.                 tPoint:run()
  1052.             end
  1053.             local settingThread = createThread(settingFunc, settingRedirect.term)
  1054.            
  1055.             local lastClickX, lastClickY, lastButton = false, false, false
  1056.            
  1057.             local guiElements = {}
  1058.             for i = 2, 13 do
  1059.                 guiElements[i] = false
  1060.             end
  1061.             local eventHandlers = {
  1062.                 glasses_attach = function(event)
  1063.                     programRedirect.setDrawn(true)
  1064.                     toolbarRedirect.setDrawn(true)
  1065.                 end,
  1066.                 glasses_detach = function(event)
  1067.                     programRedirect.setDrawn(false)
  1068.                     toolbarRedirect.setDrawn(false)
  1069.                 end,
  1070.                 glasses_capture = function(event)
  1071.                     capture.setBackground(0xffffff, 0)
  1072.                     capture.toggleGuiElements(guiElements)
  1073.                     capture.setKeyRepeat(true)
  1074.                     programRedirect.setVisible(true)
  1075.                     toolbarRedirect.setVisible(true)
  1076.                     if forceSettingsDrawn then
  1077.                         settingRedirect.setDrawn(true)
  1078.                         forceSettingsDrawn = false
  1079.                     end
  1080.                 end,
  1081.                 glasses_release = function(event)
  1082.                     if not isLocked then
  1083.                         programRedirect.setVisible(false)
  1084.                     end
  1085.                     toolbarRedirect.setVisible(false)
  1086.                     settingRedirect.setDrawn(false)
  1087.                 end,
  1088.                 glasses_chat_command = function(event)
  1089.                     if event[5] == "settings" then
  1090.                         forceSettingsDrawn = true
  1091.                     end
  1092.                 end,
  1093.                 glasses_chat_message = function(event)
  1094.                 end,
  1095.                 glasses_key_down = function(event)
  1096.                     resumeThread(programThread, "key", event[5])
  1097.                     if #string.gsub(event[6], "%c", "") > 0 then
  1098.                         resumeThread(programThread, "char", event[6])
  1099.                     end
  1100.                 end,
  1101.                 glasses_key_up = function(event)
  1102.                     resumeThread(programThread, "key_up", event[5])
  1103.                 end,
  1104.                 glasses_mouse_scroll = function(event)
  1105.                 end,
  1106.                 glasses_mouse_down = function(event)
  1107.                     lastClickX, lastClickY, lastButton = false, false, false
  1108.                 end,
  1109.                 glasses_mouse_up = function(event)
  1110.                     if lastClickX and lastClickY then
  1111.                         resumeThread(programThread, "mouse_up", event[5] + 1, lastClickX, lastClickY)
  1112.                         lastClickX, lastClickY, lastButton = false, false, false
  1113.                     end
  1114.                 end,
  1115.                 glasses_component_mouse_wheel = function(event)
  1116.                     local xPos, yPos = programRedirect.getClick(event[5], event[7], event[8])
  1117.                     if xPos and yPos then
  1118.                         resumeThread(programThread, "mouse_scroll", -event[9]/math.abs(event[9]), xPos, yPos)
  1119.                     end
  1120.                 end,
  1121.                 glasses_component_mouse_down = function(event)
  1122.                     local xPos, yPos = programRedirect.getClick(event[5], event[7], event[8])
  1123.                     if xPos and yPos then
  1124.                         resumeThread(programThread, "mouse_click", event[9] + 1, xPos, yPos)
  1125.                         lastClickX, lastClickY, lastButton = xPos, yPos, event[9] + 1
  1126.                     else
  1127.                         lastClickX, lastClickY, lastButton = false, false, false
  1128.                         xPos, yPos = toolbarRedirect.getClick(event[5], event[7], event[8])
  1129.                         if xPos and yPos then
  1130.                             resumeThread(toolbarThread, "mouse_click", event[9] + 1, xPos, yPos)
  1131.                         else
  1132.                             xPos, yPos = settingRedirect.getClick(event[5], event[7], event[8])
  1133.                             if xPos and yPos then
  1134.                                 resumeThread(settingThread, "mouse_click", event[9] + 1, xPos, yPos)
  1135.                             end
  1136.                         end
  1137.                     end
  1138.                 end,
  1139.                 glasses_component_mouse_up = function(event)
  1140.                     local xPos, yPos = programRedirect.getClick(event[5], event[7], event[8])
  1141.                     if xPos and yPos then
  1142.                         resumeThread(programThread, "mouse_up", event[9] + 1, xPos, yPos)
  1143.                     elseif lastClickX and lastClickY then
  1144.                         resumeThread(programThread, "mouse_up", event[9] + 1, lastClickX, lastClickY)
  1145.                     end
  1146.                     lastClickX, lastClickY, lastButton = false, false, false
  1147.                 end,
  1148.                 glasses_component_mouse_drag = function(event)
  1149.                     if lastClickX and lastClickY and lastButton then
  1150.                         local xPos, yPos = programRedirect.getClick(event[5], event[7], event[8])
  1151.                         if xPos and yPos then
  1152.                             resumeThread(programThread, "mouse_drag", lastButton, xPos, yPos)
  1153.                             lastClickX, lastClickY = xPos, yPos
  1154.                         end
  1155.                     end
  1156.                 end,
  1157.             }
  1158.             local event = {}
  1159.             local handler
  1160.             while true do
  1161.                 handler = eventHandlers[ event[1] ]
  1162.                 if handler then
  1163.                     handler(event)
  1164.                 else
  1165.                     resumeThread(programThread, unpack(event))
  1166.                     resumeThread(toolbarThread, unpack(event))
  1167.                     resumeThread(settingThread, unpack(event))
  1168.                 end
  1169.                 if not programThread.running then
  1170.                     capture.stopCapturing()
  1171.                    
  1172.                     programRedirect.setVisible(false)
  1173.                     programRedirect.term.setBackgroundColour(colours.black)
  1174.                     programRedirect.term.setTextColour(colours.white)
  1175.                     programRedirect.term.clear()
  1176.                     programRedirect.term.setCursorPos(1, 1)
  1177.                    
  1178.                     toolbarRedirect.setVisible(false)
  1179.                    
  1180.                     settingRedirect.setDrawn(false)
  1181.                    
  1182.                     programThread = createThread(fnFile, programRedirect.term)
  1183.                 end
  1184.                 event = coroutine.yield()
  1185.             end
  1186.         end
  1187.     )
  1188. end
  1189.  
  1190. local function setupPlayer(playerUUID)
  1191.     local playerSurface = bridge.getSurfaceByUUID(playerUUID)
  1192.     playerSurface.clear()
  1193.  
  1194.     local player = {
  1195.         capture = bridge.getCaptureControl(playerUUID),
  1196.         programRedirect = newGlassesRedirect(playerSurface, 51, 19, -153, -85, 1, 1),
  1197.         toolbarRedirect = newGlassesRedirect(playerSurface, 3, 1, -9, 95, 5, 1),
  1198.         settingRedirect = newGlassesRedirect(playerSurface, 15, 15, 20, 20, 9, 1),
  1199.     }
  1200.     player.capture.stopCapturing()
  1201.    
  1202.     player.programRedirect.setVisible(false)
  1203.     player.programRedirect.setBezelDrawn(true)
  1204.     player.programRedirect.setDrawn(true)
  1205.    
  1206.     player.toolbarRedirect.setVisible(false)
  1207.     player.toolbarRedirect.setBezelDrawn(true)
  1208.     player.toolbarRedirect.setDrawn(true)
  1209.    
  1210.     player.settingRedirect.setVisible(true)
  1211.     player.settingRedirect.setBezelDrawn(true)
  1212.     player.settingRedirect.setAlignment("LEFT", "TOP")
  1213.    
  1214.     player.thread = newSurfaceHandler(playerUUID, player.capture, player.programRedirect, player.toolbarRedirect, player.settingRedirect)
  1215.  
  1216.     return player
  1217. end
  1218.  
  1219. local players = {}
  1220. local mainTerminalEvents = {
  1221.     char = true,
  1222.     key = true,
  1223.     key_up = true,
  1224.     mouse_click = true,
  1225.     mouse_drag = true,
  1226.     mouse_scroll = true,
  1227.     mouse_up = true,
  1228.     paste = true,
  1229.     term_resize = true,
  1230.     terminate = true,
  1231. }
  1232. local glassesEvents = {
  1233.     glasses_attach = true,
  1234.     glasses_detach = true,
  1235.     glasses_capture = true,
  1236.     glasses_release = true,
  1237.     glasses_chat_command = true,
  1238.     glasses_chat_message = true,
  1239.     glasses_key_down = true,
  1240.     glasses_key_up = true,
  1241.     glasses_mouse_scroll = true,
  1242.     glasses_mouse_down = true,
  1243.     glasses_mouse_up = true,
  1244.     glasses_component_mouse_wheel = true,
  1245.     glasses_component_mouse_down = true,
  1246.     glasses_component_mouse_up = true,
  1247.     glasses_component_mouse_drag = true,
  1248. }
  1249. local function main()
  1250.     local event, eventType
  1251.     local playerUUID, player
  1252.     local exit = false
  1253.     while not exit do
  1254.         event = {coroutine.yield()}
  1255.         eventType = event[1]
  1256.         if glassesEvents[eventType] then
  1257.             playerUUID = event[4]
  1258.             player = players[playerUUID]
  1259.             if not player then
  1260.                 players[playerUUID] = setupPlayer(playerUUID)
  1261.             else
  1262.                 if eventType == "glasses_attach" then
  1263.                     local playerSurface = bridge.getSurfaceByUUID(playerUUID)
  1264.                     player.programRedirect.setSurface(playerSurface)
  1265.                     player.toolbarRedirect.setSurface(playerSurface)
  1266.                     player.settingRedirect.setSurface(playerSurface)
  1267.                 end
  1268.                 local ok, passback = coroutine.resume(player.thread, event)
  1269.                 if not ok then
  1270.                     printError(passback)
  1271.                 end
  1272.             end
  1273.         elseif not mainTerminalEvents[eventType] then
  1274.             for _, player in pairs(players) do
  1275.                 local ok, passback = coroutine.resume(player.thread, event)
  1276.                 if not ok then
  1277.                     printError(passback)
  1278.                 end
  1279.             end
  1280.         elseif eventType == "key" and event[2] == keys.backspace then
  1281.             --clean up maybe
  1282.             exit = true
  1283.         end        
  1284.     end
  1285. end
  1286.  
  1287. local function render()
  1288.     local sync = false
  1289.     while true do
  1290.         for _, player in pairs(players) do
  1291.             if player.programRedirect.hasChanged() then
  1292.                 sync = true
  1293.                 player.programRedirect.reset()
  1294.             end
  1295.             if player.toolbarRedirect.hasChanged() then
  1296.                 sync = true
  1297.                 player.toolbarRedirect.reset()
  1298.             end
  1299.             if player.settingRedirect.hasChanged() then
  1300.                 sync = true
  1301.                 player.settingRedirect.reset()
  1302.             end
  1303.         end
  1304.         if sync then
  1305.             bridge.sync()
  1306.             sync = false
  1307.         end
  1308.         coroutine.yield()
  1309.     end
  1310. end
  1311.  
  1312. for _, playerData in ipairs(bridge.getUsers()) do
  1313.     players[playerData.uuid] = setupPlayer(playerData.uuid)
  1314. end
  1315.  
  1316. parallel.waitForAny(main, render)
  1317.  
  1318. --clean up
  1319. for playerUUID, player in pairs(players) do
  1320.     player.capture.stopCapturing()
  1321.     local playerSurface = bridge.getSurfaceByUUID(playerUUID)
  1322.     playerSurface.clear()
  1323. end
  1324. bridge.sync()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement