105 lines
2.9 KiB
Lua
105 lines
2.9 KiB
Lua
local Element = require "lib.simple_ui.core.element"
|
||
|
||
--- Объект, который отвечает за работу с элементами интерфейса одного экрана
|
||
--- @class UIBuilder
|
||
--- @field private _cache UIElement[]
|
||
--- @field elementTree UIElement
|
||
--- @field private shadowTree UIElement
|
||
local builder = {}
|
||
builder.__index = builder
|
||
|
||
--- @return UIBuilder
|
||
local function new(from)
|
||
from._cache = {}
|
||
from.shadowTree = Element:new {}
|
||
setmetatable(from, builder)
|
||
return from
|
||
end
|
||
|
||
-- --- @param element? UIElement
|
||
-- --- @private
|
||
-- function builder:_get(element)
|
||
-- if not element then return nil end
|
||
-- local key = builder:_makeKey(element)
|
||
-- if not key then return element end
|
||
|
||
-- local cached = self._cache[key]
|
||
-- if cached then return cached end
|
||
|
||
-- self._cache[key] = element
|
||
-- return element
|
||
-- end
|
||
|
||
--- @param newNode UIElement?
|
||
--- @param oldNode UIElement?
|
||
--- @private
|
||
function builder:didChange(newNode, oldNode)
|
||
if not oldNode or not newNode then
|
||
return true
|
||
end
|
||
if oldNode.type ~= newNode.type then return true end
|
||
if oldNode.key ~= newNode.key then return true end
|
||
return false
|
||
end
|
||
|
||
--- @param element UIElement
|
||
--- @private
|
||
function builder:_makeKey(element)
|
||
--if not element.key then return nil end
|
||
if type(element.key) == "string" then return element.key end
|
||
element.key = element.type .. "<" .. tostring(element.key) .. ">"
|
||
return element.key
|
||
end
|
||
|
||
--- @param cur UIElement
|
||
--- @private
|
||
function builder:build_step(cur)
|
||
cur = cur --[[@as SingleChildElement | MultiChildElement]]
|
||
if cur.build then
|
||
cur = cur --[[@as SingleChildElement]]
|
||
|
||
local child = cur:build()
|
||
if not child then return end
|
||
|
||
-- local oldChild = cur._child_
|
||
-- if oldChild then
|
||
-- for key, value in pairs(oldChild) do
|
||
-- if (not Element[key]) then child[key] = value end
|
||
-- end
|
||
-- end
|
||
|
||
cur._child_ = child
|
||
child._parent_ = cur
|
||
|
||
self:build_step(cur._child_)
|
||
elseif cur.children then
|
||
cur = cur --[[@as MultiChildElement]]
|
||
for _, child in ipairs(cur.children) do
|
||
child._parent_ = cur
|
||
self:build_step(child)
|
||
end
|
||
end
|
||
end
|
||
|
||
--- Этот метод раскрывает всех отложенных (через build) детей в дереве и хитро их кэширует, чтобы не перестраивались постоянно
|
||
---
|
||
--- Благодаря этому можно каждый раз создавать новые элементы в верстке, а получать старые :)
|
||
function builder:build()
|
||
local root = self.elementTree
|
||
self:build_step(root)
|
||
end
|
||
|
||
function builder:layout()
|
||
self.elementTree:layout()
|
||
end
|
||
|
||
function builder:update(dt)
|
||
self.elementTree:update(dt)
|
||
end
|
||
|
||
function builder:draw()
|
||
self.elementTree:draw()
|
||
end
|
||
|
||
return new
|