This commit is contained in:
Michael Freno
2025-09-18 22:26:25 -04:00
parent 5704c4de95
commit c0684e88ab
2 changed files with 57 additions and 125 deletions

View File

@@ -804,43 +804,14 @@ function Element:layoutChildren()
for _, child in ipairs(line) do for _, child in ipairs(line) do
-- Determine effective cross-axis alignment -- Determine effective cross-axis alignment
local effectiveAlign = child.alignSelf local effectiveAlign = child.alignSelf
if effectiveAlign == AlignSelf.AUTO then if effectiveAlign == nil or effectiveAlign == AlignSelf.AUTO then
effectiveAlign = self.alignItems effectiveAlign = self.alignItems
end end
-- DEBUG: Print alignment info for last child
-- DEBUG: Output alignment information for troubleshooting
if child.debugId or (_ == #line) then
local debugPrefix = child.debugId and string.format("[%s]", child.debugId) or "[LAST_CHILD]"
print(
string.format(
"DEBUG %s: effectiveAlign='%s', alignSelf='%s', parent.alignItems='%s'",
debugPrefix,
tostring(effectiveAlign),
tostring(child.alignSelf),
tostring(self.alignItems)
)
)
end
if self.flexDirection == FlexDirection.HORIZONTAL then if self.flexDirection == FlexDirection.HORIZONTAL then
-- Horizontal layout: main axis is X, cross axis is Y -- Horizontal layout: main axis is X, cross axis is Y
child.x = self.x + self.padding.left + currentMainPos child.x = self.x + self.padding.left + currentMainPos
-- Apply cross-axis (vertical) alignment within the line
-- Additional DEBUG: Log detailed positioning for elements with debugId
if child.debugId then
print(
string.format(
"DEBUG [%s]: HORIZONTAL layout - lineHeight=%.2f, childHeight=%.2f, currentCrossPos=%.2f",
child.debugId,
lineHeight,
child.height or 0,
currentCrossPos
)
)
end
if effectiveAlign == AlignItems.FLEX_START then if effectiveAlign == AlignItems.FLEX_START then
child.y = self.y + self.padding.top + currentCrossPos child.y = self.y + self.padding.top + currentCrossPos
elseif effectiveAlign == AlignItems.CENTER then elseif effectiveAlign == AlignItems.CENTER then
@@ -850,15 +821,6 @@ function Element:layoutChildren()
elseif effectiveAlign == AlignItems.STRETCH then elseif effectiveAlign == AlignItems.STRETCH then
child.height = lineHeight child.height = lineHeight
child.y = self.y + self.padding.top + currentCrossPos child.y = self.y + self.padding.top + currentCrossPos
else
-- Default fallback: treat as FLEX_START
print(
string.format(
"WARNING: Unknown effectiveAlign value '%s', defaulting to FLEX_START",
tostring(effectiveAlign)
)
)
child.y = self.y + self.padding.top + currentCrossPos
end end
-- Final position DEBUG for elements with debugId -- Final position DEBUG for elements with debugId
@@ -871,44 +833,15 @@ function Element:layoutChildren()
-- Vertical layout: main axis is Y, cross axis is X -- Vertical layout: main axis is Y, cross axis is X
child.y = self.y + self.padding.top + currentMainPos child.y = self.y + self.padding.top + currentMainPos
-- Apply cross-axis (horizontal) alignment within the line
-- Additional DEBUG: Log detailed positioning for elements with debugId
if child.debugId then
print(
string.format(
"DEBUG [%s]: VERTICAL layout - lineHeight=%.2f, childWidth=%.2f, currentCrossPos=%.2f",
child.debugId,
lineHeight,
child.width or 0,
currentCrossPos
)
)
end
if effectiveAlign == AlignItems.FLEX_START then if effectiveAlign == AlignItems.FLEX_START then
child.x = self.x + self.padding.left + currentCrossPos child.x = self.x + self.padding.left + currentCrossPos
elseif effectiveAlign == AlignItems.CENTER then elseif effectiveAlign == AlignItems.CENTER then
Logger:debug(lineHeight)
child.x = self.x + self.padding.left + currentCrossPos + ((lineHeight - (child.width or 0)) / 2) child.x = self.x + self.padding.left + currentCrossPos + ((lineHeight - (child.width or 0)) / 2)
elseif effectiveAlign == AlignItems.FLEX_END then elseif effectiveAlign == AlignItems.FLEX_END then
child.x = self.x + self.padding.left + currentCrossPos + lineHeight - (child.width or 0) child.x = self.x + self.padding.left + currentCrossPos + lineHeight - (child.width or 0)
elseif effectiveAlign == AlignItems.STRETCH then elseif effectiveAlign == AlignItems.STRETCH then
child.width = lineHeight child.width = lineHeight
child.x = self.x + self.padding.left + currentCrossPos child.x = self.x + self.padding.left + currentCrossPos
else
-- Default fallback: treat as FLEX_START
print(
string.format(
"WARNING: Unknown effectiveAlign value '%s', defaulting to FLEX_START",
tostring(effectiveAlign)
)
)
child.x = self.x + self.padding.left + currentCrossPos
end
-- Final position DEBUG for elements with debugId
if child.debugId then
print(string.format("DEBUG [%s]: Final X position: %.2f", child.debugId, child.x))
end end
currentMainPos = currentMainPos + (child.height or 0) + itemSpacing currentMainPos = currentMainPos + (child.height or 0) + itemSpacing

View File

@@ -27,16 +27,16 @@ function TestAbsolutePositioningBasic:testCreateElementWithAbsolutePositioning()
y = 200, y = 200,
w = 300, w = 300,
h = 150, h = 150,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Verify element was created with correct properties -- Verify element was created with correct properties
luaunit.assertEquals(elem.x, 100) luaunit.assertEquals(elem.x, 100)
luaunit.assertEquals(elem.y, 200) luaunit.assertEquals(elem.y, 200)
luaunit.assertEquals(elem.width, 300) luaunit.assertEquals(elem.width, 300)
luaunit.assertEquals(elem.height, 150) luaunit.assertEquals(elem.height, 150)
luaunit.assertEquals(elem.positioning, Positioning.ABSOLUTE) luaunit.assertEquals(elem.positioning, Positioning.ABSOLUTE)
-- Verify element was added to topElements -- Verify element was added to topElements
luaunit.assertEquals(#Gui.topElements, 1) luaunit.assertEquals(#Gui.topElements, 1)
luaunit.assertEquals(Gui.topElements[1], elem) luaunit.assertEquals(Gui.topElements[1], elem)
@@ -48,9 +48,9 @@ function TestAbsolutePositioningBasic:testDefaultAbsolutePositioning()
x = 50, x = 50,
y = 75, y = 75,
w = 200, w = 200,
h = 100 h = 100,
}) })
-- Default should be absolute positioning -- Default should be absolute positioning
luaunit.assertEquals(elem.positioning, Positioning.ABSOLUTE) luaunit.assertEquals(elem.positioning, Positioning.ABSOLUTE)
luaunit.assertEquals(elem.x, 50) luaunit.assertEquals(elem.x, 50)
@@ -65,31 +65,31 @@ function TestAbsolutePositioningBasic:testZIndexHandling()
w = 100, w = 100,
h = 100, h = 100,
z = 1, z = 1,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
local elem2 = Gui.new({ local elem2 = Gui.new({
x = 50, x = 50,
y = 50, y = 50,
w = 100, w = 100,
h = 100, h = 100,
z = 5, z = 5,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
local elem3 = Gui.new({ local elem3 = Gui.new({
x = 25, x = 25,
y = 25, y = 25,
w = 100, w = 100,
h = 100, h = 100,
z = 3, z = 3,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
luaunit.assertEquals(elem1.z, 1) luaunit.assertEquals(elem1.z, 1)
luaunit.assertEquals(elem2.z, 5) luaunit.assertEquals(elem2.z, 5)
luaunit.assertEquals(elem3.z, 3) luaunit.assertEquals(elem3.z, 3)
-- All should be in topElements -- All should be in topElements
luaunit.assertEquals(#Gui.topElements, 3) luaunit.assertEquals(#Gui.topElements, 3)
end end
@@ -101,9 +101,9 @@ function TestAbsolutePositioningBasic:testDefaultZIndex()
y = 20, y = 20,
w = 50, w = 50,
h = 50, h = 50,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
luaunit.assertEquals(elem.z, 0) luaunit.assertEquals(elem.z, 0)
end end
@@ -114,23 +114,23 @@ function TestAbsolutePositioningBasic:testCoordinateIndependence()
y = 100, y = 100,
w = 50, w = 50,
h = 50, h = 50,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
local elem2 = Gui.new({ local elem2 = Gui.new({
x = 200, x = 200,
y = 200, y = 200,
w = 50, w = 50,
h = 50, h = 50,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Elements should maintain their own coordinates -- Elements should maintain their own coordinates
luaunit.assertEquals(elem1.x, 100) luaunit.assertEquals(elem1.x, 100)
luaunit.assertEquals(elem1.y, 100) luaunit.assertEquals(elem1.y, 100)
luaunit.assertEquals(elem2.x, 200) luaunit.assertEquals(elem2.x, 200)
luaunit.assertEquals(elem2.y, 200) luaunit.assertEquals(elem2.y, 200)
-- Modifying one shouldn't affect the other -- Modifying one shouldn't affect the other
elem1.x = 150 elem1.x = 150
luaunit.assertEquals(elem1.x, 150) luaunit.assertEquals(elem1.x, 150)
@@ -144,23 +144,23 @@ function TestAbsolutePositioningBasic:testAbsoluteWithParentIndependentCoordinat
y = 50, y = 50,
w = 200, w = 200,
h = 200, h = 200,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
local child = Gui.new({ local child = Gui.new({
parent = parent, parent = parent,
x = 25, x = 25,
y = 25, y = 25,
w = 50, w = 50,
h = 50, h = 50,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Child should maintain its absolute coordinates (CSS absolute behavior) -- Child should maintain its absolute coordinates (CSS absolute behavior)
luaunit.assertEquals(child.x, 25) luaunit.assertEquals(child.x, 25)
luaunit.assertEquals(child.y, 25) luaunit.assertEquals(child.y, 25)
luaunit.assertEquals(child.positioning, Positioning.ABSOLUTE) luaunit.assertEquals(child.positioning, Positioning.ABSOLUTE)
-- Parent should have the child -- Parent should have the child
luaunit.assertEquals(#parent.children, 1) luaunit.assertEquals(#parent.children, 1)
luaunit.assertEquals(parent.children[1], child) luaunit.assertEquals(parent.children[1], child)
@@ -169,7 +169,7 @@ end
-- Test 7: Multiple absolute elements should not interfere -- Test 7: Multiple absolute elements should not interfere
function TestAbsolutePositioningBasic:testMultipleAbsoluteElementsNonInterference() function TestAbsolutePositioningBasic:testMultipleAbsoluteElementsNonInterference()
local elements = {} local elements = {}
for i = 1, 5 do for i = 1, 5 do
elements[i] = Gui.new({ elements[i] = Gui.new({
x = i * 10, x = i * 10,
@@ -177,10 +177,10 @@ function TestAbsolutePositioningBasic:testMultipleAbsoluteElementsNonInterferenc
w = 30, w = 30,
h = 40, h = 40,
z = i, z = i,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
end end
-- Verify all elements maintain their properties -- Verify all elements maintain their properties
for i = 1, 5 do for i = 1, 5 do
luaunit.assertEquals(elements[i].x, i * 10) luaunit.assertEquals(elements[i].x, i * 10)
@@ -189,7 +189,7 @@ function TestAbsolutePositioningBasic:testMultipleAbsoluteElementsNonInterferenc
luaunit.assertEquals(elements[i].height, 40) luaunit.assertEquals(elements[i].height, 40)
luaunit.assertEquals(elements[i].z, i) luaunit.assertEquals(elements[i].z, i)
end end
luaunit.assertEquals(#Gui.topElements, 5) luaunit.assertEquals(#Gui.topElements, 5)
end end
@@ -200,9 +200,9 @@ function TestAbsolutePositioningBasic:testNegativeCoordinates()
y = -100, y = -100,
w = 200, w = 200,
h = 150, h = 150,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
luaunit.assertEquals(elem.x, -50) luaunit.assertEquals(elem.x, -50)
luaunit.assertEquals(elem.y, -100) luaunit.assertEquals(elem.y, -100)
end end
@@ -214,9 +214,9 @@ function TestAbsolutePositioningBasic:testZeroCoordinates()
y = 0, y = 0,
w = 100, w = 100,
h = 100, h = 100,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
luaunit.assertEquals(elem.x, 0) luaunit.assertEquals(elem.x, 0)
luaunit.assertEquals(elem.y, 0) luaunit.assertEquals(elem.y, 0)
end end
@@ -226,9 +226,9 @@ function TestAbsolutePositioningBasic:testDefaultCoordinates()
local elem = Gui.new({ local elem = Gui.new({
w = 100, w = 100,
h = 100, h = 100,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Default coordinates should be 0,0 -- Default coordinates should be 0,0
luaunit.assertEquals(elem.x, 0) luaunit.assertEquals(elem.x, 0)
luaunit.assertEquals(elem.y, 0) luaunit.assertEquals(elem.y, 0)
@@ -241,9 +241,9 @@ function TestAbsolutePositioningBasic:testElementBounds()
y = 200, y = 200,
w = 300, w = 300,
h = 400, h = 400,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
local bounds = elem:getBounds() local bounds = elem:getBounds()
luaunit.assertEquals(bounds.x, 100) luaunit.assertEquals(bounds.x, 100)
luaunit.assertEquals(bounds.y, 200) luaunit.assertEquals(bounds.y, 200)
@@ -258,23 +258,23 @@ function TestAbsolutePositioningBasic:testParentChildRelationshipAbsolute()
y = 100, y = 100,
w = 300, w = 300,
h = 300, h = 300,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
local child = Gui.new({ local child = Gui.new({
parent = parent, parent = parent,
x = 50, x = 50,
y = 75, y = 75,
w = 100, w = 100,
h = 150, h = 150,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Verify parent-child relationship -- Verify parent-child relationship
luaunit.assertEquals(child.parent, parent) luaunit.assertEquals(child.parent, parent)
luaunit.assertEquals(#parent.children, 1) luaunit.assertEquals(#parent.children, 1)
luaunit.assertEquals(parent.children[1], child) luaunit.assertEquals(parent.children[1], child)
-- Child should maintain absolute coordinates -- Child should maintain absolute coordinates
luaunit.assertEquals(child.x, 50) luaunit.assertEquals(child.x, 50)
luaunit.assertEquals(child.y, 75) luaunit.assertEquals(child.y, 75)
@@ -285,22 +285,21 @@ function TestAbsolutePositioningBasic:testAbsoluteChildNoParentAutoSizeAffect()
local parent = Gui.new({ local parent = Gui.new({
x = 0, x = 0,
y = 0, y = 0,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
-- No w/h specified, should auto-size
}) })
local originalParentWidth = parent.width local originalParentWidth = parent.width
local originalParentHeight = parent.height local originalParentHeight = parent.height
local child = Gui.new({ local child = Gui.new({
parent = parent, parent = parent,
x = 1000, -- Far outside parent x = 1000, -- Far outside parent
y = 1000, y = 1000,
w = 500, w = 500,
h = 500, h = 500,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Parent size should not be affected by absolute positioned child -- Parent size should not be affected by absolute positioned child
-- (In CSS, absolute children don't affect parent size) -- (In CSS, absolute children don't affect parent size)
luaunit.assertEquals(parent.width, originalParentWidth) luaunit.assertEquals(parent.width, originalParentWidth)
@@ -315,30 +314,30 @@ function TestAbsolutePositioningBasic:testAbsoluteNoFlexParticipation()
w = 400, w = 400,
h = 200, h = 200,
positioning = Positioning.FLEX, positioning = Positioning.FLEX,
flexDirection = enums.FlexDirection.HORIZONTAL flexDirection = enums.FlexDirection.HORIZONTAL,
}) })
local flexChild = Gui.new({ local flexChild = Gui.new({
parent = flexParent, parent = flexParent,
w = 100, w = 100,
h = 50, h = 50,
positioning = Positioning.FLEX positioning = Positioning.FLEX,
}) })
local absoluteChild = Gui.new({ local absoluteChild = Gui.new({
parent = flexParent, parent = flexParent,
x = 300, x = 300,
y = 150, y = 150,
w = 80, w = 80,
h = 40, h = 40,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
-- Absolute child should maintain its coordinates -- Absolute child should maintain its coordinates
luaunit.assertEquals(absoluteChild.x, 300) luaunit.assertEquals(absoluteChild.x, 300)
luaunit.assertEquals(absoluteChild.y, 150) luaunit.assertEquals(absoluteChild.y, 150)
luaunit.assertEquals(absoluteChild.positioning, Positioning.ABSOLUTE) luaunit.assertEquals(absoluteChild.positioning, Positioning.ABSOLUTE)
-- Both children should be in parent -- Both children should be in parent
luaunit.assertEquals(#flexParent.children, 2) luaunit.assertEquals(#flexParent.children, 2)
end end
@@ -351,12 +350,12 @@ function TestAbsolutePositioningBasic:testLargeCoordinateValues()
w = 100, w = 100,
h = 100, h = 100,
z = 1000, z = 1000,
positioning = Positioning.ABSOLUTE positioning = Positioning.ABSOLUTE,
}) })
luaunit.assertEquals(elem.x, 9999) luaunit.assertEquals(elem.x, 9999)
luaunit.assertEquals(elem.y, 8888) luaunit.assertEquals(elem.y, 8888)
luaunit.assertEquals(elem.z, 1000) luaunit.assertEquals(elem.z, 1000)
end end
luaunit.LuaUnit.run() luaunit.LuaUnit.run()