Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- OpenUI --
- -- Developed by Hawk --
- -- discord: hwkg --
- -- theres a big manual at the bottom for things you might wanna know if you wanna create your own ui library
- --/REQUIRES/--
- local component = require "component"
- local gpu = component.gpu
- local event = require "event"
- local shell = require "shell"
- local unicode = require "unicode" -- used only for the length function (string.len isnt good for cool utf-8 characters)
- local fs = require "filesystem"
- local w, h = gpu.getResolution()
- -- contains openui
- local API = {}
- -- contains all the ui elements made by openui, you can access it with openui.getUIElements()
- local uiElements = {}
- -- list of used colors generated by chatgpt, you can access them with openui.colors
- local colors = {
- red = 0xFF0000,
- green = 0x00FF00,
- blue = 0x0000FF,
- white = 0xFFFFFF,
- black = 0x000000,
- yellow = 0xFFFF00,
- cyan = 0x00FFFF,
- magenta = 0xFF00FF,
- gray = 0x808080,
- darkGray = 0x404040,
- lightGray = 0xD3D3D3,
- orange = 0xFFA500,
- darkOrange = 0xFF8C00,
- purple = 0x800080,
- pink = 0xFFC0CB,
- darkPink = 0xFF1493,
- brown = 0xA52A2A,
- darkBrown = 0x654321,
- olive = 0x808000,
- darkOlive = 0x556B2F,
- teal = 0x008080,
- darkTeal = 0x004C4C,
- navy = 0x000080,
- maroon = 0x800000,
- silver = 0xC0C0C0,
- lime = 0x00FF00,
- darkLime = 0x32CD32,
- gold = 0xFFD700,
- darkGold = 0xB8860B,
- coral = 0xFF7F50,
- darkCoral = 0xCD5B45,
- beige = 0xF5F5DC,
- darkBeige = 0xD2B48C,
- lavender = 0xE6E6FA,
- darkLavender = 0x7C4C7D,
- turquoise = 0x40E0D0,
- darkTurquoise = 0x00CED1,
- indigo = 0x4B0082,
- darkIndigo = 0x2E0854,
- violet = 0xEE82EE,
- darkViolet = 0x9400D3,
- salmon = 0xFA8072,
- darkSalmon = 0xE9967A,
- khaki = 0xF0E68C,
- darkKhaki = 0xBDB76B,
- plum = 0xDDA0DD,
- darkPlum = 0x8B008B,
- tan = 0xD2B48C,
- darkTan = 0x918151,
- mint = 0xF5FFFA,
- darkMint = 0x98FF98,
- charcoal = 0x36454F,
- darkCharcoal = 0x2F4F4F,
- sienna = 0xA0522D,
- darkSienna = 0x5D3A1A,
- lightBlue = 0xADD8E6,
- darkBlue = 0x00008B,
- lightGreen = 0x90EE90,
- darkGreen = 0x006400,
- lightRed = 0xFF6666,
- darkRed = 0x8B0000,
- lightPurple = 0x9370DB,
- darkPurple = 0x301934,
- lightYellow = 0xFFFFE0,
- darkYellow = 0x9B870C
- }
- -- TODO -- : make the interface and stop using pastebin
- -- a prototype to a interface ill make later
- local args, ops = shell.parse(...)
- if (ops.u) then
- print("attempting download...")
- if (args[1]) then
- if (fs.exists(fs.concat(shell.getWorkingDirectory(), args[1]))) then
- print("downloading latest version to " .. fs.concat(shell.getWorkingDirectory(), args[1]))
- shell.execute("pastebin get 2dBBnQH6 " .. fs.concat(shell.getWorkingDirectory(), args[1]) .. " -f")
- else
- print("no file or folder exists there")
- end
- else
- print("please provide a filename to download to, ex: openui -u openui.lua")
- end
- end
- function setbg(c, b)
- gpu.setBackground(c, b)
- end
- function setfg(c, b)
- gpu.setForeground(c, b)
- end
- --/TEMPLATES/--
- API.templates = {
- --make a exit button at the top right of hte screen
- exitButton = function()
- local newButton = addButton(w, 2, 3, 1) -- make a button at the far right of the screen, with 3 chars in width and 1 in height
- newButton.style.color = colors.red -- make the color red (red in hex)
- newButton.text = "X"
- newButton.style.textColor = colors.black -- make the text black
- newButton.onClick = function()
- -- this function is fired by openui (MUST CALL openui.uiEventHandlers()) when the button is pressed
- os.exit() -- close the program if the buttons clicked
- end
- return newButton
- end
- }
- -- its literally just a simple rectangle with barely any customizability
- function API.addSimpleRect(x1, y1, x2, y2)
- local newRect = {}
- newRect.ElementCheck = true
- newRect.type = "Simple Rect"
- newRect.x1 = x1
- newRect.y1 = y1
- newRect.x2 = x2
- newRect.y2 = y2
- newRect.interactable = false
- newRect.hidden = false
- newRect.style = {
- color = colors.green
- }
- table.insert(uiElements, newRect)
- return newRect
- end
- -- this is a rectangle with customizability for characters of corners and edges
- function API.addAdvRect(x1, y1, x2, y2)
- local newRect = {}
- newRect.ElementCheck = true
- newRect.type = "Advanced Rect"
- newRect.x1 = x1
- newRect.y1 = y1
- newRect.x2 = x2
- newRect.y2 = y2
- newRect.interactable = false
- newRect.hidden = false
- newRect.style = {
- color = colors.green,
- backgroundColor = colors.black,
- TopLeftCornerChar = "┌",
- LeftEdgeChar = "│",
- BottomLeftCornerChar = "└",
- BottomEdgeChar = "─",
- BottomRightCornerChar = "┙",
- RightEdgeChar = "│",
- TopRightCornerChar = "┐",
- TopEdgeChar = "─"
- }
- table.insert(uiElements, newRect)
- return newRect
- end
- -- this uses bresenhams and draws a series of points to form a line, customizable character
- function API.addLine(x1, y1, x2, y2)
- local newLine = {}
- newLine.ElementCheck = true
- newLine.type = "Line"
- newLine.x1 = x1
- newLine.y1 = y1
- newLine.x2 = x2
- newLine.y2 = y2
- newLine.interactable = false
- newLine.hidden = false
- newLine.style = {
- color = colors.green,
- char = "█"
- }
- table.insert(uiElements, newLine)
- return newWire
- end
- -- TODO -- : Add more styles to this, fix the AnchorPoint
- -- this just displays text
- function addLabel(x, y, text)
- local newLabel = {}
- newLabel.ElementCheck = true
- newLabel.type = "Label"
- newLabel.text = text
- newLabel.x = x
- newLabel.y = y
- newLabel.interactable = false
- newLabel.hidden = false
- newLabel.style = {
- id = 1,
- color = colors.white,
- AnchorPoint = 1, -- 1=center, 2=far left, 3=far right
- backgroundColor = colors.darkGreen
- }
- table.insert(uiElements, newLabel)
- return newLabel
- end
- API.addLabel = addLabel -- so it can be used in the api
- -- puts a char at where that x and y is
- function addMarker(x, y)
- local newMarker = {}
- newMarker.ElementCheck = true
- newMarker.type = "Marker"
- newMarker.x = x
- newMarker.y = y
- newMarker.interactable = false
- newMarker.hidden = false
- newMarker.style = {
- color = colors.yellow,
- backgroundColor = colors.black,
- char = "#"
- }
- table.insert(uiElements, newMarker)
- return newMarker
- end
- API.addMarker = addMarker -- so it can be used in the api
- -- TODO -- : fix the hitboxes
- -- its a button, NOTE: MUST CALL openui.uiEventHandlers() IF YOU WANT TO USE THE onClick() EVENT
- function addButton(x, y, w, h)
- local newButton = {}
- newButton.ElementCheck = true -- a simple check to see if its a openui element
- newButton.type = "Button" -- a type for what ui element it is
- newButton.x = x
- newButton.y = y
- newButton.width = w
- newButton.height = h
- newButton.text = ""
- newButton.onClick = function()
- -- fires when its pressed NOTE: MUST CALL openui.uiEventHandlers()
- end
- newButton.hidden = false
- newButton.interactable = true
- newButton.style = {
- id = 1, -- style id, 0=custom, 1=default 2=background
- color = colors.green, -- default green
- textColor = colors.white,
- layerBackgroundColor = colors.darkGreen, -- layer is the layer behind the button in most styles
- layerColor = colors.white,
- AnchorPoint = 1 -- 1=center, 2=top left
- }
- table.insert(uiElements, newButton)
- return newButton
- end
- API.addButton = addButton -- so it can be used in the api
- -- TODO -- : make this not a single character, add more styles
- -- a single character button with builtin toggle functionallity NOTE: MUST CALL openui.uiEventHandlers()
- function addToggleButton(x, y)
- local newToggleButton = {}
- newToggleButton.ElementCheck = true
- newToggleButton.type = "Toggle Button"
- newToggleButton.x = x
- newToggleButton.y = y
- newToggleButton.width = 1
- newToggleButton.height = 1
- newToggleButton.toggle = false
- newToggleButton.onToggle = function(bool) -- NOTE: MUST CALL openui.uiEventHandlers()
- end
- newToggleButton.interactable = true
- newToggleButton.hidden = false
- newToggleButton.style = {
- id = 1
- }
- table.insert(uiElements, newToggleButton)
- return newToggleButton
- end
- API.addToggleButton = addToggleButton -- so it can be used in the api
- -- wipes all ui elements, because they carry on and dont wipe when running different openui instances
- function API.clearUIElements()
- uiElements = {}
- end
- -- just put this here so you dont have to do `require"component".gpu.getResolution()[1]"
- function API.width()
- return w
- end
- -- just put this here so you dont have to do `require"component".gpu.getResolution()[2]"
- function API.height()
- return w
- end
- -- returns the table containing all openui uiElements
- function API.getUIElements()
- return uiElements
- end
- -- resets the foreground and background and clears everything
- function API.clearScreen()
- setbg(colors.black, false)
- setfg(colors.white, false)
- gpu.fill(1, 1, w, h, " ")
- end
- API.colors = colors -- so you can access the colors
- -- you gotta call this whenever something changes in the ui and you want to update it
- function API.draw()
- for _, element in ipairs(uiElements) do -- iterate through all the ui elements
- if (element.ElementCheck == true) then -- ElementCheck is just a simple check to see if its a openui object
- if (not element.hidden) then -- if its hidden you dont wanna render it
- if (element.type == "Button") then
- setbg(element.style.color, false)
- local sx = element.x
- local sy = element.y
- if (element.style.AnchorPoint == 1) then -- logic for centering the button
- sx = element.x - element.width / 2
- sy = element.y - element.height / 2
- end
- if (element.style.id == 1) then -- simplest style
- gpu.fill(sx, sy, element.width, element.height, " ")
- elseif (element.style.id == 2) then -- just with a shadow
- setbg(element.style.layerBackgroundColor, false)
- setfg(element.style.layerColor, false)
- gpu.fill(sx + 1, sy + 1, element.width, element.height, "▓")
- setbg(element.style.color, false)
- gpu.fill(sx, sy, element.width, element.height, " ")
- elseif (element.style.id == 3) then -- shadow and curved outlines
- gpu.set(sx, sy, "╭")
- gpu.set(sx + element.width - 1, sy, "╮")
- gpu.set(sx, sy + element.height - 1, "╰")
- gpu.set(sx + element.width - 1, sy + element.height - 1, "╯")
- gpu.fill(sx + 1, sy, element.width - 2, 1, "─")
- gpu.fill(sx, sy + 1, 1, element.height - 2, "│")
- gpu.fill(sx + 1, sy + element.height - 1, element.width - 2, 1, "─")
- gpu.fill(sx + element.width - 1, sy + 1, 1, element.height - 2, "│")
- setbg(element.style.layerBackgroundColor, false)
- setfg(element.style.layerColor, false)
- gpu.set(sx + 1, sy + element.height, "╰")
- gpu.fill(sx + 2, sy + element.height, element.width - 2, 1, "─")
- gpu.set(sx + element.width, sy + element.height, "╯")
- gpu.set(sx + element.width, sy + 1, "╮")
- gpu.fill(sx + element.width, sy + 2, 1, element.height - 2, "│")
- end
- setbg(element.style.color)
- setfg(element.style.textColor)
- if (element.text ~= "") then
- gpu.set( -- the math is for centering the text on the button
- sx + element.width / 2 - unicode.len(element.text) / 2, -- using unicode.len fixes the issue where box characters counted as 3 characters
- sy + element.height / 2 - 1,
- element.text
- )
- end
- elseif (element.type == "Line") then
- setbg(element.style.color)
- -- this uses bresenhams line algorithm to draw a line
- local x1_ = element.x1
- local x2_ = element.x2
- local y1_ = element.y1
- local y2_ = element.y2
- local dx = math.abs(x2_ - x1_)
- local dy = math.abs(y2_ - y1_)
- local sx = x1_ < x2_ and 1 or -1
- local sy = y1_ < y2_ and 1 or -1
- local err = dx - dy
- while true do
- gpu.set(x1_, y1_, element.style.char)
- if x1_ == x2_ and y1_ == y2_ then
- break
- end
- local e2 = err * 2
- if e2 > -dy then
- err = err - dy
- x1_ = x1_ + sx
- end
- if e2 < dx then
- err = err + dx
- y1_ = y1_ + sy
- end
- end
- elseif (element.type == "Label") then
- setbg(element.style.backgroundColor)
- setfg(element.style.color)
- local sx = element.x
- local sy = element.y
- if (element.AnchorPoint == 1) then
- sx = element.x - unicode.len(element.text) / 2 -- centering it
- elseif (element.AnchorPoint == 3) then
- sx = element.x + unicode.len(element.text) / 2 -- snapping it on the right
- end
- gpu.set(sx, sy, element.text)
- elseif (element.type == "Marker") then
- setbg(element.style.backgroundColor)
- setfg(element.style.color)
- gpu.set(element.x, element.y, element.style.char)
- elseif (element.type == "Toggle Button") then
- if (element.style.id == 1) then
- if (element.toggle) then
- setfg(colors.green)
- else
- setfg(colors.red)
- end
- gpu.set(element.x, element.y, "◉")
- end
- elseif (element.type == "Simple Rect") then
- setbg(element.style.color)
- -- all the min and max is in case x1,y1 is greater than x2,y2 (gpu.fill doesnt like that)
- local minx = math.min(element.x1, element.x2)
- local miny = math.min(element.y1, element.y2)
- local maxx = math.max(element.x1, element.x2)
- local maxy = math.max(element.y1, element.y2)
- gpu.fill(minx, miny, maxx - minx, maxy - miny, " ")
- elseif (element.type == "Advanced Rect") then
- setbg(element.style.backgroundColor)
- setfg(element.style.color)
- -- all the min and max is in case x1,y1 is greater than x2,y2 (gpu.fill doesnt like that)
- local minx = math.min(element.x1, element.x2)
- local miny = math.min(element.y1, element.y2)
- local maxx = math.max(element.x1, element.x2)
- local maxy = math.max(element.y1, element.y2)
- gpu.set(minx, miny, element.style.TopLeftCornerChar)
- gpu.set(minx, maxy, element.style.BottomLeftCornerChar)
- gpu.set(maxx, maxy, element.style.BottomRightCornerChar)
- gpu.set(maxx, miny, element.style.TopRightCornerChar)
- gpu.fill(minx, miny + 1, 1, maxy - miny - 1, element.style.LeftEdgeChar)
- gpu.fill(minx + 1, miny, maxx - minx - 1, 1, element.style.TopEdgeChar)
- gpu.fill(maxx, miny + 1, 1, maxy - miny - 1, element.style.RightEdgeChar)
- gpu.fill(minx + 1, maxy, maxx - minx - 1, 1, element.style.BottomEdgeChar)
- end
- end
- end
- end
- -- reset the colors back to default
- setbg(colors.black)
- setfg(colors.white)
- end
- function API.uiEventHandlers()
- local eventType, _, x, y = event.pull("touch") -- click events
- if eventType == "touch" then
- for _, element in ipairs(uiElements) do -- iterate through all the ui elements
- if (element.interactable) then -- if its interactable
- if (not element.hidden) then -- if its not hidden
- if (element.type == "Button") then
- if (element.style.AnchorPoint == 1) then
- if
- x >= math.floor(element.x - element.width / 2) and
- x <= math.floor(element.x + element.width / 2) and
- y >= math.floor(element.y - element.height / 2) and
- y <= math.floor(element.y + element.height / 2)
- then
- element.onClick()
- end
- else
- if
- x >= element.x and x <= element.x + element.width - 1 and y >= element.y and
- y <= element.y + element.height - 1
- then
- element.onClick()
- end
- end
- end
- if (element.type == "Toggle Button") then
- if (x == element.x and y == element.y) then
- element.onToggle(not element.toggle)
- element.toggle = not element.toggle
- end
- end
- end
- end
- end
- end
- end
- --[[ big ui library manual
- ───────────────────────────
- ┌─GPU
- ├─ gpu can be gotten by doing require("component").gpu
- ├─ the docs to the gpu component are here: https://ocdoc.cil.li/component:gpu
- └─┬SCREEN FUNCTIONS
- ├─ to set a single char you would do gpu.set(x,y,char)
- ├─ to set a string you would do gpu.set(x,y,string)
- ├─┬COLOR
- │ ├─ color works by setting the text color and background before setting the characters
- │ ├─ the color system uses a hex system, ex: 0xFFFFFF is white, 0xFF0000 is red, etc.
- │ ├─ in order to set the background color you would do gpu.setBackground(color)
- │ ├┬ in order to set the text color you would do gpu.setForeground(color)
- │ │└─ NOTE: I recommend setting an alias for these two they get repetitive
- │ └─ colors are restricted by their screens so always use a tier 3
- ├─ if you want to fill in a character completely I recommend setting the background color and filling it with " ", it saves power
- └┬ gpu.fill(x,y,width,height,char)
- └┬ gpu fill works from the top left to the bottom right so you have to do some simple math for centering it
- ┌─EVENTS
- ├─ event docs can be found here https://ocdoc.cil.li/api:event
- ├─ event is a api rather than a component
- ├─ in order to get the event object you can do require("event")
- ├───NOTE: event is something im not to sure in so you might have to refer to the docs──
- ├─┬HOW TO USE EVENTS
- │ └─┬ in openui the only event call is in openui.uiEventHandlers()
- │ ├─ local eventType, _, x, y = event.pull("touch")
- │ ├─ quote from the docs: In driver mode your program needs to register callbacks for events (using event.listen())
- │ │ then it should exit to return execution to the primary program (usually the shell).
- │ │ In primary mode your program does not need to register events,
- │ │ it can handle them directly using event.pull().
- │ │
- │ └─ the code where its at fires whenever the "touch" event is fired (i think)
- └─┬USEFUL EVENTS
- └┬ the only used event in openui is the "Touch event"
- ├─ essentually a onClick event
- └─ params for it are _, x, y
- ]] return API
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement