enscapsulate SingleChildElement.child

This commit is contained in:
PeaAshMeter 2026-05-31 06:00:53 +03:00
parent 3d5ac077be
commit 6c8dc6a52b
10 changed files with 64 additions and 46 deletions

View File

@ -51,22 +51,31 @@ function builder:_makeKey(element)
return element.key return element.key
end end
--- @param cur UIElement
--- @private --- @private
function builder:build_step(cur) function builder:build_step(cur)
cur = cur --[[@as SingleChildElement | MultiChildElement]]
if cur.build then if cur.build then
local orphan = cur:build() cur = cur --[[@as SingleChildElement]]
local child = cur.child
child = orphan local child = cur:build()
if not child then return end if not child then return end
child._parent_ = cur -- local oldChild = cur._child_
cur.child = child -- if oldChild then
-- for key, value in pairs(oldChild) do
-- if (not Element[key]) then child[key] = value end
-- end
-- end
self:build_step(cur.child) cur._child_ = child
child._parent_ = cur
self:build_step(cur._child_)
elseif cur.children then elseif cur.children then
cur = cur --[[@as MultiChildElement]]
for _, child in ipairs(cur.children) do for _, child in ipairs(cur.children) do
child._parent_ = cur child._parent_ = cur
self:build_step(child) self:build_step(child)
end end
end end

View File

@ -8,7 +8,6 @@ local Vec3 = require "lib.utils.vec3"
--- @field _constraints_ Constraints --- @field _constraints_ Constraints
--- @field _offset_ Vec3 Положение левого верхнего угла элемента в локальных координатах {x, y}. Устанавливается родительским элементом. --- @field _offset_ Vec3 Положение левого верхнего угла элемента в локальных координатах {x, y}. Устанавливается родительским элементом.
--- @field _size_ Vec3 Размеры элемента {x, y} --- @field _size_ Vec3 Размеры элемента {x, y}
--- @field build? fun(self, ctx: UIElement): UIElement
local element = {} local element = {}
element.__index = element element.__index = element
element.type = "Element" element.type = "Element"

View File

@ -3,10 +3,11 @@ local Constraints = require "lib.simple_ui.core.constraints"
--- @class SingleChildElement : UIElement --- @class SingleChildElement : UIElement
--- @field child? UIElement --- @field child? UIElement
--- @field _child_? UIElement
local element = setmetatable({}, require "lib.simple_ui.core.element") local element = setmetatable({}, require "lib.simple_ui.core.element")
element.__index = element element.__index = element
--- дефолтное поведение -- просто возвращать своего ребенка --- дефолтное поведение -- просто возвращать переданного ребенка
function element:build() function element:build()
return self.child return self.child
end end
@ -15,20 +16,20 @@ function element:layout()
--- передать ребенку ограничения --- передать ребенку ограничения
--- получить назад размеры --- получить назад размеры
--- разместить ребенка --- разместить ребенка
if not self.child then return end if not self._child_ then return end
self.child._constraints_ = Constraints(self._constraints_) self._child_._constraints_ = Constraints(self._constraints_)
self.child:layout() self._child_:layout()
self.child._offset_ = Vec3 {} self._child_._offset_ = Vec3 {}
end end
function element:update(dt) function element:update(dt)
if self.child then self.child:update(dt) end if self._child_ then self._child_:update(dt) end
end end
function element:draw() function element:draw()
love.graphics.push("transform") love.graphics.push("transform")
love.graphics.translate(self._offset_.x, self._offset_.y) love.graphics.translate(self._offset_.x, self._offset_.y)
if self.child then self.child:draw() end if self._child_ then self._child_:draw() end
love.graphics.pop() love.graphics.pop()
end end

View File

@ -9,13 +9,13 @@ element.type = "Center"
function element:layout() function element:layout()
self._size_ = Vec3 { self._constraints_.maxWidth, self._constraints_.maxHeight } self._size_ = Vec3 { self._constraints_.maxWidth, self._constraints_.maxHeight }
if not self.child then return end if not self._child_ then return end
self.child._constraints_ = Constraints(self._constraints_) self._child_._constraints_ = Constraints(self._constraints_)
self.child:layout() self._child_:layout()
self.child._offset_ = Vec3 { self._child_._offset_ = Vec3 {
(self._size_.x - self.child._size_.x) / 2, (self._size_.x - self._child_._size_.x) / 2,
(self._size_.y - self.child._size_.y) / 2, (self._size_.y - self._child_._size_.y) / 2,
} }
end end

View File

@ -31,7 +31,7 @@ function element:layout()
end end
local shift = 0 local shift = 0
for _, child in ipairs(self.children) do for _, child in ipairs(self.children) do
child._offset_ = Vec3 { self._offset_.x + start + shift, self._offset_.y } child._offset_ = Vec3 { start + shift, 0 }
shift = shift + child._size_.x shift = shift + child._size_.x
end end
@ -57,7 +57,7 @@ function element:layout()
end end
local shift = 0 local shift = 0
for _, child in ipairs(self.children) do for _, child in ipairs(self.children) do
child._offset_ = Vec3 { self._offset_.x, self._offset_.y + start + shift } child._offset_ = Vec3 { 0, start + shift }
shift = shift + child._size_.y shift = shift + child._size_.y
end end

View File

@ -19,17 +19,17 @@ element.bottom = 0
--- ---
--- as in https://api.flutter.dev/flutter/widgets/Padding-class.html --- as in https://api.flutter.dev/flutter/widgets/Padding-class.html
function element:layout() function element:layout()
if not self.child then return end if not self._child_ then return end
local c = Constraints(self._constraints_) local c = Constraints(self._constraints_)
c.maxWidth = c.maxWidth - self.left - self.right c.maxWidth = c.maxWidth - self.left - self.right
c.maxHeight = c.maxHeight - self.top - self.bottom c.maxHeight = c.maxHeight - self.top - self.bottom
c.maxWidth = c.maxWidth > 0 and c.maxWidth or 0 c.maxWidth = c.maxWidth > 0 and c.maxWidth or 0
c.maxHeight = c.maxHeight > 0 and c.maxHeight or 0 c.maxHeight = c.maxHeight > 0 and c.maxHeight or 0
self.child._constraints_ = c self._child_._constraints_ = c
self.child:layout() self._child_:layout()
self._size_ = Vec3 { self.child._size_.x + self.left + self.right, self.child._size_.y + self.top + self.bottom } self._size_ = Vec3 { self._child_._size_.x + self.left + self.right, self._child_._size_.y + self.top + self.bottom }
self.child._offset_ = Vec3 { self.left, self.top } self._child_._offset_ = Vec3 { self.left, self.top }
end end
--- @return Padding --- @return Padding

View File

@ -9,17 +9,17 @@ element.type = "Placeholder"
function element:layout() function element:layout()
self._size_ = Vec3 { self._constraints_.maxWidth, self._constraints_.maxHeight } self._size_ = Vec3 { self._constraints_.maxWidth, self._constraints_.maxHeight }
if not self.child then return end if not self._child_ then return end
self.child._constraints_ = Constraints(self._constraints_) self._child_._constraints_ = Constraints(self._constraints_)
self.child:layout() self._child_:layout()
end end
function element:draw() function element:draw()
love.graphics.rectangle("line", self._offset_.x, self._offset_.y, self._size_.x, self._size_.y) love.graphics.rectangle("line", self._offset_.x, self._offset_.y, self._size_.x, self._size_.y)
love.graphics.line(self._offset_.x, self._offset_.y, self._offset_.x + self._size_.x, self._offset_.y + self._size_ love.graphics.line(self._offset_.x, self._offset_.y, self._offset_.x + self._size_.x, self._offset_.y + self._size_
.y) .y)
love.graphics.line(self._offset_.x, self._offset_.y + self._size_.y, self._offset_.x + self._size_.x, self._offset_ love.graphics.line(self._offset_.x, self._offset_.y + self._size_.y, self._offset_.x + self._size_.x, self._offset_
.y) .y)
end end
--- @return Placeholder --- @return Placeholder

View File

@ -14,10 +14,10 @@ function element:layout()
} }
self._size_ = Vec3 { screenW, screenH } self._size_ = Vec3 { screenW, screenH }
if not self.child then return end if not self._child_ then return end
self.child._constraints_ = Constraints(self._constraints_) self._child_._constraints_ = Constraints(self._constraints_)
self.child:layout() self._child_:layout()
self.child._offset_ = Vec3 {} self._child_._offset_ = Vec3 {}
end end
--- @return ScreenArea --- @return ScreenArea

View File

@ -11,13 +11,13 @@ element.height = 0
function element:layout() function element:layout()
self._size_ = Vec3 { self.width, self.height } self._size_ = Vec3 { self.width, self.height }
if not self.child then return end if not self._child_ then return end
self.child._constraints_ = Constraints { self._child_._constraints_ = Constraints {
maxWidth = self.width, maxWidth = self.width,
maxHeight = self.height, maxHeight = self.height,
} }
self.child:layout() self._child_:layout()
self.child._offset_ = Vec3 {} self._child_._offset_ = Vec3 {}
end end
--- @return SizedBox --- @return SizedBox

View File

@ -18,8 +18,8 @@ Canary.type = "Canary"
local reported = false local reported = false
function Canary:build() function Canary:build()
-- self.i = self.i and self.i + 1 or 0 self.i = self.i and self.i + 1 or 0
-- print(self.i) print(self.i)
-- if not reported then -- if not reported then
-- self:traverseUp(function(element) -- self:traverseUp(function(element)
-- print(element.type) -- print(element.type)
@ -60,7 +60,7 @@ function MyWidget:build()
width = 100, width = 100,
height = 100, height = 100,
child = Canary:new { child = Canary:new {
i = 10 i = 0
} }
}, },
}, },
@ -68,7 +68,7 @@ function MyWidget:build()
}, },
Flex:new { Flex:new {
key = "inner_flex2", key = "inner_flex2",
mainAxisAlignment = "center", mainAxisAlignment = "end",
children = { children = {
SizedBox:new { SizedBox:new {
width = 100, width = 100,
@ -84,6 +84,7 @@ function MyWidget:build()
}, },
}, },
math.floor(love.timer.getTime()) % 2 == 0 and self.child or nil
} }
} }
end end
@ -119,6 +120,14 @@ end
return Builder { return Builder {
elementTree = ScreenArea:new { elementTree = ScreenArea:new {
child = MyWidget:new {} child = MyWidget:new {
child = SizedBox:new {
width = 100,
height = 100,
child = Canary:new {
i = 100
}
}
}
} }
} }