From 8168fa4465f3022cc2e3ff02fa5533b9d31fe548 Mon Sep 17 00:00:00 2001 From: Robert Jelic Date: Wed, 13 Mar 2024 09:57:07 +0100 Subject: [PATCH] 1.7 stuff The master branch was reverted to 1.7 because it was very unstable (bugs and stuff that wasn't mentioned on the documentation page yet) - features will come back with 2.0 - fixed debug window - fixed flexbox not sending drag events to it's children - small docs updates for 1.7 - removed the examples because the are outdated --- Basalt/libraries/basaltDraw.lua | 72 ++++-- Basalt/libraries/basaltEvent.lua | 4 +- Basalt/libraries/basaltMon.lua | 242 ++++++++++-------- Basalt/libraries/images.lua | 27 +-- Basalt/libraries/process.lua | 1 - Basalt/libraries/utils.lua | 62 ++--- Basalt/libraries/xmlParser.lua | 2 +- Basalt/main.lua | 70 ++---- Basalt/objects/BaseFrame.lua | 99 ++++++-- Basalt/objects/Button.lua | 55 ++++- Basalt/objects/ChangeableObject.lua | 37 +-- Basalt/objects/Checkbox.lua | 70 +++++- Basalt/objects/Container.lua | 48 ++-- Basalt/objects/Dropdown.lua | 143 ++++++----- Basalt/objects/Flexbox.lua | 154 ++++++++---- Basalt/objects/Frame.lua | 53 +++- Basalt/objects/Graph.lua | 117 ++++++--- Basalt/objects/Image.lua | 62 ++++- Basalt/objects/Input.lua | 199 ++++++++------- Basalt/objects/Label.lua | 102 +++++--- Basalt/objects/List.lua | 136 ++++++++--- Basalt/objects/Menubar.lua | 45 +++- Basalt/objects/MonitorFrame.lua | 78 ++++-- Basalt/objects/MovableFrame.lua | 39 ++- Basalt/objects/Object.lua | 237 +++--------------- Basalt/objects/Pane.lua | 8 +- Basalt/objects/Program.lua | 55 +++-- Basalt/objects/Progressbar.lua | 149 ++++++++---- Basalt/objects/Radio.lua | 83 +++++-- Basalt/objects/ScrollableFrame.lua | 199 ++++----------- Basalt/objects/Scrollbar.lua | 126 +++++++--- Basalt/objects/Slider.lua | 90 ++++--- Basalt/objects/Switch.lua | 47 +++- Basalt/objects/Textfield.lua | 173 ++++++------- Basalt/objects/Thread.lua | 7 +- Basalt/objects/Timer.lua | 49 ++-- Basalt/objects/Treeview.lua | 140 ++++++++--- Basalt/objects/VisualObject.lua | 323 +++++++++++++++---------- Basalt/plugins/animations.lua | 12 - Basalt/plugins/bigfonts.lua | 52 ++-- Basalt/plugins/border.lua | 2 +- Basalt/plugins/debug.lua | 27 +-- Basalt/plugins/dynamicValues.lua | 304 +++++++++-------------- Basalt/plugins/moreDrawing.lua | 321 ------------------------ Basalt/plugins/pixelbox.lua | 4 +- Basalt/plugins/reactive.lua | 203 ++++++++++++++++ Basalt/plugins/reactiveXml.lua | 142 ----------- Basalt/plugins/shadow.lua | 2 + Basalt/plugins/templates.lua | 132 ---------- Basalt/plugins/textures.lua | 154 ++++++------ docs/_footer.md | 2 +- docs/_sidebar.md | 3 +- docs/objects/Basalt.md | 4 +- docs/objects/BaseFrame/setOffset.md | 3 +- docs/objects/Checkbox.md | 4 +- docs/objects/Container/setImportant.md | 2 +- docs/objects/Container/updateZIndex.md | 2 +- docs/objects/Image/blit.md | 27 +++ docs/objects/Input/getOffset.md | 9 + docs/objects/Input/getTextOffset.md | 9 + docs/objects/Input/setOffset.md | 22 ++ docs/objects/Input/setTextOffset.md | 22 ++ docs/objects/Label.md | 1 - docs/objects/Textfield.md | 14 +- docs/objects/Textfield/clear.md | 23 ++ docs/objects/Textfield/editRule.md | 30 +++ docs/objects/Textfield/getOffset.md | 26 ++ docs/objects/Textfield/getSelection.md | 10 + docs/objects/Textfield/removeRule.md | 28 +++ docs/objects/Textfield/setOffset.md | 28 +++ docs/objects/Textfield/setSelection.md | 27 +++ examples/discordCC.lua | 291 ---------------------- examples/progressBarEnergyExample.lua | 51 ---- examples/redstoneAnalogOutput.lua | 49 ---- examples/resizeableFrames.lua | 38 --- 75 files changed, 2839 insertions(+), 2844 deletions(-) delete mode 100644 Basalt/plugins/moreDrawing.lua create mode 100644 Basalt/plugins/reactive.lua delete mode 100644 Basalt/plugins/reactiveXml.lua delete mode 100644 Basalt/plugins/templates.lua create mode 100644 docs/objects/Image/blit.md create mode 100644 docs/objects/Input/getOffset.md create mode 100644 docs/objects/Input/getTextOffset.md create mode 100644 docs/objects/Input/setOffset.md create mode 100644 docs/objects/Input/setTextOffset.md create mode 100644 docs/objects/Textfield/clear.md create mode 100644 docs/objects/Textfield/editRule.md create mode 100644 docs/objects/Textfield/getOffset.md create mode 100644 docs/objects/Textfield/getSelection.md create mode 100644 docs/objects/Textfield/removeRule.md create mode 100644 docs/objects/Textfield/setOffset.md create mode 100644 docs/objects/Textfield/setSelection.md delete mode 100644 examples/discordCC.lua delete mode 100644 examples/progressBarEnergyExample.lua delete mode 100644 examples/redstoneAnalogOutput.lua delete mode 100644 examples/resizeableFrames.lua diff --git a/Basalt/libraries/basaltDraw.lua b/Basalt/libraries/basaltDraw.lua index c16c0ea..8c62a31 100644 --- a/Basalt/libraries/basaltDraw.lua +++ b/Basalt/libraries/basaltDraw.lua @@ -1,4 +1,6 @@ local tHex = require("tHex") +local utils = require("utils") +local split = utils.splitString local sub,rep = string.sub,string.rep return function(drawTerm) @@ -40,27 +42,33 @@ return function(drawTerm) if #t == #fg and #t == #bg then if y >= 1 and y <= height then if x + #t > 0 and x <= width then - local startN = x < 1 and 1 - x + 1 or 1 - local endN = x + #t > width and width - x + 1 or #t - + local newCacheT, newCacheFG, newCacheBG local oldCacheT, oldCacheFG, oldCacheBG = cacheT[y], cacheFG[y], cacheBG[y] - - local newCacheT = sub(oldCacheT, 1, x - 1) .. sub(t, startN, endN) - local newCacheFG = sub(oldCacheFG, 1, x - 1) .. sub(fg, startN, endN) - local newCacheBG = sub(oldCacheBG, 1, x - 1) .. sub(bg, startN, endN) - + 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 @@ -86,7 +94,7 @@ return function(drawTerm) end end - local function setBg(x, y, bg) + local function setBG(x, y, bg) if y >= 1 and y <= height then if x + #bg > 0 and x <= width then local newCacheBG @@ -111,7 +119,7 @@ return function(drawTerm) end end - local function setFg(x, y, fg) + local function setFG(x, y, fg) if y >= 1 and y <= height then if x + #fg > 0 and x <= width then local newCacheFG @@ -136,6 +144,32 @@ return function(drawTerm) 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 @@ -146,17 +180,17 @@ return function(drawTerm) mirrorTerm = mirror end, - setBg = function(x, y, colorStr) - setBg(x, y, colorStr) + 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, + setFG = function(x, y, colorStr) + setFG(x, y, colorStr) + end; blit = function(x, y, t, fg, bg) blit(x, y, t, fg, bg) @@ -165,13 +199,13 @@ return function(drawTerm) drawBackgroundBox = function(x, y, width, height, bgCol) local colorStr = rep(tHex[bgCol], width) for n = 1, height do - setBg(x, y + (n - 1), colorStr) + 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) + setFG(x, y + (n - 1), colorStr) end end, drawTextBox = function(x, y, width, height, symbol) diff --git a/Basalt/libraries/basaltEvent.lua b/Basalt/libraries/basaltEvent.lua index e5e256e..f870ad4 100644 --- a/Basalt/libraries/basaltEvent.lua +++ b/Basalt/libraries/basaltEvent.lua @@ -1,5 +1,3 @@ -local tableCount = require("utils").tableCount - return function() local events = {} @@ -20,7 +18,7 @@ return function() end, getEventCount = function(self, _event) - return _event~=nil and events[_event]~=nil and tableCount(events[_event]) or tableCount(events) + return events[_event]~=nil and #events[_event] or 0 end, getEvents = function(self) diff --git a/Basalt/libraries/basaltMon.lua b/Basalt/libraries/basaltMon.lua index bda683b..820e997 100644 --- a/Basalt/libraries/basaltMon.lua +++ b/Basalt/libraries/basaltMon.lua @@ -1,143 +1,180 @@ +-- 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 max, sub = math.max,string.sub +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", +} -return function(monitorNames) +local type,len,rep,sub = type,string.len,string.rep,string.sub + + +return function (monitorNames) local monitors = {} - local multiMonWidth, multiMonHeight = 0,0 - local multiMonX, multiMonY = 1, 1 - local bgColor, txtColor = colors.black, colors.white - for k,v in pairs(monitorNames) do - monitors[k] = {} + for k,v in pairs(monitorNames)do + monitors[k] = {} for a,b in pairs(v)do - monitors[k][a] = {name=b, monitor=peripheral.wrap(b)} - end - end - - local function calculateSize() - local absWidth, absHeight = 0,0 - local height = 0 - for _,v in pairs(monitors)do - local width = 0 - for _,b in pairs(v)do - local w, h = b.monitor.getSize() - width = width + w - height = max(height, h) + local mon = peripheral.wrap(b) + if(mon==nil)then + error("Unable to find monitor "..b) end - absWidth = max(absWidth, width) - absHeight = absHeight + height - height = 0 + monitors[k][a] = mon + monitors[k][a].name = b end - multiMonWidth, multiMonHeight = absWidth, absHeight end - calculateSize() - local function getMonitorFromPosition(x, y) - local absWidth, absHeight = 0,0 - local height = 0 + + 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 width = 0 + local _maxW,_maxH = 0,0 for a,b in pairs(v)do - local w, h = b.monitor.getSize() - width = width + w - height = max(height, h) - if(x >= absWidth and x <= absWidth + w and y >= absHeight and y <= absHeight + h)then - return b.monitor, a, k - end - absWidth = absWidth + w + local nw,nh = b.getSize() + _maxW = _maxW + nw + _maxH = nh > _maxH and nh or _maxH end - absWidth = 0 - absHeight = absHeight + height - height = 0 + maxW = maxW > _maxW and maxW or _maxW + maxH = maxH + _maxH end + w,h = maxW,maxH end + calcSize() - local function getRelativeCursorPos(mon, x, y) - local absWidth, absHeight = 0,0 - local height = 0 + local function calcPosition() + local relY = 0 + local mX,mY = 0,0 for k,v in pairs(monitors)do - local width = 0 + local relX = 0 + local _mh = 0 for a,b in pairs(v)do - local w, h = b.monitor.getSize() - width = width + w - height = max(height, h) - if(b.monitor == mon)then - return x - absWidth, y - absHeight + local mw,mh = b.getSize() + if(x-relX>=1)and(x-relX<=mw)then + mX = a end - absWidth = absWidth + w + b.setCursorPos(x-relX, y-relY) + relX = relX + mw + if(_mh=1)and(y-relY<=_mh)then + mY = k + end + relY = relY + _mh end + monX,monY = mX,mY end + calcPosition() - local function blit(text, fgColor, bgColor) - local mon, x, y = getMonitorFromPosition(multiMonX, multiMonY) - - for k, v in pairs(monitors[y])do - if(k >= x)then - local xCursor, yCursor = getRelativeCursorPos(v.monitor, multiMonX, multiMonY) - local w, h = v.monitor.getSize() - local textToScreen = sub(text, 1, w) - text = sub(text, w+1) - local fgColorToScreen = sub(fgColor, 1, w) - fgColor = sub(fgColor, w+1) - local bgColorToScreen = sub(bgColor, 1, w) - bgColor = sub(bgColor, w+1) - v.monitor.setCursorPos(xCursor, yCursor) - v.monitor.blit(textToScreen, fgColorToScreen, bgColorToScreen) - multiMonX = multiMonX + w + 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 - return { - getSize = function() - return multiMonWidth, multiMonHeight - 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 - blit = blit, - getCursorPos = function() - return multiMonX, multiMonY - end, - - setCursorPos = function(x, y) - multiMonX, multiMonY = x, y - for _,v in pairs(monitors)do - for _,b in pairs(v)do - local xCursor, yCursor = getRelativeCursorPos(b.monitor, multiMonX, multiMonY) - b.monitor.setCursorPos(xCursor, yCursor) - 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() - local mon = getMonitorFromPosition(multiMonX, multiMonY) - return mon.getCursorBlink() + return blink end, - setCursorBlink = function(blink) - for _,v in pairs(monitors)do - for _,b in pairs(v)do - b.monitor.setCursorBlink(blink) - end - end + getCursorPos = function() + return x, y + end, + + setCursorPos = function(newX,newY) + x, y = newX, newY + calcPosition() + cursorBlink() end, - setBackgroundColor = function(color) - bgColor = color + setTextScale = function(_scale) + call("setTextScale", _scale)() + calcSize() + calcPosition() + scale = _scale end, - getBackgroundColor = function() - return bgColor + getTextScale = function() + return scale end, - setTextColor = function(color) - txtColor = color + blit = function(text,fgCol,bgCol) + blit(text,fgCol,bgCol) end, - getTextColor = function() - return txtColor + 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) @@ -146,7 +183,7 @@ return function(monitorNames) local relX = 0 local maxY = 0 for a,b in pairs(v)do - local wM,hM = b.monitor.getSize() + local wM,hM = b.getSize() if(b.name==name)then return xClick + relX, yClick + relY end @@ -157,5 +194,6 @@ return function(monitorNames) end return xClick, yClick end, - } + + } end \ No newline at end of file diff --git a/Basalt/libraries/images.lua b/Basalt/libraries/images.lua index a8caaa8..ce6ac00 100644 --- a/Basalt/libraries/images.lua +++ b/Basalt/libraries/images.lua @@ -27,29 +27,24 @@ local function loadBBFAsBimg(path) end -local function loadImage(path, binaryMode) - --Loads the image with the right loader, returns error if the file type is unknown. - if(sub(path, -5) == ".bimg")then +local function loadImage(path, f, binaryMode) + if(sub(path, -4) == ".bimg")then return loadBIMG(path, binaryMode) - elseif(sub(path, -4) == ".bbf")then - return loadBBF(path) - elseif(sub(path, -4) == ".nfp")then - return loadNFP(path) + elseif(sub(path, -3) == ".bbf")then + return loadBBF(path, binaryMode) else - error("Unknown file type") + return loadNFP(path, binaryMode) end + -- ... end -local function loadImageAsBimg(path, binaryMode) - --Loads the image with the right Bimg loader, returns error if the file type is unknown. - if(sub(path, -5) == ".bimg")then - return loadBIMG(path, binaryMode) - elseif(sub(path, -4) == ".bbf")then +local function loadImageAsBimg(path) + if(path:find(".bimg"))then + return loadBIMG(path) + elseif(path:find(".bbf"))then return loadBBFAsBimg(path) - elseif(sub(path, -4) == ".nfp")then - return loadNFPAsBimg(path) else - error("Unknown file type") + return loadNFPAsBimg(path) end end diff --git a/Basalt/libraries/process.lua b/Basalt/libraries/process.lua index bf2cd4d..fb5b76d 100644 --- a/Basalt/libraries/process.lua +++ b/Basalt/libraries/process.lua @@ -6,7 +6,6 @@ local newPackage = dofile("rom/modules/main/cc/require.lua").make function process:new(path, window, newEnv, ...) local args = {...} - newEnv = newEnv or {} local newP = setmetatable({ path = path }, { __index = self }) newP.window = window window.current = term.current diff --git a/Basalt/libraries/utils.lua b/Basalt/libraries/utils.lua index 5db7c71..f76e26a 100644 --- a/Basalt/libraries/utils.lua +++ b/Basalt/libraries/utils.lua @@ -167,42 +167,34 @@ local function wrapRichText(text, width) elseif entry.bgColor then currentBgColor = entry.bgColor else - local paragraphs = splitString(entry.text, "\n") - for p, paragraph in ipairs(paragraphs) do - local words = splitString(paragraph, " ") + local words = splitString(entry.text, " ") - for i, word in ipairs(words) do - local wordLength = #word + 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 + if i > 1 then + if x + 1 + wordLength <= width then + addFormattedEntry({ text = " " }) + x = x + 1 + else + x = 1 + y = y + 1 end end - if p ~= #paragraphs then - x = 1 - y = y + 1 + 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 @@ -217,7 +209,6 @@ local function wrapRichText(text, width) end - return { @@ -327,13 +318,10 @@ wrapRichText = wrapRichText, --- @param height number Height writeWrappedText = function(obj, x, y, text, width, height) local wrapped = wrapRichText(text, width) - for k,v in pairs(wrapped)do + for _,v in pairs(wrapped)do if(v.y>height)then break end - if(k==#wrapped)and(v=="")then - break - end if(v.text~=nil)then obj:addText(x+v.x-1, y+v.y-1, v.text) end @@ -352,4 +340,4 @@ 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 -} +} \ No newline at end of file diff --git a/Basalt/libraries/xmlParser.lua b/Basalt/libraries/xmlParser.lua index fbc7781..1be0df9 100644 --- a/Basalt/libraries/xmlParser.lua +++ b/Basalt/libraries/xmlParser.lua @@ -74,4 +74,4 @@ local XMLParser = { end } -return XMLParser +return XMLParser \ No newline at end of file diff --git a/Basalt/main.lua b/Basalt/main.lua index da52b18..206700c 100644 --- a/Basalt/main.lua +++ b/Basalt/main.lua @@ -9,18 +9,16 @@ local wrapText = utils.wrapText local count = utils.tableCount local moveThrottle = 300 local dragThrottle = 0 -local renderingThrottle = 50 +local renderingThrottle = 0 local newObjects = {} -local mousePos = {0, 0} local baseTerm = term.current() -local version = "1.7.1" +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 renderingTimer = nil local basalt = {} @@ -84,39 +82,11 @@ local createObject = function(basalt, objectName, id) return getObject(objectName)(id, basalt) end -local setRenderingThrottle = function(amount) - if(amount<=0)then - renderingThrottle = 0 - else - renderingTimer = nil - renderingThrottle = amount - end -end - -local getRenderingThrottle = function() - return renderingThrottle -end - -local debugTimer = 0 -local startTimer = function() - debugTimer = os.clock("utc") - basalt.log("Timer started at "..debugTimer.." seconds") -end - -local endTimer = function() - local endT = os.clock("utc") - debugTimer - basalt.log("Timer ended at "..os.clock().." seconds") - basalt.log("Timer ended after "..endT.." seconds") -end - local bInstance = { getDynamicValueEventSetting = function() return basalt.dynamicValueEvents end, - - getRenderingThrottle = getRenderingThrottle, - setRenderingThrottle = setRenderingThrottle, - + getMainFrame = function() return mainFrame end, @@ -269,14 +239,15 @@ local function mouseDragEvent(_, b, x, y) end +local renderingTimer = nil local function renderingUpdateTimer() renderingTimer = nil - drawFrames() + drawFrames() end local function renderingUpdateEvent(timer) - if(renderingThrottle<50)then - drawFrames() + if(renderingThrottle<50)then + drawFrames() else if(renderingTimer==nil)then renderingTimer = os.startTimer(renderingThrottle/1000) @@ -298,10 +269,6 @@ local function basaltUpdateEvent(event, ...) } local mouseEvent = mouseEvents[event] if(mouseEvent~=nil)then - local mouseX, mouseY = a[3], a[4] - if(mouseX~=nil and mouseY~=nil)then - mousePos = {mouseX, mouseY} - end mouseEvent(mainFrame, ...) handleSchedules(event, ...) renderingUpdateEvent() @@ -412,9 +379,9 @@ local function InitializeBasalt() loadedPlugins = true end end -InitializeBasalt() local function createFrame(name) + InitializeBasalt() for _, v in pairs(frames) do if (v:getName() == name) then return nil @@ -466,9 +433,6 @@ basalt = { end return objectNames end, - getMousePosition = function() - return mousePos[1], mousePos[2] - end, setVariable = setVariable, getVariable = getVariable, @@ -503,9 +467,14 @@ basalt = { return false end, - setRenderingThrottle = setRenderingThrottle, - - getRenderingThrottle = getRenderingThrottle, + setRenderingThrottle = function(amount) + if(amount<=0)then + renderingThrottle = 0 + else + renderingTimer = nil + renderingThrottle = amount + end + end, setMouseDragThrottle = function(amount) if(amount<=0)then @@ -554,7 +523,7 @@ basalt = { getFrame = function(name) for _, value in pairs(frames) do - if (value:getName() == name) then + if (value.name == name) then return value end end @@ -590,6 +559,7 @@ basalt = { createFrame = createFrame, addMonitor = function(name) + InitializeBasalt() for _, v in pairs(frames) do if (v:getName() == name) then return nil @@ -602,7 +572,7 @@ basalt = { table.insert(monFrames, newFrame) return newFrame end, - + removeFrame = function(name) frames[name] = nil end, @@ -630,4 +600,4 @@ if(basaltPlugins~=nil)then end end -return basalt +return basalt \ No newline at end of file diff --git a/Basalt/objects/BaseFrame.lua b/Basalt/objects/BaseFrame.lua index 2bf3041..dc0f0ac 100644 --- a/Basalt/objects/BaseFrame.lua +++ b/Basalt/objects/BaseFrame.lua @@ -5,7 +5,9 @@ local max,min,sub,rep = math.max,math.min,string.sub,string.rep return function(name, basalt) local base = basalt.getObject("Container")(name, basalt) - base:setType("BaseFrame") + local objectType = "BaseFrame" + + local xOffset, yOffset = 0, 0 local colorTheme = {} @@ -16,38 +18,58 @@ return function(name, basalt) local xCursor, yCursor, cursorBlink, cursorColor = 1, 1, false, colors.white - base:addProperty("XOffset", "number", 0) - base:addProperty("YOffset", "number", 0) - base:combineProperty("Offset", "XOffset", "YOffset") - base:addProperty("Term", "table", nil, false, function(self, value) - termObject = value - basaltDraw = nil - if(value~=nil)then - basaltDraw = drawSystem(value) - base:setSize(value.getSize()) - end - end) - base:setSize(termObject.getSize()) - 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, - setPalette = function(self, col, ...) + 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 - col = colors[col] - colorTheme[math.log(col, 2)] = ... - termObject.setPaletteColor(col, ...) + 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(2 ^ k, v) + termObject.setPaletteColor(type(k)=="number" and k or colors[k], v) else local r,g,b = table.unpack(v) - termObject.setPaletteColor(2 ^ k, r,g,b) + termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b) end end end @@ -61,6 +83,18 @@ return function(name, basalt) 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) @@ -71,10 +105,10 @@ return function(name, basalt) end for k,v in pairs(colorTheme)do if(type(v)=="number")then - termObject.setPaletteColor(k ^ 2, v) + termObject.setPaletteColor(type(k)=="number" and k or colors[k], v) else local r,g,b = table.unpack(v) - termObject.setPaletteColor(k ^ 2, r,g,b) + termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b) end end basalt.setMainFrame(self) @@ -116,6 +150,20 @@ return function(name, basalt) 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() @@ -149,7 +197,7 @@ return function(name, basalt) end, } - for _,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do + 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) @@ -157,18 +205,17 @@ return function(name, basalt) end end - for _,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do + 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() - if(height==nil)then return end 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 _,v in pairs({"setBg", "setFg", "setText"}) do + 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() diff --git a/Basalt/objects/Button.lua b/Basalt/objects/Button.lua index e601990..f2a5d3b 100644 --- a/Basalt/objects/Button.lua +++ b/Basalt/objects/Button.lua @@ -4,29 +4,62 @@ local tHex = require("tHex") return function(name, basalt) -- Button local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("Button") + local objectType = "Button" + local textHorizontalAlign = "center" + local textVerticalAlign = "center" + + local text = "Button" base:setSize(12, 3) - base:setZ(5) - - base:addProperty("text", "string", "Button") - base:addProperty("textHorizontalAlign", {"left", "center", "right"}, "center") - base:addProperty("textVerticalAlign", {"left", "center", "right"}, "center") - base:combineProperty("textAlign", "textHorizontalAlign", "textVerticalAlign") + 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 textHorizontalAlign = self:getTextHorizontalAlign() - local textVerticalAlign = self:getTextVerticalAlign() local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign) - local text = self:getText() local xOffset if(textHorizontalAlign=="center")then xOffset = math.floor((w - text:len()) / 2) @@ -35,7 +68,7 @@ return function(name, basalt) end self:addText(xOffset + 1, verticalAlign, text) - self:addFg(xOffset + 1, verticalAlign, tHex[self:getForeground() or colors.white]:rep(text:len())) + self:addFG(xOffset + 1, verticalAlign, tHex[self:getForeground() or colors.white]:rep(text:len())) end) end, } diff --git a/Basalt/objects/ChangeableObject.lua b/Basalt/objects/ChangeableObject.lua index 0bec0ba..3ef6dd7 100644 --- a/Basalt/objects/ChangeableObject.lua +++ b/Basalt/objects/ChangeableObject.lua @@ -1,21 +1,26 @@ return function(name, basalt) local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("ChangeableObject") - - base:addProperty("ChangeHandler", "function", nil) - base:addProperty("Value", "any", nil, false, function(self, value) - local _value = self:getValue() - if (value ~= _value) then - local valueChangedHandler = self:getChangeHandler() - if(valueChangedHandler~=nil)then - valueChangedHandler(self, value) - end - self:sendEvent("value_changed", value) - end - return value - end) + -- 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 @@ -24,6 +29,10 @@ return function(name, basalt) end return self end, + + valueChangedHandler = function(self) + self:sendEvent("value_changed", value) + end, } object.__index = object diff --git a/Basalt/objects/Checkbox.lua b/Basalt/objects/Checkbox.lua index 54a650f..298f82c 100644 --- a/Basalt/objects/Checkbox.lua +++ b/Basalt/objects/Checkbox.lua @@ -4,25 +4,72 @@ local tHex = require("tHex") return function(name, basalt) -- Checkbox local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("Checkbox") + local objectType = "Checkbox" - base:setZ(5) + base:setZIndex(5) base:setValue(false) base:setSize(1, 1) - base:addProperty("activeSymbol", "char", "\42") - base:addProperty("inactiveSymbol", "char", " ") - base:combineProperty("Symbol", "activeSymbol", "inactiveSymbol") - - base:addProperty("text", "string", "") - base:addProperty("textPosition", {"left", "right"}, "right") + 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, @@ -45,13 +92,10 @@ return function(name, basalt) 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() - local symbol = self:getActiveSymbol() - local inactiveSymbol = self:getInactiveSymbol() - local text = self:getText() - local textPos = self:getTextPosition() if (self:getValue()) then self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(symbol, w, "center"), tHex[fg], tHex[bg]) else diff --git a/Basalt/objects/Container.lua b/Basalt/objects/Container.lua index 138c362..67e9115 100644 --- a/Basalt/objects/Container.lua +++ b/Basalt/objects/Container.lua @@ -1,10 +1,9 @@ local utils = require("utils") local tableCount = utils.tableCount -local rpairs = utils.rpairs return function(name, basalt) local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("Container") + local objectType = "Container" local children = {} @@ -67,7 +66,7 @@ return function(name, basalt) return end objId = objId + 1 - local zIndex = element:getZ() + local zIndex = element:getZIndex() table.insert(children, {element = element, zIndex = zIndex, objId = objId}) sorted = false element:setParent(self, true) @@ -96,11 +95,11 @@ return function(name, basalt) for i, v in ipairs(children) do if v.element == element then table.remove(children, i) - self:removeEvents(element) - sorted = false return true end end + self:removeEvents(element) + sorted = false end local function removeChildren(self) @@ -112,7 +111,6 @@ return function(name, basalt) evId = 0 focusedChild = nil parent:removeEvents(self) - self:updateEvents() end local function updateZIndex(self, element, newZ) @@ -147,10 +145,7 @@ return function(name, basalt) end if(tableCount(events[a])<=0)then if(parent~=nil)then - if(self:getEventSystem().getEventCount(a)<=0)then - parent:removeEvent(a, self) - self:updateEvents() - end + parent:removeEvent(a, self) end end end @@ -172,7 +167,7 @@ return function(name, basalt) if (getEvent(self, event, element:getName()) ~= nil) then return end - local zIndex = element:getZ() + 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}) @@ -200,10 +195,18 @@ return function(name, basalt) end container = { - getBase = function(self) - return base + 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") @@ -305,23 +308,6 @@ return function(name, basalt) getFocused = function(self) return focusedChild end, - - getChildrenAt = function(self, x, y) - local results = {} - for _, child in rpairs(children) do - if(child.element.getPosition~=nil)and(child.element.getSize~=nil)then - local xObj, yObj = child.element:getPosition() - local wObj, hObj = child.element:getSize() - local isVisible = child.element:getVisible() - if(isVisible)then - if (x >= xObj and x <= xObj + wObj - 1 and y >= yObj and y <= yObj + hObj - 1) then - table.insert(results, child.element) - end - end - end - end - return results - end, getChild = getChild, getChildren = getChildren, @@ -398,7 +384,7 @@ return function(name, basalt) xO, yO = 0, 0 end end - if (obj.element[v[1]](obj.element, btn, x+xO, y+yO, ...)) then + if (obj.element[v[1]](obj.element, btn, x+xO, y+yO, ...)) then return true end end diff --git a/Basalt/objects/Dropdown.lua b/Basalt/objects/Dropdown.lua index e801bfa..0e538df 100644 --- a/Basalt/objects/Dropdown.lua +++ b/Basalt/objects/Dropdown.lua @@ -3,21 +3,31 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("List")(name, basalt) - base:setType("Dropdown") + local objectType = "Dropdown" base:setSize(12, 1) - base:setZ(6) + base:setZIndex(6) - base:addProperty("Align", {"left", "center", "right"}, "left") - base:addProperty("AutoSize", "boolean", true) - base:addProperty("ClosedSymbol", "char", "\16") - base:addProperty("OpenedSymbol", "char", "\31") - base:addProperty("Opened", "boolean", false) - base:addProperty("DropdownWidth", "number", 12) - base:addProperty("DropdownHeight", "number", 0) - base:combineProperty("DropdownSize", "DropdownWidth", "DropdownHeight") + 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) @@ -25,49 +35,84 @@ return function(name, basalt) 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(self:getAutoSize())then - local dropdownW, dropdownH = self:getDropdownSize() - self:setDropdownSize(math.max(dropdownW, #t), dropdownH + 1) + if(autoSize)then + dropdownW = math.max(dropdownW, #t) + dropdownH = dropdownH + 1 end return self end, removeItem = function(self, index) base.removeItem(self, index) - local list = self:getAll() - if(self:getAutoSize())then - local dropdownW, dropdownH = self:getDropdownSize() + if(autoSize)then dropdownW = 0 dropdownH = 0 for n = 1, #list do dropdownW = math.max(dropdownW, #list[n].text) end dropdownH = #list - self:setDropdownSize(dropdownW, dropdownH) end - return self end, isOpened = function(self) - return self:getOpened() + 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) - local isOpened = self:getOpened() if (isOpened) then local obx, oby = self:getAbsolutePosition() if(button==1)then local list = self:getAll() if (#list > 0) then - local dropdownW, dropdownH = self:getDropdownSize() - local offset = self:getOffset() for n = 1, dropdownH do - if (list[n + offset] ~= nil) then + if (list[n + yOffset] ~= nil) then if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then - self:setValue(list[n + offset]) - self:selectHandler() + 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 @@ -86,32 +131,29 @@ return function(name, basalt) end local base = base:getBase() if (base.mouseHandler(self, button, x, y)) then - self:setOpened(not isOpened) + isOpened = not isOpened self:getParent():setImportant(self) self:updateDraw() return true else if(isOpened)then self:updateDraw() - self:setOpened(false) - end + isOpened = false + end return false end end, mouseUpHandler = function(self, button, x, y) - local isOpened = self:getOpened() if (isOpened) then local obx, oby = self:getAbsolutePosition() if(button==1)then local list = self:getAll() if (#list > 0) then - local dropdownW, dropdownH = self:getDropdownSize() - local offset = self:getOffset() for n = 1, dropdownH do - if (list[n + offset] ~= nil) then + if (list[n + yOffset] ~= nil) then if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then - self:setOpened(false) + isOpened = false self:updateDraw() local val = self:sendEvent("mouse_up", self, "mouse_up", button, x, y) if(val==false)then return val end @@ -126,13 +168,11 @@ return function(name, basalt) dragHandler = function(self, btn, x, y) if(base.dragHandler(self, btn, x, y))then - self:setOpened(true) + isOpened = true end end, scrollHandler = function(self, dir, x, y) - local isOpened = self:getOpened() - local dropdownW, dropdownH = self:getDropdownSize() if(isOpened)then local xPos, yPos = self:getAbsolutePosition() if(x >= xPos)and(x <= xPos + dropdownW)and(y >= yPos)and(y <= yPos + dropdownH)then @@ -147,21 +187,19 @@ return function(name, basalt) if(#self:getAll() <= dropdownH)then return false end local list = self:getAll() - - local offset = self:getOffset() + dir - if (offset < 0) then - offset = 0 + yOffset = yOffset + dir + if (yOffset < 0) then + yOffset = 0 end if (dir == 1) then if (#list > dropdownH) then - if (offset > #list - dropdownH) then - offset = #list - dropdownH + if (yOffset > #list - dropdownH) then + yOffset = #list - dropdownH end else - offset = math.min(#list - 1, 0) + yOffset = math.min(#list - 1, 0) end end - self:setOffset(offset) local val = self:sendEvent("mouse_scroll", self, "mouse_scroll", dir, x, y) if(val==false)then return val end self:updateDraw() @@ -173,16 +211,11 @@ return function(name, basalt) 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 openedSymbol, closedSymbol = self:getOpenedSymbol(), self:getClosedSymbol() - local align = self:getAlign() - local dropdownW, dropdownH = self:getDropdownSize() - local offset = self:getOffset() - local selectionColorActive = self:getSelectionColorActive() - local isOpened = self:getOpened() 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)) @@ -191,17 +224,17 @@ return function(name, basalt) self:addBackgroundBox(1, 2, dropdownW, dropdownH, bgCol) self:addForegroundBox(1, 2, dropdownW, dropdownH, fgCol) for n = 1, dropdownH do - if (list[n + offset] ~= nil) then - local t =utils.getTextHorizontalAlign(list[n + offset].text, dropdownW, align) - if (list[n + offset] == val) then + 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 + offset].fgCol]:rep(#t), tHex[list[n + offset].bgCol]:rep(#t)) + 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 + offset].fgCol]:rep(#t), tHex[list[n + offset].bgCol]:rep(#t)) + self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t)) end end end diff --git a/Basalt/objects/Flexbox.lua b/Basalt/objects/Flexbox.lua index 88acf7a..c1705ae 100644 --- a/Basalt/objects/Flexbox.lua +++ b/Basalt/objects/Flexbox.lua @@ -1,23 +1,48 @@ local function flexObjectPlugin(base, basalt) + local flexGrow = 0 + local flexShrink = 0 + local flexBasis = 0 + local baseWidth, baseHeight = base:getSize() - if(base:getType()~="lineBreakFakeObject")then - base:addProperty("FlexGrow", "number", 0) - base:addProperty("FlexShrink", "number", 0) - base:addProperty("FlexBasis", "number", 0) - end - local object = { - getBaseSize = function(self) + 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, - getBaseWidth = function(self) + getWidth = function(self) return baseWidth end, - getBaseHeight = function(self) + getHeight = function(self) return baseHeight end, @@ -36,47 +61,28 @@ end return function(name, basalt) local base = basalt.getObject("ScrollableFrame")(name, basalt) - base:setType("Flexbox") - - local updateLayout = false - - base:addProperty("FlexDirection", {"row", "column"}, "row", nil, function(self, direction) - if(direction=="row")then - base:setDirection("horizontal") - elseif(direction=="column")then - base:setDirection("vertical") - end - end) - base:addProperty("Spacing", "number", 1, nil, function(self, spacing) - updateLayout = true - end) - base:addProperty("JustifyContent", {"flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"}, "flex-start", nil, function(self, justifyContent) - updateLayout = true - end) - base:addProperty("Wrap", {"nowrap", "wrap"}, "nowrap", nil, function(self, wrap) - updateLayout = true - end) + 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({ - getBaseHeight = function(self) return 0 end, - getBaseWidth = function(self) return 0 end, + 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, - getFlexGrow = function(self) return 0 end, - getFlexShrink = function(self) return 0 end, - getFlexBasis = function(self) return 0 end, }) - local function sortChildren(self) - local direction = self:getDirection() - local spacing = self:getSpacing() - local wrap = self:getWrap() + lineBreakFakeObject:setFlexBasis(0):setFlexGrow(0):setFlexShrink(0) + local function sortChildren(self) if(wrap=="nowrap")then sortedChildren = {} local index = 1 @@ -117,19 +123,19 @@ return function(name, basalt) index = index + 1 sortedChildren[index] = {offset=lineOffset} else - local objSize = direction == "row" and v:getBaseWidth() or v:getBaseHeight() + 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:getBaseHeight() or v:getBaseWidth() + 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:getBaseHeight() or v:getBaseWidth() + local childHeight = direction == "row" and v:getHeight() or v:getWidth() if childHeight > lineSize then lineSize = childHeight end @@ -140,9 +146,6 @@ return function(name, basalt) local function calculateRow(self, children) local containerWidth, containerHeight = self:getSize() - local spacing = self:getSpacing() - local justifyContent = self:getJustifyContent() - local totalFlexGrow = 0 local totalFlexShrink = 0 local totalFlexBasis = 0 @@ -163,7 +166,7 @@ return function(name, basalt) local flexGrow = child:getFlexGrow() local flexShrink = child:getFlexShrink() - local baseWidth = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getBaseWidth() + local baseWidth = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getWidth() if totalFlexGrow > 0 then childWidth = baseWidth + flexGrow / totalFlexGrow * remainingSpace else @@ -231,9 +234,6 @@ return function(name, basalt) local function calculateColumn(self, children) local containerWidth, containerHeight = self:getSize() - local spacing = self:getSpacing() - local justifyContent = self:getJustifyContent() - local totalFlexGrow = 0 local totalFlexShrink = 0 local totalFlexBasis = 0 @@ -255,7 +255,7 @@ return function(name, basalt) local flexGrow = child:getFlexGrow() local flexShrink = child:getFlexShrink() - local baseHeight = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getBaseHeight() + local baseHeight = child:getFlexBasis() ~= 0 and child:getFlexBasis() or child:getHeight() if totalFlexGrow > 0 then childHeight = baseHeight + flexGrow / totalFlexGrow * remainingSpace else @@ -324,7 +324,7 @@ return function(name, basalt) local function applyLayout(self) sortChildren(self) - if self:getFlexDirection() == "row" then + if direction == "row" then for _,v in pairs(sortedChildren)do calculateRow(self, v) end @@ -337,6 +337,58 @@ return function(name, basalt) 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() @@ -378,4 +430,4 @@ return function(name, basalt) object.__index = object return setmetatable(object, base) -end \ No newline at end of file +end diff --git a/Basalt/objects/Frame.lua b/Basalt/objects/Frame.lua index c2c9847..472f488 100644 --- a/Basalt/objects/Frame.lua +++ b/Basalt/objects/Frame.lua @@ -4,19 +4,54 @@ 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) - base:setType("Frame") + local objectType = "Frame" local parent + local updateRender = true + + local xOffset, yOffset = 0, 0 + base:setSize(30, 10) - base:setZ(10) + base:setZIndex(10) - base:addProperty("XOffset", "number", 0) - base:addProperty("YOffset", "number", 0) - base:combineProperty("Offset", "XOffset", "YOffset") + 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, - local object = { 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, ...) @@ -58,7 +93,7 @@ return function(name, basalt) 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, + end, setCursor = function(self, blink, x, y, color) local obx, oby = self:getPosition() @@ -68,7 +103,7 @@ return function(name, basalt) end, } - for _,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do + 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() @@ -80,7 +115,7 @@ return function(name, basalt) end end - for _,v in pairs({"setBg", "setFg", "setText"})do + 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() diff --git a/Basalt/objects/Graph.lua b/Basalt/objects/Graph.lua index 8d13728..f6a145c 100644 --- a/Basalt/objects/Graph.lua +++ b/Basalt/objects/Graph.lua @@ -1,34 +1,102 @@ return function(name, basalt) - local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("Graph") + local base = basalt.getObject("ChangeableObject")(name, basalt) + local objectType = "Graph" - base:setZ(5) + base:setZIndex(5) base:setSize(30, 10) - base:addProperty("GraphColor", "color", colors.gray) - base:addProperty("GraphSymbol", "char", "\7") - base:addProperty("GraphSymbolColor", "color", colors.black) - base:addProperty("MaxValue", "number", 100) - base:addProperty("MinValue", "number", 0) - base:addProperty("GraphType", {"bar", "line", "scatter"}, "line") - base:addProperty("MaxEntries", "number", 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) - local minValue = self:getMinValue() - local maxValue = self:getMaxValue() if value >= minValue and value <= maxValue then table.insert(graphData, value) self:updateDraw() end - while #graphData>self:getMaxEntries() do + 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() @@ -38,14 +106,9 @@ return function(name, basalt) draw = function(self) base.draw(self) self:addDraw("graph", function() + local obx, oby = self:getPosition() local w, h = self:getSize() - local graphColor = self:getGraphColor() - local graphSymbol = self:getGraphSymbol() - local graphSymbolCol = self:getGraphSymbolColor() - local maxValue = self:getMaxValue() - local minValue = self:getMinValue() - local graphType = self:getGraphType() - local maxEntries = self:getMaxEntries() + local bgCol, fgCol = self:getBackground(), self:getForeground() local range = maxValue - minValue local prev_x, prev_y @@ -70,23 +133,23 @@ return function(name, basalt) 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 @@ -105,4 +168,4 @@ return function(name, basalt) object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/Image.lua b/Basalt/objects/Image.lua index 0db4f10..9580aa7 100644 --- a/Basalt/objects/Image.lua +++ b/Basalt/objects/Image.lua @@ -4,7 +4,7 @@ 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) - base:setType("Image") + local objectType = "Image" local bimgLibrary = bimg() local bimgFrame = bimgLibrary.getFrameObject(1) @@ -16,32 +16,30 @@ return function(name, basalt) local animTimer local usePalette = false local autoSize = true - local x, y = 1, 1 - base:addProperty("XOffset", "number", 0) - base:addProperty("YOffset", "number", 0) - base:combineProperty("Offset", "XOffset", "YOffset") + local xOffset, yOffset = 0, 0 base:setSize(24, 8) - base:setZ(2) + base:setZIndex(2) - local function getPalette() + local function getPalette(id) local p = {} for k,v in pairs(colors)do if(type(v)=="number")then - p[math.log(v, 2)] = {term.nativePaletteColor(v)} + 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] = v + p[k] = tonumber(v) end end - local localPalette = bimgFrame.getFrameData("palette") + local localPalette = bimgLibrary.getFrameData("palette") + basalt.log(localPalette) if(localPalette~=nil)then for k,v in pairs(localPalette)do - p[k] = v + p[k] = tonumber(v) end end return p @@ -56,12 +54,51 @@ return function(name, basalt) 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) @@ -298,11 +335,10 @@ return function(name, basalt) end if(usePalette)then - self:getParent():setPalette(getPalette()) + self:getParent():setPalette(getPalette(activeFrame)) end if(image~=nil)then - local xOffset, yOffset = self:getOffset() 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] diff --git a/Basalt/objects/Input.lua b/Basalt/objects/Input.lua index e6763fd..2355ac3 100644 --- a/Basalt/objects/Input.lua +++ b/Basalt/objects/Input.lua @@ -4,26 +4,21 @@ local tHex = require("tHex") return function(name, basalt) -- Input local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("Input") + local objectType = "Input" - base:setZ(5) + local inputType = "text" + local inputLimit = 0 + base:setZIndex(5) base:setValue("") base:setSize(12, 1) - local showingText = "" - - base:addProperty("defaultText", "string", "", nil, function(self, value) - showingText = value - end) - base:addProperty("defaultForeground", "color", nil) - base:addProperty("defaultBackground", "color", nil) - base:combineProperty("default", "defaultText", "defaultForeground", "defaultBackground") - base:addProperty("offset", "number", 1) - base:addProperty("cursorPosition", "number", 1) - base:addProperty("inputType", {"text", "number", "password"}, "text") - base:addProperty("inputLimit", "number", 0) - base:addProperty("align", {"left", "center", "right"}, "left") + local textX = 1 + local wIndex = 1 + local defaultText = "" + local defaultBGCol = colors.black + local defaultFGCol = colors.lightGray + local showingText = defaultText local internalValueChange = false local object = { @@ -35,13 +30,73 @@ return function(name, basalt) 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 - local textX = tostring(val):len() + 1 - local wIndex = math.max(1, textX-self:getWidth()+1) - self:setOffset(wIndex) - self:setCursorPosition(textX) + 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() @@ -52,23 +107,39 @@ return function(name, basalt) 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 defaultText = self:getDefaultText() + 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 = self:getDefaultText() - if(showingText~="")then + showingText = defaultText + if(defaultText~="")then self:updateDraw() end parent:setCursor(false) @@ -79,11 +150,9 @@ return function(name, basalt) local w,h = self:getSize() local parent = self:getParent() internalValueChange = true - local wIndex = self:getOffset() - local textX = self:getCursorPosition() if (key == keys.backspace) then -- on backspace - local text = tostring(self:getValue()) + 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) @@ -96,7 +165,7 @@ return function(name, basalt) parent:clearFocusedChild(self) end if (key == keys.right) then - local tLength = tostring(self:getValue()):len() + local tLength = tostring(base.getValue()):len() textX = textX + 1 if (textX > tLength) then @@ -120,18 +189,9 @@ return function(name, basalt) textX = math.max(textX, 1) wIndex = math.max(wIndex, 1) end - if (key == keys.home) then - -- home - textX = 1 - wIndex = 1 - end - if (key == keys["end"]) then - -- end - textX = tostring(self:getValue()):len() + 1 - wIndex = math.max(textX - w + 1, 1) - end - self:setOffset(wIndex) - self:setCursorPosition(textX) + local obx, oby = self:getPosition() + local val = tostring(base.getValue()) + self:updateDraw() internalValueChange = false return true @@ -141,12 +201,8 @@ return function(name, basalt) charHandler = function(self, char) if (base.charHandler(self, char)) then internalValueChange = true - local wIndex = self:getOffset() - local textX = self:getCursorPosition() local w,h = self:getSize() - local text = tostring(self:getValue()) - local inputType = self:getInputType() - local inputLimit = self:getInputLimit() + local text = base.getValue() if (text:len() < inputLimit or inputLimit <= 0) then if (inputType == "number") then local cache = text @@ -154,7 +210,7 @@ return function(name, basalt) 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(self:getValue()) == nil) then + if (tonumber(base.getValue()) == nil) then self:setValue(cache) textX = textX - 1 end @@ -167,9 +223,9 @@ return function(name, basalt) if (textX >= w + wIndex) then wIndex = wIndex + 1 end - self:setOffset(wIndex) - self:setCursorPosition(textX) end + local obx, oby = self:getPosition() + local val = tostring(base.getValue()) internalValueChange = false self:updateDraw() @@ -179,12 +235,12 @@ return function(name, basalt) 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 wIndex = self:getOffset() - local textX = self:getCursorPosition() + local w, h = self:getSize() textX = x - obx + wIndex - local text = tostring(self:getValue()) + local text = base.getValue() if (textX > text:len()) then textX = text:len() + 1 end @@ -194,8 +250,7 @@ return function(name, basalt) wIndex = 1 end end - self:setOffset(wIndex) - self:setCursorPosition(textX) + parent:setCursor(true, ax + textX - wIndex, ay+math.max(math.ceil(h/2-1, 1)), self:getForeground()) return true end end, @@ -212,54 +267,22 @@ return function(name, basalt) end end, - eventHandler = function(self, event, paste, ...) - base.eventHandler(self, event, paste, ...) - if(event=="paste")then - if(self:isFocused())then - local text = tostring(self:getValue()) - local textX = self:getCursorPosition() - local inputType = self:getInputType() - if (inputType == "number") then - local cache = text - if (paste == ".") or (tonumber(paste) ~= nil) then - self:setValue(text:sub(1, textX - 1) .. paste .. text:sub(textX, text:len())) - end - if (tonumber(self:getValue()) == nil) then - self:setValue(cache) - end - else - self:setValue(text:sub(1, textX - 1) .. paste .. text:sub(textX, text:len())) - end - - self:updateDraw() - end - 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 wIndex = self:getOffset() - local textX = self:getCursorPosition() - local defaultBGCol = self:getDefaultBackground() - local defaultFGCol = self:getDefaultForeground() - local inputType = self:getInputType() - - local verticalAlign = utils.getTextVerticalAlign(h, "center") + local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign) - local val = tostring(self:getValue() or "") + local val = tostring(base.getValue()) local bCol = self:getBackground() local fCol = self:getForeground() local text if (val:len() <= 0) then - if not(self:isFocused())then - text = showingText - bCol = defaultBGCol or bCol - fCol = defaultFGCol or fCol - end + text = showingText + bCol = defaultBGCol or bCol + fCol = defaultFGCol or fCol end text = showingText diff --git a/Basalt/objects/Label.lua b/Basalt/objects/Label.lua index 0441340..f25b86c 100644 --- a/Basalt/objects/Label.lua +++ b/Basalt/objects/Label.lua @@ -1,69 +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) - base:setType("Label") + local objectType = "Label" - base:setZ(3) + base:setZIndex(3) base:setSize(5, 1) + base:setBackground(false) - base:addProperty("text", "string", "Label", nil, function(self, value) - local autoSize = self:getAutoSize() - value = tostring(value) - if(autoSize)then - local t = wrapText(value, #value) - local newW, newH = 1,0 - for _,v in pairs(t)do - newH = newH + 1 - newW = math.max(newW, v:len()) - end - if(newH==0)then newH = 1 end - self:setSize(newW, newH) - self:setAutoSize(true) - end - end) - base:addProperty("autoSize", "boolean", true) - base:addProperty("textAlign", {"left", "center", "right"}, "left") + local autoSize = true + local text, textAlign = "Label", "left" local object = { - init = function(self) - base.init(self) - local parent = self:getParent() - self:setBackground(nil) - self:setForeground(parent:getForeground()) + --- 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) - self:setAutoSize(false) + 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 text = self:getText() - local textAlign = self:getTextAlign() 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 +end \ No newline at end of file diff --git a/Basalt/objects/List.lua b/Basalt/objects/List.lua index 16a18cf..1927638 100644 --- a/Basalt/objects/List.lua +++ b/Basalt/objects/List.lua @@ -3,23 +3,22 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("List") + 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:setZ(5) - - base:addProperty("SelectionBackground", "color", colors.black) - base:addProperty("SelectionForeground", "color", colors.lightGray) - base:combineProperty("SelectionColor", "SelectionBackground", "SelectionForeground") - base:addProperty("selectionColorActive", "boolean", true) - base:addProperty("textAlign", {"left", "center", "right"}, "left") - base:addProperty("scrollable", "boolean", true) - base:addProperty("offset", "number", 0) + base:setZIndex(5) local object = { init = function(self) + local parent = self:getParent() self:listenEvent("mouse_click") self:listenEvent("mouse_drag") self:listenEvent("mouse_scroll") @@ -30,6 +29,27 @@ return function(name, basalt) 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 @@ -53,6 +73,16 @@ return function(name, basalt) 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) @@ -113,29 +143,69 @@ return function(name, basalt) 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 - local scrollable = self:getScrollable() if(scrollable)then - local offset = self:getOffset() local w,h = self:getSize() - offset = offset + dir - if (offset < 0) then - offset = 0 + yOffset = yOffset + dir + if (yOffset < 0) then + yOffset = 0 end if (dir >= 1) then if (#list > h) then - if (offset > #list - h) then - offset = #list - h + if (yOffset > #list - h) then + yOffset = #list - h end - if (offset >= #list) then - offset = #list - 1 + if (yOffset >= #list) then + yOffset = #list - 1 end else - offset = offset - 1 + yOffset = yOffset - 1 end end - self:setOffset(offset) self:updateDraw() end return true @@ -148,11 +218,10 @@ return function(name, basalt) local obx, oby = self:getAbsolutePosition() local w,h = self:getSize() if (#list > 0) then - local offset = self:getOffset() for n = 1, h do - if (list[n + offset] ~= nil) then + if (list[n + yOffset] ~= nil) then if (obx <= x) and (obx + w > x) and (oby + n - 1 == y) then - self:setValue(list[n + offset]) + self:setValue(list[n + yOffset]) self:selectHandler() self:updateDraw() end @@ -189,21 +258,16 @@ return function(name, basalt) base.draw(self) self:addDraw("list", function() local w, h = self:getSize() - local offset = self:getOffset() - local selectionColorActive = self:getSelectionColorActive() - local itemSelectedBG = self:getSelectionBackground() - local itemSelectedFG = self:getSelectionForeground() - local activeObject = self:getValue() for n = 1, h do - if list[n + offset] then - local t = list[n + offset].text - local fg, bg = list[n + offset].fgCol, list[n + offset].bgCol - if list[n + offset] == activeObject and selectionColorActive then + 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:addFg(1, n, tHex[fg]:rep(w)) - self:addBg(1, n, tHex[bg]:rep(w)) + 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) diff --git a/Basalt/objects/Menubar.lua b/Basalt/objects/Menubar.lua index 4d32b7d..da2eb44 100644 --- a/Basalt/objects/Menubar.lua +++ b/Basalt/objects/Menubar.lua @@ -3,20 +3,20 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("List")(name, basalt) - base:setType("Menubar") + local objectType = "Menubar" local object = {} base:setSize(30, 1) - base:setZ(5) + base:setZIndex(5) - base:addProperty("ItemOffset", "number", 0) - base:addProperty("Space", "number", 1) + 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() - local space = base:getSpace() for n = 1, #list do mScroll = mScroll + list[n].text:len() + space * 2 end @@ -25,29 +25,52 @@ return function(name, basalt) 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() - local space = self:getSpace() - local itemOffset = self:getItemOffset() 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:selectHandler() + self:sendEvent(event, self, event, 0, x, y, list[n]) end xPos = xPos + list[n].text:len() + space * 2 end @@ -59,9 +82,7 @@ return function(name, basalt) scrollHandler = function(self, dir, x, y) if(base:getBase().scrollHandler(self, dir, x, y))then - local scrollable = self:getScrollable() if(scrollable)then - local itemOffset = self:getItemOffset() itemOffset = itemOffset + dir if (itemOffset < 0) then itemOffset = 0 @@ -72,7 +93,6 @@ return function(name, basalt) if (itemOffset > mScroll) then itemOffset = mScroll end - self:setItemOffset(itemOffset) self:updateDraw() end return true @@ -83,13 +103,12 @@ return function(name, basalt) 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() - local itemOffset = self:getItemOffset() - local space = self:getSpace() for _, v in pairs(self:getAll()) do local newItem = (" "):rep(space) .. v.text .. (" "):rep(space) text = text .. newItem diff --git a/Basalt/objects/MonitorFrame.lua b/Basalt/objects/MonitorFrame.lua index bc628af..1da103c 100644 --- a/Basalt/objects/MonitorFrame.lua +++ b/Basalt/objects/MonitorFrame.lua @@ -4,37 +4,73 @@ local max,min,sub,rep = math.max,math.min,string.sub,string.rep return function(name, basalt) local base = basalt.getObject("BaseFrame")(name, basalt) - base:setType("MonitorFrame") - - local isMonitorGroup = false - - base:addProperty("Monitor", "string|table", nil, false, function(self, value) - if(type(value)=="string")then - local mon = peripheral.wrap(value) - if(mon~=nil)then - self:setTerm(mon) - end - elseif(type(value)=="table")then - self:setTerm(value) - end - end) - - base:addProperty("MonitorGroup", "string|table", nil, false, function(self, value) - self:setTerm(basaltMon(value)) - isMonitorGroup = true - end) + 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, - local object = { 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 - local monGroup = self:getTerm() x, y = monGroup.calculateClick(monitor, x, y) end base.mouseHandler(self, btn, x, y, isMon, monitor, ...) diff --git a/Basalt/objects/MovableFrame.lua b/Basalt/objects/MovableFrame.lua index 9eb93e0..df38b43 100644 --- a/Basalt/objects/MovableFrame.lua +++ b/Basalt/objects/MovableFrame.lua @@ -2,19 +2,37 @@ local max,min,sub,rep = math.max,math.min,string.sub,string.rep return function(name, basalt) local base = basalt.getObject("Frame")(name, basalt) - base:setType("MovableFrame") + local objectType = "MovableFrame" local parent local dragXOffset, dragYOffset, isDragging = 0, 0, false - local renderThrottle = basalt.getRenderingThrottle() - base:addProperty("DraggingMap", "table", {{x1 = 1, x2 = "width", y1 = 1, y2 = 1}}) + local dragMap = { + {x1 = 1, x2 = "width", y1 = 1, y2 = 1} + } - local object = { - getBase = function(self) - return base + 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") @@ -32,10 +50,13 @@ return function(name, basalt) 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), y + dragYOffset - (parentY - 1)) + self:setPosition(x + dragXOffset - (parentX - 1) + xO, y + dragYOffset - (parentY - 1) + yO) self:updateDraw() end return true @@ -47,13 +68,10 @@ return function(name, basalt) parent:setImportant(self) local fx, fy = self:getAbsolutePosition() local w, h = self:getSize() - local dragMap = self:getDraggingMap() 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 - renderThrottle = basalt.getRenderingThrottle() - basalt.setRenderingThrottle(50) isDragging = true dragXOffset = fx - x dragYOffset = fy - y @@ -66,7 +84,6 @@ return function(name, basalt) mouseUpHandler = function(self, ...) isDragging = false - basalt.setRenderingThrottle(0) return base.mouseUpHandler(self, ...) end, diff --git a/Basalt/objects/Object.lua b/Basalt/objects/Object.lua index 5b3a6fa..ce5ec0f 100644 --- a/Basalt/objects/Object.lua +++ b/Basalt/objects/Object.lua @@ -1,6 +1,5 @@ local basaltEvent = require("basaltEvent") local utils = require("utils") -local split = utils.splitString local uuid = utils.uuid local unpack,sub = table.unpack,string.sub @@ -10,197 +9,52 @@ return function(name, basalt) assert(basalt~=nil, "Unable to find basalt instance! ID: "..name) -- Base object - local initialized = false + local objectType = "Object" -- not changeable + local isEnabled,initialized = true,false local eventSystem = basaltEvent() local registeredEvents = {} local activeEvents = {} - local properties = {} - local propertyConfig = {} - - local function defaultRule(typ) - return function(self, value) - local isValid = false - if(type(typ)=="string")then - local types = split(typ, "|") - - for _,v in pairs(types)do - if(type(value)==v)then - isValid = true - end - end - end - if(type(typ)=="table")then - for _,v in pairs(typ)do - if(v==value)then - isValid = true - end - end - end - if(typ=="color")then - if(type(value)=="string")then - if(colors[value]~=nil)then - isValid = true - value = colors[value] - end - else - for _,v in pairs(colors)do - if(v==value)then - isValid = true - end - end - end - end - if(typ=="char")then - if(type(value)=="string")then - if(#value==1)then - isValid = true - end - end - end - if(typ=="any")or(value==nil)or(type(value)=="function")then - isValid = true - end - if(typ=="string")and(type(value)~="function")then - value = tostring(value) - isValid = true - end - - if(not isValid)then - local t = type(value) - if(type(typ)=="table")then - typ = table.concat(typ, ", ") - t = value - end - error(self:getType()..": Invalid type for property "..name.."! Expected "..typ..", got "..t) - end - return value - end - end local parent - local object - - object = { + + local object = { init = function(self) if(initialized)then return false end initialized = true return true end, - isType = function(self, typ) - for k,v in pairs(properties["Type"])do - if(v==typ)then - return true - end - end - return false - end, - - getTypes = function(self) - return properties["Type"] - 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, - getProperty = function(self, name) - local prop = properties[name:gsub("^%l", string.upper)] - if(type(prop)=="function")then - return prop() - end - return prop - end, - - getProperties = function(self) - local p = {} - for k,v in pairs(properties)do - if(type(v)=="function")then - p[k] = v() - else - p[k] = v - end - end - return p - end, - - setProperty = function(self, name, value, rule) - name = name:gsub("^%l", string.upper) - if(rule~=nil)then - value = rule(self, value) - end - --if(properties[name]~=value)then - properties[name] = value - if(self.updateDraw~=nil)then - self:updateDraw() - end - --end - return self - end, - - getPropertyConfig = function(self, name) - return propertyConfig[name] - end, - - addProperty = function(self, name, typ, defaultValue, readonly, setLogic, getLogic, alteredRule) - name = name:gsub("^%l", string.upper) - propertyConfig[name] = {type=typ, defaultValue=defaultValue, readonly=readonly} - if(properties[name]~=nil)then - error("Property "..name.." in "..self:getType().." already exists!") - end - self:setProperty(name, defaultValue) - - object["get" .. name] = function(self, ...) - if(self~=nil)then - local prop = self:getProperty(name) - if(getLogic~=nil)then - return getLogic(self, prop, ...) - end - return prop - end - end - if(not readonly)then - object["set" .. name] = function(self, value, ...) - if(self~=nil)then - if(setLogic~=nil)then - local modifiedVal = setLogic(self, value, ...) - if(modifiedVal~=nil)then - value = modifiedVal - end - end - self:setProperty(name, value, alteredRule~=nil and alteredRule(typ) or defaultRule(typ)) - end - return self - end - end - return self - end, - - combineProperty = function(self, name, ...) - name = name:gsub("^%l", string.upper) - local args = {...} - object["get" .. name] = function(self) - local result = {} - for _,v in pairs(args)do - v = v:gsub("^%l", string.upper) - result[#result+1] = self["get" .. v](self) - end - return unpack(result) - end - object["set" .. name] = function(self, ...) - local values = {...} - for k,v in pairs(args)do - if(self["set"..v]~=nil)then -- if später entfernen - self["set" .. v](self, values[k]) - end - end - return self - end - return self + getParent = function(self) + return parent end, setParent = function(self, newParent, noRemove) @@ -208,15 +62,14 @@ return function(name, basalt) 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, - getParent = function(self) - return parent - end, - updateEvents = function(self) for k,v in pairs(activeEvents)do parent:removeEvent(k, self) @@ -240,18 +93,22 @@ return function(name, basalt) return self end, + getZIndex = function(self) + return 1 + end, + enable = function(self) - self:setProperty("Enabled", true) + isEnabled = true return self end, disable = function(self) - self:setProperty("Enabled", false) + isEnabled = false return self end, isEnabled = function(self) - return self:getProperty("Enabled") + return isEnabled end, remove = function(self) @@ -288,11 +145,11 @@ return function(name, basalt) registerEvent = function(self, event, func) if(parent~=nil)then - parent:addEvent(event, self) if(event=="mouse_drag")then parent:addEvent("mouse_click", self) parent:addEvent("mouse_up", self) end + parent:addEvent(event, self) end eventSystem:registerEvent(event, func) if (registeredEvents[event] == nil) then @@ -425,24 +282,6 @@ return function(name, basalt) end, } - object:addProperty("Z", "number", 1, false, function(self, value) - if (parent ~= nil) then - parent:updateZIndex(self, value) - self:updateDraw() - end - return value - end) - object:addProperty("Type", "string|table", {"Object"}, false, function(self, value) - if(type(value)=="string")then - table.insert(properties["Type"], 1, value) - return properties["Type"] - end - end, - function(self, _, depth) - return properties["Type"][depth or 1] - end) - object:addProperty("Enabled", "boolean", true) - object.__index = object return object end \ No newline at end of file diff --git a/Basalt/objects/Pane.lua b/Basalt/objects/Pane.lua index 4bf5185..9f4ec9a 100644 --- a/Basalt/objects/Pane.lua +++ b/Basalt/objects/Pane.lua @@ -1,11 +1,15 @@ return function(name, basalt) -- Pane local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("Pane") + local objectType = "Pane" base:setSize(25, 10) - local object = {} + local object = { + getType = function(self) + return objectType + end, + } object.__index = object return setmetatable(object, base) diff --git a/Basalt/objects/Program.lua b/Basalt/objects/Program.lua index 8f2a84d..32e9380 100644 --- a/Basalt/objects/Program.lua +++ b/Basalt/objects/Program.lua @@ -5,11 +5,10 @@ local sub = string.sub return function(name, basalt) local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("Program") + local objectType = "Program" local object - - base:addProperty("Path", "string", nil) - base:addProperty("Enviroment", "table", nil) + local cachedPath + local enviroment = {} local function createBasaltWindow(x, y, width, height) local xCursor, yCursor = 1, 1 @@ -347,7 +346,7 @@ return function(name, basalt) return basaltwindow end - base:setZ(5) + base:setZIndex(5) base:setSize(30, 12) local pWindow = createBasaltWindow(1, 1, 30, 12) local curProcess @@ -406,19 +405,23 @@ return function(name, basalt) 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, + end; hide = function(self) base.hide(self) pWindow.basalt_setVisible(false) return self - end, + end; setPosition = function(self, x, y, rel) base.setPosition(self, x, y, rel) @@ -428,32 +431,32 @@ return function(name, basalt) getBasaltWindow = function() return pWindow - end, + end; getBasaltProcess = function() return curProcess - end, + end; setSize = function(self, width, height, rel) base.setSize(self, width, height, rel) pWindow.basalt_resize(self:getWidth(), self:getHeight()) return self - end, + 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, ...) - local cachedPath = self:getPath() - local enviroment = self:getEnviroment() cachedPath = path or cachedPath - if(path~=nil)then - self:setPath(path) - end curProcess = process:new(cachedPath, pWindow, enviroment, ...) pWindow.setBackgroundColor(colors.black) pWindow.setTextColor(colors.white) @@ -474,7 +477,7 @@ return function(name, basalt) self:listenEvent("char", self) self:listenEvent("other_event", self) return self - end, + end; setExecute = function(self, path, ...) return self:execute(path, ...) @@ -492,7 +495,7 @@ return function(name, basalt) end parent:removeEvents(self) return self - end, + end; pause = function(self, p) paused = p or (not paused) @@ -505,11 +508,11 @@ return function(name, basalt) end end return self - end, + end; isPaused = function(self) return paused - end, + end; injectEvent = function(self, event, ign, ...) if (curProcess ~= nil) then @@ -522,16 +525,16 @@ return function(name, basalt) end end return self - end, + end; getQueuedEvents = function(self) return queuedEvent - end, + end; updateQueuedEvents = function(self, events) queuedEvent = events or queuedEvent return self - end, + end; injectEvents = function(self, ...) if (curProcess ~= nil) then @@ -542,7 +545,7 @@ return function(name, basalt) end end return self - end, + end; mouseHandler = function(self, button, x, y) if (base.mouseHandler(self, button, x, y)) then @@ -681,6 +684,10 @@ return function(name, basalt) 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, @@ -691,6 +698,7 @@ return function(name, basalt) self:registerEvent("program_error", v) end end + local parent = self:getParent() self:listenEvent("other_event") return self end, @@ -701,6 +709,7 @@ return function(name, basalt) self:registerEvent("program_done", v) end end + local parent = self:getParent() self:listenEvent("other_event") return self end, diff --git a/Basalt/objects/Progressbar.lua b/Basalt/objects/Progressbar.lua index ae0764e..6520862 100644 --- a/Basalt/objects/Progressbar.lua +++ b/Basalt/objects/Progressbar.lua @@ -1,30 +1,96 @@ return function(name, basalt) local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("ProgressBar") + local objectType = "Progressbar" - base:setZ(5) + local progress = 0 + + base:setZIndex(5) base:setValue(false) base:setSize(25, 3) - base:addProperty("Progress", "number", 0, false, function(self, value) - local progress = self:getProgress() - if (value >= 0) and (value <= 100) and (progress ~= value) then - self:setValue(progress) - if (progress == 100) then - self:progressDoneHandler() - end - return value - end - return progress - end) - base:addProperty("Direction", "number", 0) - base:addProperty("ActiveBarSymbol", "string", " ") - base:addProperty("ActiveBarColor", "color", colors.black) - base:addProperty("ActiveBarSymbolColor", "color", colors.white) - base:combineProperty("ProgressBar", "ActiveBarColor", "ActiveBarSymbol", "ActiveBarSymbolColor") - base:addProperty("BackgroundSymbol", "char", "") + 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 @@ -37,31 +103,28 @@ return function(name, basalt) draw = function(self) base.draw(self) self:addDraw("progressbar", function() + local obx, oby = self:getPosition() local w,h = self:getSize() - local p = self:getProperties() - local activeBarColor, activeBarSymbol, activeBarSymbolCol = self:getActiveBarColor(), self:getActiveBarSymbol(), self:getActiveBarSymbolColor() - activeBarColor = activeBarColor or colors.red - activeBarSymbol = activeBarSymbol or " " - activeBarSymbolCol = activeBarSymbolCol or colors.white - if(p.Background~=nil)then self:addBackgroundBox(1, 1, w, h, p.Background) end - if(p.BgSymbol~="")then self:addTextBox(1, 1, w, h, p.BgSymbol) end - if(p.Foreground~=nil)then self:addForegroundBox(1, 1, w, h, p.Foreground) end - if (p.Direction == 1) then - self:addBackgroundBox(1, 1, w, h / 100 * p.Progress, activeBarColor) - self:addForegroundBox(1, 1, w, h / 100 * p.Progress, activeBarSymbolCol) - self:addTextBox(1, 1, w, h / 100 * p.Progress, activeBarSymbol) - elseif (p.Direction == 3) then - self:addBackgroundBox(1, 1 + math.ceil(h - h / 100 * p.Progress), w, h / 100 * p.Progress, activeBarColor) - self:addForegroundBox(1, 1 + math.ceil(h - h / 100 * p.Progress), w, h / 100 * p.Progress, activeBarSymbolCol) - self:addTextBox(1, 1 + math.ceil(h - h / 100 * p.Progress), w, h / 100 * p.Progress, activeBarSymbol) - elseif (p.Direction == 2) then - self:addBackgroundBox(1 + math.ceil(w - w / 100 * p.Progress), 1, w / 100 * p.Progress, h, activeBarColor) - self:addForegroundBox(1 + math.ceil(w - w / 100 * p.Progress), 1, w / 100 * p.Progress, h, activeBarSymbolCol) - self:addTextBox(1 + math.ceil(w - w / 100 * p.Progress), 1, w / 100 * p.Progress, h, activeBarSymbol) + 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 * p.Progress), h, activeBarColor) - self:addForegroundBox(1, 1, math.ceil(w / 100 * p.Progress), h, activeBarSymbolCol) - self:addTextBox(1, 1, math.ceil(w / 100 * p.Progress), h, activeBarSymbol) + 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, @@ -70,4 +133,4 @@ return function(name, basalt) object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/Radio.lua b/Basalt/objects/Radio.lua index d314d5c..19303d1 100644 --- a/Basalt/objects/Radio.lua +++ b/Basalt/objects/Radio.lua @@ -3,26 +3,25 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("List")(name, basalt) - base:setType("Radio") + local objectType = "Radio" base:setSize(1, 1) - base:setZ(5) - - base:addProperty("BoxSelectionBG", "color", colors.black) - base:addProperty("BoxSelectionFG", "color", colors.green) - base:combineProperty("BoxSelectionColor", "BoxSelectionBG", "BoxSelectionFG") - - base:addProperty("BoxNotSelectionBG", "color", colors.black) - base:addProperty("BoxNotSelectionFG", "color", colors.red) - base:combineProperty("BoxNotSelectionColor", "BoxNotSelectionBG", "BoxNotSelectionFG") - - base:addProperty("SelectionColorActive", "boolean", true) - base:addProperty("Symbol", "char", "\7") - base:addProperty("Align", "string", { "left", "right" }, "left") + 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 }) @@ -48,6 +47,58 @@ return function(name, basalt) 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() @@ -55,7 +106,6 @@ return function(name, basalt) 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) - self:selectHandler() local val = self:sendEvent("mouse_click", self, "mouse_click", button, x, y, ...) self:updateDraw() if(val==false)then return val end @@ -69,9 +119,6 @@ return function(name, basalt) self:addDraw("radio", function() local itemSelectedBG, itemSelectedFG = self:getSelectionColor() local baseList = self:getAll() - local boxSelectedBG, boxSelectedFG = self:getBoxSelectionColor() - local boxNotSelectedBG, boxNotSelectedFG = self:getBoxNotSelectionColor() - local symbol = self:getSymbol() 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]) diff --git a/Basalt/objects/ScrollableFrame.lua b/Basalt/objects/ScrollableFrame.lua index 17db4ed..29e063c 100644 --- a/Basalt/objects/ScrollableFrame.lua +++ b/Basalt/objects/ScrollableFrame.lua @@ -1,30 +1,13 @@ local max,min,sub,rep = math.max,math.min,string.sub,string.rep -local tHex = require("tHex") - return function(name, basalt) local base = basalt.getObject("Frame")(name, basalt) - base:setType("ScrollableFrame") + local objectType = "ScrollableFrame" + local parent - base:addProperty("AutoCalculate", "boolean", true) - base:addProperty("Direction", {"vertical", "horizontal"}, "vertical") - base:addProperty("Scrollbar", "boolean", false) - base:addProperty("ScrollbarSymbolBackground", "number", colors.black) - base:addProperty("ScrollbarSymbolForeground", "number", colors.black) - base:addProperty("ScrollbarSymbol", "char", " ") - base:combineProperty("ScrollbarFront", "ScrollbarSymbol", "ScrollbarSymbolBackground", "ScrollbarSymbolForeground") - base:addProperty("ScrollbarBackgroundSymbol", "char", "\127") - base:addProperty("ScrollbarBackground", "number", colors.gray) - base:addProperty("ScrollbarForeground", "number", colors.black) - base:combineProperty("ScrollbarBack", "ScrollbarBackgroundSymbol", "ScrollbarBackground", "ScrollbarForeground") - base:addProperty("ScrollbarArrowForeground", "number", colors.lightGray) - base:addProperty("ScrollbarArrowBackground", "number", colors.black) - base:combineProperty("ScrollbarArrowColor", "ScrollbarArrowBackground", "ScrollbarArrowForeground") - - base:addProperty("ScrollAmount", "number", 0, false, function(self, value) - self:setAutoCalculate(false) - end) - base:addProperty("ScrollSpeed", "number", 1) + local direction = 0 + local manualScrollAmount = 0 + local calculateScrollAmount = true local function getHorizontalScrollAmount(self) local amount = 0 @@ -76,69 +59,54 @@ return function(name, basalt) local function scrollHandler(self, dir) local xO, yO = self:getOffset() local scrollAmn - local direction = self:getDirection() - local calculateScrollAmount = self:getAutoCalculate() - local manualScrollAmount = self:getScrollAmount() - local scrollSpeed = self:getScrollSpeed() - if(direction=="horizontal")then + if(direction==1)then scrollAmn = calculateScrollAmount and getHorizontalScrollAmount(self) or manualScrollAmount - self:setOffset(min(scrollAmn, max(0, xO + dir * scrollSpeed)), yO) - elseif(direction=="vertical")then + 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 * scrollSpeed))) + self:setOffset(xO, min(scrollAmn, max(0, yO + dir))) end self:updateDraw() end - - local function scrollWithMouse(self, x, y) - local direction = self:getDirection() - local scrollAmn - local calculateScrollAmount = self:getAutoCalculate() - local manualScrollAmount = self:getScrollAmount() - - if(direction=="horizontal") then - if(y==self:getHeight()) then - if(x>1)and(x1)and(y=scrollBarY)and(y<=scrollBarY+scrollBarHeight)then - char = fgSymbol - bg = fgColor - fg = fgFgColor - end - self:blit(width, y, char, fg, bg) - end - self:blit(width, 1, "\30", arrowFg, arrowBg) - self:blit(width, height, "\31", arrowFg, arrowBg) - elseif(p.Direction=="horizontal")then - local scrollAmount = getHorizontalScrollAmount(self) - local scrollBarWidth = max(1, math.floor(width * width / (width + scrollAmount))) - local scrollBarX = xO * (width - scrollBarWidth) / scrollAmount - - local bgSymbol, bgColor, bgFgColor = self:getScrollbarBack() - local fgSymbol, fgColor, fgFgColor = self:getScrollbarFront() - local arrowBg, arrowFg = self:getScrollbarArrowColor() - - bgColor = tHex[bgColor] - fgColor = tHex[fgColor] - bgFgColor = tHex[bgFgColor] - fgFgColor = tHex[fgFgColor] - arrowBg = tHex[arrowBg] - arrowFg = tHex[arrowFg] - - for x=2, width-1 do - local char = bgSymbol - local bg = bgColor - local fg = bgFgColor - if(x>=scrollBarX)and(x<=scrollBarX+scrollBarWidth)then - char = fgSymbol - bg = fgColor - fg = fgFgColor - end - self:blit(x, height, char, fg, bg) - end - self:blit(1, height, "\17", arrowFg, arrowBg) - self:blit(width, height, "\16", arrowFg, arrowBg) - end + self:addDraw("scrollableFrame", function() + if(calculateScrollAmount)then + scrollHandler(self, 0) end - end) + end, 0) end, } diff --git a/Basalt/objects/Scrollbar.lua b/Basalt/objects/Scrollbar.lua index 10fabc1..63ecf94 100644 --- a/Basalt/objects/Scrollbar.lua +++ b/Basalt/objects/Scrollbar.lua @@ -2,43 +2,33 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("VisualObject")(name, basalt) - base:setType("Scrollbar") + local objectType = "Scrollbar" - base:setZ(2) + base:setZIndex(2) base:setSize(1, 8) - base:setBackground(colors.lightGray, "\127", colors.black) - - base:addProperty("SymbolChar", "char", " ") - base:addProperty("SymbolBG", "color", colors.black) - base:addProperty("SymbolFG", "color", colors.black) - base:combineProperty("Symbol", "SymbolChar", "SymbolBG", "SymbolFG") - base:addProperty("SymbolAutoSize", "boolean", true) + 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() - local symbolAutoSize = base:getSymbolAutoSize() if(symbolAutoSize)then - local barType = base:getBarType() - local scrollAmount = base:getScrollAmount() - local symbol = base:getSymbolChar() - base:setSymbolSize(math.max((barType == "vertical" and h or w-(#symbol)) - (scrollAmount-1), 1)) + symbolSize = math.max((barType == "vertical" and h or w-(#symbol)) - (scrollAmount-1), 1) end end - - base:addProperty("ScrollAmount", "number", 3, false, updateSymbolSize) - base:addProperty("SymbolSize", "number", 1) - base:addProperty("BarType", {"vertical", "horizontal"}, "vertical", false, updateSymbolSize) updateSymbolSize() - local function mouseEvent(self, _, x, y) + local function mouseEvent(self, button, x, y) local obx, oby = self:getAbsolutePosition() local w,h = self:getSize() updateSymbolSize() - local barType = self:getBarType() - local symbol = self:getSymbolChar() - local symbolSize = self:getSymbolSize() 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 @@ -50,31 +40,99 @@ return function(name, basalt) 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() - local barType = self:getBarType() - local scrollAmount = self:getScrollAmount() 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) @@ -105,9 +163,6 @@ return function(name, basalt) if (index < 1) then index = 1 end - local barType = self:getBarType() - local symbol = self:getSymbolChar() - local symbolSize = self:getSymbolSize() index = math.min(index, (barType == "vertical" and h or w) - (barType == "vertical" and symbolSize - 1 or #symbol+symbolSize-2)) self:scrollbarMoveHandler() self:updateDraw() @@ -132,23 +187,24 @@ return function(name, basalt) base.customEventHandler(self, event, ...) if(event=="basalt_FrameResize")then updateSymbolSize() - end + end end, draw = function(self) base.draw(self) self:addDraw("scrollbar", function() - local p = self:getProperties() - local w, h = p.Width, p.Height - if (p.BarType == "horizontal") then + 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, p.SymbolChar:rep(p.SymbolSize), tHex[p.SymbolFG]:rep(#p.SymbolChar*p.SymbolSize), tHex[p.SymbolBG]:rep(#p.SymbolChar*p.SymbolSize)) + self:addBlit(index, 1 + n, symbol:rep(symbolSize), tHex[symbolFG]:rep(#symbol*symbolSize), tHex[symbolBG]:rep(#symbol*symbolSize)) end - elseif (p.BarType == "vertical") then + elseif (barType == "vertical") then for n = 0, h - 1 do if (index == n + 1) then - for curIndexOffset = 0, math.min(p.SymbolSize - 1, h) do - self:addBlit(1, index + curIndexOffset, p.SymbolChar:rep(math.max(#p.SymbolChar, w)), tHex[p.SymbolFG]:rep(math.max(#p.SymbolChar, w)), tHex[p.SymbolBG]:rep(math.max(#p.SymbolChar, w))) + 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 diff --git a/Basalt/objects/Slider.lua b/Basalt/objects/Slider.lua index 0dbb51b..5bc6ac0 100644 --- a/Basalt/objects/Slider.lua +++ b/Basalt/objects/Slider.lua @@ -2,29 +2,24 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("Slider") + local objectType = "Slider" base:setSize(12, 1) base:setValue(1) + base:setBackground(false, "\140", colors.black) - base:addProperty("SymbolText", "char", " ") - base:addProperty("SymbolForeground", "color", colors.black) - base:addProperty("SymbolBackground", "color", colors.gray) - base:combineProperty("Symbol", "SymbolText", "SymbolForeground", "SymbolBackground") - base:addProperty("SymbolSize", "number", 1) - base:addProperty("BarType", {"vertical", "horizontal"}, "horizontal") - base:addProperty("MaxValue", "number", 12) - + 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, _, x, y) + local function mouseEvent(self, button, x, y) local obx, oby = self:getPosition() local w,h = self:getSize() - local barType = self:getBarType() local size = barType == "vertical" and h or w - local symbolSize = self:getSymbolSize() - local symbol = self:getSymbol() - local maxValue = self:getMaxValue() 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)) @@ -35,27 +30,32 @@ return function(name, basalt) end local object = { - init = function(self) - base.init(self) - base:setBgSymbol("\140") - base:setBgSymbolColor(colors.black) - base:setBackground(nil) + 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() - local symbolSize = self:getSymbolSize() - local maxValue = self:getMaxValue() - local barType = self:getBarType() index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1)) self:setValue(maxValue / (barType == "vertical" and h or w) * index) self:updateDraw() @@ -66,6 +66,35 @@ return function(name, basalt) 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) @@ -89,9 +118,6 @@ return function(name, basalt) if (index < 1) then index = 1 end - local symbolSize = self:getSymbolSize() - local maxValue = self:getMaxValue() - local barType = self:getBarType() index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1)) self:setValue(maxValue / (barType == "vertical" and h or w) * index) self:updateDraw() @@ -105,27 +131,21 @@ return function(name, basalt) self:addDraw("slider", function() local w,h = self:getSize() local bgCol,fgCol = self:getBackground(), self:getForeground() - local symbolSize = self:getSymbolSize() - local symbol = self:getSymbolText() - local symbolFG = self:getSymbolForeground() - local symbolBG = self:getSymbolBackground() - local barType = self:getBarType() - local obx, oby = self:getPosition() 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 + 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[symbolFG], tHex[symbolFG]) + 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, " ", tHex[fgCol], tHex[bgCol]) + self:addBlit(1, 1+n, bgSymbol, tHex[fgCol], tHex[bgCol]) end end end diff --git a/Basalt/objects/Switch.lua b/Basalt/objects/Switch.lua index 1d1237d..19a7367 100644 --- a/Basalt/objects/Switch.lua +++ b/Basalt/objects/Switch.lua @@ -1,16 +1,48 @@ return function(name, basalt) local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("Switch") + local objectType = "Switch" base:setSize(4, 1) base:setValue(false) - base:setZ(5) + base:setZIndex(5) - base:addProperty("SymbolColor", "color", colors.black) - base:addProperty("ActiveBackground", "color", colors.green) - base:addProperty("InactiveBackground", "color", colors.red) + 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, @@ -26,9 +58,8 @@ return function(name, basalt) draw = function(self) base.draw(self) self:addDraw("switch", function() - local activeBG = self:getActiveBackground() - local inactiveBG = self:getInactiveBackground() - local bgSymbol = self:getSymbolColor() + 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) diff --git a/Basalt/objects/Textfield.lua b/Basalt/objects/Textfield.lua index b64d411..48e571f 100644 --- a/Basalt/objects/Textfield.lua +++ b/Basalt/objects/Textfield.lua @@ -4,7 +4,8 @@ local rep,find,gmatch,sub,len = string.rep,string.find,string.gmatch,string.sub, return function(name, basalt) local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("Textfield") + local objectType = "Textfield" + local hIndex, wIndex, textX, textY = 1, 1, 1, 1 local lines = { "" } local bgLines = { "" } @@ -14,18 +15,10 @@ return function(name, basalt) local startSelX,endSelX,startSelY,endSelY - base:addProperty("SelectionForeground", "color", colors.black) - base:addProperty("SelectionBackground", "color", colors.lightBlue) - base:combineProperty("SelectionColor", "SelectionBackground", "SelectionForeground") - base:addProperty("XOffset", "number", 1) - base:addProperty("YOffset", "number", 1) - base:combineProperty("Offset", "XOffset", "YOffset") - base:addProperty("TextXPosition", "number", 1) - base:addProperty("TextYPosition", "number", 1) - base:combineProperty("TextPosition", "TextXPosition", "TextYPosition") + local selectionBG,selectionFG = colors.lightBlue,colors.black base:setSize(30, 12) - base:setZ(5) + base:setZIndex(5) local function isSelected() if(startSelX~=nil)and(endSelX~=nil)and(startSelY~=nil)and(endSelY~=nil)then @@ -83,28 +76,11 @@ return function(name, basalt) end end - self:setTextPosition(sx, sy) + textX, textY = sx, sy startSelX, endSelX, startSelY, endSelY = nil, nil, nil, nil return self end - local function getSelectedContent(self) - local sx, ex, sy, ey = getSelectionCoordinates() - local content = {} - if isSelected() then - if sy == ey then - table.insert(content, lines[sy]:sub(sx, ex)) - else - table.insert(content, lines[sy]:sub(sx, lines[sy]:len())) - for i = sy + 1, ey - 1 do - table.insert(content, lines[i]) - end - table.insert(content, lines[ey]:sub(1, ex)) - end - end - return content - end - local function stringGetPositions(str, word) local pos = {} if(str:len()>0)then @@ -122,22 +98,8 @@ return function(name, basalt) return pos end - local function stringGetKeywordPositions(str, keyword) - local pattern = "%f[%a]"..keyword.."%f[%A]" - local positions = {} - local start, finish = str:find(pattern) - while start do - table.insert(positions, start) - table.insert(positions, finish) - start, finish = str:find(pattern, finish + 1) - end - return positions - end - - local function updateColors(self, l) - l = l or self:getTextYPosition() - if(l>#lines)then return end + 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 @@ -156,7 +118,7 @@ return function(name, basalt) end for k,v in pairs(keyWords)do for _,b in pairs(v)do - local pos = stringGetKeywordPositions(lines[l], b) + local pos = stringGetPositions(lines[l], b) if(#pos>0)then for x=1,#pos/2 do local xP = x*2 - 1 @@ -177,6 +139,10 @@ return function(name, basalt) end local object = { + getType = function(self) + return objectType + end; + setBackground = function(self, bg) base.setBackground(self, bg) updateAllColors(self) @@ -189,6 +155,32 @@ return function(name, basalt) 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, @@ -209,8 +201,7 @@ return function(name, basalt) bgLines = {""} fgLines = {""} startSelX,endSelX,startSelY,endSelY = nil,nil,nil,nil - self:setTextPosition(1, 1) - self:setOffset(1, 1) + hIndex, wIndex, textX, textY = 1, 1, 1, 1 self:updateDraw() return self end, @@ -245,18 +236,18 @@ return function(name, basalt) if(keyWords[color]==nil)then keyWords[color] = {} end - for _,v in pairs(tab)do + for k,v in pairs(tab)do table.insert(keyWords[color], v) end self:updateDraw() return self - end, + end; addRule = function(self, rule, fg, bg) table.insert(rules, {rule, fg, bg}) self:updateDraw() return self - end, + end; editRule = function(self, rule, fg, bg) for k,v in pairs(rules)do @@ -299,22 +290,40 @@ return function(name, basalt) return self end, - getLineCount = function(self) - return #lines + getTextCursor = function(self) + return textX, textY end, - getLineLength = function(self, index) - return lines[index]:len() + getOffset = function(self) + return wIndex, hIndex end, - getSelectedContent = getSelectedContent, + 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) - basalt.setRenderingThrottle(50) local obx, oby = self:getPosition() - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() self:getParent():setCursor(true, obx + textX - wIndex, oby + textY - hIndex, self:getForeground()) end, @@ -328,8 +337,6 @@ return function(name, basalt) local parent = self:getParent() local obx, oby = self:getPosition() local w,h = self:getSize() - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() if (key == keys.backspace) then -- on backspace if(isSelected())then @@ -533,8 +540,6 @@ return function(name, basalt) cursorX = 0 end parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground()) - self:setOffset(wIndex, hIndex) - self:setTextPosition(textX, textY) self:updateDraw() return true end @@ -548,9 +553,6 @@ return function(name, basalt) if(isSelected())then removeSelection(self) end - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() - 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()) @@ -575,8 +577,6 @@ return function(name, basalt) cursorX = 0 end parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground()) - self:setOffset(wIndex, hIndex) - self:setTextPosition(textX, textY) self:updateDraw() return true end @@ -588,8 +588,6 @@ return function(name, basalt) local obx, oby = self:getAbsolutePosition() local ox, oy = self:getPosition() local w,h = self:getSize() - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() if (lines[y - oby + hIndex] ~= nil) then if(x - obx + wIndex > 0)and(x - obx + wIndex <= w)then textX = x - obx + wIndex @@ -607,8 +605,6 @@ return function(name, basalt) wIndex = 1 end end - self:setOffset(wIndex, hIndex) - self:setTextPosition(textX, textY) parent:setCursor(not isSelected(), ox + textX - wIndex, oy + textY - hIndex, self:getForeground()) self:updateDraw() end @@ -623,8 +619,6 @@ return function(name, basalt) local obx, oby = self:getAbsolutePosition() local anchx, anchy = self:getPosition() local w,h = self:getSize() - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() hIndex = hIndex + dir if (hIndex > #lines - (h - 1)) then hIndex = #lines - (h - 1) @@ -634,7 +628,6 @@ return function(name, basalt) hIndex = 1 end - self:setOffset(wIndex, hIndex) 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 @@ -650,8 +643,6 @@ return function(name, basalt) local parent = self:getParent() local obx, oby = self:getAbsolutePosition() local anchx, anchy = self:getPosition() - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() if (lines[y - oby + hIndex] ~= nil) then textX = x - obx + wIndex textY = y - oby + hIndex @@ -671,8 +662,6 @@ return function(name, basalt) end self:updateDraw() end - self:setOffset(wIndex, hIndex) - self:setTextPosition(textX, textY) parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground()) return true end @@ -681,7 +670,6 @@ return function(name, basalt) mouseUpHandler = function(self, button, x, y) if (base.mouseUpHandler(self, button, x, y)) then local obx, oby = self:getAbsolutePosition() - local wIndex, hIndex = self:getOffset() if (lines[y - oby + hIndex] ~= nil) then endSelX = x - obx + wIndex endSelY = y - oby + hIndex @@ -703,11 +691,6 @@ return function(name, basalt) if(self:isFocused())then local parent = self:getParent() local fgColor, bgColor = self:getForeground(), self:getBackground() - if(isSelected())then - removeSelection(self) - end - local wIndex, hIndex = self:getOffset() - local textX, textY = self:getTextPosition() 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()) @@ -718,8 +701,6 @@ return function(name, basalt) end local anchx, anchy = self:getPosition() parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, fgColor) - self:setOffset(wIndex, hIndex) - self:setTextPosition(textX, textY) updateColors(self) self:updateDraw() end @@ -730,9 +711,9 @@ return function(name, basalt) base.draw(self) self:addDraw("textfield", function() local w, h = self:getSize() - local wIndex, hIndex = self:getOffset() - local selectionBG = self:getSelectionBackground() - local selectionFG = self:getSelectionForeground() + local bgColor = tHex[self:getBackground()] + local fgColor = tHex[self:getForeground()] + for n = 1, h do local text = "" local bg = "" @@ -744,12 +725,12 @@ return function(name, basalt) end text = sub(text, wIndex, w + wIndex - 1) - bg = sub(bg, wIndex, w + wIndex - 1) - fg = sub(fg, 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:addBG(1, n, bg) + self:addFG(1, n, fg) self:addBlit(1, n, text, fg, bg) end @@ -770,8 +751,8 @@ return function(name, basalt) 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)) + 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) @@ -790,4 +771,4 @@ return function(name, basalt) object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/Thread.lua b/Basalt/objects/Thread.lua index 64b1215..36129df 100644 --- a/Basalt/objects/Thread.lua +++ b/Basalt/objects/Thread.lua @@ -1,6 +1,7 @@ return function(name, basalt) local base = basalt.getObject("Object")(name, basalt) - base:setType("Thread") + + local objectType = "Thread" local func local cRoutine @@ -8,6 +9,10 @@ return function(name, basalt) 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") diff --git a/Basalt/objects/Timer.lua b/Basalt/objects/Timer.lua index a163464..9d2b575 100644 --- a/Basalt/objects/Timer.lua +++ b/Basalt/objects/Timer.lua @@ -1,36 +1,33 @@ return function(name, basalt) local base = basalt.getObject("Object")(name, basalt) - base:setType("Timer") - - base:addProperty("Timer", "number", 0, false, function(self, value) - if (value < 0) then - value = 0 - end - return value - end) - - base:addProperty("Repeat", "number", 1, false, function(self, value) - if(value~=nil)then - if (value < 0) then - value = 0 - end - else - value = 0 - end - return value - end) - - base:combineProperty("Time", "Timer", "Repeat") + 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 - local timer, repeatAmount = self:getTime() + repeats = savedRepeats timerObj = os.startTimer(timer) timerIsActive = true self:listenEvent("other_event") @@ -63,12 +60,10 @@ return function(name, basalt) return self end, - eventHandler = function(self, event, tObj, ...) - base.eventHandler(self, event, tObj, ...) + eventHandler = function(self, event, ...) + base.eventHandler(self, event, ...) if event == "timer" and tObj == timerObj and timerIsActive then self:sendEvent("timed_event") - local timer = self:getTimer() - local repeats = self:getRepeat() if (repeats >= 1) then repeats = repeats - 1 if (repeats >= 1) then @@ -83,4 +78,4 @@ return function(name, basalt) object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/Treeview.lua b/Basalt/objects/Treeview.lua index f2e633c..03f63aa 100644 --- a/Basalt/objects/Treeview.lua +++ b/Basalt/objects/Treeview.lua @@ -3,30 +3,18 @@ local tHex = require("tHex") return function(name, basalt) local base = basalt.getObject("ChangeableObject")(name, basalt) - base:setType("Treeview") + local objectType = "Treeview" - base:addProperty("Nodes", "table", {}) - base:addProperty("SelectionBackground", "color", colors.black) - base:addProperty("SelectionForeground", "color", colors.lightGray) - base:combineProperty("SelectionColor", "SelectionBackground", "SelectionForeground") - base:addProperty("XOffset", "number", 0) - base:addProperty("YOffset", "number", 0) - base:combineProperty("Offset", "XOffset", "YOffset") - base:addProperty("Scrollable", "boolean", true) - base:addProperty("TextAlign", {"left", "center", "right"}, "left") - base:addProperty("ExpandableSymbol", "char", "\7") - base:addProperty("ExpandableSymbolForeground", "color", colors.lightGray) - base:addProperty("ExpandableSymbolBackground", "color", colors.black) - base:combineProperty("ExpandableSymbolColor", "ExpandableSymbolForeground", "ExpandableSymbolBackground") - base:addProperty("ExpandedSymbol", "char", "\8") - base:addProperty("ExpandedSymbolForeground", "color", colors.lightGray) - base:addProperty("ExpandedSymbolBackground", "color", colors.black) - base:combineProperty("ExpandedSymbolColor", "ExpandedSymbolForeground", "ExpandedSymbolBackground") - base:addProperty("ExpandableSymbolSpacing", "number", 1) - base:addProperty("selectionColorActive", "boolean", true) + 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:setZ(5) + base:setZIndex(5) local function newNode(text, expandable) text = text or "" @@ -66,7 +54,9 @@ return function(name, basalt) end, setExpanded = function(self, exp) - expanded = exp + if(expandable)then + expanded = exp + end base:updateDraw() return node end, @@ -89,9 +79,9 @@ return function(name, basalt) onSelect(node) end end, - - setExpandable = function(self, _expandable) - expandable = _expandable + + setExpandable = function(self, expandable) + expandable = expandable base:updateDraw() return node end, @@ -139,9 +129,6 @@ return function(name, basalt) end local root = newNode("Root", true) - base:addProperty("Root", "table", root, false, function(self, value) - value.setParent(nil) - end) root:setExpanded(true) local object = { @@ -156,6 +143,91 @@ return function(name, basalt) 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 @@ -173,7 +245,7 @@ return function(name, basalt) mouseHandler = function(self, button, x, y) if base.mouseHandler(self, button, x, y) then - local currentLine = 1 - self:getYOffset() + local currentLine = 1 - yOffset local obx, oby = self:getAbsolutePosition() local w, h = self:getSize() local function checkNodeClick(node, level) @@ -207,8 +279,6 @@ return function(name, basalt) scrollHandler = function(self, dir, x, y) if base.scrollHandler(self, dir, x, y) then - local scrollable = self:getScrollable() - local yOffset = self:getYOffset() if scrollable then local _, h = self:getSize() yOffset = yOffset + dir @@ -240,7 +310,6 @@ return function(name, basalt) yOffset = yOffset - 1 end end - self:setYOffset(yOffset) self:updateDraw() end return true @@ -251,9 +320,6 @@ return function(name, basalt) draw = function(self) base.draw(self) self:addDraw("treeview", function() - local xOffset, yOffset = self:getOffset() - local itemSelectedBG self:getSelectionBackground() - local itemSelectedFG self:getSelectionForeground() local currentLine = 1 - yOffset local lastClickedNode = self:getValue() local function drawNode(node, level) @@ -281,8 +347,10 @@ return function(name, basalt) end end) end, + + } object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/VisualObject.lua b/Basalt/objects/VisualObject.lua index a3ef03d..ca572c4 100644 --- a/Basalt/objects/VisualObject.lua +++ b/Basalt/objects/VisualObject.lua @@ -3,31 +3,18 @@ local tHex = require("tHex") local sub, find, insert = string.sub, string.find, table.insert -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 - return function(name, basalt) local base = basalt.getObject("Object")(name, basalt) - base:setType("VisualObject") + -- Base object + local objectType = "VisualObject" -- not changeable - local ignOffset,isHovered,isClicked,isDragging = false,false,false,false + local isVisible,ignOffset,isHovered,isClicked,isDragging = true,false,false,false,false + local zIndex = 1 - local dragStartX, dragStartY = 0, 0 + 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 = {} @@ -36,54 +23,35 @@ return function(name, basalt) local renderObject = {} - base:addProperty("Visible", "boolean", true, false, function(self, val) - self:setProperty("Enabled", val) - end) - base:addProperty("Transparent", "boolean", false) - base:addProperty("Background", "color", colors.black) - base:addProperty("BgSymbol", "char", "") - base:addProperty("BgSymbolColor", "color", colors.red) - base:addProperty("Foreground", "color", colors.white) - base:addProperty("X", "number", 1, false, function(self, val) - local y = self:getProperty("Y") - if (parent ~= nil) then - parent:customEventHandler("basalt_FrameReposition", self, val, y) + local function split(str, d) + local result = {} + if str == "" then + return result end - self:repositionHandler(val, y) - end) - base:addProperty("Y", "number", 1, false, function(self, val) - local x = self:getProperty("X") - if (parent ~= nil) then - parent:customEventHandler("basalt_FrameReposition", self, x, val) - end - self:repositionHandler(x, val) - end) - base:addProperty("Width", "number", 1, false, function(self, val) - local height = self:getProperty("Height") - if (parent ~= nil) then - parent:customEventHandler("basalt_FrameResize", self, val, height) - end - self:resizeHandler(val, height) - end) - base:addProperty("Height", "number", 1, false, function(self, val) - local width = self:getProperty("Width") - if (parent ~= nil) then - parent:customEventHandler("basalt_FrameResize", self, width, val) - end - self:resizeHandler(width, val) - end) - base:addProperty("IgnoreOffset", "boolean", false, false) - base:combineProperty("Position", "X", "Y") - base:combineProperty("Size", "Width", "Height") + 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 - base:setProperty("Clicked", false) - base:setProperty("Hovered", false) - base:setProperty("Dragging", false) - base:setProperty("Focused", false) 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) @@ -91,22 +59,36 @@ return function(name, basalt) end, show = function(self) - self:setVisible(true) + isVisible = true + self:updateDraw() return self end, hide = function(self) - self:setVisible(false) + isVisible = false + self:updateDraw() return self end, isVisible = function(self) - return self:getVisible() + 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) - parent = newParent base.setParent(self, newParent, noRemove) + parent = newParent return self end, @@ -117,6 +99,19 @@ return function(name, basalt) 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() @@ -124,7 +119,100 @@ return function(name, basalt) 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 @@ -137,24 +225,21 @@ return function(name, basalt) return x, y end, - getRelativePosition = function(self, x, y) - if (x == nil) or (y == nil) then - x, y = 1, 1 - end + ignoreOffset = function(self, ignore) + ignOffset = ignore + if(ignore==nil)then ignOffset = true end + return self + end, - if (parent ~= nil) then - local xO, yO = self:getAbsolutePosition() - x = xO - x + 1 - y = yO - y + 1 - end - return x, y + getIgnoreOffset = function(self) + return ignOffset end, isCoordsInObject = function(self, x, y) - if(self:getVisible())and(self:getEnabled())then + 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() + local w, h = self:getSize() if (objX <= x) and (objX + w > x) and (objY <= y) and (objY + h > y) then return true end @@ -231,9 +316,7 @@ return function(name, basalt) end isClicked = true isDragging = true - self:setProperty("Dragging", true) - self:setProperty("Clicked", true) - dragStartX, dragStartY = x, y + dragStartX, dragStartY = x, y return true end end, @@ -244,8 +327,6 @@ return function(name, basalt) local objX, objY = self:getAbsolutePosition() local val = self:sendEvent("mouse_release", button, x - (objX-1), y - (objY-1), x, y) isClicked = false - self:setProperty("Clicked", false) - self:setProperty("Dragging", false) end if(self:isCoordsInObject(x, y))then local objX, objY = self:getAbsolutePosition() @@ -256,11 +337,11 @@ return function(name, basalt) end, dragHandler = function(self, button, x, y) - if(isDragging)then + 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(val==false)then return false end if(parent~=nil)then parent:setFocusedChild(self) end @@ -268,7 +349,9 @@ return function(name, basalt) end if(self:isCoordsInObject(x, y))then - dragStartX, dragStartY = x, y + local objX, objY = self:getAbsolutePosition() + dragStartX, dragStartY = x, y + dragXOffset, dragYOffset = objX - x, objY - y end end, @@ -289,19 +372,17 @@ return function(name, basalt) local val = self:sendEvent("mouse_hover", x, y, stopped) if(val==false)then return false end isHovered = true - self:setProperty("Hovered", 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 - self:setProperty("Hovered", false) end end, keyHandler = function(self, key, isHolding) - if(self:isEnabled())and(self:getVisible())then + if(self:isEnabled())and(isVisible)then if (self:isFocused()) then local val = self:sendEvent("key", key, isHolding) if(val==false)then return false end @@ -311,7 +392,7 @@ return function(name, basalt) end, keyUpHandler = function(self, key) - if(self:isEnabled())and(self:getVisible())then + if(self:isEnabled())and(isVisible)then if (self:isFocused()) then local val = self:sendEvent("key_up", key) if(val==false)then return false end @@ -321,7 +402,7 @@ return function(name, basalt) end, charHandler = function(self, char) - if(self:isEnabled())and(self:getVisible())then + if(self:isEnabled())and(isVisible)then if(self:isFocused())then local val = self:sendEvent("char", char) if(val==false)then return false end @@ -332,15 +413,12 @@ return function(name, basalt) getFocusHandler = function(self) local val = self:sendEvent("get_focus") - self:setProperty("Focused", true) if(val~=nil)then return val end return true end, loseFocusHandler = function(self) isDragging = false - self:setProperty("Dragging", false) - self:setProperty("Focused", false) local val = self:sendEvent("lose_focus") if(val~=nil)then return val end return true @@ -376,7 +454,7 @@ return function(name, basalt) 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 + if(v.name==name)then v.active = state break end @@ -397,13 +475,12 @@ return function(name, basalt) addText = function(self, x, y, text) local obj = self:getParent() or self local xPos,yPos = self:getPosition() - local transparent = self:getTransparent() 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(transparent)then + if not(transparency)then obj:setText(x+xPos-1, y+yPos-1, text) return end @@ -415,50 +492,48 @@ return function(name, basalt) end end, - addBg = function(self, x, y, bg, noText) + addBG = function(self, x, y, bg, noText) local obj = parent or self local xPos,yPos = self:getPosition() - local transparent = self:getTransparent() 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(transparent)then - obj:setBg(x+xPos-1, y+yPos-1, bg) + if not(transparency)then + obj:setBG(x+xPos-1, y+yPos-1, bg) return end local t = split(bg) - for _,v in pairs(t)do + 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) + 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, v.value) + obj:setBG(x+xPos-1, y+yPos-1, fg) end end end end, - addFg = function(self, x, y, fg) + addFG = function(self, x, y, fg) local obj = parent or self local xPos,yPos = self:getPosition() - local transparent = self:getTransparent() 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(transparent)then - obj:setFg(x+xPos-1, y+yPos-1, fg) + if not(transparency)then + obj:setFG(x+xPos-1, y+yPos-1, fg) return end local t = split(fg) - for _,v in pairs(t)do + 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) + obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value) end end end, @@ -466,32 +541,31 @@ return function(name, basalt) addBlit = function(self, x, y, t, fg, bg) local obj = parent or self local xPos,yPos = self:getPosition() - local transparent = self:getTransparent() 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(transparent)then + 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 _,v in pairs(_text)do + 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 _,v in pairs(_bg)do + 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) + obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value) end end - for _,v in pairs(_fg)do + 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) + obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value) end end end, @@ -530,7 +604,7 @@ return function(name, basalt) end, render = function(self) - if (self:getVisible())then + if (isVisible)then self:redraw() end end, @@ -557,25 +631,16 @@ return function(name, basalt) draw = function(self) self:addDraw("base", function() local w,h = self:getSize() - local bgColor = self:getBackground() - local bgSymbol = self:getBgSymbol() - local bgSymbolColor = self:getBgSymbolColor() - local fgColor = self:getForeground() - if(bgColor~=nil)then + if(bgColor~=false)then self:addTextBox(1, 1, w, h, " ") self:addBackgroundBox(1, 1, w, h, bgColor) end - if(bgSymbol~=nil)and(bgSymbol~="")then - self:addTextBox(1, 1, w, h, bgSymbol) - self:addForegroundBox(1, 1, w, h, bgSymbolColor) - end - if(fgColor~=nil)then + if(fgColor~=false)then self:addForegroundBox(1, 1, w, h, fgColor) end end, 1) end, } - object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/plugins/animations.lua b/Basalt/plugins/animations.lua index acbf426..99fe8f0 100644 --- a/Basalt/plugins/animations.lua +++ b/Basalt/plugins/animations.lua @@ -217,16 +217,10 @@ local lerp = { local XMLParser = require("xmlParser") -local animationCount = 0 -local renderThrottleCACHE - return { VisualObject = function(base, basalt) local activeAnimations = {} local defaultMode = "linear" - if(renderThrottleCACHE==nil)then - renderThrottleCACHE = basalt.getRenderingThrottle() - end local function getAnimation(self, timerId) for k,v in pairs(activeAnimations)do @@ -250,10 +244,6 @@ return { end activeAnimations[typ].finished = function() set(self, v1, v2) - animationCount = animationCount - 1 - if(animationCount==0)then - basalt.setRenderingThrottle(renderThrottleCACHE) - end if(f~=nil)then f(self) end end @@ -261,8 +251,6 @@ return { activeAnimations[typ].progress=0 activeAnimations[typ].duration=duration activeAnimations[typ].mode=mode - animationCount = animationCount + 1 - basalt.setRenderingThrottle(0) self:listenEvent("other_event") end diff --git a/Basalt/plugins/bigfonts.lua b/Basalt/plugins/bigfonts.lua index c277121..2dd01bb 100644 --- a/Basalt/plugins/bigfonts.lua +++ b/Basalt/plugins/bigfonts.lua @@ -140,11 +140,12 @@ local function makeText(nSize, sString, nFC, nBC, bBlit) end -- The following code is related to basalt and has nothing to do with bigfonts, it creates a plugin which will be added to labels: +local XMLParser = require("xmlParser") return { Label = function(base) local fontsize = 1 local bigfont - + local object = { setFontSize = function(self, newFont) if(type(newFont)=="number")then @@ -163,30 +164,51 @@ return { return self end, - setText = function(self, text) - base.setText(self, text) - if(fontsize>1)then - bigfont = makeText(fontsize-1, self:getText(), self:getForeground(), self:getBackground() or colors.lightGray) - if(self:getAutoSize())then - self:getBase():setSize(#bigfont[1][1], #bigfont[1]-1) - end - end - return self - end, - getFontSize = function(self) return fontsize end, + getSize = function(self) + local w, h = base.getSize(self) + if(fontsize>1)and(self:getAutoSize())then + return fontsize==2 and self:getText():len()*3 or math.floor(self:getText():len() * 8.5), fontsize==2 and h * 2 or math.floor(h) + else + return w, h + end + end, + + getWidth = function(self) + local w = base.getWidth(self) + if(fontsize>1)and(self:getAutoSize())then + return fontsize==2 and self:getText():len()*3 or math.floor(self:getText():len() * 8.5) + else + return w + end + end, + + getHeight = function(self) + local h = base.getHeight(self) + if(fontsize>1)and(self:getAutoSize())then + return fontsize==2 and h * 2 or math.floor(h) + else + return h + end + end, + draw = function(self) base.draw(self) self:addDraw("bigfonts", function() if(fontsize>1)then + local obx, oby = self:getPosition() + local parent = self:getParent() + local oX, oY = parent:getSize() local cX, cY = #bigfont[1][1], #bigfont[1] + obx = obx or math.floor((oX - cX) / 2) + 1 + oby = oby or math.floor((oY - cY) / 2) + 1 for i = 1, cY do - self:addFg(1, i, bigfont[2][i]) - self:addBg(1, i, bigfont[3][i]) + self:addFG(1, i, bigfont[2][i]) + self:addBG(1, i, bigfont[3][i]) self:addText(1, i, bigfont[1][i]) end end @@ -195,4 +217,4 @@ return { } return object end -} +} \ No newline at end of file diff --git a/Basalt/plugins/border.lua b/Basalt/plugins/border.lua index 3e120f5..517cd86 100644 --- a/Basalt/plugins/border.lua +++ b/Basalt/plugins/border.lua @@ -74,7 +74,7 @@ return { end if(borderColors["bottom"]~=false)and(borderColors["left"]~=false)then self:addTextBox(1, h, 1, 1, "\138") - if(bgCol~=false)then self:addForegroundBox(1, h, 1, 1, bgCol) end + if(bgCol~=false)then self:addForegroundBox(0, h, 1, 1, bgCol) end self:addBackgroundBox(1, h, 1, 1, borderColors["left"]) end end diff --git a/Basalt/plugins/debug.lua b/Basalt/plugins/debug.lua index 16d04ea..efe9e87 100644 --- a/Basalt/plugins/debug.lua +++ b/Basalt/plugins/debug.lua @@ -3,28 +3,27 @@ local wrapText = utils.wrapText return { basalt = function(basalt) - local mainFrame + local mainFrame = basalt.getMainFrame() local debugFrame local debugList local debugLabel local debugExitButton local function createDebuggingFrame() - if(mainFrame==nil)then mainFrame = basalt.getMainFrame() end local minW = 16 local minH = 6 local maxW = 99 local maxH = 99 local w, h = mainFrame:getSize() - debugFrame = mainFrame:addMovableFrame("basaltDebuggingFrame"):setSize(w-10, h-6):setBackground(colors.black):setForeground(colors.white):setZ(100):hide() - debugFrame:addPane():setSize("{parent.w}", 1):setPosition(1, 1):setBackground(colors.cyan):setForeground(colors.black) - debugFrame:setPosition(-w, h/2-debugFrame:getHeight()/2):setBorder(colors.cyan) + 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}") + :setPosition("parent.w", "parent.h") :setSize(1, 1) :setText("\133") - :setForeground(colors.black) - :setBackground(colors.cyan) + :setForeground(colors.gray) + :setBackground(colors.black) :onClick(function() end) :onDrag(function(self, event, btn, xOffset, yOffset) local w, h = debugFrame:getSize() @@ -38,21 +37,21 @@ return { 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() + 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}") + :setSize("parent.w - 2", "parent.h - 3") :setPosition(2, 3) - :setBackground(colors.black) + :setBackground(colors.gray) :setForeground(colors.white) - :setSelectionColor(colors.black, colors.white) + :setSelectionColor(colors.gray, colors.white) if(debugLabel==nil)then debugLabel = mainFrame:addLabel() - :setPosition(1, "{parent.h}") + :setPosition(1, "parent.h") :setBackground(colors.black) :setForeground(colors.white) - :setZ(100) + :setZIndex(100) :onClick(function() debugFrame:show() debugFrame:animatePosition(w/2-debugFrame:getWidth()/2, h/2-debugFrame:getHeight()/2, 0.5) diff --git a/Basalt/plugins/dynamicValues.lua b/Basalt/plugins/dynamicValues.lua index 6650e6d..7a6f3ea 100644 --- a/Basalt/plugins/dynamicValues.lua +++ b/Basalt/plugins/dynamicValues.lua @@ -1,212 +1,124 @@ -local protectedNames = {clamp=true, round=true, math=true, colors=true} -local function replace(word) - if(protectedNames[word])then return word end - if word:sub(1, 1):find('%a') and not word:find('.', 1, true) then - return '"' .. word .. '"' - end - return word -end - -local function parseString(str) - str = str:gsub("{", "") - str = str:gsub("}", "") - for k,v in pairs(colors)do - if(type(k)=="string")then - str = str:gsub("%f[%w]"..k.."%f[%W]", "colors."..k) - end - end - str = str:gsub("(%s?)([%w.]+)", function(a, b) return a .. replace(b) end) - str = str:gsub("%s?%?", " and ") - str = str:gsub("%s?:", " or ") - str = str:gsub("%.w%f[%W]", ".width") - str = str:gsub("%.h%f[%W]", ".height") - return str -end - - - -local function processString(str, env) - env.math = math - env.colors = colors - env.clamp = function(val, min, max) - return math.min(math.max(val, min), max) - end - env.round = function(val) - return math.floor(val + 0.5) - end - local f = load("return " .. str, "", nil, env) - - if(f==nil)then error(str.." - is not a valid dynamic value string") end - return f() -end - -local function dynamicValue(object, name, dynamicString, basalt) - local objectGroup = {} - local observers = {} - dynamicString = parseString(dynamicString) - local cachedValue = nil - local needsUpdate = true - - local function updateFunc() - needsUpdate = true - end - - for v in dynamicString:gmatch("%a+%.%a+")do - local name = v:gsub("%.%a+", "") - local prop = v:gsub("%a+%.", "") - if(objectGroup[name]==nil)then - objectGroup[name] = {} - end - table.insert(objectGroup[name], prop) - end - - for k,v in pairs(objectGroup) do - if(k=="self") then - for _, b in pairs(v) do - if(name~=b)then - object:addPropertyObserver(b, updateFunc) - if(b=="clicked")or(b=="dragging")then - object:listenEvent("mouse_click") - object:listenEvent("mouse_up") - end - if(b=="dragging")then - object:listenEvent("mouse_drag") - end - if(b=="hovered")then - --object:listenEvent("mouse_enter") - --object:listenEvent("mouse_exit") - end - table.insert(observers, {obj=object, name=b}) - else - error("Dynamic Values - self reference to self") - end - end - end - - if(k=="parent") then - for _, b in pairs(v) do - object:getParent():addPropertyObserver(b, updateFunc) - table.insert(observers, {obj=object:getParent(), name=b}) - end - end - - if(k~="self" and k~="parent")and(protectedNames[k]==nil)then - local obj = object:getParent():getChild(k) - for _, b in pairs(v) do - obj:addPropertyObserver(b, updateFunc) - table.insert(observers, {obj=obj, name=b}) - end - end - end - - - local function calculate() - local env = {} - local parent = object:getParent() - for k,v in pairs(objectGroup)do - local objTable = {} - - if(k=="self")then - for _,b in pairs(v)do - objTable[b] = object:getProperty(b) - end - end - - if(k=="parent")then - for _,b in pairs(v)do - objTable[b] = parent:getProperty(b) - end - end - - if(k~="self")and(k~="parent")and(protectedNames[k]==nil)then - local obj = parent:getChild(k) - if(obj==nil)then - error("Dynamic Values - unable to find object: "..k) - end - for _,b in pairs(v)do - objTable[b] = obj:getProperty(b) - end - end - env[k] = objTable - end - return processString(dynamicString, env) - end - - return { - get = function(self) - if(needsUpdate)then - cachedValue = calculate() + 0.5 - if(type(cachedValue)=="number")then - cachedValue = math.floor(cachedValue + 0.5) - end - needsUpdate = false - object:updatePropertyObservers(name) - end - return cachedValue - end, - removeObservers = function(self) - for _,v in pairs(observers)do - v.obj:removePropertyObserver(v.name, updateFunc) - end - end, - } -end +local utils = require("utils") +local count = utils.tableCount return { - Object = function(base, basalt) - local observers = {} - local activeDynValues = {} + VisualObject = function(base, basalt) + local dynObjects = {} + local curProperties = {} + local properties = {x="getX", y="getY", w="getWidth", h="getHeight"} - local function filterDynValues(self, name, value) - if(type(value)=="string")and(value:sub(1,1)=="{")and(value:sub(-1)=="}")then - if(activeDynValues[name]~=nil)then - activeDynValues[name].removeObservers() - end - activeDynValues[name] = dynamicValue(self, name, value, basalt) - value = activeDynValues[name].get - end - return value + 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 - return { - updatePropertyObservers = function(self, name) - if(observers[name]~=nil)then - for _,v in pairs(observers[name])do - v(self, name) + 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 - return self - end, + end - setProperty = function(self, name, value, rule) - value = filterDynValues(self, name, value) - base.setProperty(self, name, value, rule) - if(observers[name]~=nil)then - for _,v in pairs(observers[name])do - v(self, name) - 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 - return self - end, + end + objects["self"] = self + objects["parent"] = parent - addPropertyObserver = function(self, name, func) - name = name:gsub("^%l", string.upper) - if(observers[name]==nil)then - observers[name] = {} - end - table.insert(observers[name], func) - end, - - removePropertyObserver = function(self, name, func) - name = name:gsub("^%l", string.upper) - if(observers[name]~=nil)then - for k,v in pairs(observers[name])do - if(v==func)then - table.remove(observers[name], k) + 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 -} +} \ No newline at end of file diff --git a/Basalt/plugins/moreDrawing.lua b/Basalt/plugins/moreDrawing.lua deleted file mode 100644 index fd009ff..0000000 --- a/Basalt/plugins/moreDrawing.lua +++ /dev/null @@ -1,321 +0,0 @@ -local tHex = require("tHex") - -local function line(x1, y1, x2, y2) - local points = {} - local dx = math.abs(x2 - x1) - local dy = math.abs(y2 - y1) - local sx = (x1 < x2) and 1 or -1 - local sy = (y1 < y2) and 1 or -1 - local err = dx - dy - - while true do - table.insert(points, {x = x1, y = y1}) - - if (x1 == x2 and y1 == y2) then break end - local e2 = err * 2 - if e2 > -dy then - err = err - dy - x1 = x1 + sx - end - if e2 < dx then - err = err + dx - y1 = y1 + sy - end - end - return points -end - -local function circle(xPos, yPos, radius, filled) - local points = {} - - local function plotPoints(xc, yc, x, y) - table.insert(points, {x = xc + x, y = yc + y}) - table.insert(points, {x = xc - x, y = yc + y}) - table.insert(points, {x = xc + x, y = yc - y}) - table.insert(points, {x = xc - x, y = yc - y}) - table.insert(points, {x = xc + y, y = yc + x}) - table.insert(points, {x = xc - y, y = yc + x}) - table.insert(points, {x = xc + y, y = yc - x}) - table.insert(points, {x = xc - y, y = yc - x}) - end - - local function fillPoints(xc, yc, x, y) - for fillX = -x, x do - table.insert(points, {x = xc + fillX, y = yc + y}) - table.insert(points, {x = xc + fillX, y = yc - y}) - end - for fillY = -y, y do - table.insert(points, {x = xc + fillY, y = yc + x}) - table.insert(points, {x = xc + fillY, y = yc - x}) - end - end - - local x = 0 - local y = radius - local d = 3 - 2 * radius - - if filled then - fillPoints(xPos, yPos, x, y) - else - plotPoints(xPos, yPos, x, y) - end - - while y >= x do - x = x + 1 - - if d > 0 then - y = y - 1 - d = d + 4 * (x - y) + 10 - else - d = d + 4 * x + 6 - end - - if filled then - fillPoints(xPos, yPos, x, y) - else - plotPoints(xPos, yPos, x, y) - end - end - - return points -end - -local function ellipse(xPos, yPos, radiusX, radiusY, filled) - local points = {} - local function plotPoints(xc, yc, x, y) - table.insert(points, {x = xc + x, y = yc + y}) - table.insert(points, {x = xc - x, y = yc + y}) - table.insert(points, {x = xc + x, y = yc - y}) - table.insert(points, {x = xc - x, y = yc - y}) - end - - local function fillPoints(xc, yc, x, y) - for fillX = -x, x do - table.insert(points, {x = xc + fillX, y = yc + y}) - table.insert(points, {x = xc + fillX, y = yc - y}) - end - end - - local x = 0 - local y = radiusY - local d1 = (radiusY * radiusY) - (radiusX * radiusX * radiusY) + (0.25 * radiusX * radiusX) - - plotPoints(xPos, yPos, x, y) - - while ((radiusX * radiusX * (y - 0.5)) > (radiusY * radiusY * (x + 1))) do - if (d1 < 0) then - d1 = d1 + (2 * radiusY * radiusY * x) + (3 * radiusY * radiusY) - else - d1 = d1 + (2 * radiusY * radiusY * x) - (2 * radiusX * radiusX * y) + (2 * radiusX * radiusX) - y = y - 1 - end - x = x + 1 - if filled then fillPoints(xPos, yPos, x, y) end - end - - local d2 = ((radiusY * radiusY) * ((x + 0.5) * (x + 0.5))) + ((radiusX * radiusX) * ((y - 1) * (y - 1))) - (radiusX * radiusX * radiusY * radiusY) - - while y > 0 do - y = y - 1 - if d2 < 0 then - d2 = d2 + (2 * radiusY * radiusY * x) - (2 * radiusX * radiusX * y) + (radiusX * radiusX) - x = x + 1 - else - d2 = d2 - (2 * radiusX * radiusX * y) + (radiusX * radiusX) - end - if filled then fillPoints(xPos, yPos, x, y) end - end - return points -end - -local function polygon(points, filled) - local newPoints = {} - - local pointsCopy = {} - for i, point in ipairs(points) do - table.insert(pointsCopy, {x = point.x, y = point.y}) - end - if pointsCopy[1].x ~= pointsCopy[#pointsCopy].x or pointsCopy[1].y ~= pointsCopy[#pointsCopy].y then - table.insert(pointsCopy, {x = pointsCopy[1].x, y = pointsCopy[1].y}) - end - - local lines = {} - for i = 1, #pointsCopy - 1 do - local linePoints = line(pointsCopy[i].x, pointsCopy[i].y, pointsCopy[i+1].x, pointsCopy[i+1].y) - for _, point in ipairs(linePoints) do - table.insert(lines, point) - end - end - - if filled then - local minX, maxX, minY, maxY = math.huge, -math.huge, math.huge, -math.huge - for _, point in ipairs(pointsCopy) do - minX = math.min(minX, point.x) - maxX = math.max(maxX, point.x) - minY = math.min(minY, point.y) - maxY = math.max(maxY, point.y) - end - - local fillPoints = {} - for y = minY, maxY do - for x = minX, maxX do - local numCrossings = 0 - for i = 1, #pointsCopy - 1 do - if ((pointsCopy[i].y > y) ~= (pointsCopy[i+1].y > y)) and - (x < (pointsCopy[i+1].x - pointsCopy[i].x) * (y - pointsCopy[i].y) / - (pointsCopy[i+1].y - pointsCopy[i].y) + pointsCopy[i].x) then - numCrossings = numCrossings + 1 - end - end - if numCrossings % 2 == 1 then - table.insert(fillPoints, {x = x, y = y}) - end - end - end - return fillPoints - end - return lines -end - -local function rectangle(xPos, yPos, width, height, filled) - local points = {} - - if filled then - for y = yPos, yPos + height - 1 do - for x = xPos, xPos + width - 1 do - table.insert(points, {x = x, y = y}) - end - end - else - for x = xPos, xPos + width - 1 do - table.insert(points, {x = x, y = yPos}) - table.insert(points, {x = x, y = yPos + height - 1}) - end - for y = yPos, yPos + height - 1 do - table.insert(points, {x = xPos, y = y}) - table.insert(points, {x = xPos + width - 1, y = y}) - end - end - return points -end - -local rep,sub = string.rep, string.sub - -return { - VisualObject = function(base) - local object = {} - - for _,v in pairs({"Text", "Bg", "Fg"})do - object["add"..v.."Line"] = function(self, x1, y1, x2, y2, val) - if(type(val)=="number")then - val = tHex[val] - end - if(#val>1)then - val = sub(val, 1, 1) - end - local points = line(x1, y1, x2, y2) - for _,point in ipairs(points)do - self["add"..v](self, point.x, point.y, val) - end - return self - end - - object["add"..v.."Circle"] = function(self, xPos, yPos, radius, filled, val) - if(type(val)=="number")then - val = tHex[val] - end - if(#val>1)then - val = sub(val, 1, 1) - end - - local points = circle(xPos, yPos, radius, filled) - - for _,point in ipairs(points)do - self["add"..v](self, point.x, point.y, val) - end - return self - end - - object["add"..v.."Ellipse"] = function(self, xPos, yPos, radiusX, radiusY, filled, val) - if(type(val)=="number")then - val = tHex[val] - end - if(#val>1)then - val = sub(val, 1, 1) - end - - local points = ellipse(xPos, yPos, radiusX, radiusY, filled) - for _,point in ipairs(points)do - self["add"..v](self, point.x, point.y, val) - end - return self - end - - object["add"..v.."Polygon"] = function(self, points, filled, val) - if(type(val)=="number")then - val = tHex[val] - end - if(#val>1)then - val = sub(val, 1 ,1) - end - local newPoints = polygon(points, filled) - for _,point in ipairs(newPoints)do - self["add"..v](self, point.x, point.y, val) - end - return self - end - - object["add"..v.."Rectangle"] = function(self, xPos, yPos, width, height, filled, val) - if(type(val)=="number")then - val = tHex[val] - end - if(#val>1)then - val = sub(val, 1, 1) - end - local points = rectangle(xPos, yPos, width, height, filled) - for _,point in ipairs(points)do - self["add"..v](self, point.x, point.y, val) - end - return self - end - end - - --[[ - function object.addInlineBorder(self, x, y, width, height, color, bg) - self:addTextBox(x, y, 1, h, "\149") - self:addBackgroundBox(x, y, 1, h, bgCol) - self:addForegroundBox(x, y, 1, h, borderColors["left"]) - - - self:addTextBox(x, y, x+width-1, 1, "\131") - self:addBackgroundBox(x, y, x+width-1, 1, bgCol) - self:addForegroundBox(x, y, x+width-1, 1, borderColors["top"]) - - self:addTextBox(x, y, 1, 1, "\151") - self:addBackgroundBox(x, y, 1, 1, bgCol) - self:addForegroundBox(x, y, 1, 1, borderColors["left"]) - - self:addTextBox(x+width-1, 1, 1, h, "\149") - self:addForegroundBox(x+width-1, 1, 1, h, bgCol) - self:addBackgroundBox(x+width-1, 1, 1, h, borderColors["right"]) - - self:addTextBox(1, h, x+width-1, 1, "\143") - self:addForegroundBox(1, h, x+width-1, 1, bgCol) - self:addBackgroundBox(1, h, x+width-1, 1, borderColors["bottom"]) - - self:addTextBox(x+width-1, 1, 1, 1, "\148") - self:addForegroundBox(x+width-1, 1, 1, 1, bgCol) - self:addBackgroundBox(x+width-1, 1, 1, 1, borderColors["right"]) - - self:addTextBox(x+width-1, h, 1, 1, "\133") - self:addForegroundBox(x+width-1, h, 1, 1, bgCol) - self:addBackgroundBox(x+width-1, h, 1, 1, borderColors["right"]) - - self:addTextBox(1, h, 1, 1, "\138") - self:addForegroundBox(1, h, 1, 1, bgCol) - self:addBackgroundBox(1, h, 1, 1, borderColors["left"]) - end]] - - return object - end -} \ No newline at end of file diff --git a/Basalt/plugins/pixelbox.lua b/Basalt/plugins/pixelbox.lua index e1863b0..32567af 100644 --- a/Basalt/plugins/pixelbox.lua +++ b/Basalt/plugins/pixelbox.lua @@ -5,11 +5,11 @@ 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: +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. +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 diff --git a/Basalt/plugins/reactive.lua b/Basalt/plugins/reactive.lua new file mode 100644 index 0000000..85f58fb --- /dev/null +++ b/Basalt/plugins/reactive.lua @@ -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 +} \ No newline at end of file diff --git a/Basalt/plugins/reactiveXml.lua b/Basalt/plugins/reactiveXml.lua deleted file mode 100644 index f18e4f8..0000000 --- a/Basalt/plugins/reactiveXml.lua +++ /dev/null @@ -1,142 +0,0 @@ -local Reactive = require("reactivePrimitives") -local XMLParser = require("xmlParser") - -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(function() - Reactive.transaction(load(script, nil, "t", env)) - end) - if not success then - error("XML Error: "..msg) - end - end) -end - -return { - basalt = function(basalt) - local object = { - observable = Reactive.observable, - derived = Reactive.derived, - effect = Reactive.effect, - transaction = Reactive.transaction, - untracked = Reactive.untracked, - - 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, - - 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 - Reactive.effect(function() - local value = load("return " .. expression, nil, "t", env)() - if(colors[value]~=nil)then value = colors[value] end - object:setProperty(attribute, value) - end) - 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, - - 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 - Reactive.transaction(function() - executeScript(layout.script, env) - end) - end - local objects = {} - for _, node in ipairs(layout.nodes) do - local _objects = basalt.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 -} \ No newline at end of file diff --git a/Basalt/plugins/shadow.lua b/Basalt/plugins/shadow.lua index d249fe4..d807f2d 100644 --- a/Basalt/plugins/shadow.lua +++ b/Basalt/plugins/shadow.lua @@ -1,3 +1,5 @@ +local XMLParser = require("xmlParser") + return { VisualObject = function(base) local shadow = false diff --git a/Basalt/plugins/templates.lua b/Basalt/plugins/templates.lua deleted file mode 100644 index 5f43734..0000000 --- a/Basalt/plugins/templates.lua +++ /dev/null @@ -1,132 +0,0 @@ -local split = require("utils").splitString - -local function copy(t) - local new = {} - for k,v in pairs(t)do - new[k] = v - end - return new -end - -local plugin = { - VisualObject = function(base, basalt) - return { - __getElementPathTypes = function(self, types) - if(types~=nil)then - table.insert(types, 1, self:getTypes()) - else - types = {self:getTypes()} - end - local parent = self:getParent() - if(parent~=nil)then - return parent:__getElementPathTypes(types) - else - return types - end - end, - - init = function(self) - base.init(self) - local template = basalt.getTemplate(self) - local objects = basalt.getObjects() - if(template~=nil)then - for k,v in pairs(template)do - if(objects[k]==nil)then - if(colors[v]~=nil)then - self:setProperty(k, colors[v]) - else - self:setProperty(k, v) - end - end - end - end - return self - end, - } - end, - - basalt = function() - local baseTemplate = { - default = { - Background = colors.gray, - Foreground = colors.black, - }, - BaseFrame = { - Background = colors.lightGray, - Foreground = colors.black, - Button = { - Background = "{self.clicked ? black : gray}", - Foreground = "{self.clicked ? lightGray : black}" - }, - Container = { - Background = colors.gray, - Foreground = colors.black, - Button = { - Background = "{self.clicked ? lightGray : black}", - Foreground = "{self.clicked ? black : lightGray}" - }, - }, - Checkbox = { - Background = colors.gray, - Foreground = colors.black, - Text = "Checkbox" - }, - Input = { - Background = "{self.focused ? gray : black}", - Foreground = "{self.focused ? black : lightGray}", - }, - }, - } - - local function addTemplate(newTemplate) - if(type(newTemplate)=="string")then - local file = fs.open(newTemplate, "r") - if(file~=nil)then - local data = file.readAll() - file.close() - baseTemplate = textutils.unserializeJSON(data) - else - error("Could not open template file "..newTemplate) - end - end - if(type(newTemplate)=="table")then - for k,v in pairs(newTemplate)do - baseTemplate[k] = v - end - end - end - - local function lookUpTemplate(template, allTypes) - local elementData = copy(baseTemplate.default) - local tLink = template - if(tLink~=nil)then - for _, v in pairs(allTypes)do - for _, b in pairs(v)do - if(tLink[b]~=nil)then - tLink = tLink[b] - for k, v in pairs(tLink) do - elementData[k] = v - end - break - else - for k, v in pairs(baseTemplate.default) do - elementData[k] = v - end - end - end - end - end - return elementData - end - - return { - getTemplate = function(element) - return lookUpTemplate(baseTemplate, element:__getElementPathTypes()) - end, - - addTemplate = addTemplate, - } - end -} - -return plugin \ No newline at end of file diff --git a/Basalt/plugins/textures.lua b/Basalt/plugins/textures.lua index 63ffeec..2e7d953 100644 --- a/Basalt/plugins/textures.lua +++ b/Basalt/plugins/textures.lua @@ -1,87 +1,58 @@ local images = require("images") - -local sub = string.sub - +local utils = require("utils") +local XMLParser = require("xmlParser") return { VisualObject = function(base) - local images = {} + local textureId, infinitePlay = 1, true + local bimg, texture, textureTimerId + local textureMode = "default" local object = { - addTexture = function(self, path, x, y, w, h, stretch, animate, infinitePlay) - if(type(path)=="function")then - table.insert(images, path) - else - if(type(path)=="table")then - x, y, w, h, stretch, animate, infinitePlay = path.x, path.y, path.w, path.h, path.stretch, path.animate, path.infinitePlay - path = path.path - end - local img = images.loadImageAsBimg(path) - local newEntry = { - image = img, - x = x, - y = y, - w = w, - h = h, - animated = animate, - curTextId = 1, - infinitePlay = infinitePlay, - } - if(stretch)then - newEntry.w = self:getWidth() - newEntry.h = self:getHeight() - newEntry.image = images.resizeBIMG(img, newEntry.w, newEntry.h) - end - table.insert(images, newEntry) - if(animate)then - if(img.animated)then - self:listenEvent("other_event") - local t = img[newEntry.curTextId].duration or img.secondsPerFrame or 0.2 - newEntry.timer = os.startTimer(t) - end + 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, - removeTexture = function(self, id) - table.remove(images, id) - if(#images==0)then - self:setDrawState("texture-base", false) - end + setTextureMode = function(self, mode) + textureMode = mode or textureMode self:updateDraw() return self end, - clearTextures = function(self) - images = {} - self:setDrawState("texture-base", false) - self:updateDraw() + setInfinitePlay = function(self, state) + infinitePlay = state return self end, eventHandler = function(self, event, timerId, ...) base.eventHandler(self, event, timerId, ...) if(event=="timer")then - for _,v in pairs(images)do - if(type(v)=="table")then - if(v.timer==timerId)then - if(v.animated)then - if(v.image[v.curTextId+1]~=nil)then - v.curTextId = v.curTextId + 1 - local t = v.image[v.curTextId].duration or v.image.secondsPerFrame or 0.2 - v.timer = os.startTimer(t) - self:updateDraw() - else - if(v.infinitePlay)then - v.curTextId = 1 - local t = v.image[v.curTextId].duration or v.image.secondsPerFrame or 0.2 - v.timer = os.startTimer(t) - self:updateDraw() - end - end - end + 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 @@ -91,25 +62,50 @@ return { draw = function(self) base.draw(self) self:addDraw("texture-base", function() - for _,v in pairs(images)do - if(type(v)=="table")then - local tWidth = #v.image[v.curTextId][1][1] - local tHeight = #v.image[v.curTextId][1] - local textureWidth = v.w>tWidth and tWidth or v.w - local textureHeight = v.h>tHeight and tHeight or v.h - for k = 1, textureHeight do - if(v.image[k]~=nil)then - local t, f, b = table.unpack(v.image[k]) - self:addBlit(1, k, sub(t, 1, textureWidth), sub(f, 1, textureWidth), sub(b, 1, textureWidth)) - end - end - else - if(type(v)=="function")then - v(self) - end + 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) + end, 1) self:setDrawState("texture-base", false) end } diff --git a/docs/_footer.md b/docs/_footer.md index d381de8..2ffd2d1 100644 --- a/docs/_footer.md +++ b/docs/_footer.md @@ -1,3 +1,3 @@ --- -Thanks for checking out our wiki, join our discord for more help: [discord.gg/yM7kndJdJJ](discord.gg/yNNnmBVBpE) +Thanks for checking out our wiki, join our discord for more help: [https://discord.gg/yM7kndJdJJ](discord.gg/yNNnmBVBpE) diff --git a/docs/_sidebar.md b/docs/_sidebar.md index c76fcc5..8e88709 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -37,5 +37,4 @@ - [Timer](objects/Timer.md) - Guides - [Introduction to Basalt](guides/introduction.md) - - [Dynamic Values](guides/dynamicvalues.md) - - [XML](guides/xml.md) + diff --git a/docs/objects/Basalt.md b/docs/objects/Basalt.md index cc32d8e..bf4a9e1 100644 --- a/docs/objects/Basalt.md +++ b/docs/objects/Basalt.md @@ -21,7 +21,7 @@ You are now able to access the following list of methods: |[getVersion](objects/Basalt/getVersion.md)|Returns the Basalt version |[isKeyDown](objects/Basalt/isKeyDown.md)|Returns if the key is held down |[log](objects/Basalt/log.md)|Writes something into the log file -|[memory](objects/Basalt/log.md)|Returns the current memory usage of Basalt +|[memory](objects/Basalt/memory.md)|Returns the current memory usage of Basalt |[onEvent](objects/Basalt/onEvent.md)|Event listener |[removeFrame](objects/Basalt/removeFrame.md)|Removes a previously created base frame |[schedule](objects/Basalt/schedule.md)|Schedules a new task @@ -29,7 +29,7 @@ You are now able to access the following list of methods: |[setTheme](objects/Basalt/setTheme.md)|Changes the base theme of basalt |[setMouseDragThrottle](objects/Basalt/setMouseDragThrottle.md)|Changes the mouse drag throttle amount |[setMouseMoveThrottle](objects/Basalt/setMouseMoveThrottle.md)|CraftOS-PC: Changes the mouse move throttle amount -|[setRenderingThrottle](objects/Basalt/setMouseMoveThrottle.md)|Sets the rendering throttle amount +|[setRenderingThrottle](objects/Basalt/setRenderingThrottle.md)|Sets the rendering throttle amount |[setVariable](objects/Basalt/setVariable.md)|Sets a variable which you can access via XML |[stopUpdate / stop](objects/Basalt/stopUpdate.md)|Stops the currently active event and draw listener |[update](objects/Basalt/update.md)|Starts the event and draw listener once diff --git a/docs/objects/BaseFrame/setOffset.md b/docs/objects/BaseFrame/setOffset.md index 08c56e0..c823460 100644 --- a/docs/objects/BaseFrame/setOffset.md +++ b/docs/objects/BaseFrame/setOffset.md @@ -11,8 +11,7 @@ Sets the frame's offset, this offset is beeing used to move all children object' ### Returns -1. `number` x position -2. `number` y position +1. `object` The object in use ### Usage diff --git a/docs/objects/Checkbox.md b/docs/objects/Checkbox.md index 3799940..275d68c 100644 --- a/docs/objects/Checkbox.md +++ b/docs/objects/Checkbox.md @@ -1,6 +1,6 @@ -The Checkbox object is derived from the VisualObject class and allows users to set a boolean value to true or false by clicking on it. Checkboxes are commonly used in forms and settings to enable or disable specific options. +The Checkbox object is derived from the ChangeableObject class and allows users to set a boolean value to true or false by clicking on it. Checkboxes are commonly used in forms and settings to enable or disable specific options. -In addition to the Object and VisualObject methods, checkboxes also have the following method: +In addition to the Object, VisualObject and ChangeableObject methods, checkboxes also have the following method: | | | |---|---| diff --git a/docs/objects/Container/setImportant.md b/docs/objects/Container/setImportant.md index 5c6c3dc..0b05b05 100644 --- a/docs/objects/Container/setImportant.md +++ b/docs/objects/Container/setImportant.md @@ -6,7 +6,7 @@ Sets the specified object as "important" within the container. This means the ob ### Parameters -1. `string` The object to set as important +1. `string|object` The object ID or object to set as important ### Returns diff --git a/docs/objects/Container/updateZIndex.md b/docs/objects/Container/updateZIndex.md index bd24a7a..10daffb 100644 --- a/docs/objects/Container/updateZIndex.md +++ b/docs/objects/Container/updateZIndex.md @@ -1,4 +1,4 @@ -## setFocusedObject +## updateZIndex ### Description diff --git a/docs/objects/Image/blit.md b/docs/objects/Image/blit.md new file mode 100644 index 0000000..8de3995 --- /dev/null +++ b/docs/objects/Image/blit.md @@ -0,0 +1,27 @@ +## blit + +### Description + +Sets or modifies text, foreground and background color. + +### Parameters + +1. `string` text - The text to be placed at the specified position +1. `string` foreground - A string representing the foreground color +1. `string` background - A string representing the background color +2. `number` x - The x-coordinate of the text position. +3. `number` y - The y-coordinate of the text position. + +### Returns + +1. `object` The object in use + +### Usage + +* Creates a new image object, adds a frame, and sets the text in the active frame. + +```lua +local mainFrame = basalt.createFrame() +local aImage = mainFrame:addImage():addFrame():blit("Hello", "fffff", "00000", 1, 1) + +``` diff --git a/docs/objects/Input/getOffset.md b/docs/objects/Input/getOffset.md new file mode 100644 index 0000000..2941aab --- /dev/null +++ b/docs/objects/Input/getOffset.md @@ -0,0 +1,9 @@ +## getOffset + +### Description + +Returns the current offset + +### Returns + +1. `number` the offset diff --git a/docs/objects/Input/getTextOffset.md b/docs/objects/Input/getTextOffset.md new file mode 100644 index 0000000..a5e689a --- /dev/null +++ b/docs/objects/Input/getTextOffset.md @@ -0,0 +1,9 @@ +## getTextOffset + +### Description + +Returns the current text offset + +### Returns + +1. `number` the text offset diff --git a/docs/objects/Input/setOffset.md b/docs/objects/Input/setOffset.md new file mode 100644 index 0000000..397cc84 --- /dev/null +++ b/docs/objects/Input/setOffset.md @@ -0,0 +1,22 @@ +## setOffset + +### Description + +Sets the input offset + +### Parameters + +1. `number` offset - The offset you want it to be + +### Returns + +1. `object` The object in use + +### Usage + +* Creates a default input and changes the offset to 2 + +```lua +local mainFrame = basalt.createFrame() +local aInput = mainFrame:addInput():setOffset(2) +``` \ No newline at end of file diff --git a/docs/objects/Input/setTextOffset.md b/docs/objects/Input/setTextOffset.md new file mode 100644 index 0000000..07ca4e5 --- /dev/null +++ b/docs/objects/Input/setTextOffset.md @@ -0,0 +1,22 @@ +## setTextOffset + +### Description + +Sets the input text offset + +### Parameters + +1. `number` text offset - The offset you want it to be + +### Returns + +1. `object` The object in use + +### Usage + +* Creates a default input and changes the text offset to 2 + +```lua +local mainFrame = basalt.createFrame() +local aInput = mainFrame:addInput():setTextOffset(2) +``` \ No newline at end of file diff --git a/docs/objects/Label.md b/docs/objects/Label.md index 8683304..4fa42d4 100644 --- a/docs/objects/Label.md +++ b/docs/objects/Label.md @@ -2,7 +2,6 @@ A Label object is used to display simple text on the interface. In addition to the Object and VisualObject methods, Label objects have the following methods: -[Object](objects/Object.md) methods also apply for labels. | | | |---|---| diff --git a/docs/objects/Textfield.md b/docs/objects/Textfield.md index c28f3f1..ac12b4d 100644 --- a/docs/objects/Textfield.md +++ b/docs/objects/Textfield.md @@ -12,13 +12,13 @@ In addition to the Object and VisualObject methods, Textfield objects have the f |[getTextCursor](objects/Textfield/getTextCursor.md)|Returns the current text cursor position |[addKeywords](objects/Textfield/addKeywords.md)|Adds syntax highlighting keywords |[addRule](objects/Textfield/addRule.md)|Adds a custom syntax highlighting rule -|[editRule](objects/Textfield/addRule.md)|Edits an existing syntax highlighting rule -|[removeRule](objects/Textfield/addRule.md)|Removes an existing syntax highlighting rule -|[getOffset](objects/Textfield/addRule.md)|Returns the current offset inside the Textfield -|[setOffset](objects/Textfield/addRule.md)|Changes the offset inside the Textfield -|[clear](objects/Textfield/addRule.md)|Clears the Textfield content -|[setSelection](objects/Textfield/addRule.md)|Sets the selection color (text color and background color) -|[getSelection](objects/Textfield/addRule.md)|Returns the current selection color +|[editRule](objects/Textfield/editRule.md)|Edits an existing syntax highlighting rule +|[removeRule](objects/Textfield/removeRule.md)|Removes an existing syntax highlighting rule +|[getOffset](objects/Textfield/getOffset.md)|Returns the current offset inside the Textfield +|[setOffset](objects/Textfield/setOffset.md)|Changes the offset inside the Textfield +|[clear](objects/Textfield/clear.md)|Clears the Textfield content +|[setSelection](objects/Textfield/setSelection.md)|Sets the selection color (text color and background color) +|[getSelection](objects/Textfield/getSelection.md)|Returns the current selection color In version 1.7, Textfields now allow the user to select text with the mouse. The setSelection method is used to choose the text color and background color for selected text. diff --git a/docs/objects/Textfield/clear.md b/docs/objects/Textfield/clear.md new file mode 100644 index 0000000..af946fb --- /dev/null +++ b/docs/objects/Textfield/clear.md @@ -0,0 +1,23 @@ +## clear + +### Description + +Clears the entire content of a Textfield object, removing all text currently displayed within it. + +### Returns + +1. `object ` The object in use + +### Usage + +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame() +local aTextfield = mainFrame:addTextfield() + +-- Assume there is some content in the Textfield +aTextfield:clear() -- Clear the entire content + +basalt.autoUpdate() +``` diff --git a/docs/objects/Textfield/editRule.md b/docs/objects/Textfield/editRule.md new file mode 100644 index 0000000..00786c0 --- /dev/null +++ b/docs/objects/Textfield/editRule.md @@ -0,0 +1,30 @@ +## addRule + +### Description + +Edits an existing rule for special coloring in a Textfield object. This allows you to modify the color and/or background color applied to text matching a specific pattern. + +### Parameteres + +1. `string` pattern - The Lua pattern used to match the text you want to edit the coloring for. +2. `number|color` textColor - The new color you want to apply to the text matching the pattern. +3. `number|color` backgroundColor - (optional) The new background color you want to apply to the text matching the pattern. + +### Returns + +1. `object` The object in use + +### Usage + +* Modifies the color of all numbers in a Textfield object. + +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame() +local aTextfield = mainFrame:addTextfield() + +aTextfield:editRule("%d", colors.red) -- Changes the color of numbers to red + +basalt.autoUpdate() +``` diff --git a/docs/objects/Textfield/getOffset.md b/docs/objects/Textfield/getOffset.md new file mode 100644 index 0000000..73e3f9d --- /dev/null +++ b/docs/objects/Textfield/getOffset.md @@ -0,0 +1,26 @@ +## getOffset + +### Description + +Retrieves the current offset within a Textfield object, providing information about the current viewable portion of the text. + +### Returns + +1. `number` The current horizontal offset within the Textfield. +2. `number` The current vertical offset within the Textfield. + +### Usage + +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame() +local aTextfield = mainFrame:addTextfield() + +-- Assume the Textfield has been scrolled previously +local xOffset, yOffset = aTextfield:getOffset() +basalt.debug("Horizontal Offset: "..xOffset) +basalt.debug("Vertical Offset: "..yOffset) + +basalt.autoUpdate() +``` diff --git a/docs/objects/Textfield/getSelection.md b/docs/objects/Textfield/getSelection.md new file mode 100644 index 0000000..cfee94f --- /dev/null +++ b/docs/objects/Textfield/getSelection.md @@ -0,0 +1,10 @@ +## setSelection + +### Description + +Returns the colors when selecting a text. + +### Returns + +1. `number|color` foreground color - The text color. +2. `number|color` background color - ´The background color. diff --git a/docs/objects/Textfield/removeRule.md b/docs/objects/Textfield/removeRule.md new file mode 100644 index 0000000..5c75920 --- /dev/null +++ b/docs/objects/Textfield/removeRule.md @@ -0,0 +1,28 @@ +## removeRule + +### Description + +Removes an existing rule for special coloring in a Textfield object. This allows you to remove the coloring applied to text matching a specific pattern. + +### Parameteres + +1. `string` pattern - The Lua pattern used to match the text for which the rule was applied. + +### Returns + +1. `object` The object in use + +### Usage + +* Removes the rule for coloring all numbers in a Textfield object + +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame() +local aTextfield = mainFrame:addTextfield() + +aTextfield:removeRule("%d") -- Removes the rule for coloring numbers + +basalt.autoUpdate() +``` diff --git a/docs/objects/Textfield/setOffset.md b/docs/objects/Textfield/setOffset.md new file mode 100644 index 0000000..c65b082 --- /dev/null +++ b/docs/objects/Textfield/setOffset.md @@ -0,0 +1,28 @@ +## setOffset + +### Description + +Sets the offset within a Textfield object, allowing you to adjust the viewable portion of the text. + +### Parameteres + +1. `number` xOffset - The horizontal offset to set within the Textfield +2. `number` yOffset - The vertical offset to set within the Textfield + +### Returns + +1. `object` The object in use + +### Usage + +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame() +local aTextfield = mainFrame:addTextfield() + +-- Scroll 10 units down vertically +aTextfield:setOffset(0, 10) + +basalt.autoUpdate() +``` diff --git a/docs/objects/Textfield/setSelection.md b/docs/objects/Textfield/setSelection.md new file mode 100644 index 0000000..ed97e0d --- /dev/null +++ b/docs/objects/Textfield/setSelection.md @@ -0,0 +1,27 @@ +## setSelection + +### Description + +Changes the color when selecting text. + +### Parameteres + +1. `number|color` foreground color - The text color. +2. `number|color` background color - ´The background color. + +### Returns + +1. `object` The object in use + +### Usage + +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame() +local aTextfield = mainFrame:addTextfield() + +aTextfield:setSelection(colors.white, colors.blue) + +basalt.autoUpdate() +``` diff --git a/examples/discordCC.lua b/examples/discordCC.lua deleted file mode 100644 index 29a25af..0000000 --- a/examples/discordCC.lua +++ /dev/null @@ -1,291 +0,0 @@ -local bot_id = "" -- put the bot id between the ""! -local servers = { -- setup the server/channels here, look at the example. - [""] = { - "", - }, - - --[[ Example: - ["SERVER_ID"] = { - "CHANNEL_ID", - "CHANNEL_ID", - "CHANNEL_ID", - }, - ["SERVER_ID"] = { - "CHANNEL_ID", - "CHANNEL_ID", - "CHANNEL_ID", - }, - ]] -} - -if(bot_id=="")then - error("Please setup the bot id and servers/channels first!") -end - ---Basalt configurated installer -local filePath = "basalt.lua" --here you can change the file path default: basalt.lua -if not(fs.exists(filePath))then - shell.run("pastebin run ESs1mg7P packed true "..filePath:gsub(".lua", "")) -- this is an alternative to the wget command -end -local basalt = require(filePath:gsub(".lua", "")) -- here you can change the variablename in any variablename you want default: basalt - -local main = basalt.createFrame():setBackground(colors.lightGray) -local loginFrame = main:addFrame():setBackground(colors.lightGray) -local messageFrameList = main:addFrame():setPosition("parent.w+1", 1):setBackground(colors.black):setScrollable(true):setImportantScroll(true) - -local refreshRate = 2 -local messageFrames = {} -local availableGuilds = {} - -local channel_id = "" -for k,v in pairs(servers)do - if(v[1]~=nil)then - channel_id = v[1] - end - break -end - -local function getAllGuilds(bot) - local content = http.get("https://discord.com/api/users/@me/guilds", {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) - if(content~=nil)then - return textutils.unserializeJSON(content.readAll()) - end -end - -local function getAllChannels(bot, guild) - local content = http.get("https://discord.com/api/guilds/"..guild.."/channels", {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) - if(content~=nil)then - local t = {} - for k,v in pairs(textutils.unserializeJSON(content.readAll()))do - table.insert(t, v.position, v) - end - return t - end -end - -local splitString = function(str, sep) - if sep == nil then - sep = "%s" - end - local t={} - for v in string.gmatch(str, "([^"..sep.."]+)") do - table.insert(t, v) - end - if(#t==0)then table.insert(t,str) end - return t -end - -local function createText(str, width) - local uniqueLines = splitString(str, "\n") - local lines = {} - for k,v in pairs(uniqueLines)do - local line = "" - local words = splitString(v, " ") - for a,b in pairs(words)do - if(#line+#b <= width)then - line = line=="" and b or line.." "..b - if(a==#words)then table.insert(lines, line) end - else - table.insert(lines, line) - line = b:sub(1,width) - if(a==#words)then table.insert(lines, line) end - end - end - end - return lines -end - -local maxOffset = 0 -local autoOffset = true -local function newMessage(position, msg, username, sendTime) - local lines = createText(msg, messageFrameList:getWidth()-5) - if(messageFrames[position]==nil)then - if(messageFrames[position-1]~=nil)then - messageFrames[position] = messageFrameList:addFrame("message"..tostring(position)):setPosition(2, "message"..(position-1)..".y + message"..(position-1)..".h") - else - messageFrames[position] = messageFrameList:addFrame("message"..tostring(position)):setPosition(2, 1) - end - messageFrames[position]:addLabel("title") - messageFrames[position]:addLabel("body") - end - maxOffset = maxOffset + #lines+3 - if(autoOffset)then - messageFrameList:setOffset(0, maxOffset - messageFrameList:getHeight()+1) - end - messageFrames[position]:setSize("parent.w-1", #lines+3):setBackground(colors.black) - messageFrames[position]:getObject("title"):setSize("parent.w-2", 1):setPosition(2,1):setText(username):setForeground(colors.lightGray):setBackground(colors.gray) - messageFrames[position]:getObject("body"):setSize("parent.w-2", #lines+1):setPosition(2,3):setText(msg):setForeground(colors.lightGray) -end - -local function updateDiscordMessages(channel, bot) - if(channel~=nil)and(bot~=nil)then - currentMessages = {} - local content = http.get("https://discord.com/api/channels/"..channel.."/messages?limit=25", {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) - if(content~=nil)then - local t = textutils.unserializeJSON(content.readAll()) - local tR = {} - for i=#t, 1, -1 do - tR[#tR+1] = t[i] - end - for k,v in pairs(tR)do - newMessage(k, v.content, v.author.username, v.time) - end - end - end -end - -local animations = {} - -local function offsetAnimation(obj, x, y, t) - if(animations[obj:getName()]~=nil)then animations[obj:getName()]:cancel() end - animations[obj:getName()] = main:addAnimation():setAutoDestroy(true):setObject(obj):offset(x, y, t or 1):play() -end - -local function positionAnimation(obj, x, y, t) - if(animations[obj:getName()]~=nil)then animations[obj:getName()]:cancel() end - animations[obj:getName()] = main:addAnimation():setAutoDestroy(true):setObject(obj):move(x, y, t or 1):play() -end - -local sideBar = messageFrameList:addFrame():setPosition(-18, 1):setSize(20, "parent.h"):setZIndex(17):ignoreOffset():setScrollable(true):setImportantScroll(true) -sideBar:addButton():setText("Back"):setForeground(colors.lightGray):setBackground(colors.black):setPosition(3,2):setSize("parent.w - 4", 3):onClick(function() - offsetAnimation(main, 0, 0) - positionAnimation(sideBar, -18, 1) -end) -sideBar:addLabel():setText("Channels:"):setForeground(colors.black):setPosition(2,6) -sideBar:onClick(function(self, event) - if(event=="mouse_click")then - positionAnimation(self, 1, 1) - messageFrameList:setImportantScroll(false) - end -end) -sideBar:onLoseFocus(function() - positionAnimation(sideBar, -18, 1) - messageFrameList:setImportantScroll(true) -end) - - -local newTextFrame = messageFrameList:addFrame():setSize("parent.w - 4", 10):setPosition(3, 1):setZIndex(16):ignoreOffset():setBackground(colors.gray):setAnchor("bottomLeft") -local msgInfo = newTextFrame:addLabel():setText("Click here to write a message") - -local messageField = newTextFrame:addTextfield():setSize("parent.w-2", "parent.h-4"):setPosition(2,3):setBackground(colors.lightGray) -newTextFrame:onClick(function(self, event) - if(event=="mouse_click")then - positionAnimation(self, 3, -8, 0.5) - messageFrameList:setImportantScroll(false) - msgInfo:setText("New Message:") - end -end) - -messageFrameList:onScroll(function() - local xO, yO = messageFrameList:getOffset() - messageFrameList:getMaxScroll() - if(yO==messageFrameList:getMaxScroll())then - autoOffset = true - else - autoOffset = false - end -end) - -local function messageBoxLoseFocus() - positionAnimation(newTextFrame, 3, 1, 0.5) - messageFrameList:setImportantScroll(true) - msgInfo:setText("Click here to write a message") - messageField:clear() -end - -newTextFrame:addButton():setText("Cancel"):setAnchor("bottomLeft"):setBackground(colors.black):setForeground(colors.lightGray):setSize(12,1):setPosition(2,1):onClick(function() - messageBoxLoseFocus() -end) - -newTextFrame:onLoseFocus(messageBoxLoseFocus) - -loginFrame:addLabel():setAnchor("center"):setPosition(-2, -1):setText("Username:") -local nameInput = loginFrame:addInput():setAnchor("center"):setPosition(3,0):setBackground(colors.black):setForeground(colors.lightGray):setSize(16,1):setDefaultText("Username...", colors.gray) - -local serverList = loginFrame:addList():setPosition(3, 6):setSize(16, 10) -local channelRadio = sideBar:addRadio():setForeground(colors.black):setBackground(colors.gray):setSelectedItem(colors.gray, colors.lightGray):setActiveSymbol(" ") -local channelObjects = {} -local updateChannels = basalt.shedule(function() - if(bot_id~=nil)then - for k,v in pairs(channelObjects)do - sideBar:removeObject(v) - end - channelObjects = {} - if(serverList:getValue().args~=nil)then - local y = 8 - local maxScroll = 2 - for k,v in pairs(servers[serverList:getValue().args[1]])do - local content = http.get("https://discord.com/api/channels/"..v, {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot_id}) - local channel = textutils.unserializeJSON(content.readAll()) - if(channel~=nil)then - channelRadio:addItem("#"..channel.name,1, y, nil,nil,v) - y = y + 1 - maxScroll = maxScroll + 1 - end - end - end - end -end) - -serverList:onChange(updateChannels) -basalt.shedule(function() - if(bot_id~=nil)then - for k,v in pairs(servers)do - local content = http.get("https://discord.com/api/guilds/"..k, {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot_id}) - local guild = textutils.unserializeJSON(content.readAll()) - if(guild~=nil)then - serverList:addItem(guild.name,nil,nil,k) - end - end - end -end)() - -updateChannels() - - - -channelRadio:onChange(function(self) - local val = self:getValue() - if(val~=nil)and(val.args[1]~=nil)then - channel_id = val.args[1] - end -end) - -loginFrame:addButton():setAnchor("bottomRight"):setPosition(-10, -2):setSize(11,3):setText("Login"):onClick(function() - offsetAnimation(main, main:getWidth(), 0) -end) -loginFrame:addLabel():setPosition(3, 5):setText("Servers:") - - - -local function sendDiscordMessage(msg, channel, bot) - if(channel~=nil)and(bot~=nil)then - if(nameInput:getValue()~="")then - msg = string.gsub(msg, "\n", "\\n") - http.post("https://discord.com/api/channels/"..channel.."/messages", '{ "content": "['..nameInput:getValue()..']: '..msg..'" }', {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) - end - end -end - -newTextFrame:addButton():setText("Send"):setAnchor("bottomRight"):setBackground(colors.black):setForeground(colors.lightGray):setSize(12,1):setPosition(-11,1) - :onClick(function() - local msg = table.concat(messageField:getLines(), "\n") - if(#msg>0)then - sendDiscordMessage(msg, channel_id, bot_id) - end - messageBoxLoseFocus() - end) - -local function refreshMessages() - while true do - maxOffset = 0 - updateDiscordMessages(channel_id, bot_id) - maxOffset = maxOffset - messageFrameList:getHeight()+1 - messageFrameList:setMaxScroll(maxOffset) - sleep(refreshRate) - end -end - -local thread = main:addThread():start(refreshMessages) - -basalt.autoUpdate() diff --git a/examples/progressBarEnergyExample.lua b/examples/progressBarEnergyExample.lua deleted file mode 100644 index ca68795..0000000 --- a/examples/progressBarEnergyExample.lua +++ /dev/null @@ -1,51 +0,0 @@ --- This is a example on how to use progressbars for energy. I used the Mekanism Ultimate Energy Cube. - - ---Basalt configurated installer -local filePath = "basalt.lua" --here you can change the file path default: basalt -if not(fs.exists(filePath))then - shell.run("pastebin run ESs1mg7P packed true "..filePath:gsub(".lua", "")) -- this is an alternative to the wget command -end -local basalt = require(filePath:gsub(".lua", "")) - -local energyCube = peripheral.find("ultimateEnergyCube") - -local main = basalt.createFrame() - -local progressText = main:addLabel() - :setText(0) - :setForeground(colors.gray) - :setBackground(false) - :setPosition(10, 3) - :setZIndex(6) - -local energyProgress = main:addProgressbar() - :setSize(20,3) - :setPosition(2,2) - :setBackground(colors.black) - :setProgressBar(colors.green) - -energyProgress:onChange(function() - local energy = tostring(energyCube.getEnergy()) - progressText:setText(energy) - progressText:setPosition(energyProgress:getWidth()/2+1 - math.floor(energy:len()/2), 3) -end) - - -local function checkCurrentEnergy() - while true do - energyCube = peripheral.find("ultimateEnergyCube") - if(energyCube~=nil)then - local energyCalculation = energyCube.getEnergy() / energyCube.getMaxEnergy() * 100 - energyProgress:setProgress(energyCalculation) - else - energyProgress:setProgress(0) - os.sleep(3) - end - os.sleep(1) - end -end - -main:addThread():start(checkCurrentEnergy) - -basalt.autoUpdate() diff --git a/examples/redstoneAnalogOutput.lua b/examples/redstoneAnalogOutput.lua deleted file mode 100644 index f0dd29a..0000000 --- a/examples/redstoneAnalogOutput.lua +++ /dev/null @@ -1,49 +0,0 @@ ---Basalt configurated installer -local filePath = "basalt.lua" --here you can change the file path default: basalt -if not(fs.exists(filePath))then - shell.run("pastebin run ESs1mg7P packed true "..filePath:gsub(".lua", "")) -- this is an alternative to the wget command -end - --- toastonrye's example: Redstone Analog Output -local basalt = require(filePath:gsub(".lua", "")) -- here you can change the variablename in any variablename you want default: basalt -local w, h = term.getSize() -- dimensions to use when drawing the sub frame - -local main = basalt.createFrame() - :show() - :setBackground(colours.blue) -- using colours to easily determine what frame I'm in - -local sub = main:addFrame() - :setPosition(2,2) - :setSize(w-2,h-2) - :setBackground(colours.lightBlue) - -local rFrame = sub:addFrame("redstoneFrame") - :setPosition(1,1) - :setSize(25,5) - :setMovable(true) - :setBackground(colours.red) - --- Redstone Analog Output -local redstoneAnalog = rFrame:addLabel() -- label that displays the value of the slider & Redstone output - :setPosition(18,3):setText("1") - -redstone.setAnalogOutput("left", 1) -- initialize the redstone output to 1, to match the above label - -rFrame:addLabel() -- draw a label on the frame - :setText("Redstone Analog Output") - :setPosition(1,2) - -rFrame:addSlider() - :setPosition(1,3) - :onChange(function(self) -- when a player interacts with the slider, update the variable redstoneAnalog - redstoneAnalog:setText(self:getValue()) - end) - :setMaxValue(15) -- max value of the slider, default 8. Redstone has 15 levels (16 including 0) - :setSize(15,1) -- draw the slider to this size, without this redstoneAnalog value can have decimals - -redstoneAnalog:onChange(function(self) -- when the slider value changes, change the Redstone output to match - redstone.setAnalogOutput("left", tonumber(self:getValue())) - basalt.debug(self:getValue()) -end) - -basalt.autoUpdate() diff --git a/examples/resizeableFrames.lua b/examples/resizeableFrames.lua deleted file mode 100644 index 6e48a86..0000000 --- a/examples/resizeableFrames.lua +++ /dev/null @@ -1,38 +0,0 @@ --- Hello, here is a small example on how to create resizeable frames, the default anchor (where you have to click on) will be bottom right. - -local basalt = require("basalt") - -local main = basalt.createFrame() - -local sub = main:addFrame() -- the frame we want to resize - :setPosition(3,3) - :setSize(25,8) - :setMovable() - :setBorder(colors.black) - -sub:addLabel() -- the new way to create a bar on the top - :setText("Topbar") - :setSize("parent.w",1) - :setBackground(colors.black) - :setForeground(colors.lightGray) - -sub:addButton() - :setAnchor("bottomRight") - :setPosition(1, 1) - :setText("/") - :setSize(1,1) - :onDrag(function(self, button, x, y, xOffset, yOffset) - local w, h = sub:getSize() - if(w-xOffset>5)and(h-yOffset>3)then -- dont allow it to be smaller than w5 and h3 - sub:setSize(-xOffset, -yOffset, true) -- x-/yOffset is always -1 0 or 1, true means add the value to the current size instead of set it - end - end) - -sub:addButton() -- just a random button to show dynamic values - :setPosition(2,3) - :setBackground(colors.black) - :setForeground(colors.lightGray) - :setSize("parent.w-2", 3) -- parent.w means get the parent's width which is the sub frame in this case, -2 means remove 2 from it's result. You could also use * / % or even math.random(12) - - -basalt.autoUpdate() \ No newline at end of file