implement StatefulElement

This commit is contained in:
PeaAshMeter 2026-06-02 03:39:24 +03:00
parent 0e8181baf3
commit fdff65d94d
4 changed files with 57 additions and 22 deletions

View File

@ -3,12 +3,14 @@ local Element = require "lib.simple_ui.core.element"
--- Объект, который отвечает за работу с элементами интерфейса одного экрана --- Объект, который отвечает за работу с элементами интерфейса одного экрана
--- @class UIBuilder --- @class UIBuilder
--- @field builder fun(): UIElement --- @field builder fun(): UIElement
--- @field private states {string: table}
--- @field private elementTree UIElement --- @field private elementTree UIElement
local builder = {} local builder = {}
builder.__index = builder builder.__index = builder
--- @return UIBuilder --- @return UIBuilder
local function new(from) local function new(from)
from.states = {}
setmetatable(from, builder) setmetatable(from, builder)
return from return from
end end
@ -36,7 +38,19 @@ end
--- @private --- @private
function builder:build_step(cur) function builder:build_step(cur)
-- Самоприсваивания должны вырезаться компилятором, я в это верю -- Самоприсваивания должны вырезаться компилятором, я в это верю
cur = cur --[[@as SingleChildElement | MultiChildElement]] cur = cur --[[@as SingleChildElement | StatefulElement | MultiChildElement]]
local key = self:makeKey(cur)
if key then
cur = cur --[[@as StatefulElement]]
local storedState = self.states[key]
if not storedState then
self.states[key] = cur.state
else
cur.state = storedState
end
end
local buildRes = cur:build() local buildRes = cur:build()
if not buildRes then return end if not buildRes then return end

View File

@ -24,12 +24,6 @@ function element:update(dt) end
function element:draw() end function element:draw() end
--- @param values {[string]: any}
--- @return UIElement
function element:new(values)
return setmetatable(values, self)
end
--- Рекурсивно обходит дерево элементов вверх, начиная с первого родителя. --- Рекурсивно обходит дерево элементов вверх, начиная с первого родителя.
--- ---
--- К каждому посещенному элементу применяет функцию visitor. --- К каждому посещенному элементу применяет функцию visitor.
@ -42,4 +36,10 @@ function element:traverseUp(visitor)
return self._parent_:traverseUp(visitor) return self._parent_:traverseUp(visitor)
end end
--- @param values {[string]: any}
--- @return UIElement
function element:new(values)
return setmetatable(values, self)
end
return element return element

View File

@ -0,0 +1,17 @@
local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @generic T : table
--- @class StatefulElement<T> : SingleChildElement
--- @field state T
local element = setmetatable({}, SingleChildElement)
element.__index = element
element.type = "StatefulElement"
element.state = {}
--- @return StatefulElement<T>
--- @param values {key: any, state: T?, child: UIElement?}
function element:new(values)
return SingleChildElement.new(self, values)
end
return element

View File

@ -5,28 +5,23 @@ local Builder = require "lib.simple_ui.core.builder"
local Flex = require "lib.simple_ui.elements.flex" local Flex = require "lib.simple_ui.elements.flex"
local Center = require "lib.simple_ui.elements.center" local Center = require "lib.simple_ui.elements.center"
local SizedBox = require "lib.simple_ui.elements.sized_box" local SizedBox = require "lib.simple_ui.elements.sized_box"
local SingleChildElement = require "lib.simple_ui.core.single_child_element" local StatefulElement = require "lib.simple_ui.core.stateful_element"
local MyWidget = setmetatable({}, SingleChildElement) local MyWidget = setmetatable({}, StatefulElement)
MyWidget.__index = MyWidget MyWidget.__index = MyWidget
MyWidget.type = "MyWidget" MyWidget.type = "MyWidget"
local Canary = setmetatable({}, SingleChildElement) local Canary = setmetatable({}, StatefulElement)
Canary.__index = Canary Canary.__index = Canary
Canary.type = "Canary" Canary.type = "Canary"
local reported = false --- @class CanaryState
Canary.state = { i = 0 }
function Canary:build() function Canary:build()
-- self.i = self.i and self.i + 1 or 0 self.state.i = self.state.i and self.state.i + 1 or 0
-- print(self.i) print(self.state.i)
if not reported then
self:traverseUp(function(element)
print(element.type)
return true
end)
reported = true
end
return Placeholder:new {} return Placeholder:new {}
end end
@ -56,11 +51,20 @@ function MyWidget:build()
child = Placeholder:new {} child = Placeholder:new {}
}, },
SizedBox:new { SizedBox:new {
key = "mybox",
width = 100, width = 100,
height = 100, height = 100,
child = Canary:new { child = Canary:new {
i = 0 key = "canary1",
}
},
SizedBox:new {
width = 100,
height = 100,
child = Canary:new {
key = "canary2",
state = {
i = 100
}
} }
}, },
}, },