Updated Eventsystem
Improved List with multiple Selections
This commit is contained in:
131
install.lua
131
install.lua
@@ -133,6 +133,10 @@ versionDropdown:onSelect(function(self, index, value)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
instalScreen:addLabel(coloring)
|
||||||
|
:setText("Path:")
|
||||||
|
:setPosition(2, "{versionDesc.y + versionDesc.height + 1}")
|
||||||
|
|
||||||
installScreen:addLabel(coloring)
|
installScreen:addLabel(coloring)
|
||||||
:setText("Additional Components:")
|
:setText("Additional Components:")
|
||||||
:setPosition(2, "{versionDesc.y + versionDesc.height + 1}")
|
:setPosition(2, "{versionDesc.y + versionDesc.height + 1}")
|
||||||
@@ -147,21 +151,134 @@ local luaLSCheckbox = installScreen:addCheckbox()
|
|||||||
-- Screen 3: Elements
|
-- Screen 3: Elements
|
||||||
local elementsScreen = createScreen(3)
|
local elementsScreen = createScreen(3)
|
||||||
elementsScreen:addLabel(coloring)
|
elementsScreen:addLabel(coloring)
|
||||||
:setText("Elements:")
|
:setText("Elements: (white = selected)")
|
||||||
:setPosition(2, 2)
|
:setPosition(2, 2)
|
||||||
|
|
||||||
local elementsList = elementsScreen:addList()
|
local elementsList = elementsScreen:addList("elementsList")
|
||||||
|
:setMultiSelection(true)
|
||||||
|
:setSelectedBackground(colors.lightGray)
|
||||||
|
:setForeground(colors.gray)
|
||||||
:setPosition(2, 4)
|
:setPosition(2, 4)
|
||||||
:setSize("{parent.width - 2}", "{parent.height - 6}")
|
:setSize("{parent.width - 30}", 8)
|
||||||
|
|
||||||
|
local elementDesc = elementsScreen:addLabel("elementDesc")
|
||||||
|
:setAutoSize(false)
|
||||||
|
:setWidth("{parent.width - (elementsList.x + elementsList.width) - 2}")
|
||||||
|
:setText("Select an element to see its description.")
|
||||||
|
:setPosition("{elementsList.x + elementsList.width + 1}", 4)
|
||||||
|
:setSize(28, 8)
|
||||||
|
:setBackground(colors.lightGray)
|
||||||
|
|
||||||
|
local eleScreenDesc = elementsScreen:addLabel()
|
||||||
|
:setAutoSize(false)
|
||||||
|
:setWidth("{parent.width - 2}")
|
||||||
|
:setText("This screen allows you to select which elements you want to install. You can select multiple elements.")
|
||||||
|
:setPosition(2, "{math.max(elementsList.y + elementsList.height, elementDesc.y + elementDesc.height) + 1}")
|
||||||
|
:setBackground(colors.lightGray)
|
||||||
|
|
||||||
local function addElements()
|
local function addElements()
|
||||||
elementsList:clear()
|
elementsList:clear()
|
||||||
for k,v in pairs(getConfig().files)do
|
for k,v in pairs(getConfig().categories.elements.files)do
|
||||||
if(k:match("src/elements/"))then
|
elementsList:addItem({selected=true, text=v.name, callback=function() elementDesc:setText(v.description) end})
|
||||||
elementsList:addItem(v.name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
addElements()
|
addElements()
|
||||||
|
|
||||||
|
-- Screen 4 Plugins
|
||||||
|
local pluginScreen = createScreen(4)
|
||||||
|
pluginScreen:addLabel(coloring)
|
||||||
|
:setText("Plugins: (white = selected)")
|
||||||
|
:setPosition(2, 2)
|
||||||
|
|
||||||
|
local pluginList = pluginScreen:addList("pluginList")
|
||||||
|
:setMultiSelection(true)
|
||||||
|
:setSelectedBackground(colors.lightGray)
|
||||||
|
:setForeground(colors.gray)
|
||||||
|
:setPosition(2, 4)
|
||||||
|
:setSize("{parent.width - 30}", 8)
|
||||||
|
|
||||||
|
local pluginDesc = pluginScreen:addLabel("pluginDesc")
|
||||||
|
:setAutoSize(false)
|
||||||
|
:setWidth("{parent.width - (pluginList.x + pluginList.width) - 2}")
|
||||||
|
:setText("Select a plugin to see its description.")
|
||||||
|
:setPosition("{pluginList.x + pluginList.width + 1}", 4)
|
||||||
|
:setSize(28, 8)
|
||||||
|
:setBackground(colors.lightGray)
|
||||||
|
|
||||||
|
local pluScreenDesc = pluginScreen:addLabel()
|
||||||
|
:setAutoSize(false)
|
||||||
|
:setWidth("{parent.width - 2}")
|
||||||
|
:setText("This screen allows you to select which plugins you want to install. You can select multiple plugins.")
|
||||||
|
:setPosition(2, "{math.max(pluginList.y + pluginList.height, pluginDesc.y + pluginDesc.height) + 1}")
|
||||||
|
:setBackground(colors.lightGray)
|
||||||
|
|
||||||
|
local function addPlugins()
|
||||||
|
pluginList:clear()
|
||||||
|
for k,v in pairs(getConfig().categories.plugins.files)do
|
||||||
|
pluginList:addItem({selected = true, text= v.name, callback=function() pluginDesc:setText(v.description) end})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
addPlugins()
|
||||||
|
|
||||||
|
-- Screen 5 Installation Progress
|
||||||
|
local progressScreen = createScreen(5)
|
||||||
|
local progressBar = progressScreen:addProgressBar()
|
||||||
|
:setPosition(2, "{parent.height - 2}")
|
||||||
|
:setSize("{parent.width - 12}", 2)
|
||||||
|
|
||||||
|
local log = progressScreen:addList("log")
|
||||||
|
:setPosition(2, 2)
|
||||||
|
:setSize("{parent.width - 2}", "{parent.height - 6}")
|
||||||
|
:addItem("Starting installation...")
|
||||||
|
|
||||||
|
local function install()
|
||||||
|
local function logMessage(message)
|
||||||
|
log:addItem(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function downloadFile(url, path)
|
||||||
|
logMessage("Downloading " .. url .. "...")
|
||||||
|
local request = http.get(url)
|
||||||
|
if request then
|
||||||
|
local file = fs.open(path, "w")
|
||||||
|
file.write(request.readAll())
|
||||||
|
file.close()
|
||||||
|
request.close()
|
||||||
|
logMessage("Downloaded " .. url .. " to " .. path)
|
||||||
|
else
|
||||||
|
error("Failed to download " .. url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function installElement(name, url)
|
||||||
|
logMessage("Installing element: " .. name)
|
||||||
|
--downloadFile(url, "/path/to/install/" .. name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function installPlugin(name, url)
|
||||||
|
logMessage("Installing plugin: " .. name)
|
||||||
|
--downloadFile(url, "/path/to/install/" .. name)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, element in ipairs(elementsList:getSelectedItems()) do
|
||||||
|
local item = element.item
|
||||||
|
basalt.LOGGER.debug(item.text)
|
||||||
|
installElement(item.text, getConfig().categories.elements.files[item.text].url)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, plugin in ipairs(pluginList:getSelectedItems()) do
|
||||||
|
local item = plugin.item
|
||||||
|
installPlugin(item.text, getConfig().categories.plugins.files[item.text].url)
|
||||||
|
end
|
||||||
|
|
||||||
|
progressBar:setProgress(100)
|
||||||
|
logMessage("Installation complete!")
|
||||||
|
end
|
||||||
|
|
||||||
|
local installButton = progressScreen:addButton()
|
||||||
|
:setText("Install")
|
||||||
|
:setPosition("{parent.width - 9}", "{parent.height - 1}")
|
||||||
|
:setSize(9, 1)
|
||||||
|
:onMouseClick(install)
|
||||||
|
|
||||||
basalt.run()
|
basalt.run()
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
local PropertySystem = require("propertySystem")
|
local PropertySystem = require("propertySystem")
|
||||||
local uuid = require("libraries/utils").uuid
|
local uuid = require("libraries/utils").uuid
|
||||||
|
---@configDescription The base class for all UI elements in Basalt
|
||||||
|
---@configDefault true
|
||||||
|
|
||||||
--- The base class for all UI elements in Basalt
|
--- The base class for all UI elements in Basalt
|
||||||
--- @class BaseElement : PropertySystem
|
--- @class BaseElement : PropertySystem
|
||||||
@@ -27,20 +29,37 @@ BaseElement.defineProperty(BaseElement, "id", {default = "", type = "string", re
|
|||||||
--- @property name string BaseElement The name of the element
|
--- @property name string BaseElement The name of the element
|
||||||
BaseElement.defineProperty(BaseElement, "name", {default = "", type = "string"})
|
BaseElement.defineProperty(BaseElement, "name", {default = "", type = "string"})
|
||||||
|
|
||||||
--- @property eventCallbacks table {} Table containing all registered event callbacks
|
--- @property eventCallbacks table BaseElement The event callbacks for the element
|
||||||
BaseElement.defineProperty(BaseElement, "eventCallbacks", {default = {}, type = "table"})
|
BaseElement.defineProperty(BaseElement, "eventCallbacks", {default = {}, type = "table"})
|
||||||
|
|
||||||
--- Registers an event that this class can listen to
|
|
||||||
--- @shortDescription Registers an event that this class can listen to
|
function BaseElement.defineEvent(class, eventName, requiredEvent)
|
||||||
--- @param class table The class to add the event to
|
-- Events auf Klassenebene speichern, wie bei Properties
|
||||||
--- @param eventName string The name of the event to register
|
if not rawget(class, '_eventConfigs') then
|
||||||
--- @param event? string The event to handle
|
class._eventConfigs = {}
|
||||||
--- @usage BaseElement.listenTo(MyClass, "mouse_click")
|
end
|
||||||
function BaseElement.listenTo(class, eventName, event)
|
|
||||||
if not class._events then
|
class._eventConfigs[eventName] = {
|
||||||
class._events = {}
|
requires = requiredEvent and requiredEvent or eventName
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function BaseElement.registerEventCallback(class, callbackName, ...)
|
||||||
|
local methodName = callbackName:match("^on") and callbackName or "on"..callbackName
|
||||||
|
local events = {...} -- Alle Events als varargs
|
||||||
|
local mainEvent = events[1] -- Erstes Event ist immer das Haupt-Event
|
||||||
|
|
||||||
|
class[methodName] = function(self, ...)
|
||||||
|
-- Alle Events aktivieren
|
||||||
|
for _, sysEvent in ipairs(events) do
|
||||||
|
if not self._registeredEvents[sysEvent] then
|
||||||
|
self:listenEvent(sysEvent, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Callback für das Haupt-Event registrieren
|
||||||
|
self:registerCallback(mainEvent, ...)
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
class._events[eventName] = {enabled=true, name=eventName, event=event}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a new BaseElement instance
|
--- Creates a new BaseElement instance
|
||||||
@@ -64,18 +83,37 @@ function BaseElement:init(props, basalt)
|
|||||||
self._values.id = uuid()
|
self._values.id = uuid()
|
||||||
self.basalt = basalt
|
self.basalt = basalt
|
||||||
self._registeredEvents = {}
|
self._registeredEvents = {}
|
||||||
if BaseElement._events then
|
|
||||||
for key,event in pairs(BaseElement._events) do
|
local currentClass = getmetatable(self).__index
|
||||||
self._registeredEvents[event.event or event.name] = true
|
|
||||||
local handlerName = "on" .. event.name:gsub("_(%l)", function(c)
|
-- Events Sammeln
|
||||||
return c:upper()
|
local events = {}
|
||||||
end):gsub("^%l", string.upper)
|
currentClass = self
|
||||||
self[handlerName] = function(self, ...)
|
|
||||||
self:registerCallback(event.name, ...)
|
while currentClass do
|
||||||
|
if type(currentClass) == "table" and currentClass._eventConfigs then
|
||||||
|
for eventName, config in pairs(currentClass._eventConfigs) do
|
||||||
|
if not events[eventName] then
|
||||||
|
events[eventName] = config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
currentClass = getmetatable(currentClass) and getmetatable(currentClass).__index
|
||||||
|
end
|
||||||
|
|
||||||
|
for eventName, config in pairs(events) do
|
||||||
|
self._registeredEvents[config.requires] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if self._callbacks then
|
||||||
|
for eventName, methodName in pairs(self._callbacks) do
|
||||||
|
self[methodName] = function(self, ...)
|
||||||
|
self:registerCallback(eventName, ...)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -155,8 +193,8 @@ end
|
|||||||
--- @return table self The BaseElement instance
|
--- @return table self The BaseElement instance
|
||||||
--- @usage element:fireEvent("mouse_click", 1, 2)
|
--- @usage element:fireEvent("mouse_click", 1, 2)
|
||||||
function BaseElement:fireEvent(event, ...)
|
function BaseElement:fireEvent(event, ...)
|
||||||
if self._values.eventCallbacks[event] then
|
if self.get("eventCallbacks")[event] then
|
||||||
for _, callback in ipairs(self._values.eventCallbacks[event]) do
|
for _, callback in ipairs(self.get("eventCallbacks")[event]) do
|
||||||
local result = callback(self, ...)
|
local result = callback(self, ...)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ local elementManager = require("elementManager")
|
|||||||
local Container = elementManager.getElement("Container")
|
local Container = elementManager.getElement("Container")
|
||||||
local Render = require("render")
|
local Render = require("render")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- This is the base frame class. It is the root element of all elements and the only element without a parent.
|
--- This is the base frame class. It is the root element of all elements and the only element without a parent.
|
||||||
---@class BaseFrame : Container
|
---@class BaseFrame : Container
|
||||||
---@field _render Render The render object
|
---@field _render Render The render object
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ local elementManager = require("elementManager")
|
|||||||
local VisualElement = elementManager.getElement("VisualElement")
|
local VisualElement = elementManager.getElement("VisualElement")
|
||||||
local getCenteredPosition = require("libraries/utils").getCenteredPosition
|
local getCenteredPosition = require("libraries/utils").getCenteredPosition
|
||||||
|
|
||||||
|
--- This is the button class. It is a visual element that can be clicked.
|
||||||
---@class Button : VisualElement
|
---@class Button : VisualElement
|
||||||
|
---@configDescription Standard button element with click handling and state management
|
||||||
local Button = setmetatable({}, VisualElement)
|
local Button = setmetatable({}, VisualElement)
|
||||||
Button.__index = Button
|
Button.__index = Button
|
||||||
|
|
||||||
@@ -10,25 +12,35 @@ Button.__index = Button
|
|||||||
Button.defineProperty(Button, "text", {default = "Button", type = "string", canTriggerRender = true})
|
Button.defineProperty(Button, "text", {default = "Button", type = "string", canTriggerRender = true})
|
||||||
|
|
||||||
---@event mouse_click The event that is triggered when the button is clicked
|
---@event mouse_click The event that is triggered when the button is clicked
|
||||||
Button.listenTo(Button, "mouse_click")
|
Button.defineEvent(Button, "mouse_click")
|
||||||
|
Button.defineEvent(Button, "mouse_up")
|
||||||
|
|
||||||
function Button.new(props, basalt)
|
--- Creates a new Button instance
|
||||||
|
--- @shortDescription Creates a new Button instance
|
||||||
|
--- @return table self The created instance
|
||||||
|
function Button.new()
|
||||||
local self = setmetatable({}, Button):__init()
|
local self = setmetatable({}, Button):__init()
|
||||||
self:init(props, basalt)
|
|
||||||
self.set("width", 10)
|
self.set("width", 10)
|
||||||
self.set("height", 3)
|
self.set("height", 3)
|
||||||
self.set("z", 5)
|
self.set("z", 5)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Initializes the Button instance
|
||||||
|
--- @shortDescription Initializes the Button instance
|
||||||
|
--- @param props table The properties to initialize the element with
|
||||||
|
--- @param basalt table The basalt instance
|
||||||
function Button:init(props, basalt)
|
function Button:init(props, basalt)
|
||||||
VisualElement.init(self, props, basalt)
|
VisualElement.init(self, props, basalt)
|
||||||
self.set("type", "Button")
|
self.set("type", "Button")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Renders the Button
|
||||||
|
--- @shortDescription Renders the Button
|
||||||
function Button:render()
|
function Button:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local text = self.get("text")
|
local text = self.get("text")
|
||||||
|
text = text:sub(1, self.get("width"))
|
||||||
local xO, yO = getCenteredPosition(text, self.get("width"), self.get("height"))
|
local xO, yO = getCenteredPosition(text, self.get("width"), self.get("height"))
|
||||||
self:textFg(xO, yO, text, self.get("foreground"))
|
self:textFg(xO, yO, text, self.get("foreground"))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ end})
|
|||||||
---@property autoSize boolean true Whether to automatically size the checkbox
|
---@property autoSize boolean true Whether to automatically size the checkbox
|
||||||
Checkbox.defineProperty(Checkbox, "autoSize", {default = true, type = "boolean"})
|
Checkbox.defineProperty(Checkbox, "autoSize", {default = true, type = "boolean"})
|
||||||
|
|
||||||
Checkbox.listenTo(Checkbox, "mouse_click")
|
Checkbox.defineEvent(Checkbox, "mouse_click")
|
||||||
|
|
||||||
--- Creates a new Checkbox instance
|
--- Creates a new Checkbox instance
|
||||||
--- @shortDescription Creates a new Checkbox instance
|
--- @shortDescription Creates a new Checkbox instance
|
||||||
|
|||||||
@@ -418,14 +418,15 @@ function Container:mouse_drag(button, x, y)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Container:mouse_scroll(direction, x, y)
|
function Container:mouse_scroll(direction, x, y)
|
||||||
if VisualElement.mouse_scroll(self, direction, x, y) then
|
local args = convertMousePosition(self, "mouse_scroll", direction, x, y)
|
||||||
local args = convertMousePosition(self, "mouse_scroll", direction, x, y)
|
local success, child = self:callChildrenEvents(true, "mouse_scroll", table.unpack(args))
|
||||||
local success, child = self:callChildrenEvents(true, "mouse_scroll", table.unpack(args))
|
if(success)then
|
||||||
if(success)then
|
return true
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
if(VisualElement.mouse_scroll(self, direction, x, y))then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Handles key events
|
--- Handles key events
|
||||||
@@ -504,6 +505,27 @@ function Container:textFg(x, y, text, fg)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Draws a line of text and bg as color, it is usually used in the render loop
|
||||||
|
--- @shortDescription Draws a line of text and bg as color
|
||||||
|
--- @param x number The x position to draw the text
|
||||||
|
--- @param y number The y position to draw the text
|
||||||
|
--- @param text string The text to draw
|
||||||
|
--- @param bg color The background color of the text
|
||||||
|
--- @return Container self The container instance
|
||||||
|
function Container:textBg(x, y, text, bg)
|
||||||
|
local w, h = self.get("width"), self.get("height")
|
||||||
|
|
||||||
|
if y < 1 or y > h then return self end
|
||||||
|
|
||||||
|
local textStart = x < 1 and (2 - x) or 1
|
||||||
|
local textLen = math.min(#text - textStart + 1, w - math.max(1, x) + 1)
|
||||||
|
|
||||||
|
if textLen <= 0 then return self end
|
||||||
|
|
||||||
|
VisualElement.textBg(self, math.max(1, x), math.max(1, y), text:sub(textStart, textStart + textLen - 1), bg)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Draws a line of text and fg and bg as colors, it is usually used in the render loop
|
--- Draws a line of text and fg and bg as colors, it is usually used in the render loop
|
||||||
--- @shortDescription Draws a line of text and fg and bg as colors
|
--- @shortDescription Draws a line of text and fg and bg as colors
|
||||||
--- @param x number The x position to draw the text
|
--- @param x number The x position to draw the text
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ local VisualElement = require("elements/VisualElement")
|
|||||||
local List = require("elements/List")
|
local List = require("elements/List")
|
||||||
local tHex = require("libraries/colorHex")
|
local tHex = require("libraries/colorHex")
|
||||||
|
|
||||||
|
---@configDescription A dropdown menu that shows a list of selectable items
|
||||||
|
---@configDefault false
|
||||||
|
|
||||||
--- This is the dropdown class. It is a visual element that can show a list of selectable items in a dropdown menu.
|
--- This is the dropdown class. It is a visual element that can show a list of selectable items in a dropdown menu.
|
||||||
---@class Dropdown : List
|
---@class Dropdown : List
|
||||||
|
|
||||||
local Dropdown = setmetatable({}, List)
|
local Dropdown = setmetatable({}, List)
|
||||||
Dropdown.__index = Dropdown
|
Dropdown.__index = Dropdown
|
||||||
|
|
||||||
@@ -59,26 +63,12 @@ function Dropdown:mouse_click(button, x, y)
|
|||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
elseif self.get("isOpen") and relY > 1 then
|
elseif self.get("isOpen") and relY > 1 then
|
||||||
local index = relY - 1 + self.get("offset")
|
-- Nutze List's mouse_click für Item-Selektion
|
||||||
local items = self.get("items")
|
List.mouse_click(self, button, x, y)
|
||||||
|
-- Nach Selektion Dropdown schließen
|
||||||
if index <= #items then
|
self.set("isOpen", false)
|
||||||
local item = items[index]
|
self.set("height", 1)
|
||||||
if type(item) == "table" and item.separator then
|
return true
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
self.set("selectedIndex", index)
|
|
||||||
self.set("isOpen", false)
|
|
||||||
self.set("height", 1)
|
|
||||||
|
|
||||||
if type(item) == "table" and item.callback then
|
|
||||||
item.callback(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
self:fireEvent("select", index, item)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -88,52 +78,31 @@ end
|
|||||||
function Dropdown:render()
|
function Dropdown:render()
|
||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
|
|
||||||
|
-- Header rendern
|
||||||
local text = self.get("selectedText")
|
local text = self.get("selectedText")
|
||||||
if #text == 0 and self.get("selectedIndex") > 0 then
|
if #text == 0 then
|
||||||
local item = self.get("items")[self.get("selectedIndex")]
|
-- Suche nach selektiertem Item
|
||||||
text = type(item) == "table" and item.text or tostring(item)
|
local selectedItems = self:getSelectedItems()
|
||||||
|
if #selectedItems > 0 then
|
||||||
|
local selectedItem = selectedItems[1].item
|
||||||
|
text = selectedItem.text or ""
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Header mit Dropdown Symbol
|
||||||
self:blit(1, 1, text .. string.rep(" ", self.get("width") - #text - 1) .. (self.get("isOpen") and "\31" or "\17"),
|
self:blit(1, 1, text .. string.rep(" ", self.get("width") - #text - 1) .. (self.get("isOpen") and "\31" or "\17"),
|
||||||
string.rep(tHex[self.get("foreground")], self.get("width")),
|
string.rep(tHex[self.get("foreground")], self.get("width")),
|
||||||
string.rep(tHex[self.get("background")], self.get("width")))
|
string.rep(tHex[self.get("background")], self.get("width")))
|
||||||
|
|
||||||
|
-- Liste rendern wenn offen
|
||||||
if self.get("isOpen") then
|
if self.get("isOpen") then
|
||||||
local items = self.get("items")
|
-- Offset um 1 verschieben wegen Header
|
||||||
local offset = self.get("offset")
|
local oldOffset = self.get("offset")
|
||||||
local selected = self.get("selectedIndex")
|
self.set("offset", oldOffset + 1)
|
||||||
local width = self.get("width")
|
-- Liste ab Zeile 2 rendern
|
||||||
|
List.render(self)
|
||||||
for i = 2, self.get("height") do
|
-- Offset zurücksetzen
|
||||||
local itemIndex = i - 1 + offset
|
self.set("offset", oldOffset)
|
||||||
local item = items[itemIndex]
|
|
||||||
|
|
||||||
if item then
|
|
||||||
if type(item) == "table" and item.separator then
|
|
||||||
local separatorChar = (item.text or "-"):sub(1,1)
|
|
||||||
local separatorText = string.rep(separatorChar, width)
|
|
||||||
local fg = item.foreground or self.get("foreground")
|
|
||||||
local bg = item.background or self.get("background")
|
|
||||||
|
|
||||||
self:textBg(1, i, string.rep(" ", width), bg)
|
|
||||||
self:textFg(1, i, separatorText, fg)
|
|
||||||
else
|
|
||||||
local itemText = type(item) == "table" and item.text or tostring(item)
|
|
||||||
local isSelected = itemIndex == selected
|
|
||||||
|
|
||||||
local bg = isSelected and
|
|
||||||
(item.selectedBackground or self.get("selectedColor")) or
|
|
||||||
(item.background or self.get("background"))
|
|
||||||
|
|
||||||
local fg = isSelected and
|
|
||||||
(item.selectedForeground or colors.white) or
|
|
||||||
(item.foreground or self.get("foreground"))
|
|
||||||
|
|
||||||
self:textBg(1, i, string.rep(" ", width), bg)
|
|
||||||
self:textFg(1, i, itemText, fg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ local Container = elementManager.getElement("Container")
|
|||||||
local Frame = setmetatable({}, Container)
|
local Frame = setmetatable({}, Container)
|
||||||
Frame.__index = Frame
|
Frame.__index = Frame
|
||||||
|
|
||||||
---@event onResize {width number, height number} Fired when the frame is resized
|
|
||||||
Frame.listenTo(Frame, "resize")
|
|
||||||
|
|
||||||
--- Creates a new Frame instance
|
--- Creates a new Frame instance
|
||||||
--- @shortDescription Creates a new Frame instance
|
--- @shortDescription Creates a new Frame instance
|
||||||
--- @return Frame self The newly created Frame instance
|
--- @return Frame self The newly created Frame instance
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ Input.defineProperty(Input, "pattern", {default = nil, type = "string"})
|
|||||||
---@property cursorColor number nil Color of the cursor
|
---@property cursorColor number nil Color of the cursor
|
||||||
Input.defineProperty(Input, "cursorColor", {default = nil, type = "number"})
|
Input.defineProperty(Input, "cursorColor", {default = nil, type = "number"})
|
||||||
|
|
||||||
Input.listenTo(Input, "mouse_click")
|
Input.defineEvent(Input, "mouse_click")
|
||||||
Input.listenTo(Input, "key")
|
Input.defineEvent(Input, "key")
|
||||||
Input.listenTo(Input, "char")
|
Input.defineEvent(Input, "char")
|
||||||
|
|
||||||
--- Creates a new Input instance
|
--- Creates a new Input instance
|
||||||
--- @shortDescription Creates a new Input instance
|
--- @shortDescription Creates a new Input instance
|
||||||
|
|||||||
@@ -6,20 +6,22 @@ local VisualElement = require("elements/VisualElement")
|
|||||||
local List = setmetatable({}, VisualElement)
|
local List = setmetatable({}, VisualElement)
|
||||||
List.__index = List
|
List.__index = List
|
||||||
|
|
||||||
---@property items table {} List of items to display. Items can be strings or tables with properties
|
---@property items table {} List of items to display. Items can be tables with properties including selected state
|
||||||
List.defineProperty(List, "items", {default = {}, type = "table", canTriggerRender = true})
|
List.defineProperty(List, "items", {default = {}, type = "table", canTriggerRender = true})
|
||||||
---@property selectedIndex number 0 Index of the currently selected item (0 means no selection)
|
|
||||||
List.defineProperty(List, "selectedIndex", {default = 0, type = "number", canTriggerRender = true})
|
|
||||||
---@property selectable boolean true Whether items in the list can be selected
|
---@property selectable boolean true Whether items in the list can be selected
|
||||||
List.defineProperty(List, "selectable", {default = true, type = "boolean"})
|
List.defineProperty(List, "selectable", {default = true, type = "boolean"})
|
||||||
|
---@property multiSelection boolean false Whether multiple items can be selected at once
|
||||||
|
List.defineProperty(List, "multiSelection", {default = false, type = "boolean"})
|
||||||
---@property offset number 0 Current scroll offset for viewing long lists
|
---@property offset number 0 Current scroll offset for viewing long lists
|
||||||
List.defineProperty(List, "offset", {default = 0, type = "number", canTriggerRender = true})
|
List.defineProperty(List, "offset", {default = 0, type = "number", canTriggerRender = true})
|
||||||
---@property selectedColor color blue Background color for the selected item
|
---@property selectedBackground color blue Background color for selected items
|
||||||
List.defineProperty(List, "selectedColor", {default = colors.blue, type = "number"})
|
List.defineProperty(List, "selectedBackground", {default = colors.blue, type = "number"})
|
||||||
|
---@property selectedForeground color white Text color for selected items
|
||||||
|
List.defineProperty(List, "selectedForeground", {default = colors.white, type = "number"})
|
||||||
|
|
||||||
---@event onSelect {index number, item any} Fired when an item is selected
|
---@event onSelect {index number, item any} Fired when an item is selected
|
||||||
List.listenTo(List, "mouse_click")
|
List.defineEvent(List, "mouse_click")
|
||||||
List.listenTo(List, "mouse_scroll")
|
List.defineEvent(List, "mouse_scroll")
|
||||||
|
|
||||||
--- Creates a new List instance
|
--- Creates a new List instance
|
||||||
--- @shortDescription Creates a new List instance
|
--- @shortDescription Creates a new List instance
|
||||||
@@ -76,11 +78,24 @@ end
|
|||||||
--- @usage list:clear()
|
--- @usage list:clear()
|
||||||
function List:clear()
|
function List:clear()
|
||||||
self.set("items", {})
|
self.set("items", {})
|
||||||
self.set("selectedIndex", 0)
|
|
||||||
self:updateRender()
|
self:updateRender()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Gets the currently selected items
|
||||||
|
--- @shortDescription Gets the currently selected items
|
||||||
|
--- @return table selected List of selected items
|
||||||
|
--- @usage local selected = list:getSelectedItems()
|
||||||
|
function List:getSelectedItems()
|
||||||
|
local selected = {}
|
||||||
|
for i, item in ipairs(self.get("items")) do
|
||||||
|
if type(item) == "table" and item.selected then
|
||||||
|
table.insert(selected, {index = i, item = item})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return selected
|
||||||
|
end
|
||||||
|
|
||||||
--- Handles mouse click events
|
--- Handles mouse click events
|
||||||
--- @shortDescription Handles mouse click events
|
--- @shortDescription Handles mouse click events
|
||||||
--- @param button number The mouse button that was clicked
|
--- @param button number The mouse button that was clicked
|
||||||
@@ -90,15 +105,27 @@ end
|
|||||||
function List:mouse_click(button, x, y)
|
function List:mouse_click(button, x, y)
|
||||||
if button == 1 and self:isInBounds(x, y) and self.get("selectable") then
|
if button == 1 and self:isInBounds(x, y) and self.get("selectable") then
|
||||||
local _, index = self:getRelativePosition(x, y)
|
local _, index = self:getRelativePosition(x, y)
|
||||||
|
|
||||||
local adjustedIndex = index + self.get("offset")
|
local adjustedIndex = index + self.get("offset")
|
||||||
local items = self.get("items")
|
local items = self.get("items")
|
||||||
|
|
||||||
if adjustedIndex <= #items then
|
if adjustedIndex <= #items then
|
||||||
local item = items[adjustedIndex]
|
local item = items[adjustedIndex]
|
||||||
self.set("selectedIndex", adjustedIndex)
|
if type(item) == "string" then
|
||||||
|
item = {text = item}
|
||||||
|
items[adjustedIndex] = item
|
||||||
|
end
|
||||||
|
|
||||||
if type(item) == "table" and item.callback then
|
if not self.get("multiSelection") then
|
||||||
|
for _, otherItem in ipairs(items) do
|
||||||
|
if type(otherItem) == "table" then
|
||||||
|
otherItem.selected = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
item.selected = not item.selected
|
||||||
|
|
||||||
|
if item.callback then
|
||||||
item.callback(self)
|
item.callback(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -146,7 +173,6 @@ function List:render()
|
|||||||
local items = self.get("items")
|
local items = self.get("items")
|
||||||
local height = self.get("height")
|
local height = self.get("height")
|
||||||
local offset = self.get("offset")
|
local offset = self.get("offset")
|
||||||
local selected = self.get("selectedIndex")
|
|
||||||
local width = self.get("width")
|
local width = self.get("width")
|
||||||
|
|
||||||
for i = 1, height do
|
for i = 1, height do
|
||||||
@@ -154,7 +180,12 @@ function List:render()
|
|||||||
local item = items[itemIndex]
|
local item = items[itemIndex]
|
||||||
|
|
||||||
if item then
|
if item then
|
||||||
if type(item) == "table" and item.separator then
|
if type(item) == "string" then
|
||||||
|
item = {text = item}
|
||||||
|
items[itemIndex] = item
|
||||||
|
end
|
||||||
|
|
||||||
|
if item.separator then
|
||||||
local separatorChar = (item.text or "-"):sub(1,1)
|
local separatorChar = (item.text or "-"):sub(1,1)
|
||||||
local separatorText = string.rep(separatorChar, width)
|
local separatorText = string.rep(separatorChar, width)
|
||||||
local fg = item.foreground or self.get("foreground")
|
local fg = item.foreground or self.get("foreground")
|
||||||
@@ -163,15 +194,15 @@ function List:render()
|
|||||||
self:textBg(1, i, string.rep(" ", width), bg)
|
self:textBg(1, i, string.rep(" ", width), bg)
|
||||||
self:textFg(1, i, separatorText, fg)
|
self:textFg(1, i, separatorText, fg)
|
||||||
else
|
else
|
||||||
local text = type(item) == "table" and item.text or item
|
local text = item.text
|
||||||
local isSelected = itemIndex == selected
|
local isSelected = item.selected
|
||||||
|
|
||||||
local bg = isSelected and
|
local bg = isSelected and
|
||||||
(item.selectedBackground or self.get("selectedColor")) or
|
(item.selectedBackground or self.get("selectedBackground")) or
|
||||||
(item.background or self.get("background"))
|
(item.background or self.get("background"))
|
||||||
|
|
||||||
local fg = isSelected and
|
local fg = isSelected and
|
||||||
(item.selectedForeground or colors.white) or
|
(item.selectedForeground or self.get("selectedForeground")) or
|
||||||
(item.foreground or self.get("foreground"))
|
(item.foreground or self.get("foreground"))
|
||||||
|
|
||||||
self:textBg(1, i, string.rep(" ", width), bg)
|
self:textBg(1, i, string.rep(" ", width), bg)
|
||||||
|
|||||||
@@ -63,15 +63,19 @@ function Menu:render()
|
|||||||
VisualElement.render(self)
|
VisualElement.render(self)
|
||||||
local currentX = 1
|
local currentX = 1
|
||||||
|
|
||||||
for i, item in ipairs(self.get("items")) do
|
for _, item in ipairs(self.get("items")) do
|
||||||
local isSelected = i == self.get("selectedIndex")
|
if type(item) == "string" then
|
||||||
|
item = {text = " "..item.." "}
|
||||||
|
self.get("items")[i] = item
|
||||||
|
end
|
||||||
|
|
||||||
|
local isSelected = item.selected
|
||||||
local fg = item.selectable == false and self.get("separatorColor") or
|
local fg = item.selectable == false and self.get("separatorColor") or
|
||||||
(isSelected and (item.selectedForeground or self.get("foreground")) or
|
(isSelected and (item.selectedForeground or self.get("selectedForeground")) or
|
||||||
(item.foreground or self.get("foreground")))
|
(item.foreground or self.get("foreground")))
|
||||||
|
|
||||||
local bg = isSelected and
|
local bg = isSelected and
|
||||||
(item.selectedBackground or self.get("selectedColor")) or
|
(item.selectedBackground or self.get("selectedBackground")) or
|
||||||
(item.background or self.get("background"))
|
(item.background or self.get("background"))
|
||||||
|
|
||||||
self:blit(currentX, 1, item.text,
|
self:blit(currentX, 1, item.text,
|
||||||
@@ -97,12 +101,26 @@ function Menu:mouse_click(button, x, y)
|
|||||||
for i, item in ipairs(self.get("items")) do
|
for i, item in ipairs(self.get("items")) do
|
||||||
if relX >= currentX and relX < currentX + #item.text then
|
if relX >= currentX and relX < currentX + #item.text then
|
||||||
if item.selectable ~= false then
|
if item.selectable ~= false then
|
||||||
self.set("selectedIndex", i)
|
if type(item) == "string" then
|
||||||
if type(item) == "table" then
|
item = {text = item}
|
||||||
if item.callback then
|
self.get("items")[i] = item
|
||||||
item.callback(self)
|
end
|
||||||
|
|
||||||
|
-- Wenn kein Multi-Selection, alle anderen deselektieren
|
||||||
|
if not self.get("multiSelection") then
|
||||||
|
for _, otherItem in ipairs(self.get("items")) do
|
||||||
|
if type(otherItem) == "table" then
|
||||||
|
otherItem.selected = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Toggle Selection
|
||||||
|
item.selected = not item.selected
|
||||||
|
|
||||||
|
if item.callback then
|
||||||
|
item.callback(self)
|
||||||
|
end
|
||||||
self:fireEvent("select", i, item)
|
self:fireEvent("select", i, item)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ Program.defineProperty(Program, "program", {default = nil, type = "table"})
|
|||||||
Program.defineProperty(Program, "path", {default = "", type = "string"})
|
Program.defineProperty(Program, "path", {default = "", type = "string"})
|
||||||
Program.defineProperty(Program, "running", {default = false, type = "boolean"})
|
Program.defineProperty(Program, "running", {default = false, type = "boolean"})
|
||||||
|
|
||||||
Program.listenTo(Program, "key")
|
Program.defineEvent(Program, "key")
|
||||||
Program.listenTo(Program, "char")
|
Program.defineEvent(Program, "char")
|
||||||
Program.listenTo(Program, "key_up")
|
Program.defineEvent(Program, "key_up")
|
||||||
Program.listenTo(Program, "paste")
|
Program.defineEvent(Program, "paste")
|
||||||
Program.listenTo(Program, "mouse_click")
|
Program.defineEvent(Program, "mouse_click")
|
||||||
Program.listenTo(Program, "mouse_drag")
|
Program.defineEvent(Program, "mouse_drag")
|
||||||
Program.listenTo(Program, "mouse_scroll")
|
Program.defineEvent(Program, "mouse_scroll")
|
||||||
Program.listenTo(Program, "mouse_up")
|
Program.defineEvent(Program, "mouse_up")
|
||||||
|
|
||||||
local BasaltProgram = {}
|
local BasaltProgram = {}
|
||||||
BasaltProgram.__index = BasaltProgram
|
BasaltProgram.__index = BasaltProgram
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ Scrollbar.defineProperty(Scrollbar, "orientation", {default = "vertical", type =
|
|||||||
---@property handleSize number 2 Size of the scrollbar handle in characters
|
---@property handleSize number 2 Size of the scrollbar handle in characters
|
||||||
Scrollbar.defineProperty(Scrollbar, "handleSize", {default = 2, type = "number", canTriggerRender = true})
|
Scrollbar.defineProperty(Scrollbar, "handleSize", {default = 2, type = "number", canTriggerRender = true})
|
||||||
|
|
||||||
Scrollbar.listenTo(Scrollbar, "mouse_click")
|
Scrollbar.defineEvent(Scrollbar, "mouse_click")
|
||||||
Scrollbar.listenTo(Scrollbar, "mouse_release")
|
Scrollbar.defineEvent(Scrollbar, "mouse_release")
|
||||||
Scrollbar.listenTo(Scrollbar, "mouse_drag")
|
Scrollbar.defineEvent(Scrollbar, "mouse_drag")
|
||||||
Scrollbar.listenTo(Scrollbar, "mouse_scroll")
|
Scrollbar.defineEvent(Scrollbar, "mouse_scroll")
|
||||||
|
|
||||||
--- Creates a new Scrollbar instance
|
--- Creates a new Scrollbar instance
|
||||||
--- @shortDescription Creates a new Scrollbar instance
|
--- @shortDescription Creates a new Scrollbar instance
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ Slider.defineProperty(Slider, "barColor", {default = colors.gray, type = "number
|
|||||||
Slider.defineProperty(Slider, "sliderColor", {default = colors.blue, type = "number", canTriggerRender = true})
|
Slider.defineProperty(Slider, "sliderColor", {default = colors.blue, type = "number", canTriggerRender = true})
|
||||||
|
|
||||||
---@event onChange {value number} Fired when the slider value changes
|
---@event onChange {value number} Fired when the slider value changes
|
||||||
Slider.listenTo(Slider, "mouse_click")
|
Slider.defineEvent(Slider, "mouse_click")
|
||||||
Slider.listenTo(Slider, "mouse_drag")
|
Slider.defineEvent(Slider, "mouse_drag")
|
||||||
Slider.listenTo(Slider, "mouse_up")
|
Slider.defineEvent(Slider, "mouse_up")
|
||||||
|
|
||||||
--- Creates a new Slider instance
|
--- Creates a new Slider instance
|
||||||
--- @shortDescription Creates a new Slider instance
|
--- @shortDescription Creates a new Slider instance
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ Table.defineProperty(Table, "sortDirection", {default = "asc", type = "string"})
|
|||||||
---@property scrollOffset number 0 Current scroll position
|
---@property scrollOffset number 0 Current scroll position
|
||||||
Table.defineProperty(Table, "scrollOffset", {default = 0, type = "number", canTriggerRender = true})
|
Table.defineProperty(Table, "scrollOffset", {default = 0, type = "number", canTriggerRender = true})
|
||||||
|
|
||||||
Table.listenTo(Table, "mouse_click")
|
Table.defineEvent(Table, "mouse_click")
|
||||||
Table.listenTo(Table, "mouse_scroll")
|
Table.defineEvent(Table, "mouse_scroll")
|
||||||
|
|
||||||
--- Creates a new Table instance
|
--- Creates a new Table instance
|
||||||
--- @shortDescription Creates a new Table instance
|
--- @shortDescription Creates a new Table instance
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ TextBox.defineProperty(TextBox, "syntaxPatterns", {default = {}, type = "table"}
|
|||||||
---@property cursorColor number nil Color of the cursor
|
---@property cursorColor number nil Color of the cursor
|
||||||
TextBox.defineProperty(TextBox, "cursorColor", {default = nil, type = "number"})
|
TextBox.defineProperty(TextBox, "cursorColor", {default = nil, type = "number"})
|
||||||
|
|
||||||
TextBox.listenTo(TextBox, "mouse_click")
|
TextBox.defineEvent(TextBox, "mouse_click")
|
||||||
TextBox.listenTo(TextBox, "key")
|
TextBox.defineEvent(TextBox, "key")
|
||||||
TextBox.listenTo(TextBox, "char")
|
TextBox.defineEvent(TextBox, "char")
|
||||||
TextBox.listenTo(TextBox, "mouse_scroll")
|
TextBox.defineEvent(TextBox, "mouse_scroll")
|
||||||
|
|
||||||
function TextBox.new()
|
function TextBox.new()
|
||||||
local self = setmetatable({}, TextBox):__init()
|
local self = setmetatable({}, TextBox):__init()
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ Tree.defineProperty(Tree, "nodeColor", {default = colors.white, type = "number"}
|
|||||||
---@property selectedColor color lightBlue Background color of selected node
|
---@property selectedColor color lightBlue Background color of selected node
|
||||||
Tree.defineProperty(Tree, "selectedColor", {default = colors.lightBlue, type = "number"})
|
Tree.defineProperty(Tree, "selectedColor", {default = colors.lightBlue, type = "number"})
|
||||||
|
|
||||||
Tree.listenTo(Tree, "mouse_click")
|
Tree.defineEvent(Tree, "mouse_click")
|
||||||
Tree.listenTo(Tree, "mouse_scroll")
|
Tree.defineEvent(Tree, "mouse_scroll")
|
||||||
|
|
||||||
--- Creates a new Tree instance
|
--- Creates a new Tree instance
|
||||||
--- @shortDescription Creates a new Tree instance
|
--- @shortDescription Creates a new Tree instance
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
local elementManager = require("elementManager")
|
local elementManager = require("elementManager")
|
||||||
local BaseElement = elementManager.getElement("BaseElement")
|
local BaseElement = elementManager.getElement("BaseElement")
|
||||||
local tHex = require("libraries/colorHex")
|
local tHex = require("libraries/colorHex")
|
||||||
|
---@configDescription The Visual Element class which is the base class for all visual UI elements
|
||||||
|
---@configDefault true
|
||||||
|
|
||||||
--- This is the visual element class. It serves as the base class for all visual UI elements
|
--- This is the visual element class. It serves as the base class for all visual UI elements
|
||||||
--- and provides core functionality for positioning, sizing, colors, and rendering.
|
--- and provides core functionality for positioning, sizing, colors, and rendering.
|
||||||
@@ -84,11 +86,16 @@ VisualElement.combineProperties(VisualElement, "color", "foreground", "backgroun
|
|||||||
---@event onKeyUp {key number, code number} Fired on key release
|
---@event onKeyUp {key number, code number} Fired on key release
|
||||||
---@event onChar {char string} Fired on character input
|
---@event onChar {char string} Fired on character input
|
||||||
|
|
||||||
VisualElement.listenTo(VisualElement, "focus")
|
VisualElement.defineEvent(VisualElement, "focus")
|
||||||
VisualElement.listenTo(VisualElement, "blur")
|
VisualElement.defineEvent(VisualElement, "blur")
|
||||||
VisualElement.listenTo(VisualElement, "mouse_enter", "mouse_move")
|
|
||||||
VisualElement.listenTo(VisualElement, "mouse_leave", "mouse_move")
|
VisualElement.registerEventCallback(VisualElement, "MouseClick", "mouse_click", "mouse_up")
|
||||||
VisualElement.listenTo(VisualElement, "mouse_scroll")
|
VisualElement.registerEventCallback(VisualElement, "MouseUp", "mouse_up", "mouse_click")
|
||||||
|
VisualElement.registerEventCallback(VisualElement, "MouseDrag", "mouse_drag", "mouse_click", "mouse_up")
|
||||||
|
VisualElement.registerEventCallback(VisualElement, "MouseScroll", "mouse_scroll")
|
||||||
|
VisualElement.registerEventCallback(VisualElement, "MouseEnter", "mouse_enter", "mouse_move")
|
||||||
|
VisualElement.registerEventCallback(VisualElement, "Focus", "focus", "blur")
|
||||||
|
VisualElement.registerEventCallback(VisualElement, "Blur", "blur", "focus")
|
||||||
|
|
||||||
local max, min = math.max, math.min
|
local max, min = math.max, math.min
|
||||||
|
|
||||||
@@ -114,7 +121,13 @@ end
|
|||||||
|
|
||||||
--- Draws multiple characters at once with colors
|
--- Draws multiple characters at once with colors
|
||||||
--- @shortDescription Multi-character drawing with colors
|
--- @shortDescription Multi-character drawing with colors
|
||||||
---@protected
|
--- @param x number The x position to draw
|
||||||
|
--- @param y number The y position to draw
|
||||||
|
--- @param width number The width of the area to draw
|
||||||
|
--- @param height number The height of the area to draw
|
||||||
|
--- @param text string The text to draw
|
||||||
|
--- @param fg string The foreground color
|
||||||
|
--- @param bg string The background color
|
||||||
function VisualElement:multiBlit(x, y, width, height, text, fg, bg)
|
function VisualElement:multiBlit(x, y, width, height, text, fg, bg)
|
||||||
local xElement, yElement = self:calculatePosition()
|
local xElement, yElement = self:calculatePosition()
|
||||||
x = x + xElement - 1
|
x = x + xElement - 1
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ end
|
|||||||
---@private
|
---@private
|
||||||
function VisualElement.setup(element)
|
function VisualElement.setup(element)
|
||||||
element.defineProperty(element, "animation", {default = nil, type = "table"})
|
element.defineProperty(element, "animation", {default = nil, type = "table"})
|
||||||
element.listenTo(element, "timer")
|
element.defineEvent(element, "timer")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a new Animation Object
|
--- Creates a new Animation Object
|
||||||
|
|||||||
@@ -6,13 +6,11 @@ local function serialize(t, indent)
|
|||||||
local result = "{\n"
|
local result = "{\n"
|
||||||
for k, v in pairs(t) do
|
for k, v in pairs(t) do
|
||||||
result = result .. indent .. " "
|
result = result .. indent .. " "
|
||||||
|
|
||||||
if type(k) == "string" then
|
if type(k) == "string" then
|
||||||
result = result .. "[\"" .. k .. "\"] = "
|
result = result .. "[\"" .. k .. "\"] = "
|
||||||
else
|
else
|
||||||
result = result .. "[" .. k .. "] = "
|
result = result .. "[" .. k .. "] = "
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
result = result .. serialize(v, indent .. " ")
|
result = result .. serialize(v, indent .. " ")
|
||||||
elseif type(v) == "string" then
|
elseif type(v) == "string" then
|
||||||
@@ -25,33 +23,84 @@ local function serialize(t, indent)
|
|||||||
return result .. indent .. "}"
|
return result .. indent .. "}"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extractConfigDescription(filePath)
|
local function parseFile(filePath)
|
||||||
local f = io.open(filePath, "r")
|
local file = fs.open(filePath, "r")
|
||||||
if not f then return nil end
|
local content = file.readAll()
|
||||||
|
file.close()
|
||||||
|
|
||||||
local content = f:read("*all")
|
local config = {
|
||||||
f:close()
|
description = "",
|
||||||
|
default = true,
|
||||||
|
requires = {}
|
||||||
|
}
|
||||||
|
|
||||||
return content:match("%-%-%-@configDescription%s*(.-)%s*[\n\r]") or "No description available"
|
-- Description aus @configDescription
|
||||||
|
local description = content:match("%-%-%-@configDescription%s*(.-)%s*\n")
|
||||||
|
if description then
|
||||||
|
config.description = description
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default aus @configDefault
|
||||||
|
local default = content:match("%-%-%-@configDefault%s*(%w+)")
|
||||||
|
if default then
|
||||||
|
config.default = default == "true"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Dependencies aus @requires
|
||||||
|
for required in content:gmatch("%-%-%-@requires%s*(%w+)") do
|
||||||
|
table.insert(config.requires, required)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Dependencies aus @class inheritance
|
||||||
|
local className, parent = content:match("%-%-%-@class%s*([^%s:]+)%s*:%s*([^%s\n]+)")
|
||||||
|
if className and parent and parent ~= "PropertySystem" then
|
||||||
|
table.insert(config.requires, parent)
|
||||||
|
end
|
||||||
|
|
||||||
|
return config
|
||||||
end
|
end
|
||||||
|
|
||||||
local function categorizeFile(path)
|
local function categorizeFile(path)
|
||||||
if path:match("^src/elements/") then
|
if path:match("^elements/") then
|
||||||
return "elements", "UI Elements"
|
return "elements", "UI Elements"
|
||||||
elseif path:match("^src/plugins/") then
|
elseif path:match("^plugins/") then
|
||||||
return "plugins", "Plugins and Extensions"
|
return "plugins", "Plugins"
|
||||||
elseif path:match("^src/libraries/") then
|
elseif path:match("^libraries/") then
|
||||||
return "libraries", "Utility Libraries"
|
return "libraries", "Libraries"
|
||||||
elseif path:match("^src/[^/]+%.lua$") then
|
|
||||||
return "core", "Core Framework Files"
|
|
||||||
else
|
else
|
||||||
return "other", "Other Files"
|
return "core", "Core Files"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function sortFiles(files)
|
local function scanDirectory(baseDir, relativePath)
|
||||||
|
local files = {}
|
||||||
|
local items = fs.list(fs.combine(baseDir, relativePath))
|
||||||
|
|
||||||
|
for _, item in ipairs(items) do
|
||||||
|
local fullPath = fs.combine(relativePath, item)
|
||||||
|
local absPath = fs.combine(baseDir, fullPath)
|
||||||
|
|
||||||
|
if fs.isDir(absPath) then
|
||||||
|
for path, config in pairs(scanDirectory(baseDir, fullPath)) do
|
||||||
|
files[path] = config
|
||||||
|
end
|
||||||
|
elseif item:match("%.lua$") then
|
||||||
|
local config = parseFile(absPath)
|
||||||
|
config.name = item:gsub("%.lua$", "")
|
||||||
|
config.path = fullPath
|
||||||
|
files[fullPath] = config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return files
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateConfig(srcPath)
|
||||||
|
local files = scanDirectory(srcPath, "")
|
||||||
local categories = {}
|
local categories = {}
|
||||||
for path, info in pairs(files) do
|
|
||||||
|
-- Files in Kategorien einordnen
|
||||||
|
for path, fileConfig in pairs(files) do
|
||||||
local category, categoryDesc = categorizeFile(path)
|
local category, categoryDesc = categorizeFile(path)
|
||||||
if not categories[category] then
|
if not categories[category] then
|
||||||
categories[category] = {
|
categories[category] = {
|
||||||
@@ -59,61 +108,45 @@ local function sortFiles(files)
|
|||||||
files = {}
|
files = {}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
table.insert(categories[category].files, {
|
categories[category].files[fileConfig.name] = {
|
||||||
path = path,
|
path = fileConfig.path,
|
||||||
name = info.name,
|
description = fileConfig.description,
|
||||||
description = info.description
|
default = fileConfig.default,
|
||||||
})
|
requires = fileConfig.requires
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, cat in pairs(categories) do
|
-- Dependencies validieren
|
||||||
table.sort(cat.files, function(a, b)
|
for catName, cat in pairs(categories) do
|
||||||
return a.name < b.name
|
for fileName, file in pairs(cat.files) do
|
||||||
end)
|
for _, req in ipairs(file.requires or {}) do
|
||||||
end
|
local found = false
|
||||||
|
for _, checkCat in pairs(categories) do
|
||||||
return categories
|
if checkCat.files[req] then
|
||||||
end
|
found = true
|
||||||
|
break
|
||||||
local function scanDir(dir)
|
end
|
||||||
local files = {}
|
end
|
||||||
for file in io.popen('find "'..dir..'" -maxdepth 1 -type f -name "*.lua"'):lines() do
|
if not found then
|
||||||
local name = file:match("([^/]+)%.lua$")
|
error(string.format("Missing dependency %s for %s", req, fileName))
|
||||||
if name then
|
end
|
||||||
files[file] = {
|
end
|
||||||
name = name,
|
|
||||||
path = file:gsub("^src/", ""),
|
|
||||||
description = extractConfigDescription(file)
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for file in io.popen('find "'..dir..'/elements" "'..dir..'/plugins" "'..dir..'/libraries" -type f -name "*.lua"'):lines() do
|
return {
|
||||||
local name = file:match("([^/]+)%.lua$")
|
categories = categories,
|
||||||
if name then
|
metadata = {
|
||||||
files[file] = {
|
generated = os.date(),
|
||||||
name = name,
|
version = "2.0"
|
||||||
path = file:gsub("^src/", ""),
|
}
|
||||||
description = extractConfigDescription(file)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return files
|
|
||||||
end
|
|
||||||
|
|
||||||
local sourceFiles = scanDir("src")
|
|
||||||
local categories = sortFiles(sourceFiles)
|
|
||||||
|
|
||||||
local config = {
|
|
||||||
categories = categories,
|
|
||||||
metadata = {
|
|
||||||
generated = os.date(),
|
|
||||||
version = "2.0"
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
local f = io.open("config.lua", "w")
|
|
||||||
if f then
|
|
||||||
f:write("return " .. serialize(config))
|
|
||||||
f:close()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Config generieren
|
||||||
|
local config = generateConfig("/c:/Users/rjsha/AppData/Roaming/CraftOS-PC/computer/0/Basalt2/src")
|
||||||
|
|
||||||
|
-- Config speichern
|
||||||
|
local configFile = fs.open("/c:/Users/rjsha/AppData/Roaming/CraftOS-PC/computer/0/Basalt2/config.lua", "w")
|
||||||
|
configFile.write("return " .. serialize(config))
|
||||||
|
configFile.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user