Basalt2 update

- Finished themes
- Added state plugins for persistance
- Finished reactive plugin
- Added debug plugin (80% finished)
- Added benchmark plugin
- Added Tree, Table, List, Dropdown and Menu Elements
- Bugfixes
This commit is contained in:
Robert Jelic
2025-02-15 18:18:49 +01:00
parent 8ea3ca2465
commit db716636bd
32 changed files with 1700 additions and 165 deletions

View File

@@ -164,7 +164,7 @@ end
--- @vararg any The arguments for the event
--- @return boolean? handled Whether the event was handled
function BaseElement:handleEvent(event, ...)
return true
return false
end
function BaseElement:getBaseFrame()

View File

@@ -21,9 +21,9 @@ end})
function BaseFrame.new(props, basalt)
local self = setmetatable({}, BaseFrame):__init()
self:init(props, basalt)
self.set("term", term.current())
self.set("background", colors.red)
self.set("background", colors.lightGray)
self:init(props, basalt)
return self
end

View File

@@ -11,13 +11,14 @@ Button.defineProperty(Button, "text", {default = "Button", type = "string", canT
---@event mouse_click The event that is triggered when the button is clicked
Button.listenTo(Button, "mouse_click")
Button.listenTo(Button, "mouse_up")
function Button.new(props, basalt)
local self = setmetatable({}, Button):__init()
self:init(props, basalt)
self.set("width", 10)
self.set("height", 3)
self.set("z", 5)
self:init(props, basalt)
return self
end

View File

@@ -15,9 +15,9 @@ Checkbox.listenTo(Checkbox, "mouse_click")
function Checkbox.new(props, basalt)
local self = setmetatable({}, Checkbox):__init()
self:init(props, basalt)
self.set("width", 1)
self.set("height", 1)
self:init(props, basalt)
return self
end

View File

@@ -44,9 +44,9 @@ function Container:isChildVisible(child)
local childW, childH = child.get("width"), child.get("height")
local containerW, containerH = self.get("width"), self.get("height")
return childX <= containerW and
childY <= containerH and
childX + childW > 0 and
return childX <= containerW and
childY <= containerH and
childX + childW > 0 and
childY + childH > 0
end
@@ -94,7 +94,7 @@ local function sortAndFilterChildren(self, children)
local visibleChildren = {}
for _, child in ipairs(children) do
if self:isChildVisible(child) then
if self:isChildVisible(child) and child.get("visible") then
table.insert(visibleChildren, child)
end
end
@@ -103,7 +103,6 @@ local function sortAndFilterChildren(self, children)
local current = visibleChildren[i]
local currentZ = current.get("z")
local j = i - 1
while j > 0 do
local compare = visibleChildren[j].get("z")
if compare > currentZ then
@@ -119,6 +118,15 @@ local function sortAndFilterChildren(self, children)
return visibleChildren
end
function Container:clear()
self.set("children", {})
self.set("childrenEvents", {})
self.set("visibleChildren", {})
self.set("visibleChildrenEvents", {})
self.set("childrenSorted", true)
self.set("childrenEventsSorted", true)
end
function Container:sortChildren()
self.set("visibleChildren", sortAndFilterChildren(self, self._values.children))
self.set("childrenSorted", true)
@@ -234,7 +242,7 @@ local function callChildrenEvents(self, visibleOnly, event, ...)
for i = #events, 1, -1 do
local child = events[i]
if(child:dispatchEvent(event, ...))then
return true, child
return true, child
end
end
end
@@ -242,12 +250,12 @@ local function callChildrenEvents(self, visibleOnly, event, ...)
end
function Container:handleEvent(event, ...)
if(VisualElement.handleEvent(self, event, ...))then
local args = convertMousePosition(self, event, ...)
return callChildrenEvents(self, false, event, table.unpack(args))
end
VisualElement.handleEvent(self, event, ...)
local args = convertMousePosition(self, event, ...)
return callChildrenEvents(self, false, event, table.unpack(args))
end
function Container:mouse_click(button, x, y)
if VisualElement.mouse_click(self, button, x, y) then
local args = convertMousePosition(self, "mouse_click", button, x, y)
@@ -260,6 +268,16 @@ function Container:mouse_click(button, x, y)
end
end
function Container:mouse_up(button, x, y)
if VisualElement.mouse_up(self, button, x, y) then
local args = convertMousePosition(self, "mouse_up", button, x, y)
local success, child = callChildrenEvents(self, true, "mouse_up", table.unpack(args))
if(success)then
return true
end
end
end
function Container:key(key)
if self.get("focusedChild") then
return self.get("focusedChild"):dispatchEvent("key", key)

122
src/elements/Dropdown.lua Normal file
View File

@@ -0,0 +1,122 @@
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(props, basalt)
local self = setmetatable({}, Dropdown):__init()
self.set("width", 16)
self.set("height", 1) -- Dropdown ist initial nur 1 Zeile hoch
self.set("z", 8)
self:init(props, basalt)
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

View File

@@ -232,13 +232,13 @@ end
--- @usage local element = Flexbox.new("myId", basalt)
function Flexbox.new(props, basalt)
local self = setmetatable({}, Flexbox):__init()
self:init(props, basalt)
self.set("width", 12)
self.set("height", 6)
self.set("background", colors.blue)
self.set("z", 10)
self:observe("width", function() self.set("flexUpdateLayout", true) end)
self:observe("height", function() self.set("flexUpdateLayout", true) end)
self:init(props, basalt)
return self
end

View File

@@ -12,11 +12,11 @@ Frame.__index = Frame
--- @usage local element = Frame.new("myId", basalt)
function Frame.new(props, basalt)
local self = setmetatable({}, Frame):__init()
self:init(props, basalt)
self.set("width", 12)
self.set("height", 6)
self.set("background", colors.blue)
self.set("background", colors.gray)
self.set("z", 10)
self:init(props, basalt)
return self
end

View File

@@ -32,9 +32,9 @@ Input.listenTo(Input, "char")
--- @usage local element = Input.new("myId", basalt)
function Input.new(props, basalt)
local self = setmetatable({}, Input):__init()
self:init(id, basalt)
self.set("width", 8)
self.set("z", 3)
self:init(id, basalt)
return self
end

View File

@@ -7,6 +7,7 @@ Label.__index = Label
---@property text string Label Label text to be displayed
Label.defineProperty(Label, "text", {default = "Label", type = "string", setter = function(self, value)
if(type(value)=="function")then value = value() end
self.set("width", #value)
return value
end})
@@ -18,9 +19,10 @@ end})
--- @usage local element = Label.new("myId", basalt)
function Label.new(props, basalt)
local self = setmetatable({}, Label):__init()
self:init(props, basalt)
self.set("z", 3)
self.set("foreground", colors.black)
self.set("backgroundEnabled", false)
self:init(props, basalt)
return self
end

View File

@@ -20,9 +20,10 @@ List.listenTo(List, "mouse_scroll")
function List.new(props, basalt)
local self = setmetatable({}, List):__init()
self:init(props, basalt)
self.set("width", 16)
self.set("height", 8)
self.set("background", colors.gray)
self:init(props, basalt)
return self
end
@@ -54,16 +55,25 @@ end
function List:mouse_click(button, x, y)
if button == 1 and self:isInBounds(x, y) and self.get("selectable") then
local relY = self:getRelativePosition(x, y)
local index = relY + self.get("offset")
local _, index = self:getRelativePosition(x, y)
if index <= #self.get("items") then
self.set("selectedIndex", index)
self:fireEvent("select", index, self.get("items")[index])
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
function List:mouse_scroll(direction, x, y)
@@ -77,24 +87,47 @@ function List:mouse_scroll(direction, x, y)
end
end
function List:onSelect(callback)
self:registerCallback("select", callback)
return self
end
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 itemIndex == selected then
self:textBg(1, i, string.rep(" ", self.get("width")), self.get("selectedColor"))
self:textFg(1, i, item, colors.white)
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
self:textFg(1, i, item, self.get("foreground"))
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

91
src/elements/Menu.lua Normal file
View File

@@ -0,0 +1,91 @@
local VisualElement = require("elements/VisualElement")
local List = require("elements/List")
local tHex = require("libraries/colorHex")
---@class Menu : List
local Menu = setmetatable({}, List)
Menu.__index = Menu
Menu.defineProperty(Menu, "separatorColor", {default = colors.gray, type = "number"})
function Menu.new(props, basalt)
local self = setmetatable({}, Menu):__init()
self.set("width", 30)
self.set("height", 1)
self.set("background", colors.gray)
self:init(props, basalt)
return self
end
function Menu:init(props, basalt)
List.init(self, props, basalt)
self.set("type", "Menu")
return self
end
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
function Menu:render()
VisualElement.render(self)
local currentX = 1
for i, item in ipairs(self.get("items")) do
local isSelected = i == self.get("selectedIndex")
local fg = item.selectable == false and self.get("separatorColor") or
(isSelected and (item.selectedForeground or self.get("foreground")) or
(item.foreground or self.get("foreground")))
local bg = isSelected and
(item.selectedBackground or self.get("selectedColor")) 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
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
self.set("selectedIndex", i)
if type(item) == "table" then
if item.callback then
item.callback(self)
end
end
self:fireEvent("select", i, item)
end
return true
end
currentX = currentX + #item.text
end
return false
end
return Menu

View File

@@ -13,9 +13,9 @@ ProgressBar.defineProperty(ProgressBar, "progressColor", {default = colors.lime,
function ProgressBar.new(props, basalt)
local self = setmetatable({}, ProgressBar):__init()
self:init(props, basalt)
self.set("width", 10)
self.set("height", 1)
self:init(props, basalt)
return self
end

View File

@@ -21,10 +21,10 @@ Slider.listenTo(Slider, "mouse_up")
function Slider.new(props, basalt)
local self = setmetatable({}, Slider):__init()
self:init(props, basalt)
self.set("width", 8)
self.set("height", 1)
self.set("backgroundEnabled", false)
self:init(props, basalt)
return self
end

182
src/elements/Table.lua Normal file
View File

@@ -0,0 +1,182 @@
local VisualElement = require("elements/VisualElement")
local tHex = require("libraries/colorHex")
---@class Table : VisualElement
local Table = setmetatable({}, VisualElement)
Table.__index = Table
Table.defineProperty(Table, "columns", {default = {}, type = "table"})
Table.defineProperty(Table, "data", {default = {}, type = "table", canTriggerRender = true})
Table.defineProperty(Table, "selectedRow", {default = nil, type = "number", canTriggerRender = true})
Table.defineProperty(Table, "headerColor", {default = colors.blue, type = "number"})
Table.defineProperty(Table, "selectedColor", {default = colors.lightBlue, type = "number"})
Table.defineProperty(Table, "gridColor", {default = colors.gray, type = "number"})
Table.defineProperty(Table, "sortColumn", {default = nil, type = "number"})
Table.defineProperty(Table, "sortDirection", {default = "asc", type = "string"})
Table.defineProperty(Table, "scrollOffset", {default = 0, type = "number", canTriggerRender = true})
Table.listenTo(Table, "mouse_click")
Table.listenTo(Table, "mouse_scroll")
function Table.new(props, basalt)
local self = setmetatable({}, Table):__init()
self.set("width", 30)
self.set("height", 10)
self.set("z", 5)
self:init(props, basalt)
return self
end
function Table:init(props, basalt)
VisualElement.init(self, props, basalt)
self.set("type", "Table")
return self
end
function Table:setColumns(columns)
-- Columns Format: {{name="ID", width=4}, {name="Name", width=10}}
self.set("columns", columns)
return self
end
function Table:setData(data)
-- Data Format: {{"1", "Item One"}, {"2", "Item Two"}}
self.set("data", data)
return self
end
function Table:sortData(columnIndex)
local data = self.get("data")
local direction = self.get("sortDirection")
table.sort(data, function(a, b)
if direction == "asc" then
return a[columnIndex] < b[columnIndex]
else
return a[columnIndex] > b[columnIndex]
end
end)
self.set("data", data)
return self
end
function Table: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)
-- Header-Click für Sorting
if relY == 1 then
local currentX = 1
for i, col in ipairs(self.get("columns")) do
if relX >= currentX and relX < currentX + col.width then
if self.get("sortColumn") == i then
self.set("sortDirection", self.get("sortDirection") == "asc" and "desc" or "asc")
else
self.set("sortColumn", i)
self.set("sortDirection", "asc")
end
self:sortData(i)
break
end
currentX = currentX + col.width
end
end
-- Row-Selection (berücksichtigt Scroll-Offset)
if relY > 1 then
local rowIndex = relY - 2 + self.get("scrollOffset")
if rowIndex >= 0 and rowIndex < #self.get("data") then
self.set("selectedRow", rowIndex + 1)
end
end
return true
end
function Table:mouse_scroll(direction, x, y)
local data = self.get("data")
local height = self.get("height")
local visibleRows = height - 2
local maxScroll = math.max(0, #data - visibleRows + 1) -- +1 korrigiert den Scroll-Bereich
local newOffset = math.min(maxScroll, math.max(0, self.get("scrollOffset") + direction))
self.set("scrollOffset", newOffset)
return true
end
function Table:render()
VisualElement.render(self)
local columns = self.get("columns")
local data = self.get("data")
local selected = self.get("selectedRow")
local sortCol = self.get("sortColumn")
local scrollOffset = self.get("scrollOffset")
local height = self.get("height")
local currentX = 1
for i, col in ipairs(columns) do
local text = col.name
if i == sortCol then
text = text .. (self.get("sortDirection") == "asc" and "\30" or "\31")
end
self:textFg(currentX, 1, text:sub(1, col.width), self.get("headerColor"))
currentX = currentX + col.width
end
-- Angepasste Berechnung der sichtbaren Zeilen
local visibleRows = height - 2 -- Verfügbare Zeilen (minus Header)
for y = 2, height do
local rowIndex = y - 2 + scrollOffset
local rowData = data[rowIndex + 1]
-- Zeile nur rendern wenn es auch Daten dafür gibt
if rowData and (rowIndex + 1) <= #data then -- Korrigierte Bedingung
currentX = 1
local bg = (rowIndex + 1) == selected and self.get("selectedColor") or self.get("background")
for i, col in ipairs(columns) do
local cellText = rowData[i] or ""
local paddedText = cellText .. string.rep(" ", col.width - #cellText)
self:blit(currentX, y, paddedText,
string.rep(tHex[self.get("foreground")], col.width),
string.rep(tHex[bg], col.width))
currentX = currentX + col.width
end
else
-- Leere Zeile füllen
self:blit(1, y, string.rep(" ", self.get("width")),
string.rep(tHex[self.get("foreground")], self.get("width")),
string.rep(tHex[self.get("background")], self.get("width")))
end
end
-- Scrollbar Berechnung überarbeitet
if #data > height - 2 then
local scrollbarHeight = height - 2
local thumbSize = math.max(1, math.floor(scrollbarHeight * (height - 2) / #data))
-- Thumb Position korrigiert
local maxScroll = #data - (height - 2) + 1 -- +1 für korrekte End-Position
local scrollPercent = scrollOffset / maxScroll
local thumbPos = 2 + math.floor(scrollPercent * (scrollbarHeight - thumbSize))
if scrollOffset >= maxScroll then
thumbPos = height - thumbSize -- Exakt am Ende
end
-- Scrollbar Background
for y = 2, height do
self:blit(self.get("width"), y, "\127", tHex[colors.gray], tHex[colors.gray])
end
-- Thumb zeichnen
for y = thumbPos, math.min(height, thumbPos + thumbSize - 1) do
self:blit(self.get("width"), y, "\127", tHex[colors.white], tHex[colors.white])
end
end
end
return Table

147
src/elements/Tree.lua Normal file
View File

@@ -0,0 +1,147 @@
local VisualElement = require("elements/VisualElement")
local tHex = require("libraries/colorHex")
---@class Tree : VisualElement
local Tree = setmetatable({}, VisualElement)
Tree.__index = Tree
Tree.defineProperty(Tree, "nodes", {default = {}, type = "table", canTriggerRender = true})
Tree.defineProperty(Tree, "selectedNode", {default = nil, type = "table", canTriggerRender = true})
Tree.defineProperty(Tree, "expandedNodes", {default = {}, type = "table", canTriggerRender = true})
Tree.defineProperty(Tree, "scrollOffset", {default = 0, type = "number", canTriggerRender = true})
Tree.defineProperty(Tree, "nodeColor", {default = colors.white, type = "number"})
Tree.defineProperty(Tree, "selectedColor", {default = colors.lightBlue, type = "number"})
Tree.listenTo(Tree, "mouse_click")
Tree.listenTo(Tree, "mouse_scroll")
function Tree.new(props, basalt)
local self = setmetatable({}, Tree):__init()
self.set("width", 30)
self.set("height", 10)
self.set("z", 5)
self:init(props, basalt)
return self
end
function Tree:init(props, basalt)
VisualElement.init(self, props, basalt)
self.set("type", "Tree")
return self
end
function Tree:setNodes(nodes)
self.set("nodes", nodes)
if #nodes > 0 then
self.get("expandedNodes")[nodes[1]] = true
end
return self
end
function Tree:expandNode(node)
self.get("expandedNodes")[node] = true
self:updateRender()
return self
end
function Tree:collapseNode(node)
self.get("expandedNodes")[node] = nil
self:updateRender()
return self
end
function Tree:toggleNode(node)
if self.get("expandedNodes")[node] then
self:collapseNode(node)
else
self:expandNode(node)
end
return self
end
local function flattenTree(nodes, expandedNodes, level, result)
result = result or {}
level = level or 0
for _, node in ipairs(nodes) do
table.insert(result, {node = node, level = level})
if expandedNodes[node] and node.children then
flattenTree(node.children, expandedNodes, level + 1, result)
end
end
return result
end
function Tree: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)
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
local visibleIndex = relY + self.get("scrollOffset")
if flatNodes[visibleIndex] then
local nodeInfo = flatNodes[visibleIndex]
local node = nodeInfo.node
if relX <= nodeInfo.level * 2 + 2 then
self:toggleNode(node)
end
self.set("selectedNode", node)
self:fireEvent("node_select", node)
end
return true
end
function Tree:onSelect(callback)
self:registerCallback("node_select", callback)
return self
end
function Tree:mouse_scroll(direction)
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
local maxScroll = math.max(0, #flatNodes - self.get("height"))
local newScroll = math.min(maxScroll, math.max(0, self.get("scrollOffset") + direction))
self.set("scrollOffset", newScroll)
return true
end
function Tree:render()
VisualElement.render(self)
local flatNodes = flattenTree(self.get("nodes"), self.get("expandedNodes"))
local height = self.get("height")
local selectedNode = self.get("selectedNode")
local expandedNodes = self.get("expandedNodes")
local scrollOffset = self.get("scrollOffset")
for y = 1, height do
local nodeInfo = flatNodes[y + scrollOffset]
if nodeInfo then
local node = nodeInfo.node
local level = nodeInfo.level
local indent = string.rep(" ", level)
-- Expand/Collapse Symbol
local symbol = " "
if node.children and #node.children > 0 then
symbol = expandedNodes[node] and "\31" or "\16"
end
local bg = node == selectedNode and self.get("selectedColor") or self.get("background")
local text = indent .. symbol .." " .. (node.text or "Node")
self:blit(1, y, text .. string.rep(" ", self.get("width") - #text),
string.rep(tHex[self.get("nodeColor")], self.get("width")),
string.rep(tHex[bg], self.get("width")))
else
-- Leere Zeile
self:blit(1, y, string.rep(" ", self.get("width")),
string.rep(tHex[self.get("foreground")], self.get("width")),
string.rep(tHex[self.get("background")], self.get("width")))
end
end
end
return Tree

View File

@@ -53,6 +53,18 @@ VisualElement.defineProperty(VisualElement, "focused", {default = false, type =
return value
end})
VisualElement.defineProperty(VisualElement, "visible", {default = true, type = "boolean", canTriggerRender = true, setter=function(self, value)
if(self.parent~=nil)then
self.parent.set("childrenSorted", false)
self.parent.set("childrenEventsSorted", false)
end
return value
end})
VisualElement.combineProperties(VisualElement, "position", "x", "y")
VisualElement.combineProperties(VisualElement, "size", "width", "height")
VisualElement.combineProperties(VisualElement, "color", "foreground", "background")
VisualElement.listenTo(VisualElement, "focus")
VisualElement.listenTo(VisualElement, "blur")
@@ -66,7 +78,6 @@ local max, min = math.max, math.min
function VisualElement.new(props, basalt)
local self = setmetatable({}, VisualElement):__init()
self:init(props, basalt)
self.set("type", "VisualElement")
return self
end
@@ -139,8 +150,8 @@ function VisualElement:mouse_click(button, x, y)
end
function VisualElement:mouse_up(button, x, y)
self.set("clicked", false)
if self:isInBounds(x, y) then
self.set("clicked", false)
self:fireEvent("mouse_up", button, x, y)
return true
end