From f10413dddb5dc39c1230e4a195a0dcce58b9e13a Mon Sep 17 00:00:00 2001 From: Robert Jelic <36573031+NoryiE@users.noreply.github.com> Date: Tue, 2 Sep 2025 12:24:30 +0200 Subject: [PATCH] Added basalt.onEvent(event, callback) Added basalt.removeEvent(eventcallback) basalt.triggerEvent(event, ...) Fixed a event is nil error in Container.lua --- .gitignore | 4 ++- src/elements/Container.lua | 2 +- src/main.lua | 58 ++++++++++++++++++++++++++++++++++++++ src/plugins/animation.lua | 33 ++++++++++++++++++++++ tools/generate-docs.lua | 49 ++++++++++++++++++++++++-------- 5 files changed, 132 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 453075a..496e19c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ testWorkflows todo.txt Flexbox2.lua markdown2.lua -BasaltDoc \ No newline at end of file +BasaltDoc +generate-docs.lua +io.lua \ No newline at end of file diff --git a/src/elements/Container.lua b/src/elements/Container.lua index b1cf064..9eef46c 100644 --- a/src/elements/Container.lua +++ b/src/elements/Container.lua @@ -347,7 +347,7 @@ end local function convertMousePosition(self, event, ...) local args = {...} - if event:find("mouse_") then + if event and event:find("mouse_") then local button, absX, absY = ... local xOffset, yOffset = self.get("offsetX"), self.get("offsetY") local relX, relY = self:getRelativePosition(absX + xOffset, absY + yOffset) diff --git a/src/main.lua b/src/main.lua index 6e4cb45..ebcaea1 100644 --- a/src/main.lua +++ b/src/main.lua @@ -374,4 +374,62 @@ function basalt.getAPI(name) return elementManager.getAPI(name) end +--- Registers a callback function for a specific event +--- @shortDescription Registers an event callback +--- @param eventName string The name of the event to listen for (e.g. "mouse_click", "key", "timer") +--- @param callback function The callback function to execute when the event occurs +--- @usage basalt.onEvent("mouse_click", function(button, x, y) basalt.debug("Clicked at", x, y) end) +function basalt.onEvent(eventName, callback) + expect(1, eventName, "string") + expect(2, callback, "function") + + if not basalt._events[eventName] then + basalt._events[eventName] = {} + end + + table.insert(basalt._events[eventName], callback) +end + +--- Removes a callback function for a specific event +--- @shortDescription Removes an event callback +--- @param eventName string The name of the event +--- @param callback function The callback function to remove +--- @return boolean success Whether the callback was found and removed +function basalt.removeEvent(eventName, callback) + expect(1, eventName, "string") + expect(2, callback, "function") + + if not basalt._events[eventName] then + return false + end + + for i, registeredCallback in ipairs(basalt._events[eventName]) do + if registeredCallback == callback then + table.remove(basalt._events[eventName], i) + return true + end + end + + return false +end + +--- Triggers a custom event and calls all registered callbacks +--- @shortDescription Triggers a custom event +--- @param eventName string The name of the event to trigger +--- @vararg any Arguments to pass to the event callbacks +--- @usage basalt.triggerEvent("custom_event", "data1", "data2") +function basalt.triggerEvent(eventName, ...) + expect(1, eventName, "string") + + if basalt._events[eventName] then + for _, callback in ipairs(basalt._events[eventName]) do + local ok, err = pcall(callback, ...) + if not ok then + errorManager.header = "Basalt Event Callback Error" + errorManager.error("Error in event callback for '" .. eventName .. "': " .. tostring(err)) + end + end + end +end + return basalt \ No newline at end of file diff --git a/src/plugins/animation.lua b/src/plugins/animation.lua index 3030d25..c29039a 100644 --- a/src/plugins/animation.lua +++ b/src/plugins/animation.lua @@ -270,6 +270,27 @@ function Animation:event(event, timerId) end end +--- Stops the animation immediately: cancels timers, completes running anim instances and clears the element property +--- @shortDescription Stops the animation +function Animation:stop() + if self.timer then + pcall(os.cancelTimer, self.timer) + self.timer = nil + end + + for _, seq in ipairs(self.sequences) do + for _, anim in ipairs(seq) do + pcall(function() + if anim and anim.complete then anim:complete() end + end) + end + end + + if self.element and type(self.element.set) == "function" then + pcall(function() self.element.set("animation", nil) end) + end +end + Animation.registerAnimation("move", { start = function(anim) anim.startX = anim.element.get("x") @@ -519,6 +540,18 @@ function VisualElement.setup(element) element.defineEvent(element, "timer") end +-- Convenience to stop animations from the element +function VisualElement.stopAnimation(self) + local anim = self.get("animation") + if anim and type(anim.stop) == "function" then + anim:stop() + else + -- fallback: clear property + self.set("animation", nil) + end + return self +end + --- Creates a new Animation Object --- @shortDescription Creates a new animation --- @return Animation animation The new animation diff --git a/tools/generate-docs.lua b/tools/generate-docs.lua index a25d36b..b9c0979 100644 --- a/tools/generate-docs.lua +++ b/tools/generate-docs.lua @@ -1,24 +1,49 @@ -local markdown = require("tools/markdown") -local function ensureDirectory(path) - local dir = path:match("(.*)/[^/]*$") - if dir then - os.execute('mkdir -p "' .. dir .. '"') +local oldPath = package.path + +local scriptSource = debug.getinfo(1, "S").source +local scriptDir = nil +if scriptSource and scriptSource:sub(1,1) == "@" then + local scriptPath = scriptSource:sub(2) + scriptDir = scriptPath:match("^(.*)[/\\]") or "." +else + scriptDir = "." +end + +local parserSrc = scriptDir .. "/BasaltDoc/ldoc-markdown-parser/src/" +package.path = package.path .. ";" .. parserSrc .. "?.lua;" .. parserSrc .. "?/init.lua" +local ok, parser = pcall(require, "parser.init") +local ioAdaptor = require("tools.io") +package.path = oldPath + +if not ok or not parser then + -- try dofile fallback + local initPath = parserSrc .. "/parser/init.lua" + local ok2, module = pcall(dofile, initPath) + if ok2 and module then + parser = module + else + error("Failed to load parser.init via require and dofile (tried: "..tostring(initPath)..")") end end local function processFile(inputFile) - local parsed = markdown.parseFile(inputFile) - local md = markdown.makeMarkdown(parsed) + local content = ioAdaptor.readFile(inputFile) + if not content then + io.stderr:write("Failed to read: " .. tostring(inputFile) .. "\n") + return + end + + local commentBlocks = parser.extractComments(content) + local md = parser.generateMarkdown(commentBlocks) local outputFile = "build_docs/docs/references/" .. inputFile:match("^src/(.+)"):gsub("%.lua$", "") - - ensureDirectory(outputFile) - - markdown.saveToFile(outputFile, md) + ioAdaptor.ensureDirectory(outputFile) + ioAdaptor.writeFile(outputFile .. ".md", md) end -for file in io.popen('find "src" -type f -name "*.lua"'):lines() do +local files = ioAdaptor.listFiles("src", "*.lua") +for _, file in ipairs(files) do if not file:match("LuaLS.lua$") then processFile(file) end