Files
Basalt2/docs/references/elements/Dropdown.md
2025-02-16 14:12:49 +00:00

4.3 KiB

local VisualElement = require("elements/VisualElement") local List = require("elements/List") local tHex = require("libraries/colorHex")

---@class Dropdown : List local Dropdown = setmetatable({}, List) Dropdown.__index = Dropdown

Dropdown.defineProperty(Dropdown, "isOpen", {default = false, type = "boolean", canTriggerRender = true}) Dropdown.defineProperty(Dropdown, "dropdownHeight", {default = 5, type = "number"}) Dropdown.defineProperty(Dropdown, "selectedText", {default = "", type = "string"}) Dropdown.defineProperty(Dropdown, "dropSymbol", {default = "\31", type = "string"}) -- ▼ Symbol

function Dropdown.new() local self = setmetatable({}, Dropdown):__init() self.set("width", 16) self.set("height", 1) self.set("z", 8) return self end

function Dropdown:init(props, basalt) List.init(self, props, basalt) self.set("type", "Dropdown") end

function Dropdown:mouse_click(button, x, y) if not VisualElement.mouse_click(self, button, x, y) then return false end

local relX, relY = self:getRelativePosition(x, y)

if relY == 1 then  -- Klick auf Header
    self.set("isOpen", not self.get("isOpen"))
    if not self.get("isOpen") then
        self.set("height", 1)
    else
        self.set("height", 1 + math.min(self.get("dropdownHeight"), #self.get("items")))
    end
    return true
elseif self.get("isOpen") and relY > 1 then
    -- Offset für die Liste korrigieren (relY - 1 wegen Header)
    local index = relY - 1 + self.get("offset")
    local items = self.get("items")

    if index <= #items then
        local item = items[index]
        if type(item) == "table" and item.separator then
            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
return false

end

function Dropdown:render() VisualElement.render(self)

-- Header rendern
local text = self.get("selectedText")
if #text == 0 and self.get("selectedIndex") > 0 then
    local item = self.get("items")[self.get("selectedIndex")]
    text = type(item) == "table" and item.text or tostring(item)
end

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("background")], self.get("width")))

-- Items nur rendern wenn offen
if self.get("isOpen") then
    local items = self.get("items")
    local offset = self.get("offset")
    local selected = self.get("selectedIndex")
    local width = self.get("width")

    -- Liste ab Zeile 2 rendern (unterhalb des Headers)
    for i = 2, self.get("height") do
        local itemIndex = i - 1 + offset  -- -1 wegen Header
        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

return Dropdown