Files
Basalt/Basalt/objects/Treeview.lua
2023-07-05 16:50:41 +02:00

291 lines
10 KiB
Lua

local utils = require("utils")
local tHex = require("tHex")
return function(name, basalt)
local base = basalt.getObject("ChangeableObject")(name, basalt)
base:setType("Treeview")
base:addProperty("Nodes", "table", {})
base:addProperty("SelectionBackground", "color", colors.black)
base:addProperty("SelectionForeground", "color", colors.lightGray)
base:combineProperty("SelectionColor", "SelectionBackground", "SelectionForeground")
base:addProperty("XOffset", "number", 0)
base:addProperty("YOffset", "number", 0)
base:combineProperty("Offset", "XOffset", "YOffset")
base:addProperty("Scrollable", "boolean", true)
base:addProperty("TextAlign", {"left", "center", "right"}, "left")
base:addProperty("ExpandableSymbol", "char", "\7")
base:addProperty("ExpandableSymbolForeground", "color", colors.lightGray)
base:addProperty("ExpandableSymbolBackground", "color", colors.black)
base:combineProperty("ExpandableSymbolColor", "ExpandableSymbolForeground", "ExpandableSymbolBackground")
base:addProperty("ExpandedSymbol", "char", "\8")
base:addProperty("ExpandedSymbolForeground", "color", colors.lightGray)
base:addProperty("ExpandedSymbolBackground", "color", colors.black)
base:combineProperty("ExpandedSymbolColor", "ExpandedSymbolForeground", "ExpandedSymbolBackground")
base:addProperty("ExpandableSymbolSpacing", "number", 1)
base:addProperty("selectionColorActive", "boolean", true)
base:setSize(16, 8)
base:setZ(5)
local function newNode(text, expandable)
text = text or ""
expandable = expandable or false
local expanded = false
local parent = nil
local children = {}
local node = {}
local onSelect
node = {
getChildren = function(self)
return children
end,
setParent = function(self, p)
if(parent~=nil)then
parent.removeChild(parent.findChildrenByText(node.getText()))
end
parent = p
base:updateDraw()
return node
end,
getParent = function(self)
return parent
end,
addChild = function(self, text, expandable)
local childNode = newNode(text, expandable)
childNode.setParent(node)
table.insert(children, childNode)
base:updateDraw()
return childNode
end,
setExpanded = function(self, exp)
if(expandable)then
expanded = exp
end
base:updateDraw()
return node
end,
isExpanded = function(self)
return expanded
end,
onSelect = function(self, ...)
for _,v in pairs(table.pack(...))do
if(type(v)=="function")then
onSelect = v
end
end
return node
end,
callOnSelect = function(self)
if(onSelect~=nil)then
onSelect(node)
end
end,
setExpandable = function(self, _expandable)
expandable = _expandable
base:updateDraw()
return node
end,
isExpandable = function(self)
return expandable
end,
removeChild = function(self, index)
if(type(index)=="table")then
for k,v in pairs(index)do
if(v==index)then
index = k
break
end
end
end
table.remove(children, index)
base:updateDraw()
return node
end,
findChildrenByText = function(self, searchText)
local foundNodes = {}
for _, child in ipairs(children) do
if string.find(child.getText(), searchText) then
table.insert(foundNodes, child)
end
end
return foundNodes
end,
getText = function(self)
return text
end,
setText = function(self, t)
text = t
base:updateDraw()
return node
end
}
return node
end
local root = newNode("Root", true)
base:addProperty("Root", "table", root, false, function(self, value)
value.setParent(nil)
end)
root:setExpanded(true)
local object = {
init = function(self)
local parent = self:getParent()
self:listenEvent("mouse_click")
self:listenEvent("mouse_scroll")
return base.init(self)
end,
getBase = function(self)
return base
end,
onSelect = function(self, ...)
for _,v in pairs(table.pack(...))do
if(type(v)=="function")then
self:registerEvent("treeview_select", v)
end
end
return self
end,
selectionHandler = function(self, node)
node.callOnSelect(node)
self:sendEvent("treeview_select", node)
return self
end,
mouseHandler = function(self, button, x, y)
if base.mouseHandler(self, button, x, y) then
local currentLine = 1 - self:getYOffset()
local obx, oby = self:getAbsolutePosition()
local w, h = self:getSize()
local function checkNodeClick(node, level)
if y == oby+currentLine-1 then
if x >= obx and x < obx + w then
node:setExpanded(not node:isExpanded())
self:selectionHandler(node)
self:setValue(node)
self:updateDraw()
return true
end
end
currentLine = currentLine + 1
if node:isExpanded() then
for _, child in ipairs(node:getChildren()) do
if checkNodeClick(child, level + 1) then
return true
end
end
end
return false
end
for _, item in ipairs(root:getChildren()) do
if checkNodeClick(item, 1) then
return true
end
end
end
end,
scrollHandler = function(self, dir, x, y)
if base.scrollHandler(self, dir, x, y) then
local scrollable = self:getScrollable()
local yOffset = self:getYOffset()
if scrollable then
local _, h = self:getSize()
yOffset = yOffset + dir
if yOffset < 0 then
yOffset = 0
end
if dir >= 1 then
local visibleLines = 0
local function countVisibleLines(node, level)
visibleLines = visibleLines + 1
if node:isExpanded() then
for _, child in ipairs(node:getChildren()) do
countVisibleLines(child, level + 1)
end
end
end
for _, item in ipairs(root:getChildren()) do
countVisibleLines(item, 1)
end
if visibleLines > h then
if yOffset > visibleLines - h then
yOffset = visibleLines - h
end
else
yOffset = yOffset - 1
end
end
self:setYOffset(yOffset)
self:updateDraw()
end
return true
end
return false
end,
draw = function(self)
base.draw(self)
self:addDraw("treeview", function()
local xOffset, yOffset = self:getOffset()
local itemSelectedBG self:getSelectionBackground()
local itemSelectedFG self:getSelectionForeground()
local currentLine = 1 - yOffset
local lastClickedNode = self:getValue()
local function drawNode(node, level)
local w, h = self:getSize()
if currentLine >= 1 and currentLine <= h then
local bg = (node == lastClickedNode) and itemSelectedBG or self:getBackground()
local fg = (node == lastClickedNode) and itemSelectedFG or self:getForeground()
local text = node.getText()
self:addBlit(1 + level + xOffset, currentLine, text, tHex[fg]:rep(#text), tHex[bg]:rep(#text))
end
currentLine = currentLine + 1
if node:isExpanded() then
for _, child in ipairs(node:getChildren()) do
drawNode(child, level + 1)
end
end
end
for _, item in ipairs(root:getChildren()) do
drawNode(item, 1)
end
end)
end,
}
object.__index = object
return setmetatable(object, base)
end