require "lib.utils.vec3" --- Stateful UI element --- @class Element --- @field state table --- @field update fun(self: Element, dt: number) called each logical frame, alters self.state --- @field draw fun(self: Element) uses self.state to draw, should not alter anything --- @field origin Vec3 --- @field size Vec3 --- @field parent Element | nil --- @field child Element | nil local Element = {} Element.__index = Element Element.state = {} function Element:update(dt) local parent = self.parent if not parent then return end self.origin = self.origin or parent.origin self.size = self.size or parent.size end function Element:draw() end --- Recursive depth-first traversal. --- If `visit` returns false, traversal is stopped early. --- @param visit fun(el: Element): boolean|nil --- @return boolean function Element:traverse(visit) local cont = visit(self) if not cont then return false end if not self.child then return false end self.child.parent = self return not not self.child:traverse(visit) end --- template constructor --- @param data {state: table, update: fun(dt: number), draw: fun(), [any]: any} --- @return Element function Element.new(data) return setmetatable(data, Element) end return Element