diff --git a/Basalt/init.lua b/Basalt/init.lua index cfb92d5..49c2f20 100644 --- a/Basalt/init.lua +++ b/Basalt/init.lua @@ -6,12 +6,13 @@ if not(packed)then local main = format:gsub("path", curDir) local objFolder = format:gsub("path", curDir.."/objects") + local plugFolder = format:gsub("path", curDir.."/plugins") local libFolder = format:gsub("path", curDir.."/libraries") - package.path = main..objFolder..libFolder..defaultPath + package.path = main..objFolder..plugFolder..libFolder..defaultPath end local Basalt = require("main") package.path = defaultPath -return Basalt +return Basalt \ No newline at end of file diff --git a/Basalt/libraries/basaltDraw.lua b/Basalt/libraries/basaltDraw.lua index c4fb1b5..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) @@ -9,13 +11,9 @@ return function(drawTerm) local cacheBG = {} local cacheFG = {} - local _cacheT = {} - local _cacheBG = {} - local _cacheFG = {} - local emptySpaceLine local emptyColorLines = {} - + local function createEmptyLines() emptySpaceLine = rep(" ", width) for n = 0, 15 do @@ -40,137 +38,137 @@ return function(drawTerm) end recreateWindowArray() - local function setText(x, y, text) - if (y >= 1) and (y <= height) then - if (x + text:len() > 0) and (x <= width) then - local oldCache = cacheT[y] - local newCache - local nEnd = x + #text - 1 - - if (x < 1) then - local startN = 1 - x + 1 - local endN = width - x + 1 - text = sub(text, startN, endN) - elseif (nEnd > width) then - local endN = width - x + 1 - text = sub(text, 1, endN) + local function blit(x, y, t, fg, bg) + if #t == #fg and #t == #bg then + if y >= 1 and y <= height then + if x + #t > 0 and x <= width then + local newCacheT, newCacheFG, newCacheBG + local oldCacheT, oldCacheFG, oldCacheBG = cacheT[y], cacheFG[y], cacheBG[y] + local startN, endN = 1, #t + + if x < 1 then + startN = 1 - x + 1 + endN = width - x + 1 + elseif x + #t > width then + endN = width - x + 1 + end + + newCacheT = sub(oldCacheT, 1, x - 1) .. sub(t, startN, endN) + newCacheFG = sub(oldCacheFG, 1, x - 1) .. sub(fg, startN, endN) + newCacheBG = sub(oldCacheBG, 1, x - 1) .. sub(bg, startN, endN) + + if x + #t <= width then + newCacheT = newCacheT .. sub(oldCacheT, x + #t, width) + newCacheFG = newCacheFG .. sub(oldCacheFG, x + #t, width) + newCacheBG = newCacheBG .. sub(oldCacheBG, x + #t, width) + end + + cacheT[y], cacheFG[y], cacheBG[y] = newCacheT,newCacheFG,newCacheBG end - - if (x > 1) then - local endN = x - 1 - newCache = sub(oldCache, 1, endN) .. text - else - newCache = text - end - if nEnd < width then - newCache = newCache .. sub(oldCache, nEnd + 1, width) - end - cacheT[y] = newCache end end end - local function setBG(x, y, colorStr) - if (y >= 1) and (y <= height) then - if (x + colorStr:len() > 0) and (x <= width) then - local oldCache = cacheBG[y] - local newCache - local nEnd = x + #colorStr - 1 + local function setText(x, y, t) + if y >= 1 and y <= height then + if x + #t > 0 and x <= width then + local newCacheT + local oldCacheT = cacheT[y] + local startN, endN = 1, #t - if (x < 1) then - colorStr = sub(colorStr, 1 - x + 1, width - x + 1) - elseif (nEnd > width) then - colorStr = sub(colorStr, 1, width - x + 1) + if x < 1 then + startN = 1 - x + 1 + endN = width - x + 1 + elseif x + #t > width then + endN = width - x + 1 end - if (x > 1) then - newCache = sub(oldCache, 1, x - 1) .. colorStr - else - newCache = colorStr + newCacheT = sub(oldCacheT, 1, x - 1) .. sub(t, startN, endN) + + if x + #t <= width then + newCacheT = newCacheT .. sub(oldCacheT, x + #t, width) end - if nEnd < width then - newCache = newCache .. sub(oldCache, nEnd + 1, width) - end - cacheBG[y] = newCache + + cacheT[y] = newCacheT end end end + local function setBG(x, y, bg) + if y >= 1 and y <= height then + if x + #bg > 0 and x <= width then + local newCacheBG + local oldCacheBG = cacheBG[y] + local startN, endN = 1, #bg + + if x < 1 then + startN = 1 - x + 1 + endN = width - x + 1 + elseif x + #bg > width then + endN = width - x + 1 + end + + newCacheBG = sub(oldCacheBG, 1, x - 1) .. sub(bg, startN, endN) + + if x + #bg <= width then + newCacheBG = newCacheBG .. sub(oldCacheBG, x + #bg, width) + end + + cacheBG[y] = newCacheBG + end + end + end + + local function setFG(x, y, fg) + if y >= 1 and y <= height then + if x + #fg > 0 and x <= width then + local newCacheFG + local oldCacheFG = cacheFG[y] + local startN, endN = 1, #fg + + if x < 1 then + startN = 1 - x + 1 + endN = width - x + 1 + elseif x + #fg > width then + endN = width - x + 1 + end + + newCacheFG = sub(oldCacheFG, 1, x - 1) .. sub(fg, startN, endN) + + if x + #fg <= width then + newCacheFG = newCacheFG .. sub(oldCacheFG, x + #fg, width) + end + + cacheFG[y] = newCacheFG + end + end + end + + --[[ + local function setText(x, y, text) + if (y >= 1) and (y <= height) then + local emptyLine = rep(" ", #text) + blit(x, y, text, emptyLine, emptyLine) + end + end + local function setFG(x, y, colorStr) if (y >= 1) and (y <= height) then - if (x + colorStr:len() > 0) and (x <= width) then - local oldCache = cacheFG[y] - local newCache - local nEnd = x + #colorStr - 1 - - if (x < 1) then - local startN = 1 - x + 1 - local endN = width - x + 1 - colorStr = sub(colorStr, startN, endN) - elseif (nEnd > width) then - local endN = width - x + 1 - colorStr = sub(colorStr, 1, endN) - end - - if (x > 1) then - local endN = x - 1 - newCache = sub(oldCache, 1, endN) .. colorStr - else - newCache = colorStr - end - if nEnd < width then - newCache = newCache .. sub(oldCache, nEnd + 1, width) - end - cacheFG[y] = newCache - end + local w = #colorStr + local emptyLine = rep(" ", w) + local text = sub(cacheT[y], x, w) + blit(x, y, text, colorStr, emptyLine) end end - local function blit(x, y, t, fg, bg) - if(#t == #fg)or(#t == #bg)then - if (y >= 1) and (y <= height) then - if (x + t:len() > 0) and (x <= width) then - local oldCacheT = cacheT[y] - local oldCacheFG = cacheFG[y] - local oldCacheBG = cacheBG[y] - local newCacheT, newCacheFG, newCacheBG - local nEnd = x + #t - 1 - - if (x < 1) then - local startN = 1 - x + 1 - local endN = width - x + 1 - t = sub(t, startN, endN) - fg = sub(fg, startN, endN) - bg = sub(bg, startN, endN) - elseif (nEnd > width) then - local endN = width - x + 1 - t = sub(t, 1, endN) - fg = sub(fg, 1, endN) - bg = sub(bg, 1, endN) - end - - if (x > 1) then - local endN = x - 1 - newCacheT = sub(oldCacheT, 1, endN) .. t - newCacheFG = sub(oldCacheFG, 1, endN) .. fg - newCacheBG = sub(oldCacheBG, 1, endN) .. bg - else - newCacheT = t - newCacheFG = fg - newCacheBG = bg - end - if nEnd < width then - newCacheT = newCacheT .. sub(oldCacheT, nEnd + 1, width) - newCacheFG = newCacheFG .. sub(oldCacheFG, nEnd + 1, width) - newCacheBG = newCacheBG .. sub(oldCacheBG, nEnd + 1, width) - end - cacheT[y] = newCacheT - cacheFG[y] = newCacheFG - cacheBG[y] = newCacheBG - 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 + end]] local drawHelper = { setSize = function(w, h) @@ -181,13 +179,14 @@ return function(drawTerm) setMirror = function(mirror) mirrorTerm = mirror end, + setBG = function(x, y, colorStr) setBG(x, y, colorStr) - end; + end, setText = function(x, y, text) setText(x, y, text) - end; + end, setFG = function(x, y, colorStr) setFG(x, y, colorStr) @@ -198,31 +197,23 @@ return function(drawTerm) end, drawBackgroundBox = function(x, y, width, height, bgCol) + local colorStr = rep(tHex[bgCol], width) for n = 1, height do - setBG(x, y + (n - 1), rep(tHex[bgCol], width)) + setBG(x, y + (n - 1), colorStr) end - 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) ,rep(tHex[fgCol], width)) + setFG(x, y + (n - 1), colorStr) end - end; + end, drawTextBox = function(x, y, width, height, symbol) + local textStr = rep(symbol, width) for n = 1, height do - setText(x, y + (n - 1), rep(symbol, width)) + setText(x, y + (n - 1), textStr) end - end; - writeText = function(x, y, text, bgCol, fgCol) - if(text~=nil)then - setText(x, y, text) - if(bgCol~=nil)and(bgCol~=false)then - setBG(x, y, rep(tHex[bgCol], text:len())) - end - if(fgCol~=nil)and(fgCol~=false)then - setFG(x, y, rep(tHex[fgCol], text:len())) - end - end - end; + end, update = function() local xC, yC = terminal.getCursorPos() @@ -249,11 +240,11 @@ return function(drawTerm) mirrorTerm.setCursorPos(xC, yC) end - end; + end, setTerm = function(newTerm) - terminal = newTerm; - end; + terminal = newTerm + end, } return drawHelper end \ No newline at end of file diff --git a/Basalt/libraries/basaltEvent.lua b/Basalt/libraries/basaltEvent.lua index 80bcd55..f870ad4 100644 --- a/Basalt/libraries/basaltEvent.lua +++ b/Basalt/libraries/basaltEvent.lua @@ -1,21 +1,41 @@ return function() local events = {} - local index = {} local event = { registerEvent = function(self, _event, func) if (events[_event] == nil) then events[_event] = {} - index[_event] = 1 end - events[_event][index[_event]] = func - index[_event] = index[_event] + 1 - return index[_event] - 1 - end; + table.insert(events[_event], func) + end, removeEvent = function(self, _event, index) events[_event][index[_event]] = nil - end; + end, + + hasEvent = function(self, _event) + return events[_event]~=nil + end, + + getEventCount = function(self, _event) + return events[_event]~=nil and #events[_event] or 0 + end, + + getEvents = function(self) + local t = {} + for k,v in pairs(events)do + table.insert(t, k) + end + return t + end, + + clearEvent = function(self, _event) + events[_event] = nil + end, + + clear = function(self, _event) + events = {} + end, sendEvent = function(self, _event, ...) local returnValue @@ -28,7 +48,7 @@ return function() end end return returnValue - end; + end, } event.__index = event return event diff --git a/Basalt/libraries/basaltLogs.lua b/Basalt/libraries/basaltLogs.lua index 4edcd5a..7c3d149 100644 --- a/Basalt/libraries/basaltLogs.lua +++ b/Basalt/libraries/basaltLogs.lua @@ -10,7 +10,7 @@ local mt = { if(text==nil)then return end local dirStr = logDir~="" and logDir.."/"..logFileName or logFileName local handle = fs.open(dirStr, fs.exists(dirStr) and "a" or "w") - handle.writeLine("[Basalt]["..(typ and typ or defaultLogType).."]: "..tostring(text)) + handle.writeLine("[Basalt]["..os.date("%Y-%m-%d %H:%M:%S").."]["..(typ and typ or defaultLogType).."]: "..tostring(text)) handle.close() end, } diff --git a/Basalt/libraries/bimg.lua b/Basalt/libraries/bimg.lua index fcc40be..f07cc77 100644 --- a/Basalt/libraries/bimg.lua +++ b/Basalt/libraries/bimg.lua @@ -80,9 +80,11 @@ local function frame(base, manager) end if(base~=nil)then - w = #base[1][1] - h = #base - setFrame(base) + if(#base>0)then + w = #base[1][1] + h = #base + setFrame(base) + end end return { @@ -134,7 +136,11 @@ local function frame(base, manager) end, getFrameData = function(key) - return (key~= nil and data[key] or data) + if(key~=nil)then + return data[key] + else + return data + end end, blit = function(text, fgCol, bgCol, x, y) @@ -185,10 +191,12 @@ return function(img) local function addFrame(id, data) id = id or #frames+1 - table.insert(frames, id, frame(data, manager)) + local f = frame(data, manager) + table.insert(frames, id, f) if(data==nil)then frames[id].setSize(width, height) end + return f end local function removeFrame(id) @@ -283,7 +291,6 @@ return function(img) end, addFrame = function(id) - local f = frame() if(#frames<=1)then if(metadata.animated==nil)then metadata.animated = true @@ -292,21 +299,10 @@ return function(img) metadata.secondsPerFrame = 0.2 end end - addFrame(id) - return f + return addFrame(id) end, - removeFrame = function(id) - removeFrame(id) - if(#frames<=1)then - if(metadata.animated==nil)then - metadata.animated = true - end - if(metadata.secondsPerFrame==nil)then - metadata.secondsPerFrame = 0.2 - end - end - end, + removeFrame = removeFrame, moveFrame = moveFrame, @@ -317,7 +313,9 @@ return function(img) end, getFrameData = function(id, key) - return frames[id]~=nil and frames[id].getFrameData(key) + if(frames[id]~=nil)then + return frames[id].getFrameData(key) + end end, getSize = function() @@ -339,7 +337,11 @@ return function(img) end, getMetadata = function(key) - return key~=nil and metadata[key] or metadata + if(key~=nil)then + return metadata[key] + else + return metadata + end end, createBimg = function() diff --git a/Basalt/libraries/images.lua b/Basalt/libraries/images.lua index acfefef..ffa58c7 100644 --- a/Basalt/libraries/images.lua +++ b/Basalt/libraries/images.lua @@ -1,23 +1,16 @@ -local sub,floor,rep = string.sub,math.floor,string.rep +local sub,floor = string.sub,math.floor local function loadNFPAsBimg(path) - local bimg = {{}} - local nfp = fs.open(path, "r") - if(nfp~=nil)then - for line in nfp.readLine do - table.insert(bimg[1], {rep(" ",#line), rep(" ",#line), line}) - end - nfp.close() - return bimg - end + return {[1]={{}, {}, paintutils.loadImage(path)}}, "bimg" end local function loadNFP(path) return paintutils.loadImage(path), "nfp" end -local function loadBIMG(path) - local f = fs.open(path, "rb") +local function loadBIMG(path, binaryMode) + local f = fs.open(path, binaryMode and "rb" or "r") + if(f==nil)then error("Path - "..path.." doesn't exist!") end local content = textutils.unserialize(f.readAll()) f.close() if(content~=nil)then @@ -33,28 +26,24 @@ local function loadBBFAsBimg(path) end -local function loadImage(path, f) - if(f==nil)then - if(path:find(".bimg"))then - return loadBIMG(path) - elseif(path:find(".bbf"))then - return loadBBF(path) - else - return loadNFP(path) - end +local function loadImage(path, f, binaryMode) + if(sub(path, -4) == ".bimg")then + return loadBIMG(path, binaryMode) + elseif(sub(path, -3) == ".bbf")then + return loadBBF(path, binaryMode) + else + return loadNFP(path, binaryMode) end -- ... end -local function loadImageAsBimg(path, f) - if(f==nil)then - if(path:find(".bimg"))then - return loadBIMG(path) - elseif(path:find(".bbf"))then - return loadBBFAsBimg(path) - else - return loadNFPAsBimg(path) - end +local function loadImageAsBimg(path) + if(path:find(".bimg"))then + return loadBIMG(path) + elseif(path:find(".bbf"))then + return loadBBFAsBimg(path) + else + return loadNFPAsBimg(path) end end @@ -94,4 +83,4 @@ return { resizeBIMG = resizeBIMG, loadImageAsBimg = loadImageAsBimg, -} +} \ No newline at end of file diff --git a/Basalt/libraries/process.lua b/Basalt/libraries/process.lua index 28bfc1e..cf712b0 100644 --- a/Basalt/libraries/process.lua +++ b/Basalt/libraries/process.lua @@ -17,6 +17,7 @@ function process:new(path, window, newEnv, ...) local env = setmetatable(newEnv, {__index=_ENV}) env.shell = shell env.basaltProgram=true + env.arg = {[0]=path, table.unpack(args)} env.require, env.package = newPackage(env, fs.getDir(pPath)) if(fs.exists(pPath))then local file = fs.open(pPath, "r") @@ -24,7 +25,7 @@ function process:new(path, window, newEnv, ...) file.close() local program = load(content, path, "bt", env) if(program~=nil)then - return program(table.unpack(args)) + return program() end end end) @@ -81,4 +82,4 @@ function process:start() coroutine.resume(self.coroutine) end -return process +return process \ No newline at end of file diff --git a/Basalt/libraries/tHex.lua b/Basalt/libraries/tHex.lua index bd070ca..e419d11 100644 --- a/Basalt/libraries/tHex.lua +++ b/Basalt/libraries/tHex.lua @@ -1,18 +1,6 @@ -return { -- copy paste is a very important feature - [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", -} \ No newline at end of file +local cols = {} + +for i = 0, 15 do + cols[2^i] = ("%x"):format(i) +end +return cols \ No newline at end of file diff --git a/Basalt/libraries/utils.lua b/Basalt/libraries/utils.lua index 7c23a7d..9ad8e08 100644 --- a/Basalt/libraries/utils.lua +++ b/Basalt/libraries/utils.lua @@ -1,100 +1,32 @@ -local sub,find,reverse = string.sub,string.find,string.reverse +local sub,find,reverse,rep,insert,len = string.sub,string.find,string.reverse,string.rep,table.insert,string.len local function splitString(str, delimiter) local result = {} if str == "" or delimiter == "" then return result - end + end local start = 1 local delim_start, delim_end = find(str, delimiter, start) - while delim_start do - table.insert(result, sub(str, start, delim_start - 1)) - start = delim_end + 1 - delim_start, delim_end = find(str, delimiter, start) - end - table.insert(result, sub(str, start)) + while delim_start do + insert(result, sub(str, start, delim_start - 1)) + start = delim_end + 1 + delim_start, delim_end = find(str, delimiter, start) + end + insert(result, sub(str, start)) return result end -local relations = {[0] = {8, 4, 3, 6, 5}, {4, 14, 8, 7}, {6, 10, 8, 7}, {9, 11, 8, 0}, {1, 14, 8, 0}, {13, 12, 8, 0}, {2, 10, 8, 0}, {15, 8, 10, 11, 12, 14}, - {0, 7, 1, 9, 2, 13}, {3, 11, 8, 7}, {2, 6, 7, 15}, {9, 3, 7, 15}, {13, 5, 7, 15}, {5, 12, 8, 7}, {1, 4, 7, 15}, {7, 10, 11, 12, 14}} - -local colourNum, exponents, colourChar = {}, {}, {} -for i = 0, 15 do exponents[2^i] = i end -do - local hex = "0123456789abcdef" - for i = 1, 16 do - colourNum[hex:sub(i, i)] = i - 1 - colourNum[i - 1] = hex:sub(i, i) - colourChar[hex:sub(i, i)] = 2 ^ (i - 1) - colourChar[2 ^ (i - 1)] = hex:sub(i, i) - - local thisRel = relations[i - 1] - for i = 1, #thisRel do thisRel[i] = 2 ^ thisRel[i] end - end -end - -local function getBestColourMatch(usage) - local lastCol = relations[exponents[usage[#usage][1]]] - - for j = 1, #lastCol do - local thisRelation = lastCol[j] - for i = 1, #usage - 1 do if usage[i][1] == thisRelation then return i end end - end - - return 1 -end - -local function colsToChar(pattern, totals) - if not totals then - local newPattern = {} - totals = {} - for i = 1, 6 do - local thisVal = pattern[i] - local thisTot = totals[thisVal] - totals[thisVal], newPattern[i] = thisTot and (thisTot + 1) or 1, thisVal - end - pattern = newPattern - end - - local usage = {} - for key, value in pairs(totals) do usage[#usage + 1] = {key, value} end - - if #usage > 1 then - -- Reduce the chunk to two colours: - while #usage > 2 do - table.sort(usage, function (a, b) return a[2] > b[2] end) - local matchToInd, usageLen = getBestColourMatch(usage), #usage - local matchFrom, matchTo = usage[usageLen][1], usage[matchToInd][1] - for i = 1, 6 do if pattern[i] == matchFrom then - pattern[i] = matchTo - usage[matchToInd][2] = usage[matchToInd][2] + 1 - end end - usage[usageLen] = nil - end - - -- Convert to character. Adapted from oli414's function: - -- http://www.computercraft.info/forums2/index.php?/topic/25340-cc-176-easy-drawing-characters/ - local data = 128 - for i = 1, #pattern - 1 do if pattern[i] ~= pattern[6] then data = data + 2^(i-1) end end - return string.char(data), colourChar[usage[1][1] == pattern[6] and usage[2][1] or usage[1][1]], colourChar[pattern[6]] - else - -- Solid colour character: - return "\128", colourChar[pattern[1]], colourChar[pattern[1]] - end -end - return { getTextHorizontalAlign = function(text, width, textAlign, replaceChar) text = sub(text, 1, width) - local offset = width - string.len(text) + local offset = width - len(text) if (textAlign == "right") then - text = string.rep(replaceChar or " ", offset) .. text + text = rep(replaceChar or " ", offset) .. text elseif (textAlign == "center") then - text = string.rep(replaceChar or " ", math.floor(offset / 2)) .. text .. string.rep(replaceChar or " ", math.floor(offset / 2)) - text = text .. (string.len(text) < width and (replaceChar or " ") or "") + text = rep(replaceChar or " ", math.floor(offset / 2)) .. text .. rep(replaceChar or " ", math.floor(offset / 2)) + text = text .. (len(text) < width and (replaceChar or " ") or "") else - text = text .. string.rep(replaceChar or " ", offset) + text = text .. rep(replaceChar or " ", offset) end return text end, @@ -114,6 +46,14 @@ getTextVerticalAlign = function(h, textAlign) return offset end, +orderedTable = function(t) + local newTable = {} + for _, v in pairs(t) do + newTable[#newTable+1] = v + end + return newTable +end, + rpairs = function(t) return function(t, i) i = i - 1 @@ -135,7 +75,7 @@ end, splitString = splitString, -createText = function(str, width) +wrapText = function(str, width) local uniqueLines = splitString(str, "\n") local result = {} for k,v in pairs(uniqueLines)do @@ -145,7 +85,7 @@ createText = function(str, width) if not last_space then last_space = width else - last_space = width - last_space + 1 + last_space = width - last_space --+ 1 end local line = sub(v, 1, last_space) table.insert(result, line) @@ -158,73 +98,8 @@ createText = function(str, width) return result end, -getValueFromXML = function(name, tab) - local var - if(type(tab)~="table")then return end - if(tab[name]~=nil)then - if(type(tab[name])=="table")then - if(tab[name].value~=nil)then - var = tab[name]:value() - end - end - end - if(var==nil)then var = tab["@"..name] end - - if(var=="true")then - var = true - elseif(var=="false")then - var = false - elseif(tonumber(var)~=nil)then - var = tonumber(var) - end - return var -end, - -numberFromString = function(str) - return load("return " .. str)() -end, - uuid = function() - local random = math.random - local function uuid() - local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' - return string.gsub(template, '[xy]', function (c) - local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) - return string.format('%x', v) - end) - end - return uuid() -end, + 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 -array = function(arraysize, hashsize) - return load("return {" .. ("nil,"):rep(arraysize) .. ("[0]=nil,"):rep(hashsize) .. "}")() -end, - -shrink = function(image, bgCol) - local results, width, height, bgCol = {{}, {}, {}}, 0, #image + #image % 3, bgCol or colours.black - for i = 1, #image do if #image[i] > width then width = #image[i] end end - - for y = 0, height - 1, 3 do - local cRow, tRow, bRow, counter = {}, {}, {}, 1 - - for x = 0, width - 1, 2 do - -- Grab a 2x3 chunk: - local pattern, totals = {}, {} - - for yy = 1, 3 do for xx = 1, 2 do - pattern[#pattern + 1] = (image[y + yy] and image[y + yy][x + xx]) and (image[y + yy][x + xx] == 0 and bgCol or image[y + yy][x + xx]) or bgCol - totals[pattern[#pattern]] = totals[pattern[#pattern]] and (totals[pattern[#pattern]] + 1) or 1 - end end - - cRow[counter], tRow[counter], bRow[counter] = colsToChar(pattern, totals) - counter = counter + 1 - end - - results[1][#results[1] + 1], results[2][#results[2] + 1], results[3][#results[3] + 1] = table.concat(cRow), table.concat(tRow), table.concat(bRow) - end - - results.width, results.height = #results[1][1], #results[1] - - return results -end, } \ No newline at end of file diff --git a/Basalt/loadObjects.lua b/Basalt/loadObjects.lua index bb600dd..f43f757 100644 --- a/Basalt/loadObjects.lua +++ b/Basalt/loadObjects.lua @@ -1,4 +1,5 @@ local _OBJECTS = {} + if(packaged)then for k,v in pairs(getProject("objects"))do _OBJECTS[k] = v() @@ -13,7 +14,7 @@ if(dir==nil)then end for _,v in pairs(fs.list(fs.combine(dir, "objects")))do - if(v~="example.lua")then + if(v~="example.lua")and not(v:find(".disabled"))then local name = v:gsub(".lua", "") _OBJECTS[name] = require(name) end diff --git a/Basalt/main.lua b/Basalt/main.lua index 284000e..a318325 100644 --- a/Basalt/main.lua +++ b/Basalt/main.lua @@ -1,16 +1,17 @@ local basaltEvent = require("basaltEvent")() -local Frame = require("Frame") -local theme = require("theme") +local _OBJECTS = require("loadObjects") +local pluginSystem = require("plugin") local utils = require("utils") local log = require("basaltLogs") local uuid = utils.uuid -local createText = utils.createText +local wrapText = utils.wrapText local count = utils.tableCount local moveThrottle = 300 -local dragThrottle = 50 +local dragThrottle = 0 +local renderingThrottle = 0 local baseTerm = term.current() -local version = "1.6.4" +local version = "1.7.0" local projectDirectory = fs.getDir(table.pack(...)[2] or "") @@ -42,7 +43,7 @@ local function stop() end end -local function basaltError(errMsg) +function basalt.basaltError(errMsg) baseTerm.clear() baseTerm.setBackgroundColor(colors.black) baseTerm.setTextColor(colors.red) @@ -51,7 +52,7 @@ local function basaltError(errMsg) log(errMsg, "Error") end - local text = createText("Basalt error: "..errMsg, w) + local text = wrapText("Basalt error: "..errMsg, w) local yPos = 1 for k,v in pairs(text)do baseTerm.setCursorPos(1,yPos) @@ -68,13 +69,17 @@ return function(...) local co = coroutine.create(f) local ok, result = coroutine.resume(co, ...) if(ok)then - table.insert(schedules, {co, result}) + table.insert(schedules, co) else - basaltError(result) + basalt.basaltError(result) end end end +basalt.log = function(...) + log(...) +end + local setVariable = function(name, var) variables[name] = var end @@ -83,14 +88,6 @@ local getVariable = function(name) return variables[name] end -local setTheme = function(_theme) - theme = _theme -end - -local getTheme = function(name) - return theme[name] -end - local bInstance = { getDynamicValueEventSetting = function() return basalt.dynamicValueEvents @@ -102,7 +99,6 @@ local bInstance = { setVariable = setVariable, getVariable = getVariable, - getTheme = getTheme, setMainFrame = function(mFrame) mainFrame = mFrame @@ -140,7 +136,7 @@ local bInstance = { end end, - getBaseTerm = function() + getTerm = function() return baseTerm end, @@ -148,32 +144,31 @@ local bInstance = { stop = stop, newFrame = Frame, + debug = basalt.debug, + log = basalt.log, + + getObjects = function() + return _OBJECTS + end, + + getObject = function(id) + return _OBJECTS[id] + end, getDirectory = function() return projectDirectory end } -local function handleSchedules(event, ...) +local function handleSchedules(event, p1, p2, p3, p4) if(#schedules>0)then local finished = {} for n=1,#schedules do if(schedules[n]~=nil)then - if (coroutine.status(schedules[n][1]) == "suspended")then - if(schedules[n][2]~=nil)then - if(schedules[n][2]==event)then - local ok, result = coroutine.resume(schedules[n][1], event, ...) - schedules[n][2] = result - if not(ok)then - basaltError(result) - end - end - else - local ok, result = coroutine.resume(schedules[n][1], event, ...) - schedules[n][2] = result - if not(ok)then - basaltError(result) - end + if (coroutine.status(schedules[n]) == "suspended")then + local ok, result = coroutine.resume(schedules[n], event, p1, p2, p3, p4) + if not(ok)then + basalt.basaltError(result) end else table.insert(finished, n) @@ -189,15 +184,15 @@ end local function drawFrames() if(updaterActive==false)then return end if(mainFrame~=nil)then - mainFrame:draw() + mainFrame:render() mainFrame:updateTerm() end for _,v in pairs(monFrames)do - v:draw() + v:render() v:updateTerm() end for _,v in pairs(monGroups)do - v[1]:draw() + v[1]:render() v[1]:updateTerm() end end @@ -236,6 +231,23 @@ local function mouseDragEvent(_, b, x, y) end end + +local renderingTimer = nil +local function renderingUpdateTimer() + renderingTimer = nil + drawFrames() +end + +local function renderingUpdateEvent(timer) + if(renderingThrottle<50)then + drawFrames() + else + if(renderingTimer==nil)then + renderingTimer = os.startTimer(renderingThrottle/1000) + end + end +end + local function basaltUpdateEvent(event, ...) local a = {...} if(basaltEvent:sendEvent("basaltEventCycle", event, ...)==false)then return end @@ -252,15 +264,15 @@ local function basaltUpdateEvent(event, ...) if(mouseEvent~=nil)then mouseEvent(mainFrame, ...) handleSchedules(event, ...) - drawFrames() + renderingUpdateEvent() return end end if(event == "monitor_touch") then - if(monFrames[a[1]]~=nil)then - monFrames[a[1]]:mouseHandler(1, a[2], a[3], true) - activeFrame = monFrames[a[1]] + if(monFrames[a[2]]~=nil)then + monFrames[a[2]]:mouseHandler(1, a[2], a[3], true) + activeFrame = monFrames[a[2]] end if(count(monGroups)>0)then for k,v in pairs(monGroups)do @@ -268,7 +280,7 @@ local function basaltUpdateEvent(event, ...) end end handleSchedules(event, ...) - drawFrames() + renderingUpdateEvent() return end @@ -287,7 +299,7 @@ local function basaltUpdateEvent(event, ...) end keyEvent(activeFrame, ...) handleSchedules(event, ...) - drawFrames() + renderingUpdateEvent() return end end @@ -296,13 +308,15 @@ local function basaltUpdateEvent(event, ...) moveHandlerTimer() elseif(event=="timer")and(a[1]==dragTimer)then dragHandlerTimer() + elseif(event=="timer")and(a[1]==renderingTimer)then + renderingUpdateTimer() else for k, v in pairs(frames) do v:eventHandler(event, ...) end + handleSchedules(event, ...) + renderingUpdateEvent() end - handleSchedules(event, ...) - drawFrames() end basalt = { @@ -311,10 +325,15 @@ basalt = { setTheme = setTheme, getTheme = getTheme, drawFrames = drawFrames, + log = log, getVersion = function() return version end, + memory = function() + return math.floor(collectgarbage("count")+0.5).."KB" + end, + setVariable = setVariable, getVariable = getVariable, @@ -322,8 +341,12 @@ basalt = { baseTerm = _baseTerm end, - log = function(...) - log(...) + resetPalette = function() + for k,v in pairs(colors)do + if(type(v)=="number")then + --baseTerm.setPaletteColor(v, colors.packRGB(table.unpack(defaultColors[k]))) + end + end end, setMouseMoveThrottle = function(amount) @@ -339,6 +362,15 @@ basalt = { return false end, + setRenderingThrottle = function(amount) + if(amount<=0)then + renderingThrottle = 0 + else + renderingTimer = nil + renderingThrottle = amount + end + end, + setMouseDragThrottle = function(amount) if(amount<=0)then dragThrottle = 0 @@ -357,10 +389,11 @@ basalt = { basaltUpdateEvent(os.pullEventRaw()) end end - local ok, err = xpcall(f, debug.traceback) - if not(ok)then - basaltError(err) - return + while updaterActive do + local ok, err = xpcall(f, debug.traceback) + if not(ok)then + basalt.basaltError(err) + end end end, @@ -368,7 +401,7 @@ basalt = { if (event ~= nil) then local ok, err = xpcall(basaltUpdateEvent, debug.traceback, event, ...) if not(ok)then - basaltError(err) + basalt.basaltError(err) return end end @@ -395,12 +428,16 @@ basalt = { end, setActiveFrame = function(frame) - if (frame:getType() == "Frame") then + if (frame:getType() == "Container") then activeFrame = frame return true end return false end, + + getMainFrame = function() + return mainFrame + end, onEvent = function(...) for _,v in pairs(table.pack(...))do @@ -413,14 +450,15 @@ basalt = { schedule = schedule, createFrame = function(name) - name = name or uuid() for _, v in pairs(frames) do - if (v.name == name) then + if (v:getName() == name) then return nil end end - local newFrame = Frame(name,nil,nil,bInstance) + local newFrame = _OBJECTS["BaseFrame"](name, bInstance) newFrame:init() + newFrame:load() + newFrame:draw() table.insert(frames, newFrame) if(mainFrame==nil)and(newFrame:getName()~="basaltDebuggingFrame")then newFrame:show() @@ -435,41 +473,26 @@ basalt = { setProjectDir = function(dir) projectDirectory = dir end, - - forceRenderUpdate = function() - drawFrames() - end, - - debug = function(...) - local args = { ... } - if(mainFrame==nil)then print(...) return end - if (mainFrame.name ~= "basaltDebuggingFrame") then - if (mainFrame ~= basalt.debugFrame) then - basalt.debugLabel:setParent(mainFrame) - end - end - local str = "" - for key, value in pairs(args) do - str = str .. tostring(value) .. (#args ~= key and ", " or "") - end - basalt.debugLabel:setText("[Debug] " .. str) - for k,v in pairs(createText(str, basalt.debugList:getWidth()))do - basalt.debugList:addItem(v) - end - if (basalt.debugList:getItemCount() > 50) then - basalt.debugList:removeItem(1) - end - basalt.debugList:setValue(basalt.debugList:getItem(basalt.debugList:getItemCount())) - if(basalt.debugList.getItemCount() > basalt.debugList:getHeight())then - basalt.debugList:setOffset(basalt.debugList:getItemCount() - basalt.debugList:getHeight()) - end - basalt.debugLabel:show() - end, } -basalt.debugFrame = basalt.createFrame("basaltDebuggingFrame"):showBar():setBackground(colors.lightGray):setBar("Debug", colors.black, colors.gray) -basalt.debugFrame:addButton("back"):setAnchor("topRight"):setSize(1, 1):setText("\22"):onClick(function() if(basalt.oldFrame~=nil)then basalt.oldFrame:show() end end):setBackground(colors.red):show() -basalt.debugList = basalt.debugFrame:addList("debugList"):setSize("parent.w - 2", "parent.h - 3"):setPosition(2, 3):setScrollable(true):show() -basalt.debugLabel = basalt.debugFrame:addLabel("debugLabel"):onClick(function() basalt.oldFrame = mainFrame basalt.debugFrame:show() end):setBackground(colors.black):setForeground(colors.white):setAnchor("bottomLeft"):ignoreOffset():setZIndex(20):show() +_OBJECTS = pluginSystem.addPlugins(_OBJECTS, bInstance) + +local basaltPlugins = pluginSystem.get("basalt") +if(basaltPlugins~=nil)then + for k,v in pairs(basaltPlugins)do + for a,b in pairs(v(basalt))do + basalt[a] = b + bInstance[a] = b + end + end +end +local basaltPlugins = pluginSystem.get("basaltInternal") +if(basaltPlugins~=nil)then + for k,v in pairs(basaltPlugins)do + for a,b in pairs(v(basalt))do + bInstance[a] = b + end + end +end return basalt diff --git a/Basalt/objects/Animation.lua b/Basalt/objects/Animation.lua index 45800b6..8c29924 100644 --- a/Basalt/objects/Animation.lua +++ b/Basalt/objects/Animation.lua @@ -1,6 +1,3 @@ -local xmlValue = require("utils").getValueFromXML -local basaltEvent = require("basaltEvent") - local floor,sin,cos,pi,sqrt,pow = math.floor,math.sin,math.cos,math.pi,math.sqrt,math.pow -- You can find the easing curves here https://easings.net @@ -222,7 +219,8 @@ local lerp = { local activeAnimations = {} -return function(name) +return function(name, basalt) + local base = basalt.getObject("Object")(name, basalt) local object = {} local objectType = "Animation" @@ -234,8 +232,6 @@ return function(name) local index = 1 local infinitePlay = false - local eventSystem = basaltEvent() - local nextWaitTimer = 0 local lastFunc local loop=false @@ -306,7 +302,7 @@ return function(name) local obj = _OBJ local x,y local name = "" - if(obj.parent~=nil)then name = obj.parent:getName() end + if(obj:getParent()~=nil)then name = obj:getParent():getName() end name = name..obj:getName() addAnimationPart(t+0.05, function() if(typ~=nil)then @@ -340,14 +336,7 @@ return function(name) name = name, getType = function(self) return objectType - end; - - getBaseFrame = function(self) - if(self.parent~=nil)then - return self.parent:getBaseFrame() - end - return self - end; + end, setMode = function(self, newMode) mode = newMode @@ -359,124 +348,6 @@ return function(name) return self end, - generateXMLEventFunction = function(self, func, val) - local createF = function(str) - if(str:sub(1,1)=="#")then - local o = self:getBaseFrame():getDeepObject(str:sub(2,str:len())) - if(o~=nil)and(o.internalObjetCall~=nil)then - func(self,function()o:internalObjetCall()end) - end - else - func(self,self:getBaseFrame():getVariable(str)) - end - end - if(type(val)=="string")then - createF(val) - elseif(type(val)=="table")then - for k,v in pairs(val)do - createF(v) - end - end - return self - end, - - setValuesByXMLData = function(self, data) - loop = xmlValue("loop", data)==true and true or false - if(xmlValue("object", data)~=nil)then - local o = self:getBaseFrame():getDeepObject(xmlValue("object", data)) - if(o==nil)then - o = self:getBaseFrame():getVariable(xmlValue("object", data)) - end - if(o~=nil)then - self:setObject(o) - end - end - if(data["move"]~=nil)then - local x = xmlValue("x", data["move"]) - local y = xmlValue("y", data["move"]) - local duration = xmlValue("duration", data["move"]) - local time = xmlValue("time", data["move"]) - self:move(x, y, duration, time) - end - if(data["size"]~=nil)then - local w = xmlValue("width", data["size"]) - local h = xmlValue("height", data["size"]) - local duration = xmlValue("duration", data["size"]) - local time = xmlValue("time", data["size"]) - self:size(w, h, duration, time) - end - if(data["offset"]~=nil)then - local x = xmlValue("x", data["offset"]) - local y = xmlValue("y", data["offset"]) - local duration = xmlValue("duration", data["offset"]) - local time = xmlValue("time", data["offset"]) - self:offset(x, y, duration, time) - end - if(data["textColor"]~=nil)then - local duration = xmlValue("duration", data["textColor"]) - local timer = xmlValue("time", data["textColor"]) - local t = {} - local tab = data["textColor"]["color"] - if(tab~=nil)then - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - table.insert(t, colors[v:value()]) - end - end - if(duration~=nil)and(#t>0)then - self:changeTextColor(duration, timer or 0, table.unpack(t)) - end - end - if(data["background"]~=nil)then - local duration = xmlValue("duration", data["background"]) - local timer = xmlValue("time", data["background"]) - local t = {} - local tab = data["background"]["color"] - if(tab~=nil)then - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - table.insert(t, colors[v:value()]) - end - end - if(duration~=nil)and(#t>0)then - self:changeBackground(duration, timer or 0, table.unpack(t)) - end - end - if(data["text"]~=nil)then - local duration = xmlValue("duration", data["text"]) - local timer = xmlValue("time", data["text"]) - local t = {} - local tab = data["text"]["text"] - if(tab~=nil)then - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - table.insert(t, v:value()) - end - end - if(duration~=nil)and(#t>0)then - self:changeText(duration, timer or 0, table.unpack(t)) - end - end - if(xmlValue("onDone", data)~=nil)then self:generateXMLEventFunction(self.onDone, xmlValue("onDone", data)) end - if(xmlValue("onStart", data)~=nil)then self:generateXMLEventFunction(self.onDone, xmlValue("onStart", data)) end - if(xmlValue("autoDestroy", data)~=nil)then - if(xmlValue("autoDestroy", data))then - autoDestroy = true - end - end - mode = xmlValue("mode", data) or mode - if(xmlValue("play", data)~=nil)then if(xmlValue("play", data))then self:play(loop) end end - return self - end, - - getZIndex = function(self) - return 1 - end; - - getName = function(self) - return self.name - end; - setObject = function(self, obj) _OBJ = obj return self @@ -557,12 +428,12 @@ return function(name) end; onDone = function(self, f) - eventSystem:registerEvent("animation_done", f) + self:registerEvent("animation_done", f) return self end, onStart = function(self, f) - eventSystem:registerEvent("animation_start", f) + self:registerEvent("animation_start", f) return self end, @@ -572,16 +443,16 @@ return function(name) end, animationDoneHandler = function(self) - eventSystem:sendEvent("animation_done", self) - self.parent:removeEvent("other_event", self) + self:sendEvent("animation_done", self) + self:listenEvent("other_event", false) if(autoDestroy)then - self.parent:removeObject(self) + self:getParent():removeObject(self) self = nil end end; animationStartHandler = function(self) - eventSystem:sendEvent("animation_start", self) + self:sendEvent("animation_start", self) end; clear = function(self) @@ -609,7 +480,7 @@ return function(name) else self:animationDoneHandler() end - self.parent:addEvent("other_event", self) + self:listenEvent("other_event") return self end; @@ -619,7 +490,7 @@ return function(name) infinitePlay = false end animationActive = false - self.parent:removeEvent("other_event", self) + self:listenEvent("other_event", false) return self end; @@ -639,7 +510,7 @@ return function(name) end end; } - object.__index = object - return object + object.__index = object + return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/BaseFrame.lua b/Basalt/objects/BaseFrame.lua new file mode 100644 index 0000000..3c32d53 --- /dev/null +++ b/Basalt/objects/BaseFrame.lua @@ -0,0 +1,213 @@ +local drawSystem = require("basaltDraw") +local utils = require("utils") + +local max,min,sub,rep = math.max,math.min,string.sub,string.rep + +return function(name, basalt) + local base = basalt.getObject("Container")(name, basalt) + local objectType = "BaseFrame" + + local xOffset, yOffset = 0, 0 + + local colorTheme = {} + + local updateRender = true + + local termObject = basalt.getTerm() + local basaltDraw = drawSystem(termObject) + + local xCursor, yCursor, cursorBlink, cursorColor = 1, 1, false, colors.white + + local object = { + getType = function() + return objectType + end, + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + getBase = function(self) + return base + end, + + getOffset = function(self) + return xOffset, yOffset + end, + + setOffset = function(self, xOff, yOff) + xOffset = xOff or xOffset + yOffset = yOff or yOffset + self:updateDraw() + return self + end, + + show = function(self) + base.show(self) + 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, + + setPalette = function(self, col, ...) + if(self==basalt.getActiveFrame())then + if(type(col)=="string")then + colorTheme[col] = ... + termObject.setPaletteColor(type(col)=="number" and col or colors[col], ...) + elseif(type(col)=="table")then + for k,v in pairs(col)do + colorTheme[k] = v + if(type(v)=="number")then + termObject.setPaletteColor(type(k)=="number" and k or colors[k], v) + else + local r,g,b = table.unpack(v) + termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b) + end + end + end + end + return self + end, + + setSize = function(self, ...) + base.setSize(self, ...) + basaltDraw = drawSystem(termObject) + return self + end, + + getSize = function() + return termObject.getSize() + end, + + getWidth = function(self) + return ({termObject.getSize()})[1] + end, + + getHeight = function(self) + return ({termObject.getSize()})[2] + end, + + show = function(self) + base.show(self) + basalt.setActiveFrame(self) + for k,v in pairs(colors)do + if(type(v)=="number")then + termObject.setPaletteColor(v, colors.packRGB(term.nativePaletteColor((v)))) + end + end + for k,v in pairs(colorTheme)do + if(type(v)=="number")then + termObject.setPaletteColor(type(k)=="number" and k or colors[k], v) + else + local r,g,b = table.unpack(v) + termObject.setPaletteColor(type(k)=="number" and k or colors[k], r,g,b) + end + end + basalt.setMainFrame(self) + return self + end, + + render = function(self) + if(base.render~=nil)then + if(self:isVisible())then + if(updateRender)then + base.render(self) + local objects = self:getObjects() + for _, obj in ipairs(objects) do + if (obj.element.render ~= nil) then + obj.element:render() + end + end + updateRender = false + end + end + end + end, + + updateDraw = function(self) + updateRender = true + return self + end, + + eventHandler = function(self, event, ...) + base.eventHandler(self, event, ...) + if(event=="term_resize")then + self:setSize(termObject.getSize()) + end + end, + + updateTerm = function(self) + basaltDraw.update() + end, + + setTerm = function(self, newTerm) + termObject = newTerm + basaltDraw = drawSystem(termObject) + return self + end, + + getTerm = function() + return termObject + end, + + blit = function (self, x, y, t, f, b) + local obx, oby = self:getPosition() + local w, h = self:getSize() + if y >= 1 and y <= h then + local t_visible = sub(t, max(1 - x + 1, 1), max(w - x + 1, 1)) + local f_visible = sub(f, max(1 - x + 1, 1), max(w - x + 1, 1)) + local b_visible = sub(b, max(1 - x + 1, 1), max(w - x + 1, 1)) + basaltDraw.blit(max(x + (obx - 1), obx), oby + y - 1, t_visible, f_visible, b_visible) + end + end, + + setCursor = function(self, _blink, _xCursor, _yCursor, color) + local obx, oby = self:getAbsolutePosition() + cursorBlink = _blink or false + if (_xCursor ~= nil) then + xCursor = obx + _xCursor - 1 + end + if (_yCursor ~= nil) then + yCursor = oby + _yCursor - 1 + end + cursorColor = color or cursorColor + if (cursorBlink) then + termObject.setTextColor(cursorColor) + termObject.setCursorPos(xCursor, yCursor) + termObject.setCursorBlink(cursorBlink) + else + termObject.setCursorBlink(false) + end + return self + end, + } + + for k,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do + object[v] = function(self, x, y, width, height, symbol) + local obx, oby = self:getPosition() + local w, h = self:getSize() + height = (y < 1 and (height + y > self:getHeight() and self:getHeight() or height + y - 1) or (height + y > self:getHeight() and self:getHeight() - y + 1 or height)) + width = (x < 1 and (width + x > self:getWidth() and self:getWidth() or width + x - 1) or (width + x > self:getWidth() and self:getWidth() - x + 1 or width)) + basaltDraw[v](max(x + (obx - 1), obx), max(y + (oby - 1), oby), width, height, symbol) + end + end + + for k,v in pairs({"setBG", "setFG", "setText"}) do + object[v] = function(self, x, y, str) + local obx, oby = self:getPosition() + local w, h = self:getSize() + if (y >= 1) and (y <= h) then + basaltDraw[v](max(x + (obx - 1), obx), oby + y - 1, sub(str, max(1 - x + 1, 1), max(w - x + 1,1))) + end + end + end + + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/Button.lua b/Basalt/objects/Button.lua index 3ddf0e3..e5659f4 100644 --- a/Basalt/objects/Button.lua +++ b/Basalt/objects/Button.lua @@ -1,74 +1,65 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = utils.getValueFromXML local tHex = require("tHex") -return function(name) +return function(name, basalt) -- Button - local base = Object(name) + local base = basalt.getObject("VisualObject")(name, basalt) local objectType = "Button" local textHorizontalAlign = "center" local textVerticalAlign = "center" + local text = "Button" + + base:setSize(12, 3) base:setZIndex(5) - base:setValue("Button") - base.width = 12 - base.height = 3 local object = { - init = function(self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("ButtonBG") - self.fgColor = self.parent:getTheme("ButtonText") - end - end, getType = function(self) return objectType - end; + 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, + setHorizontalAlign = function(self, pos) textHorizontalAlign = pos self:updateDraw() return self - end; + end, setVerticalAlign = function(self, pos) textVerticalAlign = pos self:updateDraw() return self - end; + end, - setText = function(self, text) - base:setValue(tostring(text)) + setText = function(self, newText) + text = newText self:updateDraw() return self - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("text", data)~=nil)then self:setText(xmlValue("text", data)) end - if(xmlValue("horizontalAlign", data)~=nil)then textHorizontalAlign = xmlValue("horizontalAlign", data) end - if(xmlValue("verticalAlign", data)~=nil)then textVerticalAlign = xmlValue("verticalAlign", data) end - return self end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign) - - for n = 1, h do - if (n == verticalAlign) then - local val = self:getValue() - self.parent:setText(obx + (w/2-val:len()/2), oby + (n - 1), utils.getTextHorizontalAlign(val, val:len(), textHorizontalAlign)) - self.parent:setFG(obx + (w/2-val:len()/2), oby + (n - 1), utils.getTextHorizontalAlign(tHex[self.fgColor]:rep(val:len()), val:len(), textHorizontalAlign)) - end - end + base.draw(self) + self:addDraw("button", function() + local w,h = self:getSize() + local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign) + local xOffset + if(textHorizontalAlign=="center")then + xOffset = math.floor((w - text:len()) / 2) + elseif(textHorizontalAlign=="right")then + xOffset = w - text:len() end - end - end, + self:addText(xOffset + 1, verticalAlign, text) + self:addFG(xOffset + 1, verticalAlign, tHex[self:getForeground() or colors.white]:rep(text:len())) + end) + end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Checkbox.lua b/Basalt/objects/Checkbox.lua index fc4ef39..d9083a4 100644 --- a/Basalt/objects/Checkbox.lua +++ b/Basalt/objects/Checkbox.lua @@ -1,31 +1,53 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = utils.getValueFromXML +local tHex = require("tHex") -return function(name) +return function(name, basalt) -- Checkbox - local base = Object(name) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "Checkbox" base:setZIndex(5) base:setValue(false) - base.width = 1 - base.height = 1 + base:setSize(1, 1) - local symbol = "\42" + 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; + end, + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, - setSymbol = function(self, sym) - symbol = sym + setSymbol = function(self, sym, inactive) + symbol = sym or symbol + inactiveSymbol = inactive or inactiveSymbol self:updateDraw() return self end, + getSymbol = function(self) + return symbol, inactiveSymbol + end, + + setText = function(self, _text) + text = _text + return self + end, + + setTextPosition = function(self, pos) + textPos = pos or textPos + return self + end, + + setChecked = base.setValue, + mouseHandler = function(self, button, x, y) if (base.mouseHandler(self, button, x, y)) then if(button == 1)then @@ -41,45 +63,26 @@ return function(name) return false end, - touchHandler = function(self, x, y) - return self:mouseHandler(1, x, y) - end, - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("checked", data)~=nil)then if(xmlValue("checked", data))then self:setValue(true) else self:setValue(false) end end - return self - end, - draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - local verticalAlign = utils.getTextVerticalAlign(h, "center") - if(self.bgColor~=false)then self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) end - for n = 1, h do - if (n == verticalAlign) then - if (self:getValue() == true) then - self.parent:writeText(obx, oby + (n - 1), utils.getTextHorizontalAlign(symbol, w, "center"), self.bgColor, self.fgColor) - else - self.parent:writeText(obx, oby + (n - 1), utils.getTextHorizontalAlign(" ", w, "center"), self.bgColor, self.fgColor) - end - end - end + base.draw(self) + self:addDraw("checkbox", function() + local obx, oby = self:getPosition() + local w,h = self:getSize() + local verticalAlign = utils.getTextVerticalAlign(h, "center") + local bg,fg = self:getBackground(), self:getForeground() + if (self:getValue()) then + self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(symbol, w, "center"), tHex[bg], tHex[fg]) + else + self:addBlit(1, verticalAlign, utils.getTextHorizontalAlign(inactiveSymbol, w, "center"), tHex[bg], tHex[fg]) end - end - end, - - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_up", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("CheckboxBG") - self.fgColor = self.parent:getTheme("CheckboxText") - end + if(text~="")then + local align = textPos=="left" and -text:len() or 3 + self:addText(align, verticalAlign, text) + end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Container.lua b/Basalt/objects/Container.lua new file mode 100644 index 0000000..26bc2ff --- /dev/null +++ b/Basalt/objects/Container.lua @@ -0,0 +1,388 @@ +local utils = require("utils") +local tableCount = utils.tableCount + +return function(name, basalt) + local base = basalt.getObject("VisualObject")(name, basalt) + local objectType = "Container" + + local elements = {} + + local events = {} + + local container = {} + local activeEvents = {} + + local focusedObject + local sorted = true + local objId, evId = 0, 0 + + local objSort = function(a, b) + if a.zIndex == b.zIndex then + return a.objId < b.objId + else + return a.zIndex < b.zIndex + end + end + local evSort = function(a, b) + if a.zIndex == b.zIndex then + return a.evId > b.evId + else + return a.zIndex > b.zIndex + end + end + + local function getObject(self, name) + if(type(name)=="table")then name = name:getName() end + for i, v in ipairs(elements) do + if v.element:getName() == name then + return v.element + end + end + end + + local function getDeepObject(self, name) + local o = getObject(name) + if(o~=nil)then return o end + for _, value in pairs(objects) do + if (b:getType() == "Container") then + local oF = b:getDeepObject(name) + if(oF~=nil)then return oF end + end + end + end + + local function addObject(self, element, el2) + if (getObject(element:getName()) ~= nil) then + return + end + objId = objId + 1 + local zIndex = element:getZIndex() + table.insert(elements, {element = element, zIndex = zIndex, objId = objId}) + sorted = false + element:setParent(self, true) + if(element.init~=nil)then element:init() end + if(element.load~=nil)then element:load() end + if(element.draw~=nil)then element:draw() end + return element + end + + local function updateZIndex(self, element, newZ) + objId = objId + 1 + evId = evId + 1 + for k,v in pairs(elements)do + if(v.element==element)then + v.zIndex = newZ + v.objId = objId + break + end + end + for k,v in pairs(events)do + for a,b in pairs(v)do + if(b.element==element)then + b.zIndex = newZ + b.evId = evId + end + end + end + sorted = false + self:updateDraw() + end + + local function removeObject(self, element) + if(type(element)=="string")then element = getObject(element:getName()) end + if(element==nil)then return end + for i, v in ipairs(elements) do + if v.element == element then + table.remove(elements, i) + return true + end + end + sorted = false + end + + local function removeEvents(self, element) + local parent = self:getParent() + for a, b in pairs(events) do + for c, d in pairs(b) do + if(d.element == element)then + table.remove(events[a], c) + end + end + if(tableCount(events[a])<=0)then + activeEvents[a] = false + if(parent~=nil)then + parent:removeEvent(a, self) + end + end + end + sorted = false + end + + local function getEvent(self, event, name) + if(type(name)=="table")then name = name:getName() end + if(events[event]~=nil)then + for _, obj in pairs(events[event]) do + if (obj.element:getName() == name) then + return obj + end + end + end + end + + local function addEvent(self, event, element) + if (getEvent(self, event, element:getName()) ~= nil) then + return + end + local zIndex = element:getZIndex() + evId = evId + 1 + if(events[event]==nil)then events[event] = {} end + table.insert(events[event], {element = element, zIndex = zIndex, evId = evId}) + sorted = false + self:listenEvent(event) + return element + end + + local function removeEvent(self, event, element) + local parent = self:getParent() + if(events[event]~=nil)then + for a, b in pairs(events[event]) do + if(b.element == element)then + table.remove(events[event], a) + end + end + if(tableCount(events[event])<=0)then + self:listenEvent(event, false) + end + end + sorted = false + end + + local function getObjects(self) + self:sortElementOrder() + return elements + end + + container = { + getType = function() + return objectType + end, + + getBase = function(self) + return base + end, + + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + setSize = function(self, ...) + base.setSize(self, ...) + self:customEventHandler("basalt_FrameResize") + return self + end, + + setPosition = function(self, ...) + base.setPosition(self, ...) + self:customEventHandler("basalt_FrameReposition") + return self + end, + + searchObjects = function(self, name) + local t = {} + for k,v in pairs(elements)do + if(string.find(k:getName(), name))then + table.insert(t, v) + end + end + return t + end, + + getObjectsByType = function(self, t) + local t = {} + for k,v in pairs(elements)do + if(v:isType(t))then + table.insert(t, v) + end + end + return t + end, + + setImportant = function(self, element) + objId = objId + 1 + evId = evId + 1 + for a, b in pairs(events) do + for c, d in pairs(b) do + if(d.element == element)then + d.evId = evId + table.remove(events[a], c) + table.insert(events[a], d) + break + end + end + end + for i, v in ipairs(elements) do + if v.element == element then + v.objId = objId + table.remove(elements, i) + table.insert(elements, v) + break + end + end + if(self.updateDraw~=nil)then + self:updateDraw() + end + sorted = false + end, + + sortElementOrder = function(self) + if(sorted)then return end + table.sort(elements, objSort) + for a, b in pairs(events) do + table.sort(events[a], evSort) + end + sorted = true + end, + + removeFocusedObject = function(self) + if(focusedObject~=nil)then + if(getObject(self, focusedObject)~=nil)then + focusedObject:loseFocusHandler() + end + end + focusedObject = nil + return self + end, + + setFocusedObject = function(self, obj) + if(focusedObject~=obj)then + if(focusedObject~=nil)then + if(getObject(self, focusedObject)~=nil)then + focusedObject:loseFocusHandler() + end + end + if(obj~=nil)then + if(getObject(self, obj)~=nil)then + obj:getFocusHandler() + end + end + focusedObject = obj + return true + end + return false + end, + + getFocusedObject = function(self) + return focusedObject + end, + + getObject = getObject, + getObjects = getObjects, + getDeepObject = getDeepObject, + addObject = addObject, + removeObject = removeObject, + getEvent = getEvent, + addEvent = addEvent, + removeEvent = removeEvent, + updateZIndex = updateZIndex, + + listenEvent = function(self, event, active) + base.listenEvent(self, event, active) + activeEvents[event] = active~=nil and active or true + if(events[event]==nil)then events[event] = {} end + return self + end, + + customEventHandler = function(self, ...) + base.customEventHandler(self, ...) + for _, o in pairs(elements) do + if (o.element.customEventHandler ~= nil) then + o.element:customEventHandler(...) + end + end + end, + + loseFocusHandler = function(self) + base.loseFocusHandler(self) + if(focusedObject~=nil)then focusedObject:loseFocusHandler() focusedObject = nil end + end, + + getBasalt = function(self) + return basalt + end, + + setPalette = function(self, col, ...) + local parent = self:getParent() + parent:setPalette(col, ...) + return self + end, + + eventHandler = function(self, ...) + if(base.eventHandler~=nil)then + base.eventHandler(self, ...) + if(events["other_event"]~=nil)then + self:sortElementOrder() + for _, obj in ipairs(events["other_event"]) do + if (obj.element.eventHandler ~= nil) then + obj.element.eventHandler(obj.element, ...) + end + end + end + end + end, + } + + for k,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do + container[v[1]] = function(self, btn, x, y, ...) + if(base[v[1]]~=nil)then + if(base[v[1]](self, btn, x, y, ...))then + if(events[k]~=nil)then + self:sortElementOrder() + for _, obj in ipairs(events[k]) do + if (obj.element[v[1]] ~= nil) then + local xO, yO = 0, 0 + if(self.getOffset~=nil)then + xO, yO = self:getOffset() + end + if (obj.element[v[1]](obj.element, btn, x+xO, y+yO, ...)) then + return true + end + end + end + if(v[2])then + self:removeFocusedObject() + end + return true + end + end + end + end + end + + for k,v in pairs({key="keyHandler",key_up="keyUpHandler",char="charHandler"})do + container[v] = function(self, ...) + if(base[v]~=nil)then + if(base[v](self, ...))then + if(events[k]~=nil)then + self:sortElementOrder() + for _, obj in ipairs(events[k]) do + if (obj.element[v] ~= nil) then + if (obj.element[v](obj.element, ...)) then + return true + end + end + end + end + end + end + end + end + + for k,v in pairs(basalt.getObjects())do + container["add"..k] = function(self, name) + return addObject(self, v(name, basalt)) + end + end + + container.__index = container + return setmetatable(container, base) +end \ No newline at end of file diff --git a/Basalt/objects/Dropdown.lua b/Basalt/objects/Dropdown.lua index 4a66928..ff10488 100644 --- a/Basalt/objects/Dropdown.lua +++ b/Basalt/objects/Dropdown.lua @@ -1,17 +1,15 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = require("utils").getValueFromXML +local tHex = require("tHex") -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("List")(name, basalt) local objectType = "Dropdown" - base.width = 12 - base.height = 1 + + base:setSize(12, 1) base:setZIndex(6) - local list = {} - local itemSelectedBG - local itemSelectedFG + local itemSelectedBG = colors.black + local itemSelectedFG = colors.lightGray local selectionColorActive = true local align = "left" local yOffset = 0 @@ -25,94 +23,28 @@ return function(name) local object = { getType = function(self) return objectType - end; + end, - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("selectionBG", data)~=nil)then itemSelectedBG = colors[xmlValue("selectionBG", data)] end - if(xmlValue("selectionFG", data)~=nil)then itemSelectedFG = colors[xmlValue("selectionFG", data)] end - if(xmlValue("dropdownWidth", data)~=nil)then dropdownW = xmlValue("dropdownWidth", data) end - if(xmlValue("dropdownHeight", data)~=nil)then dropdownH = xmlValue("dropdownHeight", data) end - if(xmlValue("offset", data)~=nil)then yOffset = xmlValue("offset", data) end - if(data["item"]~=nil)then - local tab = data["item"] - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - self:addItem(xmlValue("text", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) - end - end + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + load = function(self) + self:listenEvent("mouse_click", self) + self:listenEvent("mouse_up", self) + self:listenEvent("mouse_scroll", self) + self:listenEvent("mouse_drag", self) end, setOffset = function(self, yOff) yOffset = yOff self:updateDraw() return self - end; + end, getOffset = function(self) return yOffset - end; - - addItem = function(self, text, bgCol, fgCol, ...) - table.insert(list, { text = text, bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) - self:updateDraw() - return self - end; - - getAll = function(self) - return list - end; - - removeItem = function(self, index) - table.remove(list, index) - self:updateDraw() - return self - end; - - getItem = function(self, index) - return list[index] - end; - - getItemIndex = function(self) - local selected = self:getValue() - for key, value in pairs(list) do - if (value == selected) then - return key - end - end - end; - - clear = function(self) - list = {} - self:setValue({}, false) - self:updateDraw() - return self - end; - - getItemCount = function(self) - return #list - end; - - editItem = function(self, index, text, bgCol, fgCol, ...) - table.remove(list, index) - table.insert(list, index, { text = text, bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) - self:updateDraw() - return self - end; - - selectItem = function(self, index) - self:setValue(list[index] or {}, false) - self:updateDraw() - return self - end; - - setSelectedItem = function(self, bgCol, fgCol, active) - itemSelectedBG = bgCol or self.bgColor - itemSelectedFG = fgCol or self.fgColor - selectionColorActive = active~=nil and active - self:updateDraw() - return self - end; + end, setDropdownSize = function(self, width, height) dropdownW, dropdownH = width, height @@ -124,20 +56,18 @@ return function(name) return dropdownW, dropdownH end, - mouseHandler = function(self, button, x, y, touch) + mouseHandler = function(self, button, x, y) if (isOpened) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) + local obx, oby = self:getAbsolutePosition() if(button==1)then + local list = self:getAll() if (#list > 0) then for n = 1, dropdownH do if (list[n + yOffset] ~= nil) then if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then self:setValue(list[n + yOffset]) self:updateDraw() - local val = self:getEventSystem():sendEvent("mouse_click", self, "mouse_click", dir, x, y) - if(touch)then - self:mouseUpHandler(button, x, y) - end + local val = self:sendEvent("mouse_click", self, "mouse_click", dir, x, y) if(val==false)then return val end return true end @@ -146,8 +76,9 @@ return function(name) end end end + local base = base:getBase() if (base.mouseHandler(self, button, x, y)) then - isOpened = (not isOpened) + isOpened = true self:updateDraw() return true else @@ -161,15 +92,16 @@ return function(name) mouseUpHandler = function(self, button, x, y) if (isOpened) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) + local obx, oby = self:getAbsolutePosition() if(button==1)then + local list = self:getAll() if (#list > 0) then for n = 1, dropdownH do if (list[n + yOffset] ~= nil) then if (obx <= x) and (obx + dropdownW > x) and (oby + n == y) then isOpened = false self:updateDraw() - local val = self:getEventSystem():sendEvent("mouse_up", self, "mouse_up", dir, x, y) + local val = self:sendEvent("mouse_up", self, "mouse_up", dir, x, y) if(val==false)then return val end return true end @@ -182,6 +114,7 @@ return function(name) scrollHandler = function(self, dir, x, y) if (isOpened)and(self:isFocused()) then + local list = self:getAll() yOffset = yOffset + dir if (yOffset < 0) then yOffset = 0 @@ -195,7 +128,7 @@ return function(name) yOffset = math.min(#list - 1, 0) end end - local val = self:getEventSystem():sendEvent("mouse_scroll", self, "mouse_scroll", dir, x, y) + local val = self:sendEvent("mouse_scroll", self, "mouse_scroll", dir, x, y) if(val==false)then return val end self:updateDraw() return true @@ -203,46 +136,40 @@ return function(name) end, draw = function(self) - if (base.draw(self)) then - local obx, oby = self:getAnchorPosition() + base.draw(self) + self:setDrawState("list", false) + self:addDraw("dropdown", function() + local obx, oby = self:getPosition() local w,h = self:getSize() - if (self.parent ~= nil) then - if(self.bgColor~=false)then self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) end - local val = self:getValue() - local text = utils.getTextHorizontalAlign((val~=nil and val.text or ""), w, align):sub(1, w - 1) .. (isOpened and openedSymbol or closedSymbol) - self.parent:writeText(obx, oby, text, self.bgColor, self.fgColor) + local val = self:getValue() + local list = self:getAll() + local bgCol, fgCol = self:getBackground(), self:getForeground() + local text = utils.getTextHorizontalAlign((val~=nil and val.text or ""), w, align):sub(1, w - 1) .. (isOpened and openedSymbol or closedSymbol) + self:addBlit(1, 1, text, tHex[fgCol]:rep(#text), tHex[bgCol]:rep(#text)) - if (isOpened) then - for n = 1, dropdownH do - if (list[n + yOffset] ~= nil) then - if (list[n + yOffset] == val) then - if (selectionColorActive) then - self.parent:writeText(obx, oby + n, utils.getTextHorizontalAlign(list[n + yOffset].text, dropdownW, align), itemSelectedBG, itemSelectedFG) - else - self.parent:writeText(obx, oby + n, utils.getTextHorizontalAlign(list[n + yOffset].text, dropdownW, align), list[n + yOffset].bgCol, list[n + yOffset].fgCol) - end + if (isOpened) then + self:addTextBox(1, 2, dropdownW, dropdownH, " ") + self:addBackgroundBox(1, 2, dropdownW, dropdownH, bgCol) + self:addForegroundBox(1, 2, dropdownW, dropdownH, fgCol) + for n = 1, dropdownH do + if (list[n + yOffset] ~= nil) then + local t =utils.getTextHorizontalAlign(list[n + yOffset].text, dropdownW, align) + if (list[n + yOffset] == val) then + if (selectionColorActive) then + self:addBlit(1, n+1, t, tHex[itemSelectedFG]:rep(#t), tHex[itemSelectedBG]:rep(#t)) else - self.parent:writeText(obx, oby + n, utils.getTextHorizontalAlign(list[n + yOffset].text, dropdownW, align), list[n + yOffset].bgCol, list[n + yOffset].fgCol) + self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t)) end + else + self:addBlit(1, n+1, t, tHex[list[n + yOffset].fgCol]:rep(#t), tHex[list[n + yOffset].bgCol]:rep(#t)) end end end end - end - end, - - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_up", self) - self.parent:addEvent("mouse_scroll", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("DropdownBG") - self.fgColor = self.parent:getTheme("DropdownText") - itemSelectedBG = self.parent:getTheme("SelectionBG") - itemSelectedFG = self.parent:getTheme("SelectionText") - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Flexbox.lua b/Basalt/objects/Flexbox.lua new file mode 100644 index 0000000..fc1077f --- /dev/null +++ b/Basalt/objects/Flexbox.lua @@ -0,0 +1,95 @@ +return function(name, basalt) + local base = basalt.getObject("Frame")(name, basalt) + local objectType = "Flexbox" + + local flexDirection = "row" -- "row" oder "column" + local justifyContent = "flex-start" -- "flex-start", "flex-end", "center", "space-between", "space-around" + local spacing = 1 + + local function applyLayout(self) + local objects = self:getObjects() + local totalElements = #objects + local _, _ = self:getPosition() + local width, height = self:getSize() + + local totalChildSize = 0 + for _, obj in ipairs(objects) do + if flexDirection == "row" then + local objWidth, _ = obj.element:getSize() + totalChildSize = totalChildSize + objWidth + else + local _, objHeight = obj.element:getSize() + totalChildSize = totalChildSize + objHeight + end + end + + local availableSpace = (flexDirection == "row" and width or height) - totalChildSize - (spacing * (totalElements - 1)) + + local currentOffset = 0 + if justifyContent == "center" then + currentOffset = availableSpace / 2 + elseif justifyContent == "flex-end" then + currentOffset = availableSpace + end + + for _, obj in ipairs(objects) do + if flexDirection == "row" then + obj.element:setPosition(currentOffset, 1) -- Ändere den y-Wert auf 1 + local objWidth, _ = obj.element:getSize() + currentOffset = currentOffset + objWidth + spacing + else + obj.element:setPosition(1, math.floor(currentOffset+0.5)) -- Ändere den x-Wert auf 1 + local _, objHeight = obj.element:getSize() + currentOffset = currentOffset + objHeight + spacing + end + end + end + + + local object = { + getType = function() + return objectType + end, + + isType = function(self, t) + return objectType == t or base.getBase(self).isType(t) or false + end, + + setSpacing = function(self, newSpacing) + spacing = newSpacing + applyLayout(self) + return self + end, + + getSpacing = function(self) + return spacing + end, + + setFlexDirection = function(self, direction) + if direction == "row" or direction == "column" then + flexDirection = direction + applyLayout(self) + end + return self + end, + + setJustifyContent = function(self, alignment) + if alignment == "flex-start" or alignment == "flex-end" or alignment == "center" or alignment == "space-between" or alignment == "space-around" then + justifyContent = alignment + applyLayout(self) + end + return self + end, + } + + for k,v in pairs(basalt.getObjects())do + object["add"..k] = function(self, name) + local obj = base["add"..k](self, name) + applyLayout(base) + return obj + end + end + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/Frame.lua b/Basalt/objects/Frame.lua new file mode 100644 index 0000000..d65c5a0 --- /dev/null +++ b/Basalt/objects/Frame.lua @@ -0,0 +1,116 @@ +local utils = require("utils") + +local max,min,sub,rep,len = math.max,math.min,string.sub,string.rep,string.len + +return function(name, basalt) + local base = basalt.getObject("Container")(name, basalt) + local objectType = "Frame" + local parent + + local updateRender = true + + local xOffset, yOffset = 0, 0 + + base:setSize(30, 10) + base:setZIndex(10) + + local object = { + getType = function() + return objectType + end, + + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + getBase = function(self) + return base + end, + + getOffset = function(self) + return xOffset, yOffset + end, + + setOffset = function(self, xOff, yOff) + xOffset = xOff or xOffset + yOffset = yOff or yOffset + self:updateDraw() + return self + end, + + setParent = function(self, p, ...) + base.setParent(self, p, ...) + parent = p + return self + end, + + render = function(self) + if(base.render~=nil)then + if(self:isVisible())then + base.render(self) + local objects = self:getObjects() + for _, obj in ipairs(objects) do + if (obj.element.render ~= nil) then + obj.element:render() + end + end + end + end + end, + + updateDraw = function(self) + if(parent~=nil)then + parent:updateDraw() + end + return self + end, + + blit = function (self, x, y, t, f, b) + local obx, oby = self:getPosition() + local xO, yO = parent:getOffset() + obx = obx - xO + oby = oby - yO + local w, h = self:getSize() + if y >= 1 and y <= h then + local t_visible = sub(t, max(1 - x + 1, 1), max(w - x + 1, 1)) + local f_visible = sub(f, max(1 - x + 1, 1), max(w - x + 1, 1)) + local b_visible = sub(b, max(1 - x + 1, 1), max(w - x + 1, 1)) + parent:blit(max(x + (obx - 1), obx), oby + y - 1, t_visible, f_visible, b_visible) + end + end, + + setCursor = function(self, blink, x, y, color) + local obx, oby = self:getPosition() + parent:setCursor(blink or false, (x or 0)+obx-1, (y or 0)+oby-1, color or colors.white) + return self + end, + } + + for k,v in pairs({"drawBackgroundBox", "drawForegroundBox", "drawTextBox"})do + object[v] = function(self, x, y, width, height, symbol) + local obx, oby = self:getPosition() + local xO, yO = parent:getOffset() + obx = obx - xO + oby = oby - yO + height = (y < 1 and (height + y > self:getHeight() and self:getHeight() or height + y - 1) or (height + y > self:getHeight() and self:getHeight() - y + 1 or height)) + width = (x < 1 and (width + x > self:getWidth() and self:getWidth() or width + x - 1) or (width + x > self:getWidth() and self:getWidth() - x + 1 or width)) + parent[v](parent, max(x + (obx - 1), obx), max(y + (oby - 1), oby), width, height, symbol) + end + end + + for k,v in pairs({"setBG", "setFG", "setText"})do + object[v] = function(self, x, y, str) + local obx, oby = self:getPosition() + local xO, yO = parent:getOffset() + obx = obx - xO + oby = oby - yO + local w, h = self:getSize() + if (y >= 1) and (y <= h) then + parent[v](parent, max(x + (obx - 1), obx), oby + y - 1, sub(str, max(1 - x + 1, 1), max(w - x + 1,1))) + end + end + end + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/Graph.lua b/Basalt/objects/Graph.lua new file mode 100644 index 0000000..094f798 --- /dev/null +++ b/Basalt/objects/Graph.lua @@ -0,0 +1,159 @@ +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) + local objectType = "Graph" + + base:setZIndex(5) + base:setSize(30, 10) + + local graphData = {} + local graphColor = colors.gray + local graphSymbol = "\7" + local graphSymbolCol = colors.black + local maxValue = 100 + local minValue = 0 + local graphType = "line" + local maxEntries = 10 + + local object = { + getType = function(self) + return objectType + end, + + setGraphColor = function(self, color) + graphColor = color or graphColor + self:updateDraw() + return self + end, + + setGraphSymbol = function(self, symbol, symbolcolor) + graphSymbol = symbol or graphSymbol + graphSymbolCol = symbolcolor or graphSymbolCol + self:updateDraw() + return self + end, + + getGraphSymbol = function(self) + return graphSymbol, graphSymbolCol + end, + + addDataPoint = function(self, value) + if value >= minValue and value <= maxValue then + table.insert(graphData, value) + self:updateDraw() + end + if(#graphData>100)then -- 100 is hard capped to prevent memory leaks + table.remove(graphData,1) + end + return self + end, + + setMaxValue = function(self, value) + maxValue = value + self:updateDraw() + return self + end, + + getMaxValue = function(self) + return maxValue + end, + + setMinValue = function(self, value) + minValue = value + self:updateDraw() + return self + end, + + getMinValue = function(self) + return minValue + end, + + setGraphType = function(self, graph_type) + if graph_type == "scatter" or graph_type == "line" or graph_type == "bar" then + graphType = graph_type + self:updateDraw() + end + return self + end, + + setMaxEntries = function(self, value) + maxEntries = value + self:updateDraw() + return self + end, + + getMaxEntries = function(self) + return maxEntries + end, + + clear = function(self) + graphData = {} + self:updateDraw() + return self + end, + + draw = function(self) + base.draw(self) + self:addDraw("graph", function() + local obx, oby = self:getPosition() + local w, h = self:getSize() + local bgCol, fgCol = self:getBackground(), self:getForeground() + + local range = maxValue - minValue + local prev_x, prev_y + + local startIndex = #graphData - maxEntries + 1 + if startIndex < 1 then startIndex = 1 end + + for i = startIndex, #graphData do + local data = graphData[i] + local x = math.floor(((w - 1) / (maxEntries - 1)) * (i - startIndex) + 1.5) + local y = math.floor((h - 1) - ((h - 1) / range) * (data - minValue) + 1.5) + + + if graphType == "scatter" then + self:addBackgroundBox(x, y, 1, 1, graphColor) + self:addForegroundBox(x, y, 1, 1, graphSymbolCol) + self:addTextBox(x, y, 1, 1, graphSymbol) + elseif graphType == "line" then + if prev_x and prev_y then + local dx = math.abs(x - prev_x) + local dy = math.abs(y - prev_y) + local sx = prev_x < x and 1 or -1 + local sy = prev_y < y and 1 or -1 + local err = dx - dy + + while true do + self:addBackgroundBox(prev_x, prev_y, 1, 1, graphColor) + self:addForegroundBox(prev_x, prev_y, 1, 1, graphSymbolCol) + self:addTextBox(prev_x, prev_y, 1, 1, graphSymbol) + + if prev_x == x and prev_y == y then + break + end + + local e2 = 2 * err + + if e2 > -dy then + err = err - dy + prev_x = prev_x + sx + end + + if e2 < dx then + err = err + dx + prev_y = prev_y + sy + end + end + end + prev_x, prev_y = x, y + elseif graphType == "bar" then + self:addBackgroundBox(x - 1, y, 1, h - y, graphColor) + end + end + end) + end, + + } + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/Image.lua b/Basalt/objects/Image.lua index a953a6b..f80a760 100644 --- a/Basalt/objects/Image.lua +++ b/Basalt/objects/Image.lua @@ -1,115 +1,195 @@ -local Object = require("Object") -local xmlValue = require("utils").getValueFromXML local images = require("images") - -local unpack,sub = table.unpack,string.sub -return function(name) +local bimg = require("bimg") +local unpack,sub,max,min = table.unpack,string.sub,math.max,math.min +return function(name, basalt) -- Image - local base = Object(name) + local base = basalt.getObject("VisualObject")(name, basalt) local objectType = "Image" - base:setZIndex(2) + + local bimgLibrary = bimg() + local bimgFrame = bimgLibrary.getFrameObject(1) local originalImage local image - local curFrame = 1 + local activeFrame = 1 + local infinitePlay = false local animTimer local usePalette = false - base.width = 24 - base.height = 8 + local xOffset, yOffset = 0, 0 + + base:setSize(24, 8) + base:setZIndex(2) local function getPalette(id) - if(originalImage~=nil)then - local p = {} - for k,v in pairs(colors)do - if(type(v)=="number")then - p[v] = {term.nativePaletteColor(v)} - end + local p = {} + for k,v in pairs(colors)do + if(type(v)=="number")then + p[k] = {term.nativePaletteColor(v)} end - if(originalImage.palette~=nil)then - for k,v in pairs(originalImage.palette)do - p[2^k] = v - end - end - if(originalImage[id]~=nil)and(originalImage[id].palette~=nil)then - for k,v in pairs(originalImage[id].palette)do - p[2^k] = v - end - end - return p end + local globalPalette = bimgLibrary.getMetadata("palette") + if(globalPalette~=nil)then + for k,v in pairs(globalPalette)do + p[k] = tonumber(v) + end + end + local localPalette = bimgLibrary.getFrameData("palette") + basalt.log(localPalette) + if(localPalette~=nil)then + for k,v in pairs(localPalette)do + p[k] = tonumber(v) + end + end + return p end local object = { - init = function(self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("ImageBG") - end - end, getType = function(self) return objectType - end; + end, + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, - loadImage = function(self, path, f) - if not(fs.exists(path))then error("No valid path: "..path) end - originalImage = images.loadImageAsBimg(path, f) - curFrame = 1 - image = originalImage - if(animTimer~=nil)then - os.cancelTimer(animTimer) + 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; + end, - setImage = function(self, data) - originalImage = data - image = originalImage - curFrame = 1 - if(animTimer~=nil)then - os.cancelTimer(animTimer) + getOffset = function(self) + return xOffset, yOffset + end, + + selectFrame = function(self, id) + if(bimgLibrary.getFrameObject(id)==nil)then + bimgLibrary.addFrame(id) end + bimgFrame = bimgLibrary.getFrameObject(id) + image = bimgFrame.getImage(id) + selectedFrame = id + self:updateDraw() + end, + + addFrame = function(self, id) + bimgLibrary.addFrame(id) + return self + end, + + getFrame = function(self, id) + return bimgLibrary.getFrame(id) + end, + + getFrameObject = function(self, id) + return bimgLibrary.getFrameObject(id) + end, + + removeFrame = function(self, id) + bimgLibrary.removeFrame(id) + return self + end, + + moveFrame = function(self, id, dir) + bimgLibrary.moveFrame(id, dir) + return self + end, + + getFrames = function(self) + return bimgLibrary.getFrames() + end, + + getFrameCount = function(self) + return #bimgLibrary.getFrames() + end, + + getActiveFrame = function(self) + return activeFrame + end, + + loadImage = function(self, path) + if(fs.exists(path))then + local newBimg = images.loadBIMG(path) + bimgLibrary = bimg(newBimg) + selectedFrame = 1 + bimgFrame = bimgLibrary.getFrameObject(1) + originalImage = bimgLibrary.createBimg() + image = bimgFrame.getImage() + self:updateDraw() + end + return self + end, + + setImage = function(self, t) + if(type(t)=="table")then + bimgLibrary = bimg(t) + selectedFrame = 1 + bimgFrame = bimgLibrary.getFrameObject(1) + originalImage = bimgLibrary.createBimg() + image = bimgFrame.getImage() + self:updateDraw() + end + return self + end, + + clear = function(self) + bimgLibrary = bimg() + bimgFrame = bimgLibrary.getFrameObject(1) + image = nil self:updateDraw() return self end, + getImage = function(self) + return bimgLibrary.createBimg() + end, + + getImageFrame = function(self, id) + return bimgFrame.getImage(id) + end, + usePalette = function(self, use) usePalette = use~=nil and use or true return self end, play = function(self, inf) - if(originalImage.animated)then - local t = originalImage[curFrame].duration or originalImage.secondsPerFrame or 0.2 - self.parent:addEvent("other_event", self) + if(bimgLibrary.getMetadata("animated"))then + local t = bimgLibrary.getMetadata("duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2 + self:listenEvent("other_event") animTimer = os.startTimer(t) infinitePlay = inf or false end return self end, - selectFrame = function(self, fr) - if(originalImage[fr]~=nil)then - curFrame = fr - if(animTimer~=nil)then - os.cancelTimer(animTimer) - end - self:updateDraw() - end + stop = function(self) + os.cancelTimer(animTimer) + animTimer = nil + infinitePlay = false + return self end, eventHandler = function(self, event, timerId, ...) base.eventHandler(self, event, timerId, ...) if(event=="timer")then if(timerId==animTimer)then - if(originalImage[curFrame+1]~=nil)then - curFrame = curFrame + 1 - local t = originalImage[curFrame].duration or originalImage.secondsPerFrame or 0.2 + if(bimgLibrary.getFrame(activeFrame+1)~=nil)then + activeFrame = activeFrame + 1 + self:selectFrame(activeFrame) + local t = bimgLibrary.getFrameData(activeFrame, "duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2 animTimer = os.startTimer(t) else if(infinitePlay)then - curFrame = 1 - local t = originalImage[curFrame].duration or originalImage.secondsPerFrame or 0.2 + activeFrame = 1 + self:selectFrame(activeFrame) + local t = bimgLibrary.getFrameData(activeFrame, "duration") or bimgLibrary.getMetadata("secondsPerFrame") or 0.2 animTimer = os.startTimer(t) end end @@ -118,46 +198,117 @@ return function(name) end end, + setMetadata = function(self, key, value) + bimgLibrary.setMetadata(key, value) + return self + end, + getMetadata = function(self, key) - return originalImage[key] + return bimgLibrary.getMetadata(key) end, - getImageSize = function(self) - return originalImage.width, originalImage.height + getFrameMetadata = function(self, id, key) + return bimgLibrary.getFrameData(id, key) end, - resizeImage = function(self, w, h) - image = images.resizeBIMG(originalImage, w, h) + setFrameMetadata = function(self, id, key, value) + bimgLibrary.setFrameData(id, key, value) + return self + end, + + blit = function(self, text, fg, bg, _x, _y) + x = _x or x + y = _y or y + bimgFrame.blit(text, fg, bg, x, y) + image = bimgFrame.getImage() self:updateDraw() return self end, - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("path", data)~=nil)then self:loadImage(xmlValue("path", data)) end + setText = function(self, text, _x, _y) + x = _x or x + y = _y or y + bimgFrame.text(text, x, y) + image = bimgFrame.getImage() + self:updateDraw() + return self + end, + + setBg = function(self, bg, _x, _y) + x = _x or x + y = _y or y + bimgFrame.bg(bg, x, y) + image = bimgFrame.getImage() + self:updateDraw() + return self + end, + + setFg = function(self, fg, _x, _y) + x = _x or x + y = _y or y + bimgFrame.fg(fg, x, y) + image = bimgFrame.getImage() + self:updateDraw() + return self + end, + + getImageSize = function(self) + return bimgLibrary.getSize() + end, + + setImageSize = function(self, w, h) + bimgLibrary.setSize(w, h) + image = bimgFrame.getImage() + self:updateDraw() + return self + end, + + resizeImage = function(self, w, h) + local newBimg = images.resizeBIMG(originalImage, w, h) + bimgLibrary = bimg(newBimg) + selectedFrame = 1 + bimgFrame = bimgLibrary.getFrameObject(1) + image = bimgFrame.getImage() + self:updateDraw() return self end, draw = function(self) - if (base.draw(self)) then - if (image ~= nil) then - if(usePalette)then - self:getBaseFrame():setThemeColor(getPalette(curFrame)) - end - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - for y,v in ipairs(image[curFrame])do - local t, f, b = unpack(v) - t = sub(t, 1,w) - f = sub(f, 1,w) - b = sub(b, 1,w) - self.parent:blit(obx, oby+y-1, t, f, b) - if(y==h)then break end + base.draw(self) + self:addDraw("image", function() + local w,h = self:getSize() + local x, y = self:getPosition() + local wParent, hParent = self:getParent():getSize() + local parentXOffset, parentYOffset = self:getParent():getOffset() + + if(x - parentXOffset > wParent)or(y - parentYOffset > hParent)or(x - parentXOffset + w < 1)or(y - parentYOffset + h < 1)then + return + end + + if(usePalette)then + self:getParent():setPalette(getPalette(activeFrame)) + end + + if(image~=nil)then + for k,v in pairs(image)do + if(k+yOffset<=h)and(k+yOffset>=1)then + local t,f,b = v[1],v[2],v[3] + + local startIdx = max(1 - xOffset, 1) + local endIdx = min(w - xOffset, #t) + + t = sub(t, startIdx, endIdx) + f = sub(f, startIdx, endIdx) + b = sub(b, startIdx, endIdx) + + self:addBlit(max(1 + xOffset, 1), k + yOffset, t, f, b) + end end end - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Input.lua b/Basalt/objects/Input.lua index 580c26a..a056105 100644 --- a/Basalt/objects/Input.lua +++ b/Basalt/objects/Input.lua @@ -1,46 +1,46 @@ -local Object = require("Object") local utils = require("utils") -local log = require("basaltLogs") -local xmlValue = utils.getValueFromXML +local tHex = require("tHex") -return function(name) +return function(name, basalt) -- Input - local base = Object(name) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "Input" local inputType = "text" local inputLimit = 0 base:setZIndex(5) base:setValue("") - base.width = 10 - base.height = 1 + base:setSize(12, 1) local textX = 1 local wIndex = 1 local defaultText = "" - local defaultBGCol - local defaultFGCol + local defaultBGCol = colors.black + local defaultFGCol = colors.white local showingText = defaultText local internalValueChange = false local object = { + load = function(self) + self:listenEvent("mouse_click") + self:listenEvent("key") + self:listenEvent("char") + self:listenEvent("other_event") + self:listenEvent("mouse_drag") + end, + getType = function(self) return objectType - end; - - setInputType = function(self, iType) - if (iType == "password") or (iType == "number") or (iType == "text") then - inputType = iType - end - self:updateDraw() - return self - end; + end, + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, setDefaultText = function(self, text, fCol, bCol) defaultText = text - defaultBGCol = bCol or defaultBGCol defaultFGCol = fCol or defaultFGCol + defaultBGCol = bCol or defaultBGCol if (self:isFocused()) then showingText = "" else @@ -48,11 +48,41 @@ return function(name) end self:updateDraw() return self - end; + 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; + end, setValue = function(self, val) base.setValue(self, tostring(val)) @@ -60,105 +90,84 @@ return function(name) textX = tostring(val):len() + 1 wIndex = math.max(1, textX-self:getWidth()+1) if(self:isFocused())then - local obx, oby = self:getAnchorPosition() - self.parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self.fgColor) + local parent = self:getParent() + local obx, oby = self:getPosition() + parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self:getForeground()) end end self:updateDraw() return self - end; + end, getValue = function(self) local val = base.getValue(self) return inputType == "number" and tonumber(val) or val - end; + end, setInputLimit = function(self, limit) inputLimit = tonumber(limit) or inputLimit self:updateDraw() return self - end; + end, getInputLimit = function(self) return inputLimit - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - local dBG,dFG - if(xmlValue("defaultBG", data)~=nil)then dBG = xmlValue("defaultBG", data) end - if(xmlValue("defaultFG", data)~=nil)then dFG = xmlValue("defaultFG", data) end - if(xmlValue("default", data)~=nil)then self:setDefaultText(xmlValue("default", data), dFG~=nil and colors[dFG], dBG~=nil and colors[dBG]) end - if(xmlValue("limit", data)~=nil)then self:setInputLimit(xmlValue("limit", data)) end - if(xmlValue("type", data)~=nil)then self:setInputType(xmlValue("type", data)) end - return self end, getFocusHandler = function(self) base.getFocusHandler(self) - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() + local parent = self:getParent() + if (parent ~= nil) then + local obx, oby = self:getPosition() showingText = "" if(defaultText~="")then self:updateDraw() end - self.parent:setCursor(true, obx + textX - wIndex, oby+math.max(math.ceil(self:getHeight()/2-1, 1)), self.fgColor) + parent:setCursor(true, obx + textX - wIndex, oby+math.max(math.ceil(self:getHeight()/2-1, 1)), self:getForeground()) end - end; + end, loseFocusHandler = function(self) base.loseFocusHandler(self) - if (self.parent ~= nil) then - showingText = defaultText - if(defaultText~="")then - self:updateDraw() - end - self.parent:setCursor(false) + local parent = self:getParent() + showingText = defaultText + if(defaultText~="")then + self:updateDraw() end - end; + parent:setCursor(false) + end, keyHandler = function(self, key) if (base.keyHandler(self, key)) then local w,h = self:getSize() + local parent = self:getParent() internalValueChange = true if (key == keys.backspace) then -- on backspace local text = tostring(base.getValue()) if (textX > 1) then self:setValue(text:sub(1, textX - 2) .. text:sub(textX, text:len())) - if (textX > 1) then - textX = textX - 1 - end - if (wIndex > 1) then - if (textX < wIndex) then - wIndex = wIndex - 1 - end + textX = math.max(textX - 1, 1) + if (textX < wIndex) then + wIndex = math.max(wIndex - 1, 1) end end end if (key == keys.enter) then - -- on enter - if (self.parent ~= nil) then - --self.parent:removeFocusedObject(self) - end + parent:removeFocusedObject(self) end if (key == keys.right) then - -- right arrow local tLength = tostring(base.getValue()):len() textX = textX + 1 if (textX > tLength) then textX = tLength + 1 end - if (textX < 1) then - textX = 1 - end + textX = math.max(textX, 1) if (textX < wIndex) or (textX >= w + wIndex) then wIndex = textX - w + 1 end - if (wIndex < 1) then - wIndex = 1 - end + wIndex = math.max(wIndex, 1) end if (key == keys.left) then @@ -169,29 +178,16 @@ return function(name) wIndex = textX end end - if (textX < 1) then - textX = 1 - end - if (wIndex < 1) then - wIndex = 1 - end + textX = math.max(textX, 1) + wIndex = math.max(wIndex, 1) end - local obx, oby = self:getAnchorPosition() + local obx, oby = self:getPosition() local val = tostring(base.getValue()) - local cursorX = (textX <= val:len() and textX - 1 or val:len()) - (wIndex - 1) - - local inpX = self:getX() - if (cursorX > inpX + w - 1) then - cursorX = inpX + w - 1 - end - if (self.parent ~= nil) then - self.parent:setCursor(true, obx + cursorX, oby+math.max(math.ceil(h/2-1, 1)), self.fgColor) - end + self:updateDraw() internalValueChange = false return true end - return false end, charHandler = function(self, char) @@ -220,27 +216,19 @@ return function(name) wIndex = wIndex + 1 end end - local obx, oby = self:getAnchorPosition() + local obx, oby = self:getPosition() local val = tostring(base.getValue()) - local cursorX = (textX <= val:len() and textX - 1 or val:len()) - (wIndex - 1) - local x = self:getX() - if (cursorX > x + w - 1) then - cursorX = x + w - 1 - end - if (self.parent ~= nil) then - self.parent:setCursor(true, obx + cursorX, oby+math.max(math.ceil(h/2-1, 1)), self.fgColor) - end internalValueChange = false self:updateDraw() return true end - return false end, mouseHandler = function(self, button, x, y) if(base.mouseHandler(self, button, x, y))then - local ax, ay = self:getAnchorPosition() + local parent = self:getParent() + local ax, ay = self:getPosition() local obx, oby = self:getAbsolutePosition(ax, ay) local w, h = self:getSize() textX = x - obx + wIndex @@ -254,7 +242,7 @@ return function(name) wIndex = 1 end end - self.parent:setCursor(true, ax + textX - wIndex, ay+math.max(math.ceil(h/2-1, 1)), self.fgColor) + parent:setCursor(true, ax + textX - wIndex, ay+math.max(math.ceil(h/2-1, 1)), self:getForeground()) return true end end, @@ -266,108 +254,51 @@ return function(name) return true end end - self.parent:removeFocusedObject() - end - end, - - eventHandler = function(self, event, paste, ...) - base.eventHandler(self, event, paste, ...) - if(event=="paste")then - if(self:isFocused())then - local text = base.getValue() - local w, h = self:getSize() - internalValueChange = true - 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())) - textX = textX + paste:len() - end - if (tonumber(base.getValue()) == nil) then - self:setValue(cache) - end - else - self:setValue(text:sub(1, textX - 1) .. paste .. text:sub(textX, text:len())) - textX = textX + paste:len() - end - if (textX >= w + wIndex) then - wIndex = (textX+1)-w - end - - local obx, oby = self:getAnchorPosition() - local val = tostring(base.getValue()) - local cursorX = (textX <= val:len() and textX - 1 or val:len()) - (wIndex - 1) - - local x = self:getX() - if (cursorX > x + w - 1) then - cursorX = x + w - 1 - end - if (self.parent ~= nil) then - self.parent:setCursor(true, obx + cursorX, oby+math.max(math.ceil(h/2-1, 1)), self.fgColor) - end - self:updateDraw() - internalValueChange = false - end + local parent = self:getParent() + parent:removeFocusedObject() end end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - local verticalAlign = utils.getTextVerticalAlign(h, "center") - - if(self.bgColor~=false)then self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) end - for n = 1, h do - if (n == verticalAlign) then - local val = tostring(base.getValue()) - local bCol = self.bgColor - local fCol = self.fgColor - local text - if (val:len() <= 0) then - text = showingText - bCol = defaultBGCol or bCol - fCol = defaultFGCol or fCol - end - - text = showingText - if (val ~= "") then - text = val - end - text = text:sub(wIndex, w + wIndex - 1) - local space = w - text:len() - if (space < 0) then - space = 0 - end - if (inputType == "password") and (val ~= "") then - text = string.rep("*", text:len()) - end - text = text .. string.rep(self.bgSymbol, space) - self.parent:writeText(obx, oby + (n - 1), text, bCol, fCol) - end - end - if(self:isFocused())then - self.parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self.fgColor) - end + base.draw(self) + self:addDraw("input", function() + local parent = self:getParent() + local obx, oby = self:getPosition() + local w,h = self:getSize() + local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign) + + local val = tostring(base.getValue()) + local bCol = self:getBackground() + local fCol = self:getForeground() + local text + if (val:len() <= 0) then + text = showingText + bCol = defaultBGCol or bCol + fCol = defaultFGCol or fCol end - end - end, - init = function(self) - if(self.parent~=nil)then - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("key", self) - self.parent:addEvent("char", self) - self.parent:addEvent("other_event", self) - self.parent:addEvent("mouse_drag", self) - end - if(base.init(self))then - self.bgColor = self.parent:getTheme("InputBG") - self.fgColor = self.parent:getTheme("InputText") - end + text = showingText + if (val ~= "") then + text = val + end + text = text:sub(wIndex, w + wIndex - 1) + local space = w - text:len() + if (space < 0) then + space = 0 + end + if (inputType == "password") and (val ~= "") then + text = string.rep("*", text:len()) + end + text = text .. string.rep(" ", space) + self:addBlit(1, verticalAlign, text, tHex[fCol]:rep(text:len()), tHex[bCol]:rep(text:len())) + + if(self:isFocused())then + parent:setCursor(true, obx + textX - wIndex, oby+math.floor(self:getHeight()/2), self:getForeground()) + end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Label.lua b/Basalt/objects/Label.lua index 662b167..8867d18 100644 --- a/Basalt/objects/Label.lua +++ b/Basalt/objects/Label.lua @@ -1,170 +1,94 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = utils.getValueFromXML -local createText = utils.createText +local wrapText = utils.wrapText local tHex = require("tHex") -local bigFont = require("bigfont") -return function(name) +return function(name, basalt) -- Label - local base = Object(name) + local base = basalt.getObject("VisualObject")(name, basalt) local objectType = "Label" base:setZIndex(3) local autoSize = true - base:setValue("Label") - base.width = 5 - - local textHorizontalAlign = "left" - local textVerticalAlign = "top" - local fontsize = 0 - local fgColChanged,bgColChanged = false,false + local text, textAlign = "Label", "left" local object = { getType = function(self) return objectType - end; + end, + + getBase = function(self) + return base + end, - setText = function(self, text) - text = tostring(text) - base:setValue(text) - if (autoSize) then - local xOffset = self.parent:getOffset() - if(text:len()+self:getX()>self.parent:getWidth()+xOffset)then - local newW = self.parent:getWidth()+xOffset - self:getX() - base.setSize(self, newW, #createText(text, newW)) - else - base.setSize(self, text:len(), 1) - end + setText = function(self, newText) + text = tostring(newText) + if(autoSize)then + self:setSize(#text, 1) + autoSize = true end self:updateDraw() return self - end; + end, + + getText = function(self) + return text + end, setBackground = function(self, col) base.setBackground(self, col) bgColChanged = true - self:updateDraw() return self end, setForeground = function(self, col) base.setForeground(self, col) fgColChanged = true - self:updateDraw() return self end, - setTextAlign = function(self, hor, vert) - textHorizontalAlign = hor or textHorizontalAlign - textVerticalAlign = vert or textVerticalAlign - self:updateDraw() - return self - end; - - setFontSize = function(self, size) - if(size>0)and(size<=4)then - fontsize = size-1 or 0 - end - self:updateDraw() - return self - end; - - getFontSize = function(self) - return fontsize+1 - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("text", data)~=nil)then self:setText(xmlValue("text", data)) end - if(xmlValue("verticalAlign", data)~=nil)then textVerticalAlign = xmlValue("verticalAlign", data) end - if(xmlValue("horizontalAlign", data)~=nil)then textHorizontalAlign = xmlValue("horizontalAlign", data) end - if(xmlValue("font", data)~=nil)then self:setFontSize(xmlValue("font", data)) end - return self - end, - - setSize = function(self, width, height, rel) - base.setSize(self, width, height, rel) + setSize = function(self, ...) + base.setSize(self, ...) autoSize = false - self:updateDraw() return self - end; + end, - eventHandler = function(self, event) - if(event=="basalt_resize")then - if (autoSize) then - local text = self:getValue() - if(text:len()+self:getX()>self.parent:getWidth())then - local newW = self.parent:getWidth() - self:getX() - base.setSize(self, newW, #createText(text, newW)) - else - base.setSize(self, text:len(), 1) - end - else - --self.parent:removeEvent("other_event", self) - end - end + setTextAlign = function(self, align) + textAlign = align or textAlign + return self; end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - local verticalAlign = utils.getTextVerticalAlign(h, textVerticalAlign) - if(fontsize==0)then - if not(autoSize)then - local text = createText(self:getValue(), self:getWidth()) - for k,v in pairs(text)do - if(k<=h)then - self.parent:writeText(obx, oby+k-1, v, self.bgColor, self.fgColor) - end - end - else - if(#self:getValue()+obx>self.parent:getWidth())then - local text = createText(self:getValue(), self:getWidth()) - for k,v in pairs(text)do - if(k<=h)then - self.parent:writeText(obx, oby+k-1, v, self.bgColor, self.fgColor) - end - end - else - self.parent:writeText(obx, oby, self:getValue(), self.bgColor, self.fgColor) - end + base.draw(self) + self:addDraw("label", function() + local parent = self:getParent() + local obx, oby = self:getPosition() + local w,h = self:getSize() + local bgCol,fgCol = self:getBackground(), self:getForeground() + if not(autoSize)then + local text = wrapText(text, w) + for k,v in pairs(text)do + if(k<=h)then + local align = textAlign=="center" and math.floor(w/2-v:len()/2+0.5) or textAlign=="right" and w-(v:len()-1) or 1 + self:addText(align, k, v) end - else - local tData = bigFont(fontsize, self:getValue(), self.fgColor, self.bgColor or colors.lightGray) - if(autoSize)then - self:setSize(#tData[1][1], #tData[1]-1) - end - local oX, oY = self.parent:getSize() - local cX, cY = #tData[1][1], #tData[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.parent:setFG(obx, oby + i - 1, tData[2][i]) - self.parent:setBG(obx, oby + i - 1, tData[3][i]) - self.parent:setText(obx, oby + i - 1, tData[1][i]) - end end + else + self:addText(1, 1, text:sub(1,w)) end - end + end) end, + init = function(self) - self.parent:addEvent("other_event", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("LabelBG") - self.fgColor = self.parent:getTheme("LabelText") - if(self.parent.bgColor==colors.black)and(self.fgColor==colors.black)then - self.fgColor = colors.lightGray - end - end + base.init(self) + local parent = self:getParent() + self:setForeground(parent:getForeground()) + self:setBackground(parent:getBackground()) end } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/List.lua b/Basalt/objects/List.lua index e1f3596..1204e70 100644 --- a/Basalt/objects/List.lua +++ b/Basalt/objects/List.lua @@ -1,59 +1,87 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = utils.getValueFromXML +local tHex = require("tHex") -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "List" - base.width = 16 - base.height = 6 - base:setZIndex(5) local list = {} - local itemSelectedBG - local itemSelectedFG + local itemSelectedBG = colors.black + local itemSelectedFG = colors.lightGray local selectionColorActive = true - local align = "left" + local textAlign = "left" local yOffset = 0 local scrollable = true + base:setSize(16, 8) + base:setZIndex(5) + local object = { + init = function(self) + local parent = self:getParent() + self:listenEvent("mouse_click") + self:listenEvent("mouse_drag") + self:listenEvent("mouse_scroll") + return base.init(self) + end, + + getBase = function(self) + return base + end, + + setTextAlign = function(self, align) + textAlign = align + return self + end, + + getTextAlign = function(self) + return textAlign + end, + + getBase = function(self) + return base + end, + getType = function(self) return objectType - end; + 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.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) + table.insert(list, { text = text, bgCol = bgCol or self:getBackground(), fgCol = fgCol or self:getForeground(), args = { ... } }) if (#list <= 1) then self:setValue(list[1], false) end self:updateDraw() return self - end; + end, setOffset = function(self, yOff) yOffset = yOff self:updateDraw() return self - end; + end, getOffset = function(self) return yOffset - end; + end, removeItem = function(self, index) table.remove(list, index) self:updateDraw() return self - end; + end, getItem = function(self, index) return list[index] - end; + end, getAll = function(self) return list - end; + end, getItemIndex = function(self) local selected = self:getValue() @@ -62,61 +90,53 @@ return function(name) return key end end - end; + end, clear = function(self) list = {} self:setValue({}, false) self:updateDraw() return self - end; + end, getItemCount = function(self) return #list - end; + end, editItem = function(self, index, text, bgCol, fgCol, ...) table.remove(list, index) - table.insert(list, index, { text = text, bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) + table.insert(list, index, { text = text, bgCol = bgCol or self:getBackground(), fgCol = fgCol or self:getForeground(), args = { ... } }) self:updateDraw() return self - end; + end, selectItem = function(self, index) self:setValue(list[index] or {}, false) self:updateDraw() return self - end; + end, - setSelectedItem = function(self, bgCol, fgCol, active) - itemSelectedBG = bgCol or self.bgColor - itemSelectedFG = fgCol or self.fgColor + 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; + end, + + getSelectionColor = function(self) + return itemSelectedBG, 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; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("selectionBG", data)~=nil)then itemSelectedBG = colors[xmlValue("selectionBG", data)] end - if(xmlValue("selectionFG", data)~=nil)then itemSelectedFG = colors[xmlValue("selectionFG", data)] end - if(xmlValue("scrollable", data)~=nil)then if(xmlValue("scrollable", data))then self:setScrollable(true) else self:setScrollable(false) end end - if(xmlValue("offset", data)~=nil)then yOffset = xmlValue("offset", data) end - if(data["item"]~=nil)then - local tab = data["item"] - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - self:addItem(xmlValue("text", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) - end - end - return self end, scrollHandler = function(self, dir, x, y) @@ -148,7 +168,7 @@ return function(name) mouseHandler = function(self, button, x, y) if(base.mouseHandler(self, button, x, y))then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) + local obx, oby = self:getAbsolutePosition() local w,h = self:getSize() if (#list > 0) then for n = 1, h do @@ -174,42 +194,25 @@ return function(name) end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - if(self.bgColor~=false)then - self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) - end - for n = 1, h do - if (list[n + yOffset] ~= nil) then - if (list[n + yOffset] == self:getValue()) then - if (selectionColorActive) then - self.parent:writeText(obx, oby + n - 1, utils.getTextHorizontalAlign(list[n + yOffset].text, w, align), itemSelectedBG, itemSelectedFG) - else - self.parent:writeText(obx, oby + n - 1, utils.getTextHorizontalAlign(list[n + yOffset].text, w, align), list[n + yOffset].bgCol, list[n + yOffset].fgCol) - end - else - self.parent:writeText(obx, oby + n - 1, utils.getTextHorizontalAlign(list[n + yOffset].text, w, align), list[n + yOffset].bgCol, list[n + yOffset].fgCol) - end + base.draw(self) + self:addDraw("list", function() + local parent = self:getParent() + local obx, oby = self:getPosition() + local w, h = self:getSize() + for n = 1, h do + if list[n + yOffset] then + local t = list[n + yOffset].text + local fg, bg = list[n + yOffset].fgCol, list[n + yOffset].bgCol + if list[n + yOffset] == self:getValue() and selectionColorActive then + fg, bg = itemSelectedFG, itemSelectedBG end + self:addBlit(1, n, t, tHex[fg]:rep(#t), tHex[bg]:rep(#t)) end end - end - end, - - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_drag", self) - self.parent:addEvent("mouse_scroll", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("ListBG") - self.fgColor = self.parent:getTheme("ListText") - itemSelectedBG = self.parent:getTheme("SelectionBG") - itemSelectedFG = self.parent:getTheme("SelectionText") - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Menubar.lua b/Basalt/objects/Menubar.lua index 76bc005..6bc2792 100644 --- a/Basalt/objects/Menubar.lua +++ b/Basalt/objects/Menubar.lua @@ -1,170 +1,69 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = utils.getValueFromXML local tHex = require("tHex") -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("List")(name, basalt) local objectType = "Menubar" local object = {} - base.width = 30 - base.height = 1 + base:setSize(30, 1) base:setZIndex(5) - local list = {} - local itemSelectedBG - local itemSelectedFG - local selectionColorActive = true - local align = "left" local itemOffset = 0 - local space = 1 - local scrollable = false + local space, outerSpace = 1, 1 + local scrollable = true local function maxScroll() local mScroll = 0 - local xPos = 0 - local w = object:getWidth() + local w = base:getWidth() + local list = base:getAll() for n = 1, #list do - if (xPos + list[n].text:len() + space * 2 > w) then - if(xPos < w)then - mScroll = mScroll + (list[n].text:len() + space * 2-(w - xPos)) - else - mScroll = mScroll + list[n].text:len() + space * 2 - end - end - xPos = xPos + list[n].text:len() + space * 2 - + mScroll = mScroll + list[n].text:len() + space * 2 end - return mScroll + return math.max(mScroll - w, 0) end object = { + init = function(self) + local parent = self:getParent() + self:listenEvent("mouse_click") + self:listenEvent("mouse_drag") + self:listenEvent("mouse_scroll") + return base.init(self) + end, + getType = function(self) return objectType - end; + end, - addItem = function(self, text, bgCol, fgCol, ...) - table.insert(list, { text = tostring(text), bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) - if (#list == 1) then - self:setValue(list[1]) - end - self:updateDraw() - return self - end; - - getAll = function(self) - return list - end; - - getItemIndex = function(self) - local selected = self:getValue() - for key, value in pairs(list) do - if (value == selected) then - return key - end - end - end; - - clear = function(self) - list = {} - self:setValue({}, false) - self:updateDraw() - return self - end; + getBase = function(self) + return base + end, setSpace = function(self, _space) space = _space or space self:updateDraw() return self - end; - - setOffset = function(self, offset) - itemOffset = offset or 0 - if (itemOffset < 0) then - itemOffset = 0 - end - - local mScroll = maxScroll() - if (itemOffset > mScroll) then - itemOffset = mScroll - end - self:updateDraw() - return self - end; - - getOffset = function(self) - return itemOffset - end; + end, setScrollable = function(self, scroll) scrollable = scroll if(scroll==nil)then scrollable = true end return self - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("selectionBG", data)~=nil)then itemSelectedBG = colors[xmlValue("selectionBG", data)] end - if(xmlValue("selectionFG", data)~=nil)then itemSelectedFG = colors[xmlValue("selectionFG", data)] end - if(xmlValue("scrollable", data)~=nil)then if(xmlValue("scrollable", data))then self:setScrollable(true) else self:setScrollable(false) end end - if(xmlValue("offset", data)~=nil)then self:setOffset(xmlValue("offset", data)) end - if(xmlValue("space", data)~=nil)then space = xmlValue("space", data) end - if(data["item"]~=nil)then - local tab = data["item"] - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - self:addItem(xmlValue("text", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) - end - end - return self end, - removeItem = function(self, index) - table.remove(list, index) - self:updateDraw() - return self - end; - - getItem = function(self, index) - return list[index] - end; - - getItemCount = function(self) - return #list - end; - - editItem = function(self, index, text, bgCol, fgCol, ...) - table.remove(list, index) - table.insert(list, index, { text = text, bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) - self:updateDraw() - return self - end; - - selectItem = function(self, index) - self:setValue(list[index] or {}, false) - self:updateDraw() - return self - end; - - setSelectedItem = function(self, bgCol, fgCol, active) - itemSelectedBG = bgCol or self.bgColor - itemSelectedFG = fgCol or self.fgColor - selectionColorActive = active - self:updateDraw() - return self - end; mouseHandler = function(self, button, x, y) - if(base.mouseHandler(self, button, x, y))then - local objX, objY = self:getAbsolutePosition(self:getAnchorPosition()) + if(base:getBase().mouseHandler(self, button, x, y))then + local objX, objY = self:getAbsolutePosition() local w,h = self:getSize() local xPos = 0 + local list = self:getAll() for n = 1, #list do if (list[n] ~= nil) then if (objX + xPos <= x + itemOffset) and (objX + xPos + list[n].text:len() + (space*2) > x + itemOffset) and (objY == y) then self:setValue(list[n]) - self:getEventSystem():sendEvent(event, self, event, 0, x, y, list[n]) + self:sendEvent(event, self, event, 0, x, y, list[n]) end xPos = xPos + list[n].text:len() + space * 2 end @@ -172,11 +71,10 @@ return function(name) self:updateDraw() return true end - return false end, scrollHandler = function(self, dir, x, y) - if(base.scrollHandler(self, dir, x, y))then + if(base:getBase().scrollHandler(self, dir, x, y))then if(scrollable)then itemOffset = itemOffset + dir if (itemOffset < 0) then @@ -196,46 +94,32 @@ return function(name) end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - if(self.bgColor~=false)then - self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) + base.draw(self) + self:addDraw("list", function() + local parent = self:getParent() + local obx, oby = self:getPosition() + local w,h = self:getSize() + local text = "" + local textBGCol = "" + local textFGCol = "" + local itemSelectedBG, itemSelectedFG = self:getSelectionColor() + for _, v in pairs(self:getAll()) do + local newItem = (" "):rep(space) .. v.text .. (" "):rep(space) + text = text .. newItem + if(v == self:getValue())then + textBGCol = textBGCol .. tHex[itemSelectedBG or v.bgCol or self:getBackground()]:rep(newItem:len()) + textFGCol = textFGCol .. tHex[itemSelectedFG or v.FgCol or self:getForeground()]:rep(newItem:len()) + else + textBGCol = textBGCol .. tHex[v.bgCol or self:getBackground()]:rep(newItem:len()) + textFGCol = textFGCol .. tHex[v.FgCol or self:getForeground()]:rep(newItem:len()) end - local text = "" - local textBGCol = "" - local textFGCol = "" - for _, v in pairs(list) do - local newItem = (" "):rep(space) .. v.text .. (" "):rep(space) - text = text .. newItem - if(v == self:getValue())then - textBGCol = textBGCol .. tHex[itemSelectedBG or v.bgCol or self.bgColor]:rep(newItem:len()) - textFGCol = textFGCol .. tHex[itemSelectedFG or v.FgCol or self.fgColor]:rep(newItem:len()) - else - textBGCol = textBGCol .. tHex[v.bgCol or self.bgColor]:rep(newItem:len()) - textFGCol = textFGCol .. tHex[v.FgCol or self.fgColor]:rep(newItem:len()) - end - end - - self.parent:setText(obx, oby, text:sub(itemOffset+1, w+itemOffset)) - self.parent:setBG(obx, oby, textBGCol:sub(itemOffset+1, w+itemOffset)) - self.parent:setFG(obx, oby, textFGCol:sub(itemOffset+1, w+itemOffset)) end - end - end, - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_scroll", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("MenubarBG") - self.fgColor = self.parent:getTheme("MenubarText") - itemSelectedBG = self.parent:getTheme("SelectionBG") - itemSelectedFG = self.parent:getTheme("SelectionText") - end + self:addBlit(1, 1, text:sub(itemOffset+1, w+itemOffset), textFGCol:sub(itemOffset+1, w+itemOffset), textBGCol:sub(itemOffset+1, w+itemOffset)) + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/MonitorFrame.lua b/Basalt/objects/MonitorFrame.lua new file mode 100644 index 0000000..55fd448 --- /dev/null +++ b/Basalt/objects/MonitorFrame.lua @@ -0,0 +1,40 @@ +local max,min,sub,rep = math.max,math.min,string.sub,string.rep + +return function(name, basalt) + local base = basalt.getObject("BaseFrame")(name, basalt) + local objectType = "MonitorFrame" + + base:hide() + + local object = { + getType = function() + return objectType + end, + + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + getBase = function(self) + return base + end, + + setMonitor = function(self, name) + local mon = peripheral.wrap(name) + if(mon~=nil)then + self:setTerm(mon) + end + return self + end, + + show = function(self) + if(basalt.getTerm()~=self:getTerm())then + base.show() + end + return self + end, + } + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/MovableFrame.lua b/Basalt/objects/MovableFrame.lua new file mode 100644 index 0000000..f67dc39 --- /dev/null +++ b/Basalt/objects/MovableFrame.lua @@ -0,0 +1,92 @@ +local max,min,sub,rep = math.max,math.min,string.sub,string.rep + +return function(name, basalt) + local base = basalt.getObject("Frame")(name, basalt) + local objectType = "MovableFrame" + local parent + + local dragXOffset, dragYOffset = 0, 0 + + local dragMap = { + {x1 = 1, x2 = "width", y1 = 1, y2 = 1} + } + + local object = { + getType = function() + return objectType + end, + + setDraggingMap = function(self, t) + dragMap = t + return self + end, + + getDraggingMap = function(self) + return dragMap + end, + + isType = function(self, t) + return objectType==t or (base.isType~=nil and base.isType(t)) or false + end, + + getBase = function(self) + return base + end, + + load = function(self) + base.load(self) + self:listenEvent("mouse_click") + self:listenEvent("mouse_up") + self:listenEvent("mouse_drag") + end, + + dragHandler = function(self, btn, x, y) + if(base.dragHandler(self, btn, x, y))then + if (isDragging) then + local xO, yO = parent:getOffset() + xO = xO < 0 and math.abs(xO) or -xO + yO = yO < 0 and math.abs(yO) or -yO + local parentX = 1 + local parentY = 1 + parentX, parentY = parent:getAbsolutePosition() + self:setPosition(x + dragXOffset - (parentX - 1) + xO, y + dragYOffset - (parentY - 1) + yO) + self:updateDraw() + end + return true + end + end, + + mouseHandler = function(self, btn, x, y, ...) + if(base.mouseHandler(self, btn, x, y, ...))then + parent:setImportant(self) + local fx, fy = self:getAbsolutePosition() + local w, h = self:getSize() + for k,v in pairs(dragMap)do + local x1, x2 = v.x1=="width" and w or v.x1, v.x2=="width" and w or v.x2 + local y1, y2= v.y1=="height" and h or v.y1, v.y2=="height" and h or v.y2 + if(x>=fx+x1-1)and(x<=fx+x2-1)and(y>=fy+y1-1)and(y<=fy+y2-1)then + isDragging = true + dragXOffset = fx - x + dragYOffset = fy - y + return true + end + end + return true + end + end, + + mouseUpHandler = function(self, ...) + isDragging = false + return base.mouseUpHandler(self, ...) + end, + + setParent = function(self, p, ...) + base.setParent(self, p, ...) + parent = p + return self + end, + } + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/Object.lua b/Basalt/objects/Object.lua new file mode 100644 index 0000000..d17a2cd --- /dev/null +++ b/Basalt/objects/Object.lua @@ -0,0 +1,240 @@ +local basaltEvent = require("basaltEvent") +local utils = require("utils") +local uuid = utils.uuid + +local unpack,sub = table.unpack,string.sub + +return function(name, basalt) + name = name or uuid() + assert(basalt~=nil, "Unable to find basalt instance! ID: "..name) + + -- Base object + local objectType = "Object" -- not changeable + local isEnabled,initialized = true,false + + local eventSystem = basaltEvent() + local activeEvents = {} + + local parent + + local object = { + init = function(self) + if(initialized)then return false end + initialized = true + return true + end, + + load = function(self) + end, + + getType = function(self) + return objectType + end, + isType = function(self, t) + return objectType==t + end, + + getName = function(self) + return name + end, + + getParent = function(self) + return parent + end, + + setParent = function(self, newParent, noRemove) + if(noRemove)then parent = newParent return self end + if (newParent.getType ~= nil and newParent:isType("Container")) then + self:remove() + newParent:addObject(self) + if (self.show) then + self:show() + end + parent = newParent + end + return self + end, + + updateEvents = function(self) + for k,v in pairs(activeEvents)do + parent:removeEvent(k, self) + if(v)then + parent:addEvent(k, self) + end + end + return self + end, + + listenEvent = function(self, event, active) + if(parent~=nil)then + if(active)or(active==nil)then + activeEvents[event] = true + parent:addEvent(event, self) + elseif(active==false)then + activeEvents[event] = false + parent:removeEvent(event, self) + end + end + return self + end, + + getZIndex = function(self) + return 1 + end, + + enable = function(self) + isEnabled = true + return self + end, + + disable = function(self) + isEnabled = false + return self + end, + + isEnabled = function(self) + return isEnabled + end, + + remove = function(self) + if (parent ~= nil) then + parent:removeObject(self) + end + self:updateDraw() + return self + end, + + getBaseFrame = function(self) + if(parent~=nil)then + return parent:getBaseFrame() + end + return self + end, + + onEvent = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("other_event", v) + end + end + return self + end, + + getEventSystem = function(self) + return eventSystem + end, + + registerEvent = function(self, event, func) + if(parent~=nil)then + parent:addEvent(event, self) + end + return eventSystem:registerEvent(event, func) + end, + + removeEvent = function(self, event, index) + if(eventSystem:getEventCount(event)<1)then + if(parent~=nil)then + parent:removeEvent(event, self) + end + end + return eventSystem:removeEvent(event, index) + end, + + sendEvent = function(self, event, ...) + return eventSystem:sendEvent(event, self, ...) + end, + + onClick = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_click", v) + end + end + return self + end, + + onClickUp = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_up", v) + end + end + return self + end, + + onRelease = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_release", v) + end + end + return self + end, + + onScroll = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_scroll", v) + end + end + return self + end, + + onHover = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_hover", v) + end + end + return self + end, + + onLeave = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_leave", v) + end + end + return self + end, + + onDrag = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_drag", v) + end + end + return self + end, + + onKey = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("key", v) + end + end + return self + end, + + onChar = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("char", v) + end + end + return self + end, + + onKeyUp = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("key_up", v) + end + end + return self + end, + } + + object.__index = object + return object +end \ No newline at end of file diff --git a/Basalt/objects/Pane.lua b/Basalt/objects/Pane.lua index cfe33b7..9f4ec9a 100644 --- a/Basalt/objects/Pane.lua +++ b/Basalt/objects/Pane.lua @@ -1,28 +1,16 @@ -local Object = require("Object") -local log = require("basaltLogs") - -return function(name) +return function(name, basalt) -- Pane - local base = Object(name) + local base = basalt.getObject("VisualObject")(name, basalt) local objectType = "Pane" + base:setSize(25, 10) + local object = { getType = function(self) return objectType - end; - - setBackground = function(self, col, sym, symC) - base.setBackground(self, col, sym, symC) - return self - end, - - init = function(self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("PaneBG") - self.fgColor = self.parent:getTheme("PaneBG") - end end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Program.lua b/Basalt/objects/Program.lua index 76f4594..2c2f353 100644 --- a/Basalt/objects/Program.lua +++ b/Basalt/objects/Program.lua @@ -1,19 +1,16 @@ -local Object = require("Object") local tHex = require("tHex") local process = require("process") -local xmlValue = require("utils").getValueFromXML local sub = string.sub -return function(name, parent) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("VisualObject")(name, basalt) local objectType = "Program" - base:setZIndex(5) local object local cachedPath local enviroment = {} - local function createBasaltWindow(x, y, width, height, self) + local function createBasaltWindow(x, y, width, height) local xCursor, yCursor = 1, 1 local bgColor, fgColor = colors.black, colors.white local cursorBlink = false @@ -30,7 +27,7 @@ return function(name, parent) for i = 0, 15 do local c = 2 ^ i - tPalette[c] = { parent:getBasaltInstance().getBaseTerm().getPaletteColour(c) } + tPalette[c] = { basalt.getTerm().getPaletteColour(c) } end local function createEmptyLines() @@ -66,67 +63,17 @@ return function(name, parent) end local function internalBlit(sText, sTextColor, sBackgroundColor) - -- copy pasti strikes again (cc: window.lua) - local nStart = xCursor - local nEnd = nStart + #sText - 1 - if yCursor >= 1 and yCursor <= height then - if nStart <= width and nEnd >= 1 then - -- Modify line - if nStart == 1 and nEnd == width then - cacheT[yCursor] = sText - cacheFG[yCursor] = sTextColor - cacheBG[yCursor] = sBackgroundColor - else - local sClippedText, sClippedTextColor, sClippedBackgroundColor - if nStart < 1 then - local nClipStart = 1 - nStart + 1 - local nClipEnd = width - nStart + 1 - sClippedText = sub(sText, nClipStart, nClipEnd) - sClippedTextColor = sub(sTextColor, nClipStart, nClipEnd) - sClippedBackgroundColor = sub(sBackgroundColor, nClipStart, nClipEnd) - elseif nEnd > width then - local nClipEnd = width - nStart + 1 - sClippedText = sub(sText, 1, nClipEnd) - sClippedTextColor = sub(sTextColor, 1, nClipEnd) - sClippedBackgroundColor = sub(sBackgroundColor, 1, nClipEnd) - else - sClippedText = sText - sClippedTextColor = sTextColor - sClippedBackgroundColor = sBackgroundColor - end - - local sOldText = cacheT[yCursor] - local sOldTextColor = cacheFG[yCursor] - local sOldBackgroundColor = cacheBG[yCursor] - local sNewText, sNewTextColor, sNewBackgroundColor - if nStart > 1 then - local nOldEnd = nStart - 1 - sNewText = sub(sOldText, 1, nOldEnd) .. sClippedText - sNewTextColor = sub(sOldTextColor, 1, nOldEnd) .. sClippedTextColor - sNewBackgroundColor = sub(sOldBackgroundColor, 1, nOldEnd) .. sClippedBackgroundColor - else - sNewText = sClippedText - sNewTextColor = sClippedTextColor - sNewBackgroundColor = sClippedBackgroundColor - end - if nEnd < width then - local nOldStart = nEnd + 1 - sNewText = sNewText .. sub(sOldText, nOldStart, width) - sNewTextColor = sNewTextColor .. sub(sOldTextColor, nOldStart, width) - sNewBackgroundColor = sNewBackgroundColor .. sub(sOldBackgroundColor, nOldStart, width) - end - - cacheT[yCursor] = sNewText - cacheFG[yCursor] = sNewTextColor - cacheBG[yCursor] = sNewBackgroundColor - end - object:updateDraw() - end - xCursor = nEnd + 1 - if (visible) then - updateCursor() - end + if yCursor < 1 or yCursor > height or xCursor < 1 or xCursor + #sText - 1 > width then + return end + cacheT[yCursor] = sub(cacheT[yCursor], 1, xCursor - 1) .. sText .. sub(cacheT[yCursor], xCursor + #sText, width) + cacheFG[yCursor] = sub(cacheFG[yCursor], 1, xCursor - 1) .. sTextColor .. sub(cacheFG[yCursor], xCursor + #sText, width) + cacheBG[yCursor] = sub(cacheBG[yCursor], 1, xCursor - 1) .. sBackgroundColor .. sub(cacheBG[yCursor], xCursor + #sText, width) + xCursor = xCursor + #sText + if visible then + updateCursor() + end + object:updateDraw() end local function setText(_x, _y, text) @@ -233,7 +180,7 @@ return function(name, parent) if (visible) then updateCursor() end - end; + end, getCursorPos = function() return xCursor, yCursor @@ -310,57 +257,40 @@ return function(name, parent) end end; - writeText = function(_x, _y, text, bgCol, fgCol) - bgCol = bgCol or bgColor - fgCol = fgCol or fgColor - setText(x, _y, text) - setBG(_x, _y, tHex[bgCol]:rep(text:len())) - setFG(_x, _y, tHex[fgCol]:rep(text:len())) - end; - basalt_update = function() - if (parent ~= nil) then - for n = 1, height do - parent:setText(x, y + (n - 1), cacheT[n]) - parent:setBG(x, y + (n - 1), cacheBG[n]) - parent:setFG(x, y + (n - 1), cacheFG[n]) - end + for n = 1, height do + object:addBlit(1, n, cacheT[n], cacheFG[n], cacheBG[n]) end - end; + end, scroll = function(offset) - if type(offset) ~= "number" then - error("bad argument #1 (expected number, got " .. type(offset) .. ")", 2) - end + assert(type(offset) == "number", "bad argument #1 (expected number, got " .. type(offset) .. ")") if offset ~= 0 then - local sEmptyText = emptySpaceLine - local sEmptyTextColor = emptyColorLines[fgColor] - local sEmptyBackgroundColor = emptyColorLines[bgColor] - for newY = 1, height do - local y = newY + offset - if y >= 1 and y <= height then - cacheT[newY] = cacheT[y] - cacheBG[newY] = cacheBG[y] - cacheFG[newY] = cacheFG[y] - else - cacheT[newY] = sEmptyText - cacheFG[newY] = sEmptyTextColor - cacheBG[newY] = sEmptyBackgroundColor - end + for newY = 1, height do + local y = newY + offset + if y < 1 or y > height then + cacheT[newY] = emptySpaceLine + cacheFG[newY] = emptyColorLines[fgColor] + cacheBG[newY] = emptyColorLines[bgColor] + else + cacheT[newY] = cacheT[y] + cacheBG[newY] = cacheBG[y] + cacheFG[newY] = cacheFG[y] end + end end if (visible) then updateCursor() end - end; + end, isColor = function() - return parent:getBasaltInstance().getBaseTerm().isColor() + return basalt.getTerm().isColor() end; isColour = function() - return parent:getBasaltInstance().getBaseTerm().isColor() + return basalt.getTerm().isColor() end; write = function(text) @@ -416,19 +346,20 @@ return function(name, parent) return basaltwindow end - base.width = 30 - base.height = 12 - local pWindow = createBasaltWindow(1, 1, base.width, base.height) + base:setZIndex(5) + base:setSize(30, 12) + local pWindow = createBasaltWindow(1, 1, 30, 12) local curProcess local paused = false local queuedEvent = {} local function updateCursor(self) + local parent = self:getParent() local xCur, yCur = pWindow.getCursorPos() - local obx, oby = self:getAnchorPosition() + local obx, oby = self:getPosition() local w,h = self:getSize() if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then - self.parent:setCursor(self:isFocused() and pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) + parent:setCursor(self:isFocused() and pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) end end @@ -452,7 +383,7 @@ return function(name, parent) end if not (curProcess:isDead()) then if not (paused) then - local absX, absY = self:getAbsolutePosition(self:getAnchorPosition(nil, nil, true)) + local absX, absY = self:getAbsolutePosition() resumeProcess(self, event, p1, x-absX+1, y-absY+1) updateCursor(self) end @@ -480,8 +411,8 @@ return function(name, parent) show = function(self) base.show(self) - pWindow.setBackgroundColor(self.bgColor) - pWindow.setTextColor(self.fgColor) + pWindow.setBackgroundColor(self:getBackground()) + pWindow.setTextColor(self:getForeground()) pWindow.basalt_setVisible(true) return self end; @@ -494,14 +425,8 @@ return function(name, parent) setPosition = function(self, x, y, rel) base.setPosition(self, x, y, rel) - pWindow.basalt_reposition(self:getAnchorPosition()) + pWindow.basalt_reposition(self:getPosition()) return self - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("path", data)~=nil)then cachedPath = xmlValue("path", data) end - if(xmlValue("execute", data)~=nil)then if(xmlValue("execute", data))then if(cachedPath~=nil)then self:execute(cachedPath) end end end end, getBasaltWindow = function() @@ -537,37 +462,34 @@ return function(name, parent) pWindow.setTextColor(colors.white) pWindow.clear() pWindow.setCursorPos(1, 1) - pWindow.setBackgroundColor(self.bgColor) - pWindow.setTextColor(self.fgColor) + pWindow.setBackgroundColor(self:getBackground()) + pWindow.setTextColor(self:getForeground() or colors.white) pWindow.basalt_setVisible(true) resumeProcess(self) paused = false - if(self.parent~=nil)then - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_up", self) - self.parent:addEvent("mouse_drag", self) - self.parent:addEvent("mouse_scroll", self) - self.parent:addEvent("key", self) - self.parent:addEvent("key_up", self) - self.parent:addEvent("char", self) - self.parent:addEvent("other_event", self) - end + self:listenEvent("mouse_click", self) + self:listenEvent("mouse_up", self) + self:listenEvent("mouse_drag", self) + self:listenEvent("mouse_scroll", self) + self:listenEvent("key", self) + self:listenEvent("key_up", self) + self:listenEvent("char", self) + self:listenEvent("other_event", self) return self end; - stop = function(self) + stop = function(self) + local parent = self:getParent() if (curProcess ~= nil) then if not (curProcess:isDead()) then resumeProcess(self, "terminate") if (curProcess:isDead()) then - if (self.parent ~= nil) then - self.parent:setCursor(false) - end + parent:setCursor(false) end end end - self.parent:removeEvents(self) + parent:removeEvents(self) return self end; @@ -588,13 +510,13 @@ return function(name, parent) return paused end; - injectEvent = function(self, event, p1, p2, p3, p4, ign) + injectEvent = function(self, event, ign, ...) if (curProcess ~= nil) then if not (curProcess:isDead()) then if (paused == false) or (ign) then - resumeProcess(self, event, p1, p2, p3, p4) + resumeProcess(self, event, ...) else - table.insert(queuedEvent, { event = event, args = { p1, p2, p3, p4 } }) + table.insert(queuedEvent, { event = event, args = {...} }) end end end @@ -610,10 +532,10 @@ return function(name, parent) return self end; - injectEvents = function(self, events) + injectEvents = function(self, ...) if (curProcess ~= nil) then if not (curProcess:isDead()) then - for _, value in pairs(events) do + for _, value in pairs({...}) do resumeProcess(self, value.event, table.unpack(value.args)) end end @@ -682,12 +604,13 @@ return function(name, parent) if (curProcess ~= nil) then if not (curProcess:isDead()) then if not (paused) then - if (self.parent ~= nil) then + local parent = self:getParent() + if (parent ~= nil) then local xCur, yCur = pWindow.getCursorPos() - local obx, oby = self:getAnchorPosition() + local obx, oby = self:getPosition() local w,h = self:getSize() if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then - self.parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) + parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) end end end @@ -699,77 +622,47 @@ return function(name, parent) base.loseFocusHandler(self) if (curProcess ~= nil) then if not (curProcess:isDead()) then - if (self.parent ~= nil) then - self.parent:setCursor(false) + local parent = self:getParent() + if (parent ~= nil) then + parent:setCursor(false) end end end end, - - customEventHandler = function(self, event, ...) - base.customEventHandler(self, event, ...) - if (curProcess == nil) then - return - end - if(event=="basalt_resize")then - local w, h = pWindow.getSize() - local pW, pH = self:getSize() - if(w~=pW)or(h~=pH)then - pWindow.basalt_resize(pW, pH) - if not (curProcess:isDead()) then - resumeProcess(self, "term_resize") - end - end - pWindow.basalt_reposition(self:getAnchorPosition()) - - end - end, - eventHandler = function(self, event, p1, p2, p3, p4) - base.eventHandler(self, event, p1, p2, p3, p4) - if (curProcess == nil) then + eventHandler = function(self, event, ...) + base.eventHandler(self, event, ...) + if curProcess == nil then return end - if not (curProcess:isDead()) then - if not (paused) then - if(event ~= "terminate") then - resumeProcess(self, event, p1, p2, p3, p4) - end - if (self:isFocused()) then - local obx, oby = self:getAnchorPosition() + if not curProcess:isDead() then + if not paused then + resumeProcess(self, event, ...) + if self:isFocused() then + local parent = self:getParent() + local obx, oby = self:getPosition() local xCur, yCur = pWindow.getCursorPos() - if (self.parent ~= nil) then - local w,h = self:getSize() - if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then - self.parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) - end - end - - if (event == "terminate") then - resumeProcess(self, event) - self.parent:setCursor(false) - return true + local w,h = self:getSize() + if obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1 then + parent:setCursor(pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) end end else - table.insert(queuedEvent, { event = event, args = { p1, p2, p3, p4 } }) + table.insert(queuedEvent, { event = event, args = { ... } }) end end end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local xCur, yCur = pWindow.getCursorPos() - local w,h = self:getSize() - pWindow.basalt_reposition(obx, oby) - pWindow.basalt_update() - if (obx + xCur - 1 >= 1 and obx + xCur - 1 <= obx + w - 1 and yCur + oby - 1 >= 1 and yCur + oby - 1 <= oby + h - 1) then - self.parent:setCursor(self:isFocused() and pWindow.getCursorBlink(), obx + xCur - 1, yCur + oby - 1, pWindow.getTextColor()) - end - end - end + 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_reposition(obx, oby) + pWindow.basalt_update() + end) end, onError = function(self, ...) @@ -778,9 +671,8 @@ return function(name, parent) self:registerEvent("program_error", v) end end - if(self.parent~=nil)then - self.parent:addEvent("other_event", self) - end + local parent = self:getParent() + self:listenEvent("other_event") return self end, @@ -790,19 +682,13 @@ return function(name, parent) self:registerEvent("program_done", v) end end - if(self.parent~=nil)then - self.parent:addEvent("other_event", self) - end + local parent = self:getParent() + self:listenEvent("other_event") return self end, - init = function(self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("ProgramBG") - end - end, - } + object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/Progressbar.lua b/Basalt/objects/Progressbar.lua index 8b17151..deb70c4 100644 --- a/Basalt/objects/Progressbar.lua +++ b/Basalt/objects/Progressbar.lua @@ -1,52 +1,29 @@ -local Object = require("Object") -local xmlValue = require("utils").getValueFromXML - -return function(name) - -- Checkbox - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "Progressbar" local progress = 0 base:setZIndex(5) base:setValue(false) - base.width = 25 - base.height = 1 + base:setSize(25, 3) - local activeBarColor + local activeBarColor = colors.black local activeBarSymbol = "" local activeBarSymbolCol = colors.white local bgBarSymbol = "" local direction = 0 local object = { - init = function(self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("ProgressbarBG") - self.fgColor = self.parent:getTheme("ProgressbarText") - activeBarColor = self.parent:getTheme("ProgressbarActiveBG") - end - end, getType = function(self) return objectType - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("direction", data)~=nil)then direction = xmlValue("direction", data) end - if(xmlValue("progressColor", data)~=nil)then activeBarColor = colors[xmlValue("progressColor", data)] end - if(xmlValue("progressSymbol", data)~=nil)then activeBarSymbol = xmlValue("progressSymbol", data) end - if(xmlValue("backgroundSymbol", data)~=nil)then bgBarSymbol = xmlValue("backgroundSymbol", data) end - if(xmlValue("progressSymbolColor", data)~=nil)then activeBarSymbolCol = colors[xmlValue("progressSymbolColor", data)] end - if(xmlValue("onDone", data)~=nil)then self:generateXMLEventFunction(self.onProgressDone, xmlValue("onDone", data)) end - return self end, setDirection = function(self, dir) direction = dir self:updateDraw() return self - end; + end, setProgressBar = function(self, color, symbol, symbolcolor) activeBarColor = color or activeBarColor @@ -54,13 +31,17 @@ return function(name) activeBarSymbolCol = symbolcolor or activeBarSymbolCol self:updateDraw() return self - end; + end, + + getProgressBar = function(self) + return activeBarColor, activeBarSymbol, activeBarSymbolCol + end, setBackgroundSymbol = function(self, symbol) bgBarSymbol = symbol:sub(1, 1) self:updateDraw() return self - end; + end, setProgress = function(self, value) if (value >= 0) and (value <= 100) and (progress ~= value) then @@ -72,51 +53,52 @@ return function(name) end self:updateDraw() return self - end; + end, getProgress = function(self) return progress - end; + end, onProgressDone = function(self, f) self:registerEvent("progress_done", f) return self - end; + end, progressDoneHandler = function(self) self:sendEvent("progress_done", self) - end; + end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - if(self.bgColor~=false)then self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) end - if(bgBarSymbol~="")then self.parent:drawTextBox(obx, oby, w, h, bgBarSymbol) end - if(self.fgColor~=false)then self.parent:drawForegroundBox(obx, oby, w, h, self.fgColor) end - if (direction == 1) then - self.parent:drawBackgroundBox(obx, oby, w, h / 100 * progress, activeBarColor) - self.parent:drawForegroundBox(obx, oby, w, h / 100 * progress, activeBarSymbolCol) - self.parent:drawTextBox(obx, oby, w, h / 100 * progress, activeBarSymbol) - elseif (direction == 2) then - self.parent:drawBackgroundBox(obx, oby + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarColor) - self.parent:drawForegroundBox(obx, oby + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbolCol) - self.parent:drawTextBox(obx, oby + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbol) - elseif (direction == 3) then - self.parent:drawBackgroundBox(obx + math.ceil(w - w / 100 * progress), oby, w / 100 * progress, h, activeBarColor) - self.parent:drawForegroundBox(obx + math.ceil(w - w / 100 * progress), oby, w / 100 * progress, h, activeBarSymbolCol) - self.parent:drawTextBox(obx + math.ceil(w - w / 100 * progress), oby, w / 100 * progress, h, activeBarSymbol) - else - self.parent:drawBackgroundBox(obx, oby, w / 100 * progress, h, activeBarColor) - self.parent:drawForegroundBox(obx, oby, w / 100 * progress, h, activeBarSymbolCol) - self.parent:drawTextBox(obx, oby, w / 100 * progress, h, activeBarSymbol) - end + base.draw(self) + self:addDraw("progressbar", function() + local obx, oby = self:getPosition() + local w,h = self:getSize() + local bgCol,fgCol = self:getBackground(), self:getForeground() + if(bgCol~=false)then self:addBackgroundBox(obx, oby, w, h, bgCol) end + if(bgBarSymbol~="")then self:addTextBox(obx, oby, w, h, bgBarSymbol) end + if(fgCol~=false)then self:addForegroundBox(obx, oby, w, h, fgCol) end + if (direction == 1) then + self:addBackgroundBox(obx, oby, w, h / 100 * progress, activeBarColor) + self:addForegroundBox(obx, oby, w, h / 100 * progress, activeBarSymbolCol) + self:addTextBox(obx, oby, w, h / 100 * progress, activeBarSymbol) + elseif (direction == 2) then + self:addBackgroundBox(obx, oby + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarColor) + self:addForegroundBox(obx, oby + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbolCol) + self:addTextBox(obx, oby + math.ceil(h - h / 100 * progress), w, h / 100 * progress, activeBarSymbol) + elseif (direction == 3) then + self:addBackgroundBox(obx + math.ceil(w - w / 100 * progress), oby, w / 100 * progress, h, activeBarColor) + self:addForegroundBox(obx + math.ceil(w - w / 100 * progress), oby, w / 100 * progress, h, activeBarSymbolCol) + self:addTextBox(obx + math.ceil(w - w / 100 * progress), oby, w / 100 * progress, h, activeBarSymbol) + else + self:addBackgroundBox(obx, oby, w / 100 * progress, h, activeBarColor) + self:addForegroundBox(obx, oby, w / 100 * progress, h, activeBarSymbolCol) + self:addTextBox(obx, oby, w / 100 * progress, h, activeBarSymbol) end - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Radio.lua b/Basalt/objects/Radio.lua index 1594a5b..304f3ba 100644 --- a/Basalt/objects/Radio.lua +++ b/Basalt/objects/Radio.lua @@ -1,20 +1,18 @@ -local Object = require("Object") local utils = require("utils") -local xmlValue = utils.getValueFromXML +local tHex = require("tHex") -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("List")(name, basalt) local objectType = "Radio" - base.width = 8 + + base:setSize(1, 1) base:setZIndex(5) local list = {} - local itemSelectedBG - local itemSelectedFG - local boxSelectedBG - local boxSelectedFG - local boxNotSelectedBG - local boxNotSelectedFG + 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" @@ -22,148 +20,87 @@ return function(name) local object = { getType = function(self) return objectType - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("selectionBG", data)~=nil)then itemSelectedBG = colors[xmlValue("selectionBG", data)] end - if(xmlValue("selectionFG", data)~=nil)then itemSelectedFG = colors[xmlValue("selectionFG", data)] end - if(xmlValue("boxBG", data)~=nil)then boxSelectedBG = colors[xmlValue("boxBG", data)] end - if(xmlValue("inactiveBoxBG", data)~=nil)then boxNotSelectedBG = colors[xmlValue("inactiveBoxBG", data)] end - if(xmlValue("inactiveBoxFG", data)~=nil)then boxNotSelectedFG = colors[xmlValue("inactiveBoxFG", data)] end - if(xmlValue("boxFG", data)~=nil)then boxSelectedFG = colors[xmlValue("boxFG", data)] end - if(xmlValue("symbol", data)~=nil)then symbol = xmlValue("symbol", data) end - if(data["item"]~=nil)then - local tab = data["item"] - if(tab.properties~=nil)then tab = {tab} end - for k,v in pairs(tab)do - self:addItem(xmlValue("text", v), xmlValue("x", v), xmlValue("y", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) - end - end - return self end, addItem = function(self, text, x, y, bgCol, fgCol, ...) - table.insert(list, { x = x or 1, y = y or 1, text = text, bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) - if (#list == 1) then - self:setValue(list[1]) - end - self:updateDraw() - return self - end; - - getAll = function(self) - return list - end; - - removeItem = function(self, index) - table.remove(list, index) - self:updateDraw() - return self - end; - - getItem = function(self, index) - return list[index] - end; - - getItemIndex = function(self) - local selected = self:getValue() - for key, value in pairs(list) do - if (value == selected) then - return key - end - end - end; - - clear = function(self) - list = {} - self:setValue({}, false) - self:updateDraw() - return self - end; - - getItemCount = function(self) - return #list - end; - - editItem = function(self, index, text, x, y, bgCol, fgCol, ...) - table.remove(list, index) - table.insert(list, index, { x = x or 1, y = y or 1, text = text, bgCol = bgCol or self.bgColor, fgCol = fgCol or self.fgColor, args = { ... } }) - self:updateDraw() - return self - end; - - selectItem = function(self, index) - self:setValue(list[index] or {}, false) - self:updateDraw() - return self - end; - - setActiveSymbol = function(self, sym) - symbol = sym:sub(1,1) - self:updateDraw() + base.addItem(self, text, bgCol, fgCol, ...) + table.insert(list, { x = x or 1, y = y or #list * 2 }) return self end, - setSelectedItem = function(self, bgCol, fgCol, boxBG, boxFG, active) - itemSelectedBG = bgCol or itemSelectedBG - itemSelectedFG = fgCol or itemSelectedFG - boxSelectedBG = boxBG or boxSelectedBG - boxSelectedFG = boxFG or boxSelectedFG - selectionColorActive = active~=nil and active or true - self:updateDraw() + removeItem = function(self, index) + base.removeItem(self, index) + table.remove(list, index) return self - end; + end, - mouseHandler = function(self, button, x, y) + clear = function(self) + base.clear(self) + list = {} + return self + end, + + editItem = function(self, index, text, x, y, bgCol, fgCol, ...) + base.editItem(self, index, text, bgCol, fgCol, ...) + table.remove(list, index) + table.insert(list, index, { x = x or 1, y = y or 1 }) + return self + end, + + setBoxSelectionColor = function(self, bg, fg) + boxSelectedBG = bg + boxSelectedFG = fg + return self + end, + + getBoxSelectionColor = function(self) + return boxSelectedBG, boxSelectedFG + end, + + setBoxDefaultColor = function(self, bg, fg) + boxNotSelectedBG = bg + boxNotSelectedFG = fg + return self + end, + + getBoxDefaultColor = function(self) + return boxNotSelectedBG, boxNotSelectedFG + end, + + mouseHandler = function(self, button, x, y, ...) if (#list > 0) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) - for _, value in pairs(list) do - if (obx + value.x - 1 <= x) and (obx + value.x - 1 + value.text:len() + 1 >= x) and (oby + value.y - 1 == y) then + local obx, oby = self:getAbsolutePosition() + local baseList = self:getAll() + for k, value in pairs(baseList) do + if (obx + list[k].x - 1 <= x) and (obx + list[k].x - 1 + value.text:len() + 1 >= x) and (oby + list[k].y - 1 == y) then self:setValue(value) - local val = self:getEventSystem():sendEvent("mouse_click", self, "mouse_click", button, x, y) - if(val==false)then return val end - if(self.parent~=nil)then - self.parent:setFocusedObject(self) - end + local val = self:sendEvent("mouse_click", self, "mouse_click", button, x, y, ...) self:updateDraw() + if(val==false)then return val end return true end end end - return false - end; + end, draw = function(self) - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - for _, value in pairs(list) do + self:addDraw("radio", function() + local itemSelectedBG, itemSelectedFG = self:getSelectionColor() + local baseList = self:getAll() + for k, value in pairs(baseList) do if (value == self:getValue()) then - if (align == "left") then - self.parent:writeText(value.x + obx - 1, value.y + oby - 1, symbol, boxSelectedBG, boxSelectedFG) - self.parent:writeText(value.x + 2 + obx - 1, value.y + oby - 1, value.text, itemSelectedBG, itemSelectedFG) - end + self:addBlit(list[k].x, list[k].y, symbol, tHex[boxSelectedFG], tHex[boxSelectedBG]) + self:addBlit(list[k].x + 2, list[k].y, value.text, tHex[itemSelectedFG]:rep(#value.text), tHex[itemSelectedBG]:rep(#value.text)) else - self.parent:drawBackgroundBox(value.x + obx - 1, value.y + oby - 1, 1, 1, boxNotSelectedBG or self.bgColor) - self.parent:writeText(value.x + 2 + obx - 1, value.y + oby - 1, value.text, value.bgCol, value.fgCol) + self:addBackgroundBox(list[k].x, list[k].y, 1, 1, boxNotSelectedBG or colors.black) + self:addBlit(list[k].x + 2, list[k].y, value.text, tHex[value.fgCol]:rep(#value.text), tHex[value.bgCol]:rep(#value.text)) end end return true - end - end, - - init = function(self) - self.parent:addEvent("mouse_click", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("MenubarBG") - self.fgColor = self.parent:getTheme("MenubarFG") - itemSelectedBG = self.parent:getTheme("SelectionBG") - itemSelectedFG = self.parent:getTheme("SelectionText") - boxSelectedBG = self.parent:getTheme("MenubarBG") - boxSelectedFG = self.parent:getTheme("MenubarText") - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/ScrollableFrame.lua b/Basalt/objects/ScrollableFrame.lua new file mode 100644 index 0000000..6cb9c7b --- /dev/null +++ b/Basalt/objects/ScrollableFrame.lua @@ -0,0 +1,85 @@ +local max,min,sub,rep = math.max,math.min,string.sub,string.rep + +return function(name, basalt) + local base = basalt.getObject("Frame")(name, basalt) + local objectType = "ScrollableFrame" + local parent + + local direction = 0 + + local function getHorizontalScrollAmount(self) + local amount = 0 + local objects = self:getObjects() + for _, b in pairs(objects) do + if(b.element.getWidth~=nil)and(b.element.getX~=nil)then + local h, y = b.element:getWidth(), b.element:getX() + local width = self:getWidth() + if (h + y - width >= amount) then + amount = max(h + y - width, 0) + end + end + end + return amount + end + + local function getVerticalScrollAmount(self) + local amount = 0 + local objects = self:getObjects() + for _, b in pairs(objects) do + if(b.element.getHeight~=nil)and(b.element.getY~=nil)then + local h, y = b.element:getHeight(), b.element:getY() + local height = self:getHeight() + if (h + y - height >= amount) then + amount = max(h + y - height, 0) + end + end + end + return amount + end + + local object = { + getType = function() + return objectType + end, + + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + setDirection = function(self, dir) + direction = dir=="horizontal" and 1 or dir=="vertical" and 0 or direction + return self + end, + + getBase = function(self) + return base + end, + + load = function(self) + base.load(self) + self:listenEvent("mouse_scroll") + end, + + setParent = function(self, p, ...) + base.setParent(self, p, ...) + parent = p + return self + end, + + scrollHandler = function(self, dir, x, y) + if(base.scrollHandler(self, dir, x, y))then + local xO, yO = self:getOffset() + if(direction==1)then + self:setOffset(min(getHorizontalScrollAmount(self), max(0, xO + dir)), yO) + elseif(direction==0)then + self:setOffset(xO, min(getVerticalScrollAmount(self), max(0, yO + dir))) + end + self:updateDraw() + return true + end + end, + } + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/Scrollbar.lua b/Basalt/objects/Scrollbar.lua index e73310b..a1954f7 100644 --- a/Basalt/objects/Scrollbar.lua +++ b/Basalt/objects/Scrollbar.lua @@ -1,42 +1,39 @@ -local Object = require("Object") -local xmlValue = require("utils").getValueFromXML +local tHex = require("tHex") -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("VisualObject")(name, basalt) local objectType = "Scrollbar" - base.width = 1 - base.height = 8 - base:setValue(1) base:setZIndex(2) + base:setSize(1, 8) + base:setBackground(colors.lightGray, "\127", colors.gray) local barType = "vertical" local symbol = " " - local symbolColor - local bgSymbol = "\127" - local maxValue = base.height + local symbolBG = colors.yellow + local symbolFG = colors.black + local scrollAmount = 3 local index = 1 local symbolSize = 1 + local symbolAutoSize = true + + local function updateSymbolSize() + local w,h = base:getSize() + if(symbolAutoSize)then + symbolSize = math.max((barType == "vertical" and h or w-(#symbol)) - (scrollAmount-1), 1) + end + end local function mouseEvent(self, button, x, y) - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) + local obx, oby = self:getPosition() local w,h = self:getSize() - if (barType == "horizontal") then - for _index = 0, w do - if (obx + _index == x) and (oby <= y) and (oby + h > y) then - index = math.min(_index + 1, w - (symbolSize - 1)) - self:setValue(maxValue / w * (index)) - self:updateDraw() - end - end - end - if (barType == "vertical") then - for _index = 0, h do - if (oby + _index == y) and (obx <= x) and (obx + w > x) then - index = math.min(_index + 1, h - (symbolSize - 1)) - self:setValue(maxValue / h * (index)) - self:updateDraw() - end + updateSymbolSize() + local size = barType == "vertical" and h or w + for i = 0, size do + if ((barType == "vertical" and oby + i == y) or (barType == "horizontal" and obx + i == x)) and (obx <= x) and (obx + w > x) and (oby <= y) and (oby + h > y) then + index = math.min(i + 1, size - (#symbol + symbolSize - 2)) + self:scrollbarMoveHandler() + self:updateDraw() end end end @@ -44,23 +41,24 @@ return function(name) local object = { getType = function(self) return objectType - end; + end, - setSymbol = function(self, _symbol) - symbol = _symbol:sub(1, 1) + 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; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("maxValue", data)~=nil)then maxValue = xmlValue("maxValue", data) end - if(xmlValue("backgroundSymbol", data)~=nil)then bgSymbol = xmlValue("backgroundSymbol", data):sub(1,1) end - if(xmlValue("symbol", data)~=nil)then symbol = xmlValue("symbol", data):sub(1,1) end - if(xmlValue("barType", data)~=nil)then barType = xmlValue("barType", data):lower() end - if(xmlValue("symbolSize", data)~=nil)then self:setSymbolSize(xmlValue("symbolSize", data)) end - if(xmlValue("symbolColor", data)~=nil)then symbolColor = colors[xmlValue("symbolColor", data)] end - if(xmlValue("index", data)~=nil)then self:setIndex(xmlValue("index", data)) end end, setIndex = function(self, _index) @@ -70,50 +68,37 @@ return function(name) end local w,h = self:getSize() index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1)) - self:setValue(maxValue / (barType == "vertical" and h or w) * index) + updateSymbolSize() + self:updateDraw() + return self + end, + + setScrollAmount = function(self, amount) + scrollAmount = amount + updateSymbolSize() self:updateDraw() return self end, getIndex = function(self) - return index + local w,h = self:getSize() + return scrollAmount > (barType=="vertical" and h or w) and math.floor(scrollAmount/(barType=="vertical" and h or w) * index) or index end, setSymbolSize = function(self, size) symbolSize = tonumber(size) or 1 - local w,h = self:getSize() - if (barType == "vertical") then - self:setValue(index - 1 * (maxValue / (h - (symbolSize - 1))) - (maxValue / (h - (symbolSize - 1)))) - elseif (barType == "horizontal") then - self:setValue(index - 1 * (maxValue / (w - (symbolSize - 1))) - (maxValue / (w - (symbolSize - 1)))) - end + symbolAutoSize = size~=false and false or true + updateSymbolSize() self:updateDraw() return self - end; - - setMaxValue = function(self, val) - maxValue = val - self:updateDraw() - return self - end; - - setBackgroundSymbol = function(self, _bgSymbol) - bgSymbol = string.sub(_bgSymbol, 1, 1) - self:updateDraw() - return self - end; - - setSymbolColor = function(self, col) - symbolColor = col - self:updateDraw() - return self - end; + end, setBarType = function(self, _typ) barType = _typ:lower() + updateSymbolSize() self:updateDraw() return self - end; + end, mouseHandler = function(self, button, x, y) if (base.mouseHandler(self, button, x, y)) then @@ -131,58 +116,69 @@ return function(name) return false end, + setSize = function(self, ...) + base.setSize(self, ...) + updateSymbolSize() + return self + end, + scrollHandler = function(self, dir, x, y) if(base.scrollHandler(self, dir, x, y))then local w,h = self:getSize() + updateSymbolSize() index = index + dir if (index < 1) then index = 1 end - index = math.min(index, (barType == "vertical" and h or w) - (symbolSize - 1)) - self:setValue(maxValue / (barType == "vertical" and h or w) * index) + index = math.min(index, (barType == "vertical" and h or w) - (barType == "vertical" and symbolSize - 1 or #symbol+symbolSize-2)) + self:scrollbarMoveHandler() self:updateDraw() end end, - draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - if (barType == "horizontal") then - self.parent:writeText(obx, oby, bgSymbol:rep(index - 1), self.bgColor, self.fgColor) - self.parent:writeText(obx + index - 1, oby, symbol:rep(symbolSize), symbolColor, symbolColor) - self.parent:writeText(obx + index + symbolSize - 1, oby, bgSymbol:rep(w - (index + symbolSize - 1)), self.bgColor, self.fgColor) - end + onChange = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("scrollbar_moved", v) + end + end + return self + end, - 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.parent:writeText(obx, oby + n + curIndexOffset, symbol, symbolColor, symbolColor) - end - else - if (n + 1 < index) or (n + 1 > index - 1 + symbolSize) then - self.parent:writeText(obx, oby + n, bgSymbol, self.bgColor, self.fgColor) - end + scrollbarMoveHandler = function(self) + self:sendEvent("scrollbar_moved", self, self:getIndex()) + end, + + customEventHandler = function(self, event, ...) + base.customEventHandler(self, event, ...) + if(event=="basalt_FrameResize")then + updateSymbolSize() + end + end, + + draw = function(self) + base.draw(self) + self:addDraw("scrollbar", function() + local parent = self:getParent() + local w,h = self:getSize() + local bgCol,fgCol = self:getBackground(), self:getForeground() + if (barType == "horizontal") then + for n = 0, h - 1 do + self:addBlit(index, 1 + n, symbol:rep(symbolSize), tHex[symbolFG]:rep(#symbol*symbolSize), tHex[symbolBG]:rep(#symbol*symbolSize)) + end + elseif (barType == "vertical") then + for n = 0, h - 1 do + if (index == n + 1) then + for curIndexOffset = 0, math.min(symbolSize - 1, h) do + self:blit(1, index + curIndexOffset, symbol:rep(math.max(#symbol, w)), tHex[symbolFG]:rep(math.max(#symbol, w)), tHex[symbolBG]:rep(math.max(#symbol, w))) end end end end - end - end, - - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_drag", self) - self.parent:addEvent("mouse_scroll", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("ScrollbarBG") - self.fgColor = self.parent:getTheme("ScrollbarText") - symbolColor = self.parent:getTheme("ScrollbarSymbolColor") - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Slider.lua b/Basalt/objects/Slider.lua index dc72884..1bbbda3 100644 --- a/Basalt/objects/Slider.lua +++ b/Basalt/objects/Slider.lua @@ -1,66 +1,49 @@ -local Object = require("Object") -local log = require("basaltLogs") -local xmlValue = require("utils").getValueFromXML +local tHex = require("tHex") -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "Slider" - base.width = 8 - base.height = 1 + base:setSize(12, 1) base:setValue(1) + base:setBackground(false, "\140", colors.black) local barType = "horizontal" local symbol = " " - local symbolColor - local bgSymbol = "\140" - local maxValue = base.width + local symbolFG = colors.black + local symbolBG = colors.gray + local maxValue = 12 local index = 1 local symbolSize = 1 local function mouseEvent(self, button, x, y) - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) - local w,h = self:getSize() - if (barType == "horizontal") then - for _index = 0, w do - if (obx + _index == x) and (oby <= y) and (oby + h > y) then - index = math.min(_index + 1, w - (symbolSize - 1)) - self:setValue(maxValue / w * (index)) - self:updateDraw() - end - end - end - if (barType == "vertical") then - for _index = 0, h do - if (oby + _index == y) and (obx <= x) and (obx + w > x) then - index = math.min(_index + 1, h - (symbolSize - 1)) - self:setValue(maxValue / h * (index)) - self:updateDraw() - end - end + local obx, oby = self:getPosition() + local w,h = self:getSize() + local size = barType == "vertical" and h or w + for i = 0, size do + if ((barType == "vertical" and oby + i == y) or (barType == "horizontal" and obx + i == x)) and (obx <= x) and (obx + w > x) and (oby <= y) and (oby + h > y) then + index = math.min(i + 1, size - (#symbol + symbolSize - 2)) + self:setValue(maxValue / size * index) + self:updateDraw() end end + end local object = { getType = function(self) return objectType - end; + 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; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("maxValue", data)~=nil)then maxValue = xmlValue("maxValue", data) end - if(xmlValue("backgroundSymbol", data)~=nil)then bgSymbol = xmlValue("backgroundSymbol", data):sub(1,1) end - if(xmlValue("barType", data)~=nil)then barType = xmlValue("barType", data):lower() end - if(xmlValue("symbol", data)~=nil)then symbol = xmlValue("symbol", data):sub(1,1) end - if(xmlValue("symbolSize", data)~=nil)then self:setSymbolSize(xmlValue("symbolSize", data)) end - if(xmlValue("symbolColor", data)~=nil)then symbolColor = colors[xmlValue("symbolColor", data)] end - if(xmlValue("index", data)~=nil)then self:setIndex(xmlValue("index", data)) end end, setIndex = function(self, _index) @@ -79,39 +62,22 @@ return function(name) return index end, - setSymbolSize = function(self, size) - symbolSize = tonumber(size) or 1 - if (barType == "vertical") then - self:setValue(index - 1 * (maxValue / (h - (symbolSize - 1))) - (maxValue / (h - (symbolSize - 1)))) - elseif (barType == "horizontal") then - self:setValue(index - 1 * (maxValue / (w - (symbolSize - 1))) - (maxValue / (w - (symbolSize - 1)))) - end - self:updateDraw() - return self - end; - setMaxValue = function(self, val) maxValue = val return self - end; - - setBackgroundSymbol = function(self, _bgSymbol) - bgSymbol = string.sub(_bgSymbol, 1, 1) - self:updateDraw() - return self - end; + end, setSymbolColor = function(self, col) symbolColor = col self:updateDraw() return self - end; + end, setBarType = function(self, _typ) barType = _typ:lower() self:updateDraw() return self - end; + end, mouseHandler = function(self, button, x, y) if (base.mouseHandler(self, button, x, y)) then @@ -145,44 +111,33 @@ return function(name) end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - if (barType == "horizontal") then - self.parent:writeText(obx, oby, bgSymbol:rep(index - 1), self.bgColor, self.fgColor) - self.parent:writeText(obx + index - 1, oby, symbol:rep(symbolSize), symbolColor, symbolColor) - self.parent:writeText(obx + index + symbolSize - 1, oby, bgSymbol:rep(w - (index + symbolSize - 1)), self.bgColor, self.fgColor) - end + base.draw(self) + self:addDraw("slider", function() + local w,h = self:getSize() + local bgCol,fgCol = self:getBackground(), self:getForeground() + if (barType == "horizontal") then + self:addText(index, oby, symbol:rep(symbolSize)) + if(symbolBG~=false)then self:addBG(index, 1, tHex[symbolBG]:rep(#symbol*symbolSize)) end + if(symbolFG~=false)then self:addFG(index, 1, tHex[symbolFG]:rep(#symbol*symbolSize)) end + end - if (barType == "vertical") then - for n = 0, h - 1 do - if (index == n + 1) then - for curIndexOffset = 0, math.min(symbolSize - 1, h) do - self.parent:writeText(obx, oby + n + curIndexOffset, symbol, symbolColor, symbolColor) - end - else - if (n + 1 < index) or (n + 1 > index - 1 + symbolSize) then - self.parent:writeText(obx, oby + n, bgSymbol, self.bgColor, self.fgColor) - end + if (barType == "vertical") then + for n = 0, h - 1 do + if (index == n + 1) then + for curIndexOffset = 0, math.min(symbolSize - 1, h) do + self:addBlit(1, 1+n+curIndexOffset, symbol, tHex[symbolColor], tHex[symbolColor]) + end + else + if (n + 1 < index) or (n + 1 > index - 1 + symbolSize) then + self:addBlit(1, 1+n, bgSymbol, tHex[fgCol], tHex[bgCol]) end end end end - end - end, - - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_drag", self) - self.parent:addEvent("mouse_scroll", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("SliderBG") - self.fgColor = self.parent:getTheme("SliderText") - symbolColor = self.parent:getTheme("SliderSymbolColor") - end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Switch.lua b/Basalt/objects/Switch.lua index 717773d..9c696cc 100644 --- a/Basalt/objects/Switch.lua +++ b/Basalt/objects/Switch.lua @@ -1,14 +1,8 @@ -local Object = require("Object") -local xmlValue = require("utils").getValueFromXML - -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "Switch" - base.width = 2 - base.height = 1 - base.bgColor = colors.lightGray - base.fgColor = colors.gray + base:setSize(4, 1) base:setValue(false) base:setZIndex(5) @@ -19,71 +13,53 @@ return function(name) local object = { getType = function(self) return objectType - end; - - setSymbolColor = function(self, symbolColor) - bgSymbol = symbolColor - self:updateDraw() - return self - end; - - setActiveBackground = function(self, bgcol) - activeBG = bgcol - self:updateDraw() - return self - end; - - setInactiveBackground = function(self, bgcol) - inactiveBG = bgcol - self:updateDraw() - return self - end; - - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(xmlValue("inactiveBG", data)~=nil)then inactiveBG = colors[xmlValue("inactiveBG", data)] end - if(xmlValue("activeBG", data)~=nil)then activeBG = colors[xmlValue("activeBG", data)] end - if(xmlValue("symbolColor", data)~=nil)then bgSymbol = colors[xmlValue("symbolColor", data)] end - end, - mouseHandler = function(self, button, x, y) - if (base.mouseHandler(self, button, x, y)) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) + setSymbol = function(self, col) + bgSymbol = col + return self + end, + + setActiveBackground = function(self, col) + activeBG = col + return self + end, + + setInactiveBackground = function(self, col) + inactiveBG = col + return self + end, + + + load = function(self) + self:listenEvent("mouse_click") + end, + + mouseHandler = function(self, ...) + if (base.mouseHandler(self, ...)) then self:setValue(not self:getValue()) self:updateDraw() return true end - end; - - draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - self.parent:drawBackgroundBox(obx, oby, w, h, self.bgColor) - if(self:getValue())then - self.parent:drawBackgroundBox(obx, oby, 1, h, activeBG) - self.parent:drawBackgroundBox(obx+1, oby, 1, h, bgSymbol) - else - self.parent:drawBackgroundBox(obx, oby, 1, h, bgSymbol) - self.parent:drawBackgroundBox(obx+1, oby, 1, h, inactiveBG) - end - end - end end, - init = function(self) - self.parent:addEvent("mouse_click", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("SwitchBG") - self.fgColor = self.parent:getTheme("SwitchText") - bgSymbol = self.parent:getTheme("SwitchBGSymbol") - inactiveBG = self.parent:getTheme("SwitchInactive") - activeBG = self.parent:getTheme("SwitchActive") - end + draw = function(self) + base.draw(self) + self:addDraw("switch", function() + local parent = self:getParent() + local bgCol,fgCol = self:getBackground(), self:getForeground() + local w,h = self:getSize() + if(self:getValue())then + self:addBackgroundBox(1, 1, w, h, activeBG) + self:addBackgroundBox(w, 1, 1, h, bgSymbol) + else + self:addBackgroundBox(1, 1, w, h, inactiveBG) + self:addBackgroundBox(1, 1, 1, h, bgSymbol) + end + end) end, } + object.__index = object return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Textfield.lua b/Basalt/objects/Textfield.lua index 049b426..8cdaa08 100644 --- a/Basalt/objects/Textfield.lua +++ b/Basalt/objects/Textfield.lua @@ -1,12 +1,9 @@ -local Object = require("Object") local tHex = require("tHex") -local xmlValue = require("utils").getValueFromXML -local log = require("basaltLogs") local rep,find,gmatch,sub,len = string.rep,string.find,string.gmatch,string.sub,string.len -return function(name) - local base = Object(name) +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) local objectType = "Textfield" local hIndex, wIndex, textX, textY = 1, 1, 1, 1 @@ -20,8 +17,7 @@ return function(name) local selectionBG,selectionFG = colors.lightBlue,colors.black - base.width = 30 - base.height = 12 + base:setSize(30, 12) base:setZIndex(5) local function isSelected() @@ -32,57 +28,56 @@ return function(name) end local function getSelectionCoordinates() - local sx,ex,sy,ey - if(isSelected())then - if(startSelX>endSelX)then - sx,ex = endSelX,startSelX - else - sx,ex = startSelX,endSelX - end - if(startSelY>endSelY)then - sy,ey = endSelY,startSelY - else - sy,ey = startSelY,endSelY + local sx, ex, sy, ey = startSelX, endSelX, startSelY, endSelY + if isSelected() then + if startSelX < endSelX and startSelY <= endSelY then + sx = startSelX + ex = endSelX + if startSelY < endSelY then + sy = startSelY + ey = endSelY + else + sy = endSelY + ey = startSelY + end + elseif startSelX > endSelX and startSelY >= endSelY then + sx = endSelX + ex = startSelX + if startSelY > endSelY then + sy = endSelY + ey = startSelY + else + sy = startSelY + ey = endSelY + end + elseif startSelY > endSelY then + sx = endSelX + ex = startSelX + sy = endSelY + ey = startSelY end + return sx, ex, sy, ey end - return sx,ex,sy,ey - end - - local function getSelection() - end local function removeSelection(self) - local sx,ex,sy,ey = getSelectionCoordinates(self) - for n=ey,sy,-1 do - if(n==sy)or(n==ey)then - local l = lines[n] - local b = bgLines[n] - local f = fgLines[n] - if(n==sy)and(n==ey)then - l = l:sub(1,sx-1)..l:sub(ex+1,l:len()) - b = b:sub(1,sx-1)..b:sub(ex+1,b:len()) - f = f:sub(1,sx-1)..f:sub(ex+1,f:len()) - elseif(n==sx)then - l = l:sub(1, sx) - b = b:sub(1, sx) - f = f:sub(1, sx) - elseif(n==sy)then - l = l:sub(ex, l:len()) - b = b:sub(ex, b:len()) - f = f:sub(ex, f:len()) - end - lines[n] = l - bgLines[n] = b - fgLines[n] = f - else - table.remove(lines, n) - table.remove(bgLines, n) - table.remove(fgLines, n) + local sx, ex, sy, ey = getSelectionCoordinates(self) + local startLine = lines[sy] + local endLine = lines[ey] + lines[sy] = startLine:sub(1, sx - 1) .. endLine:sub(ex + 1, endLine:len()) + bgLines[sy] = bgLines[sy]:sub(1, sx - 1) .. bgLines[ey]:sub(ex + 1, bgLines[ey]:len()) + fgLines[sy] = fgLines[sy]:sub(1, sx - 1) .. fgLines[ey]:sub(ex + 1, fgLines[ey]:len()) + + for i = ey, sy + 1, -1 do + if i ~= sy then + table.remove(lines, i) + table.remove(bgLines, i) + table.remove(fgLines, i) end end - textX,textY = startSelX,startSelY - startSelX,endSelX,startSelY,endSelY = nil,nil,nil,nil + + textX, textY = sx, sy + startSelX, endSelX, startSelY, endSelY = nil, nil, nil, nil return self end @@ -105,8 +100,8 @@ return function(name) local function updateColors(self, l) l = l or textY - local fgLine = tHex[self.fgColor]:rep(fgLines[l]:len()) - local bgLine = tHex[self.bgColor]:rep(bgLines[l]:len()) + local fgLine = tHex[self:getForeground()]:rep(fgLines[l]:len()) + local bgLine = tHex[self:getBackground()]:rep(bgLines[l]:len()) for k,v in pairs(rules)do local pos = stringGetPositions(lines[l], v[1]) if(#pos>0)then @@ -160,60 +155,30 @@ return function(name) return self end, - setValuesByXMLData = function(self, data) - base.setValuesByXMLData(self, data) - if(data["lines"]~=nil)then - local l = data["lines"]["line"] - if(l.properties~=nil)then l = {l} end - for k,v in pairs(l)do - self:addLine(v:value()) - end - end - if(data["keywords"]~=nil)then - for k,v in pairs(data["keywords"])do - if(colors[k]~=nil)then - local entry = v - if(entry.properties~=nil)then entry = {entry} end - local tab = {} - for a,b in pairs(entry)do - local keywordList = b["keyword"] - if(b["keyword"].properties~=nil)then keywordList = {b["keyword"]} end - for c,d in pairs(keywordList)do - table.insert(tab, d:value()) - end - end - self:addKeywords(colors[k], tab) - end - end - end - if(data["rules"]~=nil)then - if(data["rules"]["rule"]~=nil)then - local tab = data["rules"]["rule"] - if(data["rules"]["rule"].properties~=nil)then tab = {data["rules"]["rule"]} end - for k,v in pairs(tab)do + setSelection = function(self, fg, bg) + selectionFG = fg or selectionFG + selectionBG = bg or selectionBG + return self + end, - if(xmlValue("pattern", v)~=nil)then - self:addRule(xmlValue("pattern", v), colors[xmlValue("fg", v)], colors[xmlValue("bg", v)]) - end - end - end - end + getSelection = function(self) + return selectionFG, selectionBG end, getLines = function(self) return lines - end; + end, getLine = function(self, index) return lines[index] - end; + end, editLine = function(self, index, text) lines[index] = text or lines[index] updateColors(self, index) self:updateDraw() return self - end; + end, clear = function(self) lines = {""} @@ -227,21 +192,23 @@ return function(name) addLine = function(self, text, index) if(text~=nil)then + local bgColor = self:getBackground() + local fgColor = self:getForeground() if(#lines==1)and(lines[1]=="")then lines[1] = text - bgLines[1] = tHex[self.bgColor]:rep(text:len()) - fgLines[1] = tHex[self.fgColor]:rep(text:len()) + bgLines[1] = tHex[bgColor]:rep(text:len()) + fgLines[1] = tHex[fgColor]:rep(text:len()) updateColors(self, 1) return self end if (index ~= nil) then table.insert(lines, index, text) - table.insert(bgLines, index, tHex[self.bgColor]:rep(text:len())) - table.insert(fgLines, index, tHex[self.fgColor]:rep(text:len())) + table.insert(bgLines, index, tHex[bgColor]:rep(text:len())) + table.insert(fgLines, index, tHex[fgColor]:rep(text:len())) else table.insert(lines, text) - table.insert(bgLines, tHex[self.bgColor]:rep(text:len())) - table.insert(fgLines, tHex[self.fgColor]:rep(text:len())) + table.insert(bgLines, tHex[bgColor]:rep(text:len())) + table.insert(fgLines, tHex[fgColor]:rep(text:len())) end end updateColors(self, index or #lines) @@ -285,13 +252,13 @@ return function(name) end self:updateDraw() return self - end; + end, setKeywords = function(self, color, tab) keyWords[color] = tab self:updateDraw() return self - end; + end, removeLine = function(self, index) if(#lines>1)then @@ -305,83 +272,91 @@ return function(name) end self:updateDraw() return self - end; + end, getTextCursor = function(self) return textX, textY - end; + end, + + getOffset = function(self) + return wIndex, hIndex + end, + + setOffset = function(self, xOff, yOff) + wIndex = xOff or wIndex + hIndex = yOff or hIndex + self:updateDraw() + return self + end, getFocusHandler = function(self) base.getFocusHandler(self) - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - if (self.parent ~= nil) then - self.parent:setCursor(true, obx + textX - wIndex, oby + textY - hIndex, self.fgColor) - end - end - end; + local obx, oby = self:getPosition() + self:getParent():setCursor(true, obx + textX - wIndex, oby + textY - hIndex, self:getForeground()) + end, loseFocusHandler = function(self) base.loseFocusHandler(self) - if (self.parent ~= nil) then - self.parent:setCursor(false) - end - end; + self:getParent():setCursor(false) + end, keyHandler = function(self, key) if (base.keyHandler(self, event, key)) then - local obx, oby = self:getAnchorPosition() + local parent = self:getParent() + local obx, oby = self:getPosition() local w,h = self:getSize() if (key == keys.backspace) then -- on backspace - if (lines[textY] == "") then - if (textY > 1) then - table.remove(lines, textY) - table.remove(fgLines, textY) - table.remove(bgLines, textY) - textX = lines[textY - 1]:len() + 1 - wIndex = textX - w + 1 - if (wIndex < 1) then - wIndex = 1 - end - textY = textY - 1 - end - elseif (textX <= 1) then - if (textY > 1) then - textX = lines[textY - 1]:len() + 1 - wIndex = textX - w + 1 - if (wIndex < 1) then - wIndex = 1 - end - lines[textY - 1] = lines[textY - 1] .. lines[textY] - fgLines[textY - 1] = fgLines[textY - 1] .. fgLines[textY] - bgLines[textY - 1] = bgLines[textY - 1] .. bgLines[textY] - table.remove(lines, textY) - table.remove(fgLines, textY) - table.remove(bgLines, textY) - textY = textY - 1 - end + if(isSelected())then + removeSelection(self) else - lines[textY] = lines[textY]:sub(1, textX - 2) .. lines[textY]:sub(textX, lines[textY]:len()) - fgLines[textY] = fgLines[textY]:sub(1, textX - 2) .. fgLines[textY]:sub(textX, fgLines[textY]:len()) - bgLines[textY] = bgLines[textY]:sub(1, textX - 2) .. bgLines[textY]:sub(textX, bgLines[textY]:len()) - if (textX > 1) then - textX = textX - 1 - end - if (wIndex > 1) then - if (textX < wIndex) then - wIndex = wIndex - 1 + if (lines[textY] == "") then + if (textY > 1) then + table.remove(lines, textY) + table.remove(fgLines, textY) + table.remove(bgLines, textY) + textX = lines[textY - 1]:len() + 1 + wIndex = textX - w + 1 + if (wIndex < 1) then + wIndex = 1 + end + textY = textY - 1 + end + elseif (textX <= 1) then + if (textY > 1) then + textX = lines[textY - 1]:len() + 1 + wIndex = textX - w + 1 + if (wIndex < 1) then + wIndex = 1 + end + lines[textY - 1] = lines[textY - 1] .. lines[textY] + fgLines[textY - 1] = fgLines[textY - 1] .. fgLines[textY] + bgLines[textY - 1] = bgLines[textY - 1] .. bgLines[textY] + table.remove(lines, textY) + table.remove(fgLines, textY) + table.remove(bgLines, textY) + textY = textY - 1 + end + else + lines[textY] = lines[textY]:sub(1, textX - 2) .. lines[textY]:sub(textX, lines[textY]:len()) + fgLines[textY] = fgLines[textY]:sub(1, textX - 2) .. fgLines[textY]:sub(textX, fgLines[textY]:len()) + bgLines[textY] = bgLines[textY]:sub(1, textX - 2) .. bgLines[textY]:sub(textX, bgLines[textY]:len()) + if (textX > 1) then + textX = textX - 1 + end + if (wIndex > 1) then + if (textX < wIndex) then + wIndex = wIndex - 1 + end end end - end - if (textY < hIndex) then - hIndex = hIndex - 1 + if (textY < hIndex) then + hIndex = hIndex - 1 + end end updateColors(self) self:setValue("") - end - - if (key == keys.delete) then + elseif (key == keys.delete) then -- on delete if(isSelected())then removeSelection(self) @@ -400,9 +375,10 @@ return function(name) end end updateColors(self) - end - - if (key == keys.enter) then + elseif (key == keys.enter) then + if(isSelected())then + removeSelection(self) + end -- on enter table.insert(lines, textY + 1, lines[textY]:sub(textX, lines[textY]:len())) table.insert(fgLines, textY + 1, fgLines[textY]:sub(textX, fgLines[textY]:len())) @@ -417,9 +393,8 @@ return function(name) hIndex = hIndex + 1 end self:setValue("") - end - - if (key == keys.up) then + elseif (key == keys.up) then + startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil -- arrow up if (textY > 1) then textY = textY - 1 @@ -440,8 +415,8 @@ return function(name) end end end - end - if (key == keys.down) then + elseif (key == keys.down) then + startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil -- arrow down if (textY < #lines) then textY = textY + 1 @@ -460,8 +435,8 @@ return function(name) hIndex = hIndex + 1 end end - end - if (key == keys.right) then + elseif (key == keys.right) then + startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil -- arrow right textX = textX + 1 if (textY < #lines) then @@ -482,8 +457,8 @@ return function(name) wIndex = 1 end - end - if (key == keys.left) then + elseif (key == keys.left) then + startSelX, startSelY, endSelX, endSelY = nil, nil, nil, nil -- arrow left textX = textX - 1 if (textX >= 1) then @@ -504,6 +479,19 @@ return function(name) if (wIndex < 1) then wIndex = 1 end + elseif(key == keys.tab)then + if(textX % 3 == 0 )then + lines[textY] = lines[textY]:sub(1, textX - 1) .. " " .. lines[textY]:sub(textX, lines[textY]:len()) + fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len()) + bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len()) + textX = textX + 1 + end + while textX % 3 ~= 0 do + lines[textY] = lines[textY]:sub(1, textX - 1) .. " " .. lines[textY]:sub(textX, lines[textY]:len()) + fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len()) + bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len()) + textX = textX + 1 + end end if not((obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (oby + textY - hIndex >= oby and oby + textY - hIndex < oby + h)) then @@ -519,7 +507,7 @@ return function(name) if (cursorX < 1) then cursorX = 0 end - self.parent:setCursor(true, obx + cursorX, oby + cursorY, self.fgColor) + parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground()) self:updateDraw() return true end @@ -527,11 +515,15 @@ return function(name) charHandler = function(self, char) if(base.charHandler(self, char))then - local obx, oby = self:getAnchorPosition() + local parent = self:getParent() + local obx, oby = self:getPosition() local w,h = self:getSize() + if(isSelected())then + removeSelection(self) + end lines[textY] = lines[textY]:sub(1, textX - 1) .. char .. lines[textY]:sub(textX, lines[textY]:len()) - fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self.fgColor] .. fgLines[textY]:sub(textX, fgLines[textY]:len()) - bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self.bgColor] .. bgLines[textY]:sub(textX, bgLines[textY]:len()) + fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[self:getForeground()] .. fgLines[textY]:sub(textX, fgLines[textY]:len()) + bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self:getBackground()] .. bgLines[textY]:sub(textX, bgLines[textY]:len()) textX = textX + 1 if (textX >= w + wIndex) then wIndex = wIndex + 1 @@ -552,10 +544,7 @@ return function(name) if (cursorX < 1) then cursorX = 0 end - if(isSelected())then - removeSelection(self) - end - self.parent:setCursor(true, obx + cursorX, oby + cursorY, self.fgColor) + parent:setCursor(true, obx + cursorX, oby + cursorY, self:getForeground()) self:updateDraw() return true end @@ -563,30 +552,31 @@ return function(name) dragHandler = function(self, button, x, y) if (base.dragHandler(self, button, x, y)) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) - local anchx, anchy = self:getAnchorPosition() + local parent = self:getParent() + local obx, oby = self:getAbsolutePosition() + local anchx, anchy = self:getPosition() local w,h = self:getSize() if (lines[y - oby + hIndex] ~= nil) then - if(anchx+w > anchx + x - (obx+1)+ wIndex)and(anchx < anchx + x - obx+ wIndex)then + if anchx <= x - obx + wIndex and anchx + w > x - obx + wIndex then textX = x - obx + wIndex textY = y - oby + hIndex - endSelX = textX - endSelY = textY - if (textX > lines[textY]:len()) then + + if textX > lines[textY]:len() then textX = lines[textY]:len() + 1 - endSelX = textX end - if (textX < wIndex) then + endSelX = textX + endSelY = textY + + if textX < wIndex then wIndex = textX - 1 - if (wIndex < 1) then + if wIndex < 1 then wIndex = 1 end end - self.parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self.fgColor) - + parent:setCursor(not isSelected(), anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground()) self:updateDraw() - end + end end return true end @@ -594,8 +584,9 @@ return function(name) scrollHandler = function(self, dir, x, y) if (base.scrollHandler(self, dir, x, y)) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) - local anchx, anchy = self:getAnchorPosition() + local parent = self:getParent() + local obx, oby = self:getAbsolutePosition() + local anchx, anchy = self:getPosition() local w,h = self:getSize() hIndex = hIndex + dir if (hIndex > #lines - (h - 1)) then @@ -607,9 +598,9 @@ return function(name) end if (obx + textX - wIndex >= obx and obx + textX - wIndex < obx + w) and (anchy + textY - hIndex >= anchy and anchy + textY - hIndex < anchy + h) then - self.parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self.fgColor) + parent:setCursor(not isSelected(), anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground()) else - self.parent:setCursor(false) + parent:setCursor(false) end self:updateDraw() return true @@ -618,8 +609,9 @@ return function(name) mouseHandler = function(self, button, x, y) if (base.mouseHandler(self, button, x, y)) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) - local anchx, anchy = self:getAnchorPosition() + local parent = self:getParent() + local obx, oby = self:getAbsolutePosition() + local anchx, anchy = self:getPosition() if (lines[y - oby + hIndex] ~= nil) then textX = x - obx + wIndex textY = y - oby + hIndex @@ -639,17 +631,15 @@ return function(name) end self:updateDraw() end - if (self.parent ~= nil) then - self.parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self.fgColor) - end + parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self:getForeground()) return true end end, mouseUpHandler = function(self, button, x, y) if (base.mouseUpHandler(self, button, x, y)) then - local obx, oby = self:getAbsolutePosition(self:getAnchorPosition()) - local anchx, anchy = self:getAnchorPosition() + local obx, oby = self:getAbsolutePosition() + local anchx, anchy = self:getPosition() if (lines[y - oby + hIndex] ~= nil) then endSelX = x - obx + wIndex endSelY = y - oby + hIndex @@ -666,100 +656,89 @@ return function(name) end, eventHandler = function(self, event, paste, p2, p3, p4) - base.eventHandler(self, event, paste, p2, p3, p4) - if(event=="paste")then - if(self:isFocused())then - 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[self.fgColor]:rep(paste:len()) .. fgLines[textY]:sub(textX, fgLines[textY]:len()) - bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[self.bgColor]:rep(paste:len()) .. bgLines[textY]:sub(textX, bgLines[textY]:len()) - textX = textX + paste:len() - if (textX >= w + wIndex) then - wIndex = (textX+1)-w + if(base.eventHandler(self, event, paste, p2, p3, p4))then + if(event=="paste")then + if(self:isFocused())then + local parent = self:getParent() + local fgColor, bgColor = self:getForeground(), self:getBackground() + local w, h = self:getSize() + lines[textY] = lines[textY]:sub(1, textX - 1) .. paste .. lines[textY]:sub(textX, lines[textY]:len()) + fgLines[textY] = fgLines[textY]:sub(1, textX - 1) .. tHex[fgColor]:rep(paste:len()) .. fgLines[textY]:sub(textX, fgLines[textY]:len()) + bgLines[textY] = bgLines[textY]:sub(1, textX - 1) .. tHex[bgColor]:rep(paste:len()) .. bgLines[textY]:sub(textX, bgLines[textY]:len()) + textX = textX + paste:len() + if (textX >= w + wIndex) then + wIndex = (textX+1)-w + end + local anchx, anchy = self:getPosition() + parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, fgColor) + updateColors(self) + self:updateDraw() end - local anchx, anchy = self:getAnchorPosition() - self.parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self.fgColor) - updateColors(self) - self:updateDraw() end end end, - - setSelectionColor = function(self, bg, fg) - selectionBG = bg or selectionBG - selectionFG = fg or selectionFG - return self - end, draw = function(self) - if (base.draw(self)) then - if (self.parent ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - for n = 1, h do - local text = "" - local bg = "" - local fg = "" - if (lines[n + hIndex - 1] ~= nil) then - text = lines[n + hIndex - 1] - fg = fgLines[n + hIndex - 1] - bg = bgLines[n + hIndex - 1] - end - text = text:sub(wIndex, w + wIndex - 1) - bg = bg:sub(wIndex, w + wIndex - 1) - fg = fg:sub(wIndex, w + wIndex - 1) - local space = w - text:len() - if (space < 0) then - space = 0 - end - text = text .. rep(self.bgSymbol, space) - bg = bg .. rep(tHex[self.bgColor], space) - fg = fg .. rep(tHex[self.fgColor], space) - self.parent:setText(obx, oby + n - 1, text) - self.parent:setBG(obx, oby + n - 1, bg) - self.parent:setFG(obx, oby + n - 1, fg) + base.draw(self) + self:addDraw("textfield", function() + local parent = self:getParent() + local obx, oby = self:getPosition() + local w, h = self:getSize() + local bgColor = tHex[self:getBackground()] + local fgColor = tHex[self:getForeground()] + + for n = 1, h do + local text = "" + local bg = "" + local fg = "" + if lines[n + hIndex - 1] then + text = lines[n + hIndex - 1] + fg = fgLines[n + hIndex - 1] + bg = bgLines[n + hIndex - 1] end - --[[ - if(startSelX~=nil)and(endSelX~=nil)and(startSelY~=nil)and(endSelY~=nil)then - local sx,ex,sy,ey = getSelectionCoordinates(self) - for n=sy,ey do - local line = lines[n]:len() - local xOffset = 0 - if(n==sy)and(n==ey)then - xOffset = sx-1 - line = line - (sx-1) - (line - ex) - elseif(n==ey)then - line = line - (line - ex) - elseif(n==sy)then - line = line-(sx-1) - xOffset = sx-1 - end - self.parent:setBG(obx + xOffset, oby + n - 1, rep(tHex[selectionBG], line)) - self.parent:setFG(obx + xOffset, oby + n - 1, rep(tHex[selectionFG], line)) + + text = sub(text, wIndex, w + wIndex - 1) + bg = rep(bgColor, w) + fg = rep(fgColor, w) + + self:addText(1, n, text) + self:addBG(1, n, bg) + self:addFG(1, n, fg) + self:addBlit(1, n, text, fg, bg) + end + + if startSelX and endSelX and startSelY and endSelY then + local sx, ex, sy, ey = getSelectionCoordinates(self) + for n = sy, ey do + local line = #lines[n] + local xOffset = 0 + if n == sy and n == ey then + xOffset = sx - 1 + line = line - (sx - 1) - (line - ex) + elseif n == ey then + line = line - (line - ex) + elseif n == sy then + line = line - (sx - 1) + xOffset = sx - 1 end - end]] - if(self:isFocused())then - local anchx, anchy = self:getAnchorPosition() - --self.parent:setCursor(true, anchx + textX - wIndex, anchy + textY - hIndex, self.fgColor) + self:addBG(1 + xOffset, n, rep(tHex[selectionBG], line)) + self:addFG(1 + xOffset, n, rep(tHex[selectionFG], line)) end end - end + end) end, - init = function(self) - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_up", self) - self.parent:addEvent("mouse_scroll", self) - self.parent:addEvent("mouse_drag", self) - self.parent:addEvent("key", self) - self.parent:addEvent("char", self) - self.parent:addEvent("other_event", self) - if(base.init(self))then - self.bgColor = self.parent:getTheme("TextfieldBG") - self.fgColor = self.parent:getTheme("TextfieldText") - end + load = function(self) + self:listenEvent("mouse_click") + self:listenEvent("mouse_up") + self:listenEvent("mouse_scroll") + self:listenEvent("mouse_drag") + self:listenEvent("key") + self:listenEvent("char") + self:listenEvent("other_event") end, } + object.__index = object return setmetatable(object, base) -end +end \ No newline at end of file diff --git a/Basalt/objects/Thread.lua b/Basalt/objects/Thread.lua index bd6e85b..4a94dc6 100644 --- a/Basalt/objects/Thread.lua +++ b/Basalt/objects/Thread.lua @@ -1,7 +1,6 @@ -local xmlValue = require("utils").getValueFromXML +return function(name, basalt) + local base = basalt.getObject("Object")(name, basalt) -return function(name) - local object local objectType = "Thread" local func @@ -9,42 +8,9 @@ return function(name) local isActive = false local filter - local generateXMLEventFunction = function(self, str) - if(str:sub(1,1)=="#")then - local o = self:getBaseFrame():getDeepObject(str:sub(2,str:len())) - if(o~=nil)and(o.internalObjetCall~=nil)then - return (function()o:internalObjetCall()end) - end - else - return self:getBaseFrame():getVariable(str) - end - return self - end - - object = { - name = name, + local object = { getType = function(self) return objectType - end; - getZIndex = function(self) - return 1 - end; - getName = function(self) - return self.name - end; - - getBaseFrame = function(self) - if(self.parent~=nil)then - return self.parent:getBaseFrame() - end - return self - end; - - setValuesByXMLData = function(self, data) - local f - if(xmlValue("thread", data)~=nil)then f = generateXMLEventFunction(self, xmlValue("thread", data)) end - if(xmlValue("start", data)~=nil)then if(xmlValue("start", data))and(f~=nil)then self:start(f) end end - return self end, start = function(self, f) @@ -62,36 +28,36 @@ return function(name) error("Thread Error Occurred - " .. result) end end - self.parent:addEvent("mouse_click", self) - self.parent:addEvent("mouse_up", self) - self.parent:addEvent("mouse_scroll", self) - self.parent:addEvent("mouse_drag", self) - self.parent:addEvent("key", self) - self.parent:addEvent("key_up", self) - self.parent:addEvent("char", self) - self.parent:addEvent("other_event", self) + self:listenEvent("mouse_click") + self:listenEvent("mouse_up") + self:listenEvent("mouse_scroll") + self:listenEvent("mouse_drag") + self:listenEvent("key") + self:listenEvent("key_up") + self:listenEvent("char") + self:listenEvent("other_event") return self - end; + end, getStatus = function(self, f) if (cRoutine ~= nil) then return coroutine.status(cRoutine) end return nil - end; + end, stop = function(self, f) isActive = false - self.parent:removeEvent("mouse_click", self) - self.parent:removeEvent("mouse_up", self) - self.parent:removeEvent("mouse_scroll", self) - self.parent:removeEvent("mouse_drag", self) - self.parent:removeEvent("key", self) - self.parent:removeEvent("key_up", self) - self.parent:removeEvent("char", self) - self.parent:removeEvent("other_event", self) + self:listenEvent("mouse_click", false) + self:listenEvent("mouse_up", false) + self:listenEvent("mouse_scroll", false) + self:listenEvent("mouse_drag", false) + self:listenEvent("key", false) + self:listenEvent("key_up", false) + self:listenEvent("char", false) + self:listenEvent("other_event", false) return self - end; + end, mouseHandler = function(self, ...) self:eventHandler("mouse_click", ...) @@ -136,11 +102,10 @@ return function(name) self:stop() end end - end; + end, } object.__index = object - - return object + return setmetatable(object, base) end \ No newline at end of file diff --git a/Basalt/objects/Timer.lua b/Basalt/objects/Timer.lua index 3e0c2a6..b10a746 100644 --- a/Basalt/objects/Timer.lua +++ b/Basalt/objects/Timer.lua @@ -1,6 +1,3 @@ -local basaltEvent = require("basaltEvent") -local xmlValue = require("utils").getValueFromXML - return function(name) local objectType = "Timer" @@ -8,64 +5,18 @@ return function(name) local savedRepeats = 0 local repeats = 0 local timerObj - local eventSystem = basaltEvent() local timerIsActive = false - local generateXMLEventFunction = function(self, func, val) - local createF = function(str) - if(str:sub(1,1)=="#")then - local o = self:getBaseFrame():getDeepObject(str:sub(2,str:len())) - if(o~=nil)and(o.internalObjetCall~=nil)then - func(self,function()o:internalObjetCall()end) - end - else - func(self,self:getBaseFrame():getVariable(str)) - end - end - if(type(val)=="string")then - createF(val) - elseif(type(val)=="table")then - for k,v in pairs(val)do - createF(v) - end - end - return self - end - local object = { - name = name, getType = function(self) return objectType - end; - - setValuesByXMLData = function(self, data) - if(xmlValue("time", data)~=nil)then timer = xmlValue("time", data) end - if(xmlValue("repeat", data)~=nil)then savedRepeats = xmlValue("repeat", data) end - if(xmlValue("start", data)~=nil)then if(xmlValue("start", data))then self:start() end end - if(xmlValue("onCall", data)~=nil)then generateXMLEventFunction(self, self.onCall, xmlValue("onCall", data)) end - return self end, - getBaseFrame = function(self) - if(self.parent~=nil)then - return self.parent:getBaseFrame() - end - return self - end; - - getZIndex = function(self) - return 1 - end; - - getName = function(self) - return self.name - end; - setTime = function(self, _timer, _repeats) timer = _timer or 0 savedRepeats = _repeats or 1 return self - end; + end, start = function(self) if(timerIsActive)then @@ -74,31 +25,31 @@ return function(name) repeats = savedRepeats timerObj = os.startTimer(timer) timerIsActive = true - self.parent:addEvent("other_event", self) + self:listenEvent("other_event") return self - end; + end, isActive = function(self) return timerIsActive - end; + end, cancel = function(self) if (timerObj ~= nil) then os.cancelTimer(timerObj) end timerIsActive = false - self.parent:removeEvent("other_event", self) + self:removeEvent("other_event") return self - end; + end, onCall = function(self, func) - eventSystem:registerEvent("timed_event", func) + self:registerEvent("timed_event", func) return self - end; + end, eventHandler = function(self, event, tObj) if event == "timer" and tObj == timerObj and timerIsActive then - eventSystem:sendEvent("timed_event", self) + self:sendEvent("timed_event") if (repeats >= 1) then repeats = repeats - 1 if (repeats >= 1) then @@ -108,7 +59,7 @@ return function(name) timerObj = os.startTimer(timer) end end - end; + end, } object.__index = object diff --git a/Basalt/objects/Treeview.lua b/Basalt/objects/Treeview.lua new file mode 100644 index 0000000..42edcd0 --- /dev/null +++ b/Basalt/objects/Treeview.lua @@ -0,0 +1,262 @@ +local utils = require("utils") +local tHex = require("tHex") + +return function(name, basalt) + local base = basalt.getObject("ChangeableObject")(name, basalt) + local objectType = "Treeview" + + local nodes = {} + local itemSelectedBG = colors.black + local itemSelectedFG = colors.lightGray + local selectionColorActive = true + local textAlign = "left" + local xOffset, yOffset = 0, 0 + local scrollable = true + + base:setSize(16, 8) + base:setZIndex(5) + + local function newNode(text, expandable) + text = text or "" + expandable = expandable or false + local expanded = false + local parent = nil + local children = {} + + local node = {} + + node = { + getChildren = function() + return children + end, + + setParent = function(p) + parent = p + end, + + getParent = function() + return parent + end, + + addChild = function(text, expandable) + local childNode = newNode(text, expandable) + childNode.setParent(node) + table.insert(children, childNode) + base:updateDraw() + return childNode + end, + + setExpanded = function(exp) + if(expandable)then + expanded = exp + end + base:updateDraw() + end, + + isExpanded = function() + return expanded + end, + + setExpandable = function(expandable) + expandable = expandable + base:updateDraw() + end, + + isExpandable = function() + return expandable + end, + + removeChild = function(index) + table.remove(children, index) + end, + + findChildrenByText = function(searchText) + local foundNodes = {} + for _, child in ipairs(children) do + if child.getText() == searchText then + table.insert(foundNodes, child) + end + end + return foundNodes + end, + + getText = function() + return text + end, + + setText = function(t) + text = t + end + } + + return node + end + + local root = newNode("Root", true) + root.setExpanded(true) + + local object = { + init = function(self) + local parent = self:getParent() + self:listenEvent("mouse_click") + self:listenEvent("mouse_scroll") + return base.init(self) + end, + + getBase = function(self) + return base + end, + + getType = function(self) + return objectType + end, + + isType = function(self, t) + return objectType == t or base.isType ~= nil and base.isType(t) or false + end, + + setOffset = function(self, x, y) + xOffset = x + yOffset = y + return self + end, + + getOffset = function(self) + return xOffset, yOffset + end, + + setScrollable = function(self, scroll) + scrollable = scroll + 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, + + getSelectionColor = function(self) + return itemSelectedBG, itemSelectedFG + end, + + isSelectionColorActive = function(self) + return selectionColorActive + end, + + getRoot = function(self) + return root + end, + + mouseHandler = function(self, button, x, y) + if base.mouseHandler(self, button, x, y) then + local currentLine = 1 - yOffset + local obx, oby = self:getAbsolutePosition() + local w, h = self:getSize() + local function checkNodeClick(node, level) + if y == oby+currentLine-1 then + if x >= obx and x < obx + w then + node.setExpanded(not node.isExpanded()) + self:setValue(node) + self:updateDraw() + return true + end + end + currentLine = currentLine + 1 + if node.isExpanded() then + for _, child in ipairs(node.getChildren()) do + if checkNodeClick(child, level + 1) then + return true + end + end + end + return false + end + + for _, item in ipairs(root.getChildren()) do + if checkNodeClick(item, 1) then + return true + end + end + end + end, + + scrollHandler = function(self, dir, x, y) + if base.scrollHandler(self, dir, x, y) then + if scrollable then + local _, h = self:getSize() + yOffset = yOffset + dir + + if yOffset < 0 then + yOffset = 0 + end + + if dir >= 1 then + local visibleLines = 0 + local function countVisibleLines(node, level) + visibleLines = visibleLines + 1 + if node.isExpanded() then + for _, child in ipairs(node.getChildren()) do + countVisibleLines(child, level + 1) + end + end + end + + for _, item in ipairs(root.getChildren()) do + countVisibleLines(item, 1) + end + + if visibleLines > h then + if yOffset > visibleLines - h then + yOffset = visibleLines - h + end + else + yOffset = yOffset - 1 + end + end + self:updateDraw() + end + return true + end + return false + end, + + draw = function(self) + base.draw(self) + self:addDraw("treeview", function() + local currentLine = 1 - yOffset + local lastClickedNode = self:getValue() + local function drawNode(node, level) + local w, h = self:getSize() + + if currentLine >= 1 and currentLine <= h then + local bg = (node == lastClickedNode) and itemSelectedBG or self:getBackground() + local fg = (node == lastClickedNode) and itemSelectedFG or self:getForeground() + + local text = node.getText() + self:addBlit(1 + level + xOffset, currentLine, text, tHex[fg]:rep(#text), tHex[bg]:rep(#text)) + end + + currentLine = currentLine + 1 + + if node.isExpanded() then + for _, child in ipairs(node.getChildren()) do + drawNode(child, level + 1) + end + end + end + + for _, item in ipairs(root.getChildren()) do + drawNode(item, 1) + end + end) + end, + + + } + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/VisualObject.lua b/Basalt/objects/VisualObject.lua new file mode 100644 index 0000000..c050d29 --- /dev/null +++ b/Basalt/objects/VisualObject.lua @@ -0,0 +1,618 @@ +local utils = require("utils") +local tHex = require("tHex") + +local sub, find, insert = string.sub, string.find, table.insert + +return function(name, basalt) + local base = basalt.getObject("Object")(name, basalt) + -- Base object + local objectType = "VisualObject" -- not changeable + + local isVisible,ignOffset,isHovered,isClicked,isDragging = true,false,false,false,false + local zIndex = 1 + + local x, y, width, height = 1,1,1,1 + local dragStartX, dragStartY, dragXOffset, dragYOffset = 0, 0, 0, 0 + + local bgColor,fgColor, transparency = colors.black, colors.white, false + local parent + + local preDrawQueue = {} + local drawQueue = {} + local postDrawQueue = {} + + local renderObject = {} + + local function split(str, d) + local result = {} + if str == "" then + return result + end + d = d or " " + local start = 1 + local delim_start, delim_end = find(str, d, start) + while delim_start do + insert(result, {x=start, value=sub(str, start, delim_start - 1)}) + start = delim_end + 1 + delim_start, delim_end = find(str, d, start) + end + insert(result, {x=start, value=sub(str, start)}) + return result + end + + + local object = { + getType = function(self) + return objectType + end, + + getBase = function(self) + return base + end, + + isType = function(self, t) + return objectType==t or base.isType~=nil and base.isType(t) or false + end, + + getBasalt = function(self) + return basalt + end, + + show = function(self) + isVisible = true + self:updateDraw() + return self + end, + + hide = function(self) + isVisible = false + self:updateDraw() + return self + end, + + isVisible = function(self) + return isVisible + end, + + setVisible = function(self, _isVisible) + isVisible = _isVisible or not isVisible + self:updateDraw() + return self + end, + + setTransparency = function(self, _transparency) + transparency = _transparency~= nil and _transparency or true + self:updateDraw() + return self + end, + + setParent = function(self, newParent, noRemove) + base.setParent(self, newParent, noRemove) + parent = newParent + return self + end, + + setFocus = function(self) + if (parent ~= nil) then + parent:setFocusedObject(self) + end + return self + end, + + setZIndex = function(self, index) + zIndex = index + if (parent ~= nil) then + parent:updateZIndex(self, zIndex) + self:updateDraw() + end + return self + end, + + getZIndex = function(self) + return zIndex + end, + + updateDraw = function(self) + if (parent ~= nil) then + parent:updateDraw() + end + return self + end, + + setPosition = function(self, xPos, yPos, rel) + local curX, curY + 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() + return self + end, + + getX = function(self) + return x + end, + + getY = function(self) + return y + end, + + getPosition = function(self) + return x, y + end, + + setSize = function(self, newWidth, newHeight, rel) + 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:updateDraw() + return self + end, + + getHeight = function(self) + return height + end, + + getWidth = function(self) + return width + end, + + getSize = function(self) + return width, height + end, + + setBackground = function(self, color) + bgColor = color + self:updateDraw() + return self + end, + + getBackground = function(self) + return bgColor + end, + + setForeground = function(self, color) + fgColor = color or false + self:updateDraw() + return self + end, + + getForeground = function(self) + return fgColor + end, + + getAbsolutePosition = function(self, x, y) + -- relative position to absolute position + if (x == nil) or (y == nil) then + x, y = self:getPosition() + end + + if (parent ~= nil) then + local fx, fy = parent:getAbsolutePosition() + x = fx + x - 1 + y = fy + y - 1 + end + return x, y + end, + + ignoreOffset = function(self, ignore) + ignOffset = ignore + if(ignore==nil)then ignOffset = true end + return self + end, + + isCoordsInObject = function(self, x, y) + if(isVisible)and(self:isEnabled())then + if(x==nil)or(y==nil)then return false end + local objX, objY = self:getAbsolutePosition() + local w, h = self:getSize() + if (objX <= x) and (objX + w > x) and (objY <= y) and (objY + h > y) then + return true + end + end + return false + end, + + onGetFocus = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("get_focus", v) + end + end + return self + end, + + onLoseFocus = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("lose_focus", v) + end + end + return self + end, + + isFocused = function(self) + if (parent ~= nil) then + return parent:getFocusedObject() == self + end + return true + end, + + onResize = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("basalt_resize", v) + end + end + return self + end, + + onReposition = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("basalt_reposition", v) + end + end + return self + end, + + mouseHandler = function(self, button, x, y, isMon) + if(self:isCoordsInObject(x, y))then + local objX, objY = self:getAbsolutePosition() + local val = self:sendEvent("mouse_click", self, button, x - (objX-1), y - (objY-1), x, y, isMon) + if(val==false)then return false end + if(parent~=nil)then + parent:setFocusedObject(self) + end + isClicked = true + isDragging = true + dragStartX, dragStartY = x, y + return true + end + end, + + mouseUpHandler = function(self, button, x, y) + isDragging = false + if(isClicked)then + local objX, objY = self:getAbsolutePosition() + local val = self:sendEvent("mouse_release", self, "mouse_release", button, x - (objX-1), y - (objY-1), x, y) + isClicked = false + end + if(self:isCoordsInObject(x, y))then + local objX, objY = self:getAbsolutePosition() + local val = self:sendEvent("mouse_up", self, button, x - (objX-1), y - (objY-1), x, y) + if(val==false)then return false end + return true + end + end, + + dragHandler = function(self, button, x, y) + if(isDragging)then + local objX, objY = self:getAbsolutePosition() + local val = self:sendEvent("mouse_drag", self, button, x - (objX-1), y - (objY-1), dragStartX-x, dragStartY-y, x, y) + dragStartX, dragStartY = x, y + if(val~=nil)then return val end + if(parent~=nil)then + parent:setFocusedObject(self) + end + return true + end + + if(self:isCoordsInObject(x, y))then + local objX, objY = self:getAbsolutePosition() + dragStartX, dragStartY = x, y + dragXOffset, dragYOffset = objX - x, objY - y + end + end, + + scrollHandler = function(self, dir, x, y) + if(self:isCoordsInObject(x, y))then + local objX, objY = self:getAbsolutePosition() + local val = self:sendEvent("mouse_scroll", self, "mouse_scroll", dir, x - (objX-1), y - (objY-1)) + if(val==false)then return false end + if(parent~=nil)then + parent:setFocusedObject(self) + end + return true + end + end, + + hoverHandler = function(self, x, y, stopped) + if(self:isCoordsInObject(x, y))then + local val = self:sendEvent("mouse_hover", self, "mouse_hover", x, y, stopped) + if(val==false)then return false end + isHovered = true + return true + end + if(isHovered)then + local val = self:sendEvent("mouse_leave", self, "mouse_leave", x, y, stopped) + if(val==false)then return false end + isHovered = false + end + end, + + keyHandler = function(self, key, isHolding) + if(self:isEnabled())and(isVisible)then + if (self:isFocused()) then + local val = self:sendEvent("key", self, "key", key, isHolding) + if(val==false)then return false end + return true + end + end + end, + + keyUpHandler = function(self, key) + if(self:isEnabled())and(isVisible)then + if (self:isFocused()) then + local val = self:sendEvent("key_up", self, "key_up", key) + if(val==false)then return false end + return true + end + end + end, + + charHandler = function(self, char) + if(self:isEnabled())and(isVisible)then + if(self:isFocused())then + local val = self:sendEvent("char", self, "char", char) + if(val==false)then return false end + return true + end + end + end, + + eventHandler = function(self, event, ...) + local val = self:sendEvent("other_event", self, event, ...) + if(val~=nil)then return val end + end, + + customEventHandler = function(self, event, ...) + local val = self:sendEvent("custom_event", self, event, ...) + if(val~=nil)then return val end + return true + end, + + getFocusHandler = function(self) + local val = self:sendEvent("get_focus", self) + if(val~=nil)then return val end + return true + end, + + loseFocusHandler = function(self) + isDragging = false + local val = self:sendEvent("lose_focus", self) + if(val~=nil)then return val end + return true + end, + + addDraw = function(self, name, f, pos, typ, active) + local queue = (typ==nil or typ==1) and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue + pos = pos or #queue+1 + if(name~=nil)then + for k,v in pairs(queue)do + if(v.name==name)then + table.remove(queue, k) + break + end + end + local t = {name=name, f=f, pos=pos, active=active~=nil and active or true} + table.insert(queue, pos, t) + end + self:updateDraw() + return self + end, + + addPreDraw = function(self, name, f, pos, typ) + self:addDraw(name, f, pos, 2) + return self + end, + + addPostDraw = function(self, name, f, pos, typ) + self:addDraw(name, f, pos, 3) + return self + end, + + setDrawState = function(self, name, state, typ) + local queue = (typ==nil or typ==1) and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue + for k,v in pairs(queue)do + if(v.name==name)then + v.active = state + break + end + end + self:updateDraw() + return self + end, + + getDrawId = function(self, name, typ) + local queue = typ==1 and drawQueue or typ==2 and preDrawQueue or typ==3 and postDrawQueue or drawQueue + for k,v in pairs(queue)do + if(v.name==name)then + return k + end + end + end, + + addText = function(self, x, y, text) + local obj = self:getParent() or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + if not(transparency)then + obj:setText(x+xPos-1, y+yPos-1, text) + return + end + local t = split(text, "\0") + for k,v in pairs(t)do + if(v.value~="")and(v.value~="\0")then + obj:setText(x+v.x+xPos-2, y+yPos-1, v.value) + end + end + end, + + addBG = function(self, x, y, bg, noText) + local obj = parent or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + if not(transparency)then + obj:setBG(x+xPos-1, y+yPos-1, bg) + return + end + local t = split(bg) + for k,v in pairs(t)do + if(v.value~="")and(v.value~=" ")then + if(noText~=true)then + obj:setText(x+v.x+xPos-2, y+yPos-1, (" "):rep(#v.value)) + obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value) + else + table.insert(renderObject, {x=x+v.x-1,y=y,bg=v.value}) + obj:setBG(x+xPos-1, y+yPos-1, fg) + end + end + end + end, + + addFG = function(self, x, y, fg) + local obj = parent or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + if not(transparency)then + obj:setFG(x+xPos-1, y+yPos-1, fg) + return + end + local t = split(fg) + for k,v in pairs(t)do + if(v.value~="")and(v.value~=" ")then + obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value) + end + end + end, + + addBlit = function(self, x, y, t, fg, bg) + local obj = parent or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + if not(transparency)then + obj:blit(x+xPos-1, y+yPos-1, t, fg, bg) + return + end + local _text = split(t, "\0") + local _fg = split(fg) + local _bg = split(bg) + for k,v in pairs(_text)do + if(v.value~="")or(v.value~="\0")then + obj:setText(x+v.x+xPos-2, y+yPos-1, v.value) + end + end + for k,v in pairs(_bg)do + if(v.value~="")or(v.value~=" ")then + obj:setBG(x+v.x+xPos-2, y+yPos-1, v.value) + end + end + for k,v in pairs(_fg)do + if(v.value~="")or(v.value~=" ")then + obj:setFG(x+v.x+xPos-2, y+yPos-1, v.value) + end + end + end, + + addTextBox = function(self, x, y, w, h, text) + local obj = parent or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + obj:drawTextBox(x+xPos-1, y+yPos-1, w, h, text) + end, + + addForegroundBox = function(self, x, y, w, h, col) + local obj = parent or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + obj:drawForegroundBox(x+xPos-1, y+yPos-1, w, h, col) + end, + + addBackgroundBox = function(self, x, y, w, h, col) + local obj = parent or self + local xPos,yPos = self:getPosition() + if(parent~=nil)then + local xO, yO = parent:getOffset() + xPos = ignOffset and xPos or xPos - xO + yPos = ignOffset and yPos or yPos - yO + end + obj:drawBackgroundBox(x+xPos-1, y+yPos-1, w, h, col) + end, + + render = function(self) + if (isVisible)then + self:redraw() + end + end, + + redraw = function(self) + for k,v in pairs(preDrawQueue)do + if (v.active)then + v.f(self) + end + end + for k,v in pairs(drawQueue)do + if (v.active)then + v.f(self) + end + end + for k,v in pairs(postDrawQueue)do + if (v.active)then + v.f(self) + end + end + return true + end, + + draw = function(self) + self:addDraw("base", function() + local w,h = self:getSize() + if(bgColor~=false)then + self:addTextBox(1, 1, w, h, " ") + self:addBackgroundBox(1, 1, w, h, bgColor) + end + if(fgColor~=false)then + self:addForegroundBox(1, 1, w, h, fgColor) + end + end, 1) + end, + } + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/objects/changeableObject.lua b/Basalt/objects/changeableObject.lua new file mode 100644 index 0000000..3ef6dd7 --- /dev/null +++ b/Basalt/objects/changeableObject.lua @@ -0,0 +1,40 @@ +return function(name, basalt) + local base = basalt.getObject("VisualObject")(name, basalt) + -- Base object + local objectType = "ChangeableObject" + + local value + + local object = { + setValue = function(self, _value, valueChangedHandler) + if (value ~= _value) then + value = _value + self:updateDraw() + if(valueChangedHandler~=false)then + self:valueChangedHandler() + end + end + return self + end, + + getValue = function(self) + return value + end, + + onChange = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("value_changed", v) + end + end + return self + end, + + valueChangedHandler = function(self) + self:sendEvent("value_changed", value) + end, + } + + object.__index = object + return setmetatable(object, base) +end \ No newline at end of file diff --git a/Basalt/plugin.lua b/Basalt/plugin.lua new file mode 100644 index 0000000..a316147 --- /dev/null +++ b/Basalt/plugin.lua @@ -0,0 +1,43 @@ +local args = {...} +local plugins = {} + +local dir = fs.getDir(args[2] or "Basalt") +local pluginDir = fs.combine(dir, "plugins") +if(fs.exists(pluginDir))then + for _,v in pairs(fs.list(pluginDir))do + local newPlugin = require(v:gsub(".lua", "")) + if(type(newPlugin)=="table")then + for a,b in pairs(newPlugin)do + if(type(a)=="string")then + if(plugins[a]==nil)then plugins[a] = {} end + table.insert(plugins[a], b) + end + end + end + end +end + +local function get(name) + return plugins[name] +end + +return { + get = get, + addPlugins = function(objects, basalt) + for k,v in pairs(objects)do + local plugList = plugins[k] + if(plugList~=nil)then + objects[k] = function(...) + local moddedObject = v(...) + for a,b in pairs(plugList)do + local ext = b(moddedObject, basalt, ...) + ext.__index = ext + moddedObject = setmetatable(ext, moddedObject) + end + return moddedObject + end + end + end + return objects + end +} \ No newline at end of file diff --git a/Basalt/plugins/advancedBackground.lua b/Basalt/plugins/advancedBackground.lua new file mode 100644 index 0000000..c85e45c --- /dev/null +++ b/Basalt/plugins/advancedBackground.lua @@ -0,0 +1,51 @@ +return { + VisualObject = function(base) + local bgSymbol = false + local bgSymbolColor = colors.black + + local object = { + setBackground = function(self, bg, symbol, symbolCol) + base.setBackground(self, bg) + bgSymbol = symbol or bgSymbol + bgSymbolColor = symbolCol or bgSymbolColor + return self + end, + + setBackgroundSymbol = function(self, symbol, symbolCol) + bgSymbol = symbol + bgSymbolColor = symbolCol or bgSymbolColor + self:updateDraw() + return self + end, + + getBackgroundSymbol = function(self) + return bgSymbol + end, + + getBackgroundSymbolColor = function(self) + return bgSymbolColor + end, + + setValuesByXMLData = function(self, data) + base.setValuesByXMLData(self, data) + if(xmlValue("background-symbol", data)~=nil)then self:setBackgroundSymbol(xmlValue("background-symbol", data), xmlValue("background-symbol-color", data)) end + return self + end, + + draw = function(self) + base.draw(self) + self:addDraw("advanced-bg", function() + local w, h = self:getSize() + if(bgSymbol~=false)then + self:addTextBox(1, 1, w, h, bgSymbol:sub(1,1)) + if(bgSymbol~=" ")then + self:addForegroundBox(1, 1, w, h, bgSymbolColor) + end + end + end, 2) + end, + } + + return object + end +} \ No newline at end of file diff --git a/Basalt/plugins/animations.lua b/Basalt/plugins/animations.lua new file mode 100644 index 0000000..feb1726 --- /dev/null +++ b/Basalt/plugins/animations.lua @@ -0,0 +1,338 @@ +local floor,sin,cos,pi,sqrt,pow = math.floor,math.sin,math.cos,math.pi,math.sqrt,math.pow + +-- You can find the easing curves here https://easings.net + +local function lerp(s, e, pct) + return s + (e - s) * pct +end + +local function linear(t) + return t +end + +local function flip(t) + return 1 - t +end + +local function easeIn(t) + return t * t * t +end + +local function easeOut(t) + return flip(easeIn(flip(t))) +end + +local function easeInOut(t) + return lerp(easeIn(t), easeOut(t), t) +end + +local function easeOutSine(t) + return sin((t * pi) / 2); +end + +local function easeInSine(t) + return flip(cos((t * pi) / 2)) +end + +local function easeInOutSine(t) + return -(cos(pi * x) - 1) / 2 +end + +local function easeInBack(t) + local c1 = 1.70158; + local c3 = c1 + 1 + return c3*t^3-c1*t^2 +end + +local function easeInCubic(t) + return t^3 +end + +local function easeInElastic(t) + local c4 = (2*pi)/3; + return t == 0 and 0 or (t == 1 and 1 or ( + -2^(10*t-10)*sin((t*10-10.75)*c4) + )) +end + +local function easeInExpo(t) + return t == 0 and 0 or 2^(10*t-10) +end + +local function easeInExpo(t) + return t == 0 and 0 or 2^(10*t-10) +end + +local function easeInOutBack(t) + local c1 = 1.70158; + local c2 = c1 * 1.525; + return t < 0.5 and ((2*t)^2*((c2+1)*2*t-c2))/2 or ((2*t-2)^2*((c2+1)*(t*2-2)+c2)+2)/2 +end + +local function easeInOutCubic(t) + return t < 0.5 and 4 * t^3 or 1-(-2*t+2)^3 / 2 +end + +local function easeInOutElastic(t) + local c5 = (2*pi) / 4.5 + return t==0 and 0 or (t == 1 and 1 or (t < 0.5 and -(2^(20*t-10) * sin((20*t - 11.125) * c5))/2 or (2^(-20*t+10) * sin((20*t - 11.125) * c5))/2 + 1)) +end + +local function easeInOutExpo(t) + return t == 0 and 0 or (t == 1 and 1 or (t < 0.5 and 2^(20*t-10)/2 or (2-2^(-20*t+10)) /2)) +end + +local function easeInOutQuad(t) + return t < 0.5 and 2*t^2 or 1-(-2*t+2)^2/2 +end + +local function easeInOutQuart(t) + return t < 0.5 and 8*t^4 or 1 - (-2*t+2)^4 / 2 +end + +local function easeInOutQuint(t) + return t < 0.5 and 16*t^5 or 1-(-2*t+2)^5 / 2 +end + +local function easeInQuad(t) + return t^2 +end + +local function easeInQuart(t) + return t^4 +end + +local function easeInQuint(t) + return t^5 +end + +local function easeOutBack(t) + local c1 = 1.70158; + local c3 = c1 + 1 + return 1+c3*(t-1)^3+c1*(t-1)^2 +end + +local function easeOutCubic(t) + return 1 - (1-t)^3 +end + +local function easeOutElastic(t) + local c4 = (2*pi)/3; + + return t == 0 and 0 or (t == 1 and 1 or (2^(-10*t)*sin((t*10-0.75)*c4)+1)) +end + +local function easeOutExpo(t) + return t == 1 and 1 or 1-2^(-10*t) +end + +local function easeOutQuad(t) + return 1 - (1 - t) * (1 - t) +end + +local function easeOutQuart(t) + return 1 - (1-t)^4 +end + +local function easeOutQuint(t) + return 1 - (1 - t)^5 +end + +local function easeInCirc(t) + return 1 - sqrt(1 - pow(t, 2)) +end + +local function easeOutCirc(t) + return sqrt(1 - pow(t - 1, 2)) +end + +local function easeInOutCirc(t) + return t < 0.5 and (1 - sqrt(1 - pow(2 * t, 2))) / 2 or (sqrt(1 - pow(-2 * t + 2, 2)) + 1) / 2; +end + +local function easeOutBounce(t) + local n1 = 7.5625; + local d1 = 2.75; + + if (t < 1 / d1)then + return n1 * t * t + elseif (t < 2 / d1)then + local a = t - 1.5 / d1 + return n1 * a * a + 0.75; + elseif (t < 2.5 / d1)then + local a = t - 2.25 / d1 + return n1 * a * a + 0.9375; + else + local a = t - 2.625 / d1 + return n1 * a * a + 0.984375; + end +end + +local function easeInBounce(t) + return 1 - easeOutBounce(1 - t) +end + +local function easeInOutBounce(t) + return x < 0.5 and (1 - easeOutBounce(1 - 2 * t)) / 2 or (1 + easeOutBounce(2 * t - 1)) / 2; +end + +local lerp = { + linear = linear, + lerp = lerp, + flip=flip, + easeIn=easeIn, + easeInSine = easeInSine, + easeInBack=easeInBack, + easeInCubic=easeInCubic, + easeInElastic=easeInElastic, + easeInExpo=easeInExpo, + easeInQuad=easeInQuad, + easeInQuart=easeInQuart, + easeInQuint=easeInQuint, + easeInCirc=easeInCirc, + easeInBounce=easeInBounce, + easeOut=easeOut, + easeOutSine = easeOutSine, + easeOutBack=easeOutBack, + easeOutCubic=easeOutCubic, + easeOutElastic=easeOutElastic, + easeOutExpo=easeOutExpo, + easeOutQuad=easeOutQuad, + easeOutQuart=easeOutQuart, + easeOutQuint=easeOutQuint, + easeOutCirc=easeOutCirc, + easeOutBounce=easeOutBounce, + easeInOut=easeInOut, + easeInOutSine = easeInOutSine, + easeInOutBack=easeInOutBack, + easeInOutCubic=easeInOutCubic, + easeInOutElastic=easeInOutElastic, + easeInOutExpo=easeInOutExpo, + easeInOutQuad=easeInOutQuad, + easeInOutQuart=easeInOutQuart, + easeInOutQuint=easeInOutQuint, + easeInOutCirc=easeInOutCirc, + easeInOutBounce=easeInOutBounce, +} + +return { + VisualObject = function(base, basalt) + local activeAnimations = {} + local defaultMode = "linear" + + local function getAnimation(self, timerId) + for k,v in pairs(activeAnimations)do + if(v.timerId==timerId)then + return v + end + end + end + + local function createAnimation(self, v1, v2, duration, timeOffset, mode, typ, f, get, set) + local v1Val, v2Val = get(self) + if(activeAnimations[typ]~=nil)then + os.cancelTimer(activeAnimations[typ].timerId) + end + activeAnimations[typ] = {} + activeAnimations[typ].call = function() + local progress = activeAnimations[typ].progress + local _v1 = math.floor(lerp.lerp(v1Val, v1, lerp[mode](progress / duration))+0.5) + local _v2 = math.floor(lerp.lerp(v2Val, v2, lerp[mode](progress / duration))+0.5) + set(self, _v1, _v2) + end + activeAnimations[typ].finished = function() + set(self, v1, v2) + if(f~=nil)then f(self) end + end + + activeAnimations[typ].timerId=os.startTimer(0.05+timeOffset) + activeAnimations[typ].progress=0 + activeAnimations[typ].duration=duration + activeAnimations[typ].mode=mode + self:listenEvent("other_event") + end + + local object = { + animatePosition = function(self, x, y, duration, timeOffset, mode, f) + mode = mode or defaultMode + duration = duration or 1 + timeOffset = timeOffset or 0 + x = math.floor(x+0.5) + y = math.floor(y+0.5) + createAnimation(self, x, y, duration, timeOffset, mode, "position", f, self.getPosition, self.setPosition) + return self + end, + + animateSize = function(self, w, h, duration, timeOffset, mode, f) + mode = mode or defaultMode + duration = duration or 1 + timeOffset = timeOffset or 0 + createAnimation(self, w, h, duration, timeOffset, mode, "size", f, self.getSize, self.setSize) + return self + end, + + animateOffset = function(self, x, y, duration, timeOffset, mode, f) + mode = mode or defaultMode + duration = duration or 1 + timeOffset = timeOffset or 0 + createAnimation(self, x, y, duration, timeOffset, mode, "offset", f, self.getOffset, self.setOffset) + return self + end, + + doneHandler = function(self, timerId, ...) + for k,v in pairs(activeAnimations)do + if(v.timerId==timerId)then + activeAnimations[k] = nil + self:sendEvent("animation_done", self, "animation_done", k) + end + end + end, + + onAnimationDone = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("animation_done", v) + end + end + + return self + end, + + eventHandler = function(self, event, timerId, ...) + base.eventHandler(self, event, timerId, ...) + if(event=="timer")then + local animation = getAnimation(self, timerId) + if(animation~=nil)then + if(animation.progress1)then + self:setDrawState("label", false) + else + self:setDrawState("label", true) + end + self:updateDraw() + end + return self + end, + + getFontSize = function(self) + return fontsize + end, + + setSize = function(self, w, h, r) + base.setSize(self, w, h, r) + autoSize = false + return self + end, + + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("text", data)~=nil)then self:setText(xmlValue("text", data)) end + if(xmlValue("fontSize", data)~=nil)then self:setFontSize(xmlValue("fontSize", data)) end + return self + end, + + draw = function(self) + base.draw(self) + self:addDraw("bigfonts", function() + if(fontsize>1)then + bigfont = makeText(fontsize-1, self:getText(), self:getForeground(), self:getBackground() or colors.lightGray) + if(autoSize)then + self:getBase():setSize(#bigfont[1][1], #bigfont[1]-1) + end + 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:addText(1, i, bigfont[1][i]) + end + end + end) + end, + } + return object + end +} \ No newline at end of file diff --git a/Basalt/plugins/border.lua b/Basalt/plugins/border.lua new file mode 100644 index 0000000..55d12af --- /dev/null +++ b/Basalt/plugins/border.lua @@ -0,0 +1,102 @@ +return { + VisualObject = function(base) + local inline = true + local borderColors = {top = false, bottom = false, left = false, right = false} + + local object = { + setBorder = function(self, ...) + if(...~=nil)then + local t = {...} + for k,v in pairs(t)do + if(v=="left")or(#t==1)then + borderColors["left"] = t[1] + end + if(v=="top")or(#t==1)then + borderColors["top"] = t[1] + end + if(v=="right")or(#t==1)then + borderColors["right"] = t[1] + end + if(v=="bottom")or(#t==1)then + borderColors["bottom"] = t[1] + end + end + end + self:updateDraw() + return self + end, + + draw = function(self) + base.draw(self) + self:addDraw("border", function() + if(border~=false)then + local x, y = self:getPosition() + local w,h = self:getSize() + local bgCol = self:getBackground() + if(inline)then + if(borderColors["left"]~=false)then + self:addTextBox(1, 1, 1, h, "\149") + if(bgCol~=false)then self:addBackgroundBox(1, 1, 1, h, bgCol) end + self:addForegroundBox(1, 1, 1, h, borderColors["left"]) + end + if(borderColors["top"]~=false)then + self:addTextBox(1, 1, w, 1, "\131") + if(bgCol~=false)then self:addBackgroundBox(1, 1, w, 1, bgCol) end + self:addForegroundBox(1, 1, w, 1, borderColors["top"]) + end + if(borderColors["left"]~=false)and(borderColors["top"]~=false)then + self:addTextBox(1, 1, 1, 1, "\151") + if(bgCol~=false)then self:addBackgroundBox(1, 1, 1, 1, bgCol) end + self:drawForegroundBox(1, 1, 1, 1, borderColors["left"]) + end + if(borderColors["right"]~=false)then + self:addTextBox(w, 1, 1, h, "\149") + if(bgCol~=false)then self:addForegroundBox(w, 1, 1, h, bgCol) end + self:addBackgroundBox(w, 1, 1, h, borderColors["right"]) + end + if(borderColors["bottom"]~=false)then + self:addTextBox(1, h, w, 1, "\143") + if(bgCol~=false)then self:addForegroundBox(1, h, w, 1, bgCol) end + self:addBackgroundBox(1, h, w, 1, borderColors["bottom"]) + end + if(borderColors["top"]~=false)and(borderColors["right"]~=false)then + self:addTextBox(w, 1, 1, 1, "\148") + if(bgCol~=false)then self:addForegroundBox(w, 1, 1, 1, bgCol) end + self:addBackgroundBox(w, 1, 1, 1, borderColors["right"]) + end + if(borderColors["right"]~=false)and(borderColors["bottom"]~=false)then + self:addTextBox(w, h, 1, 1, "\133") + if(bgCol~=false)then self:addForegroundBox(w, h, 1, 1, bgCol) end + self:addBackgroundBox(w, h, 1, 1, borderColors["right"]) + end + if(borderColors["bottom"]~=false)and(borderColors["left"]~=false)then + self:addTextBox(1, h, 1, 1, "\138") + if(bgCol~=false)then self:addForegroundBox(0, h, 1, 1, bgCol) end + self:addBackgroundBox(1, h, 1, 1, borderColors["left"]) + end + end + end + end) + end, + + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data) + local borders = {} + if(xmlValue("border", data)~=nil)then + borders["top"] = colors[xmlValue("border", data)] + borders["bottom"] = colors[xmlValue("border", data)] + borders["left"] = colors[xmlValue("border", data)] + borders["right"] = colors[xmlValue("border", data)] + end + if(xmlValue("borderTop", data)~=nil)then borders["top"] = colors[xmlValue("borderTop", data)] end + if(xmlValue("borderBottom", data)~=nil)then borders["bottom"] = colors[xmlValue("borderBottom", data)] end + if(xmlValue("borderLeft", data)~=nil)then borders["left"] = colors[xmlValue("borderLeft", data)] end + if(xmlValue("borderRight", data)~=nil)then borders["right"] = colors[xmlValue("borderRight", data)] end + self:setBorder(borders["top"], borders["bottom"], borders["left"], borders["right"]) + return self + end + } + + return object + end +} \ No newline at end of file diff --git a/Basalt/plugins/debug.lua b/Basalt/plugins/debug.lua new file mode 100644 index 0000000..eda1001 --- /dev/null +++ b/Basalt/plugins/debug.lua @@ -0,0 +1,92 @@ +local utils = require("utils") +local wrapText = utils.wrapText + +return { + basalt = function(basalt) + local mainFrame = basalt.getMainFrame() + local debugFrame + local debugList + local debugLabel + local debugExitButton + + local function createDebuggingFrame() + local minW = 16 + local minH = 6 + local maxW = 99 + local maxH = 99 + local w, h = mainFrame:getSize() + debugFrame = mainFrame:addMovableFrame("basaltDebuggingFrame"):setSize(w-20, h-10):setBackground(colors.lightGray):setForeground(colors.white):setZIndex(100):hide() + debugFrame:addPane():setSize("parent.w", 1):setPosition(1, 1):setBackground(colors.black):setForeground(colors.white) + debugFrame:setPosition(-w, h/2-debugFrame:getHeight()/2):setBorder(colors.black) + local resizeButton = debugFrame:addButton() + :setPosition("parent.w", "parent.h") + :setSize(1, 1) + :setText("\133") + :setForeground(colors.lightGray) + :setBackground(colors.black) + :onClick(function(self, event, btn, xOffset, yOffset) + end) + :onDrag(function(self, event, btn, xOffset, yOffset) + local w, h = debugFrame:getSize() + local wOff, hOff = w, h + if(w+xOffset-1>=minW)and(w+xOffset-1<=maxW)then + wOff = w+xOffset-1 + end + if(h+yOffset-1>=minH)and(h+yOffset-1<=maxH)then + hOff = h+yOffset-1 + end + debugFrame:setSize(wOff, hOff) + end) + + debugExitButton = debugFrame:addButton():setText("Exit"):setPosition("parent.w - 6", 1):setSize(7, 1):setBackground(colors.red):setForeground(colors.white):onClick(function() + debugFrame:animatePosition(-w, h/2-debugFrame:getHeight()/2, 0.5) + end) + debugList = debugFrame:addList():setSize("parent.w - 2", "parent.h - 3"):setPosition(2, 3):setBackground(colors.lightGray):setForeground(colors.white):setSelectionColor(colors.lightGray, colors.gray) + if(debugLabel==nil)then + debugLabel = mainFrame:addLabel() + :setPosition(1, "parent.h") + :setBackground(colors.black) + :setForeground(colors.white) + :onClick(function() + debugFrame:show() + debugFrame:animatePosition(w/2-debugFrame:getWidth()/2, h/2-debugFrame:getHeight()/2, 0.5) + end) + end + end + + return { + debug = function(...) + local args = { ... } + if(mainFrame==nil)then + mainFrame = basalt.getMainFrame() + if(mainFrame~=nil)then + createDebuggingFrame() + else + print(...) return + end + end + if (mainFrame:getName() ~= "basaltDebuggingFrame") then + if (mainFrame ~= debugFrame) then + debugLabel:setParent(mainFrame) + end + end + local str = "" + for key, value in pairs(args) do + str = str .. tostring(value) .. (#args ~= key and ", " or "") + end + debugLabel:setText("[Debug] " .. str) + for k,v in pairs(wrapText(str, debugList:getWidth()))do + debugList:addItem(v) + end + if (debugList:getItemCount() > 50) then + debugList:removeItem(1) + end + debugList:setValue(debugList:getItem(debugList:getItemCount())) + if(debugList.getItemCount() > debugList:getHeight())then + debugList:setOffset(debugList:getItemCount() - debugList:getHeight()) + end + debugLabel:show() + end + } + end +} \ No newline at end of file diff --git a/Basalt/plugins/dynamicValues.lua b/Basalt/plugins/dynamicValues.lua new file mode 100644 index 0000000..b6fa591 --- /dev/null +++ b/Basalt/plugins/dynamicValues.lua @@ -0,0 +1,123 @@ +local count = require("utils").tableCount + +return { + VisualObject = function(base, basalt) + local dynObjects = {} + local curProperties = {} + local properties = {x="getX", y="getY", w="getWidth", h="getHeight"} + + local function stringToNumber(str) + local ok, result = pcall(load("return " .. str, "", nil, {math=math})) + if not(ok)then error(str.." - is not a valid dynamic value string") end + return result + end + + local function createDynamicValue(self, key, val) + local objectGroup = {} + local properties = properties + for a,b in pairs(properties)do + for v in val:gmatch("%a+%."..a)do + local name = v:gsub("%."..a, "") + if(name~="self")and(name~="parent")then + table.insert(objectGroup, name) + end + end + end + + local parent = self:getParent() + local objects = {} + for k,v in pairs(objectGroup)do + objects[v] = parent:getObject(v) + if(objects[v]==nil)then + error("Dynamic Values - unable to find object: "..v) + end + end + objects["self"] = self + objects["parent"] = parent + + dynObjects[key] = function() + local mainVal = val + for a,b in pairs(properties)do + for v in val:gmatch("%w+%."..a) do + local obj = objects[v:gsub("%."..a, "")] + if(obj~=nil)then + mainVal = mainVal:gsub(v, obj[b](obj)) + else + error("Dynamic Values - unable to find object: "..v) + end + end + end + curProperties[key] = math.floor(stringToNumber(mainVal)+0.5) + end + dynObjects[key]() + end + + local function updatePositions(self) + if(count(dynObjects)>0)then + for k,v in pairs(dynObjects)do + v() + end + local properties = {x="getX", y="getY", w="getWidth", h="getHeight"} + for k,v in pairs(properties)do + if(dynObjects[k]~=nil)then + if(curProperties[k]~=self[v](self))then + if(k=="x")or(k=="y")then + base.setPosition(self, curProperties["x"] or self:getX(), curProperties["y"] or self:getY()) + end + if(k=="w")or(k=="h")then + base.setSize(self, curProperties["w"] or self:getWidth(), curProperties["h"] or self:getHeight()) + end + end + end + end + end + end + + local object = { + updatePositions = updatePositions, + createDynamicValue = createDynamicValue, + + setPosition = function(self, xPos, yPos, rel) + curProperties.x = xPos + curProperties.y = yPos + if(type(xPos)=="string")then + createDynamicValue(self, "x", xPos) + else + dynObjects["x"] = nil + end + if(type(yPos)=="string")then + createDynamicValue(self, "y", yPos) + else + dynObjects["y"] = nil + end + base.setPosition(self, curProperties.x, curProperties.y, rel) + return self + end, + + setSize = function(self, w, h, rel) + curProperties.w = w + curProperties.h = h + if(type(w)=="string")then + createDynamicValue(self, "w", w) + else + dynObjects["w"] = nil + end + if(type(h)=="string")then + createDynamicValue(self, "h", h) + else + dynObjects["h"] = nil + end + base.setSize(self, curProperties.w, curProperties.h, rel) + return self + end, + + customEventHandler = function(self, event, ...) + base.customEventHandler(self, event, ...) + if(event=="basalt_FrameReposition")or(event=="basalt_FrameResize")then + updatePositions(self) + end + end, + } + return object + end +} \ No newline at end of file diff --git a/Basalt/plugins/pixelbox.lua b/Basalt/plugins/pixelbox.lua new file mode 100644 index 0000000..e1863b0 --- /dev/null +++ b/Basalt/plugins/pixelbox.lua @@ -0,0 +1,221 @@ +-- Most of this is made by Dev9551, you can find his awesome work here: https://github.com/9551-Dev/apis/blob/main/pixelbox_lite.lua +-- Slighly modified by NyoriE to work with Basalt + +--[[ +The MIT License (MIT) +Copyright © 2022 Oliver Caha (9551Dev) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] +local t_sort,t_cat,s_char = table.sort,table.concat,string.char +local function sort(a,b) return a[2] > b[2] end + +local distances = { + {5,256,16,8,64,32}, + {4,16,16384,256,128}, + [4] = {4,64,1024,256,128}, + [8] = {4,512,2048,256,1}, + [16] = {4,2,16384,256,1}, + [32] = {4,8192,4096,256,1}, + [64] = {4,4,1024,256,1}, + [128] = {6,32768,256,1024,2048,4096,16384}, + [256] = {6,1,128,2,512,4,8192}, + [512] = {4,8,2048,256,128}, + [1024] = {4,4,64,128,32768}, + [2048] = {4,512,8,128,32768}, + [4096] = {4,8192,32,128,32768}, + [8192] = {3,32,4096,256128}, + [16384] = {4,2,16,128,32768}, + [32768] = {5,128,1024,2048,4096,16384} +} + +local to_colors = {} +for i = 0, 15 do + to_colors[("%x"):format(i)] = 2^i +end + +local to_blit = {} +for i = 0, 15 do + to_blit[2^i] = ("%x"):format(i) +end + +local function pixelbox(colTable, defaultCol) + defaultCol = defaultCol or "f" + local width, height = #colTable[1], #colTable + local cache = {} + local canv = {} + local cached = false + + local function generateCanvas() + for y = 1, height * 3 do + for x = 1, width * 2 do + if not canv[y] then canv[y] = {} end + canv[y][x] = defaultCol + end + end + + for k, v in ipairs(colTable) do + for x = 1, #v do + local col = v:sub(x, x) + canv[k][x] = to_colors[col] + end + end + end + generateCanvas() + + local function setSize(w,h) + width, height = w, h + canv = {} + cached = false + generateCanvas() + end + + + local function generateChar(a,b,c,d,e,f) + local arr = {a,b,c,d,e,f} + local c_types = {} + local sortable = {} + local ind = 0 + for i=1,6 do + local c = arr[i] + if not c_types[c] then + ind = ind + 1 + c_types[c] = {0,ind} + end + + local t = c_types[c] + local t1 = t[1] + 1 + + t[1] = t1 + sortable[t[2]] = {c,t1} + end + local n = #sortable + while n > 2 do + t_sort(sortable,sort) + local bit6 = distances[sortable[n][1]] + local index,run = 1,false + local nm1 = n - 1 + for i=2,bit6[1] do + if run then break end + local tab = bit6[i] + for j=1,nm1 do + if sortable[j][1] == tab then + index = j + run = true + break + end + end + end + local from,to = sortable[n][1],sortable[index][1] + for i=1,6 do + if arr[i] == from then + arr[i] = to + local sindex = sortable[index] + sindex[2] = sindex[2] + 1 + end + end + + sortable[n] = nil + n = n - 1 + end + + local n = 128 + local a6 = arr[6] + + if arr[1] ~= a6 then n = n + 1 end + if arr[2] ~= a6 then n = n + 2 end + if arr[3] ~= a6 then n = n + 4 end + if arr[4] ~= a6 then n = n + 8 end + if arr[5] ~= a6 then n = n + 16 end + + if sortable[1][1] == arr[6] then + return s_char(n),sortable[2][1],arr[6] + else + return s_char(n),sortable[1][1],arr[6] + end + end + + local function convert() + local w_double = width * 2 + + local sy = 0 + for y = 1, height * 3, 3 do + sy = sy + 1 + local layer_1 = canv[y] + local layer_2 = canv[y + 1] + local layer_3 = canv[y + 2] + local char_line, fg_line, bg_line = {}, {}, {} + local n = 0 + for x = 1, w_double, 2 do + local xp1 = x + 1 + local b11, b21, b12, b22, b13, b23 = layer_1[x], layer_1[xp1], layer_2[x], layer_2[xp1], layer_3[x], layer_3[xp1] + + local char, fg, bg = " ", 1, b11 + if not (b21 == b11 and b12 == b11 and b22 == b11 and b13 == b11 and b23 == b11) then + char, fg, bg = generateChar(b11, b21, b12, b22, b13, b23) + end + n = n + 1 + char_line[n] = char + fg_line[n] = to_blit[fg] + bg_line[n] = to_blit[bg] + end + + cache[sy] = {t_cat(char_line), t_cat(fg_line), t_cat(bg_line)} + end + cached = true + end + + return { + convert = convert, + generateCanvas = generateCanvas, + setSize = setSize, + getSize = function() + return width, height + end, + set = function(colTab, defCol) + colTable = colTab + defaultCol = defCol or defaultCol + canv = {} + cached = false + generateCanvas() + end, + get = function(y) + if not cached then convert() end + return y~= nil and cache[y] or cache + end + } +end + +return { + Image = function(base, basalt) + return { + shrink = function(self) + local bimg = self:getImageFrame(1) + local img = {} + for k,v in pairs(bimg)do + if(type(k)=="number")then + table.insert(img,v[3]) + end + end + local shrinkedImg = pixelbox(img, self:getBackground()).get() + self:setImage(shrinkedImg) + return self + end, + + getShrinkedImage = function(self) + local bimg = self:getImageFrame(1) + local img = {} + for k,v in pairs(bimg)do + if(type(k)=="number")then + table.insert(img, v[3]) + end + end + return pixelbox(img, self:getBackground()).get() + end, + } + end, +} \ No newline at end of file diff --git a/Basalt/plugins/shadow.lua b/Basalt/plugins/shadow.lua new file mode 100644 index 0000000..49bfb81 --- /dev/null +++ b/Basalt/plugins/shadow.lua @@ -0,0 +1,40 @@ +return { + VisualObject = function(base) + local shadow = false + + local object = { + setShadow = function(self, color) + shadow = color + self:updateDraw() + return self + end, + + getShadow = function(self) + return shadow + end, + + draw = function(self) + base.draw(self) + self:addDraw("shadow", function() + if(shadow~=false)then + local w,h = self:getSize() + if(shadow)then + self:addBackgroundBox(w+1, 2, 1, h, shadow) + self:addBackgroundBox(2, h+1, w, 1, shadow) + self:addForegroundBox(w+1, 2, 1, h, shadow) + self:addForegroundBox(2, h+1, w, 1, shadow) + end + end + end) + end, + + setValuesByXMLData = function(self, data) + base.setValuesByXMLData(self, data) + if(xmlValue("shadow", data)~=nil)then self:setShadow(xmlValue("shadow", data)) end + return self + end + } + + return object + end +} \ No newline at end of file diff --git a/Basalt/plugins/textures.lua b/Basalt/plugins/textures.lua new file mode 100644 index 0000000..ff77019 --- /dev/null +++ b/Basalt/plugins/textures.lua @@ -0,0 +1,122 @@ +local images = require("images") + +return { + VisualObject = function(base) + local textureId, infinitePlay = 1, true + local bimg, texture, textureTimerId + local textureMode = "default" + + local object = { + addTexture = function(self, path, animate) + bimg = images.loadImageAsBimg(path) + texture = bimg[1] + if(animate)then + if(bimg.animated)then + self:listenEvent("other_event") + local t = bimg[textureId].duration or bimg.secondsPerFrame or 0.2 + textureTimerId = os.startTimer(t) + end + end + self:setBackground(false) + self:setForeground(false) + self:setDrawState("texture-base", true) + self:updateDraw() + return self + end, + + setTextureMode = function(self, mode) + textureMode = mode or textureMode + self:updateDraw() + return self + end, + + setInfinitePlay = function(self, state) + infinitePlay = state + return self + end, + + eventHandler = function(self, event, timerId, ...) + base.eventHandler(self, event, timerId, ...) + if(event=="timer")then + if(timerId == textureTimerId)then + if(bimg[textureId+1]~=nil)then + textureId = textureId + 1 + texture = bimg[textureId] + local t = bimg[textureId].duration or bimg.secondsPerFrame or 0.2 + textureTimerId = os.startTimer(t) + self:updateDraw() + else + if(infinitePlay)then + textureId = 1 + texture = bimg[1] + local t = bimg[textureId].duration or bimg.secondsPerFrame or 0.2 + textureTimerId = os.startTimer(t) + self:updateDraw() + end + end + end + end + end, + + draw = function(self) + base.draw(self) + self:addDraw("texture-base", function() + local obj = self:getParent() or self + local x, y = self:getPosition() + local w,h = self:getSize() + local wP,hP = obj:getSize() + + local textureWidth = bimg.width or #bimg[textureId][1][1] + local textureHeight = bimg.height or #bimg[textureId] + + local startX, startY = 0, 0 + + if (textureMode == "center") then + startX = x + math.floor((w - textureWidth) / 2 + 0.5) - 1 + startY = y + math.floor((h - textureHeight) / 2 + 0.5) - 1 + elseif (textureMode == "default") then + startX, startY = x, y + elseif (textureMode == "right") then + startX, startY = x + w - textureWidth, y + h - textureHeight + end + + local textureX = x - startX + local textureY = y - startY + + if startX < x then + startX = x + textureWidth = textureWidth - textureX + end + if startY < y then + startY = y + textureHeight = textureHeight - textureY + end + if startX + textureWidth > x + w then + textureWidth = (x + w) - startX + end + if startY + textureHeight > y + h then + textureHeight = (y + h) - startY + end + + for k = 1, textureHeight do + if(texture[k+textureY]~=nil)then + local t, f, b = table.unpack(texture[k+textureY]) + self:addBlit(1, k, t:sub(textureX, textureX + textureWidth), f:sub(textureX, textureX + textureWidth), b:sub(textureX, textureX + textureWidth)) + end + end + end, 1) + self:setDrawState("texture-base", false) + end, + + setValuesByXMLData = function(self, data) + base.setValuesByXMLData(self, data) + if(xmlValue("texture", data)~=nil)then self:addTexture(xmlValue("texture", data), xmlValue("animate", data)) end + if(xmlValue("textureMode", data)~=nil)then self:setTextureMode(xmlValue("textureMode", data)) end + if(xmlValue("infinitePlay", data)~=nil)then self:setInfinitePlay(xmlValue("infinitePlay", data)) end + return self + end + } + + return object + end +} \ No newline at end of file diff --git a/Basalt/plugins/themes.lua b/Basalt/plugins/themes.lua new file mode 100644 index 0000000..8342b85 --- /dev/null +++ b/Basalt/plugins/themes.lua @@ -0,0 +1,99 @@ +local baseTheme = { -- The default main theme for basalt! + BaseFrameBG = colors.lightGray, + BaseFrameText = colors.black, + FrameBG = colors.gray, + FrameText = colors.black, + ButtonBG = colors.gray, + ButtonText = colors.black, + CheckboxBG = colors.lightGray, + CheckboxText = colors.black, + InputBG = colors.black, + InputText = colors.lightGray, + TextfieldBG = colors.black, + TextfieldText = colors.white, + ListBG = colors.gray, + ListText = colors.black, + MenubarBG = colors.gray, + MenubarText = colors.black, + DropdownBG = colors.gray, + DropdownText = colors.black, + RadioBG = colors.gray, + RadioText = colors.black, + SelectionBG = colors.black, + SelectionText = colors.lightGray, + GraphicBG = colors.black, + ImageBG = colors.black, + PaneBG = colors.black, + ProgramBG = colors.black, + ProgressbarBG = colors.gray, + ProgressbarText = colors.black, + ProgressbarActiveBG = colors.black, + ScrollbarBG = colors.lightGray, + ScrollbarText = colors.gray, + ScrollbarSymbolColor = colors.black, + SliderBG = false, + SliderText = colors.gray, + SliderSymbolColor = colors.black, + SwitchBG = colors.lightGray, + SwitchText = colors.gray, + LabelBG = false, + LabelText = colors.black, + GraphBG = colors.gray, + GraphText = colors.black +} + +local plugin = { + Container = function(base, name, basalt) + local theme = {} + + local object = { + getTheme = function(self, name) + local parent = self:getParent() + return theme[name] or (parent~=nil and parent:getTheme(name) or baseTheme[name]) + end, + setTheme = function(self, _theme, col) + if(type(_theme)=="table")then + theme = _theme + elseif(type(_theme)=="string")then + theme[_theme] = col + end + self:updateDraw() + return self + end, + } + return object + end, + + basaltInternal = function() + return { + getTheme = function(name) + return baseTheme[name] + end, + setTheme = function(_theme, col) + if(type(_theme)=="table")then + theme = _theme + elseif(type(_theme)=="string")then + theme[_theme] = col + end + end + } + end + +} + +for k,v in pairs({"BaseFrame", "Frame", "ScrollableFrame", "MovableFrame", "Button", "Checkbox", "Dropdown", "Graph", "Graphic", "Input", "Label", "List", "Menubar", "Pane", "Program", "Progressbar", "Radio", "Scrollbar", "Slider", "Switch", "Textfield"})do +plugin[v] = function(base, name, basalt) + local object = { + init = function(self) + if(base.init(self))then + local parent = self:getParent() or self + self:setBackground(parent:getTheme(v.."BG")) + self:setForeground(parent:getTheme(v.."Text")) + end + end + } + return object + end +end + +return plugin \ No newline at end of file diff --git a/Basalt/plugins/xml.lua b/Basalt/plugins/xml.lua new file mode 100644 index 0000000..6f1885b --- /dev/null +++ b/Basalt/plugins/xml.lua @@ -0,0 +1,762 @@ +local utils = require("utils") +local uuid = utils.uuid + +local function newNode(name) + local node = {} + node.___value = nil + node.___name = name + node.___children = {} + node.___props = {} + + function node:value() return self.___value end + function node:setValue(val) self.___value = val end + function node:name() return self.___name end + function node:setName(name) self.___name = name end + function node:children() return self.___children end + function node:numChildren() return #self.___children end + function node:addChild(child) + if self[child:name()] ~= nil then + if type(self[child:name()].name) == "function" then + local tempTable = {} + table.insert(tempTable, self[child:name()]) + self[child:name()] = tempTable + end + table.insert(self[child:name()], child) + else + self[child:name()] = child + end + table.insert(self.___children, child) + end + + function node:properties() return self.___props end + function node:numProperties() return #self.___props end + function node:addProperty(name, value) + local lName = "@" .. name + if self[lName] ~= nil then + if type(self[lName]) == "string" then + local tempTable = {} + table.insert(tempTable, self[lName]) + self[lName] = tempTable + end + table.insert(self[lName], value) + else + self[lName] = value + end + table.insert(self.___props, { name = name, value = self[name] }) + end + + return node +end + +local XmlParser = {} + +function XmlParser:ToXmlString(value) + value = string.gsub(value, "&", "&"); -- '&' -> "&" + value = string.gsub(value, "<", "<"); -- '<' -> "<" + value = string.gsub(value, ">", ">"); -- '>' -> ">" + value = string.gsub(value, "\"", """); -- '"' -> """ + value = string.gsub(value, "([^%w%&%;%p%\t% ])", + function(c) + return string.format("&#x%X;", string.byte(c)) + end); + return value; +end + +function XmlParser:FromXmlString(value) + value = string.gsub(value, "&#x([%x]+)%;", + function(h) + return string.char(tonumber(h, 16)) + end); + value = string.gsub(value, "&#([0-9]+)%;", + function(h) + return string.char(tonumber(h, 10)) + end); + value = string.gsub(value, """, "\""); + value = string.gsub(value, "'", "'"); + value = string.gsub(value, ">", ">"); + value = string.gsub(value, "<", "<"); + value = string.gsub(value, "&", "&"); + return value; +end + +function XmlParser:ParseArgs(node, s) + string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a) + node:addProperty(w, self:FromXmlString(a)) + end) +end + +function XmlParser:ParseXmlText(xmlText) + local stack = {} + local top = newNode() + table.insert(stack, top) + local ni, c, label, xarg, empty + local i, j = 1, 1 + while true do + ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w_:]+)(.-)(%/?)>", i) + if not ni then break end + local text = string.sub(xmlText, i, ni - 1); + if not string.find(text, "^%s*$") then + local lVal = (top:value() or "") .. self:FromXmlString(text) + stack[#stack]:setValue(lVal) + end + if empty == "/" then -- empty element tag + local lNode = newNode(label) + self:ParseArgs(lNode, xarg) + top:addChild(lNode) + elseif c == "" then -- start tag + local lNode = newNode(label) + self:ParseArgs(lNode, xarg) + table.insert(stack, lNode) + top = lNode + else -- end tag + local toclose = table.remove(stack) -- remove top + + top = stack[#stack] + if #stack < 1 then + error("XmlParser: nothing to close with " .. label) + end + if toclose:name() ~= label then + error("XmlParser: trying to close " .. toclose.name .. " with " .. label) + end + top:addChild(toclose) + end + i = j + 1 + end + local text = string.sub(xmlText, i); + if #stack > 1 then + error("XmlParser: unclosed " .. stack[#stack]:name()) + end + return top +end + +function XmlParser:loadFile(xmlFilename, base) + if not base then + base = "" + end + + local path = fs.combine(base, xmlFilename) + local hFile, err = io.open(path, "r"); + + if hFile and not err then + local xmlText = hFile:read("*a"); -- read file content + io.close(hFile); + return self:ParseXmlText(xmlText), nil; + else + print(err) + return nil + end +end + +local function xmlValue(name, tab) + local var + if(type(tab)~="table")then return end + if(tab[name]~=nil)then + if(type(tab[name])=="table")then + if(tab[name].value~=nil)then + var = tab[name]:value() + end + end + end + if(var==nil)then var = tab["@"..name] end + + if(var=="true")then + var = true + elseif(var=="false")then + var = false + elseif(tonumber(var)~=nil)then + var = tonumber(var) + end + return var +end + +local function executeScript(scripts) + for k,v in pairs(scripts)do + if(k~="env")then + for a,b in pairs(v)do + load(b, nil, "t", scripts.env)() + end + end + end +end + +local function registerFunctionEvent(self, data, event, scripts) + if(data:sub(1,1)=="$")then + local data = data:sub(2) + event(self, self:getBasalt():getVariable(data)) + else + event(self, load(data, nil, "t", scripts.env)) + end +end + +return { + VisualObject = function(base, basalt) + + local object = { + setValuesByXMLData = function(self, data, scripts) + local x, y = self:getPosition() + local w, h = self:getSize() + if(xmlValue("x", data)~=nil)then x = xmlValue("x", data) end + if(xmlValue("y", data)~=nil)then y = xmlValue("y", data) end + if(xmlValue("width", data)~=nil)then w = xmlValue("width", data) end + if(xmlValue("height", data)~=nil)then h = xmlValue("height", data) end + if(xmlValue("background", data)~=nil)then self:setBackground(colors[xmlValue("background", data)]) end + + if(xmlValue("script", data)~=nil)then + if(scripts[1]==nil)then + scripts[1] = {} + end + table.insert(scripts[1], xmlValue("script", data)) + end + + local events = {"onClick", "onClickUp", "onHover", "onScroll", "onDrag", "onKey", "onKeyUp", "onRelease", "onChar", "onGetFocus", "onLoseFocus", "onResize", "onReposition", "onEvent", "onLeave"} + for k,v in pairs(events)do + if(xmlValue(v, data)~=nil)then + registerFunctionEvent(self, xmlValue(v, data), self[v], scripts) + end + end + self:setPosition(x, y) + self:setSize(w, h) + + return self + end, + } + return object + end, + + ChangeableObject = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("value", data)~=nil)then self:setValue(xmlValue("value", data)) end + if(xmlValue("onChange", data)~=nil)then + registerFunctionEvent(self, xmlValue("onChange", data), self.onChange, scripts) + end + return self + end, + } + return object + end, + + BaseFrame = function(base, basalt) + local lastXMLReferences = {} + + local function xmlDefaultValues(data, obj, scripts) + if(obj~=nil)then + obj:setValuesByXMLData(data, scripts) + end + end + + local function addXMLObjectType(tab, f, self, scripts) + if(tab~=nil)then + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + local obj = f(self, v["@id"] or uuid()) + table.insert(lastXMLReferences, obj) + xmlDefaultValues(v, obj, scripts) + end + end + end + + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local xOffset, yOffset = self:getOffset() + if(xmlValue("layout", data)~=nil)then self:addLayout(xmlValue("layout", data)) end + if(xmlValue("xOffset", data)~=nil)then xOffset = xmlValue("xOffset", data) end + self:setOffset(xOffset, yOffset) + + local objectList = data:children() + local _OBJECTS = basalt.getObjects() + + for k,v in pairs(objectList)do + if(v.___name~="animation")then + local name = v.___name:gsub("^%l", string.upper) + if(_OBJECTS[name]~=nil)then + addXMLObjectType(v, self["add"..name], self, scripts) + end + end + end + + addXMLObjectType(data["animation"], self.addAnimation, self, scripts) + return self + end, + + loadLayout = function(self, path) + if(fs.exists(path))then + local scripts = {} + scripts.env = _ENV + scripts.env.basalt = basalt + scripts.env.main = self + scripts.env.shared = {} + local f = fs.open(path, "r") + local data = XmlParser:ParseXmlText(f.readAll()) + f.close() + lastXMLReferences = {} + self:setValuesByXMLData(data, scripts) + executeScript(scripts) + end + return self + end, + + } + return object + end, + + Frame = function(base, basalt) + local lastXMLReferences = {} + + local function xmlDefaultValues(data, obj, scripts) + if(obj~=nil)then + obj:setValuesByXMLData(data, scripts) + end + end + + local function addXMLObjectType(tab, f, self, scripts) + if(tab~=nil)then + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + local obj = f(self, v["@id"] or uuid()) + table.insert(lastXMLReferences, obj) + xmlDefaultValues(v, obj, scripts) + end + end + end + + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local xOffset, yOffset = self:getOffset() + if(xmlValue("layout", data)~=nil)then self:addLayout(xmlValue("layout", data)) end + if(xmlValue("xOffset", data)~=nil)then xOffset = xmlValue("xOffset", data) end + if(xmlValue("yOffset", data)~=nil)then yOffset = xmlValue("yOffset", data) end + self:setOffset(xOffset, yOffset) + + local objectList = data:children() + local _OBJECTS = basalt.getObjects() + + for k,v in pairs(objectList)do + if(v.___name~="animation")then + local name = v.___name:gsub("^%l", string.upper) + if(_OBJECTS[name]~=nil)then + addXMLObjectType(v, self["add"..name], self, scripts) + end + end + end + + addXMLObjectType(data["animation"], self.addAnimation, self, scripts) + return self + end, + + loadLayout = function(self, path) + if(fs.exists(path))then + local scripts = {} + scripts.env = _ENV + scripts.env.basalt = basalt + scripts.env.main = self + scripts.env.shared = {} + local f = fs.open(path, "r") + local data = XmlParser:ParseXmlText(f.readAll()) + f.close() + lastXMLReferences = {} + self:setValuesByXMLData(data, scripts) + executeScript(scripts) + end + return self + end, + } + return object + end, + + Button = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("text", data)~=nil)then self:setText(xmlValue("text", data)) end + if(xmlValue("horizontalAlign", data)~=nil)then self:setHorizontalAlign(xmlValue("horizontalAlign", data)) end + if(xmlValue("verticalAlign", data)~=nil)then self:setText(xmlValue("verticalAlign", data)) end + return self + end, + } + return object + end, + + Label = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("text", data)~=nil)then self:setText(xmlValue("text", data)) end + if(xmlValue("align", data)~=nil)then self:setTextAlign(xmlValue("align", data)) end + return self + end, + } + return object + end, + + Input = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local defaultText, defaultFG, defaultBG = self:getDefaultText() + if(xmlValue("defaultText", data)~=nil)then defaultText = xmlValue("defaultText", data) end + if(xmlValue("defaultFG", data)~=nil)then defaultFG = xmlValue("defaultFG", data) end + if(xmlValue("defaultBG", data)~=nil)then defaultBG = xmlValue("defaultBG", data) end + self:setDefaultText(defaultText, defaultFG, defaultBG) + if(xmlValue("offset", data)~=nil)then self:setOffset(xmlValue("offset", data)) end + if(xmlValue("textOffset", data)~=nil)then self:setTextOffset(xmlValue("textOffset", data)) end + if(xmlValue("text", data)~=nil)then self:setValue(xmlValue("text", data)) end + if(xmlValue("inputLimit", data)~=nil)then self:setInputLimit(xmlValue("inputLimit", data)) end + return self + end, + } + return object + end, + + Image = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local xOffset, yOffset = self:getOffset() + if(xmlValue("xOffset", data)~=nil)then xOffset = xmlValue("xOffset", data) end + if(xmlValue("yOffset", data)~=nil)then yOffset = xmlValue("yOffset", data) end + self:setOffset(xOffset, yOffset) + if(xmlValue("path", data)~=nil)then self:loadImage(xmlValue("path", data)) end + if(xmlValue("usePalette", data)~=nil)then self:usePalette(xmlValue("usePalette", data)) end + if(xmlValue("play", data)~=nil)then self:play(xmlValue("play", data)) end + return self + end, + } + return object + end, + + Checkbox = function(base, basalt) + local object = { + setValuesByXMLData = function(self, dat, scriptsa) + base.setValuesByXMLData(self, data, scripts) + local activeSymbol, inactiveSymbol = self:getSymbol() + if(xmlValue("text", data)~=nil)then self:setText(xmlValue("text", data)) end + if(xmlValue("checked", data)~=nil)then self:setChecked(xmlValue("checked", data)) end + if(xmlValue("textPosition", data)~=nil)then self:setTextPosition(xmlValue("textPosition", data)) end + if(xmlValue("activeSymbol", data)~=nil)then activeSymbol = xmlValue("activeSymbol", data) end + if(xmlValue("inactiveSymbol", data)~=nil)then inactiveSymbol = xmlValue("inactiveSymbol", data) end + self:setSymbol(activeSymbol, inactiveSymbol) + return self + end, + } + return object + end, + + Program = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("execute", data)~=nil)then self:execute(xmlValue("execute", data)) end + return self + end, + } + return object + end, + + Progressbar = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local activeBarColor, activeBarSymbol, activeBarSymbolCol = self:getProgressBar() + if(xmlValue("direction", data)~=nil)then self:setDirection(xmlValue("direction", data)) end + if(xmlValue("activeBarColor", data)~=nil)then activeBarColor = colors[xmlValue("activeBarColor", data)] end + if(xmlValue("activeBarSymbol", data)~=nil)then activeBarSymbol = xmlValue("activeBarSymbol", data) end + if(xmlValue("activeBarSymbolColor", data)~=nil)then activeBarSymbolCol = colors[xmlValue("activeBarSymbolColor", data)] end + if(xmlValue("backgroundSymbol", data)~=nil)then self:setBackgroundSymbol(xmlValue("backgroundSymbol", data)) end + if(xmlValue("progress", data)~=nil)then self:setProgress(xmlValue("progress", data)) end + return self + end, + } + return object + end, + + Slider = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("symbol", data)~=nil)then self:setSymbol(xmlValue("symbol", data)) end + if(xmlValue("symbolColor", data)~=nil)then self:setSymbolColor(xmlValue("symbolColor", data)) end + if(xmlValue("index", data)~=nil)then self:setIndex(xmlValue("index", data)) end + if(xmlValue("maxValue", data)~=nil)then self:setIndex(xmlValue("maxValue", data)) end + if(xmlValue("barType", data)~=nil)then self:setBarType(xmlValue("barType", data)) end + return self + end, + } + return object + end, + + Scrollbar = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("symbol", data)~=nil)then self:setSymbol(xmlValue("symbol", data)) end + if(xmlValue("symbolColor", data)~=nil)then self:setSymbolColor(xmlValue("symbolColor", data)) end + if(xmlValue("symbolSize", data)~=nil)then self:setSymbolSize(xmlValue("symbolSize", data)) end + if(xmlValue("scrollAmount", data)~=nil)then self:setScrollAmount(xmlValue("scrollAmount", data)) end + if(xmlValue("index", data)~=nil)then self:setIndex(xmlValue("index", data)) end + if(xmlValue("maxValue", data)~=nil)then self:setIndex(xmlValue("maxValue", data)) end + if(xmlValue("barType", data)~=nil)then self:setBarType(xmlValue("barType", data)) end + return self + end, + } + return object + end, + + MonitorFrame = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("monitor", data)~=nil)then self:setSymbol(xmlValue("monitor", data)) end + return self + end, + } + return object + end, + + Switch = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("symbol", data)~=nil)then self:setSymbol(xmlValue("symbol", data)) end + if(xmlValue("activeBackground", data)~=nil)then self:setActiveBackground(xmlValue("activeBackground", data)) end + if(xmlValue("inactiveBackground", data)~=nil)then self:setInactiveBackground(xmlValue("inactiveBackground", data)) end + return self + end, + } + return object + end, + + Textfield = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local bgSel, fgSel = self:getSelection() + local xOffset, yOffset = self:getOffset() + if(xmlValue("bgSelection", data)~=nil)then bgSel = xmlValue("bgSelection", data) end + if(xmlValue("fgSelection", data)~=nil)then fgSel = xmlValue("fgSelection", data) end + if(xmlValue("xOffset", data)~=nil)then xOffset = xmlValue("xOffset", data) end + if(xmlValue("yOffset", data)~=nil)then yOffset = xmlValue("yOffset", data) end + self:setSelection(fgSel, bgSel) + self:setOffset(xOffset, yOffset) + + + if(data["lines"]~=nil)then + local l = data["lines"]["line"] + if(l.properties~=nil)then l = {l} end + for k,v in pairs(l)do + self:addLine(v:value()) + end + end + if(data["keywords"]~=nil)then + for k,v in pairs(data["keywords"])do + if(colors[k]~=nil)then + local entry = v + if(entry.properties~=nil)then entry = {entry} end + local tab = {} + for a,b in pairs(entry)do + local keywordList = b["keyword"] + if(b["keyword"].properties~=nil)then keywordList = {b["keyword"]} end + for c,d in pairs(keywordList)do + table.insert(tab, d:value()) + end + end + self:addKeywords(colors[k], tab) + end + end + end + if(data["rules"]~=nil)then + if(data["rules"]["rule"]~=nil)then + local tab = data["rules"]["rule"] + if(data["rules"]["rule"].properties~=nil)then tab = {data["rules"]["rule"]} end + for k,v in pairs(tab)do + + if(xmlValue("pattern", v)~=nil)then + self:addRule(xmlValue("pattern", v), colors[xmlValue("fg", v)], colors[xmlValue("bg", v)]) + end + end + end + end + return self + end, + } + return object + end, + + Thread = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("start", data)~=nil)then self:start(load(xmlValue("start", data), nil, "t", scripts.env)) end + return self + end, + } + return object + end, + + Timer = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("start", data)~=nil)then self:start(xmlValue("start", data)) end + if(xmlValue("time", data)~=nil)then self:setTime(xmlValue("time", data)) end + + if(xmlValue("onCall", data)~=nil)then + registerFunctionEvent(self, xmlValue("onCall", data), self.onCall, scripts) + end + return self + end, + } + return object + end, + + List = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local selBg, selFg = self:getSelectionColor() + if(xmlValue("align", data)~=nil)then self:setTextAlign(xmlValue("align", data)) end + if(xmlValue("offset", data)~=nil)then self:setOffset(xmlValue("offset", data)) end + if(xmlValue("selectionBg", data)~=nil)then selBg = xmlValue("selectionBg", data) end + if(xmlValue("selectionFg", data)~=nil)then selFg = xmlValue("selectionFg", data) end + self:setSelectionColor(selBg, selFg) + + if(xmlValue("scrollable", data)~=nil)then self:setScrollable(xmlValue("scrollable", data)) end + + if(data["item"]~=nil)then + local tab = data["item"] + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + if(self:getType()~="Radio")then + self:addItem(xmlValue("text", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) + end + end + end + return self + end, + } + return object + end, + + Dropdown = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local w, h = self:getDropdownSize() + if(xmlValue("dropdownWidth", data)~=nil)then w = xmlValue("dropdownWidth", data) end + if(xmlValue("dropdownHeight", data)~=nil)then h = xmlValue("dropdownHeight", data) end + self:setDropdownSize(w, h) + return self + end, + } + return object + end, + + Radio = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local selBg, selFg = self:getBoxSelectionColor() + local defBg, defFg = self:setBoxDefaultColor() + + if(xmlValue("selectionBg", data)~=nil)then selBg = xmlValue("selectionBg", data) end + if(xmlValue("selectionFg", data)~=nil)then selFg = xmlValue("selectionFg", data) end + self:setBoxSelectionColor(selBg, selFg) + + if(xmlValue("defaultBg", data)~=nil)then defBg = xmlValue("defaultBg", data) end + if(xmlValue("defaultFg", data)~=nil)then defFg = xmlValue("defaultFg", data) end + self:setBoxDefaultColor(defBg, defFg) + + if(data["item"]~=nil)then + local tab = data["item"] + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + self:addItem(xmlValue("text", v), xmlValue("x", v), xmlValue("y", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) + end + end + return self + end, + } + return object + end, + + Menubar = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + if(xmlValue("space", data)~=nil)then self:setSpace(xmlValue("space", data)) end + if(xmlValue("scrollable", data)~=nil)then self:setScrollable(xmlValue("scrollable", data)) end + return self + end, + } + return object + end, + + Graph = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local symbol, symbolCol = self:getGraphSymbol() + if(xmlValue("maxEntries", data)~=nil)then self:setMaxEntries(xmlValue("maxEntries", data)) end + if(xmlValue("type", data)~=nil)then self:setGraphType(xmlValue("type", data)) end + if(xmlValue("minValue", data)~=nil)then self:setMinValue(xmlValue("minValue", data)) end + if(xmlValue("maxValue", data)~=nil)then self:setMaxValue(xmlValue("maxValue", data)) end + if(xmlValue("symbol", data)~=nil)then symbol = xmlValue("symbol", data) end + if(xmlValue("symbolColor", data)~=nil)then symbolCol = xmlValue("symbolColor", data) end + self:setGraphSymbol(symbol, symbolCol) + if(data["item"]~=nil)then + local tab = data["item"] + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + self:addDataPoint(xmlValue("value")) + end + end + return self + end, + } + return object + end, + + Treeview = function(base, basalt) + local object = { + setValuesByXMLData = function(self, data, scripts) + base.setValuesByXMLData(self, data, scripts) + local selBg, selFg = self:getSelectionColor() + local xOffset, yOffset = self:getOffset() + if(xmlValue("space", data)~=nil)then self:setSpace(xmlValue("space", data)) end + if(xmlValue("scrollable", data)~=nil)then self:setScrollable(xmlValue("scrollable", data)) end + if(xmlValue("selectionBg", data)~=nil)then selBg = xmlValue("selectionBg", data) end + if(xmlValue("selectionFg", data)~=nil)then selFg = xmlValue("selectionFg", data) end + self:setSelectionColor(selBg, selFg) + if(xmlValue("xOffset", data)~=nil)then xOffset = xmlValue("xOffset", data) end + if(xmlValue("yOffset", data)~=nil)then yOffset = xmlValue("yOffset", data) end + self:setOffset(xOffset, yOffset) + local function addNode(node, data) + if(data["node"]~=nil)then + local tab = data["node"] + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + local n = node:addNode(xmlValue("text", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) + addNode(n, v) + end + end + end + if(data["node"]~=nil)then + local tab = data["node"] + if(tab.properties~=nil)then tab = {tab} end + for k,v in pairs(tab)do + local n = self:addNode(xmlValue("text", v), colors[xmlValue("bg", v)], colors[xmlValue("fg", v)]) + addNode(n, v) + end + end + + + return self + end, + } + return object + end, + +} \ No newline at end of file diff --git a/docs/Home.md b/docs/Home.md index 08db0ec..04e9ad5 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -2,11 +2,18 @@ *Note: The Basalt Wiki is a work in progress. Please treat wiki errors the same as bugs and report them accordingly.* -Here you can find information about how to use Basalt as well as examples of functional Basalt code. The aim of Basalt is to improve user interaction through visual display. +Basalt is a user-friendly UI framework for CC:Tweaked (also known as "ComputerCraft: Tweaked") - a popular Minecraft mod. It was developed to enhance user interaction through visual displays. In this wiki, you'll find information on how to use Basalt as well as examples of functional Basalt code. + ## About Basalt -Basalt is intended to be an easy-to-understand UI Framework designed for CC:Tweaked (Also known as "ComputerCraft: Tweaked") - a popular minecraft mod. For more information about CC:Tweaked, checkout the project's [wiki](https://tweaked.cc/) or [download](https://modrinth.com/mod/cc-tweaked). +Basalt is an easy-to-understand UI framework designed to improve user interaction with CC:Tweaked. Some of its key features include: + +- A set of pre-built UI components for creating interfaces quickly and easily. +- A flexible layout system that allows users to create custom designs. +- A powerful event handling system for managing user input and interaction. +- Support for multiple screen resolutions and aspect ratios. +- Extensive documentation and examples to help users get started quickly. ## Quick Demo diff --git a/docs/_footer.md b/docs/_footer.md index d381de8..dfb8692 100644 --- a/docs/_footer.md +++ b/docs/_footer.md @@ -1,3 +1 @@ ---- - -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: [discord.gg/yM7kndJdJJ](discord.gg/yM7kndJdJJ) \ No newline at end of file diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 93467e1..b6adffd 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -2,29 +2,38 @@ - [Home](home) - [How To](home/How-To) - [Download](home/download) + - [1.6 Docs](docs1_6) - Objects - [Basalt](objects/Basalt.md) - [Object](objects/Object.md) + - [VisualObject](objects/VisualObject.md) + - [ChangeableObject](objects/ChangeableObject.md) + - [Container](objects/Container.md) + - [BaseFrame](objects/BaseFrame.md) + - [Frame](objects/Frame.md) + - [Flexbox](objects/Flexbox.md) + - [MovableFrame](objects/MovableFrame.md) + - [ScrollableFrame](objects/ScrollableFrame.md) - [Button](objects/Button.md) - [Checkbox](objects/Checkbox.md) - - [Dropdown](objects/Dropdown.md) - - [Frame](objects/Frame.md) + - [Graph](objects/Graph.md) - [Image](objects/Image.md) - [Input](objects/Input.md) - [Label](objects/Label.md) - [List](objects/List.md) - - [Menubar](objects/Menubar.md) + - [Dropdown](objects/Dropdown.md) + - [Menubar](objects/Menubar.md) + - [Radio](objects/Radio.md) - [Pane](objects/Pane.md) - [Program](objects/Program.md) - [Progressbar](objects/Progressbar.md) - - [Radio](objects/Radio.md) - [Scrollbar](objects/Scrollbar.md) - [Slider](objects/Slider.md) - [Textfield](objects/Textfield.md) - - [Animation](objects/Animation.md) - [Thread](objects/Thread.md) + - [Treeview](objects/Treeview.md) - [Timer](objects/Timer.md) -- Tips & Tricks +- Tutorials - [Your Logic](tips/logic.md) - [Button coloring](tips/buttonColoring.md) - [Designing/Animating](tips/design.md) diff --git a/docs/docs1_6/.nojekyll b/docs/docs1_6/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/docs1_6/CNAME b/docs/docs1_6/CNAME new file mode 100644 index 0000000..6058206 --- /dev/null +++ b/docs/docs1_6/CNAME @@ -0,0 +1 @@ +basalt.madefor.cc \ No newline at end of file diff --git a/docs/docs1_6/Home.md b/docs/docs1_6/Home.md new file mode 100644 index 0000000..53186ff --- /dev/null +++ b/docs/docs1_6/Home.md @@ -0,0 +1,26 @@ +# Welcome to The old Basalt Wiki! + +This Basalt Wiki is outdated! + +*Note: The Basalt Wiki is a work in progress. Please treat Wiki errors the same as bugs and report them accordingly.* + +Here you can find information about how to use Basalt as well as examples of functional Basalt code. The aim of Basalt is to improve user interaction through visual display. + +## About Basalt + +Basalt is intended to be an easy-to-understand UI Framework designed for CC:Tweaked (Also know as "ComputerCraft: Tweaked") - a popular minecraft mod. For more information about CC:Tweaked, checkout the project's [wiki](https://tweaked.cc/) or [download](https://www.curseforge.com/minecraft/mc-mods/cc-tweaked). + +## Quick Demo + + +## Questions & Bugs + +Obviously NyoriE has implemented some easter eggs, *some people* call them "bugs". If you happen to discover one of these just make a new issue. + +Additionally, if you have questions about Basalt or how to make use of it, feel free to create a new discussion on Basalt's Discussion Board, or ask in our [discord](https://discord.gg/yNNnmBVBpE). + +--- + +Feel free to join our [discord](https://discord.gg/yNNnmBVBpE)! + +

diff --git a/docs/docs1_6/_footer.md b/docs/docs1_6/_footer.md new file mode 100644 index 0000000..dfb8692 --- /dev/null +++ b/docs/docs1_6/_footer.md @@ -0,0 +1 @@ +Thanks for checking out our wiki, join our discord for more help: [discord.gg/yM7kndJdJJ](discord.gg/yM7kndJdJJ) \ No newline at end of file diff --git a/docs/docs1_6/_media/basaltPreview2.gif b/docs/docs1_6/_media/basaltPreview2.gif new file mode 100644 index 0000000..6b3da2b Binary files /dev/null and b/docs/docs1_6/_media/basaltPreview2.gif differ diff --git a/docs/docs1_6/_media/installer.png b/docs/docs1_6/_media/installer.png new file mode 100644 index 0000000..dcdd535 Binary files /dev/null and b/docs/docs1_6/_media/installer.png differ diff --git a/docs/docs1_6/_media/logo.png b/docs/docs1_6/_media/logo.png new file mode 100644 index 0000000..2cd3558 Binary files /dev/null and b/docs/docs1_6/_media/logo.png differ diff --git a/docs/docs1_6/_navbar.md b/docs/docs1_6/_navbar.md new file mode 100644 index 0000000..f208277 --- /dev/null +++ b/docs/docs1_6/_navbar.md @@ -0,0 +1,4 @@ +- Getting Started + - [Home](Home.md) + - [Quick Start](home/Quick-Start.md) + - [Installer](home/installer) diff --git a/docs/docs1_6/_sidebar.md b/docs/docs1_6/_sidebar.md new file mode 100644 index 0000000..17667c6 --- /dev/null +++ b/docs/docs1_6/_sidebar.md @@ -0,0 +1,35 @@ +- About + - [Home](Home.md) + - [Quick Start](home/Quick-Start.md) + - [Installer](home/installer) +- Objects + - [Basalt](objects/Basalt) + - [Object](objects/Object) + - [Button](objects/Button) + - [Checkbox](objects/Checkbox) + - [Dropdown](objects/Dropdown) + - [Frame](objects/Frame) + - [Image](objects/Image) + - [Input](objects/Input) + - [Label](objects/Label) + - [List](objects/List) + - [Menubar](objects/Menubar) + - [Pane](objects/Pane) + - [Program](objects/Program) + - [Progressbar](objects/Progressbar) + - [Radio](objects/Radio) + - [Scrollbar](objects/Scrollbar) + - [Slider](objects/Slider) + - [Textfield](objects/Textfield) + - [Animation](objects/Animation.md) + - [Thread](objects/Thread) + - [Timer](objects/Timer) +- Events + - [Mouse Events](events/mouseEvents.md) + - [Keyboard Events](events/keyEvents.md) + - [Other Events](events/otherEvents.md) +- Tips & Tricks + - [Component Logic](tips/logic) + - [Changing Button Color](tips/buttons) + - [Advanced usage of Events](tips/events.md) + - [Example Designs](tips/design.md) diff --git a/docs/docs1_6/favicon-16x16.png b/docs/docs1_6/favicon-16x16.png new file mode 100644 index 0000000..222b2e0 Binary files /dev/null and b/docs/docs1_6/favicon-16x16.png differ diff --git a/docs/docs1_6/favicon-32x32.png b/docs/docs1_6/favicon-32x32.png new file mode 100644 index 0000000..64a8256 Binary files /dev/null and b/docs/docs1_6/favicon-32x32.png differ diff --git a/docs/docs1_6/favicon.ico b/docs/docs1_6/favicon.ico new file mode 100644 index 0000000..c45aaee Binary files /dev/null and b/docs/docs1_6/favicon.ico differ diff --git a/docs/docs1_6/home/Quick-Start.md b/docs/docs1_6/home/Quick-Start.md new file mode 100644 index 0000000..5002627 --- /dev/null +++ b/docs/docs1_6/home/Quick-Start.md @@ -0,0 +1,92 @@ +## HowTo Use + +To load the framework into your project, make use of the following code on top of your code. +```lua +local basalt = require("basalt") +``` + +It does not matter if you have installed the single file version or the full folder project.
+Both versions can be loaded by using `require("Basalt")`, you dont need to add `.lua`. + +## Download + +### Download the folder version +This version is for people who'd like to work with Basalt, change something in Basalt or checkout the project.
+But you are also able to just use it to create your own UI.
+ +To install the full project to your CC:Tweaked Computer, use the following command on your CC:Tweaked shell: + +`pastebin run ESs1mg7P` + +This will download the project as a folder called "Basalt". You are immediatly after the download is done able to use it in your projects. + +### Download the single file version +This is the version you should use if you're done with programming. It is a little bit faster and it is also minified, which makes the project smaller. +To install the single filed project to your CC:Tweaked Computer, use the following command on your CC:Tweaked shell: + +`pastebin run ESs1mg7P packed` + +This will download the project as a single file called "basalt.lua". You are immediatly after the download is done able to use it in your projects. + +### Basalt Package Manager + +The Basalt Package Manager is still in alpha!

+The Basalt Package Manager is a visual installer, you are able to change some settings, also to choose which objects are necessary for your projects and which are not. + +To install the BPM (Basalt Package Manager) use the following command on your CC:Tweaked shell: + +`pastebin run ESs1mg7P bpm true` + +The true keyword in the end is optional and would simply start BPM immediately. + +## Example +Here is a fully functioning example of Basalt code + +```lua +local basalt = require("basalt") --> Load the Basalt framework + +--> Create the first frame. Please note that Basalt needs at least one active "non-parent" frame to properly supply events +--> When Basalt#createFrame makes use of unique identifiers (commonly referred to as UIDs), meaning that the supplied value must be UNIQUE +local mainFrame = basalt.createFrame("mainFrame") + +--> Show the frame to the user +mainFrame:show() + +local button = mainFrame:addButton("clickableButton") --> Add a button to the mainFrame (With a unique identifier) + +--> Set the position of the button, Button#setPosition follows an x, y pattern. +--> The x value is how far right the object should be from its anchor (negative values from an anchor will travel left) +--> The y value is how far down the object should be from its anchor (negative values from an anchor will travel up) +button:setPosition(4, 4) + +button:setText("Click me!") --> Set the text of our button + +local function buttonClick() --> This function serves as our click logic + basalt.debug("I got clicked!") +end + +--> Remember! You cannot supply buttonClick(), that will only supply the result of the function +--> Make sure the button knows which function to call when it's clicked +button:onClick(buttonClick) + +button:show() --> Make the button visible, so the user can click it + +basalt.autoUpdate() --> Basalt#autoUpdate starts the event listener to detect user input +``` +If you're like us and strive for succinct and beautiful code, here is a cleaner implementation of the code above: +```lua +local basalt = require("basalt") + +local mainFrame = basalt.createFrame("mainFrame"):show() +local button = mainFrame --> Basalt returns an instance of the object on most methods, to make use of "call-chaining" + :addButton("clickableButton") --> This is an example of call chaining + :setPosition(4,4) + :setText("Click me!") + :onClick( + function() + basalt.debug("I got clicked!") + end) + :show() + +basalt.autoUpdate() +``` diff --git a/docs/docs1_6/home/installer.md b/docs/docs1_6/home/installer.md new file mode 100644 index 0000000..8a22e62 --- /dev/null +++ b/docs/docs1_6/home/installer.md @@ -0,0 +1,74 @@ +# Installer + +This is just a script which helps you to setup your program to automatically install the Basalt UI Framework, if it doesn't exists. Means, you create your program (which requires basalt) and add this on the top of your program. Now, everytime you execute your program it checks if basalt.lua (or your custom filepath) exists or not, if not it installs it, or if you are using the advanced installer, it asks the user if the program is allowed to install basalt for you. + +## Basic Installer +Here is a very basic one which just installs basalt.lua if don't exist: +```lua +--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", "")) -- here you can change the variablename in any variablename you want default: basalt +``` + +## Advanced Installer +This is a visual version, it asks the user if he wants to install basalt.lua (if not found)
+![](https://raw.githubusercontent.com/Pyroxenium/Basalt/master/docs/_media/installer.png) +```lua +--Basalt configurated installer +local filePath = "basalt.lua" --here you can change the file path default: basalt +if not(fs.exists(filePath))then + local w,h = term.getSize() + term.clear() + local _installerWindow = window.create(term.current(),w/2-8,h/2-3,18,6) + _installerWindow.setBackgroundColor(colors.gray) + _installerWindow.setTextColor(colors.black) + _installerWindow.write(" Basalt Installer ") + _installerWindow.setBackgroundColor(colors.lightGray) + for line=2,6,1 do + _installerWindow.setCursorPos(1,line) + if(line==3)then + _installerWindow.write(" No Basalt found! ") + elseif(line==4)then + _installerWindow.write(" Install it? ") + elseif(line==6)then + _installerWindow.setTextColor(colors.black) + _installerWindow.setBackgroundColor(colors.gray) + _installerWindow.write("Install") + _installerWindow.setBackgroundColor(colors.lightGray) + _installerWindow.write(string.rep(" ",5)) + _installerWindow.setBackgroundColor(colors.red) + _installerWindow.write("Cancel") + else + _installerWindow.write(string.rep(" ",18)) + end + end + _installerWindow.setVisible(true) + _installerWindow.redraw() + while(not(fs.exists(filePath))) do + local event, p1,p2,p3,p4 = os.pullEvent() + if(event=="mouse_click")then + if(p3==math.floor(h/2+2))and(p2>=w/2-8)and(p2<=w/2-2)then + shell.run("pastebin run ESs1mg7P packed true "..filePath:gsub(".lua", "")) + _installerWindow.setVisible(false) + term.clear() + break + end + if(p3==math.floor(h/2+2))and(p2<=w/2+9)and(p2>=w/2+4)then + _installerWindow.clear() + _installerWindow.setVisible(false) + term.setCursorPos(1,1) + term.clear() + return + end + end + end + term.setCursorPos(1,1) + term.clear() +end + +local basalt = require(filePath:gsub(".lua", "")) -- here you can change the variablename in any variablename you want default: basalt +------------------------------ +``` diff --git a/docs/docs1_6/index.html b/docs/docs1_6/index.html new file mode 100644 index 0000000..794319b --- /dev/null +++ b/docs/docs1_6/index.html @@ -0,0 +1,54 @@ + + + + + Basalt Documentation + + + + + + + + + + + +
Did you know: Basalt is a Pyroxene?>
+ + + + + + + diff --git a/docs/docs1_6/objects/Animation.md b/docs/docs1_6/objects/Animation.md new file mode 100644 index 0000000..77b8725 --- /dev/null +++ b/docs/docs1_6/objects/Animation.md @@ -0,0 +1,303 @@ +With animations, you can create a beautiful experience for users while interacting with objects.
+For now the animation class is very basic, it will be expanded in the future, but we have to say you can already do almost everything you can imagine! + +Right now animation is a class which makes use of the timer event.
+You can find more information below: + +`The animation object is still a WIP and the way you use it right now could change in the future!` + +## add +Adds a new function to an animation +#### Parameters: +1. `function` The function containing animation logic + +#### Returns: +1. `animation` Animation in use + + +#### Usage: +* This will set the button position to 3,3, waits 1 second, then sets position to 4,4, waits 2 seconds, and then sets the position to 5,5 +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton() +local aAnimation = mainFrame:addAnimation():add(function() testButton:setPosition(3,3) end):wait(1):add(function() testButton:setPosition(1,1,"r") end):wait(2):add(function() testButton:setPosition(1,1,"r") end) +aAnimation:play() +``` + +## wait +Sets a wait timer for the next function after the previous function got executed, no wait timer calls the next function immediately +#### Parameters: +1. `number` The length of delay between the functions _(in seconds)_ + +#### Returns: +1. `animation` Animation in use + +#### Usage: +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton() +local aAnimation = mainFrame:addAnimation():add(function() testButton:setPosition(3,3) end):wait(1):add(function() testButton:setPosition(1,1,"r") end):wait(2):add(function() testButton:setPosition(1,1,"r") end) + +aAnimation:play() +``` + +## play +Plays the animation +#### Parameters: +1. `boolean` Whether it will loop forever, will most likely be replaced with a count in the future + +#### Returns: +1. `animation` Animation in use + +#### Usage: +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton() +local aAnimation = mainFrame:addAnimation():add(function() testButton:setBackground(colors.black) end):wait(1):add(function() testButton:setBackground(colors.gray) end):wait(1):add(function() testButton:setBackground(colors.lightGray) end) + +aAnimation:play() -- changes the background color of that button from black to gray and then to lightGray +``` + +## cancel +Cancels the animation + +#### Returns: +1. `animation` Animation in use + +#### Usage: + +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton() +local aAnimation = mainFrame:addAnimation():add(function() testButton:setBackground(colors.black) end):wait(1):add(function() aAnimation:cancel() end):wait(1):add(function() testButton:setBackground(colors.lightGray) end) + +aAnimation:play() +``` + + +## setObject +Sets the object which the animation should reposition/resize + +#### Parameters: +1. `table` object + +#### Returns: +1. `animation` Animation in use + +#### Usage: + +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton() +local aAnimation = mainFrame:addAnimation():setObject(testButton) +``` + +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +``` +```xml + +``` + +## move +Moves the object which got defined by setObject + +#### Parameters: +1. `number` x coordinate +2. `number` y coordinate +3. `number` duration in seconds +4. `number` time - time when this part should begin (offset to when the animation starts - default 0) +5. `table` object - optional, you could also define the object here + +#### Returns: +1. `animation` Animation in use + +#### Usage: +* Takes 2 seconds to move the object from its current position to x15 y3 +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(testButton):move(15,3,2):play() +``` +```xml + +1562 + +``` + +## offset +Changes the offset on the object which got defined by setObject + +#### Parameters: +1. `number` x offset +2. `number` y offset +3. `number` duration in seconds +4. `number` time - time when this part should begin (offset to when the animation starts - default 0) +5. `table` object - optional, you could also define the object here + +#### Returns: +1. `animation` Animation in use + +#### Usage: + +```lua +local mainFrame = basalt.createFrame() +local subFrame = mainFrame:addFrame("frameToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(subFrame):offset(1,12,1):play() +``` +```xml + +1121 + +``` + +## size +Changes the size on the object which got defined by setObject + +#### Parameters: +1. `number` width +2. `number` height +3. `number` duration in seconds +4. `number` time - time when this part should begin (offset to when the animation starts - default 0) +5. `table` object - optional, you could also define the object here + +#### Returns: +1. `animation` Animation in use + +#### Usage: +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(testButton):size(15,3,1):play() +``` +```xml + +1531 + +``` + +## changeText +Changes the text while animation is running + +#### Parameters: +1. `table` multiple text strings - example: {"i", "am", "groot"} +2. `number` duration in seconds +3. `number` time - time when this part should begin (offset to when the animation starts - default 0) + +#### Returns: +1. `animation` Animation in use + +#### Usage: + +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(testButton):changeText({"i", "am", "groot"}, 2):play() +``` +```xml + + + i + am + groot + 2 + + +``` + +## changeTextColor +Changes the text color while the animation is running + +#### Parameters: +1. `table` multiple color numbers - example: {colors.red, colors.yellow, colors.green} +2. `number` duration in seconds +3. `number` time - time when this part should begin (offset to when the animation starts - default 0) + +#### Returns: +1. `animation` Animation in use + +#### Usage: + +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(testButton):changeTextColor({colors.red, colors.yellow, colors.green}, 2):play() +``` +```xml + + + red + yellow + green + 2 + + +``` + +## changeBackground +Changes the background color while the animation is running + +#### Parameters: +1. `table` multiple color numbers - example: {colors.red, colors.yellow, colors.green} +2. `number` duration in seconds +3. `number` time - time when this part should begin (offset to when the animation starts - default 0) + +#### Returns: +1. `animation` Animation in use + +#### Usage: + +```lua +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(testButton):changeTextColor({colors.red, colors.yellow, colors.green}, 2):play() +``` +```xml + + + red + yellow + green + 2 + + +``` + +# Events + +## onDone +`onDone(self)`
+This is a event which gets fired as soon as the animation has finished. + +```lua +local basalt = require("Basalt") + +local mainFrame = basalt.createFrame() +local testButton = mainFrame:addButton("buttonToAnimate") +local aAnimation = mainFrame:addAnimation():setObject(testButton):changeTextColor({colors.red, colors.yellow, colors.green}, 2):play() +aAnimation:onDone(function() + basalt.debug("The animation is done") +end) +``` + +In XML you are also able to queue multiple animations, like this: + +```xml + + + red + yellow + green + 2 + + + + + red + yellow + green + 2 + + +``` \ No newline at end of file diff --git a/docs/docs1_6/objects/Basalt.md b/docs/docs1_6/objects/Basalt.md new file mode 100644 index 0000000..844f211 --- /dev/null +++ b/docs/docs1_6/objects/Basalt.md @@ -0,0 +1,201 @@ +Before you can access Basalt, you need to add the following code on top of your file: + +`local basalt = require("Basalt")` + +Now you are able to access the following methods: + +## basalt.createFrame +Create a base-frame (main frame) +#### Parameters: +1. `string` name + +#### Returns: +1. `frame` object + +#### Usage: +* Create and show a frame with id "myFirstFrame" +```lua +local mainFrame = basalt.createFrame("myFirstFrame") +``` + +## basalt.removeFrame +Removes a base frame + +#### Parameters: +1. `string` name + +#### Usage: +* Removes the previously created frame with id "myFirstFrame" +```lua +local mainFrame = basalt.createFrame("myFirstFrame") +basalt.removeFrame("myFirstFrame") +``` + +## basalt.getFrame +Returns a base frame with the given name +#### Parameters: +1. `string` name + +#### Returns: +1. `frame` object + +#### Usage: +* Creates, fetches and shows the "myFirstFrame" object +```lua +basalt.createFrame("myFirstFrame"):hide() +basalt.getFrame("myFirstFrame"):show() +``` + +## basalt.getActiveFrame +Returns the currently active base frame + +#### Returns: +1. `frame` The current frame + +#### Usage: +* Displays the active frame name in the debug console +```lua +basalt.createFrame() +basalt.debug(basalt.getActiveFrame():getName()) -- returns the uuid +``` + +## basalt.autoUpdate +Starts the draw and event handler until basalt.stopUpdate() is called + +#### Usage: +* Enable the basalt updates, otherwise the screen will not continue to update +```lua +local mainFrame = basalt.createFrame() +basalt.autoUpdate() +``` + +## basalt.update +Calls the draw and event handler once - this gives more flexibility about which events basalt should process. For example you could filter the terminate event. + +#### Parameters: +1. `string` The event to be received +2. `...` Additional event variables to capture + +#### Usage: +* Creates and starts a custom update cycle +```lua +local mainFrame = basalt.createFrame() +local aButton = mainFrame:addButton():setPosition(2,2) +while true do + basalt.update(os.pullEventRaw()) +end +``` + +## basalt.stopUpdate +Stops the automatic draw and event handler which got started by basalt.autoUpdate() + +#### Usage: +* When the quit button is clicked, the button stops basalt auto updates +```lua +local mainFrame = basalt.createFrame() +local aButton = mainFrame:addButton():setPosition(2,2):setText("Stop Basalt!") +aButton:onClick(function() +basalt.stopUpdate() +end) +basalt.autoUpdate() +``` + +## basalt.isKeyDown +Checks if the user is currently holding a key + +#### Parameters: +1. `number` key code (use the keys table for that) + +#### Returns: +1. `boolean` true or false + +#### Usage: +* Shows a debug message with true or false if the left ctrl key is down, as soon as you click on the button. +```lua +local mainFrame = basalt.createFrame() +local aButton = mainFrame:addButton():setPosition(2,2):setText("Check Ctrl") +aButton:onClick(function() + basalt.debug(basalt.isKeyDown(keys.leftCtrl)) +end) +basalt.autoUpdate() +``` + +## basalt.debug +creates a label with some information on the main frame on the bottom left, if you click on that label it will open a log view for you. See it as the new print for debugging + +You can also edit the default debug Label (change position, change color or whatever you want) by accessing the variable basalt.debugLabel +which returns the debug Label. + +Also basalt.debugFrame and basalt.debugList are available. + +#### Parameters: +1. `...` (multiple parameters are possible, like print does) + +#### Usage: +* Prints "Hello! ^-^" to the debug console +```lua +basalt.debug("Hello! ", "^-^") +``` + +## basalt.setTheme +Sets the base theme of the project! Make sure to cover all existing objects, otherwise it will result in errors. A good example is [theme](https://github.com/Pyroxenium/Basalt/blob/master/Basalt/theme.lua) + +#### Parameters: +1. `table` theme layout look into [theme](https://github.com/Pyroxenium/Basalt/blob/master/Basalt/theme.lua) for a example + +#### Usage: +* Sets the default theme of basalt. +```lua +basalt.setTheme({ + ButtonBG = colors.yellow, + ButtonText = colors.red, + ..., +}) +``` + +## basalt.setVariable +This stores a variable which you're able to access via xml. You are also able to add a function, which then gets called by object events created in XML. + +#### Parameters: +1. `string` a key name +1. `any` any variable + +#### Usage: +* Adds a function to basalt. +```lua +basalt.setVariable("clickMe", function() + basalt.debug("I got clicked") +end) +``` +```xml + +``` + +In these examples, a button is created with the text "Click". When the left mouse button is clicked on the button, the message "Left mouse button got clicked!" is printed. diff --git a/docs/objects/Button/setHorizontalAlign.md b/docs/objects/Button/setHorizontalAlign.md index dbf3c61..814400c 100644 --- a/docs/objects/Button/setHorizontalAlign.md +++ b/docs/objects/Button/setHorizontalAlign.md @@ -1,20 +1,28 @@ ## setHorizontalAlign + +### Description + Sets the horizontal align of the button text -#### Parameters: +### Parameters + 1. `string` the position as string ("left", "center", "right") - default is center. -#### Returns: +### Returns + 1. `object` The object in use -#### Usage: -* Sets the button's horizontal text align to right. +### Usage + +* Sets the button's horizontal text align to right. + ```lua local mainFrame = basalt.createFrame() local button = mainFrame:addButton() :setText("Click me!") :setHorizontalAlign("right") ``` + ```xml +``` + +In these examples, a button is created with the text "Click". When the left mouse button is clicked on the button, the message "Left mouse button got clicked!" is printed. diff --git a/docs/objects/ChangeableObject/getValue.md b/docs/objects/ChangeableObject/getValue.md new file mode 100644 index 0000000..8b28e57 --- /dev/null +++ b/docs/objects/ChangeableObject/getValue.md @@ -0,0 +1,21 @@ +## getValue + +### Description + +Gets the value of your object + +### Returns + +1. `any` The current value of the object + +### Usage + +* Retrieves the value of a Slider. + +```lua +local mainFrame = basalt.createFrame() +local slider = mainFrame:addSlider():setValue(50) +local currentValue = slider:getValue() + +basalt.debug("The current value of the slider is:", currentValue) +``` diff --git a/docs/objects/ChangeableObject/onChange.md b/docs/objects/ChangeableObject/onChange.md new file mode 100644 index 0000000..2979216 --- /dev/null +++ b/docs/objects/ChangeableObject/onChange.md @@ -0,0 +1,33 @@ +## onChange + +### Description + +`onChange(self, event, value)` + +The onChange event is triggered when the value of a ChangeableObject, such as a Slider, is changed by the user. + +### Returns + +1. `object` The object in use + +### Usage + +* Add an onChange event to a Slider: + +```lua +local basalt = require("basalt") + +local main = basalt.createFrame() +local slider = main:addSlider() + :setPosition(3,3) + :setSize(12,3) + :setValue(50) + +function sliderOnChange(self, event, value) + basalt.debug("Slider value changed to", value) +end + +slider:onChange(sliderOnChange) + +basalt.autoUpdate() +``` diff --git a/docs/objects/ChangeableObject/setValue.md b/docs/objects/ChangeableObject/setValue.md new file mode 100644 index 0000000..1f9d9fd --- /dev/null +++ b/docs/objects/ChangeableObject/setValue.md @@ -0,0 +1,22 @@ +## setValue + +### Description + +Sets the value of your object + +### Parameters + +1. `any` new value + +### Returns + +1. `object` The object in use + +### Usage + +* Creates a Slider with a value of 50. + +```lua +local mainFrame = basalt.createFrame() +local slider = mainFrame:addSlider():setValue(50) +``` diff --git a/docs/objects/Checkbox.md b/docs/objects/Checkbox.md index c3862b9..3799940 100644 --- a/docs/objects/Checkbox.md +++ b/docs/objects/Checkbox.md @@ -1,36 +1,34 @@ -With checkboxes the user can set a boolean to true or false by clicking on them. +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. -[Object](objects/Object.md) methods also apply for checkboxes. +In addition to the Object and VisualObject methods, checkboxes also have the following method: | | | |---|---| |[setSymbol](objects/Checkbox/setSymbol.md)|Changes the symbol when checkbox is checked - # Example -This is how you would create a event which gets fired as soon as the value gets changed: +Here's an example of how to create a Checkbox object and attach an event that gets fired when the value changes: + ```lua local main = basalt.createFrame() local aCheckbox = main:addCheckbox() local function checkboxChange(self) - local checked = self:getValue() - basalt.debug("The value got changed into ", checked) + local checked = self:getValue() + basalt.debug("The value got changed into ", checked) end aCheckbox:onChange(checkboxChange) ``` also possible via xml: -```lua -local main = basalt.createFrame():addLayout("example.xml") - -basalt.setVariable("checkboxChange", function(self) - local checked = self:getValue() - basalt.debug("The value got changed into ", checked) -end) -``` ```xml - + + + local checked = self:getValue() + basalt.debug("The value got changed into ", checked) + + ``` +In these examples, a checkbox is created, and when the value changes, a debug message prints the new value of the checkbox. diff --git a/docs/objects/Checkbox/setSymbol.md b/docs/objects/Checkbox/setSymbol.md index 85c8a8c..f41363d 100644 --- a/docs/objects/Checkbox/setSymbol.md +++ b/docs/objects/Checkbox/setSymbol.md @@ -1,18 +1,26 @@ ## setSymbol + +### Description + Changes the checkbox symbol, default is "\42" -#### Parameters: +### Parameters + 1. `string` symbol -#### Returns: +### Returns + 1. `object` The object in use -#### Usage: +### Usage + * Creates a new checkbox and changes the symbol to o + ```lua local main = basalt.createFrame() local checkbox = main:addCheckbox():setSymbol("o") ``` + ```xml -``` \ No newline at end of file +``` diff --git a/docs/objects/Container.md b/docs/objects/Container.md new file mode 100644 index 0000000..804230f --- /dev/null +++ b/docs/objects/Container.md @@ -0,0 +1,17 @@ +Container is the base class for all frame types. It provides the basic structure and functionality for all frame objects. Container objects can contain other container objects, thus forming the foundation for the hierarchy of frame objects. + +In addition to the Object and VisualObject methods, container objects have the following methods: + +| | | +|---|---| +|[addObject](objects/Container/addObject.md)|Adds a new object to the container +|[getObject](objects/Container/getObject.md)|Returns an object in the container by its ID +|[getDeepObject](objects/Container/getDeepObject.md)|Returns an object in the container or its sub-containers by its ID +|[removeObject](objects/Container/removeObject.md)|Removes an object from the container by its ID +|[updateZIndex](objects/Container/updateZIndex.md)|Updates the Z-index of an object in the container +|[setImportant](objects/Container/setImportant.md)|Marks an object as important, so it is displayed on top if needed +|[sortElementOrder](objects/Container/sortElementOrder.md)|Sorts the order of elements in the container based on their Z-indices +|[removeFocusedObject](objects/Container/removeFocusedObject.md)|Removes focus from an object in the container +|[setFocusedObject](objects/Container/setFocusedObject.md)|Sets focus on a specific object in the container + +A Container Object inherits from VisualObject, but won't draw children objects. diff --git a/docs/objects/Container/addObject.md b/docs/objects/Container/addObject.md new file mode 100644 index 0000000..0a1d81e --- /dev/null +++ b/docs/objects/Container/addObject.md @@ -0,0 +1,13 @@ +## addObject + +### Description + +Adds a object to the container + +### Parameters + +1. `object` any object + +### Returns + +1. `object` The object which got added diff --git a/docs/objects/Container/getDeepObject.md b/docs/objects/Container/getDeepObject.md new file mode 100644 index 0000000..c3e1419 --- /dev/null +++ b/docs/objects/Container/getDeepObject.md @@ -0,0 +1,30 @@ +## getDeepObject + +### Description + +Retrieves an object from the container or its descendants by its ID. This method searches recursively through all child containers to find the object. + +### Parameters + +1. `string` id - The ID of the object you want to retrieve. + +### Returns + +1. `object` The object with the specified ID, or nil if no object with that ID is found. + +### Usage + +```lua +local main = basalt.createFrame() +local container = main:addFrame("container") +local button = container:addButton("myButton") + :setPosition(2, 2) + :setText("My Button") +-- Get the button object by its ID, searching through all containers +local retrievedButton = main:getDeepObject("myButton") +if retrievedButton then + basalt.debug("Button found!") +end + +basalt.autoUpdate() +``` diff --git a/docs/objects/Container/getObject.md b/docs/objects/Container/getObject.md new file mode 100644 index 0000000..3b1c590 --- /dev/null +++ b/docs/objects/Container/getObject.md @@ -0,0 +1,30 @@ +## getObject + +### Description + +Retrieves an object from the container by its ID. + +### Parameters + +1. `string` id - The ID of the object you want to retrieve. + +### Returns + +1. `object` The object with the specified ID, or nil if no object with that ID is found. + +### Usage + +```lua +local main = basalt.createFrame() +local button = main:addButton("myButton") + :setPosition(2, 2) + :setText("My Button") + +-- Get the button object by its ID +local retrievedButton = main:getObject("myButton") +if retrievedButton then + basalt.debug("Button found!") +end + +basalt.autoUpdate() +``` diff --git a/docs/objects/Container/removeFocusedObject.md b/docs/objects/Container/removeFocusedObject.md new file mode 100644 index 0000000..057fd49 --- /dev/null +++ b/docs/objects/Container/removeFocusedObject.md @@ -0,0 +1,32 @@ +## removeFocusedObject + +### Description + +Removes the focus from the currently focused object within the container. If no object is focused, this method has no effect. + +### Returns + +1. `object` The object in use + +### Usage + +```lua +local main = basalt.createFrame() +local container = main:addFrame() +local inputField1 = container:addInputField() + :setPosition(2, 2) +local inputField2 = container:addInputField() + :setPosition(2, 4) + +container:setFocusedObject(inputField1) + +main:addButton() + :setPosition(2, 6) + :setText("Remove focus from input fields") + :onClick(function() + container:removeFocusedObject() + basalt.debug("Focus removed from input fields!") + end) + +basalt.autoUpdate() +``` diff --git a/docs/objects/Container/removeObject.md b/docs/objects/Container/removeObject.md new file mode 100644 index 0000000..3ce69a8 --- /dev/null +++ b/docs/objects/Container/removeObject.md @@ -0,0 +1,37 @@ +## removeObject + +### Description + +Removes an object from the container by its ID. If the object is not a direct child of the container, this method will not remove it. + +### Parameters + +1. `string` id - The ID of the object you want to retrieve. + +### Returns + +1. `boolean` true if the object was removed + +### Usage + +```lua +local main = basalt.createFrame() +local container = main:addFrame("container") +local button = container:addButton("removableButton") + :setPosition(2, 2) + :setText("Remove me") + +main:addButton() + :setPosition(2, 4) + :setText("Remove the button above") + :onClick(function() + local removed = container:removeObject("removableButton") + if removed then + basalt.debug("Button removed!") + else + basalt.debug("Button not found!") + end + end) + +basalt.autoUpdate() +``` diff --git a/docs/objects/Container/setFocusedObject.md b/docs/objects/Container/setFocusedObject.md new file mode 100644 index 0000000..7f6d05c --- /dev/null +++ b/docs/objects/Container/setFocusedObject.md @@ -0,0 +1,38 @@ +## setFocusedObject + +### Description + +Sets the focused object within the container. When an object is focused, it will receive keyboard events. Only one object can be focused at a time within a container. + +### Parameters + +1. `object` object - The object to set as the focused object. + +### Returns + +1. `object` The object in use + +### Usage + +```lua +local main = basalt.createFrame() +local container = main:addFrame() +local inputField1 = container:addInput("inputField1") + :setPosition(2, 2) +local inputField2 = container:addInput("inputField2") + :setPosition(2, 4) + +main:addButton() + :setPosition(2, 6) + :setText("Focus on inputField1") + :onClick(function() + local focused = container:setFocusedObject(inputField1) + if focused then + basalt.debug("InputField1 is now focused!") + else + basalt.debug("Failed to set focus on InputField1!") + end + end) + +basalt.autoUpdate() +``` diff --git a/docs/objects/Container/setImportant.md b/docs/objects/Container/setImportant.md new file mode 100644 index 0000000..5c6c3dc --- /dev/null +++ b/docs/objects/Container/setImportant.md @@ -0,0 +1,36 @@ +## setImportant + +### Description + +Sets the specified object as "important" within the container. This means the object will be reordered on the same z-index level, making it more important than other objects on the same level. This can be useful when you want to prioritize event handling or drawing order for specific objects. + +### Parameters + +1. `string` The object to set as important + +### Returns + +1. `object` the object in use + +### Usage + +```lua +local main = basalt.createFrame() +local container = main:addFrame() +local inputField1 = container:addInput() + :setPosition(2, 2) +local inputField2 = container:addInput() + :setPosition(2, 4) + +inputField1:onKey(function(event, key) + basalt.debug("InputField1 received key press: ", key) +end) + +inputField2:onKey(function(event, key) + basalt.debug("InputField2 received key press: ", key) +end) + +container:setImportant(inputField1) + +basalt.autoUpdate() +``` diff --git a/docs/objects/Container/sortElementOrder.md b/docs/objects/Container/sortElementOrder.md new file mode 100644 index 0000000..4cf6280 --- /dev/null +++ b/docs/objects/Container/sortElementOrder.md @@ -0,0 +1,11 @@ +## sortElementOrder + +### Description + +This function is called internally and automatically after objects are added or removed from the container. It sorts all objects by their z-index and the time they were added, ensuring the correct order is maintained. This is essential for proper event handling and drawing order of objects within the container. + +As a user, you don't need to call this function directly, as it's automatically taken care of by the library. + +### Usage + +No direct usage example is provided since this function is called automatically by the library when needed. diff --git a/docs/objects/Container/updateZIndex.md b/docs/objects/Container/updateZIndex.md new file mode 100644 index 0000000..bd24a7a --- /dev/null +++ b/docs/objects/Container/updateZIndex.md @@ -0,0 +1,25 @@ +## setFocusedObject + +### Description + +Updates the z-index of a specified object within the container. This is useful when you need to change the z-index of an object after it has been added to the container. + +### Parameters + +1. `object` The object whose z-index you want to update. +2. `number` The new z-index value for the object. + +### Returns + +1. `object` The object in use + +### Usage + +```lua +local frame = basalt.createFrame() +local button1 = frame:addButton():setZIndex(1) +local button2 = frame:addButton():setZIndex(2) + +-- Update button1's z-index to be above button2 +frame:updateZIndex(button1, 3) +``` diff --git a/docs/objects/Dropdown.md b/docs/objects/Dropdown.md index d8e11c0..80a22fd 100644 --- a/docs/objects/Dropdown.md +++ b/docs/objects/Dropdown.md @@ -1,24 +1,12 @@ -Dropdowns are objects where the user can click on a button, this will open a list where the user can choose from. +Dropdowns are objects where the user can click on a button, which opens a list from which the user can choose an item. -[Object](objects/Object.md) methods also apply for dropdowns. +List Object methods also apply for dropdowns. +In addition to the Object, VisualObject and List methods, Dropdowns also have the following methods: | | | |---|---| -|[addItem](objects/Dropdown/addItem.md)|Adds a new item into the list -|[removeItem](objects/Dropdown/removeItem.md)|Removes a item from the list -|[editItem](objects/Dropdown/editItem.md)|Changes a already existing item in the list -|[getItem](objects/Dropdown/getItem.md)|Returns a item by its index -|[getItemCount](objects/Dropdown/getItemCount.md)|Returns the item count -|[getAll](objects/Dropdown/getAll.md)|Returns the entire list as a table -|[selectItem](objects/Dropdown/selectItem.md)|Selects a item -|[clear](objects/Dropdown/clear.md)|Makes the entire list empty -|[getItemIndex](objects/Dropdown/getItemIndex.md)|Returns the currently active item index -|[setSelectedItem](objects/Dropdown/setSelectedItem.md)|Changes the default bg and fg, when the user selects a item -|[setOffset](objects/Dropdown/setOffset.md)|Changes the list offset -|[getOffset](objects/Dropdown/getOffset.md)|Returns the current offset |[setDropdownSize](objects/Dropdown/setDropdownSize.md)|Changes the dropdown size - A item-table in dropdowns looks like the following example: ```lua @@ -28,4 +16,33 @@ item = { fgCol=colors.white -- the foreground color args = {} -- custom args you want to pass, which you will be able to access in for example onChange events } -``` \ No newline at end of file +``` + +Here's an example of how to create a fully functional dropdown using the Dropdown object: + +Lua: + +```lua +local main = basalt.createFrame() +local aDropdown = main:addDropdown() +aDropdown:addItem("Item 1") +aDropdown:addItem("Item 2", colors.yellow) +aDropdown:addItem("Item 3", colors.yellow, colors.green) + +aDropdown:onChange(function(self, item) + basalt.debug("Selected item: ", item.text) +end) +``` + +XML: + +```xml + + Item 1 + Item 2yellow + Item 3yellowgreen + + basalt.debug("Selected item: ", item.text) + + +``` diff --git a/docs/objects/Dropdown/setDropdownSize.md b/docs/objects/Dropdown/setDropdownSize.md index 59f5984..4973f64 100644 --- a/docs/objects/Dropdown/setDropdownSize.md +++ b/docs/objects/Dropdown/setDropdownSize.md @@ -1,26 +1,23 @@ ## setDropdownSize -Sets the size of the opened dropdown -#### Parameters: -1. `number` The width value -2. `number` The height value +### Description + +Sets the width and height of the dropdown menu for a Dropdown object. + +### Parameters + +1. `width` + +2. `height` + +### Returns -#### Returns: 1. `object` The object in use -#### Usage: -* Creates a default dropdown, adds 3 entries and sets the dropdown size to 15w, 8h +#### Usage + ```lua -local mainFrame = basalt.createFrame() -local aDropdown = mainFrame:addDropdown():setDropdownSize(15,8) -aDropdown:addItem("1. Entry") -aDropdown:addItem("2. Entry") -aDropdown:addItem("3. Entry") +local main = basalt.createFrame() +local aDropdown = main:addDropdown() +aDropdown:setDropdownSize(10, 5) ``` -```xml - - 1. Entry - 2. Entry - 3. Entry - -``` \ No newline at end of file diff --git a/docs/objects/Flexbox.md b/docs/objects/Flexbox.md new file mode 100644 index 0000000..81c2991 --- /dev/null +++ b/docs/objects/Flexbox.md @@ -0,0 +1,12 @@ +A Flexbox is a layout container that is designed to make it easier to create flexible and responsive UI designs. It allows you to arrange and align its children (elements) within it in a more efficient way. + +In addition to the methods inherited from Frame, Container, VisualObject and Object, Flexbox has the following methods: + +| | | +|---|---| +|[setDirection](objects/BaseFrame/getOffset.md)|Sets the direction in which the children will be placed +|[getDirection](objects/BaseFrame/getOffset.md)|Returns the direction +|[setSpacing](objects/BaseFrame/setOffset.md)|Sets the space between objects +|[getSpacing](objects/BaseFrame/setOffset.md)|Returns the space +|[setJuustifyContent](objects/BaseFrame/getOffset.md)|Determines how the children are aligned along the main axis +|[getJuustifyContent](objects/BaseFrame/getOffset.md)|Returns the justify content diff --git a/docs/objects/Frame.md b/docs/objects/Frame.md index ef93d05..f5a5ea1 100644 --- a/docs/objects/Frame.md +++ b/docs/objects/Frame.md @@ -1,334 +1,8 @@ -Frames are like groups or windows. You can add objects on them and if you move the frame, all its children objects will also be moved. Frames also have -some special functionality to create very advanced programs. +Frame is a subclass of the Container class and inherits from VisualObject and Object classes. Frame objects are used for grouping and organizing other objects within a parent object, providing structure to your interface. The main difference between Frame and BaseFrame is that Frame must always have a parent. -[Object](objects/Object.md) methods also apply for frames. +In addition to the methods inherited from Container, VisualObject and Object, Frame has the following methods: | | | |---|---| -|[addObject](objects/Frame/addObject.md)|Adds a new object -|[setBar](objects/Frame/setBar.md)|Sets the top bar text and colors - deprecated -|[setBarTextAlign](objects/Frame/setBarTextAlign.md)|Sets the top bars text align - deprecated -|[showBar](objects/Frame/showBar.md)|Shows the top bar - deprecated -|[setMonitor](objects/Frame/setMonitor.md)|Sets the frame to be a monitor frame (only for base frames) -|[setMonitorScale](objects/Frame/setMonitorScale.md)|Sets the monitor scale (same as monitor.setTextScale) -|[setMirror](objects/Frame/setMirror.md)|Sets the frame to mirror onto a monitor (only for base frames) -|[getObject](objects/Frame/getObject.md)|Returns the object by its name (or id) -|[removeObject](objects/Frame/removeObject.md)|Removes the object by its name (or id) -|[setFocusedObject](objects/Frame/setFocusedObject.md)|Sets the currently focused object by this frame -|[removeFocusedObject](objects/Frame/removeFocusedObject.md)|Removes the currenlty focused object (it only removes beeing focused) -|[getFocusedObject](objects/Frame/getFocusedObject.md)|Returns the currently focused object -|[setMovable](objects/Frame/setMovable.md)|Makes the frame movable (only for sub frames) -|[setOffset](objects/Frame/setOffset.md)|Sets the frames offset (will be added to the childrens x and y positions) -|[getOffset](objects/Frame/getOffset.md)|Returns the current x and y offset -|[addLayout](objects/Frame/addLayout.md)|Adds a new XML Layout into the frame -|[addLayoutFromString](objects/Frame/addLayoutFromString.md)|Adds a new XML Layout via string into the frame -|[getLastLayout](objects/Frame/getLastLayout.md)|Returns a table of all objects generated by the last addLayout/FromString method -|[setTheme](objects/Frame/setTheme.md)|Sets the theme of that frame and all its childrens -|[setScrollable](objects/Frame/setScrollable.md)|Makes the frame scrollable via mousewheel (internally this uses setOffset) -|[setScrollAmount](objects/Frame/setScrollAmount.md)|Sets how far the user is allowed to scroll - -This is how you would implement frames via xml: - -```xml - - -