Lots of shit
This commit is contained in:
parent
f1b31c5c3e
commit
42b7d798e1
20
apps.json
20
apps.json
|
@ -1,16 +1,14 @@
|
|||
{
|
||||
"Clicker" : {
|
||||
"version" : 2,
|
||||
"Clicker": {
|
||||
"version": 2,
|
||||
"colour": "brown",
|
||||
"url" : "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/Clicker.lua",
|
||||
"path" : "apps/Clicker.lua"
|
||||
"url": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/apps/Clicker.lua",
|
||||
"path": "apps/Clicker.lua"
|
||||
},
|
||||
|
||||
"Tester" : {
|
||||
"version" : 1,
|
||||
"Tester": {
|
||||
"version": 1,
|
||||
"colour": "red",
|
||||
"url" : "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/tester.lua",
|
||||
"path" : "apps/Tester.lua"
|
||||
"url": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/apps/Tester.lua",
|
||||
"path": "apps/Tester.lua"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
233
base_apps/eCash.lua
Normal file
233
base_apps/eCash.lua
Normal file
|
@ -0,0 +1,233 @@
|
|||
local basalt = require("/lib/basalt")
|
||||
local libcredit = require("/lib/libcredit_mobile")
|
||||
|
||||
local username = ""
|
||||
local main = basalt.getMainFrame()
|
||||
|
||||
function show_notification(status)
|
||||
local notifFrame = main:addFrame():setSize(26, 4):setBackground(colours.grey)
|
||||
|
||||
notifFrame:addButton():setText("Dismiss"):setSize(26, 1):setPosition(1, 4):onClick(function()
|
||||
notifFrame:destroy()
|
||||
end)
|
||||
|
||||
local label = notifFrame:addLabel()
|
||||
|
||||
if status then
|
||||
label
|
||||
:setText("Transaction successful")
|
||||
:setPosition(4, 2)
|
||||
:setBackground(colours.lime)
|
||||
:setForeground(colours.black)
|
||||
notifFrame:setBackground(colours.lime)
|
||||
else
|
||||
label
|
||||
:setText("Transaction unsuccessful")
|
||||
:setPosition(3, 2)
|
||||
:setBackground(colours.red)
|
||||
:setForeground(colours.white)
|
||||
notifFrame:setBackground(colours.red)
|
||||
end
|
||||
end
|
||||
|
||||
local appFrame = main:addFrame():setVisible(false):setSize(26, 19):setBackground(colours.white)
|
||||
|
||||
local requestFrame = main:addFrame():setVisible(false):setSize(26, 19):setBackground(colours.white)
|
||||
|
||||
requestFrame:addLabel():setText("Username: "):setPosition(2, 6):setSize(10, 1):setForeground(colours.black)
|
||||
|
||||
local request_user_input = requestFrame
|
||||
:addInput()
|
||||
:setPosition(12, 6)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
requestFrame:addLabel():setText("Amount: "):setPosition(2, 8):setSize(10, 1):setForeground(colours.black)
|
||||
|
||||
local request_amount_input = requestFrame
|
||||
:addInput()
|
||||
:setPosition(12, 8)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
requestFrame
|
||||
:addButton()
|
||||
:setText("Request")
|
||||
:setPosition(7, 15)
|
||||
:setSize(12, 3)
|
||||
:setBackground(colours.blue)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function(request_btn)
|
||||
request_btn:setBackground(colours.black)
|
||||
request_btn:setText("Pending")
|
||||
local target_usr = request_user_input:getText()
|
||||
local target_amount = request_amount_input:getText()
|
||||
target_amount = tonumber(target_amount:match("^%d+$"))
|
||||
|
||||
if not target_amount or target_amount <= 0 then
|
||||
show_notification(false)
|
||||
request_btn:setBackground(colours.blue)
|
||||
request_btn:setText("Request")
|
||||
return
|
||||
end
|
||||
|
||||
libcredit.addTransaction(target_usr, target_amount, username .. " [ecash]", username, function(successful)
|
||||
request_btn:setBackground(colours.blue)
|
||||
request_btn:setText("Request")
|
||||
show_notification(successful)
|
||||
refresh_ui()
|
||||
appFrame:setVisible(true)
|
||||
requestFrame:setVisible(false)
|
||||
|
||||
if successful then
|
||||
request_amount_input:setText("")
|
||||
request_user_input:setText("")
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
local sendFrame = main:addFrame():setVisible(false):setSize(26, 19):setBackground(colours.white)
|
||||
|
||||
sendFrame:addLabel():setText("Recipient: "):setPosition(2, 6):setSize(10, 1):setForeground(colours.black)
|
||||
|
||||
local send_user_input = sendFrame
|
||||
:addInput()
|
||||
:setPosition(12, 6)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
sendFrame:addLabel():setText("Amount: "):setPosition(2, 8):setSize(10, 1):setForeground(colours.black)
|
||||
|
||||
local send_amount_input = sendFrame
|
||||
:addInput()
|
||||
:setPosition(12, 8)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
sendFrame
|
||||
:addButton()
|
||||
:setText("Send")
|
||||
:setPosition(7, 15)
|
||||
:setSize(12, 3)
|
||||
:setBackground(colours.blue)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function(send_btn)
|
||||
send_btn:setBackground(colours.black)
|
||||
send_btn:setText("Pending")
|
||||
local target_usr = send_user_input:getText()
|
||||
local target_amount = send_amount_input:getText()
|
||||
target_amount = tonumber(target_amount:match("^%d+$"))
|
||||
|
||||
if not target_amount or target_amount <= 0 then
|
||||
show_notification(false)
|
||||
send_btn:setBackground(colours.blue)
|
||||
send_btn:setText("Send")
|
||||
return
|
||||
end
|
||||
|
||||
libcredit.addTransaction(username, target_amount, target_usr .. " [ecash]", target_usr, function(successful)
|
||||
send_btn:setBackground(colours.blue)
|
||||
send_btn:setText("Send")
|
||||
show_notification(successful)
|
||||
refresh_ui()
|
||||
appFrame:setVisible(true)
|
||||
sendFrame:setVisible(false)
|
||||
|
||||
if successful then
|
||||
send_amount_input:setText("")
|
||||
send_user_input:setText("")
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
local cash_label =
|
||||
appFrame:addBigFont():setText("__G"):setPosition(6, 2):setBackground(colours.white):setForeground(colours.black)
|
||||
|
||||
local request_cash = appFrame
|
||||
:addButton()
|
||||
:setText("Request")
|
||||
:setPosition(8, 10)
|
||||
:setSize(10, 3)
|
||||
:setBackground(colours.green)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
requestFrame:setVisible(true)
|
||||
appFrame:setVisible(false)
|
||||
end)
|
||||
|
||||
local send_cash = appFrame
|
||||
:addButton()
|
||||
:setText("Send")
|
||||
:setPosition(8, 15)
|
||||
:setSize(10, 3)
|
||||
:setBackground(colours.orange)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
sendFrame:setVisible(true)
|
||||
appFrame:setVisible(false)
|
||||
end)
|
||||
|
||||
function refresh_ui()
|
||||
libcredit.getCredit(username, function(amount)
|
||||
local amount_str = amount .. "G"
|
||||
cash_label:setText(amount_str)
|
||||
|
||||
if #amount_str < 6 then
|
||||
cash_label:setPosition(6 - (#amount_str / 4) - 1, 2)
|
||||
else
|
||||
cash_label:setSize(26, 4)
|
||||
cash_label:setPosition(1, 2)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local login = main:addFrame():setBackground(colours.grey):setPosition(1, 1):setSize(26, 19)
|
||||
|
||||
login:addLabel():setText("Username: "):setPosition(2, 3):setSize(10, 1):setForeground(colours.white)
|
||||
|
||||
local usernameInput = login
|
||||
:addInput()
|
||||
:setPosition(12, 3)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
local loginButton = login
|
||||
:addButton()
|
||||
:setText("Login")
|
||||
:setPosition(9, 15)
|
||||
:setSize(8, 3)
|
||||
:setBackground(colours.blue)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
username = usernameInput:getText()
|
||||
|
||||
if not fs.exists("/.usrcache") then
|
||||
local file = fs.open("/.usrcache", "w")
|
||||
file.write(username)
|
||||
file.close()
|
||||
end
|
||||
|
||||
login:setVisible(false)
|
||||
appFrame:setVisible(true)
|
||||
refresh_ui()
|
||||
end)
|
||||
|
||||
if fs.exists("/.usrcache") then
|
||||
local file = fs.open("/.usrcache", "r")
|
||||
local username = file.readLine()
|
||||
file.close()
|
||||
usernameInput:setText(username)
|
||||
end
|
||||
|
||||
basalt.run()
|
||||
|
265
eCash.lua
265
eCash.lua
|
@ -1,265 +0,0 @@
|
|||
local basalt = require("../lib/basalt")
|
||||
local libcredit = require("../lib/libcredit_mobile")
|
||||
|
||||
local username = ""
|
||||
local main = basalt.getMainFrame()
|
||||
|
||||
function show_notification(status)
|
||||
local notifFrame = main:addFrame()
|
||||
:setSize(26,4)
|
||||
:setBackground(colours.grey)
|
||||
|
||||
notifFrame:addButton()
|
||||
:setText("Dismiss")
|
||||
:setSize(26,1)
|
||||
:setPosition(1,4)
|
||||
:onClick(function()
|
||||
notifFrame:destroy()
|
||||
end)
|
||||
|
||||
local label = notifFrame:addLabel()
|
||||
|
||||
if status then
|
||||
label:setText("Transaction successful")
|
||||
:setPosition(4,2)
|
||||
:setBackground(colours.lime)
|
||||
:setForeground(colours.black)
|
||||
notifFrame:setBackground(colours.lime)
|
||||
else
|
||||
label:setText("Transaction unsuccessful")
|
||||
:setPosition(3,2)
|
||||
:setBackground(colours.red)
|
||||
:setForeground(colours.white)
|
||||
notifFrame:setBackground(colours.red)
|
||||
end
|
||||
end
|
||||
|
||||
local appFrame = main:addFrame()
|
||||
:setVisible(false)
|
||||
:setSize(26,19)
|
||||
:setBackground(colours.white)
|
||||
|
||||
local requestFrame = main:addFrame()
|
||||
:setVisible(false)
|
||||
:setSize(26,19)
|
||||
:setBackground(colours.white)
|
||||
|
||||
|
||||
requestFrame:addLabel()
|
||||
:setText("Username: ")
|
||||
:setPosition(2, 6)
|
||||
:setSize(10, 1)
|
||||
:setForeground(colours.black)
|
||||
|
||||
local request_user_input = requestFrame:addInput()
|
||||
:setPosition(12, 6)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
requestFrame:addLabel()
|
||||
:setText("Amount: ")
|
||||
:setPosition(2, 8)
|
||||
:setSize(10, 1)
|
||||
:setForeground(colours.black)
|
||||
|
||||
local request_amount_input = requestFrame:addInput()
|
||||
:setPosition(12, 8)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
requestFrame:addButton()
|
||||
:setText("Request")
|
||||
:setPosition(7, 15)
|
||||
:setSize(12, 3)
|
||||
:setBackground(colours.blue)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function(request_btn)
|
||||
request_btn:setBackground(colours.black)
|
||||
request_btn:setText("Pending")
|
||||
local target_usr = request_user_input:getText()
|
||||
local target_amount = request_amount_input:getText()
|
||||
target_amount = tonumber(target_amount:match("^%d+$"))
|
||||
|
||||
if not target_amount or target_amount <= 0 then
|
||||
show_notification(false)
|
||||
request_btn:setBackground(colours.blue)
|
||||
request_btn:setText("Request")
|
||||
return
|
||||
end
|
||||
|
||||
libcredit.addTransaction(target_usr, target_amount, username .. " [ecash]", username, function(successful)
|
||||
request_btn:setBackground(colours.blue)
|
||||
request_btn:setText("Request")
|
||||
show_notification(successful)
|
||||
refresh_ui()
|
||||
appFrame:setVisible(true)
|
||||
requestFrame:setVisible(false)
|
||||
|
||||
if successful then
|
||||
request_amount_input:setText("")
|
||||
request_user_input:setText("")
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
local sendFrame = main:addFrame()
|
||||
:setVisible(false)
|
||||
:setSize(26,19)
|
||||
:setBackground(colours.white)
|
||||
|
||||
sendFrame:addLabel()
|
||||
:setText("Recipient: ")
|
||||
:setPosition(2, 6)
|
||||
:setSize(10, 1)
|
||||
:setForeground(colours.black)
|
||||
|
||||
local send_user_input = sendFrame:addInput()
|
||||
:setPosition(12, 6)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
sendFrame:addLabel()
|
||||
:setText("Amount: ")
|
||||
:setPosition(2, 8)
|
||||
:setSize(10, 1)
|
||||
:setForeground(colours.black)
|
||||
|
||||
local send_amount_input = sendFrame:addInput()
|
||||
:setPosition(12, 8)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
sendFrame:addButton()
|
||||
:setText("Send")
|
||||
:setPosition(7, 15)
|
||||
:setSize(12, 3)
|
||||
:setBackground(colours.blue)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function(send_btn)
|
||||
send_btn:setBackground(colours.black)
|
||||
send_btn:setText("Pending")
|
||||
local target_usr = send_user_input:getText()
|
||||
local target_amount = send_amount_input:getText()
|
||||
target_amount = tonumber(target_amount:match("^%d+$"))
|
||||
|
||||
if not target_amount or target_amount <= 0 then
|
||||
show_notification(false)
|
||||
send_btn:setBackground(colours.blue)
|
||||
send_btn:setText("Send")
|
||||
return
|
||||
end
|
||||
|
||||
libcredit.addTransaction(username, target_amount, target_usr .. " [ecash]", target_usr, function(successful)
|
||||
send_btn:setBackground(colours.blue)
|
||||
send_btn:setText("Send")
|
||||
show_notification(successful)
|
||||
refresh_ui()
|
||||
appFrame:setVisible(true)
|
||||
sendFrame:setVisible(false)
|
||||
|
||||
if successful then
|
||||
send_amount_input:setText("")
|
||||
send_user_input:setText("")
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
local cash_label = appFrame:addBigFont()
|
||||
:setText("__G")
|
||||
:setPosition(6,2)
|
||||
:setBackground(colours.white)
|
||||
:setForeground(colours.black)
|
||||
|
||||
local request_cash = appFrame:addButton()
|
||||
:setText("Request")
|
||||
:setPosition(8,10)
|
||||
:setSize(10, 3)
|
||||
:setBackground(colours.green)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
requestFrame:setVisible(true)
|
||||
appFrame:setVisible(false)
|
||||
end)
|
||||
|
||||
local send_cash = appFrame:addButton()
|
||||
:setText("Send")
|
||||
:setPosition(8,15)
|
||||
:setSize(10, 3)
|
||||
:setBackground(colours.orange)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
sendFrame:setVisible(true)
|
||||
appFrame:setVisible(false)
|
||||
end)
|
||||
|
||||
function refresh_ui()
|
||||
libcredit.getCredit(username, function(amount)
|
||||
local amount_str = amount .. "G"
|
||||
cash_label:setText(amount_str)
|
||||
|
||||
if #amount_str < 6 then
|
||||
cash_label:setPosition(6 - (#amount_str / 4) - 1,2)
|
||||
else
|
||||
cash_label:setSize(26,4)
|
||||
cash_label:setPosition(1,2)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local login = main:addFrame()
|
||||
:setBackground(colours.grey)
|
||||
:setPosition(1,1)
|
||||
:setSize(26,19)
|
||||
|
||||
login:addLabel()
|
||||
:setText("Username: ")
|
||||
:setPosition(2, 3)
|
||||
:setSize(10, 1)
|
||||
:setForeground(colours.white)
|
||||
|
||||
local usernameInput = login:addInput()
|
||||
:setPosition(12, 3)
|
||||
:setSize(12, 1)
|
||||
:setBackground(colours.lightGrey)
|
||||
:setForeground(colours.black)
|
||||
:setText("")
|
||||
|
||||
local loginButton = login:addButton()
|
||||
:setText("Login")
|
||||
:setPosition(9, 15)
|
||||
:setSize(8, 3)
|
||||
:setBackground(colours.blue)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
|
||||
|
||||
username = usernameInput:getText()
|
||||
|
||||
if not fs.exists("/.usrcache") then
|
||||
local file = fs.open("/.usrcache","w")
|
||||
file.write(username)
|
||||
file.close()
|
||||
end
|
||||
|
||||
login:setVisible(false)
|
||||
appFrame:setVisible(true)
|
||||
refresh_ui()
|
||||
|
||||
end)
|
||||
|
||||
if fs.exists("/.usrcache") then
|
||||
local file = fs.open("/.usrcache","r")
|
||||
local username = file.readLine()
|
||||
file.close()
|
||||
usernameInput:setText(username)
|
||||
end
|
||||
|
||||
basalt.run()
|
18
lib/basalt/init.lua
Normal file
18
lib/basalt/init.lua
Normal file
|
@ -0,0 +1,18 @@
|
|||
local curDir = fs.getDir(table.pack(...)[2]) or ""
|
||||
|
||||
local defaultPath = package.path
|
||||
if not(packed)then
|
||||
local format = "path;/path/?.lua;/path/?/init.lua;"
|
||||
|
||||
local main = format:gsub("path", curDir)
|
||||
local objFolder = format:gsub("path", curDir.."/objects")
|
||||
local plugFolder = format:gsub("path", curDir.."/plugins")
|
||||
local libFolder = format:gsub("path", curDir.."/libraries")
|
||||
|
||||
|
||||
package.path = main..objFolder..plugFolder..libFolder..defaultPath
|
||||
end
|
||||
local Basalt = require("main")
|
||||
package.path = defaultPath
|
||||
|
||||
return Basalt
|
250
lib/basalt/libraries/basaltDraw.lua
Normal file
250
lib/basalt/libraries/basaltDraw.lua
Normal file
|
@ -0,0 +1,250 @@
|
|||
local tHex = require("tHex")
|
||||
local utils = require("utils")
|
||||
local split = utils.splitString
|
||||
local sub,rep = string.sub,string.rep
|
||||
|
||||
return function(drawTerm)
|
||||
local terminal = drawTerm or term.current()
|
||||
local mirrorTerm
|
||||
local width, height = terminal.getSize()
|
||||
local cacheT = {}
|
||||
local cacheBG = {}
|
||||
local cacheFG = {}
|
||||
|
||||
local emptySpaceLine
|
||||
local emptyColorLines = {}
|
||||
|
||||
local function createEmptyLines()
|
||||
emptySpaceLine = rep(" ", width)
|
||||
for n = 0, 15 do
|
||||
local nColor = 2 ^ n
|
||||
local sHex = tHex[nColor]
|
||||
emptyColorLines[nColor] = rep(sHex, width)
|
||||
end
|
||||
end
|
||||
----
|
||||
createEmptyLines()
|
||||
|
||||
local function recreateWindowArray()
|
||||
createEmptyLines()
|
||||
local emptyText = emptySpaceLine
|
||||
local emptyFG = emptyColorLines[colors.white]
|
||||
local emptyBG = emptyColorLines[colors.black]
|
||||
for currentY = 1, height do
|
||||
cacheT[currentY] = sub(cacheT[currentY] == nil and emptyText or cacheT[currentY] .. emptyText:sub(1, width - cacheT[currentY]:len()), 1, width)
|
||||
cacheFG[currentY] = sub(cacheFG[currentY] == nil and emptyFG or cacheFG[currentY] .. emptyFG:sub(1, width - cacheFG[currentY]:len()), 1, width)
|
||||
cacheBG[currentY] = sub(cacheBG[currentY] == nil and emptyBG or cacheBG[currentY] .. emptyBG:sub(1, width - cacheBG[currentY]:len()), 1, width)
|
||||
end
|
||||
end
|
||||
recreateWindowArray()
|
||||
|
||||
local function blit(x, y, t, fg, bg)
|
||||
if #t == #fg and #t == #bg then
|
||||
if y >= 1 and y <= height then
|
||||
if x + #t > 0 and x <= width then
|
||||
local newCacheT, newCacheFG, newCacheBG
|
||||
local oldCacheT, oldCacheFG, oldCacheBG = cacheT[y], cacheFG[y], cacheBG[y]
|
||||
local startN, endN = 1, #t
|
||||
|
||||
if x < 1 then
|
||||
startN = 1 - x + 1
|
||||
endN = width - x + 1
|
||||
elseif x + #t > width then
|
||||
endN = width - x + 1
|
||||
end
|
||||
|
||||
newCacheT = sub(oldCacheT, 1, x - 1) .. sub(t, startN, endN)
|
||||
newCacheFG = sub(oldCacheFG, 1, x - 1) .. sub(fg, startN, endN)
|
||||
newCacheBG = sub(oldCacheBG, 1, x - 1) .. sub(bg, startN, endN)
|
||||
|
||||
if x + #t <= width then
|
||||
newCacheT = newCacheT .. sub(oldCacheT, x + #t, width)
|
||||
newCacheFG = newCacheFG .. sub(oldCacheFG, x + #t, width)
|
||||
newCacheBG = newCacheBG .. sub(oldCacheBG, x + #t, width)
|
||||
end
|
||||
|
||||
cacheT[y], cacheFG[y], cacheBG[y] = newCacheT,newCacheFG,newCacheBG
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setText(x, y, t)
|
||||
if y >= 1 and y <= height then
|
||||
if x + #t > 0 and x <= width then
|
||||
local newCacheT
|
||||
local oldCacheT = cacheT[y]
|
||||
local startN, endN = 1, #t
|
||||
|
||||
if x < 1 then
|
||||
startN = 1 - x + 1
|
||||
endN = width - x + 1
|
||||
elseif x + #t > width then
|
||||
endN = width - x + 1
|
||||
end
|
||||
|
||||
newCacheT = sub(oldCacheT, 1, x - 1) .. sub(t, startN, endN)
|
||||
|
||||
if x + #t <= width then
|
||||
newCacheT = newCacheT .. sub(oldCacheT, x + #t, width)
|
||||
end
|
||||
|
||||
cacheT[y] = newCacheT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setBG(x, y, bg)
|
||||
if y >= 1 and y <= height then
|
||||
if x + #bg > 0 and x <= width then
|
||||
local newCacheBG
|
||||
local oldCacheBG = cacheBG[y]
|
||||
local startN, endN = 1, #bg
|
||||
|
||||
if x < 1 then
|
||||
startN = 1 - x + 1
|
||||
endN = width - x + 1
|
||||
elseif x + #bg > width then
|
||||
endN = width - x + 1
|
||||
end
|
||||
|
||||
newCacheBG = sub(oldCacheBG, 1, x - 1) .. sub(bg, startN, endN)
|
||||
|
||||
if x + #bg <= width then
|
||||
newCacheBG = newCacheBG .. sub(oldCacheBG, x + #bg, width)
|
||||
end
|
||||
|
||||
cacheBG[y] = newCacheBG
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setFG(x, y, fg)
|
||||
if y >= 1 and y <= height then
|
||||
if x + #fg > 0 and x <= width then
|
||||
local newCacheFG
|
||||
local oldCacheFG = cacheFG[y]
|
||||
local startN, endN = 1, #fg
|
||||
|
||||
if x < 1 then
|
||||
startN = 1 - x + 1
|
||||
endN = width - x + 1
|
||||
elseif x + #fg > width then
|
||||
endN = width - x + 1
|
||||
end
|
||||
|
||||
newCacheFG = sub(oldCacheFG, 1, x - 1) .. sub(fg, startN, endN)
|
||||
|
||||
if x + #fg <= width then
|
||||
newCacheFG = newCacheFG .. sub(oldCacheFG, x + #fg, width)
|
||||
end
|
||||
|
||||
cacheFG[y] = newCacheFG
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
local function setText(x, y, text)
|
||||
if (y >= 1) and (y <= height) then
|
||||
local emptyLine = rep(" ", #text)
|
||||
blit(x, y, text, emptyLine, emptyLine)
|
||||
end
|
||||
end
|
||||
|
||||
local function setFG(x, y, colorStr)
|
||||
if (y >= 1) and (y <= height) then
|
||||
local w = #colorStr
|
||||
local emptyLine = rep(" ", w)
|
||||
local text = sub(cacheT[y], x, w)
|
||||
blit(x, y, text, colorStr, emptyLine)
|
||||
end
|
||||
end
|
||||
|
||||
local function setBG(x, y, colorStr)
|
||||
if (y >= 1) and (y <= height) then
|
||||
local w = #colorStr
|
||||
local emptyLine = rep(" ", w)
|
||||
local text = sub(cacheT[y], x, w)
|
||||
blit(x, y, text, emptyLine, colorStr)
|
||||
end
|
||||
end]]
|
||||
|
||||
local drawHelper = {
|
||||
setSize = function(w, h)
|
||||
width, height = w, h
|
||||
recreateWindowArray()
|
||||
end,
|
||||
|
||||
setMirror = function(mirror)
|
||||
mirrorTerm = mirror
|
||||
end,
|
||||
|
||||
setBG = function(x, y, colorStr)
|
||||
setBG(x, y, colorStr)
|
||||
end,
|
||||
|
||||
setText = function(x, y, text)
|
||||
setText(x, y, text)
|
||||
end,
|
||||
|
||||
setFG = function(x, y, colorStr)
|
||||
setFG(x, y, colorStr)
|
||||
end;
|
||||
|
||||
blit = function(x, y, t, fg, bg)
|
||||
blit(x, y, t, fg, bg)
|
||||
end,
|
||||
|
||||
drawBackgroundBox = function(x, y, width, height, bgCol)
|
||||
local colorStr = rep(tHex[bgCol], width)
|
||||
for n = 1, height do
|
||||
setBG(x, y + (n - 1), colorStr)
|
||||
end
|
||||
end,
|
||||
drawForegroundBox = function(x, y, width, height, fgCol)
|
||||
local colorStr = rep(tHex[fgCol], width)
|
||||
for n = 1, height do
|
||||
setFG(x, y + (n - 1), colorStr)
|
||||
end
|
||||
end,
|
||||
drawTextBox = function(x, y, width, height, symbol)
|
||||
local textStr = rep(symbol, width)
|
||||
for n = 1, height do
|
||||
setText(x, y + (n - 1), textStr)
|
||||
end
|
||||
end,
|
||||
|
||||
update = function()
|
||||
local xC, yC = terminal.getCursorPos()
|
||||
local isBlinking = false
|
||||
if (terminal.getCursorBlink ~= nil) then
|
||||
isBlinking = terminal.getCursorBlink()
|
||||
end
|
||||
terminal.setCursorBlink(false)
|
||||
if(mirrorTerm~=nil)then mirrorTerm.setCursorBlink(false) end
|
||||
for n = 1, height do
|
||||
terminal.setCursorPos(1, n)
|
||||
terminal.blit(cacheT[n], cacheFG[n], cacheBG[n])
|
||||
if(mirrorTerm~=nil)then
|
||||
mirrorTerm.setCursorPos(1, n)
|
||||
mirrorTerm.blit(cacheT[n], cacheFG[n], cacheBG[n])
|
||||
end
|
||||
end
|
||||
terminal.setBackgroundColor(colors.black)
|
||||
terminal.setCursorBlink(isBlinking)
|
||||
terminal.setCursorPos(xC, yC)
|
||||
if(mirrorTerm~=nil)then
|
||||
mirrorTerm.setBackgroundColor(colors.black)
|
||||
mirrorTerm.setCursorBlink(isBlinking)
|
||||
mirrorTerm.setCursorPos(xC, yC)
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
setTerm = function(newTerm)
|
||||
terminal = newTerm
|
||||
end,
|
||||
}
|
||||
return drawHelper
|
||||
end
|
55
lib/basalt/libraries/basaltEvent.lua
Normal file
55
lib/basalt/libraries/basaltEvent.lua
Normal file
|
@ -0,0 +1,55 @@
|
|||
return function()
|
||||
local events = {}
|
||||
|
||||
local event = {
|
||||
registerEvent = function(self, _event, func)
|
||||
if (events[_event] == nil) then
|
||||
events[_event] = {}
|
||||
end
|
||||
table.insert(events[_event], func)
|
||||
end,
|
||||
|
||||
removeEvent = function(self, _event, index)
|
||||
events[_event][index[_event]] = nil
|
||||
end,
|
||||
|
||||
hasEvent = function(self, _event)
|
||||
return events[_event]~=nil
|
||||
end,
|
||||
|
||||
getEventCount = function(self, _event)
|
||||
return events[_event]~=nil and #events[_event] or 0
|
||||
end,
|
||||
|
||||
getEvents = function(self)
|
||||
local t = {}
|
||||
for k,v in pairs(events)do
|
||||
table.insert(t, k)
|
||||
end
|
||||
return t
|
||||
end,
|
||||
|
||||
clearEvent = function(self, _event)
|
||||
events[_event] = nil
|
||||
end,
|
||||
|
||||
clear = function(self, _event)
|
||||
events = {}
|
||||
end,
|
||||
|
||||
sendEvent = function(self, _event, ...)
|
||||
local returnValue
|
||||
if (events[_event] ~= nil) then
|
||||
for _, value in pairs(events[_event]) do
|
||||
local val = value(...)
|
||||
if(val==false)then
|
||||
returnValue = val
|
||||
end
|
||||
end
|
||||
end
|
||||
return returnValue
|
||||
end,
|
||||
}
|
||||
event.__index = event
|
||||
return event
|
||||
end
|
20
lib/basalt/libraries/basaltLogs.lua
Normal file
20
lib/basalt/libraries/basaltLogs.lua
Normal file
|
@ -0,0 +1,20 @@
|
|||
local logDir = ""
|
||||
local logFileName = "basaltLog.txt"
|
||||
|
||||
local defaultLogType = "Debug"
|
||||
|
||||
fs.delete(logDir~="" and logDir.."/"..logFileName or logFileName)
|
||||
|
||||
local mt = {
|
||||
__call = function(_,text, typ)
|
||||
if(text==nil)then return end
|
||||
local dirStr = logDir~="" and logDir.."/"..logFileName or logFileName
|
||||
local handle = fs.open(dirStr, fs.exists(dirStr) and "a" or "w")
|
||||
handle.writeLine("[Basalt]["..os.date("%Y-%m-%d %H:%M:%S").."]["..(typ and typ or defaultLogType).."]: "..tostring(text))
|
||||
handle.close()
|
||||
end,
|
||||
}
|
||||
|
||||
return setmetatable({}, mt)
|
||||
|
||||
--Work in progress
|
199
lib/basalt/libraries/basaltMon.lua
Normal file
199
lib/basalt/libraries/basaltMon.lua
Normal file
|
@ -0,0 +1,199 @@
|
|||
-- Right now this doesn't support scroll(n)
|
||||
-- Because this lbirary is mainly made for basalt - it doesn't need scroll support, maybe i will add it in the future
|
||||
|
||||
local tHex = {
|
||||
[colors.white] = "0",
|
||||
[colors.orange] = "1",
|
||||
[colors.magenta] = "2",
|
||||
[colors.lightBlue] = "3",
|
||||
[colors.yellow] = "4",
|
||||
[colors.lime] = "5",
|
||||
[colors.pink] = "6",
|
||||
[colors.gray] = "7",
|
||||
[colors.lightGray] = "8",
|
||||
[colors.cyan] = "9",
|
||||
[colors.purple] = "a",
|
||||
[colors.blue] = "b",
|
||||
[colors.brown] = "c",
|
||||
[colors.green] = "d",
|
||||
[colors.red] = "e",
|
||||
[colors.black] = "f",
|
||||
}
|
||||
|
||||
local type,len,rep,sub = type,string.len,string.rep,string.sub
|
||||
|
||||
|
||||
return function (monitorNames)
|
||||
local monitors = {}
|
||||
for k,v in pairs(monitorNames)do
|
||||
monitors[k] = {}
|
||||
for a,b in pairs(v)do
|
||||
local mon = peripheral.wrap(b)
|
||||
if(mon==nil)then
|
||||
error("Unable to find monitor "..b)
|
||||
end
|
||||
monitors[k][a] = mon
|
||||
monitors[k][a].name = b
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local x,y,monX,monY,monW,monH,w,h = 1,1,1,1,0,0,0,0
|
||||
local blink,scale = false,1
|
||||
local fg,bg = colors.white,colors.black
|
||||
|
||||
|
||||
local function calcSize()
|
||||
local maxW,maxH = 0,0
|
||||
for k,v in pairs(monitors)do
|
||||
local _maxW,_maxH = 0,0
|
||||
for a,b in pairs(v)do
|
||||
local nw,nh = b.getSize()
|
||||
_maxW = _maxW + nw
|
||||
_maxH = nh > _maxH and nh or _maxH
|
||||
end
|
||||
maxW = maxW > _maxW and maxW or _maxW
|
||||
maxH = maxH + _maxH
|
||||
end
|
||||
w,h = maxW,maxH
|
||||
end
|
||||
calcSize()
|
||||
|
||||
local function calcPosition()
|
||||
local relY = 0
|
||||
local mX,mY = 0,0
|
||||
for k,v in pairs(monitors)do
|
||||
local relX = 0
|
||||
local _mh = 0
|
||||
for a,b in pairs(v)do
|
||||
local mw,mh = b.getSize()
|
||||
if(x-relX>=1)and(x-relX<=mw)then
|
||||
mX = a
|
||||
end
|
||||
b.setCursorPos(x-relX, y-relY)
|
||||
relX = relX + mw
|
||||
if(_mh<mh)then _mh = mh end
|
||||
end
|
||||
if(y-relY>=1)and(y-relY<=_mh)then
|
||||
mY = k
|
||||
end
|
||||
relY = relY + _mh
|
||||
end
|
||||
monX,monY = mX,mY
|
||||
end
|
||||
calcPosition()
|
||||
|
||||
local function call(f, ...)
|
||||
local t = {...}
|
||||
return function()
|
||||
for k,v in pairs(monitors)do
|
||||
for a,b in pairs(v)do
|
||||
b[f](table.unpack(t))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function cursorBlink()
|
||||
call("setCursorBlink", false)()
|
||||
if not(blink)then return end
|
||||
if(monitors[monY]==nil)then return end
|
||||
local mon = monitors[monY][monX]
|
||||
if(mon==nil)then return end
|
||||
mon.setCursorBlink(blink)
|
||||
end
|
||||
|
||||
local function blit(text, tCol, bCol)
|
||||
if(monitors[monY]==nil)then return end
|
||||
local mon = monitors[monY][monX]
|
||||
if(mon==nil)then return end
|
||||
mon.blit(text, tCol, bCol)
|
||||
local mW, mH = mon.getSize()
|
||||
if(len(text)+x>mW)then
|
||||
local monRight = monitors[monY][monX+1]
|
||||
if(monRight~=nil)then
|
||||
monRight.blit(text, tCol, bCol)
|
||||
monX = monX + 1
|
||||
x = x + len(text)
|
||||
end
|
||||
end
|
||||
calcPosition()
|
||||
end
|
||||
|
||||
return {
|
||||
clear = call("clear"),
|
||||
|
||||
setCursorBlink = function(_blink)
|
||||
blink = _blink
|
||||
cursorBlink()
|
||||
end,
|
||||
|
||||
getCursorBlink = function()
|
||||
return blink
|
||||
end,
|
||||
|
||||
getCursorPos = function()
|
||||
return x, y
|
||||
end,
|
||||
|
||||
setCursorPos = function(newX,newY)
|
||||
x, y = newX, newY
|
||||
calcPosition()
|
||||
cursorBlink()
|
||||
end,
|
||||
|
||||
setTextScale = function(_scale)
|
||||
call("setTextScale", _scale)()
|
||||
calcSize()
|
||||
calcPosition()
|
||||
scale = _scale
|
||||
end,
|
||||
|
||||
getTextScale = function()
|
||||
return scale
|
||||
end,
|
||||
|
||||
blit = function(text,fgCol,bgCol)
|
||||
blit(text,fgCol,bgCol)
|
||||
end,
|
||||
|
||||
write = function(text)
|
||||
text = tostring(text)
|
||||
local l = len(text)
|
||||
blit(text, rep(tHex[fg], l), rep(tHex[bg], l))
|
||||
end,
|
||||
|
||||
getSize = function()
|
||||
return w,h
|
||||
end,
|
||||
|
||||
setBackgroundColor = function(col)
|
||||
call("setBackgroundColor", col)()
|
||||
bg = col
|
||||
end,
|
||||
|
||||
setTextColor = function(col)
|
||||
call("setTextColor", col)()
|
||||
fg = col
|
||||
end,
|
||||
|
||||
calculateClick = function(name, xClick, yClick)
|
||||
local relY = 0
|
||||
for k,v in pairs(monitors)do
|
||||
local relX = 0
|
||||
local maxY = 0
|
||||
for a,b in pairs(v)do
|
||||
local wM,hM = b.getSize()
|
||||
if(b.name==name)then
|
||||
return xClick + relX, yClick + relY
|
||||
end
|
||||
relX = relX + wM
|
||||
if(hM > maxY)then maxY = hM end
|
||||
end
|
||||
relY = relY + maxY
|
||||
end
|
||||
return xClick, yClick
|
||||
end,
|
||||
|
||||
}
|
||||
end
|
390
lib/basalt/libraries/bimg.lua
Normal file
390
lib/basalt/libraries/bimg.lua
Normal file
|
@ -0,0 +1,390 @@
|
|||
local sub,rep = string.sub,string.rep
|
||||
|
||||
local function frame(base, manager)
|
||||
local w, h = 0, 0
|
||||
local t,fg,bg = {}, {}, {}
|
||||
local x, y = 1,1
|
||||
|
||||
local data = {}
|
||||
|
||||
local function recalculateSize()
|
||||
for y=1,h do
|
||||
if(t[y]==nil)then
|
||||
t[y] = rep(" ", w)
|
||||
else
|
||||
t[y] = t[y]..rep(" ", w-#t[y])
|
||||
end
|
||||
if(fg[y]==nil)then
|
||||
fg[y] = rep("0", w)
|
||||
else
|
||||
fg[y] = fg[y]..rep("0", w-#fg[y])
|
||||
end
|
||||
if(bg[y]==nil)then
|
||||
bg[y] = rep("f", w)
|
||||
else
|
||||
bg[y] = bg[y]..rep("f", w-#bg[y])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local addText = function(text, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
if(t[y]==nil)then
|
||||
t[y] = rep(" ", x-1)..text..rep(" ", w-(#text+x))
|
||||
else
|
||||
t[y] = sub(t[y], 1, x-1)..rep(" ", x-#t[y])..text..sub(t[y], x+#text, w)
|
||||
end
|
||||
if(#t[y]>w)then w = #t[y] end
|
||||
if(y > h)then h = y end
|
||||
manager.updateSize(w, h)
|
||||
end
|
||||
|
||||
local addBg = function(b, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
if(bg[y]==nil)then
|
||||
bg[y] = rep("f", x-1)..b..rep("f", w-(#b+x))
|
||||
else
|
||||
bg[y] = sub(bg[y], 1, x-1)..rep("f", x-#bg[y])..b..sub(bg[y], x+#b, w)
|
||||
end
|
||||
if(#bg[y]>w)then w = #bg[y] end
|
||||
if(y > h)then h = y end
|
||||
manager.updateSize(w, h)
|
||||
end
|
||||
|
||||
local addFg = function(f, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
if(fg[y]==nil)then
|
||||
fg[y] = rep("0", x-1)..f..rep("0", w-(#f+x))
|
||||
else
|
||||
fg[y] = sub(fg[y], 1, x-1)..rep("0", x-#fg[y])..f..sub(fg[y], x+#f, w)
|
||||
end
|
||||
if(#fg[y]>w)then w = #fg[y] end
|
||||
if(y > h)then h = y end
|
||||
manager.updateSize(w, h)
|
||||
end
|
||||
|
||||
local function setFrame(frm)
|
||||
data = {}
|
||||
t, fg, bg = {}, {}, {}
|
||||
for k,v in pairs(base)do
|
||||
if(type(k)=="string")then
|
||||
data[k] = v
|
||||
else
|
||||
t[k], fg[k], bg[k] = v[1], v[2], v[3]
|
||||
end
|
||||
end
|
||||
manager.updateSize(w, h)
|
||||
end
|
||||
|
||||
if(base~=nil)then
|
||||
if(#base>0)then
|
||||
w = #base[1][1]
|
||||
h = #base
|
||||
setFrame(base)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
recalculateSize = recalculateSize,
|
||||
setFrame = setFrame,
|
||||
|
||||
getFrame = function()
|
||||
local f = {}
|
||||
|
||||
for k,v in pairs(t)do
|
||||
table.insert(f, {v, fg[k], bg[k]})
|
||||
end
|
||||
|
||||
for k,v in pairs(data)do
|
||||
f[k] = v
|
||||
end
|
||||
|
||||
return f, w, h
|
||||
end,
|
||||
|
||||
getImage = function()
|
||||
local i = {}
|
||||
for k,v in pairs(t)do
|
||||
table.insert(i, {v, fg[k], bg[k]})
|
||||
end
|
||||
return i
|
||||
end,
|
||||
|
||||
setFrameData = function(key, value)
|
||||
if(value~=nil)then
|
||||
data[key] = value
|
||||
else
|
||||
if(type(key)=="table")then
|
||||
data = key
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
setFrameImage = function(imgData)
|
||||
for k,v in pairs(imgData.t)do
|
||||
t[k] = imgData.t[k]
|
||||
fg[k] = imgData.fg[k]
|
||||
bg[k] = imgData.bg[k]
|
||||
end
|
||||
end,
|
||||
|
||||
getFrameImage = function()
|
||||
return {t = t, fg = fg, bg = bg}
|
||||
end,
|
||||
|
||||
getFrameData = function(key)
|
||||
if(key~=nil)then
|
||||
return data[key]
|
||||
else
|
||||
return data
|
||||
end
|
||||
end,
|
||||
|
||||
blit = function(text, fgCol, bgCol, x, y)
|
||||
addText(text, x, y)
|
||||
addFg(fgCol, x, y)
|
||||
addBg(bgCol, x, y)
|
||||
end,
|
||||
|
||||
text = addText,
|
||||
fg = addFg,
|
||||
bg = addBg,
|
||||
|
||||
getSize = function()
|
||||
return w, h
|
||||
end,
|
||||
|
||||
setSize = function(_w, _h)
|
||||
local nt,nfg,nbg = {}, {}, {}
|
||||
for _y=1,_h do
|
||||
if(t[_y]~=nil)then
|
||||
nt[_y] = sub(t[_y], 1, _w)..rep(" ", _w - w)
|
||||
else
|
||||
nt[_y] = rep(" ", _w)
|
||||
end
|
||||
if(fg[_y]~=nil)then
|
||||
nfg[_y] = sub(fg[_y], 1, _w)..rep("0", _w - w)
|
||||
else
|
||||
nfg[_y] = rep("0", _w)
|
||||
end
|
||||
if(bg[_y]~=nil)then
|
||||
nbg[_y] = sub(bg[_y], 1, _w)..rep("f", _w - w)
|
||||
else
|
||||
nbg[_y] = rep("f", _w)
|
||||
end
|
||||
end
|
||||
t, fg, bg = nt, nfg, nbg
|
||||
w, h = _w, _h
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return function(img)
|
||||
local frames = {}
|
||||
local metadata = {creator="Bimg Library by NyoriE", date=os.date("!%Y-%m-%dT%TZ")}
|
||||
local width,height = 0, 0
|
||||
|
||||
if(img~=nil)then
|
||||
if(img[1][1][1]~=nil)then
|
||||
width,height = metadata.width or #img[1][1][1], metadata.height or #img[1]
|
||||
end
|
||||
end
|
||||
|
||||
local manager = {}
|
||||
|
||||
local function addFrame(id, data)
|
||||
id = id or #frames+1
|
||||
local f = frame(data, manager)
|
||||
table.insert(frames, id, f)
|
||||
if(data==nil)then
|
||||
frames[id].setSize(width, height)
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
local function removeFrame(id)
|
||||
table.remove(frames, id or #frames)
|
||||
end
|
||||
|
||||
local function moveFrame(id, dir)
|
||||
local f = frames[id]
|
||||
if(f~=nil)then
|
||||
local newId = id+dir
|
||||
if(newId>=1)and(newId<=#frames)then
|
||||
table.remove(frames, id)
|
||||
table.insert(frames, newId, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
manager = {
|
||||
updateSize = function(w, h, force)
|
||||
local changed = force==true and true or false
|
||||
if(w > width)then changed = true width = w end
|
||||
if(h > height)then changed = true height = h end
|
||||
if(changed)then
|
||||
for k,v in pairs(frames)do
|
||||
v.setSize(width, height)
|
||||
v.recalculateSize()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
text = function(frame, text, x, y)
|
||||
local f = frames[frame]
|
||||
if(f==nil)then
|
||||
f = addFrame(frame)
|
||||
end
|
||||
f.text(text, x, y)
|
||||
end,
|
||||
|
||||
fg = function(frame, fg, x, y)
|
||||
local f = frames[frame]
|
||||
if(f==nil)then
|
||||
f = addFrame(frame)
|
||||
end
|
||||
f.fg(fg, x, y)
|
||||
end,
|
||||
|
||||
bg = function(frame, bg, x, y)
|
||||
local f = frames[frame]
|
||||
if(f==nil)then
|
||||
f = addFrame(frame)
|
||||
end
|
||||
f.bg(bg, x, y)
|
||||
end,
|
||||
|
||||
blit = function(frame, text, fg, bg, x, y)
|
||||
local f = frames[frame]
|
||||
if(f==nil)then
|
||||
f = addFrame(frame)
|
||||
end
|
||||
f.blit(text, fg, bg, x, y)
|
||||
end,
|
||||
|
||||
setSize = function(w, h)
|
||||
width = w
|
||||
height = h
|
||||
for k,v in pairs(frames)do
|
||||
v.setSize(w, h)
|
||||
end
|
||||
end,
|
||||
|
||||
getFrame = function(id)
|
||||
if(frames[id]~=nil)then
|
||||
return frames[id].getFrame()
|
||||
end
|
||||
end,
|
||||
|
||||
getFrameObjects = function()
|
||||
return frames
|
||||
end,
|
||||
|
||||
getFrames = function()
|
||||
local f = {}
|
||||
for k,v in pairs(frames)do
|
||||
local frame = v.getFrame()
|
||||
table.insert(f, frame)
|
||||
end
|
||||
return f
|
||||
end,
|
||||
|
||||
getFrameObject = function(id)
|
||||
return frames[id]
|
||||
end,
|
||||
|
||||
addFrame = function(id)
|
||||
if(#frames<=1)then
|
||||
if(metadata.animated==nil)then
|
||||
metadata.animated = true
|
||||
end
|
||||
if(metadata.secondsPerFrame==nil)then
|
||||
metadata.secondsPerFrame = 0.2
|
||||
end
|
||||
end
|
||||
return addFrame(id)
|
||||
end,
|
||||
|
||||
removeFrame = removeFrame,
|
||||
|
||||
moveFrame = moveFrame,
|
||||
|
||||
setFrameData = function(id, key, value)
|
||||
if(frames[id]~=nil)then
|
||||
frames[id].setFrameData(key, value)
|
||||
end
|
||||
end,
|
||||
|
||||
getFrameData = function(id, key)
|
||||
if(frames[id]~=nil)then
|
||||
return frames[id].getFrameData(key)
|
||||
end
|
||||
end,
|
||||
|
||||
getSize = function()
|
||||
return width, height
|
||||
end,
|
||||
|
||||
setAnimation = function(anim)
|
||||
metadata.animation = anim
|
||||
end,
|
||||
|
||||
setMetadata = function(key, val)
|
||||
if(val~=nil)then
|
||||
metadata[key] = val
|
||||
else
|
||||
if(type(key)=="table")then
|
||||
metadata = key
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
getMetadata = function(key)
|
||||
if(key~=nil)then
|
||||
return metadata[key]
|
||||
else
|
||||
return metadata
|
||||
end
|
||||
end,
|
||||
|
||||
createBimg = function()
|
||||
local bimg = {}
|
||||
for k,v in pairs(frames)do
|
||||
local f = v.getFrame()
|
||||
table.insert(bimg, f)
|
||||
end
|
||||
for k,v in pairs(metadata)do
|
||||
bimg[k] = v
|
||||
end
|
||||
bimg.width = width
|
||||
bimg.height = height
|
||||
return bimg
|
||||
end,
|
||||
}
|
||||
|
||||
if(img~=nil)then
|
||||
for k,v in pairs(img)do
|
||||
if(type(k)=="string")then
|
||||
metadata[k] = v
|
||||
end
|
||||
end
|
||||
if(metadata.width==nil)or(metadata.height==nil)then
|
||||
width = metadata.width or #img[1][1][1]
|
||||
height = metadata.height or #img[1]
|
||||
manager.updateSize(width, height, true)
|
||||
end
|
||||
|
||||
for k,v in pairs(img)do
|
||||
if(type(k)=="number")then
|
||||
addFrame(k, v)
|
||||
end
|
||||
end
|
||||
else
|
||||
addFrame(1)
|
||||
end
|
||||
|
||||
return manager
|
||||
end
|
87
lib/basalt/libraries/images.lua
Normal file
87
lib/basalt/libraries/images.lua
Normal file
|
@ -0,0 +1,87 @@
|
|||
local sub,floor = string.sub,math.floor
|
||||
|
||||
local function loadNFPAsBimg(path)
|
||||
return {[1]={{}, {}, paintutils.loadImage(path)}}, "bimg"
|
||||
end
|
||||
|
||||
local function loadNFP(path)
|
||||
return paintutils.loadImage(path), "nfp"
|
||||
end
|
||||
|
||||
local function loadBIMG(path, binaryMode)
|
||||
local f = fs.open(path, binaryMode and "rb" or "r")
|
||||
if(f==nil)then error("Path - "..path.." doesn't exist!") end
|
||||
local content = textutils.unserialize(f.readAll())
|
||||
|
||||
f.close()
|
||||
if(content~=nil)then
|
||||
return content, "bimg"
|
||||
end
|
||||
end
|
||||
|
||||
local function loadBBF(path)
|
||||
|
||||
end
|
||||
|
||||
local function loadBBFAsBimg(path)
|
||||
|
||||
end
|
||||
|
||||
local function loadImage(path, f, binaryMode)
|
||||
if(sub(path, -4) == ".bimg")then
|
||||
return loadBIMG(path, binaryMode)
|
||||
elseif(sub(path, -3) == ".bbf")then
|
||||
return loadBBF(path, binaryMode)
|
||||
else
|
||||
return loadNFP(path, binaryMode)
|
||||
end
|
||||
-- ...
|
||||
end
|
||||
|
||||
local function loadImageAsBimg(path)
|
||||
if(path:find(".bimg"))then
|
||||
return loadBIMG(path)
|
||||
elseif(path:find(".bbf"))then
|
||||
return loadBBFAsBimg(path)
|
||||
else
|
||||
return loadNFPAsBimg(path)
|
||||
end
|
||||
end
|
||||
|
||||
local function resizeBIMG(source, w, h)
|
||||
local oW, oH = source.width or #source[1][1][1], source.height or #source[1]
|
||||
local newImg = {}
|
||||
for k,v in pairs(source)do
|
||||
if(type(k)=="number")then
|
||||
local frame = {}
|
||||
for y=1, h do
|
||||
local xT,xFG,xBG = "","",""
|
||||
local yR = floor(y / h * oH + 0.5)
|
||||
if(v[yR]~=nil)then
|
||||
for x=1, w do
|
||||
local xR = floor(x / w * oW + 0.5)
|
||||
xT = xT..sub(v[yR][1], xR,xR)
|
||||
xFG = xFG..sub(v[yR][2], xR,xR)
|
||||
xBG = xBG..sub(v[yR][3], xR,xR)
|
||||
end
|
||||
table.insert(frame, {xT, xFG, xBG})
|
||||
end
|
||||
end
|
||||
table.insert(newImg, k, frame)
|
||||
else
|
||||
newImg[k] = v
|
||||
end
|
||||
end
|
||||
newImg.width = w
|
||||
newImg.height = h
|
||||
return newImg
|
||||
end
|
||||
|
||||
return {
|
||||
loadNFP = loadNFP,
|
||||
loadBIMG = loadBIMG,
|
||||
loadImage = loadImage,
|
||||
resizeBIMG = resizeBIMG,
|
||||
loadImageAsBimg = loadImageAsBimg,
|
||||
|
||||
}
|
88
lib/basalt/libraries/process.lua
Normal file
88
lib/basalt/libraries/process.lua
Normal file
|
@ -0,0 +1,88 @@
|
|||
local processes = {}
|
||||
local process = {}
|
||||
local processId = 0
|
||||
|
||||
local newPackage = dofile("rom/modules/main/cc/require.lua").make
|
||||
|
||||
function process:new(path, window, newEnv, ...)
|
||||
local args = {...}
|
||||
local newP = setmetatable({ path = path }, { __index = self })
|
||||
newP.window = window
|
||||
window.current = term.current
|
||||
window.redirect = term.redirect
|
||||
newP.processId = processId
|
||||
if(type(path)=="string")then
|
||||
newP.coroutine = coroutine.create(function()
|
||||
local pPath = shell.resolveProgram(path)
|
||||
local env = setmetatable(newEnv, {__index=_ENV})
|
||||
env.shell = shell
|
||||
env.basaltProgram=true
|
||||
env.arg = {[0]=path, table.unpack(args)}
|
||||
if(pPath==nil)then
|
||||
error("The path "..path.." does not exist!")
|
||||
end
|
||||
env.require, env.package = newPackage(env, fs.getDir(pPath))
|
||||
if(fs.exists(pPath))then
|
||||
local file = fs.open(pPath, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
local program = load(content, path, "bt", env)
|
||||
if(program~=nil)then
|
||||
return program()
|
||||
end
|
||||
end
|
||||
end)
|
||||
elseif(type(path)=="function")then
|
||||
newP.coroutine = coroutine.create(function()
|
||||
path(table.unpack(args))
|
||||
end)
|
||||
else
|
||||
return
|
||||
end
|
||||
processes[processId] = newP
|
||||
processId = processId + 1
|
||||
return newP
|
||||
end
|
||||
|
||||
function process:resume(event, ...)
|
||||
local cur = term.current()
|
||||
term.redirect(self.window)
|
||||
if(self.filter~=nil)then
|
||||
if(event~=self.filter)then return end
|
||||
self.filter=nil
|
||||
end
|
||||
local ok, result = coroutine.resume(self.coroutine, event, ...)
|
||||
|
||||
if ok then
|
||||
self.filter = result
|
||||
else
|
||||
printError(result)
|
||||
end
|
||||
term.redirect(cur)
|
||||
return ok, result
|
||||
end
|
||||
|
||||
function process:isDead()
|
||||
if (self.coroutine ~= nil) then
|
||||
if (coroutine.status(self.coroutine) == "dead") then
|
||||
table.remove(processes, self.processId)
|
||||
return true
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function process:getStatus()
|
||||
if (self.coroutine ~= nil) then
|
||||
return coroutine.status(self.coroutine)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function process:start()
|
||||
coroutine.resume(self.coroutine)
|
||||
end
|
||||
|
||||
return process
|
6
lib/basalt/libraries/tHex.lua
Normal file
6
lib/basalt/libraries/tHex.lua
Normal file
|
@ -0,0 +1,6 @@
|
|||
local cols = {}
|
||||
|
||||
for i = 0, 15 do
|
||||
cols[2^i] = ("%x"):format(i)
|
||||
end
|
||||
return cols
|
343
lib/basalt/libraries/utils.lua
Normal file
343
lib/basalt/libraries/utils.lua
Normal file
|
@ -0,0 +1,343 @@
|
|||
local tHex = require("tHex")
|
||||
local sub,find,reverse,rep,insert,len = string.sub,string.find,string.reverse,string.rep,table.insert,string.len
|
||||
|
||||
local function splitString(str, delimiter)
|
||||
local results = {}
|
||||
if str == "" or delimiter == "" then
|
||||
return results
|
||||
end
|
||||
local start = 1
|
||||
local delim_start, delim_end = find(str, delimiter, start)
|
||||
while delim_start do
|
||||
insert(results, sub(str, start, delim_start - 1))
|
||||
start = delim_end + 1
|
||||
delim_start, delim_end = find(str, delimiter, start)
|
||||
end
|
||||
insert(results, sub(str, start))
|
||||
return results
|
||||
end
|
||||
|
||||
local function removeTags(input)
|
||||
return input:gsub("{[^}]+}", "")
|
||||
end
|
||||
|
||||
|
||||
local function wrapText(str, width)
|
||||
str = removeTags(str)
|
||||
if(str=="")or(width==0)then
|
||||
return {""}
|
||||
end
|
||||
local uniqueLines = splitString(str, "\n")
|
||||
local result = {}
|
||||
for k, v in pairs(uniqueLines) do
|
||||
if #v == 0 then
|
||||
table.insert(result, "")
|
||||
else
|
||||
while #v > width do
|
||||
local last_space = width
|
||||
for i = width, 1, -1 do
|
||||
if sub(v, i, i) == " " then
|
||||
last_space = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if last_space == width then
|
||||
local line = sub(v, 1, last_space - 1) .. "-"
|
||||
table.insert(result, line)
|
||||
v = sub(v, last_space)
|
||||
else
|
||||
local line = sub(v, 1, last_space - 1)
|
||||
table.insert(result, line)
|
||||
v = sub(v, last_space + 1)
|
||||
end
|
||||
|
||||
if #v <= width then
|
||||
break
|
||||
end
|
||||
end
|
||||
if #v > 0 then
|
||||
table.insert(result, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Coonverts a string with special tags to a table with colors and text
|
||||
-- @param input The string to convert
|
||||
-- @return A table with the following structure: { {text = "Hello", color = colors.red}, {text = "World", color = colors.blue} }
|
||||
local function convertRichText(input)
|
||||
local parsedResult = {}
|
||||
local currentPosition = 1
|
||||
local rawPosition = 1
|
||||
|
||||
while currentPosition <= #input do
|
||||
local closestColor, closestBgColor
|
||||
local color, bgColor
|
||||
local colorEnd, bgColorEnd
|
||||
|
||||
for colorName, _ in pairs(colors) do
|
||||
local fgPattern = "{fg:" .. colorName.."}"
|
||||
local bgColorPattern = "{bg:" .. colorName.."}"
|
||||
local colorStart, colorEndCandidate = input:find(fgPattern, currentPosition)
|
||||
local bgColorStart, bgColorEndCandidate = input:find(bgColorPattern, currentPosition)
|
||||
|
||||
if colorStart and (not closestColor or colorStart < closestColor) then
|
||||
closestColor = colorStart
|
||||
color = colorName
|
||||
colorEnd = colorEndCandidate
|
||||
end
|
||||
|
||||
if bgColorStart and (not closestBgColor or bgColorStart < closestBgColor) then
|
||||
closestBgColor = bgColorStart
|
||||
bgColor = colorName
|
||||
bgColorEnd = bgColorEndCandidate
|
||||
end
|
||||
end
|
||||
|
||||
local nextPosition
|
||||
if closestColor and (not closestBgColor or closestColor < closestBgColor) then
|
||||
nextPosition = closestColor
|
||||
elseif closestBgColor then
|
||||
nextPosition = closestBgColor
|
||||
else
|
||||
nextPosition = #input + 1
|
||||
end
|
||||
|
||||
local text = input:sub(currentPosition, nextPosition - 1)
|
||||
if #text > 0 then
|
||||
table.insert(parsedResult, {
|
||||
color = nil,
|
||||
bgColor = nil,
|
||||
text = text,
|
||||
position = rawPosition
|
||||
})
|
||||
rawPosition = rawPosition + #text
|
||||
currentPosition = currentPosition + #text
|
||||
end
|
||||
|
||||
if closestColor and (not closestBgColor or closestColor < closestBgColor) then
|
||||
table.insert(parsedResult, {
|
||||
color = color,
|
||||
bgColor = nil,
|
||||
text = "",
|
||||
position = rawPosition,
|
||||
})
|
||||
currentPosition = colorEnd + 1
|
||||
elseif closestBgColor then
|
||||
table.insert(parsedResult, {
|
||||
color = nil,
|
||||
bgColor = bgColor,
|
||||
text = "",
|
||||
position = rawPosition,
|
||||
})
|
||||
currentPosition = bgColorEnd + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return parsedResult
|
||||
end
|
||||
|
||||
--- Wrapts text with special color tags, like {fg:red} or {bg:blue} to multiple lines
|
||||
--- @param text string Text to wrap
|
||||
--- @param width number Width of the line
|
||||
--- @return table Table of lines
|
||||
local function wrapRichText(text, width)
|
||||
local colorData = convertRichText(text)
|
||||
local formattedLines = {}
|
||||
local x, y = 1, 1
|
||||
local currentColor, currentBgColor
|
||||
|
||||
local function addFormattedEntry(entry)
|
||||
table.insert(formattedLines, {
|
||||
x = x,
|
||||
y = y,
|
||||
text = entry.text,
|
||||
color = entry.color or currentColor,
|
||||
bgColor = entry.bgColor or currentBgColor
|
||||
})
|
||||
end
|
||||
|
||||
for _, entry in ipairs(colorData) do
|
||||
if entry.color then
|
||||
currentColor = entry.color
|
||||
elseif entry.bgColor then
|
||||
currentBgColor = entry.bgColor
|
||||
else
|
||||
local words = splitString(entry.text, " ")
|
||||
|
||||
for i, word in ipairs(words) do
|
||||
local wordLength = #word
|
||||
|
||||
if i > 1 then
|
||||
if x + 1 + wordLength <= width then
|
||||
addFormattedEntry({ text = " " })
|
||||
x = x + 1
|
||||
else
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
|
||||
while wordLength > 0 do
|
||||
local line = word:sub(1, width - x + 1)
|
||||
word = word:sub(width - x + 2)
|
||||
wordLength = #word
|
||||
|
||||
addFormattedEntry({ text = line })
|
||||
|
||||
if wordLength > 0 then
|
||||
x = 1
|
||||
y = y + 1
|
||||
else
|
||||
x = x + #line
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if x > width then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
|
||||
return formattedLines
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
getTextHorizontalAlign = function(text, width, textAlign, replaceChar)
|
||||
text = sub(text, 1, width)
|
||||
local offset = width - len(text)
|
||||
if (textAlign == "right") then
|
||||
text = rep(replaceChar or " ", offset) .. text
|
||||
elseif (textAlign == "center") then
|
||||
text = rep(replaceChar or " ", math.floor(offset / 2)) .. text .. rep(replaceChar or " ", math.floor(offset / 2))
|
||||
text = text .. (len(text) < width and (replaceChar or " ") or "")
|
||||
else
|
||||
text = text .. rep(replaceChar or " ", offset)
|
||||
end
|
||||
return text
|
||||
end,
|
||||
|
||||
getTextVerticalAlign = function(h, textAlign)
|
||||
local offset = 0
|
||||
if (textAlign == "center") then
|
||||
offset = math.ceil(h / 2)
|
||||
if (offset < 1) then
|
||||
offset = 1
|
||||
end
|
||||
end
|
||||
if (textAlign == "bottom") then
|
||||
offset = h
|
||||
end
|
||||
if(offset<1)then offset=1 end
|
||||
return offset
|
||||
end,
|
||||
|
||||
orderedTable = function(t)
|
||||
local newTable = {}
|
||||
for _, v in pairs(t) do
|
||||
newTable[#newTable+1] = v
|
||||
end
|
||||
return newTable
|
||||
end,
|
||||
|
||||
rpairs = function(t)
|
||||
return function(t, i)
|
||||
i = i - 1
|
||||
if i ~= 0 then
|
||||
return i, t[i]
|
||||
end
|
||||
end, t, #t + 1
|
||||
end,
|
||||
|
||||
tableCount = function(t)
|
||||
local n = 0
|
||||
if(t~=nil)then
|
||||
for k,v in pairs(t)do
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
return n
|
||||
end,
|
||||
|
||||
splitString = splitString,
|
||||
removeTags = removeTags,
|
||||
|
||||
wrapText = wrapText,
|
||||
|
||||
convertRichText = convertRichText,
|
||||
|
||||
--- Writes text with special color tags
|
||||
--- @param obj object The object to write to
|
||||
--- @param x number X-Position
|
||||
--- @param y number Y-Position
|
||||
--- @param text string The text to write
|
||||
writeRichText = function(obj, x, y, text)
|
||||
local richText = convertRichText(text)
|
||||
if(#richText==0)then
|
||||
obj:addText(x, y, text)
|
||||
return
|
||||
end
|
||||
|
||||
local defaultFG, defaultBG = obj:getForeground(), obj:getBackground()
|
||||
for _,v in pairs(richText)do
|
||||
obj:addText(x+v.position-1, y, v.text)
|
||||
if(v.color~=nil)then
|
||||
obj:addFG(x+v.position-1, y, tHex[colors[v.color] ]:rep(#v.text))
|
||||
defaultFG = colors[v.color]
|
||||
else
|
||||
obj:addFG(x+v.position-1, y, tHex[defaultFG]:rep(#v.text))
|
||||
end
|
||||
if(v.bgColor~=nil)then
|
||||
obj:addBG(x+v.position-1, y, tHex[colors[v.bgColor] ]:rep(#v.text))
|
||||
defaultBG = colors[v.bgColor]
|
||||
else
|
||||
if(defaultBG~=false)then
|
||||
obj:addBG(x+v.position-1, y, tHex[defaultBG]:rep(#v.text))
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
wrapRichText = wrapRichText,
|
||||
|
||||
--- Writes wrapped Text with special tags.
|
||||
--- @param obj object The object to write to
|
||||
--- @param x number X-Position
|
||||
--- @param y number Y-Position
|
||||
--- @param text string Text
|
||||
--- @param width number Width
|
||||
--- @param height number Height
|
||||
writeWrappedText = function(obj, x, y, text, width, height)
|
||||
local wrapped = wrapRichText(text, width)
|
||||
for _,v in pairs(wrapped)do
|
||||
if(v.y>height)then
|
||||
break
|
||||
end
|
||||
if(v.text~=nil)then
|
||||
obj:addText(x+v.x-1, y+v.y-1, v.text)
|
||||
end
|
||||
if(v.color~=nil)then
|
||||
obj:addFG(x+v.x-1, y+v.y-1, tHex[colors[v.color] ]:rep(#v.text))
|
||||
end
|
||||
if(v.bgColor~=nil)then
|
||||
obj:addBG(x+v.x-1, y+v.y-1, tHex[colors[v.bgColor] ]:rep(#v.text))
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
--- Returns a random UUID.
|
||||
--- @return string UUID.
|
||||
uuid = function()
|
||||
return string.gsub(string.format('%x-%x-%x-%x-%x', math.random(0, 0xffff), math.random(0, 0xffff), math.random(0, 0xffff), math.random(0, 0x0fff) + 0x4000, math.random(0, 0x3fff) + 0x8000), ' ', '0')
|
||||
end
|
||||
|
||||
}
|
77
lib/basalt/libraries/xmlParser.lua
Normal file
77
lib/basalt/libraries/xmlParser.lua
Normal file
|
@ -0,0 +1,77 @@
|
|||
local XMLNode = {
|
||||
new = function(tag)
|
||||
return {
|
||||
tag = tag,
|
||||
value = nil,
|
||||
attributes = {},
|
||||
children = {},
|
||||
|
||||
addChild = function(self, child)
|
||||
table.insert(self.children, child)
|
||||
end,
|
||||
|
||||
addAttribute = function(self, tag, value)
|
||||
self.attributes[tag] = value
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
local parseAttributes = function(node, s)
|
||||
-- Parse "" style string attributes
|
||||
local _, _ = string.gsub(s, "(%w+)=([\"'])(.-)%2", function(attribute, _, value)
|
||||
node:addAttribute(attribute, "\"" .. value .. "\"")
|
||||
end)
|
||||
-- Parse {} style computed attributes
|
||||
local _, _ = string.gsub(s, "(%w+)={(.-)}", function(attribute, expression)
|
||||
node:addAttribute(attribute, expression)
|
||||
end)
|
||||
end
|
||||
|
||||
local XMLParser = {
|
||||
parseText = function(xmlText)
|
||||
local stack = {}
|
||||
local top = XMLNode.new()
|
||||
table.insert(stack, top)
|
||||
local ni, c, label, xarg, empty
|
||||
local i, j = 1, 1
|
||||
while true do
|
||||
ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w_:]+)(.-)(%/?)>", i)
|
||||
if not ni then break end
|
||||
local text = string.sub(xmlText, i, ni - 1);
|
||||
if not string.find(text, "^%s*$") then
|
||||
local lVal = (top.value or "") .. text
|
||||
stack[#stack].value = lVal
|
||||
end
|
||||
if empty == "/" then -- empty element tag
|
||||
local lNode = XMLNode.new(label)
|
||||
parseAttributes(lNode, xarg)
|
||||
top:addChild(lNode)
|
||||
elseif c == "" then -- start tag
|
||||
local lNode = XMLNode.new(label)
|
||||
parseAttributes(lNode, xarg)
|
||||
table.insert(stack, lNode)
|
||||
top = lNode
|
||||
else -- end tag
|
||||
local toclose = table.remove(stack) -- remove top
|
||||
|
||||
top = stack[#stack]
|
||||
if #stack < 1 then
|
||||
error("XMLParser: nothing to close with " .. label)
|
||||
end
|
||||
if toclose.tag ~= label then
|
||||
error("XMLParser: trying to close " .. toclose.tag .. " with " .. label)
|
||||
end
|
||||
top:addChild(toclose)
|
||||
end
|
||||
i = j + 1
|
||||
end
|
||||
local text = string.sub(xmlText, i);
|
||||
if #stack > 1 then
|
||||
error("XMLParser: unclosed " .. stack[#stack].tag)
|
||||
end
|
||||
return top.children
|
||||
end
|
||||
}
|
||||
|
||||
return XMLParser
|
22
lib/basalt/loadObjects.lua
Normal file
22
lib/basalt/loadObjects.lua
Normal file
|
@ -0,0 +1,22 @@
|
|||
local _OBJECTS = {}
|
||||
|
||||
if(packaged)then
|
||||
for k,v in pairs(getProject("objects"))do
|
||||
_OBJECTS[k] = v()
|
||||
end
|
||||
return _OBJECTS
|
||||
end
|
||||
|
||||
local args = table.pack(...)
|
||||
local dir = fs.getDir(args[2] or "Basalt")
|
||||
if(dir==nil)then
|
||||
error("Unable to find directory "..args[2].." please report this bug to our discord.")
|
||||
end
|
||||
|
||||
for _,v in pairs(fs.list(fs.combine(dir, "objects")))do
|
||||
if(v~="example.lua")and not(v:find(".disabled"))then
|
||||
local name = v:gsub(".lua", "")
|
||||
_OBJECTS[name] = require(name)
|
||||
end
|
||||
end
|
||||
return _OBJECTS
|
603
lib/basalt/main.lua
Normal file
603
lib/basalt/main.lua
Normal file
|
@ -0,0 +1,603 @@
|
|||
local basaltEvent = require("basaltEvent")()
|
||||
local baseObjects = require("loadObjects")
|
||||
local moddedObjects
|
||||
local pluginSystem = require("plugin")
|
||||
local utils = require("utils")
|
||||
local log = require("basaltLogs")
|
||||
local uuid = utils.uuid
|
||||
local wrapText = utils.wrapText
|
||||
local count = utils.tableCount
|
||||
local moveThrottle = 300
|
||||
local dragThrottle = 0
|
||||
local renderingThrottle = 0
|
||||
local newObjects = {}
|
||||
|
||||
local baseTerm = term.current()
|
||||
local version = "1.7.0"
|
||||
|
||||
local projectDirectory = fs.getDir(table.pack(...)[2] or "")
|
||||
|
||||
local activeKey, frames, monFrames, variables, schedules = {}, {}, {}, {}, {}
|
||||
local mainFrame, activeFrame, focusedObject, updaterActive
|
||||
|
||||
local basalt = {}
|
||||
|
||||
if not term.isColor or not term.isColor() then
|
||||
error('Basalt requires an advanced (golden) computer to run.', 0)
|
||||
end
|
||||
|
||||
local defaultColors = {}
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
defaultColors[k] = {baseTerm.getPaletteColor(v)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function stop()
|
||||
updaterActive = false
|
||||
baseTerm.clear()
|
||||
baseTerm.setCursorPos(1, 1)
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
baseTerm.setPaletteColor(v, colors.packRGB(table.unpack(defaultColors[k])))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function schedule(f)
|
||||
assert(f~="function", "Schedule needs a function in order to work!")
|
||||
return function(...)
|
||||
local co = coroutine.create(f)
|
||||
local ok, result = coroutine.resume(co, ...)
|
||||
if(ok)then
|
||||
table.insert(schedules, co)
|
||||
else
|
||||
basalt.basaltError(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
basalt.log = function(...)
|
||||
log(...)
|
||||
end
|
||||
|
||||
local setVariable = function(name, var)
|
||||
variables[name] = var
|
||||
end
|
||||
|
||||
local getVariable = function(name)
|
||||
return variables[name]
|
||||
end
|
||||
|
||||
local getObjects = function()
|
||||
return moddedObjects
|
||||
end
|
||||
|
||||
local getObject = function(objectName)
|
||||
return getObjects()[objectName]
|
||||
end
|
||||
|
||||
local createObject = function(basalt, objectName, id)
|
||||
return getObject(objectName)(id, basalt)
|
||||
end
|
||||
|
||||
local bInstance = {
|
||||
getDynamicValueEventSetting = function()
|
||||
return basalt.dynamicValueEvents
|
||||
end,
|
||||
|
||||
getMainFrame = function()
|
||||
return mainFrame
|
||||
end,
|
||||
|
||||
setVariable = setVariable,
|
||||
getVariable = getVariable,
|
||||
|
||||
setMainFrame = function(mFrame)
|
||||
mainFrame = mFrame
|
||||
end,
|
||||
|
||||
getActiveFrame = function()
|
||||
return activeFrame
|
||||
end,
|
||||
|
||||
setActiveFrame = function(aFrame)
|
||||
activeFrame = aFrame
|
||||
end,
|
||||
|
||||
getFocusedObject = function()
|
||||
return focusedObject
|
||||
end,
|
||||
|
||||
setFocusedObject = function(focused)
|
||||
focusedObject = focused
|
||||
end,
|
||||
|
||||
getMonitorFrame = function(name)
|
||||
return monFrames[name] or monGroups[name][1]
|
||||
end,
|
||||
|
||||
setMonitorFrame = function(name, frame, isGroupedMon)
|
||||
if(mainFrame == frame)then mainFrame = nil end
|
||||
if(isGroupedMon)then
|
||||
monGroups[name] = {frame, sides}
|
||||
else
|
||||
monFrames[name] = frame
|
||||
end
|
||||
if(frame==nil)then
|
||||
monGroups[name] = nil
|
||||
end
|
||||
end,
|
||||
|
||||
getTerm = function()
|
||||
return baseTerm
|
||||
end,
|
||||
|
||||
schedule = schedule,
|
||||
|
||||
stop = stop,
|
||||
debug = basalt.debug,
|
||||
log = basalt.log,
|
||||
|
||||
getObjects = getObjects,
|
||||
|
||||
getObject = getObject,
|
||||
|
||||
createObject = createObject,
|
||||
|
||||
getDirectory = function()
|
||||
return projectDirectory
|
||||
end
|
||||
}
|
||||
|
||||
local function defaultErrorHandler(errMsg)
|
||||
baseTerm.clear()
|
||||
baseTerm.setBackgroundColor(colors.black)
|
||||
baseTerm.setTextColor(colors.red)
|
||||
local w,h = baseTerm.getSize()
|
||||
if(basalt.logging)then
|
||||
log(errMsg, "Error")
|
||||
end
|
||||
|
||||
local text = wrapText("Basalt error: "..errMsg, w)
|
||||
local yPos = 1
|
||||
for _,v in pairs(text)do
|
||||
baseTerm.setCursorPos(1,yPos)
|
||||
baseTerm.write(v)
|
||||
yPos = yPos + 1
|
||||
end
|
||||
baseTerm.setCursorPos(1,yPos+1)
|
||||
updaterActive = false
|
||||
end
|
||||
|
||||
local function handleSchedules(event, p1, p2, p3, p4)
|
||||
if(#schedules>0)then
|
||||
local finished = {}
|
||||
for n=1,#schedules do
|
||||
if(schedules[n]~=nil)then
|
||||
if (coroutine.status(schedules[n]) == "suspended")then
|
||||
local ok, result = coroutine.resume(schedules[n], event, p1, p2, p3, p4)
|
||||
if not(ok)then
|
||||
basalt.basaltError(result)
|
||||
end
|
||||
else
|
||||
table.insert(finished, n)
|
||||
end
|
||||
end
|
||||
end
|
||||
for n=1,#finished do
|
||||
table.remove(schedules, finished[n]-(n-1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function drawFrames()
|
||||
if(updaterActive==false)then return end
|
||||
if(mainFrame~=nil)then
|
||||
mainFrame:render()
|
||||
mainFrame:updateTerm()
|
||||
end
|
||||
for _,v in pairs(monFrames)do
|
||||
v:render()
|
||||
v:updateTerm()
|
||||
end
|
||||
end
|
||||
|
||||
local stopped, moveX, moveY = nil, nil, nil
|
||||
local moveTimer = nil
|
||||
local function mouseMoveEvent(_, stp, x, y)
|
||||
stopped, moveX, moveY = stp, x, y
|
||||
if(moveTimer==nil)then
|
||||
moveTimer = os.startTimer(moveThrottle/1000)
|
||||
end
|
||||
end
|
||||
|
||||
local function moveHandlerTimer()
|
||||
moveTimer = nil
|
||||
mainFrame:hoverHandler(moveX, moveY, stopped)
|
||||
activeFrame = mainFrame
|
||||
end
|
||||
|
||||
local btn, dragX, dragY = nil, nil, nil
|
||||
local dragTimer = nil
|
||||
local function dragHandlerTimer()
|
||||
dragTimer = nil
|
||||
mainFrame:dragHandler(btn, dragX, dragY)
|
||||
activeFrame = mainFrame
|
||||
end
|
||||
|
||||
local function mouseDragEvent(_, b, x, y)
|
||||
btn, dragX, dragY = b, x, y
|
||||
if(dragThrottle<50)then
|
||||
dragHandlerTimer()
|
||||
else
|
||||
if(dragTimer==nil)then
|
||||
dragTimer = os.startTimer(dragThrottle/1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local renderingTimer = nil
|
||||
local function renderingUpdateTimer()
|
||||
renderingTimer = nil
|
||||
drawFrames()
|
||||
end
|
||||
|
||||
local function renderingUpdateEvent(timer)
|
||||
if(renderingThrottle<50)then
|
||||
drawFrames()
|
||||
else
|
||||
if(renderingTimer==nil)then
|
||||
renderingTimer = os.startTimer(renderingThrottle/1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function basaltUpdateEvent(event, ...)
|
||||
local a = {...}
|
||||
if(basaltEvent:sendEvent("basaltEventCycle", event, ...)==false)then return end
|
||||
if(event=="terminate")then basalt.stop() end
|
||||
if(mainFrame~=nil)then
|
||||
local mouseEvents = {
|
||||
mouse_click = mainFrame.mouseHandler,
|
||||
mouse_up = mainFrame.mouseUpHandler,
|
||||
mouse_scroll = mainFrame.scrollHandler,
|
||||
mouse_drag = mouseDragEvent,
|
||||
mouse_move = mouseMoveEvent,
|
||||
}
|
||||
local mouseEvent = mouseEvents[event]
|
||||
if(mouseEvent~=nil)then
|
||||
mouseEvent(mainFrame, ...)
|
||||
handleSchedules(event, ...)
|
||||
renderingUpdateEvent()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if(event == "monitor_touch") then
|
||||
for k,v in pairs(monFrames)do
|
||||
if(v:mouseHandler(1, a[2], a[3], true, a[1]))then
|
||||
activeFrame = v
|
||||
end
|
||||
end
|
||||
handleSchedules(event, ...)
|
||||
renderingUpdateEvent()
|
||||
return
|
||||
end
|
||||
|
||||
if(activeFrame~=nil)then
|
||||
local keyEvents = {
|
||||
char = activeFrame.charHandler,
|
||||
key = activeFrame.keyHandler,
|
||||
key_up = activeFrame.keyUpHandler,
|
||||
}
|
||||
local keyEvent = keyEvents[event]
|
||||
if(keyEvent~=nil)then
|
||||
if(event == "key")then
|
||||
activeKey[a[1]] = true
|
||||
elseif(event == "key_up")then
|
||||
activeKey[a[1]] = false
|
||||
end
|
||||
keyEvent(activeFrame, ...)
|
||||
handleSchedules(event, ...)
|
||||
renderingUpdateEvent()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if(event=="timer")and(a[1]==moveTimer)then
|
||||
moveHandlerTimer()
|
||||
elseif(event=="timer")and(a[1]==dragTimer)then
|
||||
dragHandlerTimer()
|
||||
elseif(event=="timer")and(a[1]==renderingTimer)then
|
||||
renderingUpdateTimer()
|
||||
else
|
||||
for _, v in pairs(frames) do
|
||||
v:eventHandler(event, ...)
|
||||
end
|
||||
for _, v in pairs(monFrames) do
|
||||
v:eventHandler(event, ...)
|
||||
end
|
||||
handleSchedules(event, ...)
|
||||
renderingUpdateEvent()
|
||||
end
|
||||
end
|
||||
|
||||
local loadedObjects = false
|
||||
local loadedPlugins = false
|
||||
local function InitializeBasalt()
|
||||
if not(loadedObjects)then
|
||||
for _,v in pairs(newObjects)do
|
||||
if(fs.exists(v))then
|
||||
if(fs.isDir(v))then
|
||||
local files = fs.list(v)
|
||||
for _,object in pairs(files)do
|
||||
if not(fs.isDir(v.."/"..object))then
|
||||
local name = object:gsub(".lua", "")
|
||||
if(name~="example.lua")and not(name:find(".disabled"))then
|
||||
if(baseObjects[name]==nil)then
|
||||
baseObjects[name] = require(v.."."..object:gsub(".lua", ""))
|
||||
else
|
||||
error("Duplicate object name: "..name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local name = v:gsub(".lua", "")
|
||||
if(baseObjects[name]==nil)then
|
||||
baseObjects[name] = require(name)
|
||||
else
|
||||
error("Duplicate object name: "..name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
loadedObjects = true
|
||||
end
|
||||
if not(loadedPlugins)then
|
||||
moddedObjects = pluginSystem.loadPlugins(baseObjects, bInstance)
|
||||
local basaltPlugins = pluginSystem.get("basalt")
|
||||
if(basaltPlugins~=nil)then
|
||||
for k,v in pairs(basaltPlugins)do
|
||||
for a,b in pairs(v(basalt))do
|
||||
basalt[a] = b
|
||||
bInstance[a] = b
|
||||
end
|
||||
end
|
||||
end
|
||||
local basaltPlugins = pluginSystem.get("basaltInternal")
|
||||
if(basaltPlugins~=nil)then
|
||||
for _,v in pairs(basaltPlugins)do
|
||||
for a,b in pairs(v(basalt))do
|
||||
bInstance[a] = b
|
||||
end
|
||||
end
|
||||
end
|
||||
loadedPlugins = true
|
||||
end
|
||||
end
|
||||
|
||||
local function createFrame(name)
|
||||
InitializeBasalt()
|
||||
for _, v in pairs(frames) do
|
||||
if (v:getName() == name) then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
local newFrame = moddedObjects["BaseFrame"](name, bInstance)
|
||||
newFrame:init()
|
||||
newFrame:load()
|
||||
newFrame:draw()
|
||||
table.insert(frames, newFrame)
|
||||
if(mainFrame==nil)and(newFrame:getName()~="basaltDebuggingFrame")then
|
||||
newFrame:show()
|
||||
end
|
||||
return newFrame
|
||||
end
|
||||
|
||||
basalt = {
|
||||
basaltError = defaultErrorHandler,
|
||||
logging = false,
|
||||
dynamicValueEvents = false,
|
||||
drawFrames = drawFrames,
|
||||
log = log,
|
||||
getVersion = function()
|
||||
return version
|
||||
end,
|
||||
|
||||
memory = function()
|
||||
return math.floor(collectgarbage("count")+0.5).."KB"
|
||||
end,
|
||||
|
||||
addObject = function(path)
|
||||
if(fs.exists(path))then
|
||||
table.insert(newObjects, path)
|
||||
end
|
||||
end,
|
||||
|
||||
addPlugin = function(path)
|
||||
pluginSystem.addPlugin(path)
|
||||
end,
|
||||
|
||||
getAvailablePlugins = function()
|
||||
return pluginSystem.getAvailablePlugins()
|
||||
end,
|
||||
|
||||
getAvailableObjects = function()
|
||||
local objectNames = {}
|
||||
for k,_ in pairs(baseObjects)do
|
||||
table.insert(objectNames, k)
|
||||
end
|
||||
return objectNames
|
||||
end,
|
||||
|
||||
setVariable = setVariable,
|
||||
getVariable = getVariable,
|
||||
|
||||
getObjects = getObjects,
|
||||
getObject = getObject,
|
||||
|
||||
createObject = createObject,
|
||||
|
||||
setBaseTerm = function(_baseTerm)
|
||||
baseTerm = _baseTerm
|
||||
end,
|
||||
|
||||
resetPalette = function()
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
--baseTerm.setPaletteColor(v, colors.packRGB(table.unpack(defaultColors[k])))
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
setMouseMoveThrottle = function(amount)
|
||||
if(_HOST:find("CraftOS%-PC"))then
|
||||
if(config.get("mouse_move_throttle")~=10)then config.set("mouse_move_throttle", 10) end
|
||||
if(amount<100)then
|
||||
moveThrottle = 100
|
||||
else
|
||||
moveThrottle = amount
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
setRenderingThrottle = function(amount)
|
||||
if(amount<=0)then
|
||||
renderingThrottle = 0
|
||||
else
|
||||
renderingTimer = nil
|
||||
renderingThrottle = amount
|
||||
end
|
||||
end,
|
||||
|
||||
setMouseDragThrottle = function(amount)
|
||||
if(amount<=0)then
|
||||
dragThrottle = 0
|
||||
else
|
||||
dragTimer = nil
|
||||
dragThrottle = amount
|
||||
end
|
||||
end,
|
||||
|
||||
autoUpdate = function(isActive)
|
||||
updaterActive = isActive
|
||||
if(isActive==nil)then updaterActive = true end
|
||||
local function f()
|
||||
drawFrames()
|
||||
while updaterActive do
|
||||
basaltUpdateEvent(os.pullEventRaw())
|
||||
end
|
||||
end
|
||||
while updaterActive do
|
||||
local ok, err = xpcall(f, debug.traceback)
|
||||
if not(ok)then
|
||||
basalt.basaltError(err)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
update = function(event, ...)
|
||||
if (event ~= nil) then
|
||||
local args = {...}
|
||||
local ok, err = xpcall(function() basaltUpdateEvent(event, table.unpack(args)) end, debug.traceback)
|
||||
if not(ok)then
|
||||
basalt.basaltError(err)
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
stop = stop,
|
||||
stopUpdate = stop,
|
||||
|
||||
isKeyDown = function(key)
|
||||
if(activeKey[key]==nil)then return false end
|
||||
return activeKey[key];
|
||||
end,
|
||||
|
||||
getFrame = function(name)
|
||||
for _, value in pairs(frames) do
|
||||
if (value.name == name) then
|
||||
return value
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
getActiveFrame = function()
|
||||
return activeFrame
|
||||
end,
|
||||
|
||||
setActiveFrame = function(frame)
|
||||
if (frame:getType() == "Container") then
|
||||
activeFrame = frame
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
getMainFrame = function()
|
||||
return mainFrame
|
||||
end,
|
||||
|
||||
onEvent = function(...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
basaltEvent:registerEvent("basaltEventCycle", v)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
schedule = schedule,
|
||||
|
||||
addFrame = createFrame,
|
||||
createFrame = createFrame,
|
||||
|
||||
addMonitor = function(name)
|
||||
InitializeBasalt()
|
||||
for _, v in pairs(frames) do
|
||||
if (v:getName() == name) then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
local newFrame = moddedObjects["MonitorFrame"](name, bInstance)
|
||||
newFrame:init()
|
||||
newFrame:load()
|
||||
newFrame:draw()
|
||||
table.insert(monFrames, newFrame)
|
||||
return newFrame
|
||||
end,
|
||||
|
||||
removeFrame = function(name)
|
||||
frames[name] = nil
|
||||
end,
|
||||
|
||||
setProjectDir = function(dir)
|
||||
projectDirectory = dir
|
||||
end,
|
||||
}
|
||||
|
||||
local basaltPlugins = pluginSystem.get("basalt")
|
||||
if(basaltPlugins~=nil)then
|
||||
for k,v in pairs(basaltPlugins)do
|
||||
for a,b in pairs(v(basalt))do
|
||||
basalt[a] = b
|
||||
bInstance[a] = b
|
||||
end
|
||||
end
|
||||
end
|
||||
local basaltPlugins = pluginSystem.get("basaltInternal")
|
||||
if(basaltPlugins~=nil)then
|
||||
for k,v in pairs(basaltPlugins)do
|
||||
for a,b in pairs(v(basalt))do
|
||||
bInstance[a] = b
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return basalt
|
231
lib/basalt/objects/BaseFrame.lua
Normal file
231
lib/basalt/objects/BaseFrame.lua
Normal file
|
@ -0,0 +1,231 @@
|
|||
local drawSystem = require("basaltDraw")
|
||||
local utils = require("utils")
|
||||
|
||||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Container")(name, basalt)
|
||||
local objectType = "BaseFrame"
|
||||
|
||||
local xOffset, yOffset = 0, 0
|
||||
|
||||
local colorTheme = {}
|
||||
|
||||
local updateRender = true
|
||||
|
||||
local termObject = basalt.getTerm()
|
||||
local basaltDraw = drawSystem(termObject)
|
||||
|
||||
local xCursor, yCursor, cursorBlink, cursorColor = 1, 1, false, colors.white
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
setOffset = function(self, xOff, yOff)
|
||||
xOffset = xOff or xOffset
|
||||
yOffset = yOff or yOffset
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
setXOffset = function(self, newXOffset)
|
||||
return self:setOffset(newXOffset, nil)
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
setYOffset = function(self, newYOffset)
|
||||
return self:setOffset(nil, newYOffset)
|
||||
end,
|
||||
|
||||
setPalette = function(self, col, ...)
|
||||
if(self==basalt.getActiveFrame())then
|
||||
if(type(col)=="string")then
|
||||
colorTheme[col] = ...
|
||||
termObject.setPaletteColor(type(col)=="number" and col or colors[col], ...)
|
||||
elseif(type(col)=="table")then
|
||||
for k,v in pairs(col)do
|
||||
colorTheme[k] = v
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], v)
|
||||
else
|
||||
local r,g,b = table.unpack(v)
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setSize = function(self, ...)
|
||||
base.setSize(self, ...)
|
||||
basaltDraw = drawSystem(termObject)
|
||||
return self
|
||||
end,
|
||||
|
||||
getSize = function()
|
||||
return termObject.getSize()
|
||||
end,
|
||||
|
||||
getWidth = function(self)
|
||||
return ({termObject.getSize()})[1]
|
||||
end,
|
||||
|
||||
getHeight = function(self)
|
||||
return ({termObject.getSize()})[2]
|
||||
end,
|
||||
|
||||
show = function(self)
|
||||
base.show(self)
|
||||
basalt.setActiveFrame(self)
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(v, colors.packRGB(term.nativePaletteColor((v))))
|
||||
end
|
||||
end
|
||||
for k,v in pairs(colorTheme)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], v)
|
||||
else
|
||||
local r,g,b = table.unpack(v)
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b)
|
||||
end
|
||||
end
|
||||
basalt.setMainFrame(self)
|
||||
return self
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if(base.render~=nil)then
|
||||
if(self:isVisible())then
|
||||
if(updateRender)then
|
||||
base.render(self)
|
||||
local children = self:getChildren()
|
||||
for _, child in ipairs(children) do
|
||||
if (child.element.render ~= nil) then
|
||||
child.element:render()
|
||||
end
|
||||
end
|
||||
updateRender = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
updateDraw = function(self)
|
||||
updateRender = true
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if(event=="term_resize")then
|
||||
self:setSize(termObject.getSize())
|
||||
end
|
||||
end,
|
||||
|
||||
updateTerm = function(self)
|
||||
if(basaltDraw~=nil)then
|
||||
basaltDraw.update()
|
||||
end
|
||||
end,
|
||||
|
||||
setTerm = function(self, newTerm)
|
||||
termObject = newTerm
|
||||
if(newTerm==nil)then
|
||||
basaltDraw = nil
|
||||
else
|
||||
basaltDraw = drawSystem(termObject)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getTerm = function()
|
||||
return termObject
|
||||
end,
|
||||
|
||||
blit = function (self, x, y, t, f, b)
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
if y >= 1 and y <= h then
|
||||
local t_visible = sub(t, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local f_visible = sub(f, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local b_visible = sub(b, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
basaltDraw.blit(max(x + (obx - 1), obx), oby + y - 1, t_visible, f_visible, b_visible)
|
||||
end
|
||||
end,
|
||||
|
||||
setCursor = function(self, _blink, _xCursor, _yCursor, color)
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local xO, yO = self:getOffset()
|
||||
cursorBlink = _blink or false
|
||||
if (_xCursor ~= nil) then
|
||||
xCursor = obx + _xCursor - 1 - xO
|
||||
end
|
||||
if (_yCursor ~= nil) then
|
||||
yCursor = oby + _yCursor - 1 - yO
|
||||
end
|
||||
cursorColor = color or cursorColor
|
||||
if (cursorBlink) then
|
||||
termObject.setTextColor(cursorColor)
|
||||
termObject.setCursorPos(xCursor, yCursor)
|
||||
termObject.setCursorBlink(cursorBlink)
|
||||
else
|
||||
termObject.setCursorBlink(false)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
for k,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do
|
||||
object[v[1]] = function(self, btn, x, y, ...)
|
||||
if(base[v[1]](self, btn, x, y, ...))then
|
||||
basalt.setActiveFrame(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do
|
||||
object[v] = function(self, x, y, width, height, symbol)
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
height = (y < 1 and (height + y > self:getHeight() and self:getHeight() or height + y - 1) or (height + y > self:getHeight() and self:getHeight() - y + 1 or height))
|
||||
width = (x < 1 and (width + x > self:getWidth() and self:getWidth() or width + x - 1) or (width + x > self:getWidth() and self:getWidth() - x + 1 or width))
|
||||
basaltDraw[v](max(x + (obx - 1), obx), max(y + (oby - 1), oby), width, height, symbol)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({"setBG", "setFG", "setText"}) do
|
||||
object[v] = function(self, x, y, str)
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
if (y >= 1) and (y <= h) then
|
||||
basaltDraw[v](max(x + (obx - 1), obx), oby + y - 1, sub(str, max(1 - x + 1, 1), max(w - x + 1,1)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
77
lib/basalt/objects/Button.lua
Normal file
77
lib/basalt/objects/Button.lua
Normal file
|
@ -0,0 +1,77 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Button
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Button"
|
||||
local textHorizontalAlign = "center"
|
||||
local textVerticalAlign = "center"
|
||||
|
||||
local text = "Button"
|
||||
|
||||
base:setSize(12, 3)
|
||||
base:setZIndex(5)
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getHorizontalAlign = function(self)
|
||||
return textHorizontalAlign
|
||||
end,
|
||||
|
||||
setHorizontalAlign = function(self, pos)
|
||||
textHorizontalAlign = pos
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getVerticalAlign = function(self)
|
||||
return textVerticalAlign
|
||||
end,
|
||||
|
||||
setVerticalAlign = function(self, pos)
|
||||
textVerticalAlign = pos
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
setText = function(self, newText)
|
||||
text = newText
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("button", function()
|
||||
local w,h = self:getSize()
|
||||
local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign)
|
||||
local xOffset
|
||||
if(textHorizontalAlign=="center")then
|
||||
xOffset = math.floor((w - text:len()) / 2)
|
||||
elseif(textHorizontalAlign=="right")then
|
||||
xOffset = w - text:len()
|
||||
end
|
||||
|
||||
self:addText(xOffset + 1, verticalAlign, text)
|
||||
self:addFG(xOffset + 1, verticalAlign, tHex[self:getForeground() or colors.white]:rep(text:len()))
|
||||
end)
|
||||
end,
|
||||
}
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
40
lib/basalt/objects/ChangeableObject.lua
Normal file
40
lib/basalt/objects/ChangeableObject.lua
Normal file
|
@ -0,0 +1,40 @@
|
|||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
-- Base object
|
||||
local objectType = "ChangeableObject"
|
||||
|
||||
local value
|
||||
|
||||
local object = {
|
||||
setValue = function(self, _value, valueChangedHandler)
|
||||
if (value ~= _value) then
|
||||
value = _value
|
||||
self:updateDraw()
|
||||
if(valueChangedHandler~=false)then
|
||||
self:valueChangedHandler()
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getValue = function(self)
|
||||
return value
|
||||
end,
|
||||
|
||||
onChange = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("value_changed", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
valueChangedHandler = function(self)
|
||||
self:sendEvent("value_changed", value)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
114
lib/basalt/objects/Checkbox.lua
Normal file
114
lib/basalt/objects/Checkbox.lua
Normal file
|
@ -0,0 +1,114 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Checkbox
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Checkbox"
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setValue(false)
|
||||
base:setSize(1, 1)
|
||||
|
||||
local symbol,inactiveSymbol,text,textPos = "\42"," ","","right"
|
||||
|
||||
local object = {
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click", self)
|
||||
self:listenEvent("mouse_up", self)
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setSymbol = function(self, sym, inactive)
|
||||
symbol = sym or symbol
|
||||
inactiveSymbol = inactive or inactiveSymbol
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setActiveSymbol = function(self, sym)
|
||||
return self:setSymbol(sym, nil)
|
||||
end,
|
||||
|
||||
setInactiveSymbol = function(self, inactive)
|
||||
return self:setSymbol(nil, inactive)
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return symbol, inactiveSymbol
|
||||
end,
|
||||
|
||||
getActiveSymbol = function(self)
|
||||
return symbol
|
||||
end,
|
||||
|
||||
getInactiveSymbol = function(self)
|
||||
return inactiveSymbol
|
||||
end,
|
||||
|
||||
setText = function(self, _text)
|
||||
text = _text
|
||||
return self
|
||||
end,
|
||||
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
setTextPosition = function(self, pos)
|
||||
textPos = pos or textPos
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextPosition = function(self)
|
||||
return textPos
|
||||
end,
|
||||
|
||||
setChecked = base.setValue,
|
||||
|
||||
getChecked = base.getValue,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
if(button == 1)then
|
||||
if (self:getValue() ~= true) and (self:getValue() ~= false) then
|
||||
self:setValue(false)
|
||||
else
|
||||
self:setValue(not self:getValue())
|
||||
end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("checkbox", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local verticalAlign = utils.getTextVerticalAlign(h, "center")
|
||||
local bg,fg = self:getBackground(), self:getForeground()
|
||||
if (self:getValue()) then
|
||||
self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(symbol, w, "center"), tHex[fg], tHex[bg])
|
||||
else
|
||||
self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(inactiveSymbol, w, "center"), tHex[fg], tHex[bg])
|
||||
end
|
||||
if(text~="")then
|
||||
local align = textPos=="left" and -text:len() or 3
|
||||
self:addText(align, verticalAlign, text)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
429
lib/basalt/objects/Container.lua
Normal file
429
lib/basalt/objects/Container.lua
Normal file
|
@ -0,0 +1,429 @@
|
|||
local utils = require("utils")
|
||||
local tableCount = utils.tableCount
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Container"
|
||||
|
||||
local children = {}
|
||||
|
||||
local events = {}
|
||||
|
||||
local container = {}
|
||||
|
||||
local focusedChild
|
||||
local sorted = true
|
||||
local objId, evId = 0, 0
|
||||
|
||||
local objSort = function(a, b)
|
||||
if a.zIndex == b.zIndex then
|
||||
return a.objId < b.objId
|
||||
else
|
||||
return a.zIndex < b.zIndex
|
||||
end
|
||||
end
|
||||
local evSort = function(a, b)
|
||||
if a.zIndex == b.zIndex then
|
||||
return a.evId > b.evId
|
||||
else
|
||||
return a.zIndex > b.zIndex
|
||||
end
|
||||
end
|
||||
|
||||
local function getChildren(self)
|
||||
self:sortChildren()
|
||||
return children
|
||||
end
|
||||
|
||||
local function getChild(self, name)
|
||||
if (type(name)=="table") then
|
||||
name = name:getName()
|
||||
end
|
||||
for _, v in ipairs(children) do
|
||||
if v.element:getName() == name then
|
||||
return v.element
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getDeepChild(self, name)
|
||||
local maybeChild = getChild(name)
|
||||
if (maybeChild ~= nil) then
|
||||
return maybeChild
|
||||
end
|
||||
for _, child in ipairs(children) do
|
||||
if (child:getType() == "Container") then
|
||||
local maybeDeepChild = child:getDeepChild(name)
|
||||
if (maybeDeepChild ~= nil) then
|
||||
return maybeDeepChild
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addChild(self, element)
|
||||
if (getChild(element:getName()) ~= nil) then
|
||||
return
|
||||
end
|
||||
objId = objId + 1
|
||||
local zIndex = element:getZIndex()
|
||||
table.insert(children, {element = element, zIndex = zIndex, objId = objId})
|
||||
sorted = false
|
||||
element:setParent(self, true)
|
||||
for event, _ in pairs(element:getRegisteredEvents()) do
|
||||
self:addEvent(event, element)
|
||||
end
|
||||
if (element.init~=nil) then
|
||||
element:init()
|
||||
end
|
||||
if (element.load~=nil) then
|
||||
element:load()
|
||||
end
|
||||
if (element.draw~=nil) then
|
||||
element:draw()
|
||||
end
|
||||
return element
|
||||
end
|
||||
|
||||
local function removeChild(self, element)
|
||||
if (type(element)=="string") then
|
||||
element = getChild(element:getName())
|
||||
end
|
||||
if (element==nil) then
|
||||
return
|
||||
end
|
||||
for i, v in ipairs(children) do
|
||||
if v.element == element then
|
||||
table.remove(children, i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
self:removeEvents(element)
|
||||
sorted = false
|
||||
end
|
||||
|
||||
local function removeChildren(self)
|
||||
local parent = self:getParent()
|
||||
children = {}
|
||||
events = {}
|
||||
sorted = false
|
||||
objId = 0
|
||||
evId = 0
|
||||
focusedChild = nil
|
||||
parent:removeEvents(self)
|
||||
end
|
||||
|
||||
local function updateZIndex(self, element, newZ)
|
||||
objId = objId + 1
|
||||
evId = evId + 1
|
||||
for _,v in pairs(children)do
|
||||
if(v.element==element)then
|
||||
v.zIndex = newZ
|
||||
v.objId = objId
|
||||
break
|
||||
end
|
||||
end
|
||||
for _,v in pairs(events)do
|
||||
for a,b in pairs(v)do
|
||||
if(b.element==element)then
|
||||
b.zIndex = newZ
|
||||
b.evId = evId
|
||||
end
|
||||
end
|
||||
end
|
||||
sorted = false
|
||||
self:updateDraw()
|
||||
end
|
||||
|
||||
local function removeEvents(self, element)
|
||||
local parent = self:getParent()
|
||||
for a, b in pairs(events) do
|
||||
for c, d in pairs(b) do
|
||||
if(d.element == element)then
|
||||
table.remove(events[a], c)
|
||||
end
|
||||
end
|
||||
if(tableCount(events[a])<=0)then
|
||||
if(parent~=nil)then
|
||||
parent:removeEvent(a, self)
|
||||
end
|
||||
end
|
||||
end
|
||||
sorted = false
|
||||
end
|
||||
|
||||
local function getEvent(self, event, name)
|
||||
if(type(name)=="table")then name = name:getName() end
|
||||
if(events[event]~=nil)then
|
||||
for _, obj in pairs(events[event]) do
|
||||
if (obj.element:getName() == name) then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addEvent(self, event, element)
|
||||
if (getEvent(self, event, element:getName()) ~= nil) then
|
||||
return
|
||||
end
|
||||
local zIndex = element:getZIndex()
|
||||
evId = evId + 1
|
||||
if(events[event]==nil)then events[event] = {} end
|
||||
table.insert(events[event], {element = element, zIndex = zIndex, evId = evId})
|
||||
sorted = false
|
||||
self:listenEvent(event)
|
||||
return element
|
||||
end
|
||||
|
||||
local function removeEvent(self, event, element)
|
||||
if(events[event]~=nil)then
|
||||
for a, b in pairs(events[event]) do
|
||||
if(b.element == element)then
|
||||
table.remove(events[event], a)
|
||||
end
|
||||
end
|
||||
if(tableCount(events[event])<=0)then
|
||||
self:listenEvent(event, false)
|
||||
end
|
||||
end
|
||||
sorted = false
|
||||
end
|
||||
|
||||
local function getEvents(self, event)
|
||||
return event~=nil and events[event] or events
|
||||
end
|
||||
|
||||
container = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setSize = function(self, ...)
|
||||
base.setSize(self, ...)
|
||||
self:customEventHandler("basalt_FrameResize")
|
||||
return self
|
||||
end,
|
||||
|
||||
setPosition = function(self, ...)
|
||||
base.setPosition(self, ...)
|
||||
self:customEventHandler("basalt_FrameReposition")
|
||||
return self
|
||||
end,
|
||||
|
||||
searchChildren = function(self, name)
|
||||
local results = {}
|
||||
for _, child in pairs(children) do
|
||||
if (string.find(child.element:getName(), name)) then
|
||||
table.insert(results, child)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end,
|
||||
|
||||
getChildrenByType = function(self, type)
|
||||
local results = {}
|
||||
for _, child in pairs(children) do
|
||||
if (child.element:isType(type)) then
|
||||
table.insert(results, child)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end,
|
||||
|
||||
setImportant = function(self, element)
|
||||
objId = objId + 1
|
||||
evId = evId + 1
|
||||
for a, b in pairs(events) do
|
||||
for c, d in pairs(b) do
|
||||
if(d.element == element)then
|
||||
d.evId = evId
|
||||
table.remove(events[a], c)
|
||||
table.insert(events[a], d)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
for i, v in ipairs(children) do
|
||||
if v.element == element then
|
||||
v.objId = objId
|
||||
table.remove(children, i)
|
||||
table.insert(children, v)
|
||||
break
|
||||
end
|
||||
end
|
||||
if(self.updateDraw~=nil)then
|
||||
self:updateDraw()
|
||||
end
|
||||
sorted = false
|
||||
end,
|
||||
|
||||
sortChildren = function(self)
|
||||
if (sorted) then
|
||||
return
|
||||
end
|
||||
table.sort(children, objSort)
|
||||
for event, _ in pairs(events) do
|
||||
table.sort(events[event], evSort)
|
||||
end
|
||||
sorted = true
|
||||
end,
|
||||
|
||||
clearFocusedChild = function(self)
|
||||
if(focusedChild~=nil)then
|
||||
if(getChild(self, focusedChild)~=nil)then
|
||||
focusedChild:loseFocusHandler()
|
||||
end
|
||||
end
|
||||
focusedChild = nil
|
||||
return self
|
||||
end,
|
||||
|
||||
setFocusedChild = function(self, obj)
|
||||
if(focusedChild~=obj)then
|
||||
if(focusedChild~=nil)then
|
||||
if(getChild(self, focusedChild)~=nil)then
|
||||
focusedChild:loseFocusHandler()
|
||||
end
|
||||
end
|
||||
if(obj~=nil)then
|
||||
if(getChild(self, obj)~=nil)then
|
||||
obj:getFocusHandler()
|
||||
end
|
||||
end
|
||||
focusedChild = obj
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
getFocused = function(self)
|
||||
return focusedChild
|
||||
end,
|
||||
|
||||
getChild = getChild,
|
||||
getChildren = getChildren,
|
||||
getDeepChildren = getDeepChild,
|
||||
addChild = addChild,
|
||||
removeChild = removeChild,
|
||||
removeChildren = removeChildren,
|
||||
getEvents = getEvents,
|
||||
getEvent = getEvent,
|
||||
addEvent = addEvent,
|
||||
removeEvent = removeEvent,
|
||||
removeEvents = removeEvents,
|
||||
updateZIndex = updateZIndex,
|
||||
|
||||
listenEvent = function(self, event, active)
|
||||
base.listenEvent(self, event, active)
|
||||
if(events[event]==nil)then events[event] = {} end
|
||||
return self
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, ...)
|
||||
base.customEventHandler(self, ...)
|
||||
for _, o in pairs(children) do
|
||||
if (o.element.customEventHandler ~= nil) then
|
||||
o.element:customEventHandler(...)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
if(focusedChild~=nil)then focusedChild:loseFocusHandler() focusedChild = nil end
|
||||
end,
|
||||
|
||||
getBasalt = function(self)
|
||||
return basalt
|
||||
end,
|
||||
|
||||
setPalette = function(self, col, ...)
|
||||
local parent = self:getParent()
|
||||
parent:setPalette(col, ...)
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, ...)
|
||||
if(base.eventHandler~=nil)then
|
||||
base.eventHandler(self, ...)
|
||||
if(events["other_event"]~=nil)then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(events["other_event"]) do
|
||||
if (obj.element.eventHandler ~= nil) then
|
||||
obj.element.eventHandler(obj.element, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
for k,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do
|
||||
container[v[1]] = function(self, btn, x, y, ...)
|
||||
if(base[v[1]]~=nil)then
|
||||
if(base[v[1]](self, btn, x, y, ...))then
|
||||
if(events[k]~=nil)then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(events[k]) do
|
||||
if (obj.element[v[1]] ~= nil) then
|
||||
local xO, yO = 0, 0
|
||||
if(self.getOffset~=nil)then
|
||||
xO, yO = self:getOffset()
|
||||
end
|
||||
if(obj.element.getIgnoreOffset~=nil)then
|
||||
if(obj.element.getIgnoreOffset())then
|
||||
xO, yO = 0, 0
|
||||
end
|
||||
end
|
||||
if (obj.element[v[1]](obj.element, btn, x+xO, y+yO, ...)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if(v[2])then
|
||||
self:clearFocusedChild()
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({key="keyHandler",key_up="keyUpHandler",char="charHandler"})do
|
||||
container[v] = function(self, ...)
|
||||
if(base[v]~=nil)then
|
||||
if(base[v](self, ...))then
|
||||
if(events[k]~=nil)then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(events[k]) do
|
||||
if (obj.element[v] ~= nil) then
|
||||
if (obj.element[v](obj.element, ...)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for objectName, _ in pairs(basalt.getObjects()) do
|
||||
container["add" .. objectName] = function(self, id)
|
||||
return self:addChild(basalt:createObject(objectName, id))
|
||||
end
|
||||
end
|
||||
|
||||
container.__index = container
|
||||
return setmetatable(container, base)
|
||||
end
|
248
lib/basalt/objects/Dropdown.lua
Normal file
248
lib/basalt/objects/Dropdown.lua
Normal file
|
@ -0,0 +1,248 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("List")(name, basalt)
|
||||
local objectType = "Dropdown"
|
||||
|
||||
base:setSize(12, 1)
|
||||
base:setZIndex(6)
|
||||
|
||||
local selectionColorActive = true
|
||||
local align = "left"
|
||||
local yOffset = 0
|
||||
|
||||
local dropdownW = 0
|
||||
local dropdownH = 0
|
||||
local autoSize = true
|
||||
local closedSymbol = "\16"
|
||||
local openedSymbol = "\31"
|
||||
local isOpened = false
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click", self)
|
||||
self:listenEvent("mouse_up", self)
|
||||
self:listenEvent("mouse_scroll", self)
|
||||
self:listenEvent("mouse_drag", self)
|
||||
end,
|
||||
|
||||
setOffset = function(self, yOff)
|
||||
yOffset = yOff
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
addItem = function(self, t, ...)
|
||||
base.addItem(self, t, ...)
|
||||
if(autoSize)then
|
||||
dropdownW = math.max(dropdownW, #t)
|
||||
dropdownH = dropdownH + 1
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
removeItem = function(self, index)
|
||||
base.removeItem(self, index)
|
||||
if(autoSize)then
|
||||
dropdownW = 0
|
||||
dropdownH = 0
|
||||
for n = 1, #list do
|
||||
dropdownW = math.max(dropdownW, #list[n].text)
|
||||
end
|
||||
dropdownH = #list
|
||||
end
|
||||
end,
|
||||
|
||||
isOpened = function(self)
|
||||
return isOpened
|
||||
end,
|
||||
|
||||
setOpened = function(self, open)
|
||||
isOpened = open
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setDropdownSize = function(self, width, height)
|
||||
dropdownW, dropdownH = width, height
|
||||
autoSize = false
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setDropdownWidth = function(self, width)
|
||||
return self:setDropdownSize(width, dropdownH)
|
||||
end,
|
||||
|
||||
setDropdownHeight = function(self, height)
|
||||
return self:setDropdownSize(dropdownW, height)
|
||||
end,
|
||||
|
||||
getDropdownSize = function(self)
|
||||
return dropdownW, dropdownH
|
||||
end,
|
||||
|
||||
getDropdownWidth = function(self)
|
||||
return dropdownW
|
||||
end,
|
||||
|
||||
getDropdownHeight = function(self)
|
||||
return dropdownH
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, isMon)
|
||||
if (isOpened) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
if(button==1)then
|
||||
local list = self:getAll()
|
||||
if (#list > 0) then
|
||||
for n = 1, dropdownH do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then
|
||||
self:setValue(list[n + yOffset])
|
||||
self:updateDraw()
|
||||
local val = self:sendEvent("mouse_click", self, "mouse_click", button, x, y)
|
||||
if(val==false)then return val end
|
||||
if(isMon)then
|
||||
basalt.schedule(function()
|
||||
sleep(0.1)
|
||||
self:mouseUpHandler(button, x, y)
|
||||
end)()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local base = base:getBase()
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
isOpened = not isOpened
|
||||
self:getParent():setImportant(self)
|
||||
self:updateDraw()
|
||||
return true
|
||||
else
|
||||
if(isOpened)then
|
||||
self:updateDraw()
|
||||
isOpened = false
|
||||
end
|
||||
return false
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
if (isOpened) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
if(button==1)then
|
||||
local list = self:getAll()
|
||||
if (#list > 0) then
|
||||
for n = 1, dropdownH do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then
|
||||
isOpened = false
|
||||
self:updateDraw()
|
||||
local val = self:sendEvent("mouse_up", self, "mouse_up", button, x, y)
|
||||
if(val==false)then return val end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, btn, x, y)
|
||||
if(base.dragHandler(self, btn, x, y))then
|
||||
isOpened = true
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(isOpened)then
|
||||
local xPos, yPos = self:getAbsolutePosition()
|
||||
if(x >= xPos)and(x <= xPos + dropdownW)and(y >= yPos)and(y <= yPos + dropdownH)then
|
||||
self:setFocus()
|
||||
end
|
||||
end
|
||||
if (isOpened)and(self:isFocused()) then
|
||||
local xPos, yPos = self:getAbsolutePosition()
|
||||
if(x < xPos)or(x > xPos + dropdownW)or(y < yPos)or(y > yPos + dropdownH)then
|
||||
return false
|
||||
end
|
||||
if(#self:getAll() <= dropdownH)then return false end
|
||||
|
||||
local list = self:getAll()
|
||||
yOffset = yOffset + dir
|
||||
if (yOffset < 0) then
|
||||
yOffset = 0
|
||||
end
|
||||
if (dir == 1) then
|
||||
if (#list > dropdownH) then
|
||||
if (yOffset > #list - dropdownH) then
|
||||
yOffset = #list - dropdownH
|
||||
end
|
||||
else
|
||||
yOffset = math.min(#list - 1, 0)
|
||||
end
|
||||
end
|
||||
local val = self:sendEvent("mouse_scroll", self, "mouse_scroll", dir, x, y)
|
||||
if(val==false)then return val end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:setDrawState("list", false)
|
||||
self:addDraw("dropdown", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local val = self:getValue()
|
||||
local list = self:getAll()
|
||||
local bgCol, fgCol = self:getBackground(), self:getForeground()
|
||||
local text = utils.getTextHorizontalAlign((val~=nil and val.text or ""), w, align):sub(1, w - 1) .. (isOpened and openedSymbol or closedSymbol)
|
||||
self:addBlit(1, 1, text, tHex[fgCol]:rep(#text), tHex[bgCol]:rep(#text))
|
||||
|
||||
if (isOpened) then
|
||||
self:addTextBox(1, 2, dropdownW, dropdownH, " ")
|
||||
self:addBackgroundBox(1, 2, dropdownW, dropdownH, bgCol)
|
||||
self:addForegroundBox(1, 2, dropdownW, dropdownH, fgCol)
|
||||
for n = 1, dropdownH do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
local t =utils.getTextHorizontalAlign(list[n + yOffset].text, dropdownW, align)
|
||||
if (list[n + yOffset] == val) then
|
||||
if (selectionColorActive) then
|
||||
local itemSelectedBG, itemSelectedFG = self:getSelectionColor()
|
||||
self:addBlit(1, n+1, t, tHex[itemSelectedFG]:rep(#t), tHex[itemSelectedBG]:rep(#t))
|
||||
else
|
||||
self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t))
|
||||
end
|
||||
else
|
||||
self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
433
lib/basalt/objects/Flexbox.lua
Normal file
433
lib/basalt/objects/Flexbox.lua
Normal file
|
@ -0,0 +1,433 @@
|
|||
|
||||
local function flexObjectPlugin(base, basalt)
|
||||
local flexGrow = 0
|
||||
local flexShrink = 0
|
||||
local flexBasis = 0
|
||||
|
||||
local baseWidth, baseHeight = base:getSize()
|
||||
|
||||
local object = {
|
||||
getFlexGrow = function(self)
|
||||
return flexGrow
|
||||
end,
|
||||
|
||||
setFlexGrow = function(self, value)
|
||||
flexGrow = value
|
||||
return self
|
||||
end,
|
||||
|
||||
getFlexShrink = function(self)
|
||||
return flexShrink
|
||||
end,
|
||||
|
||||
setFlexShrink = function(self, value)
|
||||
flexShrink = value
|
||||
return self
|
||||
end,
|
||||
|
||||
getFlexBasis = function(self)
|
||||
return flexBasis
|
||||
end,
|
||||
|
||||
setFlexBasis = function(self, value)
|
||||
flexBasis = value
|
||||
return self
|
||||
end,
|
||||
|
||||
getSize = function(self)
|
||||
return baseWidth, baseHeight
|
||||
end,
|
||||
|
||||
getWidth = function(self)
|
||||
return baseWidth
|
||||
end,
|
||||
|
||||
getHeight = function(self)
|
||||
return baseHeight
|
||||
end,
|
||||
|
||||
setSize = function(self, width, height, rel, internalCall)
|
||||
base.setSize(self, width, height, rel)
|
||||
if not internalCall then
|
||||
baseWidth, baseHeight = base:getSize()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ScrollableFrame")(name, basalt)
|
||||
local objectType = "Flexbox"
|
||||
|
||||
local direction = "row"
|
||||
local spacing = 1
|
||||
local justifyContent = "flex-start"
|
||||
local wrap = "nowrap"
|
||||
local children = {}
|
||||
local sortedChildren = {}
|
||||
local updateLayout = false
|
||||
local lineBreakFakeObject = flexObjectPlugin({
|
||||
getHeight = function(self) return 0 end,
|
||||
getWidth = function(self) return 0 end,
|
||||
getPosition = function(self) return 0, 0 end,
|
||||
getSize = function(self) return 0, 0 end,
|
||||
isType = function(self) return false end,
|
||||
getType = function(self) return "lineBreakFakeObject" end,
|
||||
setPosition = function(self) end,
|
||||
setSize = function(self) end,
|
||||
})
|
||||
lineBreakFakeObject:setFlexBasis(0):setFlexGrow(0):setFlexShrink(0)
|
||||
|
||||
local function sortChildren(self)
|
||||
if(wrap=="nowrap")then
|
||||
sortedChildren = {}
|
||||
local index = 1
|
||||
local lineSize = 1
|
||||
local lineOffset = 1
|
||||
for _,v in pairs(children)do
|
||||
if(sortedChildren[index]==nil)then sortedChildren[index]={offset=1} end
|
||||
|
||||
local childHeight = direction == "row" and v:getHeight() or v:getWidth()
|
||||
if childHeight > lineSize then
|
||||
lineSize = childHeight
|
||||
end
|
||||
if(v == lineBreakFakeObject)then
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
lineSize = 1
|
||||
index = index + 1
|
||||
sortedChildren[index] = {offset=lineOffset}
|
||||
else
|
||||
table.insert(sortedChildren[index], v)
|
||||
end
|
||||
end
|
||||
elseif(wrap=="wrap")then
|
||||
sortedChildren = {}
|
||||
local lineSize = 1
|
||||
local lineOffset = 1
|
||||
|
||||
local maxSize = direction == "row" and self:getWidth() or self:getHeight()
|
||||
local usedSize = 0
|
||||
local index = 1
|
||||
|
||||
for _,v in pairs(children) do
|
||||
if(sortedChildren[index]==nil) then sortedChildren[index]={offset=1} end
|
||||
|
||||
if v == lineBreakFakeObject then
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
usedSize = 0
|
||||
lineSize = 1
|
||||
index = index + 1
|
||||
sortedChildren[index] = {offset=lineOffset}
|
||||
else
|
||||
local objSize = direction == "row" and v:getWidth() or v:getHeight()
|
||||
if(objSize+usedSize<=maxSize) then
|
||||
table.insert(sortedChildren[index], v)
|
||||
usedSize = usedSize + objSize + spacing
|
||||
else
|
||||
lineOffset = lineOffset + lineSize + spacing
|
||||
lineSize = direction == "row" and v:getHeight() or v:getWidth()
|
||||
index = index + 1
|
||||
usedSize = objSize + spacing
|
||||
sortedChildren[index] = {offset=lineOffset, v}
|
||||
end
|
||||
|
||||
local childHeight = direction == "row" and v:getHeight() or v:getWidth()
|
||||
if childHeight > lineSize then
|
||||
lineSize = childHeight
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function calculateRow(self, children)
|
||||
local containerWidth, containerHeight = self:getSize()
|
||||
local totalFlexGrow = 0
|
||||
local totalFlexShrink = 0
|
||||
local totalFlexBasis = 0
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
totalFlexGrow = totalFlexGrow + child:getFlexGrow()
|
||||
totalFlexShrink = totalFlexShrink + child:getFlexShrink()
|
||||
totalFlexBasis = totalFlexBasis + child:getFlexBasis()
|
||||
end
|
||||
|
||||
local remainingSpace = containerWidth - totalFlexBasis - (spacing * (#children - 1))
|
||||
|
||||
local currentX = 1
|
||||
for _, child in ipairs(children) do
|
||||
if(child~=lineBreakFakeObject)then
|
||||
local childWidth
|
||||
|
||||
local flexGrow = child:getFlexGrow()
|
||||
local flexShrink = child:getFlexShrink()
|
||||
|
||||
local baseWidth = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getWidth()
|
||||
if totalFlexGrow > 0 then
|
||||
childWidth = baseWidth + flexGrow / totalFlexGrow * remainingSpace
|
||||
else
|
||||
childWidth = baseWidth
|
||||
end
|
||||
|
||||
if remainingSpace < 0 and totalFlexShrink > 0 then
|
||||
childWidth = baseWidth + flexShrink / totalFlexShrink * remainingSpace
|
||||
end
|
||||
|
||||
child:setPosition(currentX, children.offset or 1)
|
||||
child:setSize(childWidth, child:getHeight(), false, true)
|
||||
currentX = currentX + childWidth + spacing
|
||||
end
|
||||
end
|
||||
|
||||
if justifyContent == "flex-end" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = containerWidth - totalWidth + 1
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset, y)
|
||||
end
|
||||
elseif justifyContent == "center" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = (containerWidth - totalWidth) / 2 + 1
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset, y)
|
||||
end
|
||||
elseif justifyContent == "space-between" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = (containerWidth - totalWidth) / (#children - 1) + 1
|
||||
for i, child in ipairs(children) do
|
||||
if i > 1 then
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset * (i - 1), y)
|
||||
end
|
||||
end
|
||||
elseif justifyContent == "space-around" then
|
||||
local totalWidth = currentX - spacing
|
||||
local offset = (containerWidth - totalWidth) / #children
|
||||
for i, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x + offset * i - offset / 2, y)
|
||||
end
|
||||
elseif justifyContent == "space-evenly" then
|
||||
local numSpaces = #children + 1
|
||||
local totalChildWidth = 0
|
||||
for _, child in ipairs(children) do
|
||||
totalChildWidth = totalChildWidth + child:getWidth()
|
||||
end
|
||||
local totalSpace = containerWidth - totalChildWidth
|
||||
local offset = math.floor(totalSpace / numSpaces)
|
||||
local remaining = totalSpace - offset * numSpaces
|
||||
currentX = offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
for _, child in ipairs(children) do
|
||||
child:setPosition(currentX, 1)
|
||||
currentX = currentX + child:getWidth() + offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function calculateColumn(self, children)
|
||||
local containerWidth, containerHeight = self:getSize()
|
||||
local totalFlexGrow = 0
|
||||
local totalFlexShrink = 0
|
||||
local totalFlexBasis = 0
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
totalFlexGrow = totalFlexGrow + child:getFlexGrow()
|
||||
totalFlexShrink = totalFlexShrink + child:getFlexShrink()
|
||||
totalFlexBasis = totalFlexBasis + child:getFlexBasis()
|
||||
end
|
||||
|
||||
local remainingSpace = containerHeight - totalFlexBasis - (spacing * (#children - 1))
|
||||
|
||||
local currentY = 1
|
||||
|
||||
for _, child in ipairs(children) do
|
||||
if(child~=lineBreakFakeObject)then
|
||||
local childHeight
|
||||
|
||||
local flexGrow = child:getFlexGrow()
|
||||
local flexShrink = child:getFlexShrink()
|
||||
|
||||
local baseHeight = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getHeight()
|
||||
if totalFlexGrow > 0 then
|
||||
childHeight = baseHeight + flexGrow / totalFlexGrow * remainingSpace
|
||||
else
|
||||
childHeight = baseHeight
|
||||
end
|
||||
|
||||
if remainingSpace < 0 and totalFlexShrink > 0 then
|
||||
childHeight = baseHeight + flexShrink / totalFlexShrink * remainingSpace
|
||||
end
|
||||
|
||||
child:setPosition(children.offset, currentY)
|
||||
child:setSize(child:getWidth(), childHeight, false, true)
|
||||
currentY = currentY + childHeight + spacing
|
||||
end
|
||||
end
|
||||
|
||||
if justifyContent == "flex-end" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = containerHeight - totalHeight + 1
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset)
|
||||
end
|
||||
elseif justifyContent == "center" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = (containerHeight - totalHeight) / 2
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset)
|
||||
end
|
||||
elseif justifyContent == "space-between" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = (containerHeight - totalHeight) / (#children - 1) + 1
|
||||
for i, child in ipairs(children) do
|
||||
if i > 1 then
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset * (i - 1))
|
||||
end
|
||||
end
|
||||
elseif justifyContent == "space-around" then
|
||||
local totalHeight = currentY - spacing
|
||||
local offset = (containerHeight - totalHeight) / #children
|
||||
for i, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, y + offset * i - offset / 2)
|
||||
end
|
||||
elseif justifyContent == "space-evenly" then
|
||||
local numSpaces = #children + 1
|
||||
local totalChildHeight = 0
|
||||
for _, child in ipairs(children) do
|
||||
totalChildHeight = totalChildHeight + child:getHeight()
|
||||
end
|
||||
local totalSpace = containerHeight - totalChildHeight
|
||||
local offset = math.floor(totalSpace / numSpaces)
|
||||
local remaining = totalSpace - offset * numSpaces
|
||||
currentY = offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
for _, child in ipairs(children) do
|
||||
local x, y = child:getPosition()
|
||||
child:setPosition(x, currentY)
|
||||
currentY = currentY + child:getHeight() + offset + (remaining > 0 and 1 or 0)
|
||||
remaining = remaining > 0 and remaining - 1 or 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function applyLayout(self)
|
||||
sortChildren(self)
|
||||
if direction == "row" then
|
||||
for _,v in pairs(sortedChildren)do
|
||||
calculateRow(self, v)
|
||||
end
|
||||
else
|
||||
for _,v in pairs(sortedChildren)do
|
||||
calculateColumn(self, v)
|
||||
end
|
||||
end
|
||||
updateLayout = false
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType == t or base.isType ~= nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setJustifyContent = function(self, value)
|
||||
justifyContent = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getJustifyContent = function(self)
|
||||
return justifyContent
|
||||
end,
|
||||
|
||||
setDirection = function(self, value)
|
||||
direction = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDirection = function(self)
|
||||
return direction
|
||||
end,
|
||||
|
||||
setSpacing = function(self, value)
|
||||
spacing = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSpacing = function(self)
|
||||
return spacing
|
||||
end,
|
||||
|
||||
setWrap = function(self, value)
|
||||
wrap = value
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getWrap = function(self)
|
||||
return wrap
|
||||
end,
|
||||
|
||||
updateLayout = function(self)
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
end,
|
||||
|
||||
addBreak = function(self)
|
||||
table.insert(children, lineBreakFakeObject)
|
||||
updateLayout = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
base.customEventHandler(self, event, ...)
|
||||
if event == "basalt_FrameResize" then
|
||||
updateLayout = true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("flexboxDraw", function()
|
||||
if updateLayout then
|
||||
applyLayout(self)
|
||||
end
|
||||
end, 1)
|
||||
end
|
||||
}
|
||||
|
||||
for k, _ in pairs(basalt.getObjects()) do
|
||||
object["add" .. k] = function(self, name)
|
||||
local baseChild = base["add" .. k](self, name)
|
||||
local child = flexObjectPlugin(baseChild, basalt)
|
||||
table.insert(children, child)
|
||||
updateLayout = true
|
||||
return child
|
||||
end
|
||||
end
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
133
lib/basalt/objects/Frame.lua
Normal file
133
lib/basalt/objects/Frame.lua
Normal file
|
@ -0,0 +1,133 @@
|
|||
local utils = require("utils")
|
||||
|
||||
local max,min,sub,rep,len = math.max,math.min,string.sub,string.rep,string.len
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Container")(name, basalt)
|
||||
local objectType = "Frame"
|
||||
local parent
|
||||
|
||||
local updateRender = true
|
||||
|
||||
local xOffset, yOffset = 0, 0
|
||||
|
||||
base:setSize(30, 10)
|
||||
base:setZIndex(10)
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
setOffset = function(self, xOff, yOff)
|
||||
xOffset = xOff or xOffset
|
||||
yOffset = yOff or yOffset
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
setXOffset = function(self, newXOffset)
|
||||
return self:setOffset(newXOffset, nil)
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
setYOffset = function(self, newYOffset)
|
||||
return self:setOffset(nil, newYOffset)
|
||||
end,
|
||||
|
||||
setParent = function(self, p, ...)
|
||||
base.setParent(self, p, ...)
|
||||
parent = p
|
||||
return self
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if(base.render~=nil)then
|
||||
if(self:isVisible())then
|
||||
base.render(self)
|
||||
local children = self:getChildren()
|
||||
for _, child in ipairs(children) do
|
||||
if (child.element.render ~= nil) then
|
||||
child.element:render()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
updateDraw = function(self)
|
||||
if(parent~=nil)then
|
||||
parent:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
blit = function (self, x, y, t, f, b)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = parent:getOffset()
|
||||
obx = obx - xO
|
||||
oby = oby - yO
|
||||
local w, h = self:getSize()
|
||||
if y >= 1 and y <= h then
|
||||
local t_visible = sub(t, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local f_visible = sub(f, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
local b_visible = sub(b, max(1 - x + 1, 1), max(w - x + 1, 1))
|
||||
parent:blit(max(x + (obx - 1), obx), oby + y - 1, t_visible, f_visible, b_visible)
|
||||
end
|
||||
end,
|
||||
|
||||
setCursor = function(self, blink, x, y, color)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = self:getOffset()
|
||||
parent:setCursor(blink or false, (x or 0)+obx-1 - xO, (y or 0)+oby-1 - yO, color or colors.white)
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
for k,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do
|
||||
object[v] = function(self, x, y, width, height, symbol)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = parent:getOffset()
|
||||
obx = obx - xO
|
||||
oby = oby - yO
|
||||
height = (y < 1 and (height + y > self:getHeight() and self:getHeight() or height + y - 1) or (height + y > self:getHeight() and self:getHeight() - y + 1 or height))
|
||||
width = (x < 1 and (width + x > self:getWidth() and self:getWidth() or width + x - 1) or (width + x > self:getWidth() and self:getWidth() - x + 1 or width))
|
||||
parent[v](parent, max(x + (obx - 1), obx), max(y + (oby - 1), oby), width, height, symbol)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs({"setBG", "setFG", "setText"})do
|
||||
object[v] = function(self, x, y, str)
|
||||
local obx, oby = self:getPosition()
|
||||
local xO, yO = parent:getOffset()
|
||||
obx = obx - xO
|
||||
oby = oby - yO
|
||||
local w, h = self:getSize()
|
||||
if (y >= 1) and (y <= h) then
|
||||
parent[v](parent, max(x + (obx - 1), obx), oby + y - 1, sub(str, max(1 - x + 1, 1), max(w - x + 1,1)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
171
lib/basalt/objects/Graph.lua
Normal file
171
lib/basalt/objects/Graph.lua
Normal file
|
@ -0,0 +1,171 @@
|
|||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Graph"
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setSize(30, 10)
|
||||
|
||||
local graphData = {}
|
||||
local graphColor = colors.gray
|
||||
local graphSymbol = "\7"
|
||||
local graphSymbolCol = colors.black
|
||||
local maxValue = 100
|
||||
local minValue = 0
|
||||
local graphType = "line"
|
||||
local maxEntries = 10
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setGraphColor = function(self, color)
|
||||
graphColor = color or graphColor
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setGraphSymbol = function(self, symbol, symbolcolor)
|
||||
graphSymbol = symbol or graphSymbol
|
||||
graphSymbolCol = symbolcolor or graphSymbolCol
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setGraphSymbolColor = function(self, symbolColor)
|
||||
return self:setGraphSymbolColor(nil, symbolColor)
|
||||
end,
|
||||
|
||||
getGraphSymbol = function(self)
|
||||
return graphSymbol, graphSymbolCol
|
||||
end,
|
||||
|
||||
getGraphSymbolColor = function(self)
|
||||
return graphSymbolCol
|
||||
end,
|
||||
|
||||
addDataPoint = function(self, value)
|
||||
if value >= minValue and value <= maxValue then
|
||||
table.insert(graphData, value)
|
||||
self:updateDraw()
|
||||
end
|
||||
if(#graphData>100)then -- 100 is hard capped to prevent memory leaks
|
||||
table.remove(graphData,1)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setMaxValue = function(self, value)
|
||||
maxValue = value
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getMaxValue = function(self)
|
||||
return maxValue
|
||||
end,
|
||||
|
||||
setMinValue = function(self, value)
|
||||
minValue = value
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getMinValue = function(self)
|
||||
return minValue
|
||||
end,
|
||||
|
||||
setGraphType = function(self, graph_type)
|
||||
if graph_type == "scatter" or graph_type == "line" or graph_type == "bar" then
|
||||
graphType = graph_type
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getGraphType = function(self)
|
||||
return graphType
|
||||
end,
|
||||
|
||||
setMaxEntries = function(self, value)
|
||||
maxEntries = value
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getMaxEntries = function(self)
|
||||
return maxEntries
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
graphData = {}
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("graph", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w, h = self:getSize()
|
||||
local bgCol, fgCol = self:getBackground(), self:getForeground()
|
||||
|
||||
local range = maxValue - minValue
|
||||
local prev_x, prev_y
|
||||
|
||||
local startIndex = #graphData - maxEntries + 1
|
||||
if startIndex < 1 then startIndex = 1 end
|
||||
|
||||
for i = startIndex, #graphData do
|
||||
local data = graphData[i]
|
||||
local x = math.floor(((w - 1) / (maxEntries - 1)) * (i - startIndex) + 1.5)
|
||||
local y = math.floor((h - 1) - ((h - 1) / range) * (data - minValue) + 1.5)
|
||||
|
||||
|
||||
if graphType == "scatter" then
|
||||
self:addBackgroundBox(x, y, 1, 1, graphColor)
|
||||
self:addForegroundBox(x, y, 1, 1, graphSymbolCol)
|
||||
self:addTextBox(x, y, 1, 1, graphSymbol)
|
||||
elseif graphType == "line" then
|
||||
if prev_x and prev_y then
|
||||
local dx = math.abs(x - prev_x)
|
||||
local dy = math.abs(y - prev_y)
|
||||
local sx = prev_x < x and 1 or -1
|
||||
local sy = prev_y < y and 1 or -1
|
||||
local err = dx - dy
|
||||
|
||||
while true do
|
||||
self:addBackgroundBox(prev_x, prev_y, 1, 1, graphColor)
|
||||
self:addForegroundBox(prev_x, prev_y, 1, 1, graphSymbolCol)
|
||||
self:addTextBox(prev_x, prev_y, 1, 1, graphSymbol)
|
||||
|
||||
if prev_x == x and prev_y == y then
|
||||
break
|
||||
end
|
||||
|
||||
local e2 = 2 * err
|
||||
|
||||
if e2 > -dy then
|
||||
err = err - dy
|
||||
prev_x = prev_x + sx
|
||||
end
|
||||
|
||||
if e2 < dx then
|
||||
err = err + dx
|
||||
prev_y = prev_y + sy
|
||||
end
|
||||
end
|
||||
end
|
||||
prev_x, prev_y = x, y
|
||||
elseif graphType == "bar" then
|
||||
self:addBackgroundBox(x - 1, y, 1, h - y, graphColor)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
363
lib/basalt/objects/Image.lua
Normal file
363
lib/basalt/objects/Image.lua
Normal file
|
@ -0,0 +1,363 @@
|
|||
local images = require("images")
|
||||
local bimg = require("bimg")
|
||||
local unpack,sub,max,min = table.unpack,string.sub,math.max,math.min
|
||||
return function(name, basalt)
|
||||
-- Image
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Image"
|
||||
|
||||
local bimgLibrary = bimg()
|
||||
local bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
local originalImage
|
||||
local image
|
||||
local activeFrame = 1
|
||||
|
||||
local infinitePlay = false
|
||||
local animTimer
|
||||
local usePalette = false
|
||||
local autoSize = true
|
||||
|
||||
local xOffset, yOffset = 0, 0
|
||||
|
||||
base:setSize(24, 8)
|
||||
base:setZIndex(2)
|
||||
|
||||
local function getPalette(id)
|
||||
local p = {}
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
p[k] = {term.nativePaletteColor(v)}
|
||||
end
|
||||
end
|
||||
local globalPalette = bimgLibrary.getMetadata("palette")
|
||||
if(globalPalette~=nil)then
|
||||
for k,v in pairs(globalPalette)do
|
||||
p[k] = tonumber(v)
|
||||
end
|
||||
end
|
||||
local localPalette = bimgLibrary.getFrameData("palette")
|
||||
basalt.log(localPalette)
|
||||
if(localPalette~=nil)then
|
||||
for k,v in pairs(localPalette)do
|
||||
p[k] = tonumber(v)
|
||||
end
|
||||
end
|
||||
return p
|
||||
end
|
||||
|
||||
local function checkAutoSize()
|
||||
if(autoSize)then
|
||||
if(bimgLibrary~=nil)then
|
||||
base:setSize(bimgLibrary.getSize())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setOffset = function(self, _x, _y, rel)
|
||||
if(rel)then
|
||||
xOffset = xOffset + _x or 0
|
||||
yOffset = yOffset + _y or 0
|
||||
else
|
||||
xOffset = _x or xOffset
|
||||
yOffset = _y or yOffset
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setXOffset = function(self, _x)
|
||||
return self:setOffset(self, _x, nil)
|
||||
end,
|
||||
|
||||
setYOffset = function(self, _y)
|
||||
return self:setOffset(self, nil, _y)
|
||||
end,
|
||||
|
||||
setSize = function(self, _x, _y)
|
||||
base:setSize(_x, _y)
|
||||
autoSize = false
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
selectFrame = function(self, id)
|
||||
if(bimgLibrary.getFrameObject(id)==nil)then
|
||||
bimgLibrary.addFrame(id)
|
||||
end
|
||||
bimgFrame = bimgLibrary.getFrameObject(id)
|
||||
image = bimgFrame.getImage(id)
|
||||
activeFrame = id
|
||||
self:updateDraw()
|
||||
end,
|
||||
|
||||
addFrame = function(self, id)
|
||||
bimgLibrary.addFrame(id)
|
||||
return self
|
||||
end,
|
||||
|
||||
getFrame = function(self, id)
|
||||
return bimgLibrary.getFrame(id)
|
||||
end,
|
||||
|
||||
getFrameObject = function(self, id)
|
||||
return bimgLibrary.getFrameObject(id)
|
||||
end,
|
||||
|
||||
removeFrame = function(self, id)
|
||||
bimgLibrary.removeFrame(id)
|
||||
return self
|
||||
end,
|
||||
|
||||
moveFrame = function(self, id, dir)
|
||||
bimgLibrary.moveFrame(id, dir)
|
||||
return self
|
||||
end,
|
||||
|
||||
getFrames = function(self)
|
||||
return bimgLibrary.getFrames()
|
||||
end,
|
||||
|
||||
getFrameCount = function(self)
|
||||
return #bimgLibrary.getFrames()
|
||||
end,
|
||||
|
||||
getActiveFrame = function(self)
|
||||
return activeFrame
|
||||
end,
|
||||
|
||||
loadImage = function(self, path)
|
||||
if(fs.exists(path))then
|
||||
local newBimg = images.loadBIMG(path)
|
||||
bimgLibrary = bimg(newBimg)
|
||||
activeFrame = 1
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
originalImage = bimgLibrary.createBimg()
|
||||
image = bimgFrame.getImage()
|
||||
checkAutoSize()
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setPath = function(self, path)
|
||||
return self:loadImage(path)
|
||||
end,
|
||||
|
||||
setImage = function(self, t)
|
||||
if(type(t)=="table")then
|
||||
bimgLibrary = bimg(t)
|
||||
activeFrame = 1
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
originalImage = bimgLibrary.createBimg()
|
||||
image = bimgFrame.getImage()
|
||||
checkAutoSize()
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
bimgLibrary = bimg()
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
image = nil
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getImage = function(self)
|
||||
return bimgLibrary.createBimg()
|
||||
end,
|
||||
|
||||
getImageFrame = function(self, id)
|
||||
return bimgFrame.getImage(id)
|
||||
end,
|
||||
|
||||
usePalette = function(self, use)
|
||||
usePalette = use~=nil and use or true
|
||||
return self
|
||||
end,
|
||||
|
||||
getUsePalette = function(self)
|
||||
return usePalette
|
||||
end,
|
||||
|
||||
setUsePalette = function(self, use)
|
||||
return self:usePalette(use)
|
||||
end,
|
||||
|
||||
play = function(self, inf)
|
||||
if(bimgLibrary.getMetadata("animated"))then
|
||||
local t = bimgLibrary.getMetadata("duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2
|
||||
self:listenEvent("other_event")
|
||||
animTimer = os.startTimer(t)
|
||||
infinitePlay = inf or false
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setPlay = function(self, inf)
|
||||
return self:play(inf)
|
||||
end,
|
||||
|
||||
stop = function(self)
|
||||
os.cancelTimer(animTimer)
|
||||
animTimer = nil
|
||||
infinitePlay = false
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, timerId, ...)
|
||||
base.eventHandler(self, event, timerId, ...)
|
||||
if(event=="timer")then
|
||||
if(timerId==animTimer)then
|
||||
if(bimgLibrary.getFrame(activeFrame+1)~=nil)then
|
||||
activeFrame = activeFrame + 1
|
||||
self:selectFrame(activeFrame)
|
||||
local t = bimgLibrary.getFrameData(activeFrame, "duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2
|
||||
animTimer = os.startTimer(t)
|
||||
else
|
||||
if(infinitePlay)then
|
||||
activeFrame = 1
|
||||
self:selectFrame(activeFrame)
|
||||
local t = bimgLibrary.getFrameData(activeFrame, "duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2
|
||||
animTimer = os.startTimer(t)
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
setMetadata = function(self, key, value)
|
||||
bimgLibrary.setMetadata(key, value)
|
||||
return self
|
||||
end,
|
||||
|
||||
getMetadata = function(self, key)
|
||||
return bimgLibrary.getMetadata(key)
|
||||
end,
|
||||
|
||||
getFrameMetadata = function(self, id, key)
|
||||
return bimgLibrary.getFrameData(id, key)
|
||||
end,
|
||||
|
||||
setFrameMetadata = function(self, id, key, value)
|
||||
bimgLibrary.setFrameData(id, key, value)
|
||||
return self
|
||||
end,
|
||||
|
||||
blit = function(self, text, fg, bg, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.blit(text, fg, bg, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setText = function(self, text, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.text(text, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setBg = function(self, bg, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.bg(bg, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setFg = function(self, fg, _x, _y)
|
||||
x = _x or x
|
||||
y = _y or y
|
||||
bimgFrame.fg(fg, x, y)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getImageSize = function(self)
|
||||
return bimgLibrary.getSize()
|
||||
end,
|
||||
|
||||
setImageSize = function(self, w, h)
|
||||
bimgLibrary.setSize(w, h)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
resizeImage = function(self, w, h)
|
||||
local newBimg = images.resizeBIMG(originalImage, w, h)
|
||||
bimgLibrary = bimg(newBimg)
|
||||
activeFrame = 1
|
||||
bimgFrame = bimgLibrary.getFrameObject(1)
|
||||
image = bimgFrame.getImage()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("image", function()
|
||||
local w,h = self:getSize()
|
||||
local x, y = self:getPosition()
|
||||
local wParent, hParent = self:getParent():getSize()
|
||||
local parentXOffset, parentYOffset = self:getParent():getOffset()
|
||||
|
||||
if(x - parentXOffset > wParent)or(y - parentYOffset > hParent)or(x - parentXOffset + w < 1)or(y - parentYOffset + h < 1)then
|
||||
return
|
||||
end
|
||||
|
||||
if(usePalette)then
|
||||
self:getParent():setPalette(getPalette(activeFrame))
|
||||
end
|
||||
|
||||
if(image~=nil)then
|
||||
for k,v in pairs(image)do
|
||||
if(k+yOffset<=h)and(k+yOffset>=1)then
|
||||
local t,f,b = v[1],v[2],v[3]
|
||||
|
||||
local startIdx = max(1 - xOffset, 1)
|
||||
local endIdx = min(w - xOffset, #t)
|
||||
|
||||
t = sub(t, startIdx, endIdx)
|
||||
f = sub(f, startIdx, endIdx)
|
||||
b = sub(b, startIdx, endIdx)
|
||||
|
||||
self:addBlit(max(1 + xOffset, 1), k + yOffset, t, f, b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
312
lib/basalt/objects/Input.lua
Normal file
312
lib/basalt/objects/Input.lua
Normal file
|
@ -0,0 +1,312 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Input
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Input"
|
||||
|
||||
local inputType = "text"
|
||||
local inputLimit = 0
|
||||
base:setZIndex(5)
|
||||
base:setValue("")
|
||||
base:setSize(12, 1)
|
||||
|
||||
local textX = 1
|
||||
local wIndex = 1
|
||||
|
||||
local defaultText = ""
|
||||
local defaultBGCol = colors.black
|
||||
local defaultFGCol = colors.lightGray
|
||||
local showingText = defaultText
|
||||
local internalValueChange = false
|
||||
|
||||
local object = {
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("key")
|
||||
self:listenEvent("char")
|
||||
self:listenEvent("other_event")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setDefaultFG = function(self, fCol)
|
||||
return self:setDefaultText(self, defaultText, fCol, nil)
|
||||
end,
|
||||
|
||||
setDefaultBG = function(self, bCol)
|
||||
return self:setDefaultText(self, defaultText, nil, bCol)
|
||||
end,
|
||||
|
||||
setDefaultText = function(self, text, fCol, bCol)
|
||||
defaultText = text
|
||||
defaultFGCol = fCol or defaultFGCol
|
||||
defaultBGCol = bCol or defaultBGCol
|
||||
if (self:isFocused()) then
|
||||
showingText = ""
|
||||
else
|
||||
showingText = defaultText
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDefaultText = function(self)
|
||||
return defaultText, defaultFGCol, defaultBGCol
|
||||
end,
|
||||
|
||||
setOffset = function(self, x)
|
||||
wIndex = x
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return wIndex
|
||||
end,
|
||||
|
||||
setTextOffset = function(self, x)
|
||||
textX = x
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextOffset = function(self)
|
||||
return textX
|
||||
end,
|
||||
|
||||
setInputType = function(self, t)
|
||||
inputType = t
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getInputType = function(self)
|
||||
return inputType
|
||||
end,
|
||||
|
||||
setValue = function(self, val)
|
||||
base.setValue(self, tostring(val))
|
||||
if not (internalValueChange) then
|
||||
textX = tostring(val):len() + 1
|
||||
wIndex = math.max(1, textX-self:getWidth()+1)
|
||||
if(self:isFocused())then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self:getForeground())
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getValue = function(self)
|
||||
local val = base.getValue(self)
|
||||
return inputType == "number" and tonumber(val) or val
|
||||
end,
|
||||
|
||||
setInputLimit = function(self, limit)
|
||||
inputLimit = tonumber(limit) or inputLimit
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getInputLimit = function(self)
|
||||
return inputLimit
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
base.getFocusHandler(self)
|
||||
local parent = self:getParent()
|
||||
if (parent ~= nil) then
|
||||
local obx, oby = self:getPosition()
|
||||
showingText = ""
|
||||
if(defaultText~="")then
|
||||
self:updateDraw()
|
||||
end
|
||||
parent:setCursor(true, obx + textX - wIndex, oby+math.max(math.ceil(self:getHeight()/2-1, 1)), self:getForeground())
|
||||
end
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
local parent = self:getParent()
|
||||
showingText = defaultText
|
||||
if(defaultText~="")then
|
||||
self:updateDraw()
|
||||
end
|
||||
parent:setCursor(false)
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key)
|
||||
if (base.keyHandler(self, key)) then
|
||||
local w,h = self:getSize()
|
||||
local parent = self:getParent()
|
||||
internalValueChange = true
|
||||
if (key == keys.backspace) then
|
||||
-- on backspace
|
||||
local text = tostring(base.getValue())
|
||||
if (textX > 1) then
|
||||
self:setValue(text:sub(1, textX - 2) .. text:sub(textX, text:len()))
|
||||
textX = math.max(textX - 1, 1)
|
||||
if (textX < wIndex) then
|
||||
wIndex = math.max(wIndex - 1, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (key == keys.enter) then
|
||||
parent:clearFocusedChild(self)
|
||||
end
|
||||
if (key == keys.right) then
|
||||
local tLength = tostring(base.getValue()):len()
|
||||
textX = textX + 1
|
||||
|
||||
if (textX > tLength) then
|
||||
textX = tLength + 1
|
||||
end
|
||||
textX = math.max(textX, 1)
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
end
|
||||
wIndex = math.max(wIndex, 1)
|
||||
end
|
||||
|
||||
if (key == keys.left) then
|
||||
-- left arrow
|
||||
textX = textX - 1
|
||||
if (textX >= 1) then
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX
|
||||
end
|
||||
end
|
||||
textX = math.max(textX, 1)
|
||||
wIndex = math.max(wIndex, 1)
|
||||
end
|
||||
local obx, oby = self:getPosition()
|
||||
local val = tostring(base.getValue())
|
||||
|
||||
self:updateDraw()
|
||||
internalValueChange = false
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if (base.charHandler(self, char)) then
|
||||
internalValueChange = true
|
||||
local w,h = self:getSize()
|
||||
local text = base.getValue()
|
||||
if (text:len() < inputLimit or inputLimit <= 0) then
|
||||
if (inputType == "number") then
|
||||
local cache = text
|
||||
if (textX==1 and char == "-") or (char == ".") or (tonumber(char) ~= nil) then
|
||||
self:setValue(text:sub(1, textX - 1) .. char .. text:sub(textX, text:len()))
|
||||
textX = textX + 1
|
||||
if(char==".")or(char=="-")and(#text>0)then
|
||||
if (tonumber(base.getValue()) == nil) then
|
||||
self:setValue(cache)
|
||||
textX = textX - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
self:setValue(text:sub(1, textX - 1) .. char .. text:sub(textX, text:len()))
|
||||
textX = textX + 1
|
||||
end
|
||||
if (textX >= w + wIndex) then
|
||||
wIndex = wIndex + 1
|
||||
end
|
||||
end
|
||||
local obx, oby = self:getPosition()
|
||||
local val = tostring(base.getValue())
|
||||
|
||||
internalValueChange = false
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if(base.mouseHandler(self, button, x, y))then
|
||||
local parent = self:getParent()
|
||||
local ax, ay = self:getPosition()
|
||||
local obx, oby = self:getAbsolutePosition(ax, ay)
|
||||
local w, h = self:getSize()
|
||||
textX = x - obx + wIndex
|
||||
local text = base.getValue()
|
||||
if (textX > text:len()) then
|
||||
textX = text:len() + 1
|
||||
end
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
parent:setCursor(true, ax + textX - wIndex, ay+math.max(math.ceil(h/2-1, 1)), self:getForeground())
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, btn, x, y, xOffset, yOffset)
|
||||
if(self:isFocused())then
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
if(base.dragHandler(self, btn, x, y, xOffset, yOffset))then
|
||||
return true
|
||||
end
|
||||
end
|
||||
local parent = self:getParent()
|
||||
parent:clearFocusedChild()
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("input", function()
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign)
|
||||
|
||||
local val = tostring(base.getValue())
|
||||
local bCol = self:getBackground()
|
||||
local fCol = self:getForeground()
|
||||
local text
|
||||
if (val:len() <= 0) then
|
||||
text = showingText
|
||||
bCol = defaultBGCol or bCol
|
||||
fCol = defaultFGCol or fCol
|
||||
end
|
||||
|
||||
text = showingText
|
||||
if (val ~= "") then
|
||||
text = val
|
||||
end
|
||||
text = text:sub(wIndex, w + wIndex - 1)
|
||||
local space = w - text:len()
|
||||
if (space < 0) then
|
||||
space = 0
|
||||
end
|
||||
if (inputType == "password") and (val ~= "") then
|
||||
text = string.rep("*", text:len())
|
||||
end
|
||||
text = text .. string.rep(" ", space)
|
||||
self:addBlit(1, verticalAlign, text, tHex[fCol]:rep(text:len()), tHex[bCol]:rep(text:len()))
|
||||
|
||||
if(self:isFocused())then
|
||||
parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self:getForeground())
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
115
lib/basalt/objects/Label.lua
Normal file
115
lib/basalt/objects/Label.lua
Normal file
|
@ -0,0 +1,115 @@
|
|||
local utils = require("utils")
|
||||
local wrapText = utils.wrapText
|
||||
local writeWrappedText = utils.writeWrappedText
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
-- Label
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Label"
|
||||
|
||||
base:setZIndex(3)
|
||||
base:setSize(5, 1)
|
||||
base:setBackground(false)
|
||||
|
||||
local autoSize = true
|
||||
local text, textAlign = "Label", "left"
|
||||
|
||||
local object = {
|
||||
--- Returns the object type.
|
||||
--- @return string
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
--- Returns the label's base object.
|
||||
--- @return object
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
--- Changes the label's text.
|
||||
--- @param newText string The new text of the label.
|
||||
--- @return object
|
||||
setText = function(self, newText)
|
||||
text = tostring(newText)
|
||||
if(autoSize)then
|
||||
local t = wrapText(text, #text)
|
||||
local newW, newH = 1,1
|
||||
for k,v in pairs(t)do
|
||||
newH = newH+1
|
||||
newW = math.max(newW, v:len())
|
||||
end
|
||||
self:setSize(newW, newH)
|
||||
autoSize = true
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
--- Returns the label's autoSize property.
|
||||
--- @return boolean
|
||||
getAutoSize = function(self)
|
||||
return autoSize
|
||||
end,
|
||||
|
||||
--- Sets the label's autoSize property.
|
||||
--- @param bool boolean The new value of the autoSize property.
|
||||
--- @return object
|
||||
setAutoSize = function(self, bool)
|
||||
autoSize = bool
|
||||
return self
|
||||
end,
|
||||
|
||||
--- Returns the label's text.
|
||||
--- @return string
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
--- Sets the size of the label.
|
||||
--- @param width number The width of the label.
|
||||
--- @param height number The height of the label.
|
||||
--- @return object
|
||||
setSize = function(self, width, height)
|
||||
base.setSize(self, width, height)
|
||||
autoSize = false
|
||||
return self
|
||||
end,
|
||||
|
||||
--- Gets the text alignment of the label.
|
||||
--- @return string
|
||||
getTextAlign = function(self)
|
||||
return textAlign
|
||||
end,
|
||||
|
||||
--- Sets the text alignment of the label.
|
||||
--- @param align string The alignment of the text. Can be "left", "center", or "right".
|
||||
--- @return object
|
||||
setTextAlign = function(self, align)
|
||||
textAlign = align or textAlign
|
||||
return self;
|
||||
end,
|
||||
|
||||
--- Queues a new draw function to be called when the object is drawn.
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("label", function()
|
||||
local w, h = self:getSize()
|
||||
local align = textAlign=="center" and math.floor(w/2-text:len()/2+0.5) or textAlign=="right" and w-(text:len()-1) or 1
|
||||
writeWrappedText(self, align, 1, text, w+1, h)
|
||||
end)
|
||||
end,
|
||||
|
||||
--- Initializes the label.
|
||||
init = function(self)
|
||||
base.init(self)
|
||||
local parent = self:getParent()
|
||||
self:setForeground(parent:getForeground())
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
279
lib/basalt/objects/List.lua
Normal file
279
lib/basalt/objects/List.lua
Normal file
|
@ -0,0 +1,279 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "List"
|
||||
|
||||
local list = {}
|
||||
local itemSelectedBG = colors.black
|
||||
local itemSelectedFG = colors.lightGray
|
||||
local selectionColorActive = true
|
||||
local textAlign = "left"
|
||||
local yOffset = 0
|
||||
local scrollable = true
|
||||
|
||||
base:setSize(16, 8)
|
||||
base:setZIndex(5)
|
||||
|
||||
local object = {
|
||||
init = function(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("mouse_scroll")
|
||||
return base.init(self)
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
setTextAlign = function(self, align)
|
||||
textAlign = align
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextAlign = function(self)
|
||||
return textAlign
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
addItem = function(self, text, bgCol, fgCol, ...)
|
||||
table.insert(list, { text = text, bgCol = bgCol or self:getBackground(), fgCol = fgCol or self:getForeground(), args = { ... } })
|
||||
if (#list <= 1) then
|
||||
self:setValue(list[1], false)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setOptions = function(self, ...)
|
||||
list = {}
|
||||
for k,v in pairs(...)do
|
||||
if(type(v)=="string")then
|
||||
table.insert(list, { text = v, bgCol = self:getBackground(), fgCol = self:getForeground(), args = {} })
|
||||
else
|
||||
table.insert(list, { text = v[1], bgCol = v[2] or self:getBackground(), fgCol = v[3] or self:getForeground(), args = v[4] or {} })
|
||||
end
|
||||
end
|
||||
self:setValue(list[1], false)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setOffset = function(self, yOff)
|
||||
yOffset = yOff
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
removeItem = function(self, index)
|
||||
if(type(index)=="number")then
|
||||
table.remove(list, index)
|
||||
elseif(type(index)=="table")then
|
||||
for k,v in pairs(list)do
|
||||
if(v==index)then
|
||||
table.remove(list, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getItem = function(self, index)
|
||||
return list[index]
|
||||
end,
|
||||
|
||||
getAll = function(self)
|
||||
return list
|
||||
end,
|
||||
|
||||
getOptions = function(self)
|
||||
return list
|
||||
end,
|
||||
|
||||
getItemIndex = function(self)
|
||||
local selected = self:getValue()
|
||||
for key, value in pairs(list) do
|
||||
if (value == selected) then
|
||||
return key
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
list = {}
|
||||
self:setValue({}, false)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getItemCount = function(self)
|
||||
return #list
|
||||
end,
|
||||
|
||||
editItem = function(self, index, text, bgCol, fgCol, ...)
|
||||
table.remove(list, index)
|
||||
table.insert(list, index, { text = text, bgCol = bgCol or self:getBackground(), fgCol = fgCol or self:getForeground(), args = { ... } })
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
selectItem = function(self, index)
|
||||
self:setValue(list[index] or {}, false)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionColor = function(self, bgCol, fgCol, active)
|
||||
itemSelectedBG = bgCol or self:getBackground()
|
||||
itemSelectedFG = fgCol or self:getForeground()
|
||||
selectionColorActive = active~=nil and active or true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionBG = function(self, bgCol)
|
||||
return self:setSelectionColor(bgCol, nil, selectionColorActive)
|
||||
end,
|
||||
|
||||
setSelectionFG = function(self, fgCol)
|
||||
return self:setSelectionColor(nil, fgCol, selectionColorActive)
|
||||
end,
|
||||
|
||||
getSelectionColor = function(self)
|
||||
return itemSelectedBG, itemSelectedFG
|
||||
end,
|
||||
|
||||
getSelectionBG = function(self)
|
||||
return itemSelectedBG
|
||||
end,
|
||||
|
||||
getSelectionFG = function(self)
|
||||
return itemSelectedFG
|
||||
end,
|
||||
|
||||
isSelectionColorActive = function(self)
|
||||
return selectionColorActive
|
||||
end,
|
||||
|
||||
setScrollable = function(self, scroll)
|
||||
scrollable = scroll
|
||||
if(scroll==nil)then scrollable = true end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollable = function(self)
|
||||
return scrollable
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base.scrollHandler(self, dir, x, y))then
|
||||
if(scrollable)then
|
||||
local w,h = self:getSize()
|
||||
yOffset = yOffset + dir
|
||||
if (yOffset < 0) then
|
||||
yOffset = 0
|
||||
end
|
||||
if (dir >= 1) then
|
||||
if (#list > h) then
|
||||
if (yOffset > #list - h) then
|
||||
yOffset = #list - h
|
||||
end
|
||||
if (yOffset >= #list) then
|
||||
yOffset = #list - 1
|
||||
end
|
||||
else
|
||||
yOffset = yOffset - 1
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if(base.mouseHandler(self, button, x, y))then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local w,h = self:getSize()
|
||||
if (#list > 0) then
|
||||
for n = 1, h do
|
||||
if (list[n + yOffset] ~= nil) then
|
||||
if (obx <= x) and (obx + w > x) and (oby + n - 1 == y) then
|
||||
self:setValue(list[n + yOffset])
|
||||
self:selectHandler()
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
return self:mouseHandler(button, x, y)
|
||||
end,
|
||||
|
||||
touchHandler = function(self, x, y)
|
||||
return self:mouseHandler(1, x, y)
|
||||
end,
|
||||
|
||||
onSelect = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("select_item", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
selectHandler = function(self)
|
||||
self:sendEvent("select_item", self:getValue())
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("list", function()
|
||||
local w, h = self:getSize()
|
||||
for n = 1, h do
|
||||
if list[n + yOffset] then
|
||||
local t = list[n + yOffset].text
|
||||
local fg, bg = list[n + yOffset].fgCol, list[n + yOffset].bgCol
|
||||
if list[n + yOffset] == self:getValue() and selectionColorActive then
|
||||
fg, bg = itemSelectedFG, itemSelectedBG
|
||||
end
|
||||
self:addText(1, n, t:sub(1,w))
|
||||
self:addBG(1, n, tHex[bg]:rep(w))
|
||||
self:addFG(1, n, tHex[fg]:rep(w))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
131
lib/basalt/objects/Menubar.lua
Normal file
131
lib/basalt/objects/Menubar.lua
Normal file
|
@ -0,0 +1,131 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("List")(name, basalt)
|
||||
local objectType = "Menubar"
|
||||
local object = {}
|
||||
|
||||
base:setSize(30, 1)
|
||||
base:setZIndex(5)
|
||||
|
||||
local itemOffset = 0
|
||||
local space, outerSpace = 1, 1
|
||||
local scrollable = true
|
||||
|
||||
local function maxScroll()
|
||||
local mScroll = 0
|
||||
local w = base:getWidth()
|
||||
local list = base:getAll()
|
||||
for n = 1, #list do
|
||||
mScroll = mScroll + list[n].text:len() + space * 2
|
||||
end
|
||||
return math.max(mScroll - w, 0)
|
||||
end
|
||||
|
||||
object = {
|
||||
init = function(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("mouse_scroll")
|
||||
return base.init(self)
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
setSpace = function(self, _space)
|
||||
space = _space or space
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSpace = function(self)
|
||||
return space
|
||||
end,
|
||||
|
||||
setScrollable = function(self, scroll)
|
||||
scrollable = scroll
|
||||
if(scroll==nil)then scrollable = true end
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollable = function(self)
|
||||
return scrollable
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if(base:getBase().mouseHandler(self, button, x, y))then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local w,h = self:getSize()
|
||||
local xPos = 0
|
||||
local list = self:getAll()
|
||||
for n = 1, #list do
|
||||
if (list[n] ~= nil) then
|
||||
if (objX + xPos <= x + itemOffset) and (objX + xPos + list[n].text:len() + (space*2) > x + itemOffset) and (objY == y) then
|
||||
self:setValue(list[n])
|
||||
self:sendEvent(event, self, event, 0, x, y, list[n])
|
||||
end
|
||||
xPos = xPos + list[n].text:len() + space * 2
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base:getBase().scrollHandler(self, dir, x, y))then
|
||||
if(scrollable)then
|
||||
itemOffset = itemOffset + dir
|
||||
if (itemOffset < 0) then
|
||||
itemOffset = 0
|
||||
end
|
||||
|
||||
local mScroll = maxScroll()
|
||||
|
||||
if (itemOffset > mScroll) then
|
||||
itemOffset = mScroll
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("list", function()
|
||||
local parent = self:getParent()
|
||||
local w,h = self:getSize()
|
||||
local text = ""
|
||||
local textBGCol = ""
|
||||
local textFGCol = ""
|
||||
local itemSelectedBG, itemSelectedFG = self:getSelectionColor()
|
||||
for _, v in pairs(self:getAll()) do
|
||||
local newItem = (" "):rep(space) .. v.text .. (" "):rep(space)
|
||||
text = text .. newItem
|
||||
if(v == self:getValue())then
|
||||
textBGCol = textBGCol .. tHex[itemSelectedBG or v.bgCol or self:getBackground()]:rep(newItem:len())
|
||||
textFGCol = textFGCol .. tHex[itemSelectedFG or v.FgCol or self:getForeground()]:rep(newItem:len())
|
||||
else
|
||||
textBGCol = textBGCol .. tHex[v.bgCol or self:getBackground()]:rep(newItem:len())
|
||||
textFGCol = textFGCol .. tHex[v.FgCol or self:getForeground()]:rep(newItem:len())
|
||||
end
|
||||
end
|
||||
|
||||
self:addBlit(1, 1, text:sub(itemOffset+1, w+itemOffset), textFGCol:sub(itemOffset+1, w+itemOffset), textBGCol:sub(itemOffset+1, w+itemOffset))
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
81
lib/basalt/objects/MonitorFrame.lua
Normal file
81
lib/basalt/objects/MonitorFrame.lua
Normal file
|
@ -0,0 +1,81 @@
|
|||
local basaltMon = require("basaltMon")
|
||||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("BaseFrame")(name, basalt)
|
||||
local objectType = "MonitorFrame"
|
||||
|
||||
base:setTerm(nil)
|
||||
local isMonitorGroup = false
|
||||
local monGroup
|
||||
|
||||
local object = {
|
||||
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
setMonitor = function(self, newMon)
|
||||
if(type(newMon)=="string")then
|
||||
local mon = peripheral.wrap(newMon)
|
||||
if(mon~=nil)then
|
||||
self:setTerm(mon)
|
||||
end
|
||||
elseif(type(newMon)=="table")then
|
||||
self:setTerm(newMon)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setMonitorGroup = function(self, monGrp)
|
||||
monGroup = basaltMon(monGrp)
|
||||
self:setTerm(monGroup)
|
||||
isMonitorGroup = true
|
||||
return self
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if(self:getTerm()~=nil)then
|
||||
base.render(self)
|
||||
end
|
||||
end,
|
||||
|
||||
show = function(self)
|
||||
base:getBase().show(self)
|
||||
basalt.setActiveFrame(self)
|
||||
for k,v in pairs(colors)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(v, colors.packRGB(term.nativePaletteColor((v))))
|
||||
end
|
||||
end
|
||||
for k,v in pairs(colorTheme)do
|
||||
if(type(v)=="number")then
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], v)
|
||||
else
|
||||
local r,g,b = table.unpack(v)
|
||||
termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.mouseHandler = function(self, btn, x, y, isMon, monitor, ...)
|
||||
if(isMonitorGroup)then
|
||||
x, y = monGroup.calculateClick(monitor, x, y)
|
||||
end
|
||||
base.mouseHandler(self, btn, x, y, isMon, monitor, ...)
|
||||
end
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
99
lib/basalt/objects/MovableFrame.lua
Normal file
99
lib/basalt/objects/MovableFrame.lua
Normal file
|
@ -0,0 +1,99 @@
|
|||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Frame")(name, basalt)
|
||||
local objectType = "MovableFrame"
|
||||
local parent
|
||||
|
||||
local dragXOffset, dragYOffset, isDragging = 0, 0, false
|
||||
|
||||
local dragMap = {
|
||||
{x1 = 1, x2 = "width", y1 = 1, y2 = 1}
|
||||
}
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setDraggingMap = function(self, t)
|
||||
dragMap = t
|
||||
return self
|
||||
end,
|
||||
|
||||
getDraggingMap = function(self)
|
||||
return dragMap
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or (base.isType~=nil and base.isType(t)) or false
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
base.load(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
removeChildren = function(self)
|
||||
base.removeChildren(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
dragHandler = function(self, btn, x, y)
|
||||
if(base.dragHandler(self, btn, x, y))then
|
||||
if (isDragging) then
|
||||
local xO, yO = parent:getOffset()
|
||||
xO = xO < 0 and math.abs(xO) or -xO
|
||||
yO = yO < 0 and math.abs(yO) or -yO
|
||||
local parentX = 1
|
||||
local parentY = 1
|
||||
parentX, parentY = parent:getAbsolutePosition()
|
||||
self:setPosition(x + dragXOffset - (parentX - 1) + xO, y + dragYOffset - (parentY - 1) + yO)
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, btn, x, y, ...)
|
||||
if(base.mouseHandler(self, btn, x, y, ...))then
|
||||
parent:setImportant(self)
|
||||
local fx, fy = self:getAbsolutePosition()
|
||||
local w, h = self:getSize()
|
||||
for k,v in pairs(dragMap)do
|
||||
local x1, x2 = v.x1=="width" and w or v.x1, v.x2=="width" and w or v.x2
|
||||
local y1, y2= v.y1=="height" and h or v.y1, v.y2=="height" and h or v.y2
|
||||
if(x>=fx+x1-1)and(x<=fx+x2-1)and(y>=fy+y1-1)and(y<=fy+y2-1)then
|
||||
isDragging = true
|
||||
dragXOffset = fx - x
|
||||
dragYOffset = fy - y
|
||||
return true
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, ...)
|
||||
isDragging = false
|
||||
return base.mouseUpHandler(self, ...)
|
||||
end,
|
||||
|
||||
setParent = function(self, p, ...)
|
||||
base.setParent(self, p, ...)
|
||||
parent = p
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
283
lib/basalt/objects/Object.lua
Normal file
283
lib/basalt/objects/Object.lua
Normal file
|
@ -0,0 +1,283 @@
|
|||
local basaltEvent = require("basaltEvent")
|
||||
local utils = require("utils")
|
||||
local uuid = utils.uuid
|
||||
|
||||
local unpack,sub = table.unpack,string.sub
|
||||
|
||||
return function(name, basalt)
|
||||
name = name or uuid()
|
||||
assert(basalt~=nil, "Unable to find basalt instance! ID: "..name)
|
||||
|
||||
-- Base object
|
||||
local objectType = "Object" -- not changeable
|
||||
local isEnabled,initialized = true,false
|
||||
|
||||
local eventSystem = basaltEvent()
|
||||
local registeredEvents = {}
|
||||
local activeEvents = {}
|
||||
|
||||
local parent
|
||||
|
||||
local object = {
|
||||
init = function(self)
|
||||
if(initialized)then return false end
|
||||
initialized = true
|
||||
return true
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
isType = function(self, t)
|
||||
return objectType==t
|
||||
end,
|
||||
|
||||
getProperty = function(self, name)
|
||||
local get = self["get" .. name:gsub("^%l", string.upper)]
|
||||
if (get ~= nil) then
|
||||
return get(self)
|
||||
end
|
||||
end,
|
||||
|
||||
setProperty = function(self, name, ...)
|
||||
local set = self["set" .. name:gsub("^%l", string.upper)]
|
||||
if (set ~= nil) then
|
||||
return set(self, ...)
|
||||
end
|
||||
end,
|
||||
|
||||
getName = function(self)
|
||||
return name
|
||||
end,
|
||||
|
||||
getParent = function(self)
|
||||
return parent
|
||||
end,
|
||||
|
||||
setParent = function(self, newParent, noRemove)
|
||||
if(noRemove)then parent = newParent return self end
|
||||
if (newParent.getType ~= nil and newParent:isType("Container")) then
|
||||
self:remove()
|
||||
newParent:addChild(self)
|
||||
if (self.show) then
|
||||
self:show()
|
||||
end
|
||||
parent = newParent
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
updateEvents = function(self)
|
||||
for k,v in pairs(activeEvents)do
|
||||
parent:removeEvent(k, self)
|
||||
if(v)then
|
||||
parent:addEvent(k, self)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
listenEvent = function(self, event, active)
|
||||
if(parent~=nil)then
|
||||
if(active)or(active==nil)then
|
||||
activeEvents[event] = true
|
||||
parent:addEvent(event, self)
|
||||
elseif(active==false)then
|
||||
activeEvents[event] = false
|
||||
parent:removeEvent(event, self)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getZIndex = function(self)
|
||||
return 1
|
||||
end,
|
||||
|
||||
enable = function(self)
|
||||
isEnabled = true
|
||||
return self
|
||||
end,
|
||||
|
||||
disable = function(self)
|
||||
isEnabled = false
|
||||
return self
|
||||
end,
|
||||
|
||||
isEnabled = function(self)
|
||||
return isEnabled
|
||||
end,
|
||||
|
||||
remove = function(self)
|
||||
if (parent ~= nil) then
|
||||
parent:removeChild(self)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBaseFrame = function(self)
|
||||
if(parent~=nil)then
|
||||
return parent:getBaseFrame()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onEvent = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("other_event", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getEventSystem = function(self)
|
||||
return eventSystem
|
||||
end,
|
||||
|
||||
getRegisteredEvents = function(self)
|
||||
return registeredEvents
|
||||
end,
|
||||
|
||||
registerEvent = function(self, event, func)
|
||||
if(parent~=nil)then
|
||||
parent:addEvent(event, self)
|
||||
end
|
||||
eventSystem:registerEvent(event, func)
|
||||
if (registeredEvents[event] == nil) then
|
||||
registeredEvents[event] = {}
|
||||
end
|
||||
table.insert(registeredEvents[event], func)
|
||||
end,
|
||||
|
||||
removeEvent = function(self, event, index)
|
||||
if(eventSystem:getEventCount(event)<1)then
|
||||
if(parent~=nil)then
|
||||
parent:removeEvent(event, self)
|
||||
end
|
||||
end
|
||||
eventSystem:removeEvent(event, index)
|
||||
if (registeredEvents[event] ~= nil) then
|
||||
table.remove(registeredEvents[event], index)
|
||||
if (#registeredEvents[event] == 0) then
|
||||
registeredEvents[event] = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
local val = self:sendEvent("other_event", event, ...)
|
||||
if(val~=nil)then return val end
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
local val = self:sendEvent("custom_event", event, ...)
|
||||
if(val~=nil)then return val end
|
||||
return true
|
||||
end,
|
||||
|
||||
sendEvent = function(self, event, ...)
|
||||
if(event=="other_event")or(event=="custom_event")then
|
||||
return eventSystem:sendEvent(event, self, ...)
|
||||
end
|
||||
return eventSystem:sendEvent(event, self, event, ...)
|
||||
end,
|
||||
|
||||
onClick = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_click", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onClickUp = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_up", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onRelease = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_release", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onScroll = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_scroll", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onHover = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_hover", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onLeave = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_leave", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onDrag = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("mouse_drag", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onKey = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("key", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onChar = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("char", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onKeyUp = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("key_up", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return object
|
||||
end
|
16
lib/basalt/objects/Pane.lua
Normal file
16
lib/basalt/objects/Pane.lua
Normal file
|
@ -0,0 +1,16 @@
|
|||
return function(name, basalt)
|
||||
-- Pane
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Pane"
|
||||
|
||||
base:setSize(25, 10)
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
721
lib/basalt/objects/Program.lua
Normal file
721
lib/basalt/objects/Program.lua
Normal file
|
@ -0,0 +1,721 @@
|
|||
local tHex = require("tHex")
|
||||
local process = require("process")
|
||||
|
||||
local sub = string.sub
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Program"
|
||||
local object
|
||||
local cachedPath
|
||||
local enviroment = {}
|
||||
|
||||
local function createBasaltWindow(x, y, width, height)
|
||||
local xCursor, yCursor = 1, 1
|
||||
local bgColor, fgColor = colors.black, colors.white
|
||||
local cursorBlink = false
|
||||
local visible = false
|
||||
|
||||
local cacheT = {}
|
||||
local cacheBG = {}
|
||||
local cacheFG = {}
|
||||
|
||||
local tPalette = {}
|
||||
|
||||
local emptySpaceLine
|
||||
local emptyColorLines = {}
|
||||
|
||||
for i = 0, 15 do
|
||||
local c = 2 ^ i
|
||||
tPalette[c] = { basalt.getTerm().getPaletteColour(c) }
|
||||
end
|
||||
|
||||
local function createEmptyLines()
|
||||
emptySpaceLine = (" "):rep(width)
|
||||
for n = 0, 15 do
|
||||
local nColor = 2 ^ n
|
||||
local sHex = tHex[nColor]
|
||||
emptyColorLines[nColor] = sHex:rep(width)
|
||||
end
|
||||
end
|
||||
|
||||
local function recreateWindowArray()
|
||||
createEmptyLines()
|
||||
local emptyText = emptySpaceLine
|
||||
local emptyFG = emptyColorLines[colors.white]
|
||||
local emptyBG = emptyColorLines[colors.black]
|
||||
for n = 1, height do
|
||||
cacheT[n] = sub(cacheT[n] == nil and emptyText or cacheT[n] .. emptyText:sub(1, width - cacheT[n]:len()), 1, width)
|
||||
cacheFG[n] = sub(cacheFG[n] == nil and emptyFG or cacheFG[n] .. emptyFG:sub(1, width - cacheFG[n]:len()), 1, width)
|
||||
cacheBG[n] = sub(cacheBG[n] == nil and emptyBG or cacheBG[n] .. emptyBG:sub(1, width - cacheBG[n]:len()), 1, width)
|
||||
end
|
||||
base.updateDraw(base)
|
||||
end
|
||||
recreateWindowArray()
|
||||
|
||||
local function updateCursor()
|
||||
if xCursor >= 1 and yCursor >= 1 and xCursor <= width and yCursor <= height then
|
||||
--parentTerminal.setCursorPos(xCursor + x - 1, yCursor + y - 1)
|
||||
else
|
||||
--parentTerminal.setCursorPos(0, 0)
|
||||
end
|
||||
--parentTerminal.setTextColor(fgColor)
|
||||
end
|
||||
|
||||
local function internalBlit(sText, sTextColor, sBackgroundColor)
|
||||
if yCursor < 1 or yCursor > height or xCursor < 1 or xCursor + #sText - 1 > width then
|
||||
return
|
||||
end
|
||||
cacheT[yCursor] = sub(cacheT[yCursor], 1, xCursor - 1) .. sText .. sub(cacheT[yCursor], xCursor + #sText, width)
|
||||
cacheFG[yCursor] = sub(cacheFG[yCursor], 1, xCursor - 1) .. sTextColor .. sub(cacheFG[yCursor], xCursor + #sText, width)
|
||||
cacheBG[yCursor] = sub(cacheBG[yCursor], 1, xCursor - 1) .. sBackgroundColor .. sub(cacheBG[yCursor], xCursor + #sText, width)
|
||||
xCursor = xCursor + #sText
|
||||
if visible then
|
||||
updateCursor()
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local function setText(_x, _y, text)
|
||||
if (text ~= nil) then
|
||||
local gText = cacheT[_y]
|
||||
if (gText ~= nil) then
|
||||
cacheT[_y] = sub(gText:sub(1, _x - 1) .. text .. gText:sub(_x + (text:len()), width), 1, width)
|
||||
end
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local function setBG(_x, _y, colorStr)
|
||||
if (colorStr ~= nil) then
|
||||
local gBG = cacheBG[_y]
|
||||
if (gBG ~= nil) then
|
||||
cacheBG[_y] = sub(gBG:sub(1, _x - 1) .. colorStr .. gBG:sub(_x + (colorStr:len()), width), 1, width)
|
||||
end
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local function setFG(_x, _y, colorStr)
|
||||
if (colorStr ~= nil) then
|
||||
local gFG = cacheFG[_y]
|
||||
if (gFG ~= nil) then
|
||||
cacheFG[_y] = sub(gFG:sub(1, _x - 1) .. colorStr .. gFG:sub(_x + (colorStr:len()), width), 1, width)
|
||||
end
|
||||
end
|
||||
object:updateDraw()
|
||||
end
|
||||
|
||||
local setTextColor = function(color)
|
||||
if type(color) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(color) .. ")", 2)
|
||||
elseif tHex[color] == nil then
|
||||
error("Invalid color (got " .. color .. ")", 2)
|
||||
end
|
||||
fgColor = color
|
||||
end
|
||||
|
||||
local setBackgroundColor = function(color)
|
||||
if type(color) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(color) .. ")", 2)
|
||||
elseif tHex[color] == nil then
|
||||
error("Invalid color (got " .. color .. ")", 2)
|
||||
end
|
||||
bgColor = color
|
||||
end
|
||||
|
||||
local setPaletteColor = function(colour, r, g, b)
|
||||
-- have to work on
|
||||
if type(colour) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(colour) .. ")", 2)
|
||||
end
|
||||
|
||||
if tHex[colour] == nil then
|
||||
error("Invalid color (got " .. colour .. ")", 2)
|
||||
end
|
||||
|
||||
local tCol
|
||||
if type(r) == "number" and g == nil and b == nil then
|
||||
tCol = { colours.rgb8(r) }
|
||||
tPalette[colour] = tCol
|
||||
else
|
||||
if type(r) ~= "number" then
|
||||
error("bad argument #2 (expected number, got " .. type(r) .. ")", 2)
|
||||
end
|
||||
if type(g) ~= "number" then
|
||||
error("bad argument #3 (expected number, got " .. type(g) .. ")", 2)
|
||||
end
|
||||
if type(b) ~= "number" then
|
||||
error("bad argument #4 (expected number, got " .. type(b) .. ")", 2)
|
||||
end
|
||||
|
||||
tCol = tPalette[colour]
|
||||
tCol[1] = r
|
||||
tCol[2] = g
|
||||
tCol[3] = b
|
||||
end
|
||||
end
|
||||
|
||||
local getPaletteColor = function(colour)
|
||||
if type(colour) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(colour) .. ")", 2)
|
||||
end
|
||||
if tHex[colour] == nil then
|
||||
error("Invalid color (got " .. colour .. ")", 2)
|
||||
end
|
||||
local tCol = tPalette[colour]
|
||||
return tCol[1], tCol[2], tCol[3]
|
||||
end
|
||||
|
||||
local basaltwindow = {
|
||||
setCursorPos = function(_x, _y)
|
||||
if type(_x) ~= "number" then
|
||||
error("bad argument #1 (expected number, got " .. type(_x) .. ")", 2)
|
||||
end
|
||||
if type(_y) ~= "number" then
|
||||
error("bad argument #2 (expected number, got " .. type(_y) .. ")", 2)
|
||||
end
|
||||
xCursor = math.floor(_x)
|
||||
yCursor = math.floor(_y)
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end,
|
||||
|
||||
getCursorPos = function()
|
||||
return xCursor, yCursor
|
||||
end;
|
||||
|
||||
setCursorBlink = function(blink)
|
||||
if type(blink) ~= "boolean" then
|
||||
error("bad argument #1 (expected boolean, got " .. type(blink) .. ")", 2)
|
||||
end
|
||||
cursorBlink = blink
|
||||
end;
|
||||
|
||||
getCursorBlink = function()
|
||||
return cursorBlink
|
||||
end;
|
||||
|
||||
|
||||
getPaletteColor = getPaletteColor,
|
||||
getPaletteColour = getPaletteColor,
|
||||
|
||||
setBackgroundColor = setBackgroundColor,
|
||||
setBackgroundColour = setBackgroundColor,
|
||||
|
||||
setTextColor = setTextColor,
|
||||
setTextColour = setTextColor,
|
||||
|
||||
setPaletteColor = setPaletteColor,
|
||||
setPaletteColour = setPaletteColor,
|
||||
|
||||
getBackgroundColor = function()
|
||||
return bgColor
|
||||
end;
|
||||
getBackgroundColour = function()
|
||||
return bgColor
|
||||
end;
|
||||
|
||||
getSize = function()
|
||||
return width, height
|
||||
end;
|
||||
|
||||
getTextColor = function()
|
||||
return fgColor
|
||||
end;
|
||||
getTextColour = function()
|
||||
return fgColor
|
||||
end;
|
||||
|
||||
basalt_resize = function(_width, _height)
|
||||
width, height = _width, _height
|
||||
recreateWindowArray()
|
||||
end;
|
||||
|
||||
basalt_reposition = function(_x, _y)
|
||||
x, y = _x, _y
|
||||
end;
|
||||
|
||||
basalt_setVisible = function(vis)
|
||||
visible = vis
|
||||
end;
|
||||
|
||||
drawBackgroundBox = function(_x, _y, _width, _height, bgCol)
|
||||
for n = 1, _height do
|
||||
setBG(_x, _y + (n - 1), tHex[bgCol]:rep(_width))
|
||||
end
|
||||
end;
|
||||
drawForegroundBox = function(_x, _y, _width, _height, fgCol)
|
||||
for n = 1, _height do
|
||||
setFG(_x, _y + (n - 1), tHex[fgCol]:rep(_width))
|
||||
end
|
||||
end;
|
||||
drawTextBox = function(_x, _y, _width, _height, symbol)
|
||||
for n = 1, _height do
|
||||
setText(_x, _y + (n - 1), symbol:rep(_width))
|
||||
end
|
||||
end;
|
||||
|
||||
basalt_update = function()
|
||||
for n = 1, height do
|
||||
object:addBlit(1, n, cacheT[n], cacheFG[n], cacheBG[n])
|
||||
end
|
||||
end,
|
||||
|
||||
scroll = function(offset)
|
||||
assert(type(offset) == "number", "bad argument #1 (expected number, got " .. type(offset) .. ")")
|
||||
if offset ~= 0 then
|
||||
for newY = 1, height do
|
||||
local y = newY + offset
|
||||
if y < 1 or y > height then
|
||||
cacheT[newY] = emptySpaceLine
|
||||
cacheFG[newY] = emptyColorLines[fgColor]
|
||||
cacheBG[newY] = emptyColorLines[bgColor]
|
||||
else
|
||||
cacheT[newY] = cacheT[y]
|
||||
cacheBG[newY] = cacheBG[y]
|
||||
cacheFG[newY] = cacheFG[y]
|
||||
end
|
||||
end
|
||||
end
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end,
|
||||
|
||||
|
||||
isColor = function()
|
||||
return basalt.getTerm().isColor()
|
||||
end;
|
||||
|
||||
isColour = function()
|
||||
return basalt.getTerm().isColor()
|
||||
end;
|
||||
|
||||
write = function(text)
|
||||
text = tostring(text)
|
||||
if (visible) then
|
||||
internalBlit(text, tHex[fgColor]:rep(text:len()), tHex[bgColor]:rep(text:len()))
|
||||
end
|
||||
end;
|
||||
|
||||
clearLine = function()
|
||||
if (visible) then
|
||||
setText(1, yCursor, (" "):rep(width))
|
||||
setBG(1, yCursor, tHex[bgColor]:rep(width))
|
||||
setFG(1, yCursor, tHex[fgColor]:rep(width))
|
||||
end
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end;
|
||||
|
||||
clear = function()
|
||||
for n = 1, height do
|
||||
setText(1, n, (" "):rep(width))
|
||||
setBG(1, n, tHex[bgColor]:rep(width))
|
||||
setFG(1, n, tHex[fgColor]:rep(width))
|
||||
end
|
||||
if (visible) then
|
||||
updateCursor()
|
||||
end
|
||||
end;
|
||||
|
||||
blit = function(text, fgcol, bgcol)
|
||||
if type(text) ~= "string" then
|
||||
error("bad argument #1 (expected string, got " .. type(text) .. ")", 2)
|
||||
end
|
||||
if type(fgcol) ~= "string" then
|
||||
error("bad argument #2 (expected string, got " .. type(fgcol) .. ")", 2)
|
||||
end
|
||||
if type(bgcol) ~= "string" then
|
||||
error("bad argument #3 (expected string, got " .. type(bgcol) .. ")", 2)
|
||||
end
|
||||
if #fgcol ~= #text or #bgcol ~= #text then
|
||||
error("Arguments must be the same length", 2)
|
||||
end
|
||||
if (visible) then
|
||||
internalBlit(text, fgcol, bgcol)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
}
|
||||
|
||||
return basaltwindow
|
||||
end
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setSize(30, 12)
|
||||
local pWindow = createBasaltWindow(1, 1, 30, 12)
|
||||
local curProcess
|
||||
local paused = false
|
||||
local queuedEvent = {}
|
||||
|
||||
local function updateCursor(self)
|
||||
local parent = self:getParent()
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then
|
||||
parent:setCursor(self:isFocused() and pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor())
|
||||
end
|
||||
end
|
||||
|
||||
local function resumeProcess(self, event, ...)
|
||||
local ok, result = curProcess:resume(event, ...)
|
||||
if (ok==false)and(result~=nil)and(result~="Terminated")then
|
||||
local val = self:sendEvent("program_error", result)
|
||||
if(val~=false)then
|
||||
error("Basalt Program - "..result)
|
||||
end
|
||||
end
|
||||
|
||||
if(curProcess:getStatus()=="dead")then
|
||||
self:sendEvent("program_done")
|
||||
end
|
||||
end
|
||||
|
||||
local function mouseEvent(self, event, p1, x, y)
|
||||
if (curProcess == nil) then
|
||||
return false
|
||||
end
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
local absX, absY = self:getAbsolutePosition()
|
||||
resumeProcess(self, event, p1, x-absX+1, y-absY+1)
|
||||
updateCursor(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function keyEvent(self, event, key, isHolding)
|
||||
if (curProcess == nil) then
|
||||
return false
|
||||
end
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
if (self.draw) then
|
||||
resumeProcess(self, event, key, isHolding)
|
||||
updateCursor(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end;
|
||||
|
||||
show = function(self)
|
||||
base.show(self)
|
||||
pWindow.setBackgroundColor(self:getBackground())
|
||||
pWindow.setTextColor(self:getForeground())
|
||||
pWindow.basalt_setVisible(true)
|
||||
return self
|
||||
end;
|
||||
|
||||
hide = function(self)
|
||||
base.hide(self)
|
||||
pWindow.basalt_setVisible(false)
|
||||
return self
|
||||
end;
|
||||
|
||||
setPosition = function(self, x, y, rel)
|
||||
base.setPosition(self, x, y, rel)
|
||||
pWindow.basalt_reposition(self:getPosition())
|
||||
return self
|
||||
end,
|
||||
|
||||
getBasaltWindow = function()
|
||||
return pWindow
|
||||
end;
|
||||
|
||||
getBasaltProcess = function()
|
||||
return curProcess
|
||||
end;
|
||||
|
||||
setSize = function(self, width, height, rel)
|
||||
base.setSize(self, width, height, rel)
|
||||
pWindow.basalt_resize(self:getWidth(), self:getHeight())
|
||||
return self
|
||||
end;
|
||||
|
||||
getStatus = function(self)
|
||||
if (curProcess ~= nil) then
|
||||
return curProcess:getStatus()
|
||||
end
|
||||
return "inactive"
|
||||
end;
|
||||
|
||||
setEnviroment = function(self, env)
|
||||
enviroment = env or {}
|
||||
return self
|
||||
end,
|
||||
|
||||
execute = function(self, path, ...)
|
||||
cachedPath = path or cachedPath
|
||||
curProcess = process:new(cachedPath, pWindow, enviroment, ...)
|
||||
pWindow.setBackgroundColor(colors.black)
|
||||
pWindow.setTextColor(colors.white)
|
||||
pWindow.clear()
|
||||
pWindow.setCursorPos(1, 1)
|
||||
pWindow.setBackgroundColor(self:getBackground())
|
||||
pWindow.setTextColor(self:getForeground() or colors.white)
|
||||
pWindow.basalt_setVisible(true)
|
||||
|
||||
resumeProcess(self)
|
||||
paused = false
|
||||
self:listenEvent("mouse_click", self)
|
||||
self:listenEvent("mouse_up", self)
|
||||
self:listenEvent("mouse_drag", self)
|
||||
self:listenEvent("mouse_scroll", self)
|
||||
self:listenEvent("key", self)
|
||||
self:listenEvent("key_up", self)
|
||||
self:listenEvent("char", self)
|
||||
self:listenEvent("other_event", self)
|
||||
return self
|
||||
end;
|
||||
|
||||
setExecute = function(self, path, ...)
|
||||
return self:execute(path, ...)
|
||||
end,
|
||||
|
||||
stop = function(self)
|
||||
local parent = self:getParent()
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
resumeProcess(self, "terminate")
|
||||
if (curProcess:isDead()) then
|
||||
parent:setCursor(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
parent:removeEvents(self)
|
||||
return self
|
||||
end;
|
||||
|
||||
pause = function(self, p)
|
||||
paused = p or (not paused)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
self:injectEvents(table.unpack(queuedEvent))
|
||||
queuedEvent = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end;
|
||||
|
||||
isPaused = function(self)
|
||||
return paused
|
||||
end;
|
||||
|
||||
injectEvent = function(self, event, ign, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if (paused == false) or (ign) then
|
||||
resumeProcess(self, event, ...)
|
||||
else
|
||||
table.insert(queuedEvent, { event = event, args = {...} })
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end;
|
||||
|
||||
getQueuedEvents = function(self)
|
||||
return queuedEvent
|
||||
end;
|
||||
|
||||
updateQueuedEvents = function(self, events)
|
||||
queuedEvent = events or queuedEvent
|
||||
return self
|
||||
end;
|
||||
|
||||
injectEvents = function(self, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
for _, value in pairs({...}) do
|
||||
resumeProcess(self, value.event, table.unpack(value.args))
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end;
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
mouseEvent(self, "mouse_click", button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
if (base.mouseUpHandler(self, button, x, y)) then
|
||||
mouseEvent(self, "mouse_up", button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if (base.scrollHandler(self, dir, x, y)) then
|
||||
mouseEvent(self, "mouse_scroll", dir, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
mouseEvent(self, "mouse_drag", button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key, isHolding)
|
||||
if(base.keyHandler(self, key, isHolding))then
|
||||
keyEvent(self, "key", key, isHolding)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
keyUpHandler = function(self, key)
|
||||
if(base.keyUpHandler(self, key))then
|
||||
keyEvent(self, "key_up", key)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if(base.charHandler(self, char))then
|
||||
keyEvent(self, "char", char)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
base.getFocusHandler(self)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
local parent = self:getParent()
|
||||
if (parent ~= nil) then
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then
|
||||
parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
local parent = self:getParent()
|
||||
if (parent ~= nil) then
|
||||
parent:setCursor(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if curProcess == nil then
|
||||
return
|
||||
end
|
||||
if not curProcess:isDead() then
|
||||
if not paused then
|
||||
resumeProcess(self, event, ...)
|
||||
if self:isFocused() then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local w,h = self:getSize()
|
||||
if obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1 then
|
||||
parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor())
|
||||
end
|
||||
end
|
||||
else
|
||||
table.insert(queuedEvent, { event = event, args = { ... } })
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
resizeHandler = function(self, ...)
|
||||
base.resizeHandler(self, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
if not (paused) then
|
||||
pWindow.basalt_resize(self:getSize())
|
||||
resumeProcess(self, "term_resize", self:getSize())
|
||||
else
|
||||
pWindow.basalt_resize(self:getSize())
|
||||
table.insert(queuedEvent, { event = "term_resize", args = { self:getSize() } })
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
repositionHandler = function(self, ...)
|
||||
base.repositionHandler(self, ...)
|
||||
if (curProcess ~= nil) then
|
||||
if not (curProcess:isDead()) then
|
||||
pWindow.basalt_reposition(self:getPosition())
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("program", function()
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local xCur, yCur = pWindow.getCursorPos()
|
||||
local w,h = self:getSize()
|
||||
pWindow.basalt_update()
|
||||
end)
|
||||
end,
|
||||
|
||||
onError = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("program_error", v)
|
||||
end
|
||||
end
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
onDone = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("program_done", v)
|
||||
end
|
||||
end
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
136
lib/basalt/objects/Progressbar.lua
Normal file
136
lib/basalt/objects/Progressbar.lua
Normal file
|
@ -0,0 +1,136 @@
|
|||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Progressbar"
|
||||
|
||||
local progress = 0
|
||||
|
||||
base:setZIndex(5)
|
||||
base:setValue(false)
|
||||
base:setSize(25, 3)
|
||||
|
||||
local activeBarColor = colors.black
|
||||
local activeBarSymbol = ""
|
||||
local activeBarSymbolCol = colors.white
|
||||
local bgBarSymbol = ""
|
||||
local direction = 0
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setDirection = function(self, dir)
|
||||
direction = dir
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDirection = function(self)
|
||||
return direction
|
||||
end,
|
||||
|
||||
setProgressBar = function(self, color, symbol, symbolcolor)
|
||||
activeBarColor = color or activeBarColor
|
||||
activeBarSymbol = symbol or activeBarSymbol
|
||||
activeBarSymbolCol = symbolcolor or activeBarSymbolCol
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getProgressBar = function(self)
|
||||
return activeBarColor, activeBarSymbol, activeBarSymbolCol
|
||||
end,
|
||||
|
||||
setActiveBarColor = function(self, color)
|
||||
return self:setProgressBar(color, nil, nil)
|
||||
end,
|
||||
|
||||
getActiveBarColor = function(self)
|
||||
return activeBarColor
|
||||
end,
|
||||
|
||||
setActiveBarSymbol = function(self, symbol)
|
||||
return self:setProgressBar(nil, symbol, nil)
|
||||
end,
|
||||
|
||||
getActiveBarSymbol = function(self)
|
||||
return activeBarSymbol
|
||||
end,
|
||||
|
||||
setActiveBarSymbolColor = function(self, symbolColor)
|
||||
return self:setProgressBar(nil, nil, symbolColor)
|
||||
end,
|
||||
|
||||
getActiveBarSymbolColor = function(self)
|
||||
return activeBarSymbolCol
|
||||
end,
|
||||
|
||||
setBackgroundSymbol = function(self, symbol)
|
||||
bgBarSymbol = symbol:sub(1, 1)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBackgroundSymbol = function(self)
|
||||
return bgBarSymbol
|
||||
end,
|
||||
|
||||
setProgress = function(self, value)
|
||||
if (value >= 0) and (value <= 100) and (progress ~= value) then
|
||||
progress = value
|
||||
self:setValue(progress)
|
||||
if (progress == 100) then
|
||||
self:progressDoneHandler()
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getProgress = function(self)
|
||||
return progress
|
||||
end,
|
||||
|
||||
onProgressDone = function(self, f)
|
||||
self:registerEvent("progress_done", f)
|
||||
return self
|
||||
end,
|
||||
|
||||
progressDoneHandler = function(self)
|
||||
self:sendEvent("progress_done")
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("progressbar", function()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
if(bgCol~=false)then self:addBackgroundBox(1, 1, w, h, bgCol) end
|
||||
if(bgBarSymbol~="")then self:addTextBox(1, 1, w, h, bgBarSymbol) end
|
||||
if(fgCol~=false)then self:addForegroundBox(1, 1, w, h, fgCol) end
|
||||
if (direction == 1) then
|
||||
self:addBackgroundBox(1, 1, w, h / 100 * progress, activeBarColor)
|
||||
self:addForegroundBox(1, 1, w, h / 100 * progress, activeBarSymbolCol)
|
||||
self:addTextBox(1, 1, w, h / 100 * progress, activeBarSymbol)
|
||||
elseif (direction == 3) then
|
||||
self:addBackgroundBox(1, 1 + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarColor)
|
||||
self:addForegroundBox(1, 1 + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbolCol)
|
||||
self:addTextBox(1, 1 + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbol)
|
||||
elseif (direction == 2) then
|
||||
self:addBackgroundBox(1 + math.ceil(w - w / 100 * progress), 1, w / 100 * progress, h, activeBarColor)
|
||||
self:addForegroundBox(1 + math.ceil(w - w / 100 * progress), 1, w / 100 * progress, h, activeBarSymbolCol)
|
||||
self:addTextBox(1 + math.ceil(w - w / 100 * progress), 1, w / 100 * progress, h, activeBarSymbol)
|
||||
else
|
||||
self:addBackgroundBox(1, 1, math.ceil( w / 100 * progress), h, activeBarColor)
|
||||
self:addForegroundBox(1, 1, math.ceil(w / 100 * progress), h, activeBarSymbolCol)
|
||||
self:addTextBox(1, 1, math.ceil(w / 100 * progress), h, activeBarSymbol)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
138
lib/basalt/objects/Radio.lua
Normal file
138
lib/basalt/objects/Radio.lua
Normal file
|
@ -0,0 +1,138 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("List")(name, basalt)
|
||||
local objectType = "Radio"
|
||||
|
||||
base:setSize(1, 1)
|
||||
base:setZIndex(5)
|
||||
|
||||
local list = {}
|
||||
local boxSelectedBG = colors.black
|
||||
local boxSelectedFG = colors.green
|
||||
local boxNotSelectedBG = colors.black
|
||||
local boxNotSelectedFG = colors.red
|
||||
local selectionColorActive = true
|
||||
local symbol = "\7"
|
||||
local align = "left"
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
addItem = function(self, text, x, y, bgCol, fgCol, ...)
|
||||
base.addItem(self, text, bgCol, fgCol, ...)
|
||||
table.insert(list, { x = x or 1, y = y or #list * 2 })
|
||||
return self
|
||||
end,
|
||||
|
||||
removeItem = function(self, index)
|
||||
base.removeItem(self, index)
|
||||
table.remove(list, index)
|
||||
return self
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
base.clear(self)
|
||||
list = {}
|
||||
return self
|
||||
end,
|
||||
|
||||
editItem = function(self, index, text, x, y, bgCol, fgCol, ...)
|
||||
base.editItem(self, index, text, bgCol, fgCol, ...)
|
||||
table.remove(list, index)
|
||||
table.insert(list, index, { x = x or 1, y = y or 1 })
|
||||
return self
|
||||
end,
|
||||
|
||||
setBoxSelectionColor = function(self, bg, fg)
|
||||
boxSelectedBG = bg
|
||||
boxSelectedFG = fg
|
||||
return self
|
||||
end,
|
||||
|
||||
setBoxSelectionBG = function(self, bg)
|
||||
return self:setBoxSelectionColor(bg, boxSelectedFG)
|
||||
end,
|
||||
|
||||
setBoxSelectionFG = function(self, fg)
|
||||
return self:setBoxSelectionColor(boxSelectedBG, fg)
|
||||
end,
|
||||
|
||||
getBoxSelectionColor = function(self)
|
||||
return boxSelectedBG, boxSelectedFG
|
||||
end,
|
||||
|
||||
getBoxSelectionBG = function(self)
|
||||
return boxSelectedBG
|
||||
end,
|
||||
|
||||
getBoxSelectionFG = function(self)
|
||||
return boxSelectedFG
|
||||
end,
|
||||
|
||||
setBoxDefaultColor = function(self, bg, fg)
|
||||
boxNotSelectedBG = bg
|
||||
boxNotSelectedFG = fg
|
||||
return self
|
||||
end,
|
||||
|
||||
setBoxDefaultBG = function(self, bg)
|
||||
return self:setBoxDefaultColor(bg, boxNotSelectedFG)
|
||||
end,
|
||||
|
||||
setBoxDefaultFG = function(self, fg)
|
||||
return self:setBoxDefaultColor(boxNotSelectedBG, fg)
|
||||
end,
|
||||
|
||||
getBoxDefaultColor = function(self)
|
||||
return boxNotSelectedBG, boxNotSelectedFG
|
||||
end,
|
||||
|
||||
getBoxDefaultBG = function(self)
|
||||
return boxNotSelectedBG
|
||||
end,
|
||||
|
||||
getBoxDefaultFG = function(self)
|
||||
return boxNotSelectedFG
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, ...)
|
||||
if (#list > 0) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local baseList = self:getAll()
|
||||
for k, value in pairs(baseList) do
|
||||
if (obx + list[k].x - 1 <= x) and (obx + list[k].x - 1 + value.text:len() + 1 >= x) and (oby + list[k].y - 1 == y) then
|
||||
self:setValue(value)
|
||||
local val = self:sendEvent("mouse_click", self, "mouse_click", button, x, y, ...)
|
||||
self:updateDraw()
|
||||
if(val==false)then return val end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
self:addDraw("radio", function()
|
||||
local itemSelectedBG, itemSelectedFG = self:getSelectionColor()
|
||||
local baseList = self:getAll()
|
||||
for k, value in pairs(baseList) do
|
||||
if (value == self:getValue()) then
|
||||
self:addBlit(list[k].x, list[k].y, symbol, tHex[boxSelectedFG], tHex[boxSelectedBG])
|
||||
self:addBlit(list[k].x + 2, list[k].y, value.text, tHex[itemSelectedFG]:rep(#value.text), tHex[itemSelectedBG]:rep(#value.text))
|
||||
else
|
||||
self:addBackgroundBox(list[k].x, list[k].y, 1, 1, boxNotSelectedBG or colors.black)
|
||||
self:addBlit(list[k].x + 2, list[k].y, value.text, tHex[value.fgCol]:rep(#value.text), tHex[value.bgCol]:rep(#value.text))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
147
lib/basalt/objects/ScrollableFrame.lua
Normal file
147
lib/basalt/objects/ScrollableFrame.lua
Normal file
|
@ -0,0 +1,147 @@
|
|||
local max,min,sub,rep = math.max,math.min,string.sub,string.rep
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Frame")(name, basalt)
|
||||
local objectType = "ScrollableFrame"
|
||||
local parent
|
||||
|
||||
local direction = 0
|
||||
local manualScrollAmount = 0
|
||||
local calculateScrollAmount = true
|
||||
|
||||
local function getHorizontalScrollAmount(self)
|
||||
local amount = 0
|
||||
local children = self:getChildren()
|
||||
for _, b in pairs(children) do
|
||||
if(b.element.getWidth~=nil)and(b.element.getX~=nil)then
|
||||
local w, x = b.element:getWidth(), b.element:getX()
|
||||
local width = self:getWidth()
|
||||
if(b.element:getType()=="Dropdown")then
|
||||
if(b.element:isOpened())then
|
||||
local dropdownW = b.element:getDropdownSize()
|
||||
if (dropdownW + x - width >= amount) then
|
||||
amount = max(dropdownW + x - width, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (w + x - width >= amount) then
|
||||
amount = max(w + x - width, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return amount
|
||||
end
|
||||
|
||||
local function getVerticalScrollAmount(self)
|
||||
local amount = 0
|
||||
local children = self:getChildren()
|
||||
for _, b in pairs(children) do
|
||||
if(b.element.getHeight~=nil)and(b.element.getY~=nil)then
|
||||
local h, y = b.element:getHeight(), b.element:getY()
|
||||
local height = self:getHeight()
|
||||
if(b.element:getType()=="Dropdown")then
|
||||
if(b.element:isOpened())then
|
||||
local _,dropdownH = b.element:getDropdownSize()
|
||||
if (dropdownH + y - height >= amount) then
|
||||
amount = max(dropdownH + y - height, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
if (h + y - height >= amount) then
|
||||
amount = max(h + y - height, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
return amount
|
||||
end
|
||||
|
||||
local function scrollHandler(self, dir)
|
||||
local xO, yO = self:getOffset()
|
||||
local scrollAmn
|
||||
if(direction==1)then
|
||||
scrollAmn = calculateScrollAmount and getHorizontalScrollAmount(self) or manualScrollAmount
|
||||
self:setOffset(min(scrollAmn, max(0, xO + dir)), yO)
|
||||
elseif(direction==0)then
|
||||
scrollAmn = calculateScrollAmount and getVerticalScrollAmount(self) or manualScrollAmount
|
||||
self:setOffset(xO, min(scrollAmn, max(0, yO + dir)))
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function()
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setDirection = function(self, dir)
|
||||
direction = dir=="horizontal" and 1 or dir=="vertical" and 0 or direction
|
||||
return self
|
||||
end,
|
||||
|
||||
setScrollAmount = function(self, amount)
|
||||
manualScrollAmount = amount
|
||||
calculateScrollAmount = false
|
||||
return self
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
base.load(self)
|
||||
self:listenEvent("mouse_scroll")
|
||||
end,
|
||||
|
||||
removeChildren = function(self)
|
||||
base.removeChildren(self)
|
||||
self:listenEvent("mouse_scroll")
|
||||
end,
|
||||
|
||||
setParent = function(self, p, ...)
|
||||
base.setParent(self, p, ...)
|
||||
parent = p
|
||||
return self
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base:getBase().scrollHandler(self, dir, x, y))then
|
||||
self:sortChildren()
|
||||
for _, obj in ipairs(self:getEvents("mouse_scroll")) do
|
||||
if (obj.element.scrollHandler ~= nil) then
|
||||
local xO, yO = 0, 0
|
||||
if(self.getOffset~=nil)then
|
||||
xO, yO = self:getOffset()
|
||||
end
|
||||
if(obj.element.getIgnoreOffset())then
|
||||
xO, yO = 0, 0
|
||||
end
|
||||
if (obj.element.scrollHandler(obj.element, dir, x+xO, y+yO)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
scrollHandler(self, dir, x, y)
|
||||
self:clearFocusedChild()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("scrollableFrame", function()
|
||||
if(calculateScrollAmount)then
|
||||
scrollHandler(self, 0)
|
||||
end
|
||||
end, 0)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
218
lib/basalt/objects/Scrollbar.lua
Normal file
218
lib/basalt/objects/Scrollbar.lua
Normal file
|
@ -0,0 +1,218 @@
|
|||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("VisualObject")(name, basalt)
|
||||
local objectType = "Scrollbar"
|
||||
|
||||
base:setZIndex(2)
|
||||
base:setSize(1, 8)
|
||||
base:setBackground(colors.lightGray, "\127", colors.gray)
|
||||
|
||||
local barType = "vertical"
|
||||
local symbol = " "
|
||||
local symbolBG = colors.black
|
||||
local symbolFG = colors.black
|
||||
local scrollAmount = 3
|
||||
local index = 1
|
||||
local symbolSize = 1
|
||||
local symbolAutoSize = true
|
||||
|
||||
local function updateSymbolSize()
|
||||
local w,h = base:getSize()
|
||||
if(symbolAutoSize)then
|
||||
symbolSize = math.max((barType == "vertical" and h or w-(#symbol)) - (scrollAmount-1), 1)
|
||||
end
|
||||
end
|
||||
updateSymbolSize()
|
||||
|
||||
local function mouseEvent(self, button, x, y)
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local w,h = self:getSize()
|
||||
updateSymbolSize()
|
||||
local size = barType == "vertical" and h or w
|
||||
for i = 0, size do
|
||||
if ((barType == "vertical" and oby + i == y) or (barType == "horizontal" and obx + i == x)) and (obx <= x) and (obx + w > x) and (oby <= y) and (oby + h > y) then
|
||||
index = math.min(i + 1, size - (#symbol + symbolSize - 2))
|
||||
self:scrollbarMoveHandler()
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
base.load(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_scroll")
|
||||
self:listenEvent("mouse_drag")
|
||||
end,
|
||||
|
||||
setSymbol = function(self, _symbol, bg, fg)
|
||||
symbol = _symbol:sub(1,1)
|
||||
symbolBG = bg or symbolBG
|
||||
symbolFG = fg or symbolFG
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSymbolBG = function(self, bg)
|
||||
return self:setSymbol(symbol, bg, nil)
|
||||
end,
|
||||
|
||||
setSymbolFG = function(self, fg)
|
||||
return self:setSymbol(symbol, nil, fg)
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return symbol
|
||||
end,
|
||||
|
||||
getSymbolBG = function(self)
|
||||
return symbolBG
|
||||
end,
|
||||
|
||||
getSymbolFG = function(self)
|
||||
return symbolFG
|
||||
end,
|
||||
|
||||
setIndex = function(self, _index)
|
||||
index = _index
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
local w,h = self:getSize()
|
||||
--index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1))
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setScrollAmount = function(self, amount)
|
||||
scrollAmount = amount
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollAmount = function(self)
|
||||
return scrollAmount
|
||||
end,
|
||||
|
||||
getIndex = function(self)
|
||||
local w,h = self:getSize()
|
||||
return scrollAmount > (barType=="vertical" and h or w) and math.floor(scrollAmount/(barType=="vertical" and h or w) * index) or index
|
||||
end,
|
||||
|
||||
setSymbolSize = function(self, size)
|
||||
symbolSize = tonumber(size) or 1
|
||||
symbolAutoSize = size~=false and false or true
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbolSize = function(self)
|
||||
return symbolSize
|
||||
end,
|
||||
|
||||
setBarType = function(self, _typ)
|
||||
barType = _typ:lower()
|
||||
updateSymbolSize()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBarType = function(self)
|
||||
return barType
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, ...)
|
||||
if (base.mouseHandler(self, button, x, y, ...)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
setSize = function(self, ...)
|
||||
base.setSize(self, ...)
|
||||
updateSymbolSize()
|
||||
return self
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base.scrollHandler(self, dir, x, y))then
|
||||
local w,h = self:getSize()
|
||||
updateSymbolSize()
|
||||
index = index + dir
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
index = math.min(index, (barType == "vertical" and h or w) - (barType == "vertical" and symbolSize - 1 or #symbol+symbolSize-2))
|
||||
self:scrollbarMoveHandler()
|
||||
self:updateDraw()
|
||||
end
|
||||
end,
|
||||
|
||||
onChange = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("scrollbar_moved", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
|
||||
scrollbarMoveHandler = function(self)
|
||||
self:sendEvent("scrollbar_moved", self:getIndex())
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
base.customEventHandler(self, event, ...)
|
||||
if(event=="basalt_FrameResize")then
|
||||
updateSymbolSize()
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("scrollbar", function()
|
||||
local parent = self:getParent()
|
||||
local w,h = self:getSize()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
if (barType == "horizontal") then
|
||||
for n = 0, h - 1 do
|
||||
self:addBlit(index, 1 + n, symbol:rep(symbolSize), tHex[symbolFG]:rep(#symbol*symbolSize), tHex[symbolBG]:rep(#symbol*symbolSize))
|
||||
end
|
||||
elseif (barType == "vertical") then
|
||||
for n = 0, h - 1 do
|
||||
if (index == n + 1) then
|
||||
for curIndexOffset = 0, math.min(symbolSize - 1, h) do
|
||||
self:addBlit(1, index + curIndexOffset, symbol:rep(math.max(#symbol, w)), tHex[symbolFG]:rep(math.max(#symbol, w)), tHex[symbolBG]:rep(math.max(#symbol, w)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
159
lib/basalt/objects/Slider.lua
Normal file
159
lib/basalt/objects/Slider.lua
Normal file
|
@ -0,0 +1,159 @@
|
|||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Slider"
|
||||
|
||||
base:setSize(12, 1)
|
||||
base:setValue(1)
|
||||
base:setBackground(false, "\140", colors.black)
|
||||
|
||||
local barType = "horizontal"
|
||||
local symbol = " "
|
||||
local symbolFG = colors.black
|
||||
local symbolBG = colors.gray
|
||||
local maxValue = 12
|
||||
local index = 1
|
||||
local symbolSize = 1
|
||||
|
||||
local function mouseEvent(self, button, x, y)
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local size = barType == "vertical" and h or w
|
||||
for i = 0, size do
|
||||
if ((barType == "vertical" and oby + i == y) or (barType == "horizontal" and obx + i == x)) and (obx <= x) and (obx + w > x) and (oby <= y) and (oby + h > y) then
|
||||
index = math.min(i + 1, size - (#symbol + symbolSize - 2))
|
||||
self:setValue(maxValue / size * index)
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("mouse_scroll")
|
||||
end,
|
||||
|
||||
setSymbol = function(self, _symbol)
|
||||
symbol = _symbol:sub(1, 1)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return symbol
|
||||
end,
|
||||
|
||||
setIndex = function(self, _index)
|
||||
index = _index
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
local w,h = self:getSize()
|
||||
index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1))
|
||||
self:setValue(maxValue / (barType == "vertical" and h or w) * index)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getIndex = function(self)
|
||||
return index
|
||||
end,
|
||||
|
||||
setMaxValue = function(self, val)
|
||||
maxValue = val
|
||||
return self
|
||||
end,
|
||||
|
||||
getMaxValue = function(self)
|
||||
return maxValue
|
||||
end,
|
||||
|
||||
setSymbolColor = function(self, col)
|
||||
symbolColor = col
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbolColor = function(self)
|
||||
return symbolColor
|
||||
end,
|
||||
|
||||
setBarType = function(self, _typ)
|
||||
barType = _typ:lower()
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBarType = function(self)
|
||||
return barType
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
mouseEvent(self, button, x, y)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(base.scrollHandler(self, dir, x, y))then
|
||||
local w,h = self:getSize()
|
||||
index = index + dir
|
||||
if (index < 1) then
|
||||
index = 1
|
||||
end
|
||||
index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1))
|
||||
self:setValue(maxValue / (barType == "vertical" and h or w) * index)
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("slider", function()
|
||||
local w,h = self:getSize()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
if (barType == "horizontal") then
|
||||
self:addText(index, oby, symbol:rep(symbolSize))
|
||||
if(symbolBG~=false)then self:addBG(index, 1, tHex[symbolBG]:rep(#symbol*symbolSize)) end
|
||||
if(symbolFG~=false)then self:addFG(index, 1, tHex[symbolFG]:rep(#symbol*symbolSize)) end
|
||||
end
|
||||
|
||||
if (barType == "vertical") then
|
||||
for n = 0, h - 1 do
|
||||
if (index == n + 1) then
|
||||
for curIndexOffset = 0, math.min(symbolSize - 1, h) do
|
||||
self:addBlit(1, 1+n+curIndexOffset, symbol, tHex[symbolColor], tHex[symbolColor])
|
||||
end
|
||||
else
|
||||
if (n + 1 < index) or (n + 1 > index - 1 + symbolSize) then
|
||||
self:addBlit(1, 1+n, bgSymbol, tHex[fgCol], tHex[bgCol])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
77
lib/basalt/objects/Switch.lua
Normal file
77
lib/basalt/objects/Switch.lua
Normal file
|
@ -0,0 +1,77 @@
|
|||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Switch"
|
||||
|
||||
base:setSize(4, 1)
|
||||
base:setValue(false)
|
||||
base:setZIndex(5)
|
||||
|
||||
local bgSymbol = colors.black
|
||||
local inactiveBG = colors.red
|
||||
local activeBG = colors.green
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setSymbol = function(self, col)
|
||||
bgSymbol = col
|
||||
return self
|
||||
end,
|
||||
|
||||
getSymbol = function(self)
|
||||
return bgSymbol
|
||||
end,
|
||||
|
||||
setActiveBackground = function(self, col)
|
||||
activeBG = col
|
||||
return self
|
||||
end,
|
||||
|
||||
getActiveBackground = function(self)
|
||||
return activeBG
|
||||
end,
|
||||
|
||||
setInactiveBackground = function(self, col)
|
||||
inactiveBG = col
|
||||
return self
|
||||
end,
|
||||
|
||||
getInactiveBackground = function(self)
|
||||
return inactiveBG
|
||||
end,
|
||||
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, ...)
|
||||
if (base.mouseHandler(self, ...)) then
|
||||
self:setValue(not self:getValue())
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("switch", function()
|
||||
local parent = self:getParent()
|
||||
local bgCol,fgCol = self:getBackground(), self:getForeground()
|
||||
local w,h = self:getSize()
|
||||
if(self:getValue())then
|
||||
self:addBackgroundBox(1, 1, w, h, activeBG)
|
||||
self:addBackgroundBox(w, 1, 1, h, bgSymbol)
|
||||
else
|
||||
self:addBackgroundBox(1, 1, w, h, inactiveBG)
|
||||
self:addBackgroundBox(1, 1, 1, h, bgSymbol)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
774
lib/basalt/objects/Textfield.lua
Normal file
774
lib/basalt/objects/Textfield.lua
Normal file
|
@ -0,0 +1,774 @@
|
|||
local tHex = require("tHex")
|
||||
|
||||
local rep,find,gmatch,sub,len = string.rep,string.find,string.gmatch,string.sub,string.len
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Textfield"
|
||||
local hIndex, wIndex, textX, textY = 1, 1, 1, 1
|
||||
|
||||
local lines = { "" }
|
||||
local bgLines = { "" }
|
||||
local fgLines = { "" }
|
||||
local keyWords = { }
|
||||
local rules = { }
|
||||
|
||||
local startSelX,endSelX,startSelY,endSelY
|
||||
|
||||
local selectionBG,selectionFG = colors.lightBlue,colors.black
|
||||
|
||||
base:setSize(30, 12)
|
||||
base:setZIndex(5)
|
||||
|
||||
local function isSelected()
|
||||
if(startSelX~=nil)and(endSelX~=nil)and(startSelY~=nil)and(endSelY~=nil)then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function getSelectionCoordinates()
|
||||
local sx, ex, sy, ey = startSelX, endSelX, startSelY, endSelY
|
||||
if isSelected() then
|
||||
if startSelX < endSelX and startSelY <= endSelY then
|
||||
sx = startSelX
|
||||
ex = endSelX
|
||||
if startSelY < endSelY then
|
||||
sy = startSelY
|
||||
ey = endSelY
|
||||
else
|
||||
sy = endSelY
|
||||
ey = startSelY
|
||||
end
|
||||
elseif startSelX > endSelX and startSelY >= endSelY then
|
||||
sx = endSelX
|
||||
ex = startSelX
|
||||
if startSelY > endSelY then
|
||||
sy = endSelY
|
||||
ey = startSelY
|
||||
else
|
||||
sy = startSelY
|
||||
ey = endSelY
|
||||
end
|
||||
elseif startSelY > endSelY then
|
||||
sx = endSelX
|
||||
ex = startSelX
|
||||
sy = endSelY
|
||||
ey = startSelY
|
||||
end
|
||||
return sx, ex, sy, ey
|
||||
end
|
||||
end
|
||||
|
||||
local function removeSelection(self)
|
||||
local sx, ex, sy, ey = getSelectionCoordinates()
|
||||
local startLine = lines[sy]
|
||||
local endLine = lines[ey]
|
||||
lines[sy] = startLine:sub(1, sx - 1) .. endLine:sub(ex + 1, endLine:len())
|
||||
bgLines[sy] = bgLines[sy]:sub(1, sx - 1) .. bgLines[ey]:sub(ex + 1, bgLines[ey]:len())
|
||||
fgLines[sy] = fgLines[sy]:sub(1, sx - 1) .. fgLines[ey]:sub(ex + 1, fgLines[ey]:len())
|
||||
|
||||
for i = ey, sy + 1, -1 do
|
||||
if i ~= sy then
|
||||
table.remove(lines, i)
|
||||
table.remove(bgLines, i)
|
||||
table.remove(fgLines, i)
|
||||
end
|
||||
end
|
||||
|
||||
textX, textY = sx, sy
|
||||
startSelX, endSelX, startSelY, endSelY = nil, nil, nil, nil
|
||||
return self
|
||||
end
|
||||
|
||||
local function stringGetPositions(str, word)
|
||||
local pos = {}
|
||||
if(str:len()>0)then
|
||||
for w in gmatch(str, word)do
|
||||
local s, e = find(str, w)
|
||||
if(s~=nil)and(e~=nil)then
|
||||
table.insert(pos,s)
|
||||
table.insert(pos,e)
|
||||
local startL = sub(str, 1, (s-1))
|
||||
local endL = sub(str, e+1, str:len())
|
||||
str = startL..(":"):rep(w:len())..endL
|
||||
end
|
||||
end
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
local function updateColors(self, l)
|
||||
l = l or textY
|
||||
local fgLine = tHex[self:getForeground()]:rep(fgLines[l]:len())
|
||||
local bgLine = tHex[self:getBackground()]:rep(bgLines[l]:len())
|
||||
for k,v in pairs(rules)do
|
||||
local pos = stringGetPositions(lines[l], v[1])
|
||||
if(#pos>0)then
|
||||
for x=1,#pos/2 do
|
||||
local xP = x*2 - 1
|
||||
if(v[2]~=nil)then
|
||||
fgLine = fgLine:sub(1, pos[xP]-1)..tHex[v[2]]:rep(pos[xP+1]-(pos[xP]-1))..fgLine:sub(pos[xP+1]+1, fgLine:len())
|
||||
end
|
||||
if(v[3]~=nil)then
|
||||
bgLine = bgLine:sub(1, pos[xP]-1)..tHex[v[3]]:rep(pos[xP+1]-(pos[xP]-1))..bgLine:sub(pos[xP+1]+1, bgLine:len())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for k,v in pairs(keyWords)do
|
||||
for _,b in pairs(v)do
|
||||
local pos = stringGetPositions(lines[l], b)
|
||||
if(#pos>0)then
|
||||
for x=1,#pos/2 do
|
||||
local xP = x*2 - 1
|
||||
fgLine = fgLine:sub(1, pos[xP]-1)..tHex[k]:rep(pos[xP+1]-(pos[xP]-1))..fgLine:sub(pos[xP+1]+1, fgLine:len())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
fgLines[l] = fgLine
|
||||
bgLines[l] = bgLine
|
||||
self:updateDraw()
|
||||
end
|
||||
|
||||
local function updateAllColors(self)
|
||||
for n=1,#lines do
|
||||
updateColors(self, n)
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end;
|
||||
|
||||
setBackground = function(self, bg)
|
||||
base.setBackground(self, bg)
|
||||
updateAllColors(self)
|
||||
return self
|
||||
end,
|
||||
|
||||
setForeground = function(self, fg)
|
||||
base.setForeground(self, fg)
|
||||
updateAllColors(self)
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelection = function(self, fg, bg)
|
||||
selectionFG = fg or selectionFG
|
||||
selectionBG = bg or selectionBG
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionFG = function(self, fg)
|
||||
return self:setSelection(fg, nil)
|
||||
end,
|
||||
|
||||
setSelectionBG = function(self, bg)
|
||||
return self:setSelection(nil, bg)
|
||||
end,
|
||||
|
||||
getSelection = function(self)
|
||||
return selectionFG, selectionBG
|
||||
end,
|
||||
|
||||
getSelectionFG = function(self)
|
||||
return selectionFG
|
||||
end,
|
||||
|
||||
getSelectionBG = function(self)
|
||||
return selectionBG
|
||||
end,
|
||||
|
||||
getLines = function(self)
|
||||
return lines
|
||||
end,
|
||||
|
||||
getLine = function(self, index)
|
||||
return lines[index]
|
||||
end,
|
||||
|
||||
editLine = function(self, index, text)
|
||||
lines[index] = text or lines[index]
|
||||
updateColors(self, index)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
clear = function(self)
|
||||
lines = {""}
|
||||
bgLines = {""}
|
||||
fgLines = {""}
|
||||
startSelX,endSelX,startSelY,endSelY = nil,nil,nil,nil
|
||||
hIndex, wIndex, textX, textY = 1, 1, 1, 1
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
addLine = function(self, text, index)
|
||||
if(text~=nil)then
|
||||
local bgColor = self:getBackground()
|
||||
local fgColor = self:getForeground()
|
||||
if(#lines==1)and(lines[1]=="")then
|
||||
lines[1] = text
|
||||
bgLines[1] = tHex[bgColor]:rep(text:len())
|
||||
fgLines[1] = tHex[fgColor]:rep(text:len())
|
||||
updateColors(self, 1)
|
||||
return self
|
||||
end
|
||||
if (index ~= nil) then
|
||||
table.insert(lines, index, text)
|
||||
table.insert(bgLines, index, tHex[bgColor]:rep(text:len()))
|
||||
table.insert(fgLines, index, tHex[fgColor]:rep(text:len()))
|
||||
else
|
||||
table.insert(lines, text)
|
||||
table.insert(bgLines, tHex[bgColor]:rep(text:len()))
|
||||
table.insert(fgLines, tHex[fgColor]:rep(text:len()))
|
||||
end
|
||||
end
|
||||
updateColors(self, index or #lines)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
addKeywords = function(self, color, tab)
|
||||
if(keyWords[color]==nil)then
|
||||
keyWords[color] = {}
|
||||
end
|
||||
for k,v in pairs(tab)do
|
||||
table.insert(keyWords[color], v)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
addRule = function(self, rule, fg, bg)
|
||||
table.insert(rules, {rule, fg, bg})
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
editRule = function(self, rule, fg, bg)
|
||||
for k,v in pairs(rules)do
|
||||
if(v[1]==rule)then
|
||||
rules[k][2] = fg
|
||||
rules[k][3] = bg
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end;
|
||||
|
||||
removeRule = function(self, rule)
|
||||
for k,v in pairs(rules)do
|
||||
if(v[1]==rule)then
|
||||
table.remove(rules, k)
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setKeywords = function(self, color, tab)
|
||||
keyWords[color] = tab
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
removeLine = function(self, index)
|
||||
if(#lines>1)then
|
||||
table.remove(lines, index or #lines)
|
||||
table.remove(bgLines, index or #bgLines)
|
||||
table.remove(fgLines, index or #fgLines)
|
||||
else
|
||||
lines = {""}
|
||||
bgLines = {""}
|
||||
fgLines = {""}
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getTextCursor = function(self)
|
||||
return textX, textY
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return wIndex, hIndex
|
||||
end,
|
||||
|
||||
setOffset = function(self, xOff, yOff)
|
||||
wIndex = xOff or wIndex
|
||||
hIndex = yOff or hIndex
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return wIndex
|
||||
end,
|
||||
|
||||
setXOffset = function(self, xOff)
|
||||
return self:setOffset(xOff, nil)
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return hIndex
|
||||
end,
|
||||
|
||||
setYOffset = function(self, yOff)
|
||||
return self:setOffset(nil, yOff)
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
base.getFocusHandler(self)
|
||||
local obx, oby = self:getPosition()
|
||||
self:getParent():setCursor(true, obx + textX - wIndex, oby + textY - hIndex, self:getForeground())
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
base.loseFocusHandler(self)
|
||||
self:getParent():setCursor(false)
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key)
|
||||
if (base.keyHandler(self, key)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (key == keys.backspace) then
|
||||
-- on backspace
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
else
|
||||
if (lines[textY] == "") then
|
||||
if (textY > 1) then
|
||||
table.remove(lines, textY)
|
||||
table.remove(fgLines, textY)
|
||||
table.remove(bgLines, textY)
|
||||
textX = lines[textY - 1]:len() + 1
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
textY = textY - 1
|
||||
end
|
||||
elseif (textX <= 1) then
|
||||
if (textY > 1) then
|
||||
textX = lines[textY - 1]:len() + 1
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
lines[textY - 1] = lines[textY - 1] .. lines[textY]
|
||||
fgLines[textY - 1] = fgLines[textY - 1] .. fgLines[textY]
|
||||
bgLines[textY - 1] = bgLines[textY - 1] .. bgLines[textY]
|
||||
table.remove(lines, textY)
|
||||
table.remove(fgLines, textY)
|
||||
table.remove(bgLines, textY)
|
||||
textY = textY - 1
|
||||
end
|
||||
else
|
||||
lines[textY] = lines[textY]:sub(1, textX - 2) .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 2) .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 2) .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
if (textX > 1) then
|
||||
textX = textX - 1
|
||||
end
|
||||
if (wIndex > 1) then
|
||||
if (textX < wIndex) then
|
||||
wIndex = wIndex - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if (textY < hIndex) then
|
||||
hIndex = hIndex - 1
|
||||
end
|
||||
end
|
||||
updateColors(self)
|
||||
self:setValue("")
|
||||
elseif (key == keys.delete) then
|
||||
-- on delete
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
else
|
||||
if (textX > lines[textY]:len()) then
|
||||
if (lines[textY + 1] ~= nil) then
|
||||
lines[textY] = lines[textY] .. lines[textY + 1]
|
||||
table.remove(lines, textY + 1)
|
||||
table.remove(bgLines, textY + 1)
|
||||
table.remove(fgLines, textY + 1)
|
||||
end
|
||||
else
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. lines[textY]:sub(textX + 1, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. fgLines[textY]:sub(textX + 1, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. bgLines[textY]:sub(textX + 1, bgLines[textY]:len())
|
||||
end
|
||||
end
|
||||
updateColors(self)
|
||||
elseif (key == keys.enter) then
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
end
|
||||
-- on enter
|
||||
table.insert(lines, textY + 1, lines[textY]:sub(textX, lines[textY]:len()))
|
||||
table.insert(fgLines, textY + 1, fgLines[textY]:sub(textX, fgLines[textY]:len()))
|
||||
table.insert(bgLines, textY + 1, bgLines[textY]:sub(textX, bgLines[textY]:len()))
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1)
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1)
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1)
|
||||
textY = textY + 1
|
||||
textX = 1
|
||||
wIndex = 1
|
||||
if (textY - hIndex >= h) then
|
||||
hIndex = hIndex + 1
|
||||
end
|
||||
self:setValue("")
|
||||
elseif (key == keys.up) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow up
|
||||
if (textY > 1) then
|
||||
textY = textY - 1
|
||||
if (textX > lines[textY]:len() + 1) then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
if (wIndex > 1) then
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if (hIndex > 1) then
|
||||
if (textY < hIndex) then
|
||||
hIndex = hIndex - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif (key == keys.down) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow down
|
||||
if (textY < #lines) then
|
||||
textY = textY + 1
|
||||
if (textX > lines[textY]:len() + 1) then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
if (wIndex > 1) then
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if (textY >= hIndex + h) then
|
||||
hIndex = hIndex + 1
|
||||
end
|
||||
end
|
||||
elseif (key == keys.right) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow right
|
||||
textX = textX + 1
|
||||
if (textY < #lines) then
|
||||
if (textX > lines[textY]:len() + 1) then
|
||||
textX = 1
|
||||
textY = textY + 1
|
||||
end
|
||||
elseif (textX > lines[textY]:len()) then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
if (textX < 1) then
|
||||
textX = 1
|
||||
end
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX - w + 1
|
||||
end
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
|
||||
elseif (key == keys.left) then
|
||||
startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil
|
||||
-- arrow left
|
||||
textX = textX - 1
|
||||
if (textX >= 1) then
|
||||
if (textX < wIndex) or (textX >= w + wIndex) then
|
||||
wIndex = textX
|
||||
end
|
||||
end
|
||||
if (textY > 1) then
|
||||
if (textX < 1) then
|
||||
textY = textY - 1
|
||||
textX = lines[textY]:len() + 1
|
||||
wIndex = textX - w + 1
|
||||
end
|
||||
end
|
||||
if (textX < 1) then
|
||||
textX = 1
|
||||
end
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
elseif(key == keys.tab)then
|
||||
if(textX % 3 == 0 )then
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. " " .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + 1
|
||||
end
|
||||
while textX % 3 ~= 0 do
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. " " .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + 1
|
||||
end
|
||||
end
|
||||
|
||||
if not((obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (oby + textY - hIndex >= oby and oby + textY - hIndex < oby + h)) then
|
||||
wIndex = math.max(1, lines[textY]:len()-w+1)
|
||||
hIndex = math.max(1, textY - h + 1)
|
||||
end
|
||||
|
||||
local cursorX = (textX <= lines[textY]:len() and textX - 1 or lines[textY]:len()) - (wIndex - 1)
|
||||
if (cursorX > self:getX() + w - 1) then
|
||||
cursorX = self:getX() + w - 1
|
||||
end
|
||||
local cursorY = (textY - hIndex < h and textY - hIndex or textY - hIndex - 1)
|
||||
if (cursorX < 1) then
|
||||
cursorX = 0
|
||||
end
|
||||
parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground())
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if(base.charHandler(self, char))then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if(isSelected())then
|
||||
removeSelection(self)
|
||||
end
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. char .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + 1
|
||||
if (textX >= w + wIndex) then
|
||||
wIndex = wIndex + 1
|
||||
end
|
||||
updateColors(self)
|
||||
self:setValue("")
|
||||
|
||||
if not((obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (oby + textY - hIndex >= oby and oby + textY - hIndex < oby + h)) then
|
||||
wIndex = math.max(1, lines[textY]:len()-w+1)
|
||||
hIndex = math.max(1, textY - h + 1)
|
||||
end
|
||||
|
||||
local cursorX = (textX <= lines[textY]:len() and textX - 1 or lines[textY]:len()) - (wIndex - 1)
|
||||
if (cursorX > self:getX() + w - 1) then
|
||||
cursorX = self:getX() + w - 1
|
||||
end
|
||||
local cursorY = (textY - hIndex < h and textY - hIndex or textY - hIndex - 1)
|
||||
if (cursorX < 1) then
|
||||
cursorX = 0
|
||||
end
|
||||
parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground())
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if (base.dragHandler(self, button, x, y)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local ox, oy = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
if (lines[y - oby + hIndex] ~= nil) then
|
||||
if(x - obx + wIndex > 0)and(x - obx + wIndex <= w)then
|
||||
textX = x - obx + wIndex
|
||||
textY = y - oby + hIndex
|
||||
|
||||
if textX > lines[textY]:len() then
|
||||
textX = lines[textY]:len() + 1
|
||||
end
|
||||
endSelX = textX
|
||||
endSelY = textY
|
||||
|
||||
if textX < wIndex then
|
||||
wIndex = textX - 1
|
||||
if wIndex < 1 then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
parent:setCursor(not isSelected(), ox + textX - wIndex, oy + textY - hIndex, self:getForeground())
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if (base.scrollHandler(self, dir, x, y)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local anchx, anchy = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
hIndex = hIndex + dir
|
||||
if (hIndex > #lines - (h - 1)) then
|
||||
hIndex = #lines - (h - 1)
|
||||
end
|
||||
|
||||
if (hIndex < 1) then
|
||||
hIndex = 1
|
||||
end
|
||||
|
||||
if (obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (anchy + textY - hIndex >= anchy and anchy + textY - hIndex < anchy + h) then
|
||||
parent:setCursor(not isSelected(), anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground())
|
||||
else
|
||||
parent:setCursor(false)
|
||||
end
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if (base.mouseHandler(self, button, x, y)) then
|
||||
local parent = self:getParent()
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local anchx, anchy = self:getPosition()
|
||||
if (lines[y - oby + hIndex] ~= nil) then
|
||||
textX = x - obx + wIndex
|
||||
textY = y - oby + hIndex
|
||||
endSelX = nil
|
||||
endSelY = nil
|
||||
startSelX = textX
|
||||
startSelY = textY
|
||||
if (textX > lines[textY]:len()) then
|
||||
textX = lines[textY]:len() + 1
|
||||
startSelX = textX
|
||||
end
|
||||
if (textX < wIndex) then
|
||||
wIndex = textX - 1
|
||||
if (wIndex < 1) then
|
||||
wIndex = 1
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground())
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
if (base.mouseUpHandler(self, button, x, y)) then
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
if (lines[y - oby + hIndex] ~= nil) then
|
||||
endSelX = x - obx + wIndex
|
||||
endSelY = y - oby + hIndex
|
||||
if (endSelX > lines[endSelY]:len()) then
|
||||
endSelX = lines[endSelY]:len() + 1
|
||||
end
|
||||
if(startSelX==endSelX)and(startSelY==endSelY)then
|
||||
startSelX, endSelX, startSelY, endSelY = nil, nil, nil, nil
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, paste, ...)
|
||||
base.eventHandler(self, event, paste, ...)
|
||||
if(event=="paste")then
|
||||
if(self:isFocused())then
|
||||
local parent = self:getParent()
|
||||
local fgColor, bgColor = self:getForeground(), self:getBackground()
|
||||
local w, h = self:getSize()
|
||||
lines[textY] = lines[textY]:sub(1, textX - 1) .. paste .. lines[textY]:sub(textX, lines[textY]:len())
|
||||
fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[fgColor]:rep(paste:len()) .. fgLines[textY]:sub(textX, fgLines[textY]:len())
|
||||
bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[bgColor]:rep(paste:len()) .. bgLines[textY]:sub(textX, bgLines[textY]:len())
|
||||
textX = textX + paste:len()
|
||||
if (textX >= w + wIndex) then
|
||||
wIndex = (textX+1)-w
|
||||
end
|
||||
local anchx, anchy = self:getPosition()
|
||||
parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, fgColor)
|
||||
updateColors(self)
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("textfield", function()
|
||||
local w, h = self:getSize()
|
||||
local bgColor = tHex[self:getBackground()]
|
||||
local fgColor = tHex[self:getForeground()]
|
||||
|
||||
for n = 1, h do
|
||||
local text = ""
|
||||
local bg = ""
|
||||
local fg = ""
|
||||
if lines[n + hIndex - 1] then
|
||||
text = lines[n + hIndex - 1]
|
||||
fg = fgLines[n + hIndex - 1]
|
||||
bg = bgLines[n + hIndex - 1]
|
||||
end
|
||||
|
||||
text = sub(text, wIndex, w + wIndex - 1)
|
||||
bg = rep(bgColor, w)
|
||||
fg = rep(fgColor, w)
|
||||
|
||||
self:addText(1, n, text)
|
||||
self:addBG(1, n, bg)
|
||||
self:addFG(1, n, fg)
|
||||
self:addBlit(1, n, text, fg, bg)
|
||||
end
|
||||
|
||||
if startSelX and endSelX and startSelY and endSelY then
|
||||
local sx, ex, sy, ey = getSelectionCoordinates()
|
||||
for n = sy, ey do
|
||||
local line = #lines[n]
|
||||
local xOffset = 0
|
||||
if n == sy and n == ey then
|
||||
xOffset = sx - 1 - (wIndex - 1)
|
||||
line = line - (sx - 1 - (wIndex - 1)) - (line - ex + (wIndex - 1))
|
||||
elseif n == ey then
|
||||
line = line - (line - ex + (wIndex - 1))
|
||||
elseif n == sy then
|
||||
line = line - (sx - 1)
|
||||
xOffset = sx - 1 - (wIndex - 1)
|
||||
end
|
||||
|
||||
local visible_line_length = math.min(line, w - xOffset)
|
||||
|
||||
self:addBG(1 + xOffset, n, rep(tHex[selectionBG], visible_line_length))
|
||||
self:addFG(1 + xOffset, n, rep(tHex[selectionFG], visible_line_length))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
load = function(self)
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_scroll")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("key")
|
||||
self:listenEvent("char")
|
||||
self:listenEvent("other_event")
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
112
lib/basalt/objects/Thread.lua
Normal file
112
lib/basalt/objects/Thread.lua
Normal file
|
@ -0,0 +1,112 @@
|
|||
return function(name, basalt)
|
||||
local base = basalt.getObject("Object")(name, basalt)
|
||||
|
||||
local objectType = "Thread"
|
||||
|
||||
local func
|
||||
local cRoutine
|
||||
local isActive = false
|
||||
local filter
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
start = function(self, f)
|
||||
if (f == nil) then
|
||||
error("Function provided to thread is nil")
|
||||
end
|
||||
func = f
|
||||
cRoutine = coroutine.create(func)
|
||||
isActive = true
|
||||
filter=nil
|
||||
local ok, result = coroutine.resume(cRoutine)
|
||||
filter = result
|
||||
if not (ok) then
|
||||
if (result ~= "Terminated") then
|
||||
error("Thread Error Occurred - " .. result)
|
||||
end
|
||||
end
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_up")
|
||||
self:listenEvent("mouse_scroll")
|
||||
self:listenEvent("mouse_drag")
|
||||
self:listenEvent("key")
|
||||
self:listenEvent("key_up")
|
||||
self:listenEvent("char")
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
getStatus = function(self, f)
|
||||
if (cRoutine ~= nil) then
|
||||
return coroutine.status(cRoutine)
|
||||
end
|
||||
return nil
|
||||
end,
|
||||
|
||||
stop = function(self, f)
|
||||
isActive = false
|
||||
self:listenEvent("mouse_click", false)
|
||||
self:listenEvent("mouse_up", false)
|
||||
self:listenEvent("mouse_scroll", false)
|
||||
self:listenEvent("mouse_drag", false)
|
||||
self:listenEvent("key", false)
|
||||
self:listenEvent("key_up", false)
|
||||
self:listenEvent("char", false)
|
||||
self:listenEvent("other_event", false)
|
||||
return self
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, ...)
|
||||
self:eventHandler("mouse_click", ...)
|
||||
end,
|
||||
mouseUpHandler = function(self, ...)
|
||||
self:eventHandler("mouse_up", ...)
|
||||
end,
|
||||
mouseScrollHandler = function(self, ...)
|
||||
self:eventHandler("mouse_scroll", ...)
|
||||
end,
|
||||
mouseDragHandler = function(self, ...)
|
||||
self:eventHandler("mouse_drag", ...)
|
||||
end,
|
||||
mouseMoveHandler = function(self, ...)
|
||||
self:eventHandler("mouse_move", ...)
|
||||
end,
|
||||
keyHandler = function(self, ...)
|
||||
self:eventHandler("key", ...)
|
||||
end,
|
||||
keyUpHandler = function(self, ...)
|
||||
self:eventHandler("key_up", ...)
|
||||
end,
|
||||
charHandler = function(self, ...)
|
||||
self:eventHandler("char", ...)
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if (isActive) then
|
||||
if (coroutine.status(cRoutine) == "suspended") then
|
||||
if(filter~=nil)then
|
||||
if(event~=filter)then return end
|
||||
filter=nil
|
||||
end
|
||||
local ok, result = coroutine.resume(cRoutine, event, ...)
|
||||
filter = result
|
||||
if not (ok) then
|
||||
if (result ~= "Terminated") then
|
||||
error("Thread Error Occurred - " .. result)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:stop()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
81
lib/basalt/objects/Timer.lua
Normal file
81
lib/basalt/objects/Timer.lua
Normal file
|
@ -0,0 +1,81 @@
|
|||
return function(name, basalt)
|
||||
local base = basalt.getObject("Object")(name, basalt)
|
||||
local objectType = "Timer"
|
||||
|
||||
local timer = 0
|
||||
local savedRepeats = 0
|
||||
local repeats = 0
|
||||
local timerObj
|
||||
local timerIsActive = false
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
setTime = function(self, _timer, _repeats)
|
||||
timer = _timer or 0
|
||||
savedRepeats = _repeats or 1
|
||||
return self
|
||||
end,
|
||||
|
||||
getTime = function(self)
|
||||
return timer
|
||||
end,
|
||||
|
||||
start = function(self)
|
||||
if(timerIsActive)then
|
||||
os.cancelTimer(timerObj)
|
||||
end
|
||||
repeats = savedRepeats
|
||||
timerObj = os.startTimer(timer)
|
||||
timerIsActive = true
|
||||
self:listenEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
isActive = function(self)
|
||||
return timerIsActive
|
||||
end,
|
||||
|
||||
cancel = function(self)
|
||||
if (timerObj ~= nil) then
|
||||
os.cancelTimer(timerObj)
|
||||
end
|
||||
timerIsActive = false
|
||||
self:removeEvent("other_event")
|
||||
return self
|
||||
end,
|
||||
|
||||
setStart = function(self, start)
|
||||
if (start == true) then
|
||||
return self:start()
|
||||
else
|
||||
return self:cancel()
|
||||
end
|
||||
end,
|
||||
|
||||
onCall = function(self, func)
|
||||
self:registerEvent("timed_event", func)
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, ...)
|
||||
base.eventHandler(self, event, ...)
|
||||
if event == "timer" and tObj == timerObj and timerIsActive then
|
||||
self:sendEvent("timed_event")
|
||||
if (repeats >= 1) then
|
||||
repeats = repeats - 1
|
||||
if (repeats >= 1) then
|
||||
timerObj = os.startTimer(timer)
|
||||
end
|
||||
elseif (repeats == -1) then
|
||||
timerObj = os.startTimer(timer)
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
356
lib/basalt/objects/Treeview.lua
Normal file
356
lib/basalt/objects/Treeview.lua
Normal file
|
@ -0,0 +1,356 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("ChangeableObject")(name, basalt)
|
||||
local objectType = "Treeview"
|
||||
|
||||
local nodes = {}
|
||||
local itemSelectedBG = colors.black
|
||||
local itemSelectedFG = colors.lightGray
|
||||
local selectionColorActive = true
|
||||
local textAlign = "left"
|
||||
local xOffset, yOffset = 0, 0
|
||||
local scrollable = true
|
||||
|
||||
base:setSize(16, 8)
|
||||
base:setZIndex(5)
|
||||
|
||||
local function newNode(text, expandable)
|
||||
text = text or ""
|
||||
expandable = expandable or false
|
||||
local expanded = false
|
||||
local parent = nil
|
||||
local children = {}
|
||||
|
||||
local node = {}
|
||||
|
||||
local onSelect
|
||||
|
||||
node = {
|
||||
getChildren = function(self)
|
||||
return children
|
||||
end,
|
||||
|
||||
setParent = function(self, p)
|
||||
if(parent~=nil)then
|
||||
parent.removeChild(parent.findChildrenByText(node.getText()))
|
||||
end
|
||||
parent = p
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
getParent = function(self)
|
||||
return parent
|
||||
end,
|
||||
|
||||
addChild = function(self, text, expandable)
|
||||
local childNode = newNode(text, expandable)
|
||||
childNode.setParent(node)
|
||||
table.insert(children, childNode)
|
||||
base:updateDraw()
|
||||
return childNode
|
||||
end,
|
||||
|
||||
setExpanded = function(self, exp)
|
||||
if(expandable)then
|
||||
expanded = exp
|
||||
end
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
isExpanded = function(self)
|
||||
return expanded
|
||||
end,
|
||||
|
||||
onSelect = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
onSelect = v
|
||||
end
|
||||
end
|
||||
return node
|
||||
end,
|
||||
|
||||
callOnSelect = function(self)
|
||||
if(onSelect~=nil)then
|
||||
onSelect(node)
|
||||
end
|
||||
end,
|
||||
|
||||
setExpandable = function(self, expandable)
|
||||
expandable = expandable
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
isExpandable = function(self)
|
||||
return expandable
|
||||
end,
|
||||
|
||||
removeChild = function(self, index)
|
||||
if(type(index)=="table")then
|
||||
for k,v in pairs(index)do
|
||||
if(v==index)then
|
||||
index = k
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
table.remove(children, index)
|
||||
base:updateDraw()
|
||||
return node
|
||||
end,
|
||||
|
||||
findChildrenByText = function(self, searchText)
|
||||
local foundNodes = {}
|
||||
for _, child in ipairs(children) do
|
||||
if string.find(child.getText(), searchText) then
|
||||
table.insert(foundNodes, child)
|
||||
end
|
||||
end
|
||||
return foundNodes
|
||||
end,
|
||||
|
||||
getText = function(self)
|
||||
return text
|
||||
end,
|
||||
|
||||
setText = function(self, t)
|
||||
text = t
|
||||
base:updateDraw()
|
||||
return node
|
||||
end
|
||||
}
|
||||
|
||||
return node
|
||||
end
|
||||
|
||||
local root = newNode("Root", true)
|
||||
root:setExpanded(true)
|
||||
|
||||
local object = {
|
||||
init = function(self)
|
||||
local parent = self:getParent()
|
||||
self:listenEvent("mouse_click")
|
||||
self:listenEvent("mouse_scroll")
|
||||
return base.init(self)
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType == t or base.isType ~= nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
setOffset = function(self, x, y)
|
||||
xOffset = x
|
||||
yOffset = y
|
||||
return self
|
||||
end,
|
||||
|
||||
setXOffset = function(self, x)
|
||||
return self:setOffset(x, yOffset)
|
||||
end,
|
||||
|
||||
setYOffset = function(self, y)
|
||||
return self:setOffset(xOffset, y)
|
||||
end,
|
||||
|
||||
getOffset = function(self)
|
||||
return xOffset, yOffset
|
||||
end,
|
||||
|
||||
getXOffset = function(self)
|
||||
return xOffset
|
||||
end,
|
||||
|
||||
getYOffset = function(self)
|
||||
return yOffset
|
||||
end,
|
||||
|
||||
setScrollable = function(self, scroll)
|
||||
scrollable = scroll
|
||||
return self
|
||||
end,
|
||||
|
||||
getScrollable = function(self, scroll)
|
||||
return scrollable
|
||||
end,
|
||||
|
||||
setSelectionColor = function(self, bgCol, fgCol, active)
|
||||
itemSelectedBG = bgCol or self:getBackground()
|
||||
itemSelectedFG = fgCol or self:getForeground()
|
||||
selectionColorActive = active~=nil and active or true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setSelectionBG = function(self, bgCol)
|
||||
return self:setSelectionColor(bgCol, nil, selectionColorActive)
|
||||
end,
|
||||
|
||||
setSelectionFG = function(self, fgCol)
|
||||
return self:setSelectionColor(nil, fgCol, selectionColorActive)
|
||||
end,
|
||||
|
||||
getSelectionColor = function(self)
|
||||
return itemSelectedBG, itemSelectedFG
|
||||
end,
|
||||
|
||||
getSelectionBG = function(self)
|
||||
return itemSelectedBG
|
||||
end,
|
||||
|
||||
getSelectionFG = function(self)
|
||||
return itemSelectedFG
|
||||
end,
|
||||
|
||||
isSelectionColorActive = function(self)
|
||||
return selectionColorActive
|
||||
end,
|
||||
|
||||
getRoot = function(self)
|
||||
return root
|
||||
end,
|
||||
|
||||
setRoot = function(self, node)
|
||||
root = node
|
||||
node.setParent(nil)
|
||||
return self
|
||||
end,
|
||||
|
||||
onSelect = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("treeview_select", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
selectionHandler = function(self, node)
|
||||
node.callOnSelect(node)
|
||||
self:sendEvent("treeview_select", node)
|
||||
return self
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y)
|
||||
if base.mouseHandler(self, button, x, y) then
|
||||
local currentLine = 1 - yOffset
|
||||
local obx, oby = self:getAbsolutePosition()
|
||||
local w, h = self:getSize()
|
||||
local function checkNodeClick(node, level)
|
||||
if y == oby+currentLine-1 then
|
||||
if x >= obx and x < obx + w then
|
||||
node:setExpanded(not node:isExpanded())
|
||||
self:selectionHandler(node)
|
||||
self:setValue(node)
|
||||
self:updateDraw()
|
||||
return true
|
||||
end
|
||||
end
|
||||
currentLine = currentLine + 1
|
||||
if node:isExpanded() then
|
||||
for _, child in ipairs(node:getChildren()) do
|
||||
if checkNodeClick(child, level + 1) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
for _, item in ipairs(root:getChildren()) do
|
||||
if checkNodeClick(item, 1) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if base.scrollHandler(self, dir, x, y) then
|
||||
if scrollable then
|
||||
local _, h = self:getSize()
|
||||
yOffset = yOffset + dir
|
||||
|
||||
if yOffset < 0 then
|
||||
yOffset = 0
|
||||
end
|
||||
|
||||
if dir >= 1 then
|
||||
local visibleLines = 0
|
||||
local function countVisibleLines(node, level)
|
||||
visibleLines = visibleLines + 1
|
||||
if node:isExpanded() then
|
||||
for _, child in ipairs(node:getChildren()) do
|
||||
countVisibleLines(child, level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, item in ipairs(root:getChildren()) do
|
||||
countVisibleLines(item, 1)
|
||||
end
|
||||
|
||||
if visibleLines > h then
|
||||
if yOffset > visibleLines - h then
|
||||
yOffset = visibleLines - h
|
||||
end
|
||||
else
|
||||
yOffset = yOffset - 1
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("treeview", function()
|
||||
local currentLine = 1 - yOffset
|
||||
local lastClickedNode = self:getValue()
|
||||
local function drawNode(node, level)
|
||||
local w, h = self:getSize()
|
||||
|
||||
if currentLine >= 1 and currentLine <= h then
|
||||
local bg = (node == lastClickedNode) and itemSelectedBG or self:getBackground()
|
||||
local fg = (node == lastClickedNode) and itemSelectedFG or self:getForeground()
|
||||
|
||||
local text = node.getText()
|
||||
self:addBlit(1 + level + xOffset, currentLine, text, tHex[fg]:rep(#text), tHex[bg]:rep(#text))
|
||||
end
|
||||
|
||||
currentLine = currentLine + 1
|
||||
|
||||
if node:isExpanded() then
|
||||
for _, child in ipairs(node:getChildren()) do
|
||||
drawNode(child, level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, item in ipairs(root:getChildren()) do
|
||||
drawNode(item, 1)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
|
||||
}
|
||||
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
646
lib/basalt/objects/VisualObject.lua
Normal file
646
lib/basalt/objects/VisualObject.lua
Normal file
|
@ -0,0 +1,646 @@
|
|||
local utils = require("utils")
|
||||
local tHex = require("tHex")
|
||||
|
||||
local sub, find, insert = string.sub, string.find, table.insert
|
||||
|
||||
return function(name, basalt)
|
||||
local base = basalt.getObject("Object")(name, basalt)
|
||||
-- Base object
|
||||
local objectType = "VisualObject" -- not changeable
|
||||
|
||||
local isVisible,ignOffset,isHovered,isClicked,isDragging = true,false,false,false,false
|
||||
local zIndex = 1
|
||||
|
||||
local x, y, width, height = 1,1,1,1
|
||||
local dragStartX, dragStartY, dragXOffset, dragYOffset = 0, 0, 0, 0
|
||||
|
||||
local bgColor,fgColor, transparency = colors.black, colors.white, false
|
||||
local parent
|
||||
|
||||
local preDrawQueue = {}
|
||||
local drawQueue = {}
|
||||
local postDrawQueue = {}
|
||||
|
||||
local renderObject = {}
|
||||
|
||||
local function split(str, d)
|
||||
local result = {}
|
||||
if str == "" then
|
||||
return result
|
||||
end
|
||||
d = d or " "
|
||||
local start = 1
|
||||
local delim_start, delim_end = find(str, d, start)
|
||||
while delim_start do
|
||||
insert(result, {x=start, value=sub(str, start, delim_start - 1)})
|
||||
start = delim_end + 1
|
||||
delim_start, delim_end = find(str, d, start)
|
||||
end
|
||||
insert(result, {x=start, value=sub(str, start)})
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
local object = {
|
||||
getType = function(self)
|
||||
return objectType
|
||||
end,
|
||||
|
||||
getBase = function(self)
|
||||
return base
|
||||
end,
|
||||
|
||||
isType = function(self, t)
|
||||
return objectType==t or base.isType~=nil and base.isType(t) or false
|
||||
end,
|
||||
|
||||
getBasalt = function(self)
|
||||
return basalt
|
||||
end,
|
||||
|
||||
show = function(self)
|
||||
isVisible = true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
hide = function(self)
|
||||
isVisible = false
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
isVisible = function(self)
|
||||
return isVisible
|
||||
end,
|
||||
|
||||
setVisible = function(self, _isVisible)
|
||||
isVisible = _isVisible or not isVisible
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setTransparency = function(self, _transparency)
|
||||
transparency = _transparency~= nil and _transparency or true
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setParent = function(self, newParent, noRemove)
|
||||
base.setParent(self, newParent, noRemove)
|
||||
parent = newParent
|
||||
return self
|
||||
end,
|
||||
|
||||
setFocus = function(self)
|
||||
if (parent ~= nil) then
|
||||
parent:setFocusedChild(self)
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setZIndex = function(self, index)
|
||||
zIndex = index
|
||||
if (parent ~= nil) then
|
||||
parent:updateZIndex(self, zIndex)
|
||||
self:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
getZIndex = function(self)
|
||||
return zIndex
|
||||
end,
|
||||
|
||||
updateDraw = function(self)
|
||||
if (parent ~= nil) then
|
||||
parent:updateDraw()
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
setPosition = function(self, xPos, yPos, rel)
|
||||
local curX, curY = x, y
|
||||
if(type(xPos)=="number")then
|
||||
x = rel and x+xPos or xPos
|
||||
end
|
||||
if(type(yPos)=="number")then
|
||||
y = rel and y+yPos or yPos
|
||||
end
|
||||
if(parent~=nil)then parent:customEventHandler("basalt_FrameReposition", self) end
|
||||
if(self:getType()=="Container")then parent:customEventHandler("basalt_FrameReposition", self) end
|
||||
self:updateDraw()
|
||||
self:repositionHandler(curX, curY)
|
||||
return self
|
||||
end,
|
||||
|
||||
getX = function(self)
|
||||
return x
|
||||
end,
|
||||
|
||||
setX = function(self, newX)
|
||||
return self:setPosition(newX, y)
|
||||
end,
|
||||
|
||||
getY = function(self)
|
||||
return y
|
||||
end,
|
||||
|
||||
setY = function(self, newY)
|
||||
return self:setPosition(x, newY)
|
||||
end,
|
||||
|
||||
getPosition = function(self)
|
||||
return x, y
|
||||
end,
|
||||
|
||||
setSize = function(self, newWidth, newHeight, rel)
|
||||
local oldW, oldH = width, height
|
||||
if(type(newWidth)=="number")then
|
||||
width = rel and width+newWidth or newWidth
|
||||
end
|
||||
if(type(newHeight)=="number")then
|
||||
height = rel and height+newHeight or newHeight
|
||||
end
|
||||
if(parent~=nil)then
|
||||
parent:customEventHandler("basalt_FrameResize", self)
|
||||
if(self:getType()=="Container")then parent:customEventHandler("basalt_FrameResize", self) end
|
||||
end
|
||||
self:resizeHandler(oldW, oldH)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getHeight = function(self)
|
||||
return height
|
||||
end,
|
||||
|
||||
setHeight = function(self, newHeight)
|
||||
return self:setSize(width, newHeight)
|
||||
end,
|
||||
|
||||
getWidth = function(self)
|
||||
return width
|
||||
end,
|
||||
|
||||
setWidth = function(self, newWidth)
|
||||
return self:setSize(newWidth, height)
|
||||
end,
|
||||
|
||||
getSize = function(self)
|
||||
return width, height
|
||||
end,
|
||||
|
||||
setBackground = function(self, color)
|
||||
bgColor = color
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBackground = function(self)
|
||||
return bgColor
|
||||
end,
|
||||
|
||||
setForeground = function(self, color)
|
||||
fgColor = color or false
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getForeground = function(self)
|
||||
return fgColor
|
||||
end,
|
||||
|
||||
getAbsolutePosition = function(self, x, y)
|
||||
-- relative position to absolute position
|
||||
if (x == nil) or (y == nil) then
|
||||
x, y = self:getPosition()
|
||||
end
|
||||
|
||||
if (parent ~= nil) then
|
||||
local fx, fy = parent:getAbsolutePosition()
|
||||
x = fx + x - 1
|
||||
y = fy + y - 1
|
||||
end
|
||||
return x, y
|
||||
end,
|
||||
|
||||
ignoreOffset = function(self, ignore)
|
||||
ignOffset = ignore
|
||||
if(ignore==nil)then ignOffset = true end
|
||||
return self
|
||||
end,
|
||||
|
||||
getIgnoreOffset = function(self)
|
||||
return ignOffset
|
||||
end,
|
||||
|
||||
isCoordsInObject = function(self, x, y)
|
||||
if(isVisible)and(self:isEnabled())then
|
||||
if(x==nil)or(y==nil)then return false end
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local w, h = self:getSize()
|
||||
if (objX <= x) and (objX + w > x) and (objY <= y) and (objY + h > y) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
onGetFocus = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("get_focus", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onLoseFocus = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("lose_focus", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
isFocused = function(self)
|
||||
if (parent ~= nil) then
|
||||
return parent:getFocused() == self
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
resizeHandler = function(self, ...)
|
||||
if(self:isEnabled())then
|
||||
local val = self:sendEvent("basalt_resize", ...)
|
||||
if(val==false)then return false end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
repositionHandler = function(self, ...)
|
||||
if(self:isEnabled())then
|
||||
local val = self:sendEvent("basalt_reposition", ...)
|
||||
if(val==false)then return false end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
onResize = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("basalt_resize", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
onReposition = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("basalt_reposition", v)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end,
|
||||
|
||||
mouseHandler = function(self, button, x, y, isMon)
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local val = self:sendEvent("mouse_click", button, x - (objX-1), y - (objY-1), x, y, isMon)
|
||||
if(val==false)then return false end
|
||||
if(parent~=nil)then
|
||||
parent:setFocusedChild(self)
|
||||
end
|
||||
isClicked = true
|
||||
isDragging = true
|
||||
dragStartX, dragStartY = x, y
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
mouseUpHandler = function(self, button, x, y)
|
||||
isDragging = false
|
||||
if(isClicked)then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local val = self:sendEvent("mouse_release", button, x - (objX-1), y - (objY-1), x, y)
|
||||
isClicked = false
|
||||
end
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local val = self:sendEvent("mouse_up", button, x - (objX-1), y - (objY-1), x, y)
|
||||
if(val==false)then return false end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
dragHandler = function(self, button, x, y)
|
||||
if(isDragging)then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local val = self:sendEvent("mouse_drag", button, x - (objX-1), y - (objY-1), dragStartX-x, dragStartY-y, x, y)
|
||||
dragStartX, dragStartY = x, y
|
||||
if(val~=nil)then return val end
|
||||
if(parent~=nil)then
|
||||
parent:setFocusedChild(self)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
dragStartX, dragStartY = x, y
|
||||
dragXOffset, dragYOffset = objX - x, objY - y
|
||||
end
|
||||
end,
|
||||
|
||||
scrollHandler = function(self, dir, x, y)
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
local objX, objY = self:getAbsolutePosition()
|
||||
local val = self:sendEvent("mouse_scroll", dir, x - (objX-1), y - (objY-1))
|
||||
if(val==false)then return false end
|
||||
if(parent~=nil)then
|
||||
parent:setFocusedChild(self)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end,
|
||||
|
||||
hoverHandler = function(self, x, y, stopped)
|
||||
if(self:isCoordsInObject(x, y))then
|
||||
local val = self:sendEvent("mouse_hover", x, y, stopped)
|
||||
if(val==false)then return false end
|
||||
isHovered = true
|
||||
return true
|
||||
end
|
||||
if(isHovered)then
|
||||
local val = self:sendEvent("mouse_leave", x, y, stopped)
|
||||
if(val==false)then return false end
|
||||
isHovered = false
|
||||
end
|
||||
end,
|
||||
|
||||
keyHandler = function(self, key, isHolding)
|
||||
if(self:isEnabled())and(isVisible)then
|
||||
if (self:isFocused()) then
|
||||
local val = self:sendEvent("key", key, isHolding)
|
||||
if(val==false)then return false end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
keyUpHandler = function(self, key)
|
||||
if(self:isEnabled())and(isVisible)then
|
||||
if (self:isFocused()) then
|
||||
local val = self:sendEvent("key_up", key)
|
||||
if(val==false)then return false end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
charHandler = function(self, char)
|
||||
if(self:isEnabled())and(isVisible)then
|
||||
if(self:isFocused())then
|
||||
local val = self:sendEvent("char", char)
|
||||
if(val==false)then return false end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
getFocusHandler = function(self)
|
||||
local val = self:sendEvent("get_focus")
|
||||
if(val~=nil)then return val end
|
||||
return true
|
||||
end,
|
||||
|
||||
loseFocusHandler = function(self)
|
||||
isDragging = false
|
||||
local val = self:sendEvent("lose_focus")
|
||||
if(val~=nil)then return val end
|
||||
return true
|
||||
end,
|
||||
|
||||
addDraw = function(self, name, f, pos, typ, active)
|
||||
local queue = (typ==nil or typ==1) and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue
|
||||
pos = pos or #queue+1
|
||||
if(name~=nil)then
|
||||
for k,v in pairs(queue)do
|
||||
if(v.name==name)then
|
||||
table.remove(queue, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
local t = {name=name, f=f, pos=pos, active=active~=nil and active or true}
|
||||
table.insert(queue, pos, t)
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
addPreDraw = function(self, name, f, pos, typ)
|
||||
self:addDraw(name, f, pos, 2)
|
||||
return self
|
||||
end,
|
||||
|
||||
addPostDraw = function(self, name, f, pos, typ)
|
||||
self:addDraw(name, f, pos, 3)
|
||||
return self
|
||||
end,
|
||||
|
||||
setDrawState = function(self, name, state, typ)
|
||||
local queue = (typ==nil or typ==1) and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue
|
||||
for k,v in pairs(queue)do
|
||||
if(v.name==name)then
|
||||
v.active = state
|
||||
break
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getDrawId = function(self, name, typ)
|
||||
local queue = typ==1 and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue or drawQueue
|
||||
for k,v in pairs(queue)do
|
||||
if(v.name==name)then
|
||||
return k
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
addText = function(self, x, y, text)
|
||||
local obj = self:getParent() or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
if not(transparency)then
|
||||
obj:setText(x+xPos-1, y+yPos-1, text)
|
||||
return
|
||||
end
|
||||
local t = split(text, "\0")
|
||||
for k,v in pairs(t)do
|
||||
if(v.value~="")and(v.value~="\0")then
|
||||
obj:setText(x+v.x+xPos-2, y+yPos-1, v.value)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
addBG = function(self, x, y, bg, noText)
|
||||
local obj = parent or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
if not(transparency)then
|
||||
obj:setBG(x+xPos-1, y+yPos-1, bg)
|
||||
return
|
||||
end
|
||||
local t = split(bg)
|
||||
for k,v in pairs(t)do
|
||||
if(v.value~="")and(v.value~=" ")then
|
||||
if(noText~=true)then
|
||||
obj:setText(x+v.x+xPos-2, y+yPos-1, (" "):rep(#v.value))
|
||||
obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value)
|
||||
else
|
||||
table.insert(renderObject, {x=x+v.x-1,y=y,bg=v.value})
|
||||
obj:setBG(x+xPos-1, y+yPos-1, fg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
addFG = function(self, x, y, fg)
|
||||
local obj = parent or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
if not(transparency)then
|
||||
obj:setFG(x+xPos-1, y+yPos-1, fg)
|
||||
return
|
||||
end
|
||||
local t = split(fg)
|
||||
for k,v in pairs(t)do
|
||||
if(v.value~="")and(v.value~=" ")then
|
||||
obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
addBlit = function(self, x, y, t, fg, bg)
|
||||
local obj = parent or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
if not(transparency)then
|
||||
obj:blit(x+xPos-1, y+yPos-1, t, fg, bg)
|
||||
return
|
||||
end
|
||||
local _text = split(t, "\0")
|
||||
local _fg = split(fg)
|
||||
local _bg = split(bg)
|
||||
for k,v in pairs(_text)do
|
||||
if(v.value~="")or(v.value~="\0")then
|
||||
obj:setText(x+v.x+xPos-2, y+yPos-1, v.value)
|
||||
end
|
||||
end
|
||||
for k,v in pairs(_bg)do
|
||||
if(v.value~="")or(v.value~=" ")then
|
||||
obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value)
|
||||
end
|
||||
end
|
||||
for k,v in pairs(_fg)do
|
||||
if(v.value~="")or(v.value~=" ")then
|
||||
obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
addTextBox = function(self, x, y, w, h, text)
|
||||
local obj = parent or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
obj:drawTextBox(x+xPos-1, y+yPos-1, w, h, text)
|
||||
end,
|
||||
|
||||
addForegroundBox = function(self, x, y, w, h, col)
|
||||
local obj = parent or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
obj:drawForegroundBox(x+xPos-1, y+yPos-1, w, h, col)
|
||||
end,
|
||||
|
||||
addBackgroundBox = function(self, x, y, w, h, col)
|
||||
local obj = parent or self
|
||||
local xPos,yPos = self:getPosition()
|
||||
if(parent~=nil)then
|
||||
local xO, yO = parent:getOffset()
|
||||
xPos = ignOffset and xPos or xPos - xO
|
||||
yPos = ignOffset and yPos or yPos - yO
|
||||
end
|
||||
obj:drawBackgroundBox(x+xPos-1, y+yPos-1, w, h, col)
|
||||
end,
|
||||
|
||||
render = function(self)
|
||||
if (isVisible)then
|
||||
self:redraw()
|
||||
end
|
||||
end,
|
||||
|
||||
redraw = function(self)
|
||||
for k,v in pairs(preDrawQueue)do
|
||||
if (v.active)then
|
||||
v.f(self)
|
||||
end
|
||||
end
|
||||
for k,v in pairs(drawQueue)do
|
||||
if (v.active)then
|
||||
v.f(self)
|
||||
end
|
||||
end
|
||||
for k,v in pairs(postDrawQueue)do
|
||||
if (v.active)then
|
||||
v.f(self)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
self:addDraw("base", function()
|
||||
local w,h = self:getSize()
|
||||
if(bgColor~=false)then
|
||||
self:addTextBox(1, 1, w, h, " ")
|
||||
self:addBackgroundBox(1, 1, w, h, bgColor)
|
||||
end
|
||||
if(fgColor~=false)then
|
||||
self:addForegroundBox(1, 1, w, h, fgColor)
|
||||
end
|
||||
end, 1)
|
||||
end,
|
||||
}
|
||||
object.__index = object
|
||||
return setmetatable(object, base)
|
||||
end
|
112
lib/basalt/plugin.lua
Normal file
112
lib/basalt/plugin.lua
Normal file
|
@ -0,0 +1,112 @@
|
|||
local args = {...}
|
||||
local plugins = {}
|
||||
local pluginNames = {}
|
||||
|
||||
local dir = fs.getDir(args[2] or "Basalt")
|
||||
local pluginDir = fs.combine(dir, "plugins")
|
||||
if(packaged)then
|
||||
for k,v in pairs(getProject("plugins"))do
|
||||
table.insert(pluginNames, k)
|
||||
local newPlugin = v()
|
||||
if(type(newPlugin)=="table")then
|
||||
for a,b in pairs(newPlugin)do
|
||||
if(type(a)=="string")then
|
||||
if(plugins[a]==nil)then plugins[a] = {} end
|
||||
table.insert(plugins[a], b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if(fs.exists(pluginDir))then
|
||||
for _,v in pairs(fs.list(pluginDir))do
|
||||
local newPlugin
|
||||
if(fs.isDir(fs.combine(pluginDir, v)))then
|
||||
table.insert(pluginNames, fs.combine(pluginDir, v))
|
||||
newPlugin = require(v.."/init")
|
||||
else
|
||||
table.insert(pluginNames, v)
|
||||
newPlugin = require(v:gsub(".lua", ""))
|
||||
end
|
||||
if(type(newPlugin)=="table")then
|
||||
for a,b in pairs(newPlugin)do
|
||||
if(type(a)=="string")then
|
||||
if(plugins[a]==nil)then plugins[a] = {} end
|
||||
table.insert(plugins[a], b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get(name)
|
||||
return plugins[name]
|
||||
end
|
||||
|
||||
return {
|
||||
--- Gets a plugin list
|
||||
--- @param name string name of plugin list
|
||||
--- @return table plugins
|
||||
get = get,
|
||||
getAvailablePlugins = function()
|
||||
return pluginNames
|
||||
end,
|
||||
|
||||
--- Adds a plugin to basalt's plugin list
|
||||
--- @param path string path to plugin
|
||||
addPlugin = function(path)
|
||||
if(fs.exists(path))then
|
||||
if(fs.isDir(path))then
|
||||
for _,v in pairs(fs.list(path))do
|
||||
table.insert(pluginNames, v)
|
||||
if not(fs.isDir(fs.combine(path, v)))then
|
||||
local pluginName = v:gsub(".lua", "")
|
||||
local newPlugin = require(fs.combine(path, pluginName))
|
||||
if(type(newPlugin)=="table")then
|
||||
for a,b in pairs(newPlugin)do
|
||||
if(type(a)=="string")then
|
||||
if(plugins[a]==nil)then plugins[a] = {} end
|
||||
table.insert(plugins[a], b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local newPlugin = require(path:gsub(".lua", ""))
|
||||
table.insert(pluginNames, path:match("[\\/]?([^\\/]-([^%.]+))$"))
|
||||
if(type(newPlugin)=="table")then
|
||||
for a,b in pairs(newPlugin)do
|
||||
if(type(a)=="string")then
|
||||
if(plugins[a]==nil)then plugins[a] = {} end
|
||||
table.insert(plugins[a], b)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
--- Loads all available plugins into basalt's objects
|
||||
--- @param objects table objects to load plugins into
|
||||
--- @param basalt table basalt
|
||||
--- @return table objects modified objects
|
||||
loadPlugins = function(objects, basalt)
|
||||
for k,v in pairs(objects)do
|
||||
local plugList = plugins[k]
|
||||
if(plugList~=nil)then
|
||||
objects[k] = function(...)
|
||||
local moddedObject = v(...)
|
||||
for _,b in pairs(plugList)do
|
||||
local ext = b(moddedObject, basalt, ...)
|
||||
ext.__index = ext
|
||||
moddedObject = setmetatable(ext, moddedObject)
|
||||
end
|
||||
return moddedObject
|
||||
end
|
||||
end
|
||||
end
|
||||
return objects
|
||||
end
|
||||
}
|
47
lib/basalt/plugins/advancedBackground.lua
Normal file
47
lib/basalt/plugins/advancedBackground.lua
Normal file
|
@ -0,0 +1,47 @@
|
|||
local XMLParser = require("xmlParser")
|
||||
|
||||
return {
|
||||
VisualObject = function(base)
|
||||
local bgSymbol = false
|
||||
local bgSymbolColor = colors.black
|
||||
|
||||
local object = {
|
||||
setBackground = function(self, bg, symbol, symbolCol)
|
||||
base.setBackground(self, bg)
|
||||
bgSymbol = symbol or bgSymbol
|
||||
bgSymbolColor = symbolCol or bgSymbolColor
|
||||
return self
|
||||
end,
|
||||
|
||||
setBackgroundSymbol = function(self, symbol, symbolCol)
|
||||
bgSymbol = symbol
|
||||
bgSymbolColor = symbolCol or bgSymbolColor
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getBackgroundSymbol = function(self)
|
||||
return bgSymbol
|
||||
end,
|
||||
|
||||
getBackgroundSymbolColor = function(self)
|
||||
return bgSymbolColor
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("advanced-bg", function()
|
||||
local w, h = self:getSize()
|
||||
if(bgSymbol~=false)then
|
||||
self:addTextBox(1, 1, w, h, bgSymbol:sub(1,1))
|
||||
if(bgSymbol~=" ")then
|
||||
self:addForegroundBox(1, 1, w, h, bgSymbolColor)
|
||||
end
|
||||
end
|
||||
end, 2)
|
||||
end
|
||||
}
|
||||
|
||||
return object
|
||||
end
|
||||
}
|
344
lib/basalt/plugins/animations.lua
Normal file
344
lib/basalt/plugins/animations.lua
Normal file
|
@ -0,0 +1,344 @@
|
|||
local floor,sin,cos,pi,sqrt,pow = math.floor,math.sin,math.cos,math.pi,math.sqrt,math.pow
|
||||
|
||||
-- You can find the easing curves here https://easings.net
|
||||
|
||||
local function lerp(s, e, pct)
|
||||
return s + (e - s) * pct
|
||||
end
|
||||
|
||||
local function linear(t)
|
||||
return t
|
||||
end
|
||||
|
||||
local function flip(t)
|
||||
return 1 - t
|
||||
end
|
||||
|
||||
local function easeIn(t)
|
||||
return t * t * t
|
||||
end
|
||||
|
||||
local function easeOut(t)
|
||||
return flip(easeIn(flip(t)))
|
||||
end
|
||||
|
||||
local function easeInOut(t)
|
||||
return lerp(easeIn(t), easeOut(t), t)
|
||||
end
|
||||
|
||||
local function easeOutSine(t)
|
||||
return sin((t * pi) / 2);
|
||||
end
|
||||
|
||||
local function easeInSine(t)
|
||||
return flip(cos((t * pi) / 2))
|
||||
end
|
||||
|
||||
local function easeInOutSine(t)
|
||||
return -(cos(pi * x) - 1) / 2
|
||||
end
|
||||
|
||||
local function easeInBack(t)
|
||||
local c1 = 1.70158;
|
||||
local c3 = c1 + 1
|
||||
return c3*t^3-c1*t^2
|
||||
end
|
||||
|
||||
local function easeInCubic(t)
|
||||
return t^3
|
||||
end
|
||||
|
||||
local function easeInElastic(t)
|
||||
local c4 = (2*pi)/3;
|
||||
return t == 0 and 0 or (t == 1 and 1 or (
|
||||
-2^(10*t-10)*sin((t*10-10.75)*c4)
|
||||
))
|
||||
end
|
||||
|
||||
local function easeInExpo(t)
|
||||
return t == 0 and 0 or 2^(10*t-10)
|
||||
end
|
||||
|
||||
local function easeInExpo(t)
|
||||
return t == 0 and 0 or 2^(10*t-10)
|
||||
end
|
||||
|
||||
local function easeInOutBack(t)
|
||||
local c1 = 1.70158;
|
||||
local c2 = c1 * 1.525;
|
||||
return t < 0.5 and ((2*t)^2*((c2+1)*2*t-c2))/2 or ((2*t-2)^2*((c2+1)*(t*2-2)+c2)+2)/2
|
||||
end
|
||||
|
||||
local function easeInOutCubic(t)
|
||||
return t < 0.5 and 4 * t^3 or 1-(-2*t+2)^3 / 2
|
||||
end
|
||||
|
||||
local function easeInOutElastic(t)
|
||||
local c5 = (2*pi) / 4.5
|
||||
return t==0 and 0 or (t == 1 and 1 or (t < 0.5 and -(2^(20*t-10) * sin((20*t - 11.125) * c5))/2 or (2^(-20*t+10) * sin((20*t - 11.125) * c5))/2 + 1))
|
||||
end
|
||||
|
||||
local function easeInOutExpo(t)
|
||||
return t == 0 and 0 or (t == 1 and 1 or (t < 0.5 and 2^(20*t-10)/2 or (2-2^(-20*t+10)) /2))
|
||||
end
|
||||
|
||||
local function easeInOutQuad(t)
|
||||
return t < 0.5 and 2*t^2 or 1-(-2*t+2)^2/2
|
||||
end
|
||||
|
||||
local function easeInOutQuart(t)
|
||||
return t < 0.5 and 8*t^4 or 1 - (-2*t+2)^4 / 2
|
||||
end
|
||||
|
||||
local function easeInOutQuint(t)
|
||||
return t < 0.5 and 16*t^5 or 1-(-2*t+2)^5 / 2
|
||||
end
|
||||
|
||||
local function easeInQuad(t)
|
||||
return t^2
|
||||
end
|
||||
|
||||
local function easeInQuart(t)
|
||||
return t^4
|
||||
end
|
||||
|
||||
local function easeInQuint(t)
|
||||
return t^5
|
||||
end
|
||||
|
||||
local function easeOutBack(t)
|
||||
local c1 = 1.70158;
|
||||
local c3 = c1 + 1
|
||||
return 1+c3*(t-1)^3+c1*(t-1)^2
|
||||
end
|
||||
|
||||
local function easeOutCubic(t)
|
||||
return 1 - (1-t)^3
|
||||
end
|
||||
|
||||
local function easeOutElastic(t)
|
||||
local c4 = (2*pi)/3;
|
||||
|
||||
return t == 0 and 0 or (t == 1 and 1 or (2^(-10*t)*sin((t*10-0.75)*c4)+1))
|
||||
end
|
||||
|
||||
local function easeOutExpo(t)
|
||||
return t == 1 and 1 or 1-2^(-10*t)
|
||||
end
|
||||
|
||||
local function easeOutQuad(t)
|
||||
return 1 - (1 - t) * (1 - t)
|
||||
end
|
||||
|
||||
local function easeOutQuart(t)
|
||||
return 1 - (1-t)^4
|
||||
end
|
||||
|
||||
local function easeOutQuint(t)
|
||||
return 1 - (1 - t)^5
|
||||
end
|
||||
|
||||
local function easeInCirc(t)
|
||||
return 1 - sqrt(1 - pow(t, 2))
|
||||
end
|
||||
|
||||
local function easeOutCirc(t)
|
||||
return sqrt(1 - pow(t - 1, 2))
|
||||
end
|
||||
|
||||
local function easeInOutCirc(t)
|
||||
return t < 0.5 and (1 - sqrt(1 - pow(2 * t, 2))) / 2 or (sqrt(1 - pow(-2 * t + 2, 2)) + 1) / 2;
|
||||
end
|
||||
|
||||
local function easeOutBounce(t)
|
||||
local n1 = 7.5625;
|
||||
local d1 = 2.75;
|
||||
|
||||
if (t < 1 / d1)then
|
||||
return n1 * t * t
|
||||
elseif (t < 2 / d1)then
|
||||
local a = t - 1.5 / d1
|
||||
return n1 * a * a + 0.75;
|
||||
elseif (t < 2.5 / d1)then
|
||||
local a = t - 2.25 / d1
|
||||
return n1 * a * a + 0.9375;
|
||||
else
|
||||
local a = t - 2.625 / d1
|
||||
return n1 * a * a + 0.984375;
|
||||
end
|
||||
end
|
||||
|
||||
local function easeInBounce(t)
|
||||
return 1 - easeOutBounce(1 - t)
|
||||
end
|
||||
|
||||
local function easeInOutBounce(t)
|
||||
return x < 0.5 and (1 - easeOutBounce(1 - 2 * t)) / 2 or (1 + easeOutBounce(2 * t - 1)) / 2;
|
||||
end
|
||||
|
||||
local lerp = {
|
||||
linear = linear,
|
||||
lerp = lerp,
|
||||
flip=flip,
|
||||
easeIn=easeIn,
|
||||
easeInSine = easeInSine,
|
||||
easeInBack=easeInBack,
|
||||
easeInCubic=easeInCubic,
|
||||
easeInElastic=easeInElastic,
|
||||
easeInExpo=easeInExpo,
|
||||
easeInQuad=easeInQuad,
|
||||
easeInQuart=easeInQuart,
|
||||
easeInQuint=easeInQuint,
|
||||
easeInCirc=easeInCirc,
|
||||
easeInBounce=easeInBounce,
|
||||
easeOut=easeOut,
|
||||
easeOutSine = easeOutSine,
|
||||
easeOutBack=easeOutBack,
|
||||
easeOutCubic=easeOutCubic,
|
||||
easeOutElastic=easeOutElastic,
|
||||
easeOutExpo=easeOutExpo,
|
||||
easeOutQuad=easeOutQuad,
|
||||
easeOutQuart=easeOutQuart,
|
||||
easeOutQuint=easeOutQuint,
|
||||
easeOutCirc=easeOutCirc,
|
||||
easeOutBounce=easeOutBounce,
|
||||
easeInOut=easeInOut,
|
||||
easeInOutSine = easeInOutSine,
|
||||
easeInOutBack=easeInOutBack,
|
||||
easeInOutCubic=easeInOutCubic,
|
||||
easeInOutElastic=easeInOutElastic,
|
||||
easeInOutExpo=easeInOutExpo,
|
||||
easeInOutQuad=easeInOutQuad,
|
||||
easeInOutQuart=easeInOutQuart,
|
||||
easeInOutQuint=easeInOutQuint,
|
||||
easeInOutCirc=easeInOutCirc,
|
||||
easeInOutBounce=easeInOutBounce,
|
||||
}
|
||||
|
||||
local XMLParser = require("xmlParser")
|
||||
|
||||
return {
|
||||
VisualObject = function(base, basalt)
|
||||
local activeAnimations = {}
|
||||
local defaultMode = "linear"
|
||||
|
||||
local function getAnimation(self, timerId)
|
||||
for k,v in pairs(activeAnimations)do
|
||||
if(v.timerId==timerId)then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function createAnimation(self, v1, v2, duration, timeOffset, mode, typ, f, get, set)
|
||||
local v1Val, v2Val = get(self)
|
||||
if(activeAnimations[typ]~=nil)then
|
||||
os.cancelTimer(activeAnimations[typ].timerId)
|
||||
end
|
||||
activeAnimations[typ] = {}
|
||||
activeAnimations[typ].call = function()
|
||||
local progress = activeAnimations[typ].progress
|
||||
local _v1 = math.floor(lerp.lerp(v1Val, v1, lerp[mode](progress / duration))+0.5)
|
||||
local _v2 = math.floor(lerp.lerp(v2Val, v2, lerp[mode](progress / duration))+0.5)
|
||||
set(self, _v1, _v2)
|
||||
end
|
||||
activeAnimations[typ].finished = function()
|
||||
set(self, v1, v2)
|
||||
if(f~=nil)then f(self) end
|
||||
end
|
||||
|
||||
activeAnimations[typ].timerId=os.startTimer(0.05+timeOffset)
|
||||
activeAnimations[typ].progress=0
|
||||
activeAnimations[typ].duration=duration
|
||||
activeAnimations[typ].mode=mode
|
||||
self:listenEvent("other_event")
|
||||
end
|
||||
|
||||
local function createColorAnimation(self, duration, timeOffset, typ, set, ...)
|
||||
local newColors = {...}
|
||||
if(activeAnimations[typ]~=nil)then
|
||||
os.cancelTimer(activeAnimations[typ].timerId)
|
||||
end
|
||||
activeAnimations[typ] = {}
|
||||
local colorIndex = 1
|
||||
activeAnimations[typ].call = function()
|
||||
local color = newColors[colorIndex]
|
||||
set(self, color)
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
animatePosition = function(self, x, y, duration, timeOffset, mode, f)
|
||||
mode = mode or defaultMode
|
||||
duration = duration or 1
|
||||
timeOffset = timeOffset or 0
|
||||
x = math.floor(x+0.5)
|
||||
y = math.floor(y+0.5)
|
||||
createAnimation(self, x, y, duration, timeOffset, mode, "position", f, self.getPosition, self.setPosition)
|
||||
return self
|
||||
end,
|
||||
|
||||
animateSize = function(self, w, h, duration, timeOffset, mode, f)
|
||||
mode = mode or defaultMode
|
||||
duration = duration or 1
|
||||
timeOffset = timeOffset or 0
|
||||
createAnimation(self, w, h, duration, timeOffset, mode, "size", f, self.getSize, self.setSize)
|
||||
return self
|
||||
end,
|
||||
|
||||
animateOffset = function(self, x, y, duration, timeOffset, mode, f)
|
||||
mode = mode or defaultMode
|
||||
duration = duration or 1
|
||||
timeOffset = timeOffset or 0
|
||||
createAnimation(self, x, y, duration, timeOffset, mode, "offset", f, self.getOffset, self.setOffset)
|
||||
return self
|
||||
end,
|
||||
|
||||
animateBackground = function(self, color, duration, timeOffset, mode, f)
|
||||
mode = mode or defaultMode
|
||||
duration = duration or 1
|
||||
timeOffset = timeOffset or 0
|
||||
createColorAnimation(self, color, nil, duration, timeOffset, mode, "background", f, self.getBackground, self.setBackground)
|
||||
return self
|
||||
end,
|
||||
|
||||
doneHandler = function(self, timerId, ...)
|
||||
for k,v in pairs(activeAnimations)do
|
||||
if(v.timerId==timerId)then
|
||||
activeAnimations[k] = nil
|
||||
self:sendEvent("animation_done", self, "animation_done", k)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
onAnimationDone = function(self, ...)
|
||||
for _,v in pairs(table.pack(...))do
|
||||
if(type(v)=="function")then
|
||||
self:registerEvent("animation_done", v)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, timerId, ...)
|
||||
base.eventHandler(self, event, timerId, ...)
|
||||
if(event=="timer")then
|
||||
local animation = getAnimation(self, timerId)
|
||||
if(animation~=nil)then
|
||||
if(animation.progress<animation.duration)then
|
||||
animation.call()
|
||||
animation.progress = animation.progress+0.05
|
||||
animation.timerId=os.startTimer(0.05)
|
||||
else
|
||||
animation.finished()
|
||||
self:doneHandler(timerId)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
return object
|
||||
end
|
||||
}
|
10
lib/basalt/plugins/basaltAdditions.lua
Normal file
10
lib/basalt/plugins/basaltAdditions.lua
Normal file
|
@ -0,0 +1,10 @@
|
|||
return {
|
||||
basalt = function()
|
||||
return {
|
||||
cool = function()
|
||||
print("ello")
|
||||
sleep(2)
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
220
lib/basalt/plugins/bigfonts.lua
Normal file
220
lib/basalt/plugins/bigfonts.lua
Normal file
File diff suppressed because one or more lines are too long
87
lib/basalt/plugins/border.lua
Normal file
87
lib/basalt/plugins/border.lua
Normal file
|
@ -0,0 +1,87 @@
|
|||
local XMLParser = require("xmlParser")
|
||||
|
||||
return {
|
||||
VisualObject = function(base)
|
||||
local inline = true
|
||||
local borderColors = {top = false, bottom = false, left = false, right = false}
|
||||
|
||||
local object = {
|
||||
setBorder = function(self, ...)
|
||||
local t = {...}
|
||||
if(t~=nil)then
|
||||
for k,v in pairs(t)do
|
||||
if(v=="left")or(#t==1)then
|
||||
borderColors["left"] = t[1]
|
||||
end
|
||||
if(v=="top")or(#t==1)then
|
||||
borderColors["top"] = t[1]
|
||||
end
|
||||
if(v=="right")or(#t==1)then
|
||||
borderColors["right"] = t[1]
|
||||
end
|
||||
if(v=="bottom")or(#t==1)then
|
||||
borderColors["bottom"] = t[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("border", function()
|
||||
local x, y = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local bgCol = self:getBackground()
|
||||
if(inline)then
|
||||
if(borderColors["left"]~=false)then
|
||||
self:addTextBox(1, 1, 1, h, "\149")
|
||||
if(bgCol~=false)then self:addBackgroundBox(1, 1, 1, h, bgCol) end
|
||||
self:addForegroundBox(1, 1, 1, h, borderColors["left"])
|
||||
end
|
||||
|
||||
if(borderColors["top"]~=false)then
|
||||
self:addTextBox(1, 1, w, 1, "\131")
|
||||
if(bgCol~=false)then self:addBackgroundBox(1, 1, w, 1, bgCol) end
|
||||
self:addForegroundBox(1, 1, w, 1, borderColors["top"])
|
||||
end
|
||||
|
||||
if(borderColors["left"]~=false)and(borderColors["top"]~=false)then
|
||||
self:addTextBox(1, 1, 1, 1, "\151")
|
||||
if(bgCol~=false)then self:addBackgroundBox(1, 1, 1, 1, bgCol) end
|
||||
self:addForegroundBox(1, 1, 1, 1, borderColors["left"])
|
||||
end
|
||||
if(borderColors["right"]~=false)then
|
||||
self:addTextBox(w, 1, 1, h, "\149")
|
||||
if(bgCol~=false)then self:addForegroundBox(w, 1, 1, h, bgCol) end
|
||||
self:addBackgroundBox(w, 1, 1, h, borderColors["right"])
|
||||
end
|
||||
if(borderColors["bottom"]~=false)then
|
||||
self:addTextBox(1, h, w, 1, "\143")
|
||||
if(bgCol~=false)then self:addForegroundBox(1, h, w, 1, bgCol) end
|
||||
self:addBackgroundBox(1, h, w, 1, borderColors["bottom"])
|
||||
end
|
||||
if(borderColors["top"]~=false)and(borderColors["right"]~=false)then
|
||||
self:addTextBox(w, 1, 1, 1, "\148")
|
||||
if(bgCol~=false)then self:addForegroundBox(w, 1, 1, 1, bgCol) end
|
||||
self:addBackgroundBox(w, 1, 1, 1, borderColors["right"])
|
||||
end
|
||||
if(borderColors["right"]~=false)and(borderColors["bottom"]~=false)then
|
||||
self:addTextBox(w, h, 1, 1, "\133")
|
||||
if(bgCol~=false)then self:addForegroundBox(w, h, 1, 1, bgCol) end
|
||||
self:addBackgroundBox(w, h, 1, 1, borderColors["right"])
|
||||
end
|
||||
if(borderColors["bottom"]~=false)and(borderColors["left"]~=false)then
|
||||
self:addTextBox(1, h, 1, 1, "\138")
|
||||
if(bgCol~=false)then self:addForegroundBox(0, h, 1, 1, bgCol) end
|
||||
self:addBackgroundBox(1, h, 1, 1, borderColors["left"])
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
}
|
||||
|
||||
return object
|
||||
end
|
||||
}
|
97
lib/basalt/plugins/debug.lua
Normal file
97
lib/basalt/plugins/debug.lua
Normal file
|
@ -0,0 +1,97 @@
|
|||
local utils = require("utils")
|
||||
local wrapText = utils.wrapText
|
||||
|
||||
return {
|
||||
basalt = function(basalt)
|
||||
local mainFrame = basalt.getMainFrame()
|
||||
local debugFrame
|
||||
local debugList
|
||||
local debugLabel
|
||||
local debugExitButton
|
||||
|
||||
local function createDebuggingFrame()
|
||||
local minW = 16
|
||||
local minH = 6
|
||||
local maxW = 99
|
||||
local maxH = 99
|
||||
local w, h = mainFrame:getSize()
|
||||
debugFrame = mainFrame:addMovableFrame("basaltDebuggingFrame"):setSize(w-20, h-10):setBackground(colors.gray):setForeground(colors.white):setZIndex(100):hide()
|
||||
debugFrame:addPane():setSize("parent.w", 1):setPosition(1, 1):setBackground(colors.black):setForeground(colors.white)
|
||||
debugFrame:setPosition(-w, h/2-debugFrame:getHeight()/2):setBorder(colors.black)
|
||||
local resizeButton = debugFrame:addButton()
|
||||
:setPosition("parent.w", "parent.h")
|
||||
:setSize(1, 1)
|
||||
:setText("\133")
|
||||
:setForeground(colors.gray)
|
||||
:setBackground(colors.black)
|
||||
:onClick(function() end)
|
||||
:onDrag(function(self, event, btn, xOffset, yOffset)
|
||||
local w, h = debugFrame:getSize()
|
||||
local wOff, hOff = w, h
|
||||
if(w+xOffset-1>=minW)and(w+xOffset-1<=maxW)then
|
||||
wOff = w+xOffset-1
|
||||
end
|
||||
if(h+yOffset-1>=minH)and(h+yOffset-1<=maxH)then
|
||||
hOff = h+yOffset-1
|
||||
end
|
||||
debugFrame:setSize(wOff, hOff)
|
||||
end)
|
||||
|
||||
debugExitButton = debugFrame:addButton():setText("Close"):setPosition("parent.w - 6", 1):setSize(7, 1):setBackground(colors.red):setForeground(colors.white):onClick(function()
|
||||
debugFrame:animatePosition(-w, h/2-debugFrame:getHeight()/2, 0.5)
|
||||
end)
|
||||
debugList = debugFrame:addList()
|
||||
:setSize("parent.w - 2", "parent.h - 3")
|
||||
:setPosition(2, 3)
|
||||
:setBackground(colors.gray)
|
||||
:setForeground(colors.white)
|
||||
:setSelectionColor(colors.gray, colors.white)
|
||||
if(debugLabel==nil)then
|
||||
debugLabel = mainFrame:addLabel()
|
||||
:setPosition(1, "parent.h")
|
||||
:setBackground(colors.black)
|
||||
:setForeground(colors.white)
|
||||
:setZIndex(100)
|
||||
:onClick(function()
|
||||
debugFrame:show()
|
||||
debugFrame:animatePosition(w/2-debugFrame:getWidth()/2, h/2-debugFrame:getHeight()/2, 0.5)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
debug = function(...)
|
||||
local args = { ... }
|
||||
if(mainFrame==nil)then
|
||||
mainFrame = basalt.getMainFrame()
|
||||
if(mainFrame~=nil)then
|
||||
createDebuggingFrame()
|
||||
else
|
||||
print(...) return
|
||||
end
|
||||
end
|
||||
if (mainFrame:getName() ~= "basaltDebuggingFrame") then
|
||||
if (mainFrame ~= debugFrame) then
|
||||
debugLabel:setParent(mainFrame)
|
||||
end
|
||||
end
|
||||
local str = ""
|
||||
for key, value in pairs(args) do
|
||||
str = str .. tostring(value) .. (#args ~= key and ", " or "")
|
||||
end
|
||||
debugLabel:setText("[Debug] " .. str)
|
||||
for k,v in pairs(wrapText(str, debugList:getWidth()))do
|
||||
debugList:addItem(v)
|
||||
end
|
||||
if (debugList:getItemCount() > 50) then
|
||||
debugList:removeItem(1)
|
||||
end
|
||||
debugList:setValue(debugList:getItem(debugList:getItemCount()))
|
||||
if(debugList.getItemCount() > debugList:getHeight())then
|
||||
debugList:setOffset(debugList:getItemCount() - debugList:getHeight())
|
||||
end
|
||||
debugLabel:show()
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
124
lib/basalt/plugins/dynamicValues.lua
Normal file
124
lib/basalt/plugins/dynamicValues.lua
Normal file
|
@ -0,0 +1,124 @@
|
|||
local utils = require("utils")
|
||||
local count = utils.tableCount
|
||||
|
||||
return {
|
||||
VisualObject = function(base, basalt)
|
||||
local dynObjects = {}
|
||||
local curProperties = {}
|
||||
local properties = {x="getX", y="getY", w="getWidth", h="getHeight"}
|
||||
|
||||
local function stringToNumber(str)
|
||||
local ok, result = pcall(load("return " .. str, "", nil, {math=math}))
|
||||
if not(ok)then error(str.." - is not a valid dynamic value string") end
|
||||
return result
|
||||
end
|
||||
|
||||
local function createDynamicValue(self, key, val)
|
||||
local objectGroup = {}
|
||||
local properties = properties
|
||||
for a,b in pairs(properties)do
|
||||
for v in val:gmatch("%a+%."..a)do
|
||||
local name = v:gsub("%."..a, "")
|
||||
if(name~="self")and(name~="parent")then
|
||||
table.insert(objectGroup, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local parent = self:getParent()
|
||||
local objects = {}
|
||||
for k,v in pairs(objectGroup)do
|
||||
objects[v] = parent:getChild(v)
|
||||
if(objects[v]==nil)then
|
||||
error("Dynamic Values - unable to find object: "..v)
|
||||
end
|
||||
end
|
||||
objects["self"] = self
|
||||
objects["parent"] = parent
|
||||
|
||||
dynObjects[key] = function()
|
||||
local mainVal = val
|
||||
for a,b in pairs(properties)do
|
||||
for v in val:gmatch("%w+%."..a) do
|
||||
local obj = objects[v:gsub("%."..a, "")]
|
||||
if(obj~=nil)then
|
||||
mainVal = mainVal:gsub(v, obj[b](obj))
|
||||
else
|
||||
error("Dynamic Values - unable to find object: "..v)
|
||||
end
|
||||
end
|
||||
end
|
||||
curProperties[key] = math.floor(stringToNumber(mainVal)+0.5)
|
||||
end
|
||||
dynObjects[key]()
|
||||
end
|
||||
|
||||
local function updatePositions(self)
|
||||
if(count(dynObjects)>0)then
|
||||
for k,v in pairs(dynObjects)do
|
||||
v()
|
||||
end
|
||||
local properties = {x="getX", y="getY", w="getWidth", h="getHeight"}
|
||||
for k,v in pairs(properties)do
|
||||
if(dynObjects[k]~=nil)then
|
||||
if(curProperties[k]~=self[v](self))then
|
||||
if(k=="x")or(k=="y")then
|
||||
base.setPosition(self, curProperties["x"] or self:getX(), curProperties["y"] or self:getY())
|
||||
end
|
||||
if(k=="w")or(k=="h")then
|
||||
base.setSize(self, curProperties["w"] or self:getWidth(), curProperties["h"] or self:getHeight())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local object = {
|
||||
updatePositions = updatePositions,
|
||||
createDynamicValue = createDynamicValue,
|
||||
|
||||
setPosition = function(self, xPos, yPos, rel)
|
||||
curProperties.x = xPos
|
||||
curProperties.y = yPos
|
||||
if(type(xPos)=="string")then
|
||||
createDynamicValue(self, "x", xPos)
|
||||
else
|
||||
dynObjects["x"] = nil
|
||||
end
|
||||
if(type(yPos)=="string")then
|
||||
createDynamicValue(self, "y", yPos)
|
||||
else
|
||||
dynObjects["y"] = nil
|
||||
end
|
||||
base.setPosition(self, curProperties.x, curProperties.y, rel)
|
||||
return self
|
||||
end,
|
||||
|
||||
setSize = function(self, w, h, rel)
|
||||
curProperties.w = w
|
||||
curProperties.h = h
|
||||
if(type(w)=="string")then
|
||||
createDynamicValue(self, "w", w)
|
||||
else
|
||||
dynObjects["w"] = nil
|
||||
end
|
||||
if(type(h)=="string")then
|
||||
createDynamicValue(self, "h", h)
|
||||
else
|
||||
dynObjects["h"] = nil
|
||||
end
|
||||
base.setSize(self, curProperties.w, curProperties.h, rel)
|
||||
return self
|
||||
end,
|
||||
|
||||
customEventHandler = function(self, event, ...)
|
||||
base.customEventHandler(self, event, ...)
|
||||
if(event=="basalt_FrameReposition")or(event=="basalt_FrameResize")then
|
||||
updatePositions(self)
|
||||
end
|
||||
end,
|
||||
}
|
||||
return object
|
||||
end
|
||||
}
|
221
lib/basalt/plugins/pixelbox.lua
Normal file
221
lib/basalt/plugins/pixelbox.lua
Normal file
|
@ -0,0 +1,221 @@
|
|||
-- Most of this is made by Dev9551, you can find his awesome work here: https://github.com/9551-Dev/apis/blob/main/pixelbox_lite.lua
|
||||
-- Slighly modified by NyoriE to work with Basalt
|
||||
|
||||
--[[
|
||||
The MIT License (MIT)
|
||||
Copyright © 2022 Oliver Caha (9551Dev)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ?Software?), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
]]
|
||||
local t_sort,t_cat,s_char = table.sort,table.concat,string.char
|
||||
local function sort(a,b) return a[2] > b[2] end
|
||||
|
||||
local distances = {
|
||||
{5,256,16,8,64,32},
|
||||
{4,16,16384,256,128},
|
||||
[4] = {4,64,1024,256,128},
|
||||
[8] = {4,512,2048,256,1},
|
||||
[16] = {4,2,16384,256,1},
|
||||
[32] = {4,8192,4096,256,1},
|
||||
[64] = {4,4,1024,256,1},
|
||||
[128] = {6,32768,256,1024,2048,4096,16384},
|
||||
[256] = {6,1,128,2,512,4,8192},
|
||||
[512] = {4,8,2048,256,128},
|
||||
[1024] = {4,4,64,128,32768},
|
||||
[2048] = {4,512,8,128,32768},
|
||||
[4096] = {4,8192,32,128,32768},
|
||||
[8192] = {3,32,4096,256128},
|
||||
[16384] = {4,2,16,128,32768},
|
||||
[32768] = {5,128,1024,2048,4096,16384}
|
||||
}
|
||||
|
||||
local to_colors = {}
|
||||
for i = 0, 15 do
|
||||
to_colors[("%x"):format(i)] = 2^i
|
||||
end
|
||||
|
||||
local to_blit = {}
|
||||
for i = 0, 15 do
|
||||
to_blit[2^i] = ("%x"):format(i)
|
||||
end
|
||||
|
||||
local function pixelbox(colTable, defaultCol)
|
||||
defaultCol = defaultCol or "f"
|
||||
local width, height = #colTable[1], #colTable
|
||||
local cache = {}
|
||||
local canv = {}
|
||||
local cached = false
|
||||
|
||||
local function generateCanvas()
|
||||
for y = 1, height * 3 do
|
||||
for x = 1, width * 2 do
|
||||
if not canv[y] then canv[y] = {} end
|
||||
canv[y][x] = defaultCol
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs(colTable) do
|
||||
for x = 1, #v do
|
||||
local col = v:sub(x, x)
|
||||
canv[k][x] = to_colors[col]
|
||||
end
|
||||
end
|
||||
end
|
||||
generateCanvas()
|
||||
|
||||
local function setSize(w,h)
|
||||
width, height = w, h
|
||||
canv = {}
|
||||
cached = false
|
||||
generateCanvas()
|
||||
end
|
||||
|
||||
|
||||
local function generateChar(a,b,c,d,e,f)
|
||||
local arr = {a,b,c,d,e,f}
|
||||
local c_types = {}
|
||||
local sortable = {}
|
||||
local ind = 0
|
||||
for i=1,6 do
|
||||
local c = arr[i]
|
||||
if not c_types[c] then
|
||||
ind = ind + 1
|
||||
c_types[c] = {0,ind}
|
||||
end
|
||||
|
||||
local t = c_types[c]
|
||||
local t1 = t[1] + 1
|
||||
|
||||
t[1] = t1
|
||||
sortable[t[2]] = {c,t1}
|
||||
end
|
||||
local n = #sortable
|
||||
while n > 2 do
|
||||
t_sort(sortable,sort)
|
||||
local bit6 = distances[sortable[n][1]]
|
||||
local index,run = 1,false
|
||||
local nm1 = n - 1
|
||||
for i=2,bit6[1] do
|
||||
if run then break end
|
||||
local tab = bit6[i]
|
||||
for j=1,nm1 do
|
||||
if sortable[j][1] == tab then
|
||||
index = j
|
||||
run = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local from,to = sortable[n][1],sortable[index][1]
|
||||
for i=1,6 do
|
||||
if arr[i] == from then
|
||||
arr[i] = to
|
||||
local sindex = sortable[index]
|
||||
sindex[2] = sindex[2] + 1
|
||||
end
|
||||
end
|
||||
|
||||
sortable[n] = nil
|
||||
n = n - 1
|
||||
end
|
||||
|
||||
local n = 128
|
||||
local a6 = arr[6]
|
||||
|
||||
if arr[1] ~= a6 then n = n + 1 end
|
||||
if arr[2] ~= a6 then n = n + 2 end
|
||||
if arr[3] ~= a6 then n = n + 4 end
|
||||
if arr[4] ~= a6 then n = n + 8 end
|
||||
if arr[5] ~= a6 then n = n + 16 end
|
||||
|
||||
if sortable[1][1] == arr[6] then
|
||||
return s_char(n),sortable[2][1],arr[6]
|
||||
else
|
||||
return s_char(n),sortable[1][1],arr[6]
|
||||
end
|
||||
end
|
||||
|
||||
local function convert()
|
||||
local w_double = width * 2
|
||||
|
||||
local sy = 0
|
||||
for y = 1, height * 3, 3 do
|
||||
sy = sy + 1
|
||||
local layer_1 = canv[y]
|
||||
local layer_2 = canv[y + 1]
|
||||
local layer_3 = canv[y + 2]
|
||||
local char_line, fg_line, bg_line = {}, {}, {}
|
||||
local n = 0
|
||||
for x = 1, w_double, 2 do
|
||||
local xp1 = x + 1
|
||||
local b11, b21, b12, b22, b13, b23 = layer_1[x], layer_1[xp1], layer_2[x], layer_2[xp1], layer_3[x], layer_3[xp1]
|
||||
|
||||
local char, fg, bg = " ", 1, b11
|
||||
if not (b21 == b11 and b12 == b11 and b22 == b11 and b13 == b11 and b23 == b11) then
|
||||
char, fg, bg = generateChar(b11, b21, b12, b22, b13, b23)
|
||||
end
|
||||
n = n + 1
|
||||
char_line[n] = char
|
||||
fg_line[n] = to_blit[fg]
|
||||
bg_line[n] = to_blit[bg]
|
||||
end
|
||||
|
||||
cache[sy] = {t_cat(char_line), t_cat(fg_line), t_cat(bg_line)}
|
||||
end
|
||||
cached = true
|
||||
end
|
||||
|
||||
return {
|
||||
convert = convert,
|
||||
generateCanvas = generateCanvas,
|
||||
setSize = setSize,
|
||||
getSize = function()
|
||||
return width, height
|
||||
end,
|
||||
set = function(colTab, defCol)
|
||||
colTable = colTab
|
||||
defaultCol = defCol or defaultCol
|
||||
canv = {}
|
||||
cached = false
|
||||
generateCanvas()
|
||||
end,
|
||||
get = function(y)
|
||||
if not cached then convert() end
|
||||
return y~= nil and cache[y] or cache
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
Image = function(base, basalt)
|
||||
return {
|
||||
shrink = function(self)
|
||||
local bimg = self:getImageFrame(1)
|
||||
local img = {}
|
||||
for k,v in pairs(bimg)do
|
||||
if(type(k)=="number")then
|
||||
table.insert(img,v[3])
|
||||
end
|
||||
end
|
||||
local shrinkedImg = pixelbox(img, self:getBackground()).get()
|
||||
self:setImage(shrinkedImg)
|
||||
return self
|
||||
end,
|
||||
|
||||
getShrinkedImage = function(self)
|
||||
local bimg = self:getImageFrame(1)
|
||||
local img = {}
|
||||
for k,v in pairs(bimg)do
|
||||
if(type(k)=="number")then
|
||||
table.insert(img, v[3])
|
||||
end
|
||||
end
|
||||
return pixelbox(img, self:getBackground()).get()
|
||||
end,
|
||||
}
|
||||
end,
|
||||
}
|
203
lib/basalt/plugins/reactive.lua
Normal file
203
lib/basalt/plugins/reactive.lua
Normal file
|
@ -0,0 +1,203 @@
|
|||
local XMLParser = require("xmlParser")
|
||||
|
||||
local Reactive = {}
|
||||
|
||||
Reactive.currentEffect = nil
|
||||
|
||||
Reactive.observable = function(initialValue)
|
||||
local value = initialValue
|
||||
local observerEffects = {}
|
||||
local get = function()
|
||||
if (Reactive.currentEffect ~= nil) then
|
||||
table.insert(observerEffects, Reactive.currentEffect)
|
||||
table.insert(Reactive.currentEffect.dependencies, observerEffects)
|
||||
end
|
||||
return value
|
||||
end
|
||||
local set = function(newValue)
|
||||
value = newValue
|
||||
local observerEffectsCopy = {}
|
||||
for index, effect in ipairs(observerEffects) do
|
||||
observerEffectsCopy[index] = effect
|
||||
end
|
||||
for _, effect in ipairs(observerEffectsCopy) do
|
||||
effect.execute()
|
||||
end
|
||||
end
|
||||
return get, set
|
||||
end
|
||||
|
||||
Reactive.untracked = function(getter)
|
||||
local parentEffect = Reactive.currentEffect
|
||||
Reactive.currentEffect = nil
|
||||
local value = getter()
|
||||
Reactive.currentEffect = parentEffect
|
||||
return value
|
||||
end
|
||||
|
||||
Reactive.effect = function(effectFn)
|
||||
local effect = {dependencies = {}}
|
||||
local execute = function()
|
||||
Reactive.clearEffectDependencies(effect)
|
||||
local parentEffect = Reactive.currentEffect
|
||||
Reactive.currentEffect = effect
|
||||
effectFn()
|
||||
Reactive.currentEffect = parentEffect
|
||||
end
|
||||
effect.execute = execute
|
||||
effect.execute()
|
||||
end
|
||||
|
||||
Reactive.derived = function(computeFn)
|
||||
local getValue, setValue = Reactive.observable();
|
||||
Reactive.effect(function()
|
||||
setValue(computeFn())
|
||||
end)
|
||||
return getValue;
|
||||
end
|
||||
|
||||
Reactive.clearEffectDependencies = function(effect)
|
||||
for _, dependency in ipairs(effect.dependencies) do
|
||||
for index, backlink in ipairs(dependency) do
|
||||
if (backlink == effect) then
|
||||
table.remove(dependency, index)
|
||||
end
|
||||
end
|
||||
end
|
||||
effect.dependencies = {};
|
||||
end
|
||||
|
||||
local Layout = {
|
||||
fromXML = function(text)
|
||||
local nodes = XMLParser.parseText(text)
|
||||
local script = nil
|
||||
for index, node in ipairs(nodes) do
|
||||
if (node.tag == "script") then
|
||||
script = node.value
|
||||
table.remove(nodes, index)
|
||||
break
|
||||
end
|
||||
end
|
||||
return {
|
||||
nodes = nodes,
|
||||
script = script
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
local executeScript = function(script, env)
|
||||
return load(script, nil, "t", env)()
|
||||
end
|
||||
|
||||
local registerFunctionEvent = function(object, event, script, env)
|
||||
event(object, function(...)
|
||||
local success, msg = pcall(load(script, nil, "t", env))
|
||||
if not success then
|
||||
error("XML Error: "..msg)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return {
|
||||
basalt = function(basalt)
|
||||
local createObjectsFromXMLNode = function(node, env)
|
||||
local layout = env[node.tag]
|
||||
if (layout ~= nil) then
|
||||
local props = {}
|
||||
for prop, expression in pairs(node.attributes) do
|
||||
props[prop] = load("return " .. expression, nil, "t", env)
|
||||
end
|
||||
return basalt.createObjectsFromLayout(layout, props)
|
||||
end
|
||||
|
||||
local objectName = node.tag:gsub("^%l", string.upper)
|
||||
local object = basalt:createObject(objectName, node.attributes["id"])
|
||||
for attribute, expression in pairs(node.attributes) do
|
||||
if (attribute:sub(1, 2) == "on") then
|
||||
registerFunctionEvent(object, object[attribute], expression .. "()", env)
|
||||
else
|
||||
local update = function()
|
||||
local value = load("return " .. expression, nil, "t", env)()
|
||||
object:setProperty(attribute, value)
|
||||
end
|
||||
basalt.effect(update)
|
||||
end
|
||||
end
|
||||
for _, child in ipairs(node.children) do
|
||||
local childObjects = basalt.createObjectsFromXMLNode(child, env)
|
||||
for _, childObject in ipairs(childObjects) do
|
||||
object:addChild(childObject)
|
||||
end
|
||||
end
|
||||
return {object}
|
||||
end
|
||||
|
||||
local object = {
|
||||
observable = Reactive.observable,
|
||||
untracked = Reactive.untracked,
|
||||
effect = Reactive.effect,
|
||||
derived = Reactive.derived,
|
||||
|
||||
layout = function(path)
|
||||
if (not fs.exists(path)) then
|
||||
error("Can't open file " .. path)
|
||||
end
|
||||
local f = fs.open(path, "r")
|
||||
local text = f.readAll()
|
||||
f.close()
|
||||
return Layout.fromXML(text)
|
||||
end,
|
||||
|
||||
createObjectsFromLayout = function(layout, props)
|
||||
local env = _ENV
|
||||
env.props = {}
|
||||
local updateFns = {}
|
||||
for prop, getFn in pairs(props) do
|
||||
updateFns[prop] = basalt.derived(function()
|
||||
return getFn()
|
||||
end)
|
||||
end
|
||||
setmetatable(env.props, {
|
||||
__index = function(_, k)
|
||||
return updateFns[k]()
|
||||
end
|
||||
})
|
||||
if (layout.script ~= nil) then
|
||||
executeScript(layout.script, env)
|
||||
end
|
||||
local objects = {}
|
||||
for _, node in ipairs(layout.nodes) do
|
||||
local _objects = createObjectsFromXMLNode(node, env)
|
||||
for _, object in ipairs(_objects) do
|
||||
table.insert(objects, object)
|
||||
end
|
||||
end
|
||||
return objects
|
||||
end
|
||||
}
|
||||
return object
|
||||
end,
|
||||
|
||||
Container = function(base, basalt)
|
||||
local object = {
|
||||
loadLayout = function(self, path, props)
|
||||
local wrappedProps = {}
|
||||
if (props == nil) then
|
||||
props = {}
|
||||
end
|
||||
for prop, value in pairs(props) do
|
||||
wrappedProps[prop] = function()
|
||||
return value
|
||||
end
|
||||
end
|
||||
local layout = basalt.layout(path)
|
||||
local objects = basalt.createObjectsFromLayout(layout, wrappedProps)
|
||||
for _, object in ipairs(objects) do
|
||||
self:addChild(object)
|
||||
end
|
||||
return self
|
||||
end
|
||||
}
|
||||
return object
|
||||
end
|
||||
}
|
36
lib/basalt/plugins/shadow.lua
Normal file
36
lib/basalt/plugins/shadow.lua
Normal file
|
@ -0,0 +1,36 @@
|
|||
local XMLParser = require("xmlParser")
|
||||
|
||||
return {
|
||||
VisualObject = function(base)
|
||||
local shadow = false
|
||||
|
||||
local object = {
|
||||
setShadow = function(self, color)
|
||||
shadow = color
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
getShadow = function(self)
|
||||
return shadow
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("shadow", function()
|
||||
if(shadow~=false)then
|
||||
local w,h = self:getSize()
|
||||
if(shadow)then
|
||||
self:addBackgroundBox(w+1, 2, 1, h, shadow)
|
||||
self:addBackgroundBox(2, h+1, w, 1, shadow)
|
||||
self:addForegroundBox(w+1, 2, 1, h, shadow)
|
||||
self:addForegroundBox(2, h+1, w, 1, shadow)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
}
|
||||
|
||||
return object
|
||||
end
|
||||
}
|
115
lib/basalt/plugins/textures.lua
Normal file
115
lib/basalt/plugins/textures.lua
Normal file
|
@ -0,0 +1,115 @@
|
|||
local images = require("images")
|
||||
local utils = require("utils")
|
||||
local XMLParser = require("xmlParser")
|
||||
return {
|
||||
VisualObject = function(base)
|
||||
local textureId, infinitePlay = 1, true
|
||||
local bimg, texture, textureTimerId
|
||||
local textureMode = "default"
|
||||
|
||||
local object = {
|
||||
addTexture = function(self, path, animate)
|
||||
bimg = images.loadImageAsBimg(path)
|
||||
texture = bimg[1]
|
||||
if(animate)then
|
||||
if(bimg.animated)then
|
||||
self:listenEvent("other_event")
|
||||
local t = bimg[textureId].duration or bimg.secondsPerFrame or 0.2
|
||||
textureTimerId = os.startTimer(t)
|
||||
end
|
||||
end
|
||||
self:setBackground(false)
|
||||
self:setForeground(false)
|
||||
self:setDrawState("texture-base", true)
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setTextureMode = function(self, mode)
|
||||
textureMode = mode or textureMode
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
|
||||
setInfinitePlay = function(self, state)
|
||||
infinitePlay = state
|
||||
return self
|
||||
end,
|
||||
|
||||
eventHandler = function(self, event, timerId, ...)
|
||||
base.eventHandler(self, event, timerId, ...)
|
||||
if(event=="timer")then
|
||||
if(timerId == textureTimerId)then
|
||||
if(bimg[textureId+1]~=nil)then
|
||||
textureId = textureId + 1
|
||||
texture = bimg[textureId]
|
||||
local t = bimg[textureId].duration or bimg.secondsPerFrame or 0.2
|
||||
textureTimerId = os.startTimer(t)
|
||||
self:updateDraw()
|
||||
else
|
||||
if(infinitePlay)then
|
||||
textureId = 1
|
||||
texture = bimg[1]
|
||||
local t = bimg[textureId].duration or bimg.secondsPerFrame or 0.2
|
||||
textureTimerId = os.startTimer(t)
|
||||
self:updateDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
draw = function(self)
|
||||
base.draw(self)
|
||||
self:addDraw("texture-base", function()
|
||||
local obj = self:getParent() or self
|
||||
local x, y = self:getPosition()
|
||||
local w,h = self:getSize()
|
||||
local wP,hP = obj:getSize()
|
||||
|
||||
local textureWidth = bimg.width or #bimg[textureId][1][1]
|
||||
local textureHeight = bimg.height or #bimg[textureId]
|
||||
|
||||
local startX, startY = 0, 0
|
||||
|
||||
if (textureMode == "center") then
|
||||
startX = x + math.floor((w - textureWidth) / 2 + 0.5) - 1
|
||||
startY = y + math.floor((h - textureHeight) / 2 + 0.5) - 1
|
||||
elseif (textureMode == "default") then
|
||||
startX, startY = x, y
|
||||
elseif (textureMode == "right") then
|
||||
startX, startY = x + w - textureWidth, y + h - textureHeight
|
||||
end
|
||||
|
||||
local textureX = x - startX
|
||||
local textureY = y - startY
|
||||
|
||||
if startX < x then
|
||||
startX = x
|
||||
textureWidth = textureWidth - textureX
|
||||
end
|
||||
if startY < y then
|
||||
startY = y
|
||||
textureHeight = textureHeight - textureY
|
||||
end
|
||||
if startX + textureWidth > x + w then
|
||||
textureWidth = (x + w) - startX
|
||||
end
|
||||
if startY + textureHeight > y + h then
|
||||
textureHeight = (y + h) - startY
|
||||
end
|
||||
|
||||
for k = 1, textureHeight do
|
||||
if(texture[k+textureY]~=nil)then
|
||||
local t, f, b = table.unpack(texture[k+textureY])
|
||||
self:addBlit(1, k, t:sub(textureX, textureX + textureWidth), f:sub(textureX, textureX + textureWidth), b:sub(textureX, textureX + textureWidth))
|
||||
end
|
||||
end
|
||||
end, 1)
|
||||
self:setDrawState("texture-base", false)
|
||||
end
|
||||
}
|
||||
|
||||
return object
|
||||
end
|
||||
}
|
99
lib/basalt/plugins/themes.lua
Normal file
99
lib/basalt/plugins/themes.lua
Normal file
|
@ -0,0 +1,99 @@
|
|||
local baseTheme = { -- The default main theme for basalt!
|
||||
BaseFrameBG = colors.lightGray,
|
||||
BaseFrameText = colors.black,
|
||||
FrameBG = colors.gray,
|
||||
FrameText = colors.black,
|
||||
ButtonBG = colors.gray,
|
||||
ButtonText = colors.black,
|
||||
CheckboxBG = colors.lightGray,
|
||||
CheckboxText = colors.black,
|
||||
InputBG = colors.black,
|
||||
InputText = colors.lightGray,
|
||||
TextfieldBG = colors.black,
|
||||
TextfieldText = colors.white,
|
||||
ListBG = colors.gray,
|
||||
ListText = colors.black,
|
||||
MenubarBG = colors.gray,
|
||||
MenubarText = colors.black,
|
||||
DropdownBG = colors.gray,
|
||||
DropdownText = colors.black,
|
||||
RadioBG = colors.gray,
|
||||
RadioText = colors.black,
|
||||
SelectionBG = colors.black,
|
||||
SelectionText = colors.lightGray,
|
||||
GraphicBG = colors.black,
|
||||
ImageBG = colors.black,
|
||||
PaneBG = colors.black,
|
||||
ProgramBG = colors.black,
|
||||
ProgressbarBG = colors.gray,
|
||||
ProgressbarText = colors.black,
|
||||
ProgressbarActiveBG = colors.black,
|
||||
ScrollbarBG = colors.lightGray,
|
||||
ScrollbarText = colors.gray,
|
||||
ScrollbarSymbolColor = colors.black,
|
||||
SliderBG = false,
|
||||
SliderText = colors.gray,
|
||||
SliderSymbolColor = colors.black,
|
||||
SwitchBG = colors.lightGray,
|
||||
SwitchText = colors.gray,
|
||||
LabelBG = false,
|
||||
LabelText = colors.black,
|
||||
GraphBG = colors.gray,
|
||||
GraphText = colors.black
|
||||
}
|
||||
|
||||
local plugin = {
|
||||
Container = function(base, name, basalt)
|
||||
local theme = {}
|
||||
|
||||
local object = {
|
||||
getTheme = function(self, name)
|
||||
local parent = self:getParent()
|
||||
return theme[name] or (parent~=nil and parent:getTheme(name) or baseTheme[name])
|
||||
end,
|
||||
setTheme = function(self, _theme, col)
|
||||
if(type(_theme)=="table")then
|
||||
theme = _theme
|
||||
elseif(type(_theme)=="string")then
|
||||
theme[_theme] = col
|
||||
end
|
||||
self:updateDraw()
|
||||
return self
|
||||
end,
|
||||
}
|
||||
return object
|
||||
end,
|
||||
|
||||
basalt = function()
|
||||
return {
|
||||
getTheme = function(name)
|
||||
return baseTheme[name]
|
||||
end,
|
||||
setTheme = function(_theme, col)
|
||||
if(type(_theme)=="table")then
|
||||
baseTheme = _theme
|
||||
elseif(type(_theme)=="string")then
|
||||
baseTheme[_theme] = col
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
for k,v in pairs({"BaseFrame", "Frame", "ScrollableFrame", "MovableFrame", "Button", "Checkbox", "Dropdown", "Graph", "Graphic", "Input", "Label", "List", "Menubar", "Pane", "Program", "Progressbar", "Radio", "Scrollbar", "Slider", "Switch", "Textfield"})do
|
||||
plugin[v] = function(base, name, basalt)
|
||||
local object = {
|
||||
init = function(self)
|
||||
if(base.init(self))then
|
||||
local parent = self:getParent() or self
|
||||
self:setBackground(parent:getTheme(v.."BG"))
|
||||
self:setForeground(parent:getTheme(v.."Text"))
|
||||
end
|
||||
end
|
||||
}
|
||||
return object
|
||||
end
|
||||
end
|
||||
|
||||
return plugin
|
48
scripts/gen_version_json.py
Executable file
48
scripts/gen_version_json.py
Executable file
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
BLACKLIST = [
|
||||
".git",
|
||||
".gitignore",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"scripts",
|
||||
"apps"
|
||||
]
|
||||
|
||||
|
||||
def iterate_files(blacklist=None):
|
||||
base_dir = os.getcwd()
|
||||
if blacklist is None:
|
||||
blacklist = set()
|
||||
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
# Skip blacklisted dirs based on name
|
||||
dirs[:] = [d for d in dirs if d not in blacklist]
|
||||
for file in files:
|
||||
if file not in blacklist:
|
||||
abs_path = os.path.join(root, file)
|
||||
rel_path = os.path.relpath(abs_path, base_dir)
|
||||
yield rel_path # truncated to current dir >:3
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} [version]")
|
||||
return
|
||||
version = sys.argv[1]
|
||||
obj = {}
|
||||
obj["version"] = version
|
||||
obj["sys_files"] = {}
|
||||
for file in iterate_files(BLACKLIST):
|
||||
obj["sys_files"][f"/{
|
||||
file}"] = f"https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/{file}"
|
||||
pretty_json = json.dumps(obj, indent=2)
|
||||
print(pretty_json)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
446
slabos.lua
446
slabos.lua
|
@ -1,289 +1,279 @@
|
|||
local basalt = require("basalt")
|
||||
local basalt = require("/lib/basalt")
|
||||
|
||||
local main = basalt.getMainFrame()
|
||||
|
||||
local FRAME_WIDTH = 26
|
||||
local FRAME_HEIGHT = 19
|
||||
local CONTROL_BUTTON_Y = 20
|
||||
local CONTROL_BUTTON_Y = 20
|
||||
|
||||
local homescreen = main:addFrame()
|
||||
:setPosition(1, 1)
|
||||
:setSize(FRAME_WIDTH, FRAME_HEIGHT)
|
||||
:setBackground(colours.blue)
|
||||
:setVisible(true)
|
||||
local homescreen =
|
||||
main:addFrame():setPosition(1, 1):setSize(FRAME_WIDTH, FRAME_HEIGHT):setBackground(colours.blue):setVisible(true)
|
||||
|
||||
local active_app_frames = {}
|
||||
local current_active_frame = homescreen
|
||||
local current_active_frame = homescreen
|
||||
|
||||
local app_switcher_frame = main:addFrame()
|
||||
:setPosition(1, 1)
|
||||
:setSize(FRAME_WIDTH, FRAME_HEIGHT)
|
||||
:setBackground(colours.brown)
|
||||
:setVisible(false)
|
||||
local app_switcher_frame =
|
||||
main:addFrame():setPosition(1, 1):setSize(FRAME_WIDTH, FRAME_HEIGHT):setBackground(colours.brown):setVisible(false)
|
||||
|
||||
function show_payment_confirmation(amount, purpose, callback)
|
||||
local payment_confirmation_frame =
|
||||
main:addFrame():setPosition(1, 1):setSize(FRAME_WIDTH, FRAME_HEIGHT / 3):setBackground(colours.black)
|
||||
payment_confirmation_frame.z = 99
|
||||
payment_confirmation_frame.focused = true
|
||||
|
||||
local payment_confirmation_frame = main:addFrame()
|
||||
:setPosition(1, 1)
|
||||
:setSize(FRAME_WIDTH, FRAME_HEIGHT / 3)
|
||||
:setBackground(colours.black)
|
||||
payment_confirmation_frame.z = 99
|
||||
payment_confirmation_frame.focused = true
|
||||
payment_confirmation_frame:addLabel():setText("Confirm Payment"):setForeground(colours.white)
|
||||
|
||||
payment_confirmation_frame:addLabel()
|
||||
:setText("Confirm Payment")
|
||||
:setForeground(colours.white)
|
||||
payment_confirmation_frame
|
||||
:addLabel()
|
||||
:setPosition(1, 3)
|
||||
:setText(amount .. "G -> " .. purpose)
|
||||
:setForeground(colours.white)
|
||||
|
||||
payment_confirmation_frame:addLabel()
|
||||
:setPosition(1, 3)
|
||||
:setText(amount .. "G -> " .. purpose)
|
||||
:setForeground(colours.white)
|
||||
payment_confirmation_frame
|
||||
:addButton()
|
||||
:setText("Confirm")
|
||||
:setPosition(1, 6)
|
||||
:setSize(13, 1)
|
||||
:setBackground(colours.green)
|
||||
:onClick(function()
|
||||
if callback then
|
||||
callback(true)
|
||||
end
|
||||
payment_confirmation_frame:destroy()
|
||||
end)
|
||||
|
||||
payment_confirmation_frame:addButton()
|
||||
:setText("Confirm")
|
||||
:setPosition(1, 6)
|
||||
:setSize(13, 1)
|
||||
:setBackground(colours.green)
|
||||
payment_confirmation_frame
|
||||
:addButton()
|
||||
:setText("Deny")
|
||||
:setPosition(14, 6)
|
||||
:setSize(13, 1)
|
||||
:setBackground(colours.red)
|
||||
:onClick(function()
|
||||
if callback then
|
||||
callback(false)
|
||||
end
|
||||
|
||||
:onClick(function()
|
||||
if callback then
|
||||
callback(true)
|
||||
end
|
||||
payment_confirmation_frame:destroy()
|
||||
end)
|
||||
|
||||
payment_confirmation_frame:addButton()
|
||||
:setText("Deny")
|
||||
:setPosition(14, 6)
|
||||
:setSize(13, 1)
|
||||
:setBackground(colours.red)
|
||||
|
||||
:onClick(function()
|
||||
|
||||
if callback then
|
||||
callback(false)
|
||||
end
|
||||
|
||||
payment_confirmation_frame:destroy()
|
||||
end)
|
||||
sleep(0.01)
|
||||
payment_confirmation_frame:destroy()
|
||||
end)
|
||||
sleep(0.01)
|
||||
end
|
||||
|
||||
local function payment_listener()
|
||||
local modem = peripheral.find("modem")
|
||||
local lchannel = tonumber(os.getComputerID() .. 43)
|
||||
modem.open(lchannel)
|
||||
while true do
|
||||
local modem = peripheral.find("modem")
|
||||
local lchannel = tonumber(os.getComputerID() .. 43)
|
||||
modem.open(lchannel)
|
||||
while true do
|
||||
local event, side, channel, replyChannel, message, distance
|
||||
repeat
|
||||
event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
until channel == lchannel
|
||||
|
||||
local event, side, channel, replyChannel, message, distance
|
||||
repeat
|
||||
event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
until channel == lchannel
|
||||
local payload = textutils.unserialiseJSON(message)
|
||||
if payload.type == "confirmTransaction" then
|
||||
show_payment_confirmation(payload.amount, payload.vendor, function(bruh)
|
||||
if bruh then
|
||||
local confirmation_payload = {
|
||||
type = "transactionConfirmation",
|
||||
transaction_id = payload.transaction_id,
|
||||
confirmed = true,
|
||||
}
|
||||
|
||||
local payload = textutils.unserialiseJSON(message)
|
||||
if payload.type == "confirmTransaction" then
|
||||
show_payment_confirmation(payload.amount, payload.vendor,function(bruh)
|
||||
if bruh then
|
||||
|
||||
local confirmation_payload = {
|
||||
type = "transactionConfirmation",
|
||||
transaction_id = payload.transaction_id,
|
||||
confirmed = true
|
||||
}
|
||||
|
||||
modem.transmit(replyChannel,channel,textutils.serialiseJSON(confirmation_payload))
|
||||
|
||||
else
|
||||
|
||||
local confirmation_payload = {
|
||||
type = "transactionConfirmation",
|
||||
transaction_id = payload.transaction_id,
|
||||
confirmed = false
|
||||
}
|
||||
|
||||
modem.transmit(replyChannel,channel,textutils.serialiseJSON(confirmation_payload))
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
modem.transmit(replyChannel, channel, textutils.serialiseJSON(confirmation_payload))
|
||||
else
|
||||
local confirmation_payload = {
|
||||
type = "transactionConfirmation",
|
||||
transaction_id = payload.transaction_id,
|
||||
confirmed = false,
|
||||
}
|
||||
|
||||
modem.transmit(replyChannel, channel, textutils.serialiseJSON(confirmation_payload))
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function populate_homescreen_buttons()
|
||||
homescreen:clear()
|
||||
|
||||
homescreen:clear()
|
||||
local button_width = 11
|
||||
local button_height = 3
|
||||
local button_spacing_x = 2
|
||||
local button_spacing_y = 2
|
||||
local current_x = button_spacing_x
|
||||
local current_y = button_spacing_y
|
||||
|
||||
local button_width = 11
|
||||
local button_height = 3
|
||||
local button_spacing_x = 2
|
||||
local button_spacing_y = 2
|
||||
local current_x = button_spacing_x
|
||||
local current_y = button_spacing_y
|
||||
local base_app_files = fs.list("/base_apps/")
|
||||
local app_files = fs.list("/apps/")
|
||||
for i = 1, #base_app_files do
|
||||
table.insert(app_files, base_app_files[i])
|
||||
end
|
||||
|
||||
local app_files = fs.list("/apps/")
|
||||
for i = 1, #app_files do
|
||||
local filename = app_files[i]
|
||||
|
||||
for i = 1, #app_files do
|
||||
local filename = app_files[i]
|
||||
local display_name = filename:gsub(".lua$", "")
|
||||
|
||||
local display_name = filename:gsub(".lua$", "")
|
||||
if current_x + button_width > homescreen:getWidth() then
|
||||
current_x = button_spacing_x
|
||||
current_y = current_y + button_height + button_spacing_y
|
||||
end
|
||||
|
||||
if current_x + button_width > homescreen:getWidth() then
|
||||
current_x = button_spacing_x
|
||||
current_y = current_y + button_height + button_spacing_y
|
||||
end
|
||||
if current_y + button_height > homescreen:getHeight() then
|
||||
break
|
||||
end
|
||||
|
||||
if current_y + button_height > homescreen:getHeight() then
|
||||
break
|
||||
end
|
||||
|
||||
local app_button = homescreen:addButton()
|
||||
:setText(display_name)
|
||||
:setPosition(current_x, current_y)
|
||||
:setSize(button_width, button_height)
|
||||
:setBackground(colours.grey)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
local app_button = homescreen
|
||||
:addButton()
|
||||
:setText(display_name)
|
||||
:setPosition(current_x, current_y)
|
||||
:setSize(button_width, button_height)
|
||||
:setBackground(colours.grey)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
if current_active_frame then
|
||||
current_active_frame:setVisible(false)
|
||||
end
|
||||
|
||||
if current_active_frame then
|
||||
current_active_frame:setVisible(false)
|
||||
end
|
||||
local app_frame = active_app_frames[filename]
|
||||
if not app_frame then
|
||||
app_frame = main:addFrame()
|
||||
:setPosition(1, 1)
|
||||
:setSize(FRAME_WIDTH, FRAME_HEIGHT)
|
||||
:setBackground(colours.green)
|
||||
:setVisible(false)
|
||||
|
||||
local app_frame = active_app_frames[filename]
|
||||
if not app_frame then
|
||||
app_frame:addProgram():setSize(FRAME_WIDTH, FRAME_HEIGHT):execute("/apps/" .. filename)
|
||||
|
||||
app_frame = main:addFrame()
|
||||
:setPosition(1, 1)
|
||||
:setSize(FRAME_WIDTH, FRAME_HEIGHT)
|
||||
:setBackground(colours.green)
|
||||
:setVisible(false)
|
||||
active_app_frames[filename] = app_frame
|
||||
end
|
||||
|
||||
app_frame:addProgram()
|
||||
:setSize(FRAME_WIDTH, FRAME_HEIGHT)
|
||||
:execute("/apps/" .. filename)
|
||||
app_frame:setVisible(true)
|
||||
current_active_frame = app_frame
|
||||
end)
|
||||
|
||||
active_app_frames[filename] = app_frame
|
||||
end
|
||||
|
||||
app_frame:setVisible(true)
|
||||
current_active_frame = app_frame
|
||||
end)
|
||||
|
||||
current_x = current_x + button_width + button_spacing_x
|
||||
end
|
||||
current_x = current_x + button_width + button_spacing_x
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_to_frame(target_frame, frame_name)
|
||||
if current_active_frame then
|
||||
current_active_frame:setVisible(false)
|
||||
end
|
||||
target_frame:setVisible(true)
|
||||
current_active_frame = target_frame
|
||||
if current_active_frame then
|
||||
current_active_frame:setVisible(false)
|
||||
end
|
||||
target_frame:setVisible(true)
|
||||
current_active_frame = target_frame
|
||||
end
|
||||
|
||||
local function populate_app_switcher_ui()
|
||||
app_switcher_frame:clear()
|
||||
app_switcher_frame:clear()
|
||||
|
||||
app_switcher_frame:addLabel()
|
||||
:setText("Active Applications")
|
||||
:setPosition(5, 1)
|
||||
:setSize(FRAME_WIDTH - 2, 1)
|
||||
:setForeground(colours.white)
|
||||
:setBackground(colours.blue)
|
||||
app_switcher_frame
|
||||
:addLabel()
|
||||
:setText("Active Applications")
|
||||
:setPosition(5, 1)
|
||||
:setSize(FRAME_WIDTH - 2, 1)
|
||||
:setForeground(colours.white)
|
||||
:setBackground(colours.blue)
|
||||
|
||||
local current_y = 3
|
||||
local current_y = 3
|
||||
|
||||
app_switcher_frame:addButton()
|
||||
:setText("Home Screen")
|
||||
:setPosition(2, current_y)
|
||||
:setSize(FRAME_WIDTH - 3, 1)
|
||||
:setBackground(homescreen == current_active_frame and colours.lightGrey or colours.grey)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
switch_to_frame(homescreen, "Home Screen")
|
||||
app_switcher_frame:setVisible(false)
|
||||
end)
|
||||
current_y = current_y + 2
|
||||
app_switcher_frame
|
||||
:addButton()
|
||||
:setText("Home Screen")
|
||||
:setPosition(2, current_y)
|
||||
:setSize(FRAME_WIDTH - 3, 1)
|
||||
:setBackground(homescreen == current_active_frame and colours.lightGrey or colours.grey)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
switch_to_frame(homescreen, "Home Screen")
|
||||
app_switcher_frame:setVisible(false)
|
||||
end)
|
||||
current_y = current_y + 2
|
||||
|
||||
for filename, app_frame in pairs(active_app_frames) do
|
||||
for filename, app_frame in pairs(active_app_frames) do
|
||||
local display_name = filename:gsub(".lua$", "")
|
||||
|
||||
local display_name = filename:gsub(".lua$", "")
|
||||
if current_y + 1 > app_switcher_frame:getHeight() - 2 then
|
||||
app_switcher_frame
|
||||
:addLabel()
|
||||
:setText("...more apps below...")
|
||||
:setPosition(1, current_y)
|
||||
:setSize(FRAME_WIDTH - 2, 1)
|
||||
:setForeground(colours.orange)
|
||||
:setBackground(colours.black)
|
||||
break
|
||||
end
|
||||
|
||||
if current_y + 1 > app_switcher_frame:getHeight() - 2 then
|
||||
app_switcher_frame:addLabel()
|
||||
:setText("...more apps below...")
|
||||
:setPosition(1, current_y)
|
||||
:setSize(FRAME_WIDTH - 2, 1)
|
||||
:setForeground(colours.orange)
|
||||
:setBackground(colours.black)
|
||||
break
|
||||
end
|
||||
app_switcher_frame
|
||||
:addButton()
|
||||
:setText(display_name)
|
||||
:setPosition(2, current_y)
|
||||
:setSize(FRAME_WIDTH - 8, 1)
|
||||
:setBackground(app_frame == current_active_frame and colours.lightGrey or colours.grey)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
switch_to_frame(app_frame, filename)
|
||||
app_switcher_frame:setVisible(false)
|
||||
end)
|
||||
|
||||
app_switcher_frame:addButton()
|
||||
:setText(display_name)
|
||||
:setPosition(2, current_y)
|
||||
:setSize(FRAME_WIDTH - 8, 1)
|
||||
:setBackground(app_frame == current_active_frame and colours.lightGrey or colours.grey)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
switch_to_frame(app_frame, filename)
|
||||
app_switcher_frame:setVisible(false)
|
||||
end)
|
||||
app_switcher_frame
|
||||
:addButton()
|
||||
:setText("X")
|
||||
:setPosition(FRAME_WIDTH - 6, current_y)
|
||||
:setSize(5, 1)
|
||||
:setBackground(colours.red)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
if app_frame then
|
||||
app_frame:destroy()
|
||||
end
|
||||
active_app_frames[filename] = nil
|
||||
|
||||
app_switcher_frame:addButton()
|
||||
:setText("X")
|
||||
:setPosition(FRAME_WIDTH - 6, current_y)
|
||||
:setSize(5, 1)
|
||||
:setBackground(colours.red)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
if current_active_frame == app_frame then
|
||||
switch_to_frame(homescreen, "Home Screen (after close)")
|
||||
end
|
||||
|
||||
if app_frame then
|
||||
app_frame:destroy()
|
||||
end
|
||||
active_app_frames[filename] = nil
|
||||
|
||||
if current_active_frame == app_frame then
|
||||
switch_to_frame(homescreen, "Home Screen (after close)")
|
||||
end
|
||||
|
||||
populate_app_switcher_ui()
|
||||
end)
|
||||
current_y = current_y + 2
|
||||
end
|
||||
populate_app_switcher_ui()
|
||||
end)
|
||||
current_y = current_y + 2
|
||||
end
|
||||
end
|
||||
|
||||
populate_homescreen_buttons()
|
||||
|
||||
main:addButton()
|
||||
:setText("Home")
|
||||
:setPosition(0, CONTROL_BUTTON_Y)
|
||||
:setSize(14, 1)
|
||||
:setBackground(colours.black)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
populate_homescreen_buttons()
|
||||
if current_active_frame ~= homescreen or app_switcher_frame.visible == true then
|
||||
app_switcher_frame:setVisible(false)
|
||||
switch_to_frame(homescreen, "Home Screen")
|
||||
end
|
||||
end)
|
||||
:setText("Home")
|
||||
:setPosition(0, CONTROL_BUTTON_Y)
|
||||
:setSize(14, 1)
|
||||
:setBackground(colours.black)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
populate_homescreen_buttons()
|
||||
if current_active_frame ~= homescreen or app_switcher_frame.visible == true then
|
||||
app_switcher_frame:setVisible(false)
|
||||
switch_to_frame(homescreen, "Home Screen")
|
||||
end
|
||||
end)
|
||||
|
||||
main:addButton()
|
||||
:setText("Switch")
|
||||
:setPosition(14, CONTROL_BUTTON_Y)
|
||||
:setSize(13, 1)
|
||||
:setBackground(colours.red)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
:setText("Switch")
|
||||
:setPosition(14, CONTROL_BUTTON_Y)
|
||||
:setSize(13, 1)
|
||||
:setBackground(colours.red)
|
||||
:setForeground(colours.white)
|
||||
:onClick(function()
|
||||
if current_active_frame then
|
||||
current_active_frame:setVisible(false)
|
||||
end
|
||||
populate_app_switcher_ui()
|
||||
app_switcher_frame:setVisible(true)
|
||||
end)
|
||||
|
||||
if current_active_frame then
|
||||
current_active_frame:setVisible(false)
|
||||
end
|
||||
populate_app_switcher_ui()
|
||||
app_switcher_frame:setVisible(true)
|
||||
end)
|
||||
local M = {}
|
||||
|
||||
function M.start()
|
||||
parallel.waitForAny(basalt.run, payment_listener)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
parallel.waitForAny(basalt.run,payment_listener)
|
10
startup.lua
Normal file
10
startup.lua
Normal file
|
@ -0,0 +1,10 @@
|
|||
local slabos = require("/slabos")
|
||||
|
||||
while true do
|
||||
local ok, err = pcall(slabos.run)
|
||||
if not ok then
|
||||
print("slabos crashed, restarting...")
|
||||
print("error:", err)
|
||||
sleep(1)
|
||||
end
|
||||
end
|
81
version.json
81
version.json
|
@ -1,13 +1,70 @@
|
|||
{
|
||||
"version": "1.0.0.2",
|
||||
"sys_files": {
|
||||
"startup.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/slabos.lua",
|
||||
"basalt.lua": "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/release/basalt.lua",
|
||||
"app_manifest.json": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/app_manifest.json",
|
||||
"lib/libcredit_mobile": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/libcredit_mobile.lua",
|
||||
"lib/basalt.lua": "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/release/basalt.lua",
|
||||
"apps/Updater.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/updater.lua",
|
||||
"apps/eCash.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/eCash.lua",
|
||||
"apps/App Store.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/App%20Store.lua"
|
||||
}
|
||||
}
|
||||
"version": "1.0.1.0",
|
||||
"sys_files": {
|
||||
"/version.json": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/version.json",
|
||||
"/app_manifest.json": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/app_manifest.json",
|
||||
"/slabos.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/slabos.lua",
|
||||
"/apps.json": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/apps.json",
|
||||
"/startup.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/startup.lua",
|
||||
"/base_apps/eCash.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/base_apps/eCash.lua",
|
||||
"/base_apps/updater.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/base_apps/updater.lua",
|
||||
"/base_apps/App Store.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/base_apps/App Store.lua",
|
||||
"/lib/libcredit_mobile.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/libcredit_mobile.lua",
|
||||
"/lib/basalt/plugin.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugin.lua",
|
||||
"/lib/basalt/init.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/init.lua",
|
||||
"/lib/basalt/main.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/main.lua",
|
||||
"/lib/basalt/loadObjects.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/loadObjects.lua",
|
||||
"/lib/basalt/plugins/pixelbox.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/pixelbox.lua",
|
||||
"/lib/basalt/plugins/advancedBackground.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/advancedBackground.lua",
|
||||
"/lib/basalt/plugins/animations.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/animations.lua",
|
||||
"/lib/basalt/plugins/debug.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/debug.lua",
|
||||
"/lib/basalt/plugins/reactive.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/reactive.lua",
|
||||
"/lib/basalt/plugins/textures.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/textures.lua",
|
||||
"/lib/basalt/plugins/dynamicValues.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/dynamicValues.lua",
|
||||
"/lib/basalt/plugins/border.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/border.lua",
|
||||
"/lib/basalt/plugins/basaltAdditions.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/basaltAdditions.lua",
|
||||
"/lib/basalt/plugins/bigfonts.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/bigfonts.lua",
|
||||
"/lib/basalt/plugins/shadow.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/shadow.lua",
|
||||
"/lib/basalt/plugins/themes.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/plugins/themes.lua",
|
||||
"/lib/basalt/objects/Frame.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Frame.lua",
|
||||
"/lib/basalt/objects/Object.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Object.lua",
|
||||
"/lib/basalt/objects/Radio.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Radio.lua",
|
||||
"/lib/basalt/objects/MovableFrame.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/MovableFrame.lua",
|
||||
"/lib/basalt/objects/Thread.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Thread.lua",
|
||||
"/lib/basalt/objects/Scrollbar.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Scrollbar.lua",
|
||||
"/lib/basalt/objects/VisualObject.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/VisualObject.lua",
|
||||
"/lib/basalt/objects/Switch.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Switch.lua",
|
||||
"/lib/basalt/objects/Textfield.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Textfield.lua",
|
||||
"/lib/basalt/objects/Slider.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Slider.lua",
|
||||
"/lib/basalt/objects/Button.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Button.lua",
|
||||
"/lib/basalt/objects/Flexbox.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Flexbox.lua",
|
||||
"/lib/basalt/objects/Dropdown.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Dropdown.lua",
|
||||
"/lib/basalt/objects/Label.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Label.lua",
|
||||
"/lib/basalt/objects/BaseFrame.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/BaseFrame.lua",
|
||||
"/lib/basalt/objects/ChangeableObject.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/ChangeableObject.lua",
|
||||
"/lib/basalt/objects/Checkbox.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Checkbox.lua",
|
||||
"/lib/basalt/objects/ScrollableFrame.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/ScrollableFrame.lua",
|
||||
"/lib/basalt/objects/Image.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Image.lua",
|
||||
"/lib/basalt/objects/Timer.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Timer.lua",
|
||||
"/lib/basalt/objects/MonitorFrame.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/MonitorFrame.lua",
|
||||
"/lib/basalt/objects/Graph.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Graph.lua",
|
||||
"/lib/basalt/objects/Pane.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Pane.lua",
|
||||
"/lib/basalt/objects/Treeview.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Treeview.lua",
|
||||
"/lib/basalt/objects/Container.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Container.lua",
|
||||
"/lib/basalt/objects/Program.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Program.lua",
|
||||
"/lib/basalt/objects/Progressbar.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Progressbar.lua",
|
||||
"/lib/basalt/objects/List.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/List.lua",
|
||||
"/lib/basalt/objects/Menubar.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Menubar.lua",
|
||||
"/lib/basalt/objects/Input.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/objects/Input.lua",
|
||||
"/lib/basalt/libraries/xmlParser.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/xmlParser.lua",
|
||||
"/lib/basalt/libraries/images.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/images.lua",
|
||||
"/lib/basalt/libraries/utils.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/utils.lua",
|
||||
"/lib/basalt/libraries/bimg.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/bimg.lua",
|
||||
"/lib/basalt/libraries/basaltLogs.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/basaltLogs.lua",
|
||||
"/lib/basalt/libraries/basaltEvent.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/basaltEvent.lua",
|
||||
"/lib/basalt/libraries/basaltDraw.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/basaltDraw.lua",
|
||||
"/lib/basalt/libraries/basaltMon.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/basaltMon.lua",
|
||||
"/lib/basalt/libraries/tHex.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/tHex.lua",
|
||||
"/lib/basalt/libraries/process.lua": "https://git.mcorangehq.xyz/xomf/slabOS/raw/branch/main/lib/basalt/libraries/process.lua"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user