133 lines
4.5 KiB
Lua
133 lines
4.5 KiB
Lua
local VisualElement = require("elements/VisualElement")
|
|
local List = require("elements/List")
|
|
local tHex = require("libraries/colorHex")
|
|
---@configDescription A horizontal menu bar with selectable items.
|
|
|
|
--- This is the menu class. It provides a horizontal menu bar with selectable items.
|
|
--- Menu items are displayed in a single row and can have custom colors and callbacks.
|
|
---@class Menu : List
|
|
local Menu = setmetatable({}, List)
|
|
Menu.__index = Menu
|
|
|
|
---@property separatorColor color gray The color used for separator items in the menu
|
|
Menu.defineProperty(Menu, "separatorColor", {default = colors.gray, type = "color"})
|
|
|
|
--- Creates a new Menu instance
|
|
--- @shortDescription Creates a new Menu instance
|
|
--- @return Menu self The newly created Menu instance
|
|
--- @private
|
|
function Menu.new()
|
|
local self = setmetatable({}, Menu):__init()
|
|
self.set("width", 30)
|
|
self.set("height", 1)
|
|
self.set("background", colors.gray)
|
|
return self
|
|
end
|
|
|
|
--- @shortDescription Initializes the Menu instance
|
|
--- @param props table The properties to initialize the element with
|
|
--- @param basalt table The basalt instance
|
|
--- @return Menu self The initialized instance
|
|
--- @protected
|
|
function Menu:init(props, basalt)
|
|
List.init(self, props, basalt)
|
|
self.set("type", "Menu")
|
|
return self
|
|
end
|
|
|
|
--- Sets the menu items
|
|
--- @shortDescription Sets the menu items and calculates total width
|
|
--- @param items table[] List of items with {text, separator, callback, foreground, background} properties
|
|
--- @return Menu self The Menu instance
|
|
--- @usage menu:setItems({{text="File"}, {separator=true}, {text="Edit"}})
|
|
function Menu:setItems(items)
|
|
local listItems = {}
|
|
local totalWidth = 0
|
|
for _, item in ipairs(items) do
|
|
if item.separator then
|
|
table.insert(listItems, {text = item.text or "|", selectable = false})
|
|
totalWidth = totalWidth + 1
|
|
else
|
|
local text = " " .. item.text .. " "
|
|
item.text = text
|
|
table.insert(listItems, item)
|
|
totalWidth = totalWidth + #text
|
|
end
|
|
end
|
|
self.set("width", totalWidth)
|
|
return List.setItems(self, listItems)
|
|
end
|
|
|
|
--- @shortDescription Renders the menu horizontally with proper spacing and colors
|
|
--- @protected
|
|
function Menu:render()
|
|
VisualElement.render(self)
|
|
local currentX = 1
|
|
|
|
for _, item in ipairs(self.get("items")) do
|
|
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
|
|
(isSelected and (item.selectedForeground or self.get("selectedForeground")) or
|
|
(item.foreground or self.get("foreground")))
|
|
|
|
local bg = isSelected and
|
|
(item.selectedBackground or self.get("selectedBackground")) or
|
|
(item.background or self.get("background"))
|
|
|
|
self:blit(currentX, 1, item.text,
|
|
string.rep(tHex[fg], #item.text),
|
|
string.rep(tHex[bg], #item.text))
|
|
|
|
currentX = currentX + #item.text
|
|
end
|
|
end
|
|
|
|
--- @shortDescription Handles mouse click events and item selection
|
|
--- @param button number The button that was clicked
|
|
--- @param x number The x position of the click
|
|
--- @param y number The y position of the click
|
|
--- @return boolean Whether the event was handled
|
|
--- @protected
|
|
function Menu:mouse_click(button, x, y)
|
|
if not VisualElement.mouse_click(self, button, x, y) then return false end
|
|
if(self.get("selectable") == false) then return false end
|
|
local relX = select(1, self:getRelativePosition(x, y))
|
|
local currentX = 1
|
|
|
|
for i, item in ipairs(self.get("items")) do
|
|
if relX >= currentX and relX < currentX + #item.text then
|
|
if item.selectable ~= false then
|
|
if type(item) == "string" then
|
|
item = {text = item}
|
|
self.get("items")[i] = item
|
|
end
|
|
|
|
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
|
|
|
|
item.selected = not item.selected
|
|
|
|
if item.callback then
|
|
item.callback(self)
|
|
end
|
|
self:fireEvent("select", i, item)
|
|
end
|
|
return true
|
|
end
|
|
currentX = currentX + #item.text
|
|
end
|
|
return false
|
|
end
|
|
|
|
return Menu
|