This commit is contained in:
Robert Jelic
2025-09-30 14:41:49 +02:00
parent ccc86b0d52
commit 3a87b44655
9 changed files with 226 additions and 128 deletions

View File

@@ -3,13 +3,17 @@ local VisualElement = elementManager.getElement("VisualElement")
local BaseGraph = elementManager.getElement("Graph") local BaseGraph = elementManager.getElement("Graph")
local tHex = require("libraries/colorHex") local tHex = require("libraries/colorHex")
--- @configDescription A bar chart element based on the graph element. --- @configDescription A bar chart element based on the graph element.
---@configDefault false --- @configDefault false
--- The Bar Chart element is designed for visualizing data series as vertical bars. It displays multiple values as side-by-side bars where each bar's height represents its value. --- A data visualization element that represents numeric data through vertical bars. Each bar's height corresponds to its value, making it ideal for comparing quantities across categories or showing data changes over time. Supports multiple data series with customizable colors and styles.
--- @usage -- Create a bar chart
--- @usage local chart = main:addBarChart() --- @usage local chart = main:addBarChart()
--- @usage :addSeries("input", " ", colors.green, colors.green, 5)
--- @usage :addSeries("output", " ", colors.red, colors.red, 5)
--- @usage --- @usage
--- @usage -- Add two data series with different colors
--- @usage chart:addSeries("input", " ", colors.green, colors.green, 5)
--- @usage chart:addSeries("output", " ", colors.red, colors.red, 5)
--- @usage
--- @usage -- Continuously update the chart with random data
--- @usage basalt.schedule(function() --- @usage basalt.schedule(function()
--- @usage while true do --- @usage while true do
--- @usage chart:addPoint("input", math.random(1,100)) --- @usage chart:addPoint("input", math.random(1,100))
@@ -42,7 +46,8 @@ function BarChart:init(props, basalt)
return self return self
end end
--- @shortDescription Renders the BarChart --- Renders the bar chart by calculating bar positions and heights based on data values
--- @shortDescription Draws bars for each data point in visible series
--- @protected --- @protected
function BarChart:render() function BarChart:render()
VisualElement.render(self) VisualElement.render(self)

View File

@@ -3,12 +3,12 @@ local uuid = require("libraries/utils").uuid
local errorManager = require("errorManager") local errorManager = require("errorManager")
---@configDescription The base class for all UI elements in Basalt. ---@configDescription The base class for all UI elements in Basalt.
--- The base class for all UI elements in Basalt. This class provides basic properties and event handling functionality. --- The fundamental base class for all UI elements in Basalt. It implements core functionality like event handling, property management, lifecycle hooks, and the observer pattern. Every UI component inherits from this class to ensure consistent behavior and interface.
--- @class BaseElement : PropertySystem --- @class BaseElement : PropertySystem
local BaseElement = setmetatable({}, PropertySystem) local BaseElement = setmetatable({}, PropertySystem)
BaseElement.__index = BaseElement BaseElement.__index = BaseElement
--- @property type string BaseElement The type identifier of the element --- @property type string BaseElement A hierarchical identifier of the element's type chain
BaseElement.defineProperty(BaseElement, "type", {default = {"BaseElement"}, type = "string", setter=function(self, value) BaseElement.defineProperty(BaseElement, "type", {default = {"BaseElement"}, type = "string", setter=function(self, value)
if type(value) == "string" then if type(value) == "string" then
table.insert(self._values.type, 1, value) table.insert(self._values.type, 1, value)
@@ -22,19 +22,19 @@ end, getter = function(self, _, index)
return self._values.type[index or 1] return self._values.type[index or 1]
end}) end})
--- @property id string BaseElement The unique identifier for the element --- @property id string BaseElement Auto-generated unique identifier for element lookup
BaseElement.defineProperty(BaseElement, "id", {default = "", type = "string", readonly = true}) BaseElement.defineProperty(BaseElement, "id", {default = "", type = "string", readonly = true})
--- @property name string BaseElement The name of the element --- @property name string BaseElement User-defined name for the element
BaseElement.defineProperty(BaseElement, "name", {default = "", type = "string"}) BaseElement.defineProperty(BaseElement, "name", {default = "", type = "string"})
--- @property eventCallbacks table BaseElement The event callbacks for the element --- @property eventCallbacks table BaseElement Collection of registered event handler functions
BaseElement.defineProperty(BaseElement, "eventCallbacks", {default = {}, type = "table"}) BaseElement.defineProperty(BaseElement, "eventCallbacks", {default = {}, type = "table"})
--- @property enabled boolean BaseElement Whether the element is enabled or not --- @property enabled boolean BaseElement Controls event processing for this element
BaseElement.defineProperty(BaseElement, "enabled", {default = true, type = "boolean" }) BaseElement.defineProperty(BaseElement, "enabled", {default = true, type = "boolean" })
--- Registers a new event listener for the element (on class level) --- Registers a class-level event listener with optional dependency
--- @shortDescription Registers a new event listener for the element (on class level) --- @shortDescription Registers a new event listener for the element (on class level)
--- @param class table The class to register --- @param class table The class to register
--- @param eventName string The name of the event to register --- @param eventName string The name of the event to register
@@ -49,8 +49,8 @@ function BaseElement.defineEvent(class, eventName, requiredEvent)
} }
end end
--- Registers a new event callback for the element (on class level) --- Defines a class-level event callback method with automatic event registration
--- @shortDescription Registers a new event callback for the element (on class level) --- @shortDescription Registers a new event callback method with auto-registration
--- @param class table The class to register --- @param class table The class to register
--- @param callbackName string The name of the callback to register --- @param callbackName string The name of the callback to register
--- @param ... string The names of the events to register the callback for --- @param ... string The names of the events to register the callback for
@@ -143,8 +143,8 @@ function BaseElement:postInit()
return self return self
end end
--- Checks if the element is a specific type --- Checks if the element matches or inherits from the specified type
--- @shortDescription Checks if the element is a specific type --- @shortDescription Tests if element is of or inherits given type
--- @param type string The type to check for --- @param type string The type to check for
--- @return boolean isType Whether the element is of the specified type --- @return boolean isType Whether the element is of the specified type
function BaseElement:isType(type) function BaseElement:isType(type)
@@ -156,8 +156,8 @@ function BaseElement:isType(type)
return false return false
end end
--- Enables or disables event listening for a specific event --- Configures event listening behavior with automatic parent notification
--- @shortDescription Enables or disables event listening for a specific event --- @shortDescription Enables/disables event handling for this element
--- @param eventName string The name of the event to listen for --- @param eventName string The name of the event to listen for
--- @param enable? boolean Whether to enable or disable the event (default: true) --- @param enable? boolean Whether to enable or disable the event (default: true)
--- @return table self The BaseElement instance --- @return table self The BaseElement instance
@@ -179,8 +179,8 @@ function BaseElement:listenEvent(eventName, enable)
return self return self
end end
--- Registers a callback function for an event --- Adds an event handler function with automatic event registration
--- @shortDescription Registers a callback function --- @shortDescription Registers a function to handle specific events
--- @param event string The event to register the callback for --- @param event string The event to register the callback for
--- @param callback function The callback function to register --- @param callback function The callback function to register
--- @return table self The BaseElement instance --- @return table self The BaseElement instance
@@ -197,8 +197,8 @@ function BaseElement:registerCallback(event, callback)
return self return self
end end
--- Triggers an event and calls all registered callbacks --- Executes all registered callbacks for the specified event
--- @shortDescription Triggers an event and calls all registered callbacks --- @shortDescription Triggers event callbacks with provided arguments
--- @param event string The event to fire --- @param event string The event to fire
--- @param ... any Additional arguments to pass to the callbacks --- @param ... any Additional arguments to pass to the callbacks
--- @return table self The BaseElement instance --- @return table self The BaseElement instance
@@ -236,8 +236,8 @@ function BaseElement:handleEvent(event, ...)
return false return false
end end
--- Observes a property and calls a callback when it changes --- Sets up a property change observer with immediate callback registration
--- @shortDescription Observes a property and calls a callback when it changes --- @shortDescription Watches property changes with callback notification
--- @param property string The property to observe --- @param property string The property to observe
--- @param callback function The callback to call when the property changes --- @param callback function The callback to call when the property changes
--- @return table self The BaseElement instance --- @return table self The BaseElement instance
@@ -246,8 +246,8 @@ function BaseElement:onChange(property, callback)
return self return self
end end
--- Returns the base frame of the element --- Traverses parent chain to locate the root frame element
--- @shortDescription Returns the base frame of the element --- @shortDescription Retrieves the root frame of this element's tree
--- @return BaseFrame BaseFrame The base frame of the element --- @return BaseFrame BaseFrame The base frame of the element
function BaseElement:getBaseFrame() function BaseElement:getBaseFrame()
if self.parent then if self.parent then
@@ -256,8 +256,8 @@ function BaseElement:getBaseFrame()
return self return self
end end
--- Destroys the element and cleans up all references --- Removes the element from UI tree and cleans up resources
--- @shortDescription Destroys the element and cleans up all references --- @shortDescription Removes element and performs cleanup
function BaseElement:destroy() function BaseElement:destroy()
if(self.parent) then if(self.parent) then
self.parent:removeChild(self) self.parent:removeChild(self)
@@ -267,8 +267,8 @@ function BaseElement:destroy()
self:setFocused(false) self:setFocused(false)
end end
--- Requests a render update for this element --- Propagates render request up the element tree
--- @shortDescription Requests a render update for this element --- @shortDescription Requests UI update for this element
--- @return table self The BaseElement instance --- @return table self The BaseElement instance
function BaseElement:updateRender() function BaseElement:updateRender()
if(self.parent) then if(self.parent) then

View File

@@ -5,7 +5,7 @@ local Render = require("render")
---@configDescription This is the base frame class. It is the root element of all elements and the only element without a parent. ---@configDescription 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. --- This is the root frame class that serves as the foundation for the UI hierarchy. It manages the rendering context and acts as the top-level container for all other elements. Unlike other elements, it renders directly to a terminal or monitor and does not require a parent element.
---@class BaseFrame : Container ---@class BaseFrame : Container
---@field _render Render The render object ---@field _render Render The render object
---@field _renderUpdate boolean Whether the render object needs to be updated ---@field _renderUpdate boolean Whether the render object needs to be updated
@@ -110,22 +110,31 @@ function BaseFrame:textBg(x, y, text, bg)
self._render:textBg(x, y, text, bg) self._render:textBg(x, y, text, bg)
end end
--- @shortDescription Renders a text with a background color to the render Object --- @shortDescription Draws plain text to the render Object
--- @param x number The x position to render to --- @param x number The x position to render to
--- @param y number The y position to render to --- @param y number The y position to render to
--- @param text string The text to render --- @param text string The text to render
--- @param bg colors The background color
--- @protected --- @protected
function BaseFrame:drawText(x, y, text) function BaseFrame:drawText(x, y, text)
if x < 1 then text = string.sub(text, 1 - x); x = 1 end if x < 1 then text = string.sub(text, 1 - x); x = 1 end
self._render:text(x, y, text) self._render:text(x, y, text)
end end
--- @shortDescription Draws a foreground color to the render Object
--- @param x number The x position to render to
--- @param y number The y position to render to
--- @param fg colors The foreground color
--- @protected
function BaseFrame:drawFg(x, y, fg) function BaseFrame:drawFg(x, y, fg)
if x < 1 then fg = string.sub(fg, 1 - x); x = 1 end if x < 1 then fg = string.sub(fg, 1 - x); x = 1 end
self._render:fg(x, y, fg) self._render:fg(x, y, fg)
end end
--- @shortDescription Draws a background color to the render Object
--- @param x number The x position to render to
--- @param y number The y position to render to
--- @param bg colors The background color
--- @protected
function BaseFrame:drawBg(x, y, bg) function BaseFrame:drawBg(x, y, bg)
if x < 1 then bg = string.sub(bg, 1 - x); x = 1 end if x < 1 then bg = string.sub(bg, 1 - x); x = 1 end
self._render:bg(x, y, bg) self._render:bg(x, y, bg)

View File

@@ -145,22 +145,34 @@ local VisualElement = elementManager.getElement("VisualElement")
---@cofnigDescription The BigFont is a text element that displays large text. ---@cofnigDescription The BigFont is a text element that displays large text.
---@configDefault false ---@configDefault false
--- The BigFont element is a text element that displays larger text. It uses Wojbie's BigFont API to render the text in a larger font size. Credits to Wojbie for the original API. --- A specialized text element that renders characters in larger sizes using Wojbie's BigFont API. Supports multiple font sizes and custom colors while maintaining the pixel-art style of ComputerCraft. Ideal for headers, titles, and emphasis text.
--- @run local basalt = require("basalt") --- @usage -- Create a large welcome message
--- @run local main = basalt.getMainFrame() --- @usage local main = basalt.getMainFrame()
--- @run local font = main:addBigFont() --- @usage local title = main:addBigFont()
--- @run font:setText("Hello World!") --- @usage :setPosition(3, 3)
--- @run basalt.run() --- @usage :setFontSize(2) -- Makes text twice as large
--- @usage :setText("Welcome!")
--- @usage :setForeground(colors.yellow) -- Make text yellow
--- @usage
--- @usage -- For animated text
--- @usage basalt.schedule(function()
--- @usage while true do
--- @usage title:setForeground(colors.yellow)
--- @usage sleep(0.5)
--- @usage title:setForeground(colors.orange)
--- @usage sleep(0.5)
--- @usage end
--- @usage end)
---@class BigFont : VisualElement ---@class BigFont : VisualElement
local BigFont = setmetatable({}, VisualElement) local BigFont = setmetatable({}, VisualElement)
BigFont.__index = BigFont BigFont.__index = BigFont
---@property text string BigFont BigFont text ---@property text string BigFont The text string to display in enlarged format
BigFont.defineProperty(BigFont, "text", {default = "BigFont", type = "string", canTriggerRender = true, setter=function(self, value) BigFont.defineProperty(BigFont, "text", {default = "BigFont", type = "string", canTriggerRender = true, setter=function(self, value)
self.bigfontText = makeText(self.get("fontSize"), value, self.get("foreground"), self.get("background")) self.bigfontText = makeText(self.get("fontSize"), value, self.get("foreground"), self.get("background"))
return value return value
end}) end})
---@property fontSize number 1 The font size of the BigFont ---@property fontSize number 1 Scale factor for text size (1-3, where 1 is 3x3 pixels per character)
BigFont.defineProperty(BigFont, "fontSize", {default = 1, type = "number", canTriggerRender = true, setter=function(self, value) BigFont.defineProperty(BigFont, "fontSize", {default = 1, type = "number", canTriggerRender = true, setter=function(self, value)
self.bigfontText = makeText(value, self.get("text"), self.get("foreground"), self.get("background")) self.bigfontText = makeText(value, self.get("text"), self.get("foreground"), self.get("background"))
return value return value

View File

@@ -1,14 +1,34 @@
local elementManager = require("elementManager") 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
---@cofnigDescription The Button is a standard button element with click handling and state management. ---@configDescription The Button is a standard button element with click handling and state management.
--- The Button is a standard button element with click handling and state management. --- A clickable interface element that triggers actions when pressed. Supports text labels, custom styling, and automatic text centering. Commonly used for user interactions and form submissions.
--- @usage -- Create a simple action button
--- @usage local button = parent:addButton()
--- @usage :setPosition(5, 5)
--- @usage :setText("Click me!")
--- @usage :setBackground(colors.blue)
--- @usage :setForeground(colors.white)
--- @usage
--- @usage -- Add click handling
--- @usage button:onClick(function(self, button, x, y)
--- @usage -- Change appearance when clicked
--- @usage self:setBackground(colors.green)
--- @usage self:setText("Success!")
--- @usage
--- @usage -- Revert after delay
--- @usage basalt.schedule(function()
--- @usage sleep(1)
--- @usage self:setBackground(colors.blue)
--- @usage self:setText("Click me!")
--- @usage end)
--- @usage end)
---@class Button : VisualElement ---@class Button : VisualElement
local Button = setmetatable({}, VisualElement) local Button = setmetatable({}, VisualElement)
Button.__index = Button Button.__index = Button
---@property text string Button Button text ---@property text string Button Label text displayed centered within the button
Button.defineProperty(Button, "text", {default = "Button", type = "string", canTriggerRender = true}) Button.defineProperty(Button, "text", {default = "Button", type = "string", canTriggerRender = true})
Button.defineEvent(Button, "mouse_click") Button.defineEvent(Button, "mouse_click")

View File

@@ -1,14 +1,26 @@
local VisualElement = require("elements/VisualElement") local VisualElement = require("elements/VisualElement")
---@cofnigDescription This is a checkbox. It is a visual element that can be checked. ---@configDescription This is a checkbox. It is a visual element that can be checked.
--- The CheckBox is a visual element that can be checked. --- A toggleable UI element that can be checked or unchecked. Displays different text based on its state and supports automatic sizing. Commonly used in forms and settings interfaces for boolean options.
---@class CheckBox : VisualElement --- @usage -- Create a checkbox for a setting
--- @usage local checkbox = parent:addCheckBox()
--- @usage :setText("Enable Feature")
--- @usage :setCheckedText("✓")
--- @usage :onChange("checked", function(self, checked)
--- @usage -- React to checkbox state changes
--- @usage if checked then
--- @usage -- Handle enabled state
--- @usage else
--- @usage -- Handle disabled state
--- @usage end
--- @usage end)
--- @class CheckBox : VisualElement
local CheckBox = setmetatable({}, VisualElement) local CheckBox = setmetatable({}, VisualElement)
CheckBox.__index = CheckBox CheckBox.__index = CheckBox
---@property checked boolean Whether checkbox is checked ---@property checked boolean false The current state of the checkbox (true=checked, false=unchecked)
CheckBox.defineProperty(CheckBox, "checked", {default = false, type = "boolean", canTriggerRender = true}) CheckBox.defineProperty(CheckBox, "checked", {default = false, type = "boolean", canTriggerRender = true})
---@property text string empty Text to display ---@property text string empty Text shown when the checkbox is unchecked
CheckBox.defineProperty(CheckBox, "text", {default = " ", type = "string", canTriggerRender = true, setter=function(self, value) CheckBox.defineProperty(CheckBox, "text", {default = " ", type = "string", canTriggerRender = true, setter=function(self, value)
local checkedText = self.get("checkedText") local checkedText = self.get("checkedText")
local width = math.max(#value, #checkedText) local width = math.max(#value, #checkedText)
@@ -17,7 +29,7 @@ CheckBox.defineProperty(CheckBox, "text", {default = " ", type = "string", canTr
end end
return value return value
end}) end})
---@property checkedText string Text when checked ---@property checkedText string x Text shown when the checkbox is checked
CheckBox.defineProperty(CheckBox, "checkedText", {default = "x", type = "string", canTriggerRender = true, setter=function(self, value) CheckBox.defineProperty(CheckBox, "checkedText", {default = "x", type = "string", canTriggerRender = true, setter=function(self, value)
local text = self.get("text") local text = self.get("text")
local width = math.max(#value, #text) local width = math.max(#value, #text)
@@ -26,7 +38,7 @@ CheckBox.defineProperty(CheckBox, "checkedText", {default = "x", type = "string"
end end
return value return value
end}) end})
---@property autoSize boolean true Whether to automatically size the checkbox ---@property autoSize boolean true Automatically adjusts width based on text length
CheckBox.defineProperty(CheckBox, "autoSize", {default = true, type = "boolean"}) CheckBox.defineProperty(CheckBox, "autoSize", {default = true, type = "boolean"})
CheckBox.defineEvent(CheckBox, "mouse_click") CheckBox.defineEvent(CheckBox, "mouse_click")
@@ -51,7 +63,8 @@ function CheckBox:init(props, basalt)
self.set("type", "CheckBox") self.set("type", "CheckBox")
end end
--- @shortDescription Handles mouse click events --- Handles mouse interactions to toggle the checkbox state
--- @shortDescription Toggles checked state on mouse click
--- @param button number The button that was clicked --- @param button number The button that was clicked
--- @param x number The x position of the click --- @param x number The x position of the click
--- @param y number The y position of the click --- @param y number The y position of the click

View File

@@ -5,39 +5,49 @@ local tHex = require("libraries/colorHex")
---@configDescription A ComboBox that combines dropdown selection with editable text input ---@configDescription A ComboBox that combines dropdown selection with editable text input
---@configDefault false ---@configDefault false
--- This is the ComboBox class. It extends the dropdown functionality with editable text input, --- A hybrid input element that combines a text input field with a dropdown list. Users can either type directly or select from predefined options.
--- allowing users to either select from a list or type their own custom text. --- Supports auto-completion, custom styling, and both single and multi-selection modes.
--- @usage local ComboBox = main:addCombobox() --- @usage -- Create a searchable country selector
--- @usage ComboBox:setEditable(true) --- @usage local combo = main:addComboBox()
--- @usage ComboBox:setItems({ --- @usage :setPosition(5, 5)
--- @usage {text = "Option 1"}, --- @usage :setSize(20, 1) -- Height will expand when opened
--- @usage {text = "Option 2"}, --- @usage :setItems({
--- @usage {text = "Option 3"}, --- @usage {text = "Germany"},
--- @usage }) --- @usage {text = "France"},
--- @usage ComboBox:setText("Custom input...") --- @usage {text = "Spain"},
--- @usage {text = "Italy"}
--- @usage })
--- @usage :setPlaceholder("Select country...")
--- @usage :setAutoComplete(true) -- Enable filtering while typing
--- @usage
--- @usage -- Handle selection changes
--- @usage combo:onChange(function(self, value)
--- @usage -- value will be the selected country
--- @usage basalt.debug("Selected:", value)
--- @usage end)
---@class ComboBox : DropDown ---@class ComboBox : DropDown
local ComboBox = setmetatable({}, DropDown) local ComboBox = setmetatable({}, DropDown)
ComboBox.__index = ComboBox ComboBox.__index = ComboBox
---@property editable boolean true Whether the ComboBox allows text input ---@property editable boolean true Enables direct text input in the field
ComboBox.defineProperty(ComboBox, "editable", {default = true, type = "boolean", canTriggerRender = true}) ComboBox.defineProperty(ComboBox, "editable", {default = true, type = "boolean", canTriggerRender = true})
---@property text string "" The current text content of the ComboBox ---@property text string "" The current text value of the input field
ComboBox.defineProperty(ComboBox, "text", {default = "", type = "string", canTriggerRender = true}) ComboBox.defineProperty(ComboBox, "text", {default = "", type = "string", canTriggerRender = true})
---@property cursorPos number 1 The current cursor position in the text ---@property cursorPos number 1 Current cursor position in the text input
ComboBox.defineProperty(ComboBox, "cursorPos", {default = 1, type = "number"}) ComboBox.defineProperty(ComboBox, "cursorPos", {default = 1, type = "number"})
---@property viewOffset number 0 The horizontal scroll offset for viewing long text ---@property viewOffset number 0 Horizontal scroll position for viewing long text
ComboBox.defineProperty(ComboBox, "viewOffset", {default = 0, type = "number", canTriggerRender = true}) ComboBox.defineProperty(ComboBox, "viewOffset", {default = 0, type = "number", canTriggerRender = true})
---@property placeholder string "..." Text to display when input is empty ---@property placeholder string "..." Text shown when the input is empty
ComboBox.defineProperty(ComboBox, "placeholder", {default = "...", type = "string"}) ComboBox.defineProperty(ComboBox, "placeholder", {default = "...", type = "string"})
---@property placeholderColor color gray Color of the placeholder text ---@property placeholderColor color gray Color used for placeholder text
ComboBox.defineProperty(ComboBox, "placeholderColor", {default = colors.gray, type = "color"}) ComboBox.defineProperty(ComboBox, "placeholderColor", {default = colors.gray, type = "color"})
---@property focusedBackground color blue Background color when ComboBox is focused ---@property focusedBackground color blue Background color when input is focused
ComboBox.defineProperty(ComboBox, "focusedBackground", {default = colors.blue, type = "color"}) ComboBox.defineProperty(ComboBox, "focusedBackground", {default = colors.blue, type = "color"})
---@property focusedForeground color white Foreground color when ComboBox is focused ---@property focusedForeground color white Text color when input is focused
ComboBox.defineProperty(ComboBox, "focusedForeground", {default = colors.white, type = "color"}) ComboBox.defineProperty(ComboBox, "focusedForeground", {default = colors.white, type = "color"})
---@property autoComplete boolean false Whether to enable auto-complete filtering when typing ---@property autoComplete boolean false Enables filtering dropdown items while typing
ComboBox.defineProperty(ComboBox, "autoComplete", {default = false, type = "boolean"}) ComboBox.defineProperty(ComboBox, "autoComplete", {default = false, type = "boolean"})
---@property manuallyOpened boolean false Whether the dropdown was manually opened (not by auto-complete) ---@property manuallyOpened boolean false Indicates if dropdown was opened by user action
ComboBox.defineProperty(ComboBox, "manuallyOpened", {default = false, type = "boolean"}) ComboBox.defineProperty(ComboBox, "manuallyOpened", {default = false, type = "boolean"})
--- Creates a new ComboBox instance --- Creates a new ComboBox instance
@@ -145,6 +155,7 @@ function ComboBox:updateFilteredDropdown()
end end
self:updateRender() self:updateRender()
end end
--- @shortDescription Updates the viewport --- @shortDescription Updates the viewport
--- @private --- @private
function ComboBox:updateViewport() function ComboBox:updateViewport()

View File

@@ -6,24 +6,28 @@ local split = require("libraries/utils").split
---@configDescription The container class. It is a visual element that can contain other elements. It is the base class for all containers ---@configDescription The container class. It is a visual element that can contain other elements. It is the base class for all containers
---@configDefault true ---@configDefault true
--- The Container class serves as a fundamental building block for organizing UI elements. It acts as a parent element that can hold and manage child elements. --- A fundamental layout element that manages child UI components. Containers handle element organization, event propagation,
--- @usage local container = basalt.getMainFrame() --- rendering hierarchy, and coordinate space management. They serve as the backbone of Basalt's UI structure by providing:
--- @usage container:addButton() -- Add a child element --- - Child element management and organization
--- - Event bubbling and distribution
--- - Visibility calculations and clipping
--- - Focus management
--- - Coordinate space transformation
---@class Container : VisualElement ---@class Container : VisualElement
local Container = setmetatable({}, VisualElement) local Container = setmetatable({}, VisualElement)
Container.__index = Container Container.__index = Container
---@property children table {} The children of the container ---@property children table {} Collection of all child elements
Container.defineProperty(Container, "children", {default = {}, type = "table"}) Container.defineProperty(Container, "children", {default = {}, type = "table"})
---@property childrenSorted boolean true Whether the children are sorted ---@property childrenSorted boolean true Indicates if children are sorted by z-index
Container.defineProperty(Container, "childrenSorted", {default = true, type = "boolean"}) Container.defineProperty(Container, "childrenSorted", {default = true, type = "boolean"})
---@property childrenEventsSorted boolean true Whether the children events are sorted ---@property childrenEventsSorted boolean true Indicates if event handlers are properly sorted
Container.defineProperty(Container, "childrenEventsSorted", {default = true, type = "boolean"}) Container.defineProperty(Container, "childrenEventsSorted", {default = true, type = "boolean"})
---@property childrenEvents table {} The children events of the container ---@property childrenEvents table {} Registered event handlers for all children
Container.defineProperty(Container, "childrenEvents", {default = {}, type = "table"}) Container.defineProperty(Container, "childrenEvents", {default = {}, type = "table"})
---@property eventListenerCount table {} The event listener count of the container ---@property eventListenerCount table {} Number of listeners per event type
Container.defineProperty(Container, "eventListenerCount", {default = {}, type = "table"}) Container.defineProperty(Container, "eventListenerCount", {default = {}, type = "table"})
---@property focusedChild table nil The focused child of the container ---@property focusedChild table nil Currently focused child element (receives keyboard events)
Container.defineProperty(Container, "focusedChild", {default = nil, type = "table", allowNil=true, setter = function(self, value, internal) Container.defineProperty(Container, "focusedChild", {default = nil, type = "table", allowNil=true, setter = function(self, value, internal)
local oldChild = self._values.focusedChild local oldChild = self._values.focusedChild
@@ -46,18 +50,18 @@ Container.defineProperty(Container, "focusedChild", {default = nil, type = "tabl
return value return value
end}) end})
---@property visibleChildren table {} The visible children of the container ---@property visibleChildren table {} Currently visible child elements (calculated based on viewport)
Container.defineProperty(Container, "visibleChildren", {default = {}, type = "table"}) Container.defineProperty(Container, "visibleChildren", {default = {}, type = "table"})
---@property visibleChildrenEvents table {} The visible children events of the container ---@property visibleChildrenEvents table {} Event handlers for currently visible children
Container.defineProperty(Container, "visibleChildrenEvents", {default = {}, type = "table"}) Container.defineProperty(Container, "visibleChildrenEvents", {default = {}, type = "table"})
---@property offsetX number 0 Horizontal content offset ---@property offsetX number 0 Horizontal scroll/content offset
Container.defineProperty(Container, "offsetX", {default = 0, type = "number", canTriggerRender = true, setter=function(self, value) Container.defineProperty(Container, "offsetX", {default = 0, type = "number", canTriggerRender = true, setter=function(self, value)
self.set("childrenSorted", false) self.set("childrenSorted", false)
self.set("childrenEventsSorted", false) self.set("childrenEventsSorted", false)
return value return value
end}) end})
---@property offsetY number 0 Vertical content offset ---@property offsetY number 0 Vertical scroll/content offset
Container.defineProperty(Container, "offsetY", {default = 0, type = "number", canTriggerRender = true, setter=function(self, value) Container.defineProperty(Container, "offsetY", {default = 0, type = "number", canTriggerRender = true, setter=function(self, value)
self.set("childrenSorted", false) self.set("childrenSorted", false)
self.set("childrenEventsSorted", false) self.set("childrenEventsSorted", false)
@@ -112,10 +116,10 @@ function Container:init(props, basalt)
end) end)
end end
--- Returns whether a child is visible --- Tests whether a child element is currently visible within the container's viewport
--- @shortDescription Returns whether a child is visible --- @shortDescription Checks if a child element is visible
--- @param child table The child to check --- @param child table The child element to check
--- @return boolean boolean the child is visible --- @return boolean isVisible Whether the child is within view bounds
function Container:isChildVisible(child) function Container:isChildVisible(child)
if not child:isType("VisualElement") then return false end if not child:isType("VisualElement") then return false end
if(child.get("visible") == false)then return false end if(child.get("visible") == false)then return false end
@@ -142,10 +146,10 @@ function Container:isChildVisible(child)
(relativeY <= containerH) (relativeY <= containerH)
end end
--- Adds a child to the container --- Adds a new element to this container's hierarchy
--- @shortDescription Adds a child to the container --- @shortDescription Adds a child element to the container
--- @param child table The child to add --- @param child table The element to add as a child
--- @return Container self The container instance --- @return Container self For method chaining
function Container:addChild(child) function Container:addChild(child)
if child == self then if child == self then
error("Cannot add container to itself") error("Cannot add container to itself")
@@ -188,9 +192,9 @@ local function sortAndFilterChildren(self, children)
return visibleChildren return visibleChildren
end end
--- Clears the container --- Removes all child elements and resets the container's state
--- @shortDescription Clears the container --- @shortDescription Removes all children and resets container
--- @return Container self The container instance --- @return Container self For method chaining
function Container:clear() function Container:clear()
self.set("children", {}) self.set("children", {})
self.set("childrenEvents", {}) self.set("childrenEvents", {})
@@ -201,9 +205,9 @@ function Container:clear()
return self return self
end end
--- Sorts the children of the container --- Re-sorts children by their z-index and updates visibility
--- @shortDescription Sorts the children of the container --- @shortDescription Updates child element ordering
--- @return Container self The container instance --- @return Container self For method chaining
function Container:sortChildren() function Container:sortChildren()
self.set("visibleChildren", sortAndFilterChildren(self, self._values.children)) self.set("visibleChildren", sortAndFilterChildren(self, self._values.children))
self.set("childrenSorted", true) self.set("childrenSorted", true)
@@ -234,11 +238,11 @@ function Container:registerChildrenEvents(child)
return self return self
end end
--- Registers the children events of the container --- Registers an event handler for a specific child element
--- @shortDescription Registers the children events of the container --- @shortDescription Sets up event handling for a child
--- @param child table The child to register events for --- @param child table The child element to register events for
--- @param eventName string The event name to register --- @param eventName string The name of the event to register
--- @return Container self The container instance --- @return Container self For method chaining
function Container:registerChildEvent(child, eventName) function Container:registerChildEvent(child, eventName)
if not self._values.childrenEvents[eventName] then if not self._values.childrenEvents[eventName] then
self._values.childrenEvents[eventName] = {} self._values.childrenEvents[eventName] = {}
@@ -304,10 +308,10 @@ function Container:unregisterChildEvent(child, eventName)
return self return self
end end
--- Removes a child from the container --- Removes an element from this container's hierarchy and cleans up its events
--- @shortDescription Removes a child from the container --- @shortDescription Removes a child element from the container
--- @param child table The child to remove --- @param child table The element to remove
--- @return Container self The container instance --- @return Container self For method chaining
function Container:removeChild(child) function Container:removeChild(child)
if child == nil then return self end if child == nil then return self end
for i,v in ipairs(self._values.children) do for i,v in ipairs(self._values.children) do
@@ -323,10 +327,10 @@ function Container:removeChild(child)
return self return self
end end
--- Removes a child from the container --- Locates a child element using a path-like syntax (e.g. "panel/button1")
--- @shortDescription Removes a child from the container --- @shortDescription Finds a child element by its path
--- @param path string The path to the child to remove --- @param path string Path to the child (e.g. "panel/button1", "header/title")
--- @return Container? self The container instance --- @return Element? child The found element or nil if not found
function Container:getChild(path) function Container:getChild(path)
if type(path) == "string" then if type(path) == "string" then
local parts = split(path, "/") local parts = split(path, "/")

View File

@@ -3,13 +3,37 @@ local VisualElement = elementManager.getElement("VisualElement")
local getCenteredPosition = require("libraries/utils").getCenteredPosition local getCenteredPosition = require("libraries/utils").getCenteredPosition
local deepcopy = require("libraries/utils").deepcopy local deepcopy = require("libraries/utils").deepcopy
local colorHex = require("libraries/colorHex") local colorHex = require("libraries/colorHex")
---@configDescription The Display is a special element which uses the cc window API which you can use. ---@configDescription The Display is a special element which uses the CC Window API which you can use.
---@configDefault false ---@configDefault false
--- The Display is a special element where you can use the window (term) API to draw on the display, useful when you need to use external APIs. --- A specialized element that provides direct access to ComputerCraft's Window API.
--- @usage local display = main:addDisplay() -- Create a display element --- It acts as a canvas where you can use standard CC terminal operations, making it ideal for:
--- @usage local displayWindow = display:getWindow() -- Get the window object of the display --- - Integration with existing CC programs and APIs
--- @usage displayWindow.write("Hello World!") -- Write "Hello World!" to the display --- - Custom drawing operations
--- - Terminal emulation
--- - Complex text manipulation
--- The Display maintains its own terminal buffer and can be manipulated using familiar CC terminal methods.
--- @usage -- Create a display for a custom terminal
--- @usage local display = main:addDisplay()
--- @usage :setSize(30, 10)
--- @usage :setPosition(2, 2)
--- @usage
--- @usage -- Get the window object for CC API operations
--- @usage local win = display:getWindow()
--- @usage
--- @usage -- Use standard CC terminal operations
--- @usage win.setTextColor(colors.yellow)
--- @usage win.setBackgroundColor(colors.blue)
--- @usage win.clear()
--- @usage win.setCursorPos(1, 1)
--- @usage win.write("Hello World!")
--- @usage
--- @usage -- Or use the helper method
--- @usage display:write(1, 2, "Direct write", colors.red, colors.black)
--- @usage
--- @usage -- Useful for external APIs
--- @usage local paintutils = require("paintutils")
--- @usage paintutils.drawLine(1, 1, 10, 1, colors.red, win)
---@class Display : VisualElement ---@class Display : VisualElement
local Display = setmetatable({}, VisualElement) local Display = setmetatable({}, VisualElement)
Display.__index = Display Display.__index = Display
@@ -79,21 +103,21 @@ function Display:init(props, basalt)
end) end)
end end
--- Returns the current window object --- Retrieves the underlying ComputerCraft window object
--- @shortDescription Returns the current window object --- @shortDescription Gets the CC window instance
--- @return table window The current window object --- @return table window A CC window object with all standard terminal methods
function Display:getWindow() function Display:getWindow()
return self._window return self._window
end end
--- Writes text to the display at the given position with the given foreground and background colors --- Writes text directly to the display with optional colors
--- @shortDescription Writes text to the display --- @shortDescription Writes colored text to the display
--- @param x number The x position to write to --- @param x number X position (1-based)
--- @param y number The y position to write to --- @param y number Y position (1-based)
--- @param text string The text to write --- @param text string Text to write
--- @param fg? colors The foreground color (optional) --- @param fg? colors Foreground color (optional)
--- @param bg? colors The background color (optional) --- @param bg? colors Background color (optional)
--- @return Display self The display instance --- @return Display self For method chaining
function Display:write(x, y, text, fg, bg) function Display:write(x, y, text, fg, bg)
local window = self._window local window = self._window
if window then if window then