183 lines
6.6 KiB
Lua
183 lines
6.6 KiB
Lua
local VisualElement = require("elements/VisualElement")
|
|
|
|
--- This is the list class. It provides a scrollable list of selectable items with support for
|
|
--- custom item rendering, separators, and selection handling.
|
|
---@class List : VisualElement
|
|
local List = setmetatable({}, VisualElement)
|
|
List.__index = List
|
|
|
|
---@property items table {} List of items to display. Items can be strings or tables with properties
|
|
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
|
|
List.defineProperty(List, "selectable", {default = true, type = "boolean"})
|
|
---@property offset number 0 Current scroll offset for viewing long lists
|
|
List.defineProperty(List, "offset", {default = 0, type = "number", canTriggerRender = true})
|
|
---@property selectedColor color blue Background color for the selected item
|
|
List.defineProperty(List, "selectedColor", {default = colors.blue, type = "number"})
|
|
|
|
---@event onSelect {index number, item any} Fired when an item is selected
|
|
List.listenTo(List, "mouse_click")
|
|
List.listenTo(List, "mouse_scroll")
|
|
|
|
--- Creates a new List instance
|
|
--- @shortDescription Creates a new List instance
|
|
--- @return List self The newly created List instance
|
|
--- @usage local list = List.new()
|
|
function List.new()
|
|
local self = setmetatable({}, List):__init()
|
|
self.set("width", 16)
|
|
self.set("height", 8)
|
|
self.set("background", colors.gray)
|
|
return self
|
|
end
|
|
|
|
--- Initializes the List instance
|
|
--- @shortDescription Initializes the List instance
|
|
--- @param props table The properties to initialize the element with
|
|
--- @param basalt table The basalt instance
|
|
--- @return List self The initialized instance
|
|
function List:init(props, basalt)
|
|
VisualElement.init(self, props, basalt)
|
|
self.set("type", "List")
|
|
end
|
|
|
|
--- Adds an item to the list
|
|
--- @shortDescription Adds an item to the list
|
|
--- @param text string|table The item to add (string or item table)
|
|
--- @return List self The List instance
|
|
--- @usage list:addItem("New Item")
|
|
--- @usage list:addItem({text="Item", callback=function() end})
|
|
function List:addItem(text)
|
|
local items = self.get("items")
|
|
table.insert(items, text)
|
|
self:updateRender()
|
|
return self
|
|
end
|
|
|
|
--- Removes an item from the list
|
|
--- @shortDescription Removes an item from the list
|
|
--- @param index number The index of the item to remove
|
|
--- @return List self The List instance
|
|
--- @usage list:removeItem(1)
|
|
function List:removeItem(index)
|
|
local items = self.get("items")
|
|
table.remove(items, index)
|
|
self:updateRender()
|
|
return self
|
|
end
|
|
|
|
--- Clears all items from the list
|
|
--- @shortDescription Clears all items from the list
|
|
--- @return List self The List instance
|
|
--- @usage list:clear()
|
|
function List:clear()
|
|
self.set("items", {})
|
|
self.set("selectedIndex", 0)
|
|
self:updateRender()
|
|
return self
|
|
end
|
|
|
|
--- Handles mouse click events
|
|
--- @shortDescription Handles mouse click events
|
|
--- @param button number The mouse button that was clicked
|
|
--- @param x number The x-coordinate of the click
|
|
--- @param y number The y-coordinate of the click
|
|
--- @return boolean Whether the event was handled
|
|
function List:mouse_click(button, x, y)
|
|
if button == 1 and self:isInBounds(x, y) and self.get("selectable") then
|
|
local _, index = self:getRelativePosition(x, y)
|
|
|
|
local adjustedIndex = index + self.get("offset")
|
|
local items = self.get("items")
|
|
|
|
if adjustedIndex <= #items then
|
|
local item = items[adjustedIndex]
|
|
self.set("selectedIndex", adjustedIndex)
|
|
|
|
if type(item) == "table" and item.callback then
|
|
item.callback(self)
|
|
end
|
|
|
|
self:fireEvent("select", adjustedIndex, item)
|
|
self:updateRender()
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
--- Handles mouse scroll events
|
|
--- @shortDescription Handles mouse scroll events
|
|
--- @param direction number The direction of the scroll (1 for down, -1 for up)
|
|
--- @param x number The x-coordinate of the scroll
|
|
--- @param y number The y-coordinate of the scroll
|
|
--- @return boolean Whether the event was handled
|
|
function List:mouse_scroll(direction, x, y)
|
|
if self:isInBounds(x, y) then
|
|
local offset = self.get("offset")
|
|
local maxOffset = math.max(0, #self.get("items") - self.get("height"))
|
|
|
|
offset = math.min(maxOffset, math.max(0, offset + direction))
|
|
self.set("offset", offset)
|
|
return true
|
|
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 List self The List instance
|
|
--- @usage list:onSelect(function(index, item) print("Selected item:", index, item) end)
|
|
function List:onSelect(callback)
|
|
self:registerCallback("select", callback)
|
|
return self
|
|
end
|
|
|
|
--- Renders the list
|
|
--- @shortDescription Renders the list
|
|
function List:render()
|
|
VisualElement.render(self)
|
|
|
|
local items = self.get("items")
|
|
local height = self.get("height")
|
|
local offset = self.get("offset")
|
|
local selected = self.get("selectedIndex")
|
|
local width = self.get("width")
|
|
|
|
for i = 1, height do
|
|
local itemIndex = i + offset
|
|
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 text = type(item) == "table" and item.text or 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, text, fg)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return List
|