better scaling
This commit is contained in:
195
FlexLove.lua
195
FlexLove.lua
@@ -175,6 +175,19 @@ function Units.getViewport()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Apply base scaling to a value
|
||||||
|
---@param value number
|
||||||
|
---@param axis "x"|"y" -- Which axis to scale on
|
||||||
|
---@param scaleFactors {x:number, y:number}
|
||||||
|
---@return number
|
||||||
|
function Units.applyBaseScale(value, axis, scaleFactors)
|
||||||
|
if axis == "x" then
|
||||||
|
return value * scaleFactors.x
|
||||||
|
else
|
||||||
|
return value * scaleFactors.y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Resolve units for spacing properties (padding, margin)
|
--- Resolve units for spacing properties (padding, margin)
|
||||||
---@param spacingProps table?
|
---@param spacingProps table?
|
||||||
---@param parentWidth number
|
---@param parentWidth number
|
||||||
@@ -233,14 +246,50 @@ end
|
|||||||
--- Top level GUI manager
|
--- Top level GUI manager
|
||||||
---@class Gui
|
---@class Gui
|
||||||
---@field topElements table<integer, Element>
|
---@field topElements table<integer, Element>
|
||||||
|
---@field baseScale {width:number, height:number}?
|
||||||
|
---@field scaleFactors {x:number, y:number}
|
||||||
|
---@field init fun(config: {baseScale: {width:number, height:number}}): nil
|
||||||
---@field resize fun(): nil
|
---@field resize fun(): nil
|
||||||
---@field draw fun(): nil
|
---@field draw fun(): nil
|
||||||
---@field update fun(dt:number): nil
|
---@field update fun(dt:number): nil
|
||||||
---@field destroy fun(): nil
|
---@field destroy fun(): nil
|
||||||
local Gui = { topElements = {} }
|
local Gui = {
|
||||||
|
topElements = {},
|
||||||
|
baseScale = nil,
|
||||||
|
scaleFactors = { x = 1.0, y = 1.0 },
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Initialize FlexLove with configuration
|
||||||
|
---@param config {baseScale?: {width?:number, height?:number}} --Default: {width: 1920, height: 1080}
|
||||||
|
function Gui.init(config)
|
||||||
|
if config.baseScale then
|
||||||
|
Gui.baseScale = {
|
||||||
|
width = config.baseScale.width or 1920,
|
||||||
|
height = config.baseScale.height or 1080,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Calculate initial scale factors
|
||||||
|
local currentWidth, currentHeight = Units.getViewport()
|
||||||
|
Gui.scaleFactors.x = currentWidth / Gui.baseScale.width
|
||||||
|
Gui.scaleFactors.y = currentHeight / Gui.baseScale.height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get current scale factors
|
||||||
|
---@return number, number -- scaleX, scaleY
|
||||||
|
function Gui.getScaleFactors()
|
||||||
|
return Gui.scaleFactors.x, Gui.scaleFactors.y
|
||||||
|
end
|
||||||
|
|
||||||
function Gui.resize()
|
function Gui.resize()
|
||||||
local newWidth, newHeight = love.window.getMode()
|
local newWidth, newHeight = love.window.getMode()
|
||||||
|
|
||||||
|
-- Update scale factors if base scale is set
|
||||||
|
if Gui.baseScale then
|
||||||
|
Gui.scaleFactors.x = newWidth / Gui.baseScale.width
|
||||||
|
Gui.scaleFactors.y = newHeight / Gui.baseScale.height
|
||||||
|
end
|
||||||
|
|
||||||
for _, win in ipairs(Gui.topElements) do
|
for _, win in ipairs(Gui.topElements) do
|
||||||
win:resize(newWidth, newHeight)
|
win:resize(newWidth, newHeight)
|
||||||
end
|
end
|
||||||
@@ -572,6 +621,9 @@ function Element.new(props)
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Get scale factors from Gui (will be used later)
|
||||||
|
local scaleX, scaleY = Gui.getScaleFactors()
|
||||||
|
|
||||||
-- Handle width (both w and width properties, prefer w if both exist)
|
-- Handle width (both w and width properties, prefer w if both exist)
|
||||||
local widthProp = props.width
|
local widthProp = props.width
|
||||||
if widthProp then
|
if widthProp then
|
||||||
@@ -581,7 +633,8 @@ function Element.new(props)
|
|||||||
local parentWidth = self.parent and self.parent.width or viewportWidth
|
local parentWidth = self.parent and self.parent.width or viewportWidth
|
||||||
self.width = Units.resolve(value, unit, viewportWidth, viewportHeight, parentWidth)
|
self.width = Units.resolve(value, unit, viewportWidth, viewportHeight, parentWidth)
|
||||||
else
|
else
|
||||||
self.width = widthProp
|
-- Apply base scaling to pixel values
|
||||||
|
self.width = Gui.baseScale and (widthProp * scaleX) or widthProp
|
||||||
self.units.width = { value = widthProp, unit = "px" }
|
self.units.width = { value = widthProp, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -599,7 +652,8 @@ function Element.new(props)
|
|||||||
local parentHeight = self.parent and self.parent.height or viewportHeight
|
local parentHeight = self.parent and self.parent.height or viewportHeight
|
||||||
self.height = Units.resolve(value, unit, viewportWidth, viewportHeight, parentHeight)
|
self.height = Units.resolve(value, unit, viewportWidth, viewportHeight, parentHeight)
|
||||||
else
|
else
|
||||||
self.height = heightProp
|
-- Apply base scaling to pixel values
|
||||||
|
self.height = Gui.baseScale and (heightProp * scaleY) or heightProp
|
||||||
self.units.height = { value = heightProp, unit = "px" }
|
self.units.height = { value = heightProp, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -634,14 +688,14 @@ function Element.new(props)
|
|||||||
-- Store original textSize units and constraints
|
-- Store original textSize units and constraints
|
||||||
self.minTextSize = props.minTextSize
|
self.minTextSize = props.minTextSize
|
||||||
self.maxTextSize = props.maxTextSize
|
self.maxTextSize = props.maxTextSize
|
||||||
|
|
||||||
-- Auto-scale text by default (can be disabled with autoScaleText = false)
|
-- Auto-scale text by default (can be disabled with autoScaleText = false)
|
||||||
if props.autoScaleText == nil then
|
if props.autoScaleText == nil then
|
||||||
self.autoScaleText = true
|
self.autoScaleText = true
|
||||||
else
|
else
|
||||||
self.autoScaleText = props.autoScaleText
|
self.autoScaleText = props.autoScaleText
|
||||||
end
|
end
|
||||||
|
|
||||||
if props.textSize then
|
if props.textSize then
|
||||||
if type(props.textSize) == "string" then
|
if type(props.textSize) == "string" then
|
||||||
local value, unit = Units.parse(props.textSize)
|
local value, unit = Units.parse(props.textSize)
|
||||||
@@ -664,8 +718,23 @@ function Element.new(props)
|
|||||||
self.textSize = Units.resolve(value, unit, viewportWidth, viewportHeight, nil)
|
self.textSize = Units.resolve(value, unit, viewportWidth, viewportHeight, nil)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.textSize = props.textSize
|
-- Validate pixel textSize value
|
||||||
self.units.textSize = { value = props.textSize, unit = "px" }
|
if props.textSize <= 0 then
|
||||||
|
error("textSize must be greater than 0, got: " .. tostring(props.textSize))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pixel textSize value
|
||||||
|
if self.autoScaleText then
|
||||||
|
-- Convert pixel value to viewport units for auto-scaling
|
||||||
|
-- Calculate what percentage of viewport height this represents
|
||||||
|
local vhValue = (props.textSize / viewportHeight) * 100
|
||||||
|
self.units.textSize = { value = vhValue, unit = "vh" }
|
||||||
|
self.textSize = props.textSize -- Initial size is the specified pixel value
|
||||||
|
else
|
||||||
|
-- Apply base scaling to pixel text sizes (no auto-scaling)
|
||||||
|
self.textSize = Gui.baseScale and (props.textSize * scaleY) or props.textSize
|
||||||
|
self.units.textSize = { value = props.textSize, unit = "px" }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- No textSize specified - use auto-scaling default
|
-- No textSize specified - use auto-scaling default
|
||||||
@@ -674,18 +743,26 @@ function Element.new(props)
|
|||||||
self.textSize = (1.5 / 100) * viewportHeight
|
self.textSize = (1.5 / 100) * viewportHeight
|
||||||
self.units.textSize = { value = 1.5, unit = "vh" }
|
self.units.textSize = { value = 1.5, unit = "vh" }
|
||||||
else
|
else
|
||||||
-- Fixed 12px when auto-scaling is disabled
|
-- Fixed 12px when auto-scaling is disabled (with base scaling if set)
|
||||||
self.textSize = 12
|
self.textSize = Gui.baseScale and (12 * scaleY) or 12
|
||||||
self.units.textSize = { value = nil, unit = "px" }
|
self.units.textSize = { value = nil, unit = "px" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Apply min/max constraints (also scaled)
|
||||||
|
local minSize = self.minTextSize and (Gui.baseScale and (self.minTextSize * scaleY) or self.minTextSize)
|
||||||
|
local maxSize = self.maxTextSize and (Gui.baseScale and (self.maxTextSize * scaleY) or self.maxTextSize)
|
||||||
|
|
||||||
-- Apply min/max constraints
|
if minSize and self.textSize < minSize then
|
||||||
if self.minTextSize and self.textSize < self.minTextSize then
|
self.textSize = minSize
|
||||||
self.textSize = self.minTextSize
|
|
||||||
end
|
end
|
||||||
if self.maxTextSize and self.textSize > self.maxTextSize then
|
if maxSize and self.textSize > maxSize then
|
||||||
self.textSize = self.maxTextSize
|
self.textSize = maxSize
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Protect against too-small text sizes (minimum 1px)
|
||||||
|
if self.textSize < 1 then
|
||||||
|
self.textSize = 1 -- Minimum 1px
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Store original spacing values for proper resize handling
|
-- Store original spacing values for proper resize handling
|
||||||
@@ -730,7 +807,8 @@ function Element.new(props)
|
|||||||
self.units.x = { value = value, unit = unit }
|
self.units.x = { value = value, unit = unit }
|
||||||
self.x = Units.resolve(value, unit, viewportWidth, viewportHeight, viewportWidth)
|
self.x = Units.resolve(value, unit, viewportWidth, viewportHeight, viewportWidth)
|
||||||
else
|
else
|
||||||
self.x = props.x
|
-- Apply base scaling to pixel positions
|
||||||
|
self.x = Gui.baseScale and (props.x * scaleX) or props.x
|
||||||
self.units.x = { value = props.x, unit = "px" }
|
self.units.x = { value = props.x, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -745,7 +823,8 @@ function Element.new(props)
|
|||||||
self.units.y = { value = value, unit = unit }
|
self.units.y = { value = value, unit = unit }
|
||||||
self.y = Units.resolve(value, unit, viewportWidth, viewportHeight, viewportHeight)
|
self.y = Units.resolve(value, unit, viewportWidth, viewportHeight, viewportHeight)
|
||||||
else
|
else
|
||||||
self.y = props.y
|
-- Apply base scaling to pixel positions
|
||||||
|
self.y = Gui.baseScale and (props.y * scaleY) or props.y
|
||||||
self.units.y = { value = props.y, unit = "px" }
|
self.units.y = { value = props.y, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -798,7 +877,8 @@ function Element.new(props)
|
|||||||
local parentWidth = self.parent.width
|
local parentWidth = self.parent.width
|
||||||
self.x = Units.resolve(value, unit, viewportWidth, viewportHeight, parentWidth)
|
self.x = Units.resolve(value, unit, viewportWidth, viewportHeight, parentWidth)
|
||||||
else
|
else
|
||||||
self.x = props.x
|
-- Apply base scaling to pixel positions
|
||||||
|
self.x = Gui.baseScale and (props.x * scaleX) or props.x
|
||||||
self.units.x = { value = props.x, unit = "px" }
|
self.units.x = { value = props.x, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -814,7 +894,8 @@ function Element.new(props)
|
|||||||
local parentHeight = self.parent.height
|
local parentHeight = self.parent.height
|
||||||
self.y = Units.resolve(value, unit, viewportWidth, viewportHeight, parentHeight)
|
self.y = Units.resolve(value, unit, viewportWidth, viewportHeight, parentHeight)
|
||||||
else
|
else
|
||||||
self.y = props.y
|
-- Apply base scaling to pixel positions
|
||||||
|
self.y = Gui.baseScale and (props.y * scaleY) or props.y
|
||||||
self.units.y = { value = props.y, unit = "px" }
|
self.units.y = { value = props.y, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -836,7 +917,9 @@ function Element.new(props)
|
|||||||
local offsetX = Units.resolve(value, unit, viewportWidth, viewportHeight, parentWidth)
|
local offsetX = Units.resolve(value, unit, viewportWidth, viewportHeight, parentWidth)
|
||||||
self.x = baseX + offsetX
|
self.x = baseX + offsetX
|
||||||
else
|
else
|
||||||
self.x = baseX + props.x
|
-- Apply base scaling to pixel offsets
|
||||||
|
local scaledOffset = Gui.baseScale and (props.x * scaleX) or props.x
|
||||||
|
self.x = baseX + scaledOffset
|
||||||
self.units.x = { value = props.x, unit = "px" }
|
self.units.x = { value = props.x, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -852,7 +935,9 @@ function Element.new(props)
|
|||||||
local offsetY = Units.resolve(value, unit, viewportWidth, viewportHeight, parentHeight)
|
local offsetY = Units.resolve(value, unit, viewportWidth, viewportHeight, parentHeight)
|
||||||
self.y = baseY + offsetY
|
self.y = baseY + offsetY
|
||||||
else
|
else
|
||||||
self.y = baseY + props.y
|
-- Apply base scaling to pixel offsets
|
||||||
|
local scaledOffset = Gui.baseScale and (props.y * scaleY) or props.y
|
||||||
|
self.y = baseY + scaledOffset
|
||||||
self.units.y = { value = props.y, unit = "px" }
|
self.units.y = { value = props.y, unit = "px" }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1248,7 +1333,11 @@ function Element:layoutChildren()
|
|||||||
child.y = self.y + self.padding.top + currentCrossPos + child.padding.top
|
child.y = self.y + self.padding.top + currentCrossPos + child.padding.top
|
||||||
elseif effectiveAlign == AlignItems.CENTER then
|
elseif effectiveAlign == AlignItems.CENTER then
|
||||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||||
child.y = self.y + self.padding.top + currentCrossPos + ((lineHeight - childTotalHeight) / 2) + child.padding.top
|
child.y = self.y
|
||||||
|
+ self.padding.top
|
||||||
|
+ currentCrossPos
|
||||||
|
+ ((lineHeight - childTotalHeight) / 2)
|
||||||
|
+ child.padding.top
|
||||||
elseif effectiveAlign == AlignItems.FLEX_END then
|
elseif effectiveAlign == AlignItems.FLEX_END then
|
||||||
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
local childTotalHeight = (child.height or 0) + child.padding.top + child.padding.bottom
|
||||||
child.y = self.y + self.padding.top + currentCrossPos + lineHeight - childTotalHeight + child.padding.top
|
child.y = self.y + self.padding.top + currentCrossPos + lineHeight - childTotalHeight + child.padding.top
|
||||||
@@ -1283,7 +1372,11 @@ function Element:layoutChildren()
|
|||||||
child.x = self.x + self.padding.left + currentCrossPos + child.padding.left
|
child.x = self.x + self.padding.left + currentCrossPos + child.padding.left
|
||||||
elseif effectiveAlign == AlignItems.CENTER then
|
elseif effectiveAlign == AlignItems.CENTER then
|
||||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||||
child.x = self.x + self.padding.left + currentCrossPos + ((lineHeight - childTotalWidth) / 2) + child.padding.left
|
child.x = self.x
|
||||||
|
+ self.padding.left
|
||||||
|
+ currentCrossPos
|
||||||
|
+ ((lineHeight - childTotalWidth) / 2)
|
||||||
|
+ child.padding.left
|
||||||
elseif effectiveAlign == AlignItems.FLEX_END then
|
elseif effectiveAlign == AlignItems.FLEX_END then
|
||||||
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
local childTotalWidth = (child.width or 0) + child.padding.left + child.padding.right
|
||||||
child.x = self.x + self.padding.left + currentCrossPos + lineHeight - childTotalWidth + child.padding.left
|
child.x = self.x + self.padding.left + currentCrossPos + lineHeight - childTotalWidth + child.padding.left
|
||||||
@@ -1523,11 +1616,17 @@ end
|
|||||||
---@param newViewportWidth number
|
---@param newViewportWidth number
|
||||||
---@param newViewportHeight number
|
---@param newViewportHeight number
|
||||||
function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
||||||
|
-- Get updated scale factors
|
||||||
|
local scaleX, scaleY = Gui.getScaleFactors()
|
||||||
|
|
||||||
-- Recalculate width if using viewport or percentage units (skip auto-sized)
|
-- Recalculate width if using viewport or percentage units (skip auto-sized)
|
||||||
if self.units.width.unit ~= "px" and self.units.width.unit ~= "auto" then
|
if self.units.width.unit ~= "px" and self.units.width.unit ~= "auto" then
|
||||||
local parentWidth = self.parent and self.parent.width or newViewportWidth
|
local parentWidth = self.parent and self.parent.width or newViewportWidth
|
||||||
self.width =
|
self.width =
|
||||||
Units.resolve(self.units.width.value, self.units.width.unit, newViewportWidth, newViewportHeight, parentWidth)
|
Units.resolve(self.units.width.value, self.units.width.unit, newViewportWidth, newViewportHeight, parentWidth)
|
||||||
|
elseif self.units.width.unit == "px" and self.units.width.value and Gui.baseScale then
|
||||||
|
-- Reapply base scaling to pixel widths
|
||||||
|
self.width = self.units.width.value * scaleX
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Recalculate height if using viewport or percentage units (skip auto-sized)
|
-- Recalculate height if using viewport or percentage units (skip auto-sized)
|
||||||
@@ -1535,6 +1634,9 @@ function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
|||||||
local parentHeight = self.parent and self.parent.height or newViewportHeight
|
local parentHeight = self.parent and self.parent.height or newViewportHeight
|
||||||
self.height =
|
self.height =
|
||||||
Units.resolve(self.units.height.value, self.units.height.unit, newViewportWidth, newViewportHeight, parentHeight)
|
Units.resolve(self.units.height.value, self.units.height.unit, newViewportWidth, newViewportHeight, parentHeight)
|
||||||
|
elseif self.units.height.unit == "px" and self.units.height.value and Gui.baseScale then
|
||||||
|
-- Reapply base scaling to pixel heights
|
||||||
|
self.height = self.units.height.value * scaleY
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Recalculate position if using viewport or percentage units
|
-- Recalculate position if using viewport or percentage units
|
||||||
@@ -1545,10 +1647,14 @@ function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
|||||||
Units.resolve(self.units.x.value, self.units.x.unit, newViewportWidth, newViewportHeight, parentWidth)
|
Units.resolve(self.units.x.value, self.units.x.unit, newViewportWidth, newViewportHeight, parentWidth)
|
||||||
self.x = baseX + offsetX
|
self.x = baseX + offsetX
|
||||||
else
|
else
|
||||||
-- For pixel units, update position relative to parent's new position
|
-- For pixel units, update position relative to parent's new position (with base scaling)
|
||||||
if self.parent then
|
if self.parent then
|
||||||
local baseX = self.parent.x
|
local baseX = self.parent.x
|
||||||
self.x = baseX + self.units.x.value
|
local scaledOffset = Gui.baseScale and (self.units.x.value * scaleX) or self.units.x.value
|
||||||
|
self.x = baseX + scaledOffset
|
||||||
|
elseif Gui.baseScale then
|
||||||
|
-- Top-level element with pixel position - apply base scaling
|
||||||
|
self.x = self.units.x.value * scaleX
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1559,10 +1665,14 @@ function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
|||||||
Units.resolve(self.units.y.value, self.units.y.unit, newViewportWidth, newViewportHeight, parentHeight)
|
Units.resolve(self.units.y.value, self.units.y.unit, newViewportWidth, newViewportHeight, parentHeight)
|
||||||
self.y = baseY + offsetY
|
self.y = baseY + offsetY
|
||||||
else
|
else
|
||||||
-- For pixel units, update position relative to parent's new position
|
-- For pixel units, update position relative to parent's new position (with base scaling)
|
||||||
if self.parent then
|
if self.parent then
|
||||||
local baseY = self.parent.y
|
local baseY = self.parent.y
|
||||||
self.y = baseY + self.units.y.value
|
local scaledOffset = Gui.baseScale and (self.units.y.value * scaleY) or self.units.y.value
|
||||||
|
self.y = baseY + scaledOffset
|
||||||
|
elseif Gui.baseScale then
|
||||||
|
-- Top-level element with pixel position - apply base scaling
|
||||||
|
self.y = self.units.y.value * scaleY
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1570,7 +1680,7 @@ function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
|||||||
if self.autoScaleText and self.units.textSize.value and self.units.textSize.unit ~= "px" then
|
if self.autoScaleText and self.units.textSize.value and self.units.textSize.unit ~= "px" then
|
||||||
local unit = self.units.textSize.unit
|
local unit = self.units.textSize.unit
|
||||||
local value = self.units.textSize.value
|
local value = self.units.textSize.value
|
||||||
|
|
||||||
if unit == "%" or unit == "vh" then
|
if unit == "%" or unit == "vh" then
|
||||||
-- Percentage and vh are relative to viewport height
|
-- Percentage and vh are relative to viewport height
|
||||||
self.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, newViewportHeight)
|
self.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, newViewportHeight)
|
||||||
@@ -1586,15 +1696,36 @@ function Element:recalculateUnits(newViewportWidth, newViewportHeight)
|
|||||||
else
|
else
|
||||||
self.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, nil)
|
self.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Apply min/max constraints (with base scaling)
|
||||||
|
local minSize = self.minTextSize and (Gui.baseScale and (self.minTextSize * scaleY) or self.minTextSize)
|
||||||
|
local maxSize = self.maxTextSize and (Gui.baseScale and (self.maxTextSize * scaleY) or self.maxTextSize)
|
||||||
|
|
||||||
|
if minSize and self.textSize < minSize then
|
||||||
|
self.textSize = minSize
|
||||||
|
end
|
||||||
|
if maxSize and self.textSize > maxSize then
|
||||||
|
self.textSize = maxSize
|
||||||
|
end
|
||||||
|
|
||||||
-- Apply min/max constraints
|
-- Protect against too-small text sizes (minimum 1px)
|
||||||
if self.minTextSize and self.textSize < self.minTextSize then
|
if self.textSize < 1 then
|
||||||
self.textSize = self.minTextSize
|
self.textSize = 1 -- Minimum 1px
|
||||||
end
|
end
|
||||||
if self.maxTextSize and self.textSize > self.maxTextSize then
|
elseif self.units.textSize.unit == "px" and self.units.textSize.value and Gui.baseScale then
|
||||||
self.textSize = self.maxTextSize
|
-- Reapply base scaling to pixel text sizes
|
||||||
|
self.textSize = self.units.textSize.value * scaleY
|
||||||
|
|
||||||
|
-- Protect against too-small text sizes (minimum 1px)
|
||||||
|
if self.textSize < 1 then
|
||||||
|
self.textSize = 1 -- Minimum 1px
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Final protection: ensure textSize is always at least 1px (catches all edge cases)
|
||||||
|
if self.text and self.textSize and self.textSize < 1 then
|
||||||
|
self.textSize = 1 -- Minimum 1px
|
||||||
|
end
|
||||||
|
|
||||||
-- Recalculate gap if using viewport or percentage units
|
-- Recalculate gap if using viewport or percentage units
|
||||||
if self.units.gap.unit ~= "px" then
|
if self.units.gap.unit ~= "px" then
|
||||||
|
|||||||
@@ -13,12 +13,13 @@ TestTextScaling = {}
|
|||||||
|
|
||||||
-- Basic functionality tests
|
-- Basic functionality tests
|
||||||
function TestTextScaling.testFixedTextSize()
|
function TestTextScaling.testFixedTextSize()
|
||||||
-- Create an element with fixed textSize in pixels
|
-- Create an element with fixed textSize in pixels (auto-scaling disabled)
|
||||||
local element = Gui.new({
|
local element = Gui.new({
|
||||||
id = "testElement",
|
id = "testElement",
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 50,
|
height = 50,
|
||||||
textSize = 16, -- Fixed size in pixels
|
textSize = 16, -- Fixed size in pixels
|
||||||
|
autoScaleText = false, -- Disable auto-scaling for truly fixed size
|
||||||
text = "Hello World",
|
text = "Hello World",
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ end
|
|||||||
|
|
||||||
-- Edge case tests
|
-- Edge case tests
|
||||||
function TestTextScaling.testZeroPercentageTextSize()
|
function TestTextScaling.testZeroPercentageTextSize()
|
||||||
-- Create an element with 0% textSize
|
-- Create an element with 0% textSize (protected to minimum 1px)
|
||||||
local element = Gui.new({
|
local element = Gui.new({
|
||||||
id = "testElement",
|
id = "testElement",
|
||||||
width = 100,
|
width = 100,
|
||||||
@@ -154,15 +155,15 @@ function TestTextScaling.testZeroPercentageTextSize()
|
|||||||
text = "Hello World",
|
text = "Hello World",
|
||||||
})
|
})
|
||||||
|
|
||||||
luaunit.assertEquals(element.textSize, 0.0)
|
luaunit.assertEquals(element.textSize, 1) -- Protected to minimum 1px
|
||||||
|
|
||||||
-- Should remain 0 after resize
|
-- Should remain at minimum after resize
|
||||||
element:resize(1600, 1200)
|
element:resize(1600, 1200)
|
||||||
luaunit.assertEquals(element.textSize, 0.0)
|
luaunit.assertEquals(element.textSize, 1) -- Protected to minimum 1px
|
||||||
end
|
end
|
||||||
|
|
||||||
function TestTextScaling.testVerySmallTextSize()
|
function TestTextScaling.testVerySmallTextSize()
|
||||||
-- Create an element with very small textSize
|
-- Create an element with very small textSize (protected to minimum 1px)
|
||||||
local element = Gui.new({
|
local element = Gui.new({
|
||||||
id = "testElement",
|
id = "testElement",
|
||||||
width = 100,
|
width = 100,
|
||||||
@@ -171,10 +172,10 @@ function TestTextScaling.testVerySmallTextSize()
|
|||||||
text = "Hello World",
|
text = "Hello World",
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Check initial state (0.1% of 600px = 0.6px)
|
-- Check initial state (0.1% of 600px = 0.6px, protected to 1px)
|
||||||
luaunit.assertEquals(element.textSize, 0.6)
|
luaunit.assertEquals(element.textSize, 1)
|
||||||
|
|
||||||
-- Should scale proportionally
|
-- Should scale proportionally when above minimum
|
||||||
element:resize(1600, 1200)
|
element:resize(1600, 1200)
|
||||||
luaunit.assertEquals(element.textSize, 1.2) -- 0.1% of 1200px = 1.2px
|
luaunit.assertEquals(element.textSize, 1.2) -- 0.1% of 1200px = 1.2px
|
||||||
end
|
end
|
||||||
@@ -250,7 +251,7 @@ end
|
|||||||
function TestTextScaling.testMixedUnitsInDifferentElements()
|
function TestTextScaling.testMixedUnitsInDifferentElements()
|
||||||
-- Create multiple elements with different unit types
|
-- Create multiple elements with different unit types
|
||||||
local elements = {
|
local elements = {
|
||||||
Gui.new({ id = "px", textSize = 20, text = "Fixed" }),
|
Gui.new({ id = "px", textSize = 20, autoScaleText = false, text = "Fixed" }),
|
||||||
Gui.new({ id = "percent", textSize = "5%", text = "Percent" }),
|
Gui.new({ id = "percent", textSize = "5%", text = "Percent" }),
|
||||||
Gui.new({ id = "vw", textSize = "3vw", text = "ViewWidth" }),
|
Gui.new({ id = "vw", textSize = "3vw", text = "ViewWidth" }),
|
||||||
Gui.new({ id = "vh", textSize = "4vh", text = "ViewHeight" }),
|
Gui.new({ id = "vh", textSize = "4vh", text = "ViewHeight" }),
|
||||||
|
|||||||
@@ -3,17 +3,27 @@
|
|||||||
|
|
||||||
local love_helper = {}
|
local love_helper = {}
|
||||||
|
|
||||||
|
-- Mock window state
|
||||||
|
local mockWindowWidth = 800
|
||||||
|
local mockWindowHeight = 600
|
||||||
|
|
||||||
-- Mock window functions
|
-- Mock window functions
|
||||||
love_helper.window = {}
|
love_helper.window = {}
|
||||||
function love_helper.window.getMode()
|
function love_helper.window.getMode()
|
||||||
return 800, 600 -- Default resolution
|
return mockWindowWidth, mockWindowHeight
|
||||||
|
end
|
||||||
|
|
||||||
|
function love_helper.window.setMode(width, height)
|
||||||
|
mockWindowWidth = width
|
||||||
|
mockWindowHeight = height
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Mock graphics functions
|
-- Mock graphics functions
|
||||||
love_helper.graphics = {}
|
love_helper.graphics = {}
|
||||||
|
|
||||||
function love_helper.graphics.getDimensions()
|
function love_helper.graphics.getDimensions()
|
||||||
return 800, 600 -- Default resolution - same as window.getMode
|
return mockWindowWidth, mockWindowHeight
|
||||||
end
|
end
|
||||||
|
|
||||||
function love_helper.graphics.newFont(size)
|
function love_helper.graphics.newFont(size)
|
||||||
|
|||||||
Reference in New Issue
Block a user