add type hints for EVERYTHING

organize ui into folders
implement element:traverseUp
This commit is contained in:
PeaAshMeter 2026-05-04 02:48:30 +03:00
parent a4edbf8224
commit 393638bb71
16 changed files with 150 additions and 72 deletions

View File

@ -42,6 +42,7 @@ function builder:build_step(cur)
if not cur then return end if not cur then return end
if cur.build then if cur.build then
cur.child = self:_get(cur:build()) cur.child = self:_get(cur:build())
cur.child.parent = cur
self:build_step(cur.child) self:build_step(cur.child)
elseif cur.children then elseif cur.children then
for _, child in ipairs(cur.children) do for _, child in ipairs(cur.children) do

View File

@ -12,7 +12,7 @@ local constraints = {
constraints.__index = constraints constraints.__index = constraints
--- @param from {minWidth?: number, maxWidth?: number, minHeight?: number, maxHeight?: number} --- @param from {minWidth: number?, maxWidth: number?, minHeight: number?, maxHeight: number?}
--- @return Constraints --- @return Constraints
local function new(from) local function new(from)
return setmetatable(from, constraints) return setmetatable(from, constraints)

View File

@ -1,5 +1,4 @@
local Rect = require "lib.simple_ui.rect" local Constraints = require "lib.simple_ui.core.constraints"
local Constraints = require "lib.simple_ui.constraints"
local Vec3 = require "lib.utils.vec3" local Vec3 = require "lib.utils.vec3"
--- @class UIElement --- @class UIElement
@ -26,15 +25,22 @@ function element:update(dt) end
function element:draw() end function element:draw() end
--- @generic T : UIElement --- @param values {[string]: any}
--- @param values T --- @return UIElement
--- @param self T function element:new(values)
--- @return T
function element.new(self, values)
values.bounds = values.bounds or Rect {}
values.transform = values.transform or love.math.newTransform()
if values.child then values.child.parent = values end
return setmetatable(values, self) return setmetatable(values, self)
end end
--- Рекурсивно обходит дерево элементов вверх, начиная с первого родителя.
---
--- К каждому посещенному элементу применяет функцию visitor.
---
--- Обход заканчивается, если visitor возвращает false, или если родители кончились.
--- @param visitor fun(element: UIElement): boolean
function element:traverseUp(visitor)
if not self.parent then return end
if not visitor(self.parent) then return end
return self.parent:traverseUp(visitor)
end
return element return element

View File

@ -1,6 +1,8 @@
local Element = require "lib.simple_ui.core.element"
--- @class MultiChildElement : UIElement --- @class MultiChildElement : UIElement
--- @field children UIElement[] --- @field children UIElement[]
local element = setmetatable({}, require "lib.simple_ui.element") local element = setmetatable({}, require "lib.simple_ui.core.element")
element.__index = element element.__index = element
element.children = {} element.children = {}
@ -26,4 +28,14 @@ function element:draw()
love.graphics.setColor(1, 1, 1) love.graphics.setColor(1, 1, 1)
end end
--- @generic T : MultiChildElement
--- @param values {children: UIElement[]?, [string]: any}
--- @return T
function element:new(values)
for _, child in ipairs(values.children or {}) do
child.parent = values
end
return Element.new(self, values)
end
return element return element

View File

@ -1,6 +1,8 @@
local Element = require "lib.simple_ui.core.element"
--- @class SingleChildElement : UIElement --- @class SingleChildElement : UIElement
--- @field child? UIElement --- @field child? UIElement
local element = setmetatable({}, require "lib.simple_ui.element") local element = setmetatable({}, require "lib.simple_ui.core.element")
element.__index = element element.__index = element
function element:layout() function element:layout()
@ -17,4 +19,13 @@ function element:draw()
if self.child then self.child:draw() end if self.child then self.child:draw() end
end end
--- @generic T : SingleChildElement
--- @param self T
--- @param values {child: UIElement?, [string]: any}
--- @return T
function element:new(values)
if values.child then values.child.parent = values end
return Element.new(self, values)
end
return element return element

View File

@ -0,0 +1,3 @@
--- @alias Axis "horizontal" | "vertical"
--- @alias MainAxisSize "max" | "min"
--- @alias MainAxisAlignment "start" | "center" | "end"

View File

@ -1,5 +1,5 @@
local Constraints = require "lib.simple_ui.constraints" local Constraints = require "lib.simple_ui.core.constraints"
local SingleChildElement = require "lib.simple_ui.single_child_element" local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @class Center : SingleChildElement --- @class Center : SingleChildElement
local element = setmetatable({}, SingleChildElement) local element = setmetatable({}, SingleChildElement)
@ -19,4 +19,10 @@ function element:layout()
} }
end end
--- @return Center
--- @param values {child: UIElement?}
function element:new(values)
return SingleChildElement.new(self, values)
end
return element return element

View File

@ -1,17 +1,18 @@
local Constraints = require "lib.simple_ui.constraints" local Constraints = require "lib.simple_ui.core.constraints"
local MultiChildElement = require "lib.simple_ui.core.multi_child_element"
--- @class Flex : MultiChildElement --- @class Flex : MultiChildElement
--- @field direction "horizontal" | "vertical" --- @field direction Axis
--- @field mainAxisSize "max" | "min" --- @field mainAxisSize MainAxisSize
--- @field mainAxisAlignment "start" | "center" | "end" --- @field mainAxisAlignment MainAxisAlignment
local flex = setmetatable({}, require "lib.simple_ui.multi_child_element") local element = setmetatable({}, require "lib.simple_ui.core.multi_child_element")
flex.__index = flex element.__index = element
flex.type = "Flex" element.type = "Flex"
flex.direction = "horizontal" element.direction = "horizontal"
flex.mainAxisSize = "max" element.mainAxisSize = "max"
flex.mainAxisAlignment = "start" element.mainAxisAlignment = "start"
function flex:layout() function element:layout()
local mainAxisSize = 0 local mainAxisSize = 0
local crossAxisSize = 0 local crossAxisSize = 0
if self.direction == "horizontal" then if self.direction == "horizontal" then
@ -68,4 +69,10 @@ function flex:layout()
end end
end end
return flex --- @param values {direction: Axis?, mainAxisSize: MainAxisSize?, mainAxisAlignment: MainAxisAlignment?, children: UIElement[]?}
--- @return Flex
function element:new(values)
return MultiChildElement.new(self, values)
end
return element

View File

@ -1,5 +1,5 @@
local Constraints = require "lib.simple_ui.constraints" local Constraints = require "lib.simple_ui.core.constraints"
local SingleChildElement = require "lib.simple_ui.single_child_element" local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @class Padding : SingleChildElement --- @class Padding : SingleChildElement
--- @field left number --- @field left number
@ -32,4 +32,10 @@ function element:layout()
self.child.offset = self.offset + Vec3 { self.left, self.top } self.child.offset = self.offset + Vec3 { self.left, self.top }
end end
--- @return Padding
--- @param values {left: number?, top: number?, right: number?, bottom: number?, child: UIElement?}
function element:new(values)
return SingleChildElement.new(self, values)
end
return element return element

View File

@ -1,5 +1,5 @@
local Constraints = require "lib.simple_ui.constraints" local Constraints = require "lib.simple_ui.core.constraints"
local SingleChildElement = require "lib.simple_ui.single_child_element" local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @class Placeholder : SingleChildElement --- @class Placeholder : SingleChildElement
local element = setmetatable({}, SingleChildElement) local element = setmetatable({}, SingleChildElement)
@ -21,4 +21,10 @@ function element:draw()
love.graphics.line(self.offset.x, self.offset.y + self.size.y, self.offset.x + self.size.x, self.offset.y) love.graphics.line(self.offset.x, self.offset.y + self.size.y, self.offset.x + self.size.x, self.offset.y)
end end
--- @return Placeholder
--- @param values {child: UIElement?}
function element:new(values)
return SingleChildElement.new(self, values)
end
return element return element

View File

@ -1,5 +1,5 @@
local Constraints = require "lib.simple_ui.constraints" local Constraints = require "lib.simple_ui.core.constraints"
local SingleChildElement = require "lib.simple_ui.single_child_element" local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @class ScreenArea : SingleChildElement --- @class ScreenArea : SingleChildElement
local element = setmetatable({}, SingleChildElement) local element = setmetatable({}, SingleChildElement)
@ -23,4 +23,10 @@ function element:layout()
self.child.offset = Vec3 {} self.child.offset = Vec3 {}
end end
--- @return ScreenArea
--- @param values {child: UIElement?}
function element:new(values)
return SingleChildElement.new(self, values)
end
return element return element

View File

@ -0,0 +1,29 @@
local SingleChildElement = require "lib.simple_ui.core.single_child_element"
--- @class SizedBox : SingleChildElement
local element = setmetatable({}, require "lib.simple_ui.core.single_child_element")
local Constraints = require("lib.simple_ui.core.constraints")
element.type = "SizedBox"
element.__index = element
element.width = 0
element.height = 0
function element:layout()
self.size = Vec3 { self.width, self.height }
if not self.child then return end
self.child.constraints = Constraints {
maxWidth = self.width,
maxHeight = self.height,
}
self.child:layout()
self.child.offset = self.offset:copy()
end
--- @return SizedBox
--- @param values {width: number?, height: number?, child: UIElement?}
function element:new(values)
return SingleChildElement.new(self, values)
end
return element

View File

@ -1,16 +1,31 @@
local ScreenArea = require "lib.simple_ui.screen_area" local ScreenArea = require "lib.simple_ui.elements.screen_area"
local Center = require "lib.simple_ui.center" local Placeholder = require "lib.simple_ui.elements.placeholder"
local Placeholder = require "lib.simple_ui.placeholder" local Padding = require "lib.simple_ui.elements.padding"
local Padding = require "lib.simple_ui.padding" local Builder = require "lib.simple_ui.core.builder"
local Builder = require "lib.simple_ui.builder" local Flex = require "lib.simple_ui.elements.flex"
local Flex = require "lib.simple_ui.flex" local SizedBox = require "lib.simple_ui.elements.sized_box"
local SizedBox = require "lib.simple_ui.sized_box" local SingleChildElement = require "lib.simple_ui.core.single_child_element"
local SingleChildElement = require "lib.simple_ui.single_child_element"
local MyWidget = setmetatable({}, SingleChildElement) local MyWidget = setmetatable({}, SingleChildElement)
MyWidget.__index = MyWidget MyWidget.__index = MyWidget
local Canary = setmetatable({}, SingleChildElement)
Canary.__index = Canary
local reported = false
function Canary:build()
if not reported then
self:traverseUp(function(element)
print(element.type)
return true
end)
reported = true
end
return Placeholder:new {}
end
--- comment --- comment
--- @return Flex --- @return Flex
function MyWidget:build() function MyWidget:build()
@ -39,7 +54,7 @@ function MyWidget:build()
SizedBox:new { SizedBox:new {
width = 100, width = 100,
height = 100, height = 100,
child = Placeholder:new {} child = Canary:new {}
}, },
}, },
} }
@ -66,12 +81,6 @@ function MyWidget:build()
} }
end end
-- function MyWidget:layout()
-- if not self.child then return end
-- self.child.constraints = self.constraints
-- self.child:layout()
-- end
return Builder { return Builder {
elementTree = ScreenArea:new { elementTree = ScreenArea:new {
child = MyWidget:new {} child = MyWidget:new {}

View File

@ -1,24 +0,0 @@
--- @class SizedBox : SingleChildElement
local element = setmetatable({}, require "lib.simple_ui.single_child_element")
local Constraints = require("lib.simple_ui.constraints")
element.type = "SizedBox"
element.__index = element
function element:layout()
self.size = Vec3 { self.width, self.height }
if not self.child then return end
self.child.constraints = Constraints {
maxWidth = self.width,
maxHeight = self.height,
}
self.child:layout()
self.child.offset = self.offset:copy()
end
-- function element:draw()
-- print('hello2')
-- if self.child then self.child:draw() end
-- end
return element