Files
Basalt2/src/elements/Breadcrumb.lua
Robert Jelic 2ca7ad1e4c - Added comprehensive state management with conditional states, priority-based resolution, and property overrides
- Added responsive.lua with fluent builder API (:when()/:apply()/:otherwise()) for creating responsive layouts that react to parent size or custom conditions
- All elements now use getResolved() to check active states, enabling multiple responsive rules to coexist
2025-11-04 22:40:37 +01:00

126 lines
4.4 KiB
Lua

local elementManager = require("elementManager")
local VisualElement = elementManager.getElement("VisualElement")
---@configDescription A breadcrumb navigation element that displays the current path.
---@configDefault false
---@class Breadcrumb : VisualElement
local Breadcrumb = setmetatable({}, VisualElement)
Breadcrumb.__index = Breadcrumb
---@property path table {} Array of strings representing the breadcrumb segments
Breadcrumb.defineProperty(Breadcrumb, "path", {default = {}, type = "table", canTriggerRender = true})
---@property separator > string Character(s) separating path segments
Breadcrumb.defineProperty(Breadcrumb, "separator", {default = " > ", type = "string", canTriggerRender = true})
---@property clickable true boolean Whether the segments are clickable
Breadcrumb.defineProperty(Breadcrumb, "clickable", {default = true, type = "boolean"})
---@property autoSize false boolean Whether to resize the element width automatically based on text
Breadcrumb.defineProperty(Breadcrumb, "autoSize", {default = true, type = "boolean"})
Breadcrumb.defineEvent(Breadcrumb, "mouse_click")
Breadcrumb.defineEvent(Breadcrumb, "mouse_up")
--- @shortDescription Creates a new Breadcrumb instance
--- @return table self
function Breadcrumb.new()
local self = setmetatable({}, Breadcrumb):__init()
self.class = Breadcrumb
self.set("z", 5)
self.set("height", 1)
self.set("backgroundEnabled", false)
return self
end
--- @shortDescription Initializes the Breadcrumb instance
--- @param props table
--- @param basalt table
function Breadcrumb:init(props, basalt)
VisualElement.init(self, props, basalt)
self.set("type", "Breadcrumb")
end
--- @shortDescription Handles mouse click events
--- @param button number
--- @param x number
--- @param y number
--- @return boolean handled
function Breadcrumb:mouse_click(button, x, y)
if not self.getResolved("clickable") then return false end
if VisualElement.mouse_click(self, button, x, y) then
local path = self.getResolved("path")
local separator = self.getResolved("separator")
local cursorX = 1
for i, segment in ipairs(path) do
local segLen = #segment
if x >= cursorX and x < cursorX + segLen then
self:fireEvent("select",
i,
{table.unpack(path, 1, i)}
)
return true
end
cursorX = cursorX + segLen
if i < #path then
cursorX = cursorX + #separator
end
end
end
return false
end
--- Registers a callback for the select event
--- @shortDescription Registers a callback for the select event
--- @param callback function The callback function to register
--- @return Breadcrumb self The Breadcrumb instance
--- @usage breadcrumb:onSelect(function(segmentIndex, path) print("Navigated to segment:", segmentIndex, path) end)
function Breadcrumb:onSelect(callback)
self:registerCallback("select", callback)
return self
end
--- @shortDescription Renders the breadcrumb trail
--- @protected
function Breadcrumb:render()
local path = self.getResolved("path")
local separator = self.getResolved("separator")
local fg = self.getResolved("foreground")
local clickable = self.getResolved("clickable")
local width = self.getResolved("width")
local fullText = ""
for i, segment in ipairs(path) do
fullText = fullText .. segment
if i < #path then
fullText = fullText .. separator
end
end
if self.getResolved("autoSize") then
self.getResolved("width", #fullText)
else
if #fullText > width then
local ellipsis = "... > "
local maxTextLen = width - #ellipsis
if maxTextLen > 0 then
fullText = ellipsis .. fullText:sub(-maxTextLen)
else
fullText = ellipsis:sub(1, width)
end
end
end
local cursorX = 1
local color
for word in fullText:gmatch("[^"..separator.."]+") do
color = fg
self:textFg(cursorX, 1, word, color)
cursorX = cursorX + #word
local sepStart = fullText:find(separator, cursorX, true)
if sepStart then
self:textFg(cursorX, 1, separator, clickable and colors.gray or colors.lightGray)
cursorX = cursorX + #separator
end
end
end
return Breadcrumb