diff --git a/FlexLove.lua b/FlexLove.lua index bbcd419..74ff19d 100644 --- a/FlexLove.lua +++ b/FlexLove.lua @@ -1459,18 +1459,23 @@ function Element.new(props) end -- Handle fontFamily (can be font name from theme or direct path to font file) - self.fontFamily = props.fontFamily - - -- If using themeComponent but no fontFamily specified, apply default font - if props.themeComponent and not props.fontFamily then + -- Priority: explicit props.fontFamily > parent fontFamily > theme default + if props.fontFamily then + -- Explicitly set fontFamily takes highest priority + self.fontFamily = props.fontFamily + elseif self.parent and self.parent.fontFamily then + -- Inherit from parent if parent has fontFamily set + self.fontFamily = self.parent.fontFamily + elseif props.themeComponent then + -- If using themeComponent, try to get default from theme local themeToUse = self.theme and themes[self.theme] or Theme.getActive() - if themeToUse and themeToUse.fonts then - if self.parent then - self.fontFamily = self.parent.fontFamily - else - self.fontFamily = "default" - end + if themeToUse and themeToUse.fonts and themeToUse.fonts["default"] then + self.fontFamily = "default" + else + self.fontFamily = nil end + else + self.fontFamily = nil end -- Handle textSize BEFORE width/height calculation (needed for auto-sizing) @@ -3086,7 +3091,23 @@ function Element:calculateTextWidth() end if self.textSize then - local tempFont = FONT_CACHE.get(self.textSize) + -- Resolve font path from font family (same logic as in draw) + local fontPath = nil + if self.fontFamily then + local themeToUse = self.theme and themes[self.theme] or Theme.getActive() + if themeToUse and themeToUse.fonts and themeToUse.fonts[self.fontFamily] then + fontPath = themeToUse.fonts[self.fontFamily] + else + fontPath = self.fontFamily + end + elseif self.themeComponent then + local themeToUse = self.theme and themes[self.theme] or Theme.getActive() + if themeToUse and themeToUse.fonts and themeToUse.fonts.default then + fontPath = themeToUse.fonts.default + end + end + + local tempFont = FONT_CACHE.get(self.textSize, fontPath) local width = tempFont:getWidth(self.text) return width end @@ -3103,7 +3124,23 @@ function Element:calculateTextHeight() end if self.textSize then - local tempFont = FONT_CACHE.get(self.textSize) + -- Resolve font path from font family (same logic as in draw) + local fontPath = nil + if self.fontFamily then + local themeToUse = self.theme and themes[self.theme] or Theme.getActive() + if themeToUse and themeToUse.fonts and themeToUse.fonts[self.fontFamily] then + fontPath = themeToUse.fonts[self.fontFamily] + else + fontPath = self.fontFamily + end + elseif self.themeComponent then + local themeToUse = self.theme and themes[self.theme] or Theme.getActive() + if themeToUse and themeToUse.fonts and themeToUse.fonts.default then + fontPath = themeToUse.fonts.default + end + end + + local tempFont = FONT_CACHE.get(self.textSize, fontPath) local height = tempFont:getHeight() return height end diff --git a/testing/__tests__/18_font_family_inheritance_tests.lua b/testing/__tests__/18_font_family_inheritance_tests.lua new file mode 100644 index 0000000..48f40ed --- /dev/null +++ b/testing/__tests__/18_font_family_inheritance_tests.lua @@ -0,0 +1,222 @@ +local lu = require("testing.luaunit") +require("testing.loveStub") +local FlexLove = require("FlexLove") + +TestFontFamilyInheritance = {} + +function TestFontFamilyInheritance:setUp() + FlexLove.Gui.destroy() + FlexLove.Gui.init({ baseScale = { width = 1920, height = 1080 } }) +end + +function TestFontFamilyInheritance:tearDown() + FlexLove.Gui.destroy() +end + +function TestFontFamilyInheritance:testBasicInheritanceFromParent() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + fontFamily = "Arial", + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child", + }) + + lu.assertEquals(child.fontFamily, "Arial", "Child should inherit fontFamily from parent") +end + +function TestFontFamilyInheritance:testInheritanceThroughMultipleLevels() + local grandparent = FlexLove.Element.new({ + width = 300, + height = 300, + fontFamily = "Times", + }) + + local parent = FlexLove.Element.new({ + parent = grandparent, + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Grandchild", + }) + + lu.assertEquals(parent.fontFamily, "Times", "Parent should inherit fontFamily from grandparent") + lu.assertEquals(child.fontFamily, "Times", "Child should inherit fontFamily through parent") +end + +function TestFontFamilyInheritance:testExplicitOverrideBreaksInheritance() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + fontFamily = "Arial", + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child", + fontFamily = "Helvetica", + }) + + lu.assertEquals(child.fontFamily, "Helvetica", "Child's explicit fontFamily should override parent's") +end + +function TestFontFamilyInheritance:testInheritanceWithNoParentFontFamily() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child", + }) + + lu.assertNil(child.fontFamily, "Child should have nil fontFamily when parent doesn't have one") +end + +function TestFontFamilyInheritance:testInheritanceInFlexContainer() + local flexParent = FlexLove.Element.new({ + width = 300, + height = 300, + positioning = FlexLove.Positioning.FLEX, + flexDirection = FlexLove.FlexDirection.HORIZONTAL, + fontFamily = "Courier", + }) + + local child1 = FlexLove.Element.new({ + parent = flexParent, + width = 100, + height = 100, + text = "Child 1", + }) + + local child2 = FlexLove.Element.new({ + parent = flexParent, + width = 100, + height = 100, + text = "Child 2", + }) + + lu.assertEquals(child1.fontFamily, "Courier", "Child 1 should inherit fontFamily in flex container") + lu.assertEquals(child2.fontFamily, "Courier", "Child 2 should inherit fontFamily in flex container") +end + +function TestFontFamilyInheritance:testInheritanceInGridContainer() + local gridParent = FlexLove.Element.new({ + width = 300, + height = 300, + positioning = FlexLove.Positioning.GRID, + gridRows = 2, + gridColumns = 2, + fontFamily = "Verdana", + }) + + local child1 = FlexLove.Element.new({ + parent = gridParent, + text = "Cell 1", + }) + + local child2 = FlexLove.Element.new({ + parent = gridParent, + text = "Cell 2", + }) + + lu.assertEquals(child1.fontFamily, "Verdana", "Child 1 should inherit fontFamily in grid container") + lu.assertEquals(child2.fontFamily, "Verdana", "Child 2 should inherit fontFamily in grid container") +end + +function TestFontFamilyInheritance:testMixedInheritanceAndOverride() + local grandparent = FlexLove.Element.new({ + width = 400, + height = 400, + fontFamily = "Georgia", + }) + + local parent = FlexLove.Element.new({ + parent = grandparent, + width = 300, + height = 300, + }) + + local child1 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child 1", + }) + + local child2 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child 2", + fontFamily = "Impact", + }) + + lu.assertEquals(parent.fontFamily, "Georgia", "Parent should inherit from grandparent") + lu.assertEquals(child1.fontFamily, "Georgia", "Child 1 should inherit through parent") + lu.assertEquals(child2.fontFamily, "Impact", "Child 2 should use explicit fontFamily") +end + +function TestFontFamilyInheritance:testInheritanceWithAbsolutePositioning() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + fontFamily = "Comic Sans", + }) + + local child = FlexLove.Element.new({ + parent = parent, + positioning = FlexLove.Positioning.ABSOLUTE, + x = 50, + y = 50, + width = 100, + height = 100, + text = "Absolute Child", + }) + + lu.assertEquals(child.fontFamily, "Comic Sans", "Absolutely positioned child should still inherit fontFamily") +end + +function TestFontFamilyInheritance:testInheritanceDoesNotAffectSiblings() + local parent = FlexLove.Element.new({ + width = 300, + height = 300, + fontFamily = "Tahoma", + }) + + local child1 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child 1", + fontFamily = "Trebuchet", + }) + + local child2 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + text = "Child 2", + }) + + lu.assertEquals(child1.fontFamily, "Trebuchet", "Child 1 should have its own fontFamily") + lu.assertEquals(child2.fontFamily, "Tahoma", "Child 2 should inherit parent's fontFamily") + lu.assertNotEquals(child2.fontFamily, child1.fontFamily, "Siblings should have independent fontFamily values") +end + +return TestFontFamilyInheritance diff --git a/testing/__tests__/19_negative_margin_tests.lua b/testing/__tests__/19_negative_margin_tests.lua new file mode 100644 index 0000000..7f6aef4 --- /dev/null +++ b/testing/__tests__/19_negative_margin_tests.lua @@ -0,0 +1,334 @@ +local lu = require("testing.luaunit") +require("testing.loveStub") +local FlexLove = require("FlexLove") + +TestNegativeMargin = {} + +function TestNegativeMargin:setUp() + FlexLove.Gui.destroy() + FlexLove.Gui.init({ baseScale = { width = 1920, height = 1080 } }) +end + +function TestNegativeMargin:tearDown() + FlexLove.Gui.destroy() +end + +function TestNegativeMargin:testBasicNegativeMarginTop() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + positioning = FlexLove.Positioning.FLEX, + flexDirection = FlexLove.FlexDirection.VERTICAL, + }) + + local child1 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 50, + }) + + local child2 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 50, + margin = { top = -20 }, + }) + + parent:layoutChildren() + + lu.assertNotNil(child2.margin.top) + lu.assertEquals(child2.margin.top, -20, "Child2 should have -20 top margin") +end + +function TestNegativeMargin:testNegativeMarginLeft() + local parent = FlexLove.Element.new({ + width = 300, + height = 100, + positioning = FlexLove.Positioning.FLEX, + flexDirection = FlexLove.FlexDirection.HORIZONTAL, + }) + + local child1 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 50, + }) + + local child2 = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 50, + margin = { left = -30 }, + }) + + parent:layoutChildren() + + lu.assertEquals(child2.margin.left, -30, "Child2 should have -30 left margin") +end + +function TestNegativeMargin:testNegativeMarginRight() + local parent = FlexLove.Element.new({ + width = 300, + height = 100, + positioning = FlexLove.Positioning.FLEX, + flexDirection = FlexLove.FlexDirection.HORIZONTAL, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 50, + margin = { right = -15 }, + }) + + parent:layoutChildren() + + lu.assertEquals(child.margin.right, -15, "Child should have -15 right margin") +end + +function TestNegativeMargin:testNegativeMarginBottom() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + positioning = FlexLove.Positioning.FLEX, + flexDirection = FlexLove.FlexDirection.VERTICAL, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 50, + margin = { bottom = -10 }, + }) + + parent:layoutChildren() + + lu.assertEquals(child.margin.bottom, -10, "Child should have -10 bottom margin") +end + +function TestNegativeMargin:testMultipleNegativeMargins() + local parent = FlexLove.Element.new({ + width = 300, + height = 300, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { top = -20, right = -15, bottom = -10, left = -5 }, + }) + + lu.assertEquals(child.margin.top, -20) + lu.assertEquals(child.margin.right, -15) + lu.assertEquals(child.margin.bottom, -10) + lu.assertEquals(child.margin.left, -5) +end + +function TestNegativeMargin:testNegativeMarginWithPercentage() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { left = "-10%" }, + }) + + lu.assertEquals(child.margin.left, -20, "Negative 10% of 200 width should be -20") +end + +function TestNegativeMargin:testNegativeMarginWithVwUnit() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { left = "-2vw" }, + }) + + lu.assertNotNil(child.margin.left) + lu.assertTrue(child.margin.left < 0, "Negative vw margin should be negative") +end + +function TestNegativeMargin:testNegativeMarginWithVhUnit() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { top = "-2vh" }, + }) + + lu.assertNotNil(child.margin.top) + lu.assertTrue(child.margin.top < 0, "Negative vh margin should be negative") +end + +function TestNegativeMargin:testNegativeMarginInGridLayout() + local gridParent = FlexLove.Element.new({ + width = 300, + height = 300, + positioning = FlexLove.Positioning.GRID, + gridRows = 2, + gridColumns = 2, + }) + + local child = FlexLove.Element.new({ + parent = gridParent, + width = 100, + height = 100, + margin = { top = -10, left = -10 }, + }) + + lu.assertEquals(child.margin.top, -10) + lu.assertEquals(child.margin.left, -10) +end + +function TestNegativeMargin:testNegativeMarginVerticalShorthand() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { vertical = -15 }, + }) + + lu.assertEquals(child.margin.top, -15, "Vertical shorthand should set top to -15") + lu.assertEquals(child.margin.bottom, -15, "Vertical shorthand should set bottom to -15") +end + +function TestNegativeMargin:testNegativeMarginHorizontalShorthand() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { horizontal = -20 }, + }) + + lu.assertEquals(child.margin.left, -20, "Horizontal shorthand should set left to -20") + lu.assertEquals(child.margin.right, -20, "Horizontal shorthand should set right to -20") +end + +function TestNegativeMargin:testMixedPositiveAndNegativeMargins() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { top = 20, right = -10, bottom = 15, left = -5 }, + }) + + lu.assertEquals(child.margin.top, 20) + lu.assertEquals(child.margin.right, -10) + lu.assertEquals(child.margin.bottom, 15) + lu.assertEquals(child.margin.left, -5) +end + +function TestNegativeMargin:testNegativeMarginWithAbsolutePositioning() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + positioning = FlexLove.Positioning.ABSOLUTE, + x = 50, + y = 50, + width = 100, + height = 100, + margin = { top = -10, left = -10 }, + }) + + lu.assertEquals(child.margin.top, -10) + lu.assertEquals(child.margin.left, -10) +end + +function TestNegativeMargin:testNegativeMarginDoesNotAffectPadding() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + padding = { top = 10, left = 10 }, + margin = { top = -15, left = -15 }, + }) + + lu.assertEquals(child.padding.top, 10, "Padding should not be affected by negative margin") + lu.assertEquals(child.padding.left, 10, "Padding should not be affected by negative margin") + lu.assertEquals(child.margin.top, -15) + lu.assertEquals(child.margin.left, -15) +end + +function TestNegativeMargin:testExtremeNegativeMarginValues() + local parent = FlexLove.Element.new({ + width = 200, + height = 200, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { top = -1000, left = -1000 }, + }) + + lu.assertEquals(child.margin.top, -1000, "Extreme negative margin should be allowed") + lu.assertEquals(child.margin.left, -1000, "Extreme negative margin should be allowed") +end + +function TestNegativeMargin:testNegativeMarginInNestedElements() + local grandparent = FlexLove.Element.new({ + width = 300, + height = 300, + }) + + local parent = FlexLove.Element.new({ + parent = grandparent, + width = 200, + height = 200, + margin = { top = -20, left = -20 }, + }) + + local child = FlexLove.Element.new({ + parent = parent, + width = 100, + height = 100, + margin = { top = -10, left = -10 }, + }) + + lu.assertEquals(parent.margin.top, -20) + lu.assertEquals(parent.margin.left, -20) + lu.assertEquals(child.margin.top, -10) + lu.assertEquals(child.margin.left, -10) +end + +return TestNegativeMargin diff --git a/testing/runAll.lua b/testing/runAll.lua index b930df0..29d0b29 100644 --- a/testing/runAll.lua +++ b/testing/runAll.lua @@ -21,6 +21,8 @@ local testFiles = { "testing/__tests__/15_grid_layout_tests.lua", "testing/__tests__/16_event_system_tests.lua", "testing/__tests__/17_sibling_space_reservation_tests.lua", + "testing/__tests__/18_font_family_inheritance_tests.lua", + "testing/__tests__/19_negative_margin_tests.lua", } -- testingun all tests, but don't exit on error