slabOS/lib/basalt/objects/Container.lua
2025-06-02 10:23:40 +03:00

429 lines
13 KiB
Lua

local utils = require("utils")
local tableCount = utils.tableCount
return function(name, basalt)
local base = basalt.getObject("VisualObject")(name, basalt)
local objectType = "Container"
local children = {}
local events = {}
local container = {}
local focusedChild
local sorted = true
local objId, evId = 0, 0
local objSort = function(a, b)
if a.zIndex == b.zIndex then
return a.objId < b.objId
else
return a.zIndex < b.zIndex
end
end
local evSort = function(a, b)
if a.zIndex == b.zIndex then
return a.evId > b.evId
else
return a.zIndex > b.zIndex
end
end
local function getChildren(self)
self:sortChildren()
return children
end
local function getChild(self, name)
if (type(name)=="table") then
name = name:getName()
end
for _, v in ipairs(children) do
if v.element:getName() == name then
return v.element
end
end
end
local function getDeepChild(self, name)
local maybeChild = getChild(name)
if (maybeChild ~= nil) then
return maybeChild
end
for _, child in ipairs(children) do
if (child:getType() == "Container") then
local maybeDeepChild = child:getDeepChild(name)
if (maybeDeepChild ~= nil) then
return maybeDeepChild
end
end
end
end
local function addChild(self, element)
if (getChild(element:getName()) ~= nil) then
return
end
objId = objId + 1
local zIndex = element:getZIndex()
table.insert(children, {element = element, zIndex = zIndex, objId = objId})
sorted = false
element:setParent(self, true)
for event, _ in pairs(element:getRegisteredEvents()) do
self:addEvent(event, element)
end
if (element.init~=nil) then
element:init()
end
if (element.load~=nil) then
element:load()
end
if (element.draw~=nil) then
element:draw()
end
return element
end
local function removeChild(self, element)
if (type(element)=="string") then
element = getChild(element:getName())
end
if (element==nil) then
return
end
for i, v in ipairs(children) do
if v.element == element then
table.remove(children, i)
return true
end
end
self:removeEvents(element)
sorted = false
end
local function removeChildren(self)
local parent = self:getParent()
children = {}
events = {}
sorted = false
objId = 0
evId = 0
focusedChild = nil
parent:removeEvents(self)
end
local function updateZIndex(self, element, newZ)
objId = objId + 1
evId = evId + 1
for _,v in pairs(children)do
if(v.element==element)then
v.zIndex = newZ
v.objId = objId
break
end
end
for _,v in pairs(events)do
for a,b in pairs(v)do
if(b.element==element)then
b.zIndex = newZ
b.evId = evId
end
end
end
sorted = false
self:updateDraw()
end
local function removeEvents(self, element)
local parent = self:getParent()
for a, b in pairs(events) do
for c, d in pairs(b) do
if(d.element == element)then
table.remove(events[a], c)
end
end
if(tableCount(events[a])<=0)then
if(parent~=nil)then
parent:removeEvent(a, self)
end
end
end
sorted = false
end
local function getEvent(self, event, name)
if(type(name)=="table")then name = name:getName() end
if(events[event]~=nil)then
for _, obj in pairs(events[event]) do
if (obj.element:getName() == name) then
return obj
end
end
end
end
local function addEvent(self, event, element)
if (getEvent(self, event, element:getName()) ~= nil) then
return
end
local zIndex = element:getZIndex()
evId = evId + 1
if(events[event]==nil)then events[event] = {} end
table.insert(events[event], {element = element, zIndex = zIndex, evId = evId})
sorted = false
self:listenEvent(event)
return element
end
local function removeEvent(self, event, element)
if(events[event]~=nil)then
for a, b in pairs(events[event]) do
if(b.element == element)then
table.remove(events[event], a)
end
end
if(tableCount(events[event])<=0)then
self:listenEvent(event, false)
end
end
sorted = false
end
local function getEvents(self, event)
return event~=nil and events[event] or events
end
container = {
getType = function()
return objectType
end,
getBase = function(self)
return base
end,
isType = function(self, t)
return objectType==t or base.isType~=nil and base.isType(t) or false
end,
setSize = function(self, ...)
base.setSize(self, ...)
self:customEventHandler("basalt_FrameResize")
return self
end,
setPosition = function(self, ...)
base.setPosition(self, ...)
self:customEventHandler("basalt_FrameReposition")
return self
end,
searchChildren = function(self, name)
local results = {}
for _, child in pairs(children) do
if (string.find(child.element:getName(), name)) then
table.insert(results, child)
end
end
return results
end,
getChildrenByType = function(self, type)
local results = {}
for _, child in pairs(children) do
if (child.element:isType(type)) then
table.insert(results, child)
end
end
return results
end,
setImportant = function(self, element)
objId = objId + 1
evId = evId + 1
for a, b in pairs(events) do
for c, d in pairs(b) do
if(d.element == element)then
d.evId = evId
table.remove(events[a], c)
table.insert(events[a], d)
break
end
end
end
for i, v in ipairs(children) do
if v.element == element then
v.objId = objId
table.remove(children, i)
table.insert(children, v)
break
end
end
if(self.updateDraw~=nil)then
self:updateDraw()
end
sorted = false
end,
sortChildren = function(self)
if (sorted) then
return
end
table.sort(children, objSort)
for event, _ in pairs(events) do
table.sort(events[event], evSort)
end
sorted = true
end,
clearFocusedChild = function(self)
if(focusedChild~=nil)then
if(getChild(self, focusedChild)~=nil)then
focusedChild:loseFocusHandler()
end
end
focusedChild = nil
return self
end,
setFocusedChild = function(self, obj)
if(focusedChild~=obj)then
if(focusedChild~=nil)then
if(getChild(self, focusedChild)~=nil)then
focusedChild:loseFocusHandler()
end
end
if(obj~=nil)then
if(getChild(self, obj)~=nil)then
obj:getFocusHandler()
end
end
focusedChild = obj
return true
end
return false
end,
getFocused = function(self)
return focusedChild
end,
getChild = getChild,
getChildren = getChildren,
getDeepChildren = getDeepChild,
addChild = addChild,
removeChild = removeChild,
removeChildren = removeChildren,
getEvents = getEvents,
getEvent = getEvent,
addEvent = addEvent,
removeEvent = removeEvent,
removeEvents = removeEvents,
updateZIndex = updateZIndex,
listenEvent = function(self, event, active)
base.listenEvent(self, event, active)
if(events[event]==nil)then events[event] = {} end
return self
end,
customEventHandler = function(self, ...)
base.customEventHandler(self, ...)
for _, o in pairs(children) do
if (o.element.customEventHandler ~= nil) then
o.element:customEventHandler(...)
end
end
end,
loseFocusHandler = function(self)
base.loseFocusHandler(self)
if(focusedChild~=nil)then focusedChild:loseFocusHandler() focusedChild = nil end
end,
getBasalt = function(self)
return basalt
end,
setPalette = function(self, col, ...)
local parent = self:getParent()
parent:setPalette(col, ...)
return self
end,
eventHandler = function(self, ...)
if(base.eventHandler~=nil)then
base.eventHandler(self, ...)
if(events["other_event"]~=nil)then
self:sortChildren()
for _, obj in ipairs(events["other_event"]) do
if (obj.element.eventHandler ~= nil) then
obj.element.eventHandler(obj.element, ...)
end
end
end
end
end,
}
for k,v in pairs({mouse_click={"mouseHandler", true},mouse_up={"mouseUpHandler", false},mouse_drag={"dragHandler", false},mouse_scroll={"scrollHandler", true},mouse_hover={"hoverHandler", false}})do
container[v[1]] = function(self, btn, x, y, ...)
if(base[v[1]]~=nil)then
if(base[v[1]](self, btn, x, y, ...))then
if(events[k]~=nil)then
self:sortChildren()
for _, obj in ipairs(events[k]) do
if (obj.element[v[1]] ~= nil) then
local xO, yO = 0, 0
if(self.getOffset~=nil)then
xO, yO = self:getOffset()
end
if(obj.element.getIgnoreOffset~=nil)then
if(obj.element.getIgnoreOffset())then
xO, yO = 0, 0
end
end
if (obj.element[v[1]](obj.element, btn, x+xO, y+yO, ...)) then
return true
end
end
end
if(v[2])then
self:clearFocusedChild()
end
end
return true
end
end
end
end
for k,v in pairs({key="keyHandler",key_up="keyUpHandler",char="charHandler"})do
container[v] = function(self, ...)
if(base[v]~=nil)then
if(base[v](self, ...))then
if(events[k]~=nil)then
self:sortChildren()
for _, obj in ipairs(events[k]) do
if (obj.element[v] ~= nil) then
if (obj.element[v](obj.element, ...)) then
return true
end
end
end
end
end
end
end
end
for objectName, _ in pairs(basalt.getObjects()) do
container["add" .. objectName] = function(self, id)
return self:addChild(basalt:createObject(objectName, id))
end
end
container.__index = container
return setmetatable(container, base)
end