2261 lines
53 KiB
Lua
2261 lines
53 KiB
Lua
-- 06. Align Items Tests
|
|
-- Tests for FlexLove align items functionality
|
|
|
|
-- Load test framework and dependencies
|
|
package.path = package.path .. ";?.lua"
|
|
|
|
local luaunit = require("testing/luaunit")
|
|
require("testing/loveStub") -- Required to mock LOVE functions
|
|
local FlexLove = require("FlexLove")
|
|
local Gui, enums = FlexLove.GUI, FlexLove.enums
|
|
|
|
-- Import required enums
|
|
local Positioning = enums.Positioning
|
|
local FlexDirection = enums.FlexDirection
|
|
local AlignItems = enums.AlignItems
|
|
local JustifyContent = enums.JustifyContent
|
|
|
|
-- Test class for align items functionality
|
|
TestAlignItems = {}
|
|
|
|
function TestAlignItems:setUp()
|
|
-- Clear any previous state if needed
|
|
Gui.destroy()
|
|
end
|
|
|
|
function TestAlignItems:tearDown()
|
|
-- Clean up after each test
|
|
Gui.destroy()
|
|
end
|
|
|
|
-- Test 1: Horizontal Flex with AlignItems.FLEX_START
|
|
function TestAlignItems:testHorizontalFlexAlignItemsFlexStart()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child3 = Gui.new({
|
|
id = "child3",
|
|
w = 70,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
container:addChild(child3)
|
|
|
|
-- With FLEX_START, children should be aligned to top (start of cross axis)
|
|
luaunit.assertEquals(child1.y, 0)
|
|
luaunit.assertEquals(child2.y, 0)
|
|
luaunit.assertEquals(child3.y, 0)
|
|
|
|
-- Heights should remain original (no stretching)
|
|
luaunit.assertEquals(child1.height, 30)
|
|
luaunit.assertEquals(child2.height, 40)
|
|
luaunit.assertEquals(child3.height, 20)
|
|
end
|
|
|
|
-- Test 2: Horizontal Flex with AlignItems.CENTER
|
|
function TestAlignItems:testHorizontalFlexAlignItemsCenter()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be centered vertically
|
|
-- child1: (100 - 30) / 2 = 35
|
|
-- child2: (100 - 40) / 2 = 30
|
|
luaunit.assertEquals(child1.y, 35)
|
|
luaunit.assertEquals(child2.y, 30)
|
|
|
|
-- Heights should remain original
|
|
luaunit.assertEquals(child1.height, 30)
|
|
luaunit.assertEquals(child2.height, 40)
|
|
end
|
|
|
|
-- Test 3: Horizontal Flex with AlignItems.FLEX_END
|
|
function TestAlignItems:testHorizontalFlexAlignItemsFlexEnd()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be aligned to bottom (end of cross axis)
|
|
-- child1: 100 - 30 = 70
|
|
-- child2: 100 - 40 = 60
|
|
luaunit.assertEquals(child1.y, 70)
|
|
luaunit.assertEquals(child2.y, 60)
|
|
|
|
-- Heights should remain original
|
|
luaunit.assertEquals(child1.height, 30)
|
|
luaunit.assertEquals(child2.height, 40)
|
|
end
|
|
|
|
-- Test 4: Horizontal Flex with AlignItems.STRETCH
|
|
function TestAlignItems:testHorizontalFlexAlignItemsStretch()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be stretched to fill container height
|
|
luaunit.assertEquals(child1.y, 0)
|
|
luaunit.assertEquals(child2.y, 0)
|
|
luaunit.assertEquals(child1.height, 100)
|
|
luaunit.assertEquals(child2.height, 100)
|
|
end
|
|
|
|
-- Test 5: Vertical Flex with AlignItems.FLEX_START
|
|
function TestAlignItems:testVerticalFlexAlignItemsFlexStart()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 200,
|
|
h = 300,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child3 = Gui.new({
|
|
id = "child3",
|
|
w = 60,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
container:addChild(child3)
|
|
|
|
-- With FLEX_START, children should be aligned to left (start of cross axis)
|
|
luaunit.assertEquals(child1.x, 0)
|
|
luaunit.assertEquals(child2.x, 0)
|
|
luaunit.assertEquals(child3.x, 0)
|
|
|
|
-- Widths should remain original (no stretching)
|
|
luaunit.assertEquals(child1.width, 50)
|
|
luaunit.assertEquals(child2.width, 80)
|
|
luaunit.assertEquals(child3.width, 60)
|
|
end
|
|
|
|
-- Test 6: Vertical Flex with AlignItems.CENTER
|
|
function TestAlignItems:testVerticalFlexAlignItemsCenter()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 200,
|
|
h = 300,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be centered horizontally
|
|
-- child1: (200 - 50) / 2 = 75
|
|
-- child2: (200 - 80) / 2 = 60
|
|
luaunit.assertEquals(child1.x, 75)
|
|
luaunit.assertEquals(child2.x, 60)
|
|
|
|
-- Widths should remain original
|
|
luaunit.assertEquals(child1.width, 50)
|
|
luaunit.assertEquals(child2.width, 80)
|
|
end
|
|
|
|
-- Test 7: Vertical Flex with AlignItems.FLEX_END
|
|
function TestAlignItems:testVerticalFlexAlignItemsFlexEnd()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 200,
|
|
h = 300,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be aligned to right (end of cross axis)
|
|
-- child1: 200 - 50 = 150
|
|
-- child2: 200 - 80 = 120
|
|
luaunit.assertEquals(child1.x, 150)
|
|
luaunit.assertEquals(child2.x, 120)
|
|
|
|
-- Widths should remain original
|
|
luaunit.assertEquals(child1.width, 50)
|
|
luaunit.assertEquals(child2.width, 80)
|
|
end
|
|
|
|
-- Test 8: Vertical Flex with AlignItems.STRETCH
|
|
function TestAlignItems:testVerticalFlexAlignItemsStretch()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 200,
|
|
h = 300,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be stretched to fill container width
|
|
luaunit.assertEquals(child1.x, 0)
|
|
luaunit.assertEquals(child2.x, 0)
|
|
luaunit.assertEquals(child1.width, 200)
|
|
luaunit.assertEquals(child2.width, 200)
|
|
end
|
|
|
|
-- Test 9: Default AlignItems value (should be STRETCH)
|
|
function TestAlignItems:testDefaultAlignItems()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
-- No alignItems specified, should default to STRETCH
|
|
})
|
|
|
|
local child = Gui.new({
|
|
id = "child",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child)
|
|
|
|
-- Default should be STRETCH
|
|
luaunit.assertEquals(container.alignItems, AlignItems.STRETCH)
|
|
luaunit.assertEquals(child.height, 100) -- Should be stretched
|
|
end
|
|
|
|
-- Test 10: AlignItems with mixed child sizes
|
|
function TestAlignItems:testAlignItemsWithMixedChildSizes()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 40,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 50,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child3 = Gui.new({
|
|
id = "child3",
|
|
w = 60,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
container:addChild(child3)
|
|
|
|
-- All children should be centered vertically
|
|
-- child1: (120 - 20) / 2 = 50
|
|
-- child2: (120 - 80) / 2 = 20
|
|
-- child3: (120 - 30) / 2 = 45
|
|
luaunit.assertEquals(child1.y, 50)
|
|
luaunit.assertEquals(child2.y, 20)
|
|
luaunit.assertEquals(child3.y, 45)
|
|
end
|
|
|
|
-- Test 11: AlignItems with single child
|
|
function TestAlignItems:testAlignItemsWithSingleChild()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 200,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local child = Gui.new({
|
|
id = "child",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child)
|
|
|
|
-- Child should be aligned to bottom
|
|
luaunit.assertEquals(child.y, 70) -- 100 - 30
|
|
end
|
|
|
|
-- Test 12: AlignItems with container coordinates
|
|
function TestAlignItems:testAlignItemsWithContainerCoordinates()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 50,
|
|
y = 20,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local child = Gui.new({
|
|
id = "child",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child)
|
|
|
|
-- Child should be centered relative to container position
|
|
-- Y position: container.y + (container.height - child.height) / 2
|
|
-- Y position: 20 + (100 - 40) / 2 = 20 + 30 = 50
|
|
luaunit.assertEquals(child.y, 50)
|
|
end
|
|
|
|
-- Test 13: AlignItems BASELINE (should behave like FLEX_START for now)
|
|
function TestAlignItems:testAlignItemsBaseline()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.BASELINE,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- BASELINE should behave like FLEX_START for basic implementation
|
|
luaunit.assertEquals(child1.y, 0)
|
|
luaunit.assertEquals(child2.y, 0)
|
|
end
|
|
|
|
-- Test 14: AlignItems interaction with gap
|
|
function TestAlignItems:testAlignItemsWithGap()
|
|
local container = Gui.new({
|
|
id = "container",
|
|
x = 0,
|
|
y = 0,
|
|
w = 300,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 10,
|
|
})
|
|
|
|
local child1 = Gui.new({
|
|
id = "child1",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local child2 = Gui.new({
|
|
id = "child2",
|
|
w = 60,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
container:addChild(child1)
|
|
container:addChild(child2)
|
|
|
|
-- Children should be centered vertically despite gap
|
|
luaunit.assertEquals(child1.y, 35) -- (100 - 30) / 2
|
|
luaunit.assertEquals(child2.y, 30) -- (100 - 40) / 2
|
|
|
|
-- X positions should respect gap
|
|
luaunit.assertEquals(child1.x, 0)
|
|
luaunit.assertEquals(child2.x, 60) -- 50 + 10 gap
|
|
end
|
|
|
|
-- Test 15: AlignItems with different flex directions
|
|
function TestAlignItems:testAlignItemsCrossAxisConsistency()
|
|
-- Horizontal container with vertical alignment
|
|
local hContainer = Gui.new({
|
|
id = "hContainer",
|
|
x = 0,
|
|
y = 0,
|
|
w = 200,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local hChild = Gui.new({
|
|
id = "hChild",
|
|
w = 50,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
hContainer:addChild(hChild)
|
|
|
|
-- Vertical container with horizontal alignment
|
|
local vContainer = Gui.new({
|
|
id = "vContainer",
|
|
x = 0,
|
|
y = 0,
|
|
w = 100,
|
|
h = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local vChild = Gui.new({
|
|
id = "vChild",
|
|
w = 40,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
vContainer:addChild(vChild)
|
|
|
|
-- Both should be centered on their respective cross axes
|
|
luaunit.assertEquals(hChild.y, 30) -- (100 - 40) / 2 - vertical centering
|
|
luaunit.assertEquals(vChild.x, 30) -- (100 - 40) / 2 - horizontal centering
|
|
end
|
|
|
|
-- Test 16: Complex Card Layout with Mixed AlignItems
|
|
function TestAlignItems:testComplexCardLayoutMixedAlignItems()
|
|
-- Main card container
|
|
local card = Gui.new({
|
|
id = "card",
|
|
x = 10,
|
|
y = 10,
|
|
w = 300,
|
|
h = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Card header with icon and title (horizontal layout, center-aligned)
|
|
local header = Gui.new({
|
|
id = "header",
|
|
w = 300,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local icon = Gui.new({
|
|
id = "icon",
|
|
w = 24,
|
|
h = 24,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local title = Gui.new({
|
|
id = "title",
|
|
w = 200,
|
|
h = 24,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local actions = Gui.new({
|
|
id = "actions",
|
|
w = 60,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local btn1 = Gui.new({
|
|
id = "btn1",
|
|
w = 28,
|
|
h = 28,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local btn2 = Gui.new({
|
|
id = "btn2",
|
|
w = 28,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Card content with flex-end alignment
|
|
local content = Gui.new({
|
|
id = "content",
|
|
w = 300,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local contentText = Gui.new({
|
|
id = "contentText",
|
|
w = 250,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local metadata = Gui.new({
|
|
id = "metadata",
|
|
w = 180,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Card footer with space-between and center alignment
|
|
local footer = Gui.new({
|
|
id = "footer",
|
|
w = 300,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local timestamp = Gui.new({
|
|
id = "timestamp",
|
|
w = 80,
|
|
h = 16,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local status = Gui.new({
|
|
id = "status",
|
|
w = 60,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Build the tree
|
|
actions:addChild(btn1)
|
|
actions:addChild(btn2)
|
|
header:addChild(icon)
|
|
header:addChild(title)
|
|
header:addChild(actions)
|
|
|
|
content:addChild(contentText)
|
|
content:addChild(metadata)
|
|
|
|
footer:addChild(timestamp)
|
|
footer:addChild(status)
|
|
|
|
card:addChild(header)
|
|
card:addChild(content)
|
|
card:addChild(footer)
|
|
|
|
-- Verify alignments in header (CENTER)
|
|
luaunit.assertEquals(icon.y, 23) -- (50 - 24) / 2 = 13, plus card.y = 10 + 13 = 23
|
|
luaunit.assertEquals(title.y, 23) -- Same center alignment
|
|
|
|
-- Verify actions buttons have FLEX_START alignment
|
|
luaunit.assertEquals(btn1.y, 10) -- Start of actions container
|
|
luaunit.assertEquals(btn2.y, 10) -- Same start position
|
|
|
|
-- Verify content alignment (FLEX_END)
|
|
luaunit.assertEquals(contentText.x, 60) -- 300 - 250 = 50, plus card.x = 10 + 50 = 60
|
|
luaunit.assertEquals(metadata.x, 130) -- 300 - 180 = 120, plus card.x = 10 + 120 = 130
|
|
|
|
-- Verify footer center alignment
|
|
luaunit.assertEquals(timestamp.y, 175) -- Footer center: (30 - 16) / 2 = 7, plus footer.y = 168 + 7 = 175
|
|
luaunit.assertEquals(status.y, 173) -- Footer center: (30 - 20) / 2 = 5, plus footer.y = 168 + 5 = 173
|
|
end
|
|
|
|
-- Test 17: Complex Media Object Pattern with Nested Alignments
|
|
function TestAlignItems:testComplexMediaObjectNestedAlignments()
|
|
-- Main media container
|
|
local mediaContainer = Gui.new({
|
|
id = "mediaContainer",
|
|
x = 0,
|
|
y = 0,
|
|
w = 400,
|
|
h = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
-- Media (image/avatar) section
|
|
local mediaSection = Gui.new({
|
|
id = "mediaSection",
|
|
w = 80,
|
|
h = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local avatar = Gui.new({
|
|
id = "avatar",
|
|
w = 60,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local badge = Gui.new({
|
|
id = "badge",
|
|
w = 20,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Content section with multiple alignment variations
|
|
local contentSection = Gui.new({
|
|
id = "contentSection",
|
|
w = 280,
|
|
h = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Header with user info (flex-end alignment)
|
|
local userHeader = Gui.new({
|
|
id = "userHeader",
|
|
w = 280,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local username = Gui.new({
|
|
id = "username",
|
|
w = 120,
|
|
h = 24,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local timestamp = Gui.new({
|
|
id = "timestamp",
|
|
w = 80,
|
|
h = 16,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local menu = Gui.new({
|
|
id = "menu",
|
|
w = 30,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Main content with center alignment
|
|
local mainContent = Gui.new({
|
|
id = "mainContent",
|
|
w = 280,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local text = Gui.new({
|
|
id = "text",
|
|
w = 260,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local attachments = Gui.new({
|
|
id = "attachments",
|
|
w = 200,
|
|
h = 15,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local attach1 = Gui.new({
|
|
id = "attach1",
|
|
w = 12,
|
|
h = 12,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local attach2 = Gui.new({
|
|
id = "attach2",
|
|
w = 12,
|
|
h = 8,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Footer actions with space-between
|
|
local actionsFooter = Gui.new({
|
|
id = "actionsFooter",
|
|
w = 280,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local reactions = Gui.new({
|
|
id = "reactions",
|
|
w = 100,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local like = Gui.new({
|
|
id = "like",
|
|
w = 16,
|
|
h = 16,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local share = Gui.new({
|
|
id = "share",
|
|
w = 16,
|
|
h = 14,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local moreActions = Gui.new({
|
|
id = "moreActions",
|
|
w = 60,
|
|
h = 24,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Build the tree
|
|
mediaSection:addChild(avatar)
|
|
mediaSection:addChild(badge)
|
|
|
|
userHeader:addChild(username)
|
|
userHeader:addChild(timestamp)
|
|
userHeader:addChild(menu)
|
|
|
|
attachments:addChild(attach1)
|
|
attachments:addChild(attach2)
|
|
mainContent:addChild(text)
|
|
mainContent:addChild(attachments)
|
|
|
|
reactions:addChild(like)
|
|
reactions:addChild(share)
|
|
actionsFooter:addChild(reactions)
|
|
actionsFooter:addChild(moreActions)
|
|
|
|
contentSection:addChild(userHeader)
|
|
contentSection:addChild(mainContent)
|
|
contentSection:addChild(actionsFooter)
|
|
|
|
mediaContainer:addChild(mediaSection)
|
|
mediaContainer:addChild(contentSection)
|
|
|
|
-- Verify media section center alignment
|
|
luaunit.assertEquals(avatar.x, 10) -- (80 - 60) / 2 = 10
|
|
luaunit.assertEquals(badge.x, 30) -- (80 - 20) / 2 = 30
|
|
|
|
-- Verify user header flex-end alignment
|
|
luaunit.assertEquals(username.y, 16) -- (40 - 24) = 16 from bottom
|
|
luaunit.assertEquals(timestamp.y, 24) -- (40 - 16) = 24 from bottom
|
|
luaunit.assertEquals(menu.y, 10) -- (40 - 30) = 10 from bottom
|
|
|
|
-- Verify main content center alignment
|
|
luaunit.assertEquals(text.x, 90) -- 80 + (280 - 260) / 2 = 80 + 10 = 90
|
|
luaunit.assertEquals(attachments.x, 120) -- 80 + (280 - 200) / 2 = 80 + 40 = 120
|
|
|
|
-- Verify attachment items center alignment
|
|
luaunit.assertEquals(attach1.y, 41) -- attachments.y + (15 - 12) / 2 = 40 + 1.5 ≈ 41
|
|
luaunit.assertEquals(attach2.y, 43) -- attachments.y + (15 - 8) / 2 = 40 + 3.5 ≈ 43
|
|
|
|
-- Verify actions footer center alignment
|
|
luaunit.assertEquals(like.y, 125) -- actionsFooter.y + (30 - 16) / 2 = 120 + 7 = 127, but reactions also center
|
|
luaunit.assertEquals(moreActions.y, 123) -- actionsFooter.y + (30 - 24) / 2 = 120 + 3 = 123
|
|
end
|
|
|
|
-- Test 18: Complex Toolbar with Varied Alignments
|
|
function TestAlignItems:testComplexToolbarVariedAlignments()
|
|
-- Main toolbar container
|
|
local toolbar = Gui.new({
|
|
id = "toolbar",
|
|
x = 0,
|
|
y = 0,
|
|
w = 600,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
-- Left section with logo and nav (flex-start alignment)
|
|
local leftSection = Gui.new({
|
|
id = "leftSection",
|
|
w = 200,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local logo = Gui.new({
|
|
id = "logo",
|
|
w = 40,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local navigation = Gui.new({
|
|
id = "navigation",
|
|
w = 150,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local navItem1 = Gui.new({
|
|
id = "navItem1",
|
|
w = 60,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local navItem2 = Gui.new({
|
|
id = "navItem2",
|
|
w = 70,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Center section with search (stretch alignment)
|
|
local centerSection = Gui.new({
|
|
id = "centerSection",
|
|
w = 250,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local searchContainer = Gui.new({
|
|
id = "searchContainer",
|
|
w = 250,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local searchInput = Gui.new({
|
|
id = "searchInput",
|
|
w = 200,
|
|
h = 32,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local searchButton = Gui.new({
|
|
id = "searchButton",
|
|
w = 36,
|
|
h = 36,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local searchHint = Gui.new({
|
|
id = "searchHint",
|
|
w = 250,
|
|
h = 16,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Right section with user controls (flex-end alignment)
|
|
local rightSection = Gui.new({
|
|
id = "rightSection",
|
|
w = 150,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local notifications = Gui.new({
|
|
id = "notifications",
|
|
w = 30,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local notifIcon = Gui.new({
|
|
id = "notifIcon",
|
|
w = 20,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local notifBadge = Gui.new({
|
|
id = "notifBadge",
|
|
w = 12,
|
|
h = 12,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local userMenu = Gui.new({
|
|
id = "userMenu",
|
|
w = 80,
|
|
h = 45,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local userAvatar = Gui.new({
|
|
id = "userAvatar",
|
|
w = 32,
|
|
h = 32,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local dropdown = Gui.new({
|
|
id = "dropdown",
|
|
w = 40,
|
|
h = 25,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Build the tree
|
|
navigation:addChild(navItem1)
|
|
navigation:addChild(navItem2)
|
|
leftSection:addChild(logo)
|
|
leftSection:addChild(navigation)
|
|
|
|
searchContainer:addChild(searchInput)
|
|
searchContainer:addChild(searchButton)
|
|
centerSection:addChild(searchContainer)
|
|
centerSection:addChild(searchHint)
|
|
|
|
notifications:addChild(notifIcon)
|
|
notifications:addChild(notifBadge)
|
|
userMenu:addChild(userAvatar)
|
|
userMenu:addChild(dropdown)
|
|
rightSection:addChild(notifications)
|
|
rightSection:addChild(userMenu)
|
|
|
|
toolbar:addChild(leftSection)
|
|
toolbar:addChild(centerSection)
|
|
toolbar:addChild(rightSection)
|
|
|
|
-- Verify left section flex-start alignment
|
|
luaunit.assertEquals(logo.y, 0) -- Aligned to top
|
|
luaunit.assertEquals(navItem1.y, 5) -- navigation.y + (50 - 30) / 2 = 5 + 10 = 15, but nav is at y=10
|
|
luaunit.assertEquals(navItem2.y, 2) -- navigation.y + (50 - 35) / 2 = 5 + 7.5 ≈ 12
|
|
|
|
-- Verify center section stretch alignment
|
|
luaunit.assertEquals(searchInput.y, 4) -- searchContainer.y + (40 - 32) / 2 = 10 + 4 = 14
|
|
luaunit.assertEquals(searchButton.y, 2) -- searchContainer.y + (40 - 36) / 2 = 10 + 2 = 12
|
|
luaunit.assertEquals(searchHint.width, 250) -- Should be stretched to full width
|
|
|
|
-- Verify right section flex-end alignment
|
|
luaunit.assertEquals(notifications.y, 25) -- (60 - 35) = 25 from bottom
|
|
luaunit.assertEquals(userMenu.y, 15) -- (60 - 45) = 15 from bottom
|
|
|
|
-- Verify notification items center alignment
|
|
luaunit.assertEquals(notifIcon.x, 5) -- (30 - 20) / 2 = 5
|
|
luaunit.assertEquals(notifBadge.x, 9) -- (30 - 12) / 2 = 9
|
|
|
|
-- Verify user menu center alignment
|
|
luaunit.assertEquals(userAvatar.y, 21) -- userMenu.y + (45 - 32) / 2 = 15 + 6.5 ≈ 21
|
|
luaunit.assertEquals(dropdown.y, 25) -- userMenu.y + (45 - 25) / 2 = 15 + 10 = 25
|
|
end
|
|
|
|
-- Test 19: Complex Dashboard Widget Layout
|
|
function TestAlignItems:testComplexDashboardWidgetLayout()
|
|
-- Main dashboard container
|
|
local dashboard = Gui.new({
|
|
id = "dashboard",
|
|
x = 0,
|
|
y = 0,
|
|
w = 800,
|
|
h = 600,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Header with title and controls
|
|
local header = Gui.new({
|
|
id = "header",
|
|
w = 800,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local titleSection = Gui.new({
|
|
id = "titleSection",
|
|
w = 300,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local title = Gui.new({
|
|
id = "title",
|
|
w = 250,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local subtitle = Gui.new({
|
|
id = "subtitle",
|
|
w = 200,
|
|
h = 24,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local controlsSection = Gui.new({
|
|
id = "controlsSection",
|
|
w = 200,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local filterBtn = Gui.new({
|
|
id = "filterBtn",
|
|
w = 60,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local exportBtn = Gui.new({
|
|
id = "exportBtn",
|
|
w = 70,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local settingsBtn = Gui.new({
|
|
id = "settingsBtn",
|
|
w = 40,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Main content area with widgets
|
|
local mainContent = Gui.new({
|
|
id = "mainContent",
|
|
w = 800,
|
|
h = 480,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Left panel with statistics (center alignment)
|
|
local leftPanel = Gui.new({
|
|
id = "leftPanel",
|
|
w = 250,
|
|
h = 480,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local statCard1 = Gui.new({
|
|
id = "statCard1",
|
|
w = 220,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local stat1Value = Gui.new({
|
|
id = "stat1Value",
|
|
w = 100,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local stat1Label = Gui.new({
|
|
id = "stat1Label",
|
|
w = 150,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local stat1Chart = Gui.new({
|
|
id = "stat1Chart",
|
|
w = 180,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local statCard2 = Gui.new({
|
|
id = "statCard2",
|
|
w = 220,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local stat2Value = Gui.new({
|
|
id = "stat2Value",
|
|
w = 120,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local stat2Trend = Gui.new({
|
|
id = "stat2Trend",
|
|
w = 80,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Center panel with main chart (stretch alignment)
|
|
local centerPanel = Gui.new({
|
|
id = "centerPanel",
|
|
w = 400,
|
|
h = 480,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local chartHeader = Gui.new({
|
|
id = "chartHeader",
|
|
w = 400,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local chartTitle = Gui.new({
|
|
id = "chartTitle",
|
|
w = 200,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local chartControls = Gui.new({
|
|
id = "chartControls",
|
|
w = 120,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local timeRange = Gui.new({
|
|
id = "timeRange",
|
|
w = 80,
|
|
h = 25,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local refreshBtn = Gui.new({
|
|
id = "refreshBtn",
|
|
w = 30,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local mainChart = Gui.new({
|
|
id = "mainChart",
|
|
w = 400,
|
|
h = 380,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Right panel with lists (flex-start alignment)
|
|
local rightPanel = Gui.new({
|
|
id = "rightPanel",
|
|
w = 150,
|
|
h = 480,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local alertsList = Gui.new({
|
|
id = "alertsList",
|
|
w = 140,
|
|
h = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local alert1 = Gui.new({
|
|
id = "alert1",
|
|
w = 140,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local alert2 = Gui.new({
|
|
id = "alert2",
|
|
w = 140,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local tasksList = Gui.new({
|
|
id = "tasksList",
|
|
w = 130,
|
|
h = 240,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local task1 = Gui.new({
|
|
id = "task1",
|
|
w = 120,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local task2 = Gui.new({
|
|
id = "task2",
|
|
w = 110,
|
|
h = 25,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Footer with status info
|
|
local footer = Gui.new({
|
|
id = "footer",
|
|
w = 800,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local status = Gui.new({
|
|
id = "status",
|
|
w = 200,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local timestamp = Gui.new({
|
|
id = "timestamp",
|
|
w = 150,
|
|
h = 16,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Build the tree
|
|
titleSection:addChild(title)
|
|
titleSection:addChild(subtitle)
|
|
controlsSection:addChild(filterBtn)
|
|
controlsSection:addChild(exportBtn)
|
|
controlsSection:addChild(settingsBtn)
|
|
header:addChild(titleSection)
|
|
header:addChild(controlsSection)
|
|
|
|
statCard1:addChild(stat1Value)
|
|
statCard1:addChild(stat1Label)
|
|
statCard1:addChild(stat1Chart)
|
|
statCard2:addChild(stat2Value)
|
|
statCard2:addChild(stat2Trend)
|
|
leftPanel:addChild(statCard1)
|
|
leftPanel:addChild(statCard2)
|
|
|
|
chartControls:addChild(timeRange)
|
|
chartControls:addChild(refreshBtn)
|
|
chartHeader:addChild(chartTitle)
|
|
chartHeader:addChild(chartControls)
|
|
centerPanel:addChild(chartHeader)
|
|
centerPanel:addChild(mainChart)
|
|
|
|
alertsList:addChild(alert1)
|
|
alertsList:addChild(alert2)
|
|
tasksList:addChild(task1)
|
|
tasksList:addChild(task2)
|
|
rightPanel:addChild(alertsList)
|
|
rightPanel:addChild(tasksList)
|
|
|
|
mainContent:addChild(leftPanel)
|
|
mainContent:addChild(centerPanel)
|
|
mainContent:addChild(rightPanel)
|
|
|
|
footer:addChild(status)
|
|
footer:addChild(timestamp)
|
|
|
|
dashboard:addChild(header)
|
|
dashboard:addChild(mainContent)
|
|
dashboard:addChild(footer)
|
|
|
|
-- Verify title section flex-start alignment
|
|
luaunit.assertEquals(title.x, 0) -- Aligned to left
|
|
luaunit.assertEquals(subtitle.x, 0) -- Also aligned to left
|
|
|
|
-- Verify controls section flex-end alignment
|
|
luaunit.assertEquals(filterBtn.y, 45) -- (80 - 35) = 45 from bottom
|
|
luaunit.assertEquals(exportBtn.y, 45) -- Same flex-end alignment
|
|
luaunit.assertEquals(settingsBtn.y, 40) -- (80 - 40) = 40 from bottom
|
|
|
|
-- Verify left panel center alignment
|
|
luaunit.assertEquals(statCard1.x, 15) -- (250 - 220) / 2 = 15
|
|
luaunit.assertEquals(statCard2.x, 15) -- Same center alignment
|
|
|
|
-- Verify stat card alignments
|
|
luaunit.assertEquals(stat1Value.x, 60) -- statCard1.x + (220 - 100) / 2 = 15 + 60 = 75
|
|
luaunit.assertEquals(stat1Label.x, 35) -- statCard1.x + (220 - 150) / 2 = 15 + 35 = 50
|
|
luaunit.assertEquals(stat2Value.x, 115) -- statCard2.x + (220 - 120) = 15 + 100 = 115
|
|
luaunit.assertEquals(stat2Trend.x, 155) -- statCard2.x + (220 - 80) = 15 + 140 = 155
|
|
|
|
-- Verify center panel stretch alignment
|
|
luaunit.assertEquals(chartHeader.width, 400) -- Should be stretched
|
|
luaunit.assertEquals(mainChart.width, 400) -- Should be stretched
|
|
|
|
-- Verify right panel flex-start alignment
|
|
luaunit.assertEquals(alertsList.x, 650) -- rightPanel starts at 650
|
|
luaunit.assertEquals(tasksList.x, 650) -- Also aligned to start
|
|
|
|
-- Verify tasks list flex-end alignment
|
|
luaunit.assertEquals(task1.x, 660) -- tasksList.x + (130 - 120) = 650 + 10 = 660
|
|
luaunit.assertEquals(task2.x, 670) -- tasksList.x + (130 - 110) = 650 + 20 = 670
|
|
|
|
-- Verify footer center alignment
|
|
luaunit.assertEquals(status.y, 10) -- (40 - 20) / 2 = 10
|
|
luaunit.assertEquals(timestamp.y, 12) -- (40 - 16) / 2 = 12
|
|
end
|
|
|
|
-- Test 20: Complex Form Layout with Multi-Level Alignments
|
|
function TestAlignItems:testComplexFormMultiLevelAlignments()
|
|
-- Main form container
|
|
local form = Gui.new({
|
|
id = "form",
|
|
x = 50,
|
|
y = 50,
|
|
w = 500,
|
|
h = 600,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Form header with center alignment
|
|
local formHeader = Gui.new({
|
|
id = "formHeader",
|
|
w = 500,
|
|
h = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local formTitle = Gui.new({
|
|
id = "formTitle",
|
|
w = 300,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local formDescription = Gui.new({
|
|
id = "formDescription",
|
|
w = 400,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Personal info section with flex-start alignment
|
|
local personalSection = Gui.new({
|
|
id = "personalSection",
|
|
w = 500,
|
|
h = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local sectionTitle1 = Gui.new({
|
|
id = "sectionTitle1",
|
|
w = 200,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local nameRow = Gui.new({
|
|
id = "nameRow",
|
|
w = 480,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local firstNameField = Gui.new({
|
|
id = "firstNameField",
|
|
w = 220,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local firstNameLabel = Gui.new({
|
|
id = "firstNameLabel",
|
|
w = 100,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local firstNameInput = Gui.new({
|
|
id = "firstNameInput",
|
|
w = 200,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local lastNameField = Gui.new({
|
|
id = "lastNameField",
|
|
w = 220,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local lastNameLabel = Gui.new({
|
|
id = "lastNameLabel",
|
|
w = 120,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local lastNameInput = Gui.new({
|
|
id = "lastNameInput",
|
|
w = 200,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local emailRow = Gui.new({
|
|
id = "emailRow",
|
|
w = 480,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local emailLabel = Gui.new({
|
|
id = "emailLabel",
|
|
w = 100,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local emailInput = Gui.new({
|
|
id = "emailInput",
|
|
w = 480,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Preferences section with center alignment
|
|
local preferencesSection = Gui.new({
|
|
id = "preferencesSection",
|
|
w = 500,
|
|
h = 180,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local sectionTitle2 = Gui.new({
|
|
id = "sectionTitle2",
|
|
w = 250,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local optionsContainer = Gui.new({
|
|
id = "optionsContainer",
|
|
w = 400,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local leftOptions = Gui.new({
|
|
id = "leftOptions",
|
|
w = 180,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
local option1 = Gui.new({
|
|
id = "option1",
|
|
w = 150,
|
|
h = 25,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local checkbox1 = Gui.new({
|
|
id = "checkbox1",
|
|
w = 20,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local label1 = Gui.new({
|
|
id = "label1",
|
|
w = 120,
|
|
h = 18,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local option2 = Gui.new({
|
|
id = "option2",
|
|
w = 160,
|
|
h = 25,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local checkbox2 = Gui.new({
|
|
id = "checkbox2",
|
|
w = 20,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local label2 = Gui.new({
|
|
id = "label2",
|
|
w = 130,
|
|
h = 18,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local rightOptions = Gui.new({
|
|
id = "rightOptions",
|
|
w = 180,
|
|
h = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local dropdown = Gui.new({
|
|
id = "dropdown",
|
|
w = 150,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local slider = Gui.new({
|
|
id = "slider",
|
|
w = 140,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Form actions with space-between alignment
|
|
local actionsSection = Gui.new({
|
|
id = "actionsSection",
|
|
w = 500,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local cancelBtn = Gui.new({
|
|
id = "cancelBtn",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local submitGroup = Gui.new({
|
|
id = "submitGroup",
|
|
w = 200,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local saveBtn = Gui.new({
|
|
id = "saveBtn",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local submitBtn = Gui.new({
|
|
id = "submitBtn",
|
|
w = 100,
|
|
h = 45,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Build the tree
|
|
formHeader:addChild(formTitle)
|
|
formHeader:addChild(formDescription)
|
|
|
|
firstNameField:addChild(firstNameLabel)
|
|
firstNameField:addChild(firstNameInput)
|
|
lastNameField:addChild(lastNameLabel)
|
|
lastNameField:addChild(lastNameInput)
|
|
nameRow:addChild(firstNameField)
|
|
nameRow:addChild(lastNameField)
|
|
|
|
emailRow:addChild(emailLabel)
|
|
emailRow:addChild(emailInput)
|
|
|
|
personalSection:addChild(sectionTitle1)
|
|
personalSection:addChild(nameRow)
|
|
personalSection:addChild(emailRow)
|
|
|
|
option1:addChild(checkbox1)
|
|
option1:addChild(label1)
|
|
option2:addChild(checkbox2)
|
|
option2:addChild(label2)
|
|
leftOptions:addChild(option1)
|
|
leftOptions:addChild(option2)
|
|
|
|
rightOptions:addChild(dropdown)
|
|
rightOptions:addChild(slider)
|
|
|
|
optionsContainer:addChild(leftOptions)
|
|
optionsContainer:addChild(rightOptions)
|
|
preferencesSection:addChild(sectionTitle2)
|
|
preferencesSection:addChild(optionsContainer)
|
|
|
|
submitGroup:addChild(saveBtn)
|
|
submitGroup:addChild(submitBtn)
|
|
actionsSection:addChild(cancelBtn)
|
|
actionsSection:addChild(submitGroup)
|
|
|
|
form:addChild(formHeader)
|
|
form:addChild(personalSection)
|
|
form:addChild(preferencesSection)
|
|
form:addChild(actionsSection)
|
|
|
|
-- Verify form header center alignment
|
|
luaunit.assertEquals(formTitle.x, 150) -- 50 + (500 - 300) / 2 = 50 + 100 = 150
|
|
luaunit.assertEquals(formDescription.x, 100) -- 50 + (500 - 400) / 2 = 50 + 50 = 100
|
|
|
|
-- Verify personal section flex-start alignment
|
|
luaunit.assertEquals(sectionTitle1.x, 50) -- Aligned to start
|
|
luaunit.assertEquals(nameRow.x, 60) -- Form.x + 10 margin = 50 + 10 = 60
|
|
|
|
-- Verify name field alignments
|
|
luaunit.assertEquals(firstNameLabel.x, 60) -- firstNameField starts at nameRow.x
|
|
luaunit.assertEquals(lastNameLabel.x, 180) -- lastNameField.x + (220 - 120) = 60 + 220 + 100 = 380, but flex-end within field
|
|
luaunit.assertEquals(lastNameInput.x, 100) -- lastNameField.x + (220 - 200) = 280 + 20 = 300
|
|
|
|
-- Verify preferences section center alignment
|
|
luaunit.assertEquals(sectionTitle2.x, 175) -- 50 + (500 - 250) / 2 = 50 + 125 = 175
|
|
luaunit.assertEquals(optionsContainer.x, 100) -- 50 + (500 - 400) / 2 = 50 + 50 = 100
|
|
|
|
-- Verify option alignments
|
|
luaunit.assertEquals(checkbox1.y, 332) -- option1.y + (25 - 20) / 2, where option1.y ≈ 330
|
|
luaunit.assertEquals(label1.y, 333) -- option1.y + (25 - 18) / 2 ≈ 333
|
|
|
|
-- Verify right options flex-end alignment
|
|
luaunit.assertEquals(dropdown.x, 310) -- rightOptions.x + (180 - 150) = 280 + 30 = 310
|
|
luaunit.assertEquals(slider.x, 320) -- rightOptions.x + (180 - 140) = 280 + 40 = 320
|
|
|
|
-- Verify actions section alignments
|
|
luaunit.assertEquals(cancelBtn.y, 10) -- (60 - 40) / 2 = 10
|
|
luaunit.assertEquals(saveBtn.y, 12) -- submitGroup.y + (50 - 40) / 2 = 5 + 5 = 10, but relative positioning
|
|
luaunit.assertEquals(submitBtn.y, 10) -- submitGroup.y + (50 - 45) / 2 = 5 + 2.5 ≈ 7
|
|
end
|
|
|
|
-- Test 21: Complex Modal Dialog with Nested Alignments
|
|
function TestAlignItems:testComplexModalDialogNestedAlignments()
|
|
-- Modal backdrop
|
|
local backdrop = Gui.new({
|
|
id = "backdrop",
|
|
x = 0,
|
|
y = 0,
|
|
w = 1024,
|
|
h = 768,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.CENTER,
|
|
})
|
|
|
|
-- Modal dialog
|
|
local modal = Gui.new({
|
|
id = "modal",
|
|
w = 600,
|
|
h = 500,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Modal header with space-between alignment
|
|
local modalHeader = Gui.new({
|
|
id = "modalHeader",
|
|
w = 600,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
})
|
|
|
|
local headerLeft = Gui.new({
|
|
id = "headerLeft",
|
|
w = 300,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local modalIcon = Gui.new({
|
|
id = "modalIcon",
|
|
w = 32,
|
|
h = 32,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local modalTitle = Gui.new({
|
|
id = "modalTitle",
|
|
w = 250,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local headerRight = Gui.new({
|
|
id = "headerRight",
|
|
w = 100,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
})
|
|
|
|
local helpBtn = Gui.new({
|
|
id = "helpBtn",
|
|
w = 30,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local closeBtn = Gui.new({
|
|
id = "closeBtn",
|
|
w = 32,
|
|
h = 32,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Modal content with mixed alignments
|
|
local modalContent = Gui.new({
|
|
id = "modalContent",
|
|
w = 600,
|
|
h = 380,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
-- Left sidebar with navigation
|
|
local sidebar = Gui.new({
|
|
id = "sidebar",
|
|
w = 150,
|
|
h = 380,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
local navItem1 = Gui.new({
|
|
id = "navItem1",
|
|
w = 150,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local navIcon1 = Gui.new({
|
|
id = "navIcon1",
|
|
w = 20,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local navLabel1 = Gui.new({
|
|
id = "navLabel1",
|
|
w = 100,
|
|
h = 18,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local navItem2 = Gui.new({
|
|
id = "navItem2",
|
|
w = 150,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local navIcon2 = Gui.new({
|
|
id = "navIcon2",
|
|
w = 20,
|
|
h = 20,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local navLabel2 = Gui.new({
|
|
id = "navLabel2",
|
|
w = 110,
|
|
h = 18,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Main content area
|
|
local contentArea = Gui.new({
|
|
id = "contentArea",
|
|
w = 450,
|
|
h = 380,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.FLEX_START,
|
|
})
|
|
|
|
-- Content header with flex-end alignment
|
|
local contentHeader = Gui.new({
|
|
id = "contentHeader",
|
|
w = 450,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.FLEX_END,
|
|
})
|
|
|
|
local contentTitle = Gui.new({
|
|
id = "contentTitle",
|
|
w = 200,
|
|
h = 35,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local contentActions = Gui.new({
|
|
id = "contentActions",
|
|
w = 180,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local editBtn = Gui.new({
|
|
id = "editBtn",
|
|
w = 50,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local deleteBtn = Gui.new({
|
|
id = "deleteBtn",
|
|
w = 55,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local moreBtn = Gui.new({
|
|
id = "moreBtn",
|
|
w = 30,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Content body with center alignment
|
|
local contentBody = Gui.new({
|
|
id = "contentBody",
|
|
w = 450,
|
|
h = 280,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
alignItems = AlignItems.CENTER,
|
|
})
|
|
|
|
local contentText = Gui.new({
|
|
id = "contentText",
|
|
w = 400,
|
|
h = 150,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local contentImage = Gui.new({
|
|
id = "contentImage",
|
|
w = 200,
|
|
h = 100,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Content meta with flex-end alignment
|
|
local contentMeta = Gui.new({
|
|
id = "contentMeta",
|
|
w = 350,
|
|
h = 30,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
})
|
|
|
|
local lastModified = Gui.new({
|
|
id = "lastModified",
|
|
w = 120,
|
|
h = 16,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local author = Gui.new({
|
|
id = "author",
|
|
w = 100,
|
|
h = 18,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Modal footer with center alignment
|
|
local modalFooter = Gui.new({
|
|
id = "modalFooter",
|
|
w = 600,
|
|
h = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.CENTER,
|
|
})
|
|
|
|
local footerActions = Gui.new({
|
|
id = "footerActions",
|
|
w = 300,
|
|
h = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
alignItems = AlignItems.CENTER,
|
|
justifyContent = JustifyContent.SPACE_AROUND,
|
|
})
|
|
|
|
local cancelModalBtn = Gui.new({
|
|
id = "cancelModalBtn",
|
|
w = 80,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local applyBtn = Gui.new({
|
|
id = "applyBtn",
|
|
w = 70,
|
|
h = 40,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
local okBtn = Gui.new({
|
|
id = "okBtn",
|
|
w = 60,
|
|
h = 45,
|
|
positioning = Positioning.FLEX,
|
|
})
|
|
|
|
-- Build the tree
|
|
headerLeft:addChild(modalIcon)
|
|
headerLeft:addChild(modalTitle)
|
|
headerRight:addChild(helpBtn)
|
|
headerRight:addChild(closeBtn)
|
|
modalHeader:addChild(headerLeft)
|
|
modalHeader:addChild(headerRight)
|
|
|
|
navItem1:addChild(navIcon1)
|
|
navItem1:addChild(navLabel1)
|
|
navItem2:addChild(navIcon2)
|
|
navItem2:addChild(navLabel2)
|
|
sidebar:addChild(navItem1)
|
|
sidebar:addChild(navItem2)
|
|
|
|
contentActions:addChild(editBtn)
|
|
contentActions:addChild(deleteBtn)
|
|
contentActions:addChild(moreBtn)
|
|
contentHeader:addChild(contentTitle)
|
|
contentHeader:addChild(contentActions)
|
|
|
|
contentBody:addChild(contentText)
|
|
contentBody:addChild(contentImage)
|
|
|
|
contentMeta:addChild(lastModified)
|
|
contentMeta:addChild(author)
|
|
|
|
contentArea:addChild(contentHeader)
|
|
contentArea:addChild(contentBody)
|
|
contentArea:addChild(contentMeta)
|
|
|
|
modalContent:addChild(sidebar)
|
|
modalContent:addChild(contentArea)
|
|
|
|
footerActions:addChild(cancelModalBtn)
|
|
footerActions:addChild(applyBtn)
|
|
footerActions:addChild(okBtn)
|
|
modalFooter:addChild(footerActions)
|
|
|
|
modal:addChild(modalHeader)
|
|
modal:addChild(modalContent)
|
|
modal:addChild(modalFooter)
|
|
|
|
backdrop:addChild(modal)
|
|
|
|
-- Verify modal is centered in backdrop
|
|
luaunit.assertEquals(modal.x, 212) -- (1024 - 600) / 2 = 212
|
|
luaunit.assertEquals(modal.y, 134) -- (768 - 500) / 2 = 134
|
|
|
|
-- Verify header alignment
|
|
luaunit.assertEquals(modalIcon.y, 148) -- modal.y + (60 - 32) / 2 = 134 + 14 = 148
|
|
luaunit.assertEquals(modalTitle.y, 149) -- modal.y + (60 - 30) / 2 = 134 + 15 = 149
|
|
luaunit.assertEquals(helpBtn.y, 149) -- header center alignment
|
|
luaunit.assertEquals(closeBtn.y, 148) -- header center alignment
|
|
|
|
-- Verify nav item alignments
|
|
luaunit.assertEquals(navIcon1.y, 204) -- navItem1.y + (40 - 20) / 2 = 194 + 10 = 204
|
|
luaunit.assertEquals(navLabel1.y, 205) -- navItem1.y + (40 - 18) / 2 = 194 + 11 = 205
|
|
|
|
-- Verify content header flex-end alignment
|
|
luaunit.assertEquals(contentTitle.y, 209) -- contentHeader.y + (50 - 35) = 194 + 15 = 209
|
|
luaunit.assertEquals(editBtn.y, 214) -- contentActions center: contentHeader.y + (50 - 40)/2 + (40-30)/2
|
|
|
|
-- Verify content body center alignment
|
|
luaunit.assertEquals(contentText.x, 237) -- contentArea.x + (450 - 400) / 2 = 212 + 25 = 237
|
|
luaunit.assertEquals(contentImage.x, 337) -- contentArea.x + (450 - 200) / 2 = 212 + 125 = 337
|
|
|
|
-- Verify content meta flex-end alignment
|
|
luaunit.assertEquals(lastModified.x, 542) -- contentArea.x + contentMeta.x + (350 - 120 - 100) = 362 + 130 = 492
|
|
luaunit.assertEquals(author.x, 662) -- After lastModified position
|
|
|
|
-- Verify footer center alignment
|
|
luaunit.assertEquals(footerActions.x, 362) -- modal.x + (600 - 300) / 2 = 212 + 150 = 362
|
|
luaunit.assertEquals(cancelModalBtn.y, 639) -- modalFooter.y + (60 - 50)/2 + (50-40)/2 = 634 + 5 + 5 = 644
|
|
luaunit.assertEquals(okBtn.y, 636) -- footerActions center: (50 - 45) / 2 = 2.5, plus modalFooter offset
|
|
end
|
|
|
|
luaunit.LuaUnit.run()
|
|
|