Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local version = "GraffitiAPI v1.1"
- -- fields for users
- userFunctions = {}
- userLists = {}
- selectedItems = {}
- userInputs = {}
- --monitor
- monitorSide = "right"
- monitor = nil
- -- texts
- local refreshText = "Refresh"
- local backText = "Back"
- local doneString = "Done"
- -- colors
- local buttonDefaultColor = colors.red
- local buttonPressedColor = colors.lime
- local sliderLowValueColor = colors.red
- local sliderMediumValueColor = colors.yellow
- local sliderHighValueColor = colors.lime
- local inputDefaultColor = colors.white
- local inputPressedColor = colors.yellow
- local listDefaultColor = colors.lightBlue
- local listSelectedColor = colors.orange
- local editorMoveColor = colors.magenta
- local editorScaleColor = colors.pink
- -- Save file
- saveFileName = "Graffiti.sav"
- -- API
- initDone = false
- variableValues = {}
- sliderValues = {}
- -- other
- args = { ... }
- quit = false
- local maxX, maxY = 51, 19
- local out = term
- local outIsTerm = true
- local autoLoadObjects = true
- local changeButtonColor = true
- local screens = {}
- screens.mainScreen = {}
- currentScreen = "mainScreen"
- local sides = { "left", "top", "right", "bottom", "front", "back" }
- function readUserInput(message, isPassword)
- if not outIsTerm then
- print(message)
- end
- if isPassword then
- ret = read("*")
- else
- ret = read()
- end
- return ret
- end
- -- Redirects the input to the computer and lets
- -- the user enter something. The result will be
- -- in the userInputs array with the inputID as the
- -- key.
- function getCursorInput()
- local finished = false
- while not finished do
- event, param, x, y = os.pullEvent()
- if (event == "monitor_touch" and not outIsTerm) then
- mouseButton = 1
- finished = true
- elseif (event == "mouse_click" and outIsTerm) then
- mouseButton = param
- finished = true
- end
- end
- return x, y, mouseButton
- end
- function getUserInput(inputObject)
- if (inputObject == nil or inputObject.objType ~= "Input") then
- return
- end
- x = inputObject.x
- y = inputObject.y
- inputID = inputObject.inputID
- message = inputObject.message
- isPassword = (inputObject.isPassword == nil) and false or inputObject.isPassword
- maxLength = inputObject.maxLength
- existingInput = userInputs[inputID]
- out.setBackgroundColor(colors.black)
- out.setCursorPos(x, y)
- if (existingInput ~= nil) then -- Clear the text on the input object.
- for i = -1, string.len(existingInput) do
- out.write(" ")
- end
- else
- out.write(" ")
- end
- userInputs[inputID] = nil
- if not outIsTerm then
- -- make the input-object yellow
- out.setCursorPos(x, y)
- out.setBackgroundColor(colors.yellow)
- out.write(" ")
- out.setBackgroundColor(colors.black)
- end
- if outIsTerm then
- out.setCursorPos(x + 1, y)
- end
- userInput = readUserInput(message, isPassword)
- if (userInput ~= nil) then
- userInputs[inputID] = userInput
- end
- out.setCursorPos(x, y)
- out.setBackgroundColor(colors.white)
- out.setTextColor(colors.black)
- out.write(" ")
- if (userInput ~= nil and userInput ~= "") then
- if isPassword then
- for i = 1, string.len(userInput) do
- out.write("*")
- end
- else
- out.write(userInput)
- end
- end
- out.write(" ")
- out.setBackgroundColor(colors.black)
- out.setTextColor(colors.white)
- return ret
- end
- -- Checks if dir is a valid direction-string
- function isValidDirection(dir)
- if (dir == "left" or
- dir == "up" or
- dir == "right" or
- dir == "down") then
- return true
- end
- return false
- end
- -- display objects region start --
- function drawPixel(x, y, color)
- out.setCursorPos(x, y)
- out.setBackgroundColor(color)
- out.write(" ")
- end
- function showBox(x, y, width, height, color)
- for row = x, x + width - 1 do
- for col = y, y + height - 1 do
- drawPixel(row, col, color)
- end
- end
- out.setBackgroundColor(colors.black)
- end
- -- Displays the text on the screen.
- function showText(textObject)
- if (textObject.objType ~= "Text") then
- return
- end
- x = textObject.x
- y = textObject.y
- text = textObject.text
- assert(x, "Text: X-coordinate has to be set!")
- assert(y, "Text: Y-coordinate has to be set!")
- out.setCursorPos(x, y)
- out.write(text)
- end
- -- Displays the slider on the screen.
- function showSlider(slider, fillPercentage)
- if (slider == nil or slider.objType ~= "Slider") then
- return
- end
- x = slider.x
- y = slider.y
- length = slider.length
- direction = (isValidDirection(slider.direction)) and slider.direction or "right"
- startSymbol, endSymbol = "<", ">"
- addX, addY = 1, 0 -- Sets the direction of the slider, therefore it could even be diagonal.
- if (direction == "left") then
- addX, addY = -1, 0
- startSymbol, endSymbol = ">", "<"
- out.setCursorPos(x - length, y)
- out.write(endSymbol)
- elseif (direction == "up") then
- addX, addY = 0, -1
- startSymbol, endSymbol = "V", "^"
- out.setCursorPos(x, y - length)
- out.write(endSymbol)
- elseif (direction == "right") then
- addX, addY = 1, 0
- startSymbol, endSymbol = "<", ">"
- out.setCursorPos(x + length, y)
- out.write(endSymbol)
- elseif (direction == "down") then
- addX, addY = 0, 1
- startSymbol, endSymbol = "^", "V"
- out.setCursorPos(x, y + length)
- out.write(endSymbol)
- else -- return if it's not a valid direction, even if I checked it before
- return
- end
- out.setCursorPos(x, y)
- out.write(startSymbol)
- if (fillPercentage ~= nil) then
- if (fillPercentage < 33) then
- sliderColor = sliderLowValueColor
- elseif (fillPercentage > 66) then
- sliderColor = sliderHighValueColor
- else
- sliderColor = sliderMediumValueColor
- end
- filled = math.floor((length / 100) * fillPercentage)
- currentX = x + addX
- currentY = y + addY
- out.setBackgroundColor(sliderColor)
- for i = 1, filled - 1 do
- out.setCursorPos(currentX, currentY)
- out.write(" ")
- --paintutils.drawPixel(currentX, currentY, sliderColor)
- currentX = currentX + addX
- currentY = currentY + addY
- end
- end
- out.setBackgroundColor(colors.black)
- end
- -- Displays the given button on the screen.
- function showButton(button, color)
- if (button == nil or button.objType ~= "Button") then
- return
- end
- x = button.x
- y = button.y
- width = button.width
- height = button.height
- text = button.text
- showBox(x, y, width, height, color)
- -- Tries to center the text in the button.
- textCol = x + math.floor((width - string.len(text)) / 2)
- textRow = y + math.ceil(height / 2) - 1
- out.setCursorPos(textCol, textRow)
- out.setBackgroundColor(color)
- out.write(text)
- out.setBackgroundColor(colors.black)
- end
- -- Displays the input-object (two white spaces)
- function showInput(inputObject)
- if (inputObject == nil or inputObject.objType ~= "Input") then
- return
- end
- inputId = inputObject.inputID
- x = inputObject.x
- y = inputObject.y
- out.setCursorPos(x, y)
- out.setBackgroundColor(inputDefaultColor)
- out.setTextColor(colors.black)
- out.write(" ")
- if (userInputs[inputID] ~= nil) then
- out.write(userInputs[inputID])
- end
- out.write(" ")
- out.setBackgroundColor(colors.black)
- out.setTextColor(colors.white)
- end
- -- Used by "showList" and "showSelector" to
- -- determine how wide the list should be.
- function getLongestString(stringArray)
- if (stringArray == nil or #stringArray == 0) then
- return 0
- end
- ret = 0
- for key, value in pairs(stringArray) do
- length = string.len(value)
- if (length > ret) then
- ret = length
- end
- end
- return ret
- end
- -- Displays a list on the monitor.
- function showList(listObject)
- if (listObject == nil or listObject.objType ~= "List") then
- return
- end
- if (type(listObject.elements) == "string") then
- listObject.elements = { listObject.elements }
- end
- if (#listObject.elements == 1 and userLists[listObject.elements[1]] ~= nil) then
- listObject.elements = userLists[listObject.elements[1]]
- end
- x = listObject.x
- y = listObject.y
- elements = (listObject.elements ~= nil) and listObject.elements or { "empty" }
- width = getLongestString(elements) + 2
- listObject.width = width
- height = #elements
- listObject.height = height
- elements = listObject.elements
- listID = listObject.listID
- isMultiselect = (listObject.isMultiselect ~= nil) and listObject.isMultiselect or false
- showBox(x, y, width, height, listDefaultColor)
- if (selectedItems[listID] == nil and isMultiselect) then
- selectedItems[listID] = { }
- for index, elementKey in ipairs(elements) do
- selectedItems[listID][elementKey] = false
- end
- end
- posY = 0
- for key,element in pairs(elements) do
- out.setCursorPos(x, y + posY)
- if (isMultiselect) then
- if (selectedItems[listID][key] == true) then
- out.setBackgroundColor(listSelectedColor)
- else
- out.setBackgroundColor(listDefaultColor)
- end
- else
- if (selectedItems[listID] == key) then
- out.setBackgroundColor(listSelectedColor)
- else
- out.setBackgroundColor(listDefaultColor)
- end
- end
- out.write(" " .. element .. " ")
- posY = posY + 1
- end
- out.setBackgroundColor(colors.black)
- end
- -- Displays the text with red background colour.
- function showSimpleButton(x, y, text)
- out.setCursorPos(x, y)
- out.setBackgroundColor(colors.red)
- out.write(text)
- out.setBackgroundColor(colors.black)
- end
- -- Displays the "Back"- and "Refresh"-Buttons
- function showDefaultButtons()
- x = maxX - string.len(refreshText) + 1
- showSimpleButton(x, maxY, refreshText)
- showSimpleButton(1, maxY, backText)
- end
- -- display objects region end
- function setVariableValue(varID, value)
- variableValues[varID] = value
- end
- function setSliderValue(sliderID, value)
- sliderValues[sliderID] = value
- end
- -- Loads the values of all variables and sliders
- -- of the current screen.
- function loadObjects()
- for objectID, object in pairs(screens[currentScreen]) do
- objectType = object.objType
- x = object.x
- y = object.y
- if (objectType == "Variable") then
- if (variableValues[object.varID] ~= nil) then
- out.setCursorPos(x, y)
- out.write(variableValues[object.varID])
- end
- elseif (objectType == "Slider") then
- if (sliderValues[object.sliderID] ~= nil) then
- showSlider(object, sliderValues[object.sliderID])
- end
- end
- end
- end
- -- Displays all objects of the selected screen.
- function showScreen(screenID)
- out.clear()
- currentScreen = screenID
- if (currentScreen == "mainScreen") then
- backText = "Quit"
- else
- backText = "Back"
- end
- local objectType
- for sObjectID, sObject in pairs(screens[screenID]) do
- objectType = sObject.objType
- if (objectType == "Button") then
- showButton(sObject, buttonDefaultColor)
- elseif (objectType == "Text") then
- showText(sObject)
- elseif (objectType == "Slider") then
- showSlider(sObject, 0)
- elseif (objectType == "Input") then
- showInput(sObject)
- elseif (objectType == "List") then
- showList(sObject)
- end
- end
- if autoLoadObjects then
- loadObjects()
- end
- showDefaultButtons()
- out.setCursorPos(1, maxY)
- end
- function getObjectDimensions(object)
- if (type(object) ~= "table") then
- return -1, -1, -1, -1
- end
- objectType = object.objType
- left = object.x
- top = object.y
- if (objectType == "Button" or objectType == "List") then
- right = left + object.width - 1
- bottom = top + object.height - 1
- elseif (objectType == "Text") then
- right = left + string.len(object.text) - 1
- bottom = top
- elseif (objectType == "Variable" or objectType == "Input") then
- right = left + 1
- bottom = top
- elseif (objectType == "Slider") then
- direction = object.direction
- length = object.length
- if (direction == "left") then
- left = object.x - length
- top = object.y
- right = object.x
- bottom = top
- elseif (direction == "up") then
- left = object.x
- top = object.y - length
- right = object.x
- bottom = object.y
- elseif (direction == "down") then
- left = object.x
- top = object.y
- right = object.x
- bottom = top + length
- else -- right
- left = object.x
- top = object.y
- right = object.x + length
- bottom = top
- end
- elseif (objectType == "Custom") then -- AddOn
- if (object.canScale or object.canClick) then
- right = left + object.width
- bottom = top + object.height
- else
- right = left
- bottom = top
- end
- else
- right = -1
- bottom = -1
- end
- return left, top, right, bottom
- end
- function findObject(x, y)
- for sObjectID, sObject in pairs(screens[currentScreen]) do
- left, top, right, bottom = getObjectDimensions(sObject)
- if (x >= left and x <= right and y >= top and y <= bottom) then
- return sObjectID, sObject
- end
- end
- return nil, nil
- end
- -- Waits until the user touches the monitor and
- -- if he touched a button, the function stored in
- -- it will be returned.
- function getInput()
- if not initDone then -- Function called the first time.
- loadScreens()
- getOutput()
- maxX, maxY = out.getSize()
- --checkDefaultSize()
- initDone = true
- end
- showScreen(currentScreen)
- while not quit do
- finished = false
- x, y, mouseButton = getCursorInput()
- if (y == maxY) then -- Checking the default buttons
- if (x <= string.len(backText)) then -- "Back"-Button pressed
- if (currentScreen == "mainScreen") then
- out.clear()
- out.setCursorPos(1, 1)
- return "quit"
- else
- if (screens[currentScreen].parentScreen ~= nil) then
- showScreen(screens[currentScreen].parentScreen)
- finished = true
- else
- showScreen("mainScreen")
- finished = true
- end
- end
- elseif (x >= maxX - string.len(refreshText)) then -- "Refresh"-Button pressed
- showScreen(currentScreen)
- finished = true
- end
- end
- sObjectID, sObject = findObject(x, y)
- if (sObjectID ~= nil and sObject ~= nil) then
- objectType = sObject.objType
- if (objectType == "Button") then
- return sObject.param
- elseif (objectType == "Input") then
- getUserInput(sObject)
- elseif (objectType == "List") then
- top = sObject.y
- listID = sObject.listID
- isMultiselect = sObject.isMultiselect
- if isMultiselect then
- if (selectedItems[listID][y - top + 1]) then
- selectedItems[listID][y - top + 1] = false
- else
- selectedItems[listID][y - top + 1] = true
- end
- else
- selectedItems[listID] = y - top + 1
- end
- showList(sObject)
- elseif (objectType == "Custom" and sObject.canClick) then -- AddOn Object
- callAddOn(sObject, "Click")
- end
- end
- end
- end
- function round(number)
- assert(number)
- comma = number % 1
- if comma < 0.5 then
- ret = math.floor(number)
- else
- ret = math.ceil(number)
- end
- return ret
- end
- -- Checks the default-size of the screens
- -- table and adapts all objects to the new size if
- -- the screen-size has changed.
- function checkDefaultSize()
- if (screens["defaultX"] == nil or screens["defaultY"] == nil) then -- Program has been started for the first time.
- screens["defaultX"] = maxX
- screens["defaultY"] = maxY
- elseif (screens["defaultX"] ~= maxX or screens["defaultY"] ~= maxY) then -- Screen-size is different since last program start.
- defaultX = screens["defaultX"]
- defaultY = screens["defaultY"]
- xDiff = maxX - defaultX
- yDiff = maxY - defaultY
- for screenID, screen in pairs(screens) do
- if (type(screen) == "table") then
- for objectID, object in pairs(screen) do
- if (type(object) == "table") then
- objType = object.objType
- x = object.x
- y = object.y
- xPercent = object.xPercent
- yPercent = object.yPercent
- widthPercent = object.widthPercent
- heightPercent = object.heightPercent
- horizontalAlignment = object.horizontalAlignment
- verticalAlignment = object.verticalAlignment
- if (horizontalAlignment == nil or verticalAlignment == nil) then
- horizontalAlignment = "left"
- verticalAlignment = "top"
- screens[screenID][objectID].horizontalAlignment = horizontalAlignment
- screens[screenID][objectID].verticalAlignment = verticalAlignment
- end
- if (horizontalAlignment == "stretch") then -- Stretch object horizontally.
- screens[screenID][objectID].x = round(maxX * xPercent)
- if (objType == "Button") then
- screens[screenID][objectID].width = round(maxX * widthPercent)
- elseif (objType == "Slider" and (direction == "left" or direction == "right")) then
- screens[screenID][objectID].length = round(maxX * object.lengthPercent)
- end
- end
- if (verticalAlignment == "stretch") then
- screens[screenID][objectID].y = round(maxY * yPercent)
- if (objType == "Button") then
- screens[screenID][objectID].height = round(maxY * heightPercent)
- elseif (objType == "Slider" and (direction == "up" or direction == "down")) then
- screens[screenID][objectID].length = round(maxX * object.lengthPercent)
- end
- end
- end
- end
- end
- end
- screens.defaultX = maxX
- screens.defaultY = maxy
- end
- end
- function getOutput()
- if (monitor == nil) then
- local monitorFound = false
- for _, side in pairs(sides) do
- if (peripheral.getType(side) == "monitor") then
- monitor = peripheral.wrap(side)
- monitorFound = true
- out = monitor
- outIsTerm = false
- end
- end
- if not monitorFound then
- out = term
- outIsTerm = true
- end
- else
- out = monitor
- outIsTerm = false
- end
- end
- -- Shows the message on the computer for debugging. Probably my most-used function.
- function debugMessage(message)
- --term.restore()
- print(message)
- --term.redirect(monitor)
- end
- function loadScreens()
- if not fs.exists(saveFileName) then
- error(saveFileName .. " not found!")
- end
- file = fs.open(saveFileName, "r")
- loadString = file.readAll()
- if (loadString ~= nil and loadString ~= "") then
- screens = textutils.unserialize(loadString)
- end
- file.close()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement