Advertisement
Encreedem

GraffitiAPI v1.1

Jul 28th, 2013
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.96 KB | None | 0 0
  1. local version = "GraffitiAPI v1.1"
  2.  
  3. -- fields for users
  4. userFunctions = {}
  5. userLists = {}
  6. selectedItems = {}
  7. userInputs = {}
  8.  
  9. --monitor
  10. monitorSide = "right"
  11. monitor = nil
  12.  
  13. -- texts
  14. local refreshText = "Refresh"
  15. local backText = "Back"
  16. local doneString = "Done"
  17.  
  18. -- colors
  19. local buttonDefaultColor = colors.red
  20. local buttonPressedColor = colors.lime
  21. local sliderLowValueColor = colors.red
  22. local sliderMediumValueColor = colors.yellow
  23. local sliderHighValueColor = colors.lime
  24. local inputDefaultColor = colors.white
  25. local inputPressedColor = colors.yellow
  26. local listDefaultColor = colors.lightBlue
  27. local listSelectedColor = colors.orange
  28. local editorMoveColor = colors.magenta
  29. local editorScaleColor = colors.pink
  30.  
  31. -- Save file
  32. saveFileName = "Graffiti.sav"
  33.  
  34. -- API
  35. initDone = false
  36. variableValues = {}
  37. sliderValues = {}
  38.  
  39. -- other
  40. args = { ... }
  41. quit = false
  42. local maxX, maxY = 51, 19
  43. local out = term
  44. local outIsTerm = true
  45. local autoLoadObjects = true
  46. local changeButtonColor = true
  47. local screens = {}
  48. screens.mainScreen = {}
  49. currentScreen = "mainScreen"
  50. local sides = { "left", "top", "right", "bottom", "front", "back" }
  51.  
  52. function readUserInput(message, isPassword)
  53.   if not outIsTerm then
  54.     print(message)
  55.   end
  56.  
  57.   if isPassword  then
  58.     ret = read("*")
  59.   else
  60.     ret = read()
  61.   end
  62.  
  63.   return ret
  64. end
  65.  
  66. -- Redirects the input to the computer and lets
  67. -- the user enter something. The result will be
  68. -- in the userInputs array with the inputID as the
  69. -- key.
  70.  
  71. function getCursorInput()
  72.   local finished = false
  73.  
  74.   while not finished do
  75.     event, param, x, y = os.pullEvent()
  76.    
  77.     if (event == "monitor_touch" and not outIsTerm) then
  78.       mouseButton = 1
  79.       finished = true
  80.     elseif (event == "mouse_click" and outIsTerm) then
  81.       mouseButton = param
  82.       finished = true
  83.     end
  84.   end
  85.  
  86.   return x, y, mouseButton
  87. end
  88.  
  89. function getUserInput(inputObject)
  90.   if (inputObject == nil or inputObject.objType ~= "Input") then
  91.     return
  92.   end
  93.  
  94.   x = inputObject.x
  95.   y = inputObject.y
  96.   inputID = inputObject.inputID
  97.   message = inputObject.message
  98.   isPassword = (inputObject.isPassword == nil) and false or inputObject.isPassword
  99.   maxLength = inputObject.maxLength
  100.  
  101.   existingInput = userInputs[inputID]
  102.   out.setBackgroundColor(colors.black)
  103.   out.setCursorPos(x, y)
  104.   if (existingInput ~= nil) then -- Clear the text on the input object.
  105.     for i = -1, string.len(existingInput) do
  106.       out.write(" ")
  107.     end
  108.   else
  109.     out.write("  ")
  110.   end
  111.   userInputs[inputID] = nil
  112.  
  113.   if not outIsTerm then
  114.     -- make the input-object yellow
  115.     out.setCursorPos(x, y)
  116.     out.setBackgroundColor(colors.yellow)
  117.     out.write("  ")
  118.     out.setBackgroundColor(colors.black)
  119.   end
  120.  
  121.   if outIsTerm then
  122.     out.setCursorPos(x + 1, y)
  123.   end
  124.  
  125.   userInput = readUserInput(message, isPassword)
  126.   if (userInput ~= nil) then
  127.     userInputs[inputID] = userInput
  128.   end
  129.  
  130.   out.setCursorPos(x, y)
  131.   out.setBackgroundColor(colors.white)
  132.   out.setTextColor(colors.black)
  133.  
  134.   out.write(" ")
  135.   if (userInput ~= nil and userInput ~= "") then
  136.     if isPassword then
  137.       for i = 1, string.len(userInput) do
  138.         out.write("*")
  139.       end
  140.     else
  141.       out.write(userInput)
  142.     end
  143.   end
  144.  
  145.   out.write(" ")
  146.   out.setBackgroundColor(colors.black)
  147.   out.setTextColor(colors.white)
  148.  
  149.   return ret
  150. end
  151.  
  152. -- Checks if dir is a valid direction-string
  153. function isValidDirection(dir)
  154.   if (dir == "left" or
  155.       dir == "up" or
  156.       dir == "right" or
  157.       dir == "down") then
  158.     return true
  159.   end
  160.  
  161.   return false
  162. end
  163.  
  164. -- display objects region start --
  165.  
  166. function drawPixel(x, y, color)
  167.   out.setCursorPos(x, y)
  168.   out.setBackgroundColor(color)
  169.   out.write(" ")
  170. end
  171.  
  172. function showBox(x, y, width, height, color)
  173.   for row = x, x + width - 1 do
  174.     for col = y, y + height - 1 do
  175.       drawPixel(row, col, color)
  176.     end
  177.   end
  178.  
  179.   out.setBackgroundColor(colors.black)
  180. end
  181.  
  182. -- Displays the text on the screen.
  183. function showText(textObject)
  184.   if (textObject.objType ~= "Text") then
  185.     return
  186.   end
  187.  
  188.   x = textObject.x
  189.   y = textObject.y
  190.   text = textObject.text
  191.   assert(x, "Text: X-coordinate has to be set!")
  192.   assert(y, "Text: Y-coordinate has to be set!")
  193.  
  194.   out.setCursorPos(x, y)
  195.   out.write(text)
  196. end
  197.  
  198. -- Displays the slider on the screen.
  199. function showSlider(slider, fillPercentage)
  200.   if (slider == nil or slider.objType ~= "Slider") then
  201.     return
  202.   end
  203.  
  204.   x = slider.x
  205.   y = slider.y
  206.   length = slider.length
  207.   direction = (isValidDirection(slider.direction)) and slider.direction or "right"
  208.  
  209.   startSymbol, endSymbol = "<", ">"
  210.   addX, addY = 1, 0 -- Sets the direction of the slider, therefore it could even be diagonal.
  211.  
  212.   if (direction == "left") then
  213.     addX, addY = -1, 0
  214.     startSymbol, endSymbol = ">", "<"
  215.     out.setCursorPos(x - length, y)
  216.     out.write(endSymbol)
  217.   elseif (direction == "up") then
  218.     addX, addY = 0, -1
  219.     startSymbol, endSymbol = "V", "^"
  220.     out.setCursorPos(x, y - length)
  221.     out.write(endSymbol)
  222.   elseif (direction == "right") then
  223.     addX, addY = 1, 0
  224.     startSymbol, endSymbol = "<", ">"
  225.     out.setCursorPos(x + length, y)
  226.     out.write(endSymbol)
  227.   elseif (direction == "down") then
  228.     addX, addY = 0, 1
  229.     startSymbol, endSymbol = "^", "V"
  230.     out.setCursorPos(x, y + length)
  231.     out.write(endSymbol)
  232.   else -- return if it's not a valid direction, even if I checked it before
  233.     return
  234.   end
  235.  
  236.   out.setCursorPos(x, y)
  237.   out.write(startSymbol)
  238.  
  239.   if (fillPercentage ~= nil) then
  240.     if (fillPercentage < 33) then
  241.       sliderColor = sliderLowValueColor
  242.     elseif (fillPercentage > 66) then
  243.       sliderColor = sliderHighValueColor
  244.     else
  245.       sliderColor = sliderMediumValueColor
  246.     end
  247.    
  248.     filled = math.floor((length / 100) * fillPercentage)
  249.     currentX = x + addX
  250.     currentY = y + addY
  251.    
  252.     out.setBackgroundColor(sliderColor)
  253.     for i = 1, filled - 1 do
  254.       out.setCursorPos(currentX, currentY)
  255.       out.write(" ")
  256.       --paintutils.drawPixel(currentX, currentY, sliderColor)
  257.       currentX = currentX + addX
  258.       currentY = currentY + addY
  259.     end
  260.   end
  261.  
  262.   out.setBackgroundColor(colors.black)
  263. end
  264.  
  265. -- Displays the given button on the screen.
  266. function showButton(button, color)
  267.   if (button == nil or button.objType ~= "Button") then
  268.     return
  269.   end
  270.  
  271.   x = button.x
  272.   y = button.y
  273.   width = button.width
  274.   height = button.height
  275.   text = button.text
  276.  
  277.   showBox(x, y, width, height, color)
  278.  
  279.   -- Tries to center the text in the button.
  280.   textCol = x + math.floor((width - string.len(text)) / 2)
  281.   textRow = y + math.ceil(height / 2) - 1
  282.   out.setCursorPos(textCol, textRow)
  283.   out.setBackgroundColor(color)
  284.   out.write(text)
  285.  
  286.   out.setBackgroundColor(colors.black)
  287. end
  288.  
  289. -- Displays the input-object (two white spaces)
  290. function showInput(inputObject)
  291.   if (inputObject == nil or inputObject.objType ~= "Input") then
  292.     return
  293.   end
  294.  
  295.   inputId = inputObject.inputID
  296.   x = inputObject.x
  297.   y = inputObject.y
  298.  
  299.   out.setCursorPos(x, y)
  300.   out.setBackgroundColor(inputDefaultColor)
  301.   out.setTextColor(colors.black)
  302.   out.write(" ")
  303.   if (userInputs[inputID] ~= nil) then
  304.     out.write(userInputs[inputID])
  305.   end
  306.   out.write(" ")
  307.  
  308.   out.setBackgroundColor(colors.black)
  309.   out.setTextColor(colors.white)
  310. end
  311.  
  312. -- Used by "showList" and "showSelector" to
  313. -- determine how wide the list should be.
  314. function getLongestString(stringArray)
  315.   if (stringArray == nil or #stringArray == 0) then
  316.     return 0
  317.   end
  318.  
  319.   ret = 0
  320.  
  321.   for key, value in pairs(stringArray) do
  322.     length = string.len(value)
  323.     if (length > ret) then
  324.       ret = length
  325.     end
  326.   end
  327.  
  328.   return ret
  329. end
  330.  
  331. -- Displays a list on the monitor.
  332. function showList(listObject)
  333.   if (listObject == nil or listObject.objType ~= "List") then
  334.     return
  335.   end
  336.  
  337.   if (type(listObject.elements) == "string") then
  338.     listObject.elements = { listObject.elements }
  339.   end
  340.  
  341.   if (#listObject.elements == 1 and userLists[listObject.elements[1]] ~= nil) then
  342.     listObject.elements = userLists[listObject.elements[1]]
  343.   end
  344.  
  345.   x = listObject.x
  346.   y = listObject.y
  347.   elements = (listObject.elements ~= nil) and listObject.elements or { "empty" }
  348.   width = getLongestString(elements) + 2
  349.   listObject.width = width
  350.   height = #elements
  351.   listObject.height = height
  352.   elements = listObject.elements
  353.   listID = listObject.listID
  354.   isMultiselect = (listObject.isMultiselect ~= nil) and listObject.isMultiselect or false
  355.  
  356.   showBox(x, y, width, height, listDefaultColor)
  357.  
  358.   if (selectedItems[listID] == nil and isMultiselect) then
  359.     selectedItems[listID] = {  }
  360.     for index, elementKey in ipairs(elements) do
  361.       selectedItems[listID][elementKey] = false
  362.     end
  363.   end
  364.  
  365.   posY = 0
  366.   for key,element in pairs(elements) do
  367.     out.setCursorPos(x, y + posY)
  368.    
  369.     if (isMultiselect) then
  370.       if (selectedItems[listID][key] == true) then
  371.         out.setBackgroundColor(listSelectedColor)
  372.       else
  373.         out.setBackgroundColor(listDefaultColor)
  374.       end
  375.     else
  376.       if (selectedItems[listID] == key) then
  377.         out.setBackgroundColor(listSelectedColor)
  378.       else
  379.         out.setBackgroundColor(listDefaultColor)
  380.       end
  381.     end
  382.    
  383.     out.write(" " .. element .. " ")
  384.     posY = posY + 1
  385.   end
  386.  
  387.   out.setBackgroundColor(colors.black)
  388. end
  389.  
  390. -- Displays the text with red background colour.
  391. function showSimpleButton(x, y, text)
  392.   out.setCursorPos(x, y)
  393.   out.setBackgroundColor(colors.red)
  394.   out.write(text)
  395.   out.setBackgroundColor(colors.black)
  396. end
  397.  
  398. -- Displays the "Back"- and "Refresh"-Buttons
  399. function showDefaultButtons()
  400.   x = maxX - string.len(refreshText) + 1
  401.   showSimpleButton(x, maxY, refreshText)
  402.  
  403.   showSimpleButton(1, maxY, backText)
  404. end
  405.  
  406. -- display objects region end
  407.  
  408. function setVariableValue(varID, value)
  409.   variableValues[varID] = value
  410. end
  411.  
  412. function setSliderValue(sliderID, value)
  413.   sliderValues[sliderID] = value
  414. end
  415.  
  416. -- Loads the values of all variables and sliders
  417. -- of the current screen.
  418. function loadObjects()
  419.   for objectID, object in pairs(screens[currentScreen]) do
  420.     objectType = object.objType
  421.     x = object.x
  422.     y = object.y
  423.    
  424.     if (objectType == "Variable") then
  425.       if (variableValues[object.varID] ~= nil) then
  426.         out.setCursorPos(x, y)
  427.         out.write(variableValues[object.varID])
  428.       end
  429.     elseif (objectType == "Slider") then
  430.       if (sliderValues[object.sliderID] ~= nil) then
  431.         showSlider(object, sliderValues[object.sliderID])
  432.       end
  433.     end
  434.   end
  435. end
  436.  
  437. -- Displays all objects of the selected screen.
  438. function showScreen(screenID)
  439.   out.clear()
  440.   currentScreen = screenID
  441.  
  442.   if (currentScreen == "mainScreen") then
  443.     backText = "Quit"
  444.   else
  445.     backText = "Back"
  446.   end
  447.  
  448.   local objectType
  449.  
  450.   for sObjectID, sObject in pairs(screens[screenID]) do
  451.     objectType = sObject.objType
  452.    
  453.     if (objectType == "Button") then
  454.       showButton(sObject, buttonDefaultColor)
  455.     elseif (objectType == "Text") then
  456.       showText(sObject)
  457.     elseif (objectType == "Slider") then
  458.       showSlider(sObject, 0)
  459.     elseif (objectType == "Input") then
  460.       showInput(sObject)
  461.     elseif (objectType == "List") then
  462.       showList(sObject)
  463.     end
  464.   end
  465.  
  466.   if autoLoadObjects then
  467.     loadObjects()
  468.   end
  469.  
  470.   showDefaultButtons()
  471.  
  472.   out.setCursorPos(1, maxY)
  473. end
  474.  
  475. function getObjectDimensions(object)
  476.   if (type(object) ~= "table") then
  477.     return -1, -1, -1, -1
  478.   end
  479.  
  480.   objectType = object.objType
  481.   left = object.x
  482.   top = object.y
  483.  
  484.   if (objectType == "Button" or objectType == "List") then
  485.     right = left + object.width - 1
  486.     bottom = top + object.height - 1
  487.   elseif (objectType == "Text") then
  488.     right = left + string.len(object.text) - 1
  489.     bottom = top
  490.   elseif (objectType == "Variable" or objectType == "Input") then
  491.     right = left + 1
  492.     bottom = top
  493.   elseif (objectType == "Slider") then
  494.     direction = object.direction
  495.     length = object.length
  496.    
  497.     if (direction == "left") then
  498.       left = object.x - length
  499.       top = object.y
  500.       right = object.x
  501.       bottom = top
  502.     elseif (direction == "up") then
  503.       left = object.x
  504.       top = object.y - length
  505.       right = object.x
  506.       bottom = object.y
  507.     elseif (direction == "down") then
  508.       left = object.x
  509.       top = object.y
  510.       right = object.x
  511.       bottom = top + length
  512.     else -- right
  513.       left = object.x
  514.       top = object.y
  515.       right = object.x + length
  516.       bottom = top
  517.     end
  518.   elseif (objectType == "Custom") then -- AddOn
  519.     if (object.canScale or object.canClick) then
  520.       right = left + object.width
  521.       bottom = top + object.height
  522.     else
  523.       right = left
  524.       bottom = top
  525.     end
  526.   else
  527.     right = -1
  528.     bottom = -1
  529.   end
  530.  
  531.   return left, top, right, bottom
  532. end
  533.  
  534. function findObject(x, y)
  535.   for sObjectID, sObject in pairs(screens[currentScreen]) do
  536.     left, top, right, bottom = getObjectDimensions(sObject)
  537.    
  538.     if (x >= left and x <= right and y >= top and y <= bottom) then
  539.       return sObjectID, sObject
  540.     end
  541.   end
  542.  
  543.   return nil, nil
  544. end
  545.  
  546. -- Waits until the user touches the monitor and
  547. -- if he touched a button, the function stored in
  548. -- it will be returned.
  549. function getInput()
  550.   if not initDone then -- Function called the first time.
  551.     loadScreens()
  552.     getOutput()
  553.     maxX, maxY = out.getSize()
  554.     --checkDefaultSize()
  555.     initDone = true
  556.   end
  557.  
  558.   showScreen(currentScreen)
  559.  
  560.   while not quit do
  561.     finished = false
  562.     x, y, mouseButton = getCursorInput()
  563.    
  564.     if (y == maxY) then -- Checking the default buttons
  565.       if (x <= string.len(backText)) then -- "Back"-Button pressed
  566.         if (currentScreen == "mainScreen") then
  567.           out.clear()
  568.           out.setCursorPos(1, 1)
  569.           return "quit"
  570.         else
  571.           if (screens[currentScreen].parentScreen ~= nil) then
  572.             showScreen(screens[currentScreen].parentScreen)
  573.             finished = true
  574.           else
  575.             showScreen("mainScreen")
  576.             finished = true
  577.           end
  578.         end
  579.       elseif (x >= maxX - string.len(refreshText)) then -- "Refresh"-Button pressed
  580.         showScreen(currentScreen)
  581.         finished = true
  582.       end
  583.     end
  584.    
  585.     sObjectID, sObject = findObject(x, y)
  586.     if (sObjectID ~= nil and sObject ~= nil) then
  587.       objectType = sObject.objType
  588.      
  589.       if (objectType == "Button") then
  590.         return sObject.param
  591.       elseif (objectType == "Input") then
  592.         getUserInput(sObject)
  593.       elseif (objectType == "List") then
  594.         top = sObject.y
  595.         listID = sObject.listID
  596.         isMultiselect = sObject.isMultiselect
  597.        
  598.         if isMultiselect then
  599.           if (selectedItems[listID][y - top + 1]) then
  600.             selectedItems[listID][y - top + 1] = false
  601.           else
  602.             selectedItems[listID][y - top + 1] = true
  603.           end
  604.         else
  605.           selectedItems[listID] = y - top + 1
  606.         end
  607.        
  608.         showList(sObject)
  609.       elseif (objectType == "Custom" and sObject.canClick) then -- AddOn Object
  610.         callAddOn(sObject, "Click")
  611.       end
  612.     end
  613.   end
  614. end
  615.  
  616. function round(number)
  617.   assert(number)
  618.   comma = number % 1
  619.   if comma < 0.5 then
  620.     ret = math.floor(number)
  621.   else
  622.     ret = math.ceil(number)
  623.   end
  624.  
  625.   return ret
  626. end
  627.  
  628. -- Checks the default-size of the screens
  629. -- table and adapts all objects to the new size if
  630. -- the screen-size has changed.
  631. function checkDefaultSize()
  632.   if (screens["defaultX"] == nil or screens["defaultY"] == nil) then -- Program has been started for the first time.
  633.     screens["defaultX"] = maxX
  634.     screens["defaultY"] = maxY
  635.   elseif (screens["defaultX"] ~= maxX or screens["defaultY"] ~= maxY) then -- Screen-size is different since last program start.
  636.     defaultX = screens["defaultX"]
  637.     defaultY = screens["defaultY"]
  638.     xDiff = maxX - defaultX
  639.     yDiff = maxY - defaultY
  640.    
  641.     for screenID, screen in pairs(screens) do
  642.       if (type(screen) == "table") then
  643.         for objectID, object in pairs(screen) do
  644.           if (type(object) == "table") then
  645.             objType = object.objType
  646.             x = object.x
  647.             y = object.y
  648.             xPercent = object.xPercent
  649.             yPercent = object.yPercent
  650.             widthPercent = object.widthPercent
  651.             heightPercent = object.heightPercent
  652.             horizontalAlignment = object.horizontalAlignment
  653.             verticalAlignment = object.verticalAlignment
  654.             if (horizontalAlignment == nil or verticalAlignment == nil) then
  655.               horizontalAlignment = "left"
  656.               verticalAlignment = "top"
  657.               screens[screenID][objectID].horizontalAlignment = horizontalAlignment
  658.               screens[screenID][objectID].verticalAlignment = verticalAlignment
  659.             end
  660.            
  661.             if (horizontalAlignment == "stretch") then -- Stretch object horizontally.
  662.               screens[screenID][objectID].x = round(maxX * xPercent)
  663.               if (objType == "Button") then
  664.                 screens[screenID][objectID].width = round(maxX * widthPercent)
  665.               elseif (objType == "Slider" and (direction == "left" or direction == "right")) then
  666.                 screens[screenID][objectID].length = round(maxX * object.lengthPercent)
  667.               end
  668.             end
  669.            
  670.             if (verticalAlignment == "stretch") then
  671.               screens[screenID][objectID].y = round(maxY * yPercent)
  672.               if (objType == "Button") then
  673.                 screens[screenID][objectID].height = round(maxY * heightPercent)
  674.               elseif (objType == "Slider" and (direction == "up" or direction == "down")) then
  675.                 screens[screenID][objectID].length = round(maxX * object.lengthPercent)
  676.               end
  677.             end
  678.           end
  679.         end
  680.       end
  681.     end
  682.    
  683.     screens.defaultX = maxX
  684.     screens.defaultY = maxy
  685.   end
  686. end
  687.  
  688. function getOutput()
  689.   if (monitor == nil) then
  690.     local monitorFound = false
  691.     for _, side in pairs(sides) do
  692.       if (peripheral.getType(side) == "monitor") then
  693.         monitor = peripheral.wrap(side)
  694.         monitorFound = true
  695.         out = monitor
  696.         outIsTerm = false
  697.       end
  698.     end
  699.    
  700.     if not monitorFound then
  701.       out = term
  702.       outIsTerm = true
  703.     end
  704.   else
  705.     out = monitor
  706.     outIsTerm = false
  707.   end
  708. end
  709.  
  710. -- Shows the message on the computer for debugging. Probably my most-used function.
  711. function debugMessage(message)
  712.   --term.restore()
  713.   print(message)
  714.   --term.redirect(monitor)
  715. end
  716.  
  717. function loadScreens()
  718.   if not fs.exists(saveFileName) then
  719.     error(saveFileName .. " not found!")
  720.   end
  721.  
  722.   file = fs.open(saveFileName, "r")
  723.   loadString = file.readAll()
  724.   if (loadString ~= nil and loadString ~= "") then
  725.     screens = textutils.unserialize(loadString)
  726.   end
  727.   file.close()
  728. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement