change spacing logic
This commit is contained in:
137
FlexLove.lua
137
FlexLove.lua
@@ -778,9 +778,37 @@ function Grid.layoutGridItems(element)
|
||||
local rows = element.gridRows or 1
|
||||
local columns = element.gridColumns or 1
|
||||
|
||||
-- Calculate available space
|
||||
local availableWidth = element.width - element.padding.left - element.padding.right
|
||||
local availableHeight = element.height - element.padding.top - element.padding.bottom
|
||||
-- Calculate space reserved by absolutely positioned siblings
|
||||
local reservedLeft = 0
|
||||
local reservedRight = 0
|
||||
local reservedTop = 0
|
||||
local reservedBottom = 0
|
||||
|
||||
for _, child in ipairs(element.children) do
|
||||
-- Only consider absolutely positioned children with explicit positioning
|
||||
if child.positioning == Positioning.ABSOLUTE and child._explicitlyAbsolute then
|
||||
if child.left then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
reservedLeft = math.max(reservedLeft, child.left + childTotalWidth)
|
||||
end
|
||||
if child.right then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
reservedRight = math.max(reservedRight, child.right + childTotalWidth)
|
||||
end
|
||||
if child.top then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
reservedTop = math.max(reservedTop, child.top + childTotalHeight)
|
||||
end
|
||||
if child.bottom then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
reservedBottom = math.max(reservedBottom, child.bottom + childTotalHeight)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate available space (accounting for padding and reserved space)
|
||||
local availableWidth = element.width - element.padding.left - element.padding.right - reservedLeft - reservedRight
|
||||
local availableHeight = element.height - element.padding.top - element.padding.bottom - reservedTop - reservedBottom
|
||||
|
||||
-- Get gaps
|
||||
local columnGap = element.columnGap or 0
|
||||
@@ -812,9 +840,9 @@ function Grid.layoutGridItems(element)
|
||||
break
|
||||
end
|
||||
|
||||
-- Calculate cell position
|
||||
local cellX = element.x + element.padding.left + (col * (cellWidth + columnGap))
|
||||
local cellY = element.y + element.padding.top + (row * (cellHeight + rowGap))
|
||||
-- Calculate cell position (accounting for reserved space)
|
||||
local cellX = element.x + element.padding.left + reservedLeft + (col * (cellWidth + columnGap))
|
||||
local cellY = element.y + element.padding.top + reservedTop + (row * (cellHeight + rowGap))
|
||||
|
||||
-- Apply alignment within grid cell (default to stretch)
|
||||
local effectiveAlignItems = element.alignItems or AlignItems.STRETCH
|
||||
@@ -2016,15 +2044,80 @@ function Element:layoutChildren()
|
||||
return
|
||||
end
|
||||
|
||||
-- Calculate available space (accounting for padding)
|
||||
-- Calculate space reserved by absolutely positioned siblings with explicit positioning
|
||||
local reservedMainStart = 0 -- Space reserved at the start of main axis (left for horizontal, top for vertical)
|
||||
local reservedMainEnd = 0 -- Space reserved at the end of main axis (right for horizontal, bottom for vertical)
|
||||
local reservedCrossStart = 0 -- Space reserved at the start of cross axis (top for horizontal, left for vertical)
|
||||
local reservedCrossEnd = 0 -- Space reserved at the end of cross axis (bottom for horizontal, right for vertical)
|
||||
|
||||
for _, child in ipairs(self.children) do
|
||||
-- Only consider absolutely positioned children with explicit positioning
|
||||
if child.positioning == Positioning.ABSOLUTE and child._explicitlyAbsolute then
|
||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||
-- Horizontal layout: main axis is X, cross axis is Y
|
||||
-- Check for left positioning (reserves space at main axis start)
|
||||
if child.left then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
local spaceNeeded = child.left + childTotalWidth
|
||||
reservedMainStart = math.max(reservedMainStart, spaceNeeded)
|
||||
end
|
||||
-- Check for right positioning (reserves space at main axis end)
|
||||
if child.right then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
local spaceNeeded = child.right + childTotalWidth
|
||||
reservedMainEnd = math.max(reservedMainEnd, spaceNeeded)
|
||||
end
|
||||
-- Check for top positioning (reserves space at cross axis start)
|
||||
if child.top then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
local spaceNeeded = child.top + childTotalHeight
|
||||
reservedCrossStart = math.max(reservedCrossStart, spaceNeeded)
|
||||
end
|
||||
-- Check for bottom positioning (reserves space at cross axis end)
|
||||
if child.bottom then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
local spaceNeeded = child.bottom + childTotalHeight
|
||||
reservedCrossEnd = math.max(reservedCrossEnd, spaceNeeded)
|
||||
end
|
||||
else
|
||||
-- Vertical layout: main axis is Y, cross axis is X
|
||||
-- Check for top positioning (reserves space at main axis start)
|
||||
if child.top then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
local spaceNeeded = child.top + childTotalHeight
|
||||
reservedMainStart = math.max(reservedMainStart, spaceNeeded)
|
||||
end
|
||||
-- Check for bottom positioning (reserves space at main axis end)
|
||||
if child.bottom then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
local spaceNeeded = child.bottom + childTotalHeight
|
||||
reservedMainEnd = math.max(reservedMainEnd, spaceNeeded)
|
||||
end
|
||||
-- Check for left positioning (reserves space at cross axis start)
|
||||
if child.left then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
local spaceNeeded = child.left + childTotalWidth
|
||||
reservedCrossStart = math.max(reservedCrossStart, spaceNeeded)
|
||||
end
|
||||
-- Check for right positioning (reserves space at cross axis end)
|
||||
if child.right then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
local spaceNeeded = child.right + childTotalWidth
|
||||
reservedCrossEnd = math.max(reservedCrossEnd, spaceNeeded)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate available space (accounting for padding and reserved space)
|
||||
local availableMainSize = 0
|
||||
local availableCrossSize = 0
|
||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||
availableMainSize = self.width - self.padding.left - self.padding.right
|
||||
availableCrossSize = self.height - self.padding.top - self.padding.bottom
|
||||
availableMainSize = self.width - self.padding.left - self.padding.right - reservedMainStart - reservedMainEnd
|
||||
availableCrossSize = self.height - self.padding.top - self.padding.bottom - reservedCrossStart - reservedCrossEnd
|
||||
else
|
||||
availableMainSize = self.height - self.padding.top - self.padding.bottom
|
||||
availableCrossSize = self.width - self.padding.left - self.padding.right
|
||||
availableMainSize = self.height - self.padding.top - self.padding.bottom - reservedMainStart - reservedMainEnd
|
||||
availableCrossSize = self.width - self.padding.left - self.padding.right - reservedCrossStart - reservedCrossEnd
|
||||
end
|
||||
|
||||
-- Handle flex wrap: create lines of children
|
||||
@@ -2208,20 +2301,21 @@ function Element:layoutChildren()
|
||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||
-- Horizontal layout: main axis is X, cross axis is Y
|
||||
-- Position child at border box (x, y represents top-left including padding)
|
||||
child.x = self.x + self.padding.left + currentMainPos
|
||||
-- Add reservedMainStart to account for absolutely positioned siblings
|
||||
child.x = self.x + self.padding.left + reservedMainStart + currentMainPos
|
||||
|
||||
if effectiveAlign == AlignItems.FLEX_START then
|
||||
child.y = self.y + self.padding.top + currentCrossPos
|
||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos
|
||||
elseif effectiveAlign == AlignItems.CENTER then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
child.y = self.y + self.padding.top + currentCrossPos + ((lineHeight - childTotalHeight) / 2)
|
||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos + ((lineHeight - childTotalHeight) / 2)
|
||||
elseif effectiveAlign == AlignItems.FLEX_END then
|
||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||
child.y = self.y + self.padding.top + currentCrossPos + lineHeight - childTotalHeight
|
||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos + lineHeight - childTotalHeight
|
||||
elseif effectiveAlign == AlignItems.STRETCH then
|
||||
-- STRETCH always stretches children in cross-axis direction
|
||||
child.height = lineHeight - child.padding.top - child.padding.bottom
|
||||
child.y = self.y + self.padding.top + currentCrossPos
|
||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos
|
||||
end
|
||||
|
||||
-- Apply positioning offsets (top, right, bottom, left)
|
||||
@@ -2243,20 +2337,21 @@ function Element:layoutChildren()
|
||||
else
|
||||
-- Vertical layout: main axis is Y, cross axis is X
|
||||
-- Position child at border box (x, y represents top-left including padding)
|
||||
child.y = self.y + self.padding.top + currentMainPos
|
||||
-- Add reservedMainStart to account for absolutely positioned siblings
|
||||
child.y = self.y + self.padding.top + reservedMainStart + currentMainPos
|
||||
|
||||
if effectiveAlign == AlignItems.FLEX_START then
|
||||
child.x = self.x + self.padding.left + currentCrossPos
|
||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos
|
||||
elseif effectiveAlign == AlignItems.CENTER then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
child.x = self.x + self.padding.left + currentCrossPos + ((lineHeight - childTotalWidth) / 2)
|
||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos + ((lineHeight - childTotalWidth) / 2)
|
||||
elseif effectiveAlign == AlignItems.FLEX_END then
|
||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||
child.x = self.x + self.padding.left + currentCrossPos + lineHeight - childTotalWidth
|
||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos + lineHeight - childTotalWidth
|
||||
elseif effectiveAlign == AlignItems.STRETCH then
|
||||
-- STRETCH always stretches children in cross-axis direction
|
||||
child.width = lineHeight - child.padding.left - child.padding.right
|
||||
child.x = self.x + self.padding.left + currentCrossPos
|
||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos
|
||||
end
|
||||
|
||||
-- Apply positioning offsets (top, right, bottom, left)
|
||||
|
||||
@@ -6,7 +6,7 @@ FlexLöve is a lightweight, flexible GUI library for Löve2D that implements a f
|
||||
|
||||
## ⚠️ Development Status
|
||||
|
||||
This library is under active development. While many features are functional, some aspects may change or have incomplete implementations.
|
||||
This library is under active development. While many features are functional, some aspects may change or have incomplete/broken implementations.
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
437
testing/__tests__/17_sibling_space_reservation_tests.lua
Normal file
437
testing/__tests__/17_sibling_space_reservation_tests.lua
Normal file
@@ -0,0 +1,437 @@
|
||||
-- Test: Sibling Space Reservation in Flex and Grid Layouts
|
||||
-- Purpose: Verify that absolutely positioned siblings with explicit positioning
|
||||
-- properly reserve space in flex and grid containers
|
||||
|
||||
local lu = require("testing.luaunit")
|
||||
local FlexLove = require("libs.FlexLove")
|
||||
local Gui = FlexLove.GUI
|
||||
local Color = FlexLove.Color
|
||||
|
||||
-- Mock love.graphics and love.window
|
||||
_G.love = require("testing.loveStub")
|
||||
|
||||
TestSiblingSpaceReservation = {}
|
||||
|
||||
function TestSiblingSpaceReservation:setUp()
|
||||
-- Reset GUI state before each test
|
||||
Gui.destroy()
|
||||
-- Set up a standard viewport
|
||||
love.window.setMode(1920, 1080)
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:tearDown()
|
||||
Gui.destroy()
|
||||
end
|
||||
|
||||
-- ====================
|
||||
-- Flex Layout Tests
|
||||
-- ====================
|
||||
|
||||
function TestSiblingSpaceReservation:test_flex_horizontal_left_positioned_sibling_reserves_space()
|
||||
-- Create a flex container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal",
|
||||
justifyContent = "flex-start",
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add an absolutely positioned sibling with left positioning
|
||||
local absoluteSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
left = 10, -- 10px from left edge
|
||||
width = 50,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
-- Add a flex child that should start after the absolutely positioned sibling
|
||||
local flexChild = Gui.new({
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- The absolutely positioned sibling reserves: left (10) + width (50) + padding (0) = 60px
|
||||
-- The flex child should start at x = container.x + padding.left + reservedLeft
|
||||
-- = 0 + 0 + 60 = 60
|
||||
lu.assertEquals(flexChild.x, 60, "Flex child should start after absolutely positioned sibling")
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:test_flex_horizontal_right_positioned_sibling_reserves_space()
|
||||
-- Create a flex container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal",
|
||||
justifyContent = "flex-start",
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add an absolutely positioned sibling with right positioning
|
||||
local absoluteSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
right = 10, -- 10px from right edge
|
||||
width = 50,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
-- Add a flex child
|
||||
local flexChild = Gui.new({
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- The absolutely positioned sibling reserves: right (10) + width (50) + padding (0) = 60px
|
||||
-- Available space = 1000 - 0 (padding) - 0 (reservedLeft) - 60 (reservedRight) = 940px
|
||||
-- The flex child (width 100) should fit within this space
|
||||
-- Child should start at x = 0
|
||||
lu.assertEquals(flexChild.x, 0, "Flex child should start at container left edge")
|
||||
|
||||
-- The absolutely positioned sibling should be at the right edge
|
||||
-- x = container.x + container.width + padding.left - right - (width + padding)
|
||||
-- = 0 + 1000 + 0 - 10 - 50 = 940
|
||||
lu.assertEquals(absoluteSibling.x, 940, "Absolutely positioned sibling should be at right edge")
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:test_flex_vertical_top_positioned_sibling_reserves_space()
|
||||
-- Create a vertical flex container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 1000,
|
||||
positioning = "flex",
|
||||
flexDirection = "vertical",
|
||||
justifyContent = "flex-start",
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add an absolutely positioned sibling with top positioning
|
||||
local absoluteSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 10, -- 10px from top edge
|
||||
width = 50,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
-- Add a flex child that should start after the absolutely positioned sibling
|
||||
local flexChild = Gui.new({
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 100,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- The absolutely positioned sibling reserves: top (10) + height (50) + padding (0) = 60px
|
||||
-- The flex child should start at y = container.y + padding.top + reservedTop
|
||||
-- = 0 + 0 + 60 = 60
|
||||
lu.assertEquals(flexChild.y, 60, "Flex child should start after absolutely positioned sibling")
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:test_flex_horizontal_multiple_positioned_siblings()
|
||||
-- Create a flex container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal",
|
||||
justifyContent = "flex-start",
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add two absolutely positioned siblings (left and right)
|
||||
local leftSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
left = 5,
|
||||
width = 40,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
local rightSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
right = 5,
|
||||
width = 40,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 0, 1, 1),
|
||||
})
|
||||
|
||||
-- Add flex children
|
||||
local flexChild1 = Gui.new({
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
local flexChild2 = Gui.new({
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 1, 1, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- Reserved left: 5 + 40 = 45px
|
||||
-- Reserved right: 5 + 40 = 45px
|
||||
-- Available space: 1000 - 45 - 45 = 910px
|
||||
-- First flex child should start at x = 0 + 0 + 45 = 45
|
||||
lu.assertEquals(flexChild1.x, 45, "First flex child should start after left sibling")
|
||||
|
||||
-- Second flex child should start at x = 45 + 100 + gap = 145 (assuming gap=10)
|
||||
lu.assertIsTrue(flexChild2.x >= 145, "Second flex child should be positioned after first")
|
||||
end
|
||||
|
||||
-- ====================
|
||||
-- Grid Layout Tests
|
||||
-- ====================
|
||||
|
||||
function TestSiblingSpaceReservation:test_grid_left_positioned_sibling_reserves_space()
|
||||
-- Create a grid container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 500,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 3,
|
||||
columnGap = 10,
|
||||
rowGap = 10,
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add an absolutely positioned sibling with left positioning
|
||||
local absoluteSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
left = 10,
|
||||
width = 50,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
-- Add grid children
|
||||
local gridChild1 = Gui.new({
|
||||
parent = container,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- Reserved left: 10 + 50 = 60px
|
||||
-- Available width: 1000 - 60 = 940px
|
||||
-- Column gaps: 2 * 10 = 20px
|
||||
-- Cell width: (940 - 20) / 3 = 306.67px
|
||||
-- First grid child should start at x = 0 + 0 + 60 = 60
|
||||
lu.assertEquals(gridChild1.x, 60, "Grid child should start after absolutely positioned sibling")
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:test_grid_top_positioned_sibling_reserves_space()
|
||||
-- Create a grid container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 500,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 3,
|
||||
columnGap = 10,
|
||||
rowGap = 10,
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add an absolutely positioned sibling with top positioning
|
||||
local absoluteSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 10,
|
||||
width = 50,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
-- Add grid children
|
||||
local gridChild1 = Gui.new({
|
||||
parent = container,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- Reserved top: 10 + 50 = 60px
|
||||
-- Available height: 500 - 60 = 440px
|
||||
-- Row gaps: 1 * 10 = 10px
|
||||
-- Cell height: (440 - 10) / 2 = 215px
|
||||
-- First grid child should start at y = 0 + 0 + 60 = 60
|
||||
lu.assertEquals(gridChild1.y, 60, "Grid child should start after absolutely positioned sibling")
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:test_grid_multiple_positioned_siblings()
|
||||
-- Create a grid container
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 500,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2,
|
||||
columnGap = 0,
|
||||
rowGap = 0,
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Add absolutely positioned siblings at all corners
|
||||
local topLeftSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
left = 10,
|
||||
top = 10,
|
||||
width = 40,
|
||||
height = 40,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
local bottomRightSibling = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
right = 10,
|
||||
bottom = 10,
|
||||
width = 40,
|
||||
height = 40,
|
||||
backgroundColor = Color.new(0, 0, 1, 1),
|
||||
})
|
||||
|
||||
-- Add grid children
|
||||
local gridChild1 = Gui.new({
|
||||
parent = container,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- Reserved left: 10 + 40 = 50px
|
||||
-- Reserved right: 10 + 40 = 50px
|
||||
-- Reserved top: 10 + 40 = 50px
|
||||
-- Reserved bottom: 10 + 40 = 50px
|
||||
-- Available width: 1000 - 50 - 50 = 900px
|
||||
-- Available height: 500 - 50 - 50 = 400px
|
||||
-- Cell width: 900 / 2 = 450px
|
||||
-- Cell height: 400 / 2 = 200px
|
||||
-- First grid child should start at (50, 50)
|
||||
lu.assertEquals(gridChild1.x, 50, "Grid child X should account for left sibling")
|
||||
lu.assertEquals(gridChild1.y, 50, "Grid child Y should account for top sibling")
|
||||
lu.assertEquals(gridChild1.width, 450, "Grid cell width should account for reserved space")
|
||||
lu.assertEquals(gridChild1.height, 200, "Grid cell height should account for reserved space")
|
||||
end
|
||||
|
||||
-- ====================
|
||||
-- Edge Cases
|
||||
-- ====================
|
||||
|
||||
function TestSiblingSpaceReservation:test_non_explicitly_absolute_children_dont_reserve_space()
|
||||
-- Children that default to absolute positioning (not explicitly set)
|
||||
-- should NOT reserve space in flex layouts
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal",
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- This child has positioning="flex" so it participates in layout
|
||||
local flexChild = Gui.new({
|
||||
parent = container,
|
||||
positioning = "flex",
|
||||
left = 10, -- This should be ignored since it's a flex child
|
||||
width = 100,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- Flex child should start at x = 0 (no reserved space)
|
||||
lu.assertEquals(flexChild.x, 0, "Flex children with positioning offsets should not reserve space")
|
||||
end
|
||||
|
||||
function TestSiblingSpaceReservation:test_absolute_without_positioning_offsets_doesnt_reserve_space()
|
||||
-- Absolutely positioned children without left/right/top/bottom
|
||||
-- should NOT reserve space
|
||||
local container = Gui.new({
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 1000,
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal",
|
||||
padding = { top = 0, right = 0, bottom = 0, left = 0 },
|
||||
})
|
||||
|
||||
-- Absolutely positioned but no positioning offsets
|
||||
local absoluteChild = Gui.new({
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
x = 50,
|
||||
y = 50,
|
||||
width = 50,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(1, 0, 0, 1),
|
||||
})
|
||||
|
||||
-- Flex child
|
||||
local flexChild = Gui.new({
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 50,
|
||||
backgroundColor = Color.new(0, 1, 0, 1),
|
||||
})
|
||||
|
||||
-- Layout children
|
||||
container:layoutChildren()
|
||||
|
||||
-- Flex child should start at x = 0 (no reserved space)
|
||||
lu.assertEquals(flexChild.x, 0, "Absolute children without positioning offsets should not reserve space")
|
||||
end
|
||||
|
||||
return TestSiblingSpaceReservation
|
||||
@@ -20,6 +20,7 @@ local testFiles = {
|
||||
"testing/__tests__/14_text_scaling_basic_tests.lua",
|
||||
"testing/__tests__/15_grid_layout_tests.lua",
|
||||
"testing/__tests__/16_event_system_tests.lua",
|
||||
"testing/__tests__/17_sibling_space_reservation_tests.lua",
|
||||
}
|
||||
|
||||
-- testingun all tests, but don't exit on error
|
||||
|
||||
Reference in New Issue
Block a user