fixing things here and there

This commit is contained in:
Michael Freno
2025-09-17 18:20:49 -04:00
parent 262effacd7
commit 2256dd4345
2 changed files with 101 additions and 111 deletions

View File

@@ -338,6 +338,7 @@ end
---@field children table<integer, Element> -- Children of this element ---@field children table<integer, Element> -- Children of this element
---@field parent Element? -- Parent element (nil if top-level) ---@field parent Element? -- Parent element (nil if top-level)
---@field border Border -- Border configuration for the element ---@field border Border -- Border configuration for the element
---@field opacity number
---@field borderColor Color -- Color of the border ---@field borderColor Color -- Color of the border
---@field background Color -- Background color of the element ---@field background Color -- Background color of the element
---@field prevGameSize {width:number, height:number} -- Previous game size for resize calculations ---@field prevGameSize {width:number, height:number} -- Previous game size for resize calculations
@@ -370,6 +371,7 @@ Element.__index = Element
---@field h number? -- Height of the element (default: calculated automatically) ---@field h number? -- Height of the element (default: calculated automatically)
---@field border Border? -- Border configuration for the element ---@field border Border? -- Border configuration for the element
---@field borderColor Color? -- Color of the border (default: black) ---@field borderColor Color? -- Color of the border (default: black)
---@field opacity number?
---@field background Color? -- Background color (default: transparent) ---@field background Color? -- Background color (default: transparent)
---@field gap number? -- Space between children elements (default: 10) ---@field gap number? -- Space between children elements (default: 10)
---@field padding {top:number?, right:number?, bottom:number?, left:number?, horizontal: number?, vertical:number?}? -- Padding around children (default: {top=0, right=0, bottom=0, left=0}) ---@field padding {top:number?, right:number?, bottom:number?, left:number?, horizontal: number?, vertical:number?}? -- Padding around children (default: {top=0, right=0, bottom=0, left=0})
@@ -395,9 +397,11 @@ local ElementProps = {}
---@return Element ---@return Element
function Element.new(props) function Element.new(props)
local self = setmetatable({}, Element) local self = setmetatable({}, Element)
self.x = props.x or 0 self.children = {}
self.y = props.y or 0 self.callback = props.callback
------ add non-hereditary ------
--- self drawing---
self.border = props.border self.border = props.border
and { and {
top = props.border.top or false, top = props.border.top or false,
@@ -411,19 +415,15 @@ function Element.new(props)
bottom = false, bottom = false,
left = false, left = false,
} }
self.background = props.background or Color.new(0, 0, 0, 0)
self.borderColor = props.borderColor or Color.new(0, 0, 0, 1) self.borderColor = props.borderColor or Color.new(0, 0, 0, 1)
self.background = props.background or Color.new(0, 0, 0, 0)
self.opacity = props.opacity or 1
if props.textColor then self.text = props.text
self.textColor = props.textColor self.textSize = props.textSize
elseif props.parent then self.textAlign = props.textAlign or TextAlign.START
self.textColor = props.parent.textColor
else
self.textColor = Color.new(0, 0, 0, 1)
end
self.gap = props.gap or 10 --- self positioning ---
self.padding = props.padding self.padding = props.padding
and { and {
top = props.padding.top or props.padding.vertical or 0, top = props.padding.top or props.padding.vertical or 0,
@@ -437,6 +437,7 @@ function Element.new(props)
bottom = 0, bottom = 0,
left = 0, left = 0,
} }
self.margin = props.margin self.margin = props.margin
and { and {
top = props.margin.top or props.margin.vertical or 0, top = props.margin.top or props.margin.vertical or 0,
@@ -451,26 +452,48 @@ function Element.new(props)
left = 0, left = 0,
} }
self.text = props.text ---- Sizing ----
local gw, gh = love.window.getMode()
self.prevGameSize = { width = gw, height = gh }
self.autosizing = { width = false, height = false }
self.textColor = props.textColor if props.w then
if self.textColor == nil then self.width = props.w
if props.parent then else
self.textColor = props.parent.textColor self.autosizing.width = true
else self.width = self:calculateAutoWidth()
self.textColor = Color.new(0, 0, 0, 1) end
end if props.h then
self.height = props.h
else
self.autosizing.height = true
self.height = self:calculateAutoHeight()
end end
self.textAlign = props.textAlign or TextAlign.START
self.textSize = props.textSize
self.positioning = props.positioning --- child positioning ---
if props.positioning == nil then self.gap = props.gap or 10
if props.parent then
self.positioning = props.parent.positioning ------ add hereditary ------
else if props.parent == nil then
self.positioning = Positioning.ABSOLUTE table.insert(Gui.topElements, self)
end
self.x = props.x or 0
self.y = props.y or 0
self.z = props.z or 0
self.textColor = props.textColor or Color.new(0, 0, 0, 1)
self.positioning = props.positioning or Positioning.ABSOLUTE
else
self.parent = props.parent
self.x = self.parent.x + (props.x or 0)
self.y = self.parent.y + (props.y or 0)
self.z = props.z or self.parent.z or 0
self.textColor = props.textColor or self.parent.textColor
self.positioning = props.positioning or self.parent.positioning
props.parent:addChild(self)
end end
if self.positioning == Positioning.FLEX then if self.positioning == Positioning.FLEX then
@@ -482,53 +505,10 @@ function Element.new(props)
self.alignSelf = props.alignSelf or AlignSelf.AUTO self.alignSelf = props.alignSelf or AlignSelf.AUTO
end end
self.autosizing = { width = false, height = false } ---animation
if props.w then
self.width = props.w
else
self.autosizing.width = true
self.width = self:calculateAutoWidth()
end
if props.h then
self.height = props.h
else
self.autosizing.height = true
self.height = self:calculateAutoHeight()
end
self.parent = props.parent
if self.parent then
-- Only add parent position to child coordinates if parent is not absolutely positioned
if self.parent.positioning ~= Positioning.ABSOLUTE then
self.x = self.x + self.parent.x
self.y = self.y + self.parent.y
end
end
self.children = {}
if props.parent then
props.parent:addChild(self)
end
local gw, gh = love.window.getMode()
self.prevGameSize = { width = gw, height = gh }
self.z = props.z or 0
-- Add transform and transition properties
self.transform = props.transform or {} self.transform = props.transform or {}
self.transition = props.transition or {} self.transition = props.transition or {}
-- Initialize opacity for animations to work properly
self.opacity = self.background.a
-- Store callback function for click events
self.callback = props.callback or nil
if not props.parent then
table.insert(Gui.topElements, self)
end
return self return self
end end
@@ -543,12 +523,14 @@ end
function Element:addChild(child) function Element:addChild(child)
child.parent = self child.parent = self
table.insert(self.children, child) table.insert(self.children, child)
if self.autosizing.height then if self.autosizing.height then
self.height = self:calculateAutoHeight() self.height = self:calculateAutoHeight()
end end
if self.autosizing.width then if self.autosizing.width then
self.width = self:calculateAutoWidth() self.width = self:calculateAutoWidth()
end end
self:layoutChildren() self:layoutChildren()
end end
@@ -607,17 +589,19 @@ function Element:layoutChildren()
-- Skip positioning for absolute children as they should maintain their own coordinates -- Skip positioning for absolute children as they should maintain their own coordinates
goto continue goto continue
end end
if self.flexDirection == FlexDirection.VERTICAL then if self.flexDirection == FlexDirection.VERTICAL then
child.x = self.margin.left or 0 -- Position relative to parent origin
child.y = currentPos + (self.margin.top or 0) child.x = self.x + (self.margin.left or 0)
child.y = self.y + currentPos
-- Apply alignment to vertical axis (alignItems) -- Apply alignment to vertical axis (alignItems)
if self.alignItems == AlignItems.FLEX_START then if self.alignItems == AlignItems.FLEX_START then
--nothing, currentPos is all -- nothing
elseif self.alignItems == AlignItems.CENTER then elseif self.alignItems == AlignItems.CENTER then
child.x = (self.width - (child.width or 0)) / 2 child.x = self.x + (self.width - (child.width or 0)) / 2
elseif self.alignItems == AlignItems.FLEX_END then elseif self.alignItems == AlignItems.FLEX_END then
child.x = self.width - (child.width or 0) child.x = self.x + self.width - (child.width or 0)
elseif self.alignItems == AlignItems.STRETCH then elseif self.alignItems == AlignItems.STRETCH then
child.width = self.width child.width = self.width
end end
@@ -629,20 +613,19 @@ function Element:layoutChildren()
end end
if effectiveAlignSelf == AlignSelf.FLEX_START then if effectiveAlignSelf == AlignSelf.FLEX_START then
-- nothing, currentPos is all - position should be at the beginning of cross axis -- Position at the start of cross axis relative to parent
-- For VERTICAL flex, this means X = 0 child.x = self.x + (self.margin.left or 0)
child.x = 0
elseif effectiveAlignSelf == AlignSelf.CENTER then elseif effectiveAlignSelf == AlignSelf.CENTER then
if self.flexDirection == FlexDirection.VERTICAL then if self.flexDirection == FlexDirection.VERTICAL then
child.x = (self.width - (child.width or 0)) / 2 child.x = self.x + (self.width - (child.width or 0)) / 2
else else
child.y = self.y + (self.height - (child.height or 0)) / 2 + self.y child.y = self.y + (self.height - (child.height or 0)) / 2
end end
elseif effectiveAlignSelf == AlignSelf.FLEX_END then elseif effectiveAlignSelf == AlignSelf.FLEX_END then
if self.flexDirection == FlexDirection.VERTICAL then if self.flexDirection == FlexDirection.VERTICAL then
child.x = self.width - (child.width or 0) child.x = self.x + self.width - (child.width or 0)
else else
child.y = self.height - (child.height or 0) child.y = self.y + self.height - (child.height or 0)
end end
elseif effectiveAlignSelf == AlignSelf.STRETCH then elseif effectiveAlignSelf == AlignSelf.STRETCH then
if self.flexDirection == FlexDirection.VERTICAL then if self.flexDirection == FlexDirection.VERTICAL then
@@ -660,29 +643,29 @@ function Element:layoutChildren()
currentPos = currentPos + (child.height or 0) + self.gap + (self.margin.top or 0) + (self.margin.bottom or 0) currentPos = currentPos + (child.height or 0) + self.gap + (self.margin.top or 0) + (self.margin.bottom or 0)
else else
child.x = currentPos + (self.margin.left or 0) -- Horizontal layout: position relative to parent origin
-- Start with margin child.x = self.x + currentPos + (self.margin.left or 0)
child.y = self.margin.top or 0 child.y = self.y + (self.margin.top or 0)
-- Determine effective alignment - alignSelf takes precedence over alignItems -- Determine effective alignment - alignSelf takes precedence over alignItems
local effectiveAlign = child.alignSelf local effectiveAlign = child.alignSelf
if effectiveAlign == AlignSelf.AUTO then if effectiveAlign == AlignSelf.AUTO then
effectiveAlign = self.alignItems effectiveAlign = self.alignItems
end end
-- Apply alignment -- Apply alignment
if effectiveAlign == AlignItems.FLEX_START then if effectiveAlign == AlignItems.FLEX_START then
-- Keep the margin.top position -- Keep the margin.top position (already applied)
elseif effectiveAlign == AlignItems.CENTER then elseif effectiveAlign == AlignItems.CENTER then
child.y = (self.height - (child.height or 0)) / 2 child.y = self.y + (self.height - (child.height or 0)) / 2
elseif effectiveAlign == AlignItems.FLEX_END then elseif effectiveAlign == AlignItems.FLEX_END then
child.y = self.height - (child.height or 0) child.y = self.y + self.height - (child.height or 0)
elseif effectiveAlign == AlignItems.STRETCH then elseif effectiveAlign == AlignItems.STRETCH then
-- Only set height if not already stretched -- Only set height if not already stretched
if child.height ~= self.height then if child.height ~= self.height then
child.height = self.height child.height = self.height
end end
end end
currentPos = currentPos + (child.width or 0) + self.gap + (self.margin.left or 0) + (self.margin.right or 0) currentPos = currentPos + (child.width or 0) + self.gap + (self.margin.left or 0) + (self.margin.right or 0)
end end
@@ -987,6 +970,14 @@ function Element:updateText(newText, autoresize)
end end
end end
---@param newOpacity number
function Element:updateOpacity(newOpacity)
self.opacity = newOpacity
for _, child in ipairs(self.children) do
child:updateOpacity(newOpacity)
end
end
Gui.new = Element.new Gui.new = Element.new
Gui.Element = Element Gui.Element = Element
Gui.Animation = Animation Gui.Animation = Animation

View File

@@ -40,8 +40,8 @@ function TestAbsolutePositioning:testWindowWithAbsolutePositioning()
}) })
-- Verify child properties -- Verify child properties
luaunit.assertEquals(child.x, 20) luaunit.assertEquals(child.x, 120)
luaunit.assertEquals(child.y, 30) luaunit.assertEquals(child.y, 130)
luaunit.assertEquals(child.width, 50) luaunit.assertEquals(child.width, 50)
luaunit.assertEquals(child.height, 30) luaunit.assertEquals(child.height, 30)
luaunit.assertEquals(child.positioning, enums.Positioning.ABSOLUTE) luaunit.assertEquals(child.positioning, enums.Positioning.ABSOLUTE)
@@ -185,9 +185,8 @@ function TestAbsolutePositioning:testAbsolutePositioningWithPaddingAndMargin()
text = "Test Button", text = "Test Button",
}) })
-- Verify absolute child position is independent of padding/margin luaunit.assertEquals(child.x, 30)
luaunit.assertEquals(child.x, 20) luaunit.assertEquals(child.y, 40)
luaunit.assertEquals(child.y, 30)
end end
-- Run the tests -- Run the tests