docs improvement
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,7 +6,7 @@ themes/metal/
|
||||
themes/space/
|
||||
.DS_STORE
|
||||
tasks
|
||||
testoutput
|
||||
testoutput*
|
||||
luacov.*
|
||||
docs/doc.json
|
||||
docs/doc.md
|
||||
|
||||
66
FlexLove.lua
66
FlexLove.lua
@@ -147,7 +147,8 @@ flexlove._gcState = {
|
||||
-- Deferred callback queue for operations that cannot run while Canvas is active
|
||||
flexlove._deferredCallbacks = {}
|
||||
|
||||
--- Initialize FlexLove with configuration options, set refence scale for autoscaling on window resize, immediate mode, and error logging / error file path
|
||||
--- Set up FlexLove for your application's specific needs - configure responsive scaling, theming, rendering mode, and debugging tools
|
||||
--- Use this to establish a consistent UI foundation that adapts to different screen sizes and provides performance insights
|
||||
---@param config {baseScale?: {width?:number, height?:number}, theme?: string|ThemeDefinition, immediateMode?: boolean, stateRetentionFrames?: number, maxStateEntries?: number, autoFrameManagement?: boolean, errorLogFile?: string, enableErrorLogging?: boolean, performanceMonitoring?: boolean, performanceWarnings?: boolean, performanceHudKey?: string, performanceHudPosition?: {x: number, y: number} }
|
||||
function flexlove.init(config)
|
||||
config = config or {}
|
||||
@@ -254,8 +255,8 @@ function flexlove.init(config)
|
||||
end
|
||||
end
|
||||
|
||||
--- Queue a callback to be executed after the current frame's canvas operations complete
|
||||
--- This is necessary for operations that cannot run while a Canvas is active (e.g., love.window.setMode)
|
||||
--- Safely schedule operations that modify LÖVE's rendering state (like window mode changes) to execute after all canvas operations complete
|
||||
--- Prevents crashes from attempting canvas-incompatible operations during rendering
|
||||
---@param callback function The callback to execute
|
||||
function flexlove.deferCallback(callback)
|
||||
if type(callback) ~= "function" then
|
||||
@@ -265,9 +266,8 @@ function flexlove.deferCallback(callback)
|
||||
table.insert(flexlove._deferredCallbacks, callback)
|
||||
end
|
||||
|
||||
--- Execute all deferred callbacks and clear the queue
|
||||
--- IMPORTANT: This MUST be called at the very end of love.draw() after ALL canvases
|
||||
--- have been released, including any canvases created by the application (not just FlexLove's canvases)
|
||||
--- Execute deferred operations at the safest point in the render cycle - after all canvas operations are complete
|
||||
--- Call this at the end of love.draw() to enable window resizing and other state-modifying operations without crashes
|
||||
--- @usage
|
||||
--- function love.draw()
|
||||
--- love.graphics.setCanvas(myCanvas)
|
||||
@@ -293,6 +293,8 @@ function flexlove.executeDeferredCallbacks()
|
||||
end
|
||||
end
|
||||
|
||||
--- Recalculate all UI layouts when the window size changes - ensures your interface adapts seamlessly to new dimensions
|
||||
--- Hook this to love.resize() to maintain proper scaling and positioning across window size changes
|
||||
function flexlove.resize()
|
||||
local newWidth, newHeight = love.window.getMode()
|
||||
|
||||
@@ -320,7 +322,8 @@ function flexlove.resize()
|
||||
end
|
||||
end
|
||||
|
||||
--- Can also be set in init()
|
||||
--- Switch between immediate mode (React-like, recreates UI each frame) and retained mode (persistent elements) to match your architectural needs
|
||||
--- Use immediate for simpler state management and declarative UIs, retained for performance-critical applications with complex state
|
||||
---@param mode "immediate"|"retained"
|
||||
function flexlove.setMode(mode)
|
||||
if mode == "immediate" then
|
||||
@@ -340,13 +343,15 @@ function flexlove.setMode(mode)
|
||||
end
|
||||
end
|
||||
|
||||
--- Check which rendering mode is active to conditionally handle state management logic
|
||||
--- Useful for libraries and reusable components that need to adapt to different rendering strategies
|
||||
---@return "immediate"|"retained"
|
||||
function flexlove.getMode()
|
||||
return flexlove._immediateMode and "immediate" or "retained"
|
||||
end
|
||||
|
||||
--- Begin a new immediate mode frame
|
||||
--- You do NOT need to call this directly, it will autodetect, but you can if you need more granular control - must then paired with endFrame()
|
||||
--- Manually start a new frame in immediate mode for precise control over the UI lifecycle
|
||||
--- Only needed when you want explicit frame boundaries; otherwise FlexLove auto-manages frames
|
||||
function flexlove.beginFrame()
|
||||
if not flexlove._immediateMode then
|
||||
return
|
||||
@@ -364,9 +369,8 @@ function flexlove.beginFrame()
|
||||
Context.clearFrameElements()
|
||||
end
|
||||
|
||||
--- End the current immediate mode frame
|
||||
--- You do NOT need to call this directly unless you call beginFrame() manually - it will autodetect, but you can if you need more granular control
|
||||
--- MUST BE PAIRED WITH beginFrame()
|
||||
--- Finalize the frame in immediate mode, triggering layout calculations and state persistence
|
||||
--- Only needed when manually controlling frames with beginFrame(); otherwise handled automatically
|
||||
function flexlove.endFrame()
|
||||
if not flexlove._immediateMode then
|
||||
return
|
||||
@@ -436,6 +440,8 @@ flexlove._gameCanvas = nil
|
||||
flexlove._backdropCanvas = nil
|
||||
flexlove._canvasDimensions = { width = 0, height = 0 }
|
||||
|
||||
--- Render all UI elements with optional backdrop blur support for glassmorphic effects
|
||||
--- Place your game scene in gameDrawFunc to enable backdrop blur on UI elements; use postDrawFunc for overlays
|
||||
---@param gameDrawFunc function|nil pass component draws that should be affected by a backdrop blur
|
||||
---@param postDrawFunc function|nil pass component draws that should NOT be affected by a backdrop blur
|
||||
function flexlove.draw(gameDrawFunc, postDrawFunc)
|
||||
@@ -566,7 +572,8 @@ local function isAncestor(element, target)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Find the topmost element at given coordinates
|
||||
--- Determine which UI element the user is interacting with at a specific screen position
|
||||
--- Essential for custom input handling, tooltips, or debugging click targets in complex layouts
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return Element?
|
||||
@@ -662,6 +669,8 @@ function flexlove.getElementAtPosition(x, y)
|
||||
return blockingElements[1]
|
||||
end
|
||||
|
||||
--- Update all UI animations, interactions, and state changes each frame
|
||||
--- Hook this to love.update() to enable hover effects, animations, text cursors, and scrolling
|
||||
---@param dt number
|
||||
function flexlove.update(dt)
|
||||
-- Update Performance module with actual delta time for accurate FPS
|
||||
@@ -742,7 +751,8 @@ function flexlove._manageGC()
|
||||
-- "manual" strategy: no automatic GC, user must call flexlove.collectGarbage()
|
||||
end
|
||||
|
||||
--- Manual garbage collection control
|
||||
--- Manually trigger garbage collection to prevent frame drops during critical gameplay moments
|
||||
--- Use this to control when memory cleanup happens rather than letting it occur unpredictably
|
||||
---@param mode? string "collect" for full GC, "step" for incremental (default: "collect")
|
||||
---@param stepSize? number Work units for step mode (default: 200)
|
||||
function flexlove.collectGarbage(mode, stepSize)
|
||||
@@ -760,7 +770,8 @@ function flexlove.collectGarbage(mode, stepSize)
|
||||
end
|
||||
end
|
||||
|
||||
--- Set GC strategy
|
||||
--- Choose how FlexLove manages memory cleanup to balance performance and memory usage for your app's needs
|
||||
--- Use "manual" for tight control in performance-critical sections, "auto" for hands-off operation
|
||||
---@param strategy string "auto", "periodic", "manual", or "disabled"
|
||||
function flexlove.setGCStrategy(strategy)
|
||||
if strategy == "auto" or strategy == "periodic" or strategy == "manual" or strategy == "disabled" then
|
||||
@@ -770,7 +781,8 @@ function flexlove.setGCStrategy(strategy)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get GC statistics
|
||||
--- Monitor memory management behavior to diagnose performance issues and tune GC settings
|
||||
--- Use this to identify memory leaks or optimize garbage collection timing
|
||||
---@return table stats {gcCount, framesSinceLastGC, currentMemoryMB, strategy}
|
||||
function flexlove.getGCStats()
|
||||
return {
|
||||
@@ -782,6 +794,8 @@ function flexlove.getGCStats()
|
||||
}
|
||||
end
|
||||
|
||||
--- Forward text input to focused editable elements like text fields and text areas
|
||||
--- Hook this to love.textinput() to enable text entry in your UI
|
||||
---@param text string
|
||||
function flexlove.textinput(text)
|
||||
if flexlove._focusedElement then
|
||||
@@ -789,6 +803,8 @@ function flexlove.textinput(text)
|
||||
end
|
||||
end
|
||||
|
||||
--- Handle keyboard input for text editing, navigation, and performance overlay toggling
|
||||
--- Hook this to love.keypressed() to enable text selection, cursor movement, and the performance HUD
|
||||
---@param key string
|
||||
---@param scancode string
|
||||
---@param isrepeat boolean
|
||||
@@ -800,6 +816,8 @@ function flexlove.keypressed(key, scancode, isrepeat)
|
||||
end
|
||||
end
|
||||
|
||||
--- Enable mouse wheel scrolling in scrollable containers and lists
|
||||
--- Hook this to love.wheelmoved() to allow users to scroll through content naturally
|
||||
---@param dx number
|
||||
---@param dy number
|
||||
function flexlove.wheelmoved(dx, dy)
|
||||
@@ -926,7 +944,8 @@ function flexlove.wheelmoved(dx, dy)
|
||||
end
|
||||
end
|
||||
|
||||
--- destroys all top-level elements and resets the framework state
|
||||
--- Clean up all UI elements and reset FlexLove to initial state when changing scenes or shutting down
|
||||
--- Use this to prevent memory leaks when transitioning between game states or menus
|
||||
function flexlove.destroy()
|
||||
for _, win in ipairs(flexlove.topElements) do
|
||||
win:destroy()
|
||||
@@ -951,6 +970,8 @@ function flexlove.destroy()
|
||||
StateManager:reset()
|
||||
end
|
||||
|
||||
--- Create a new UI element with flexbox layout, styling, and interaction capabilities
|
||||
--- This is your primary API for building interfaces - buttons, panels, text, images, and containers
|
||||
---@param props ElementProps
|
||||
---@return Element
|
||||
function flexlove.new(props)
|
||||
@@ -1058,6 +1079,8 @@ function flexlove.new(props)
|
||||
return element
|
||||
end
|
||||
|
||||
--- Check how many UI element states are being tracked in immediate mode to detect memory leaks
|
||||
--- Use this during development to ensure states are properly cleaned up
|
||||
---@return number
|
||||
function flexlove.getStateCount()
|
||||
if not flexlove._immediateMode then
|
||||
@@ -1066,7 +1089,8 @@ function flexlove.getStateCount()
|
||||
return StateManager.getStateCount()
|
||||
end
|
||||
|
||||
--- Clear state for a specific element ID
|
||||
--- Remove stored state for a specific element when you know it won't be rendered again
|
||||
--- Use this to immediately free memory for elements you've removed from your UI
|
||||
---@param id string
|
||||
function flexlove.clearState(id)
|
||||
if not flexlove._immediateMode then
|
||||
@@ -1075,7 +1099,8 @@ function flexlove.clearState(id)
|
||||
StateManager.clearState(id)
|
||||
end
|
||||
|
||||
--- Clear all immediate mode states
|
||||
--- Wipe all element state when transitioning between completely different UI screens
|
||||
--- Use this for scene transitions to start with a clean slate and prevent state pollution
|
||||
function flexlove.clearAllStates()
|
||||
if not flexlove._immediateMode then
|
||||
return
|
||||
@@ -1083,7 +1108,8 @@ function flexlove.clearAllStates()
|
||||
StateManager.clearAllStates()
|
||||
end
|
||||
|
||||
--- Get state (immediate mode) statistics (for debugging)
|
||||
--- Inspect state management metrics to diagnose performance issues and optimize immediate mode usage
|
||||
--- Use this to understand state lifecycle and identify unexpected state accumulation
|
||||
---@return { stateCount: number, frameNumber: number, oldestState: number|nil, newestState: number|nil }
|
||||
function flexlove.getStateStats()
|
||||
if not flexlove._immediateMode then
|
||||
|
||||
@@ -73,7 +73,8 @@ local Easing = {
|
||||
local Animation = {}
|
||||
Animation.__index = Animation
|
||||
|
||||
---Create a new animation instance
|
||||
--- Build smooth, timed transitions between visual states to create polished, professional UIs
|
||||
--- Use this to animate position, size, opacity, colors, and other properties with customizable easing
|
||||
---@param props AnimationProps Animation properties
|
||||
---@return Animation animation The new animation instance
|
||||
function Animation.new(props)
|
||||
@@ -136,7 +137,8 @@ function Animation.new(props)
|
||||
return self
|
||||
end
|
||||
|
||||
---Update the animation with delta time
|
||||
--- Advance the animation timeline and calculate interpolated values for the current frame
|
||||
--- Call this each frame to progress the animation; returns true when complete for cleanup
|
||||
---@param dt number Delta time in seconds
|
||||
---@param element table? Optional element reference for callbacks
|
||||
---@return boolean completed True if animation is complete
|
||||
@@ -302,7 +304,8 @@ local function lerpTable(startTable, finalTable, easedT)
|
||||
return result
|
||||
end
|
||||
|
||||
---Interpolate animation values at current time
|
||||
--- Calculate the current animated values between start and end states based on elapsed time
|
||||
--- Use this to get the interpolated properties to apply to your element
|
||||
---@return table result Interpolated values {width?, height?, opacity?, x?, y?, backgroundColor?, ...}
|
||||
function Animation:interpolate()
|
||||
-- Return cached result if not dirty (avoids recalculation)
|
||||
@@ -391,7 +394,8 @@ function Animation:interpolate()
|
||||
return result
|
||||
end
|
||||
|
||||
---Apply this animation to an element
|
||||
--- Attach this animation to an element so it automatically updates and applies changes
|
||||
--- Use this for hands-off animation that integrates with FlexLove's rendering system
|
||||
---@param element Element The element to apply animation to
|
||||
function Animation:apply(element)
|
||||
if not ErrorHandler then
|
||||
@@ -417,7 +421,8 @@ function Animation:setTransformModule(TransformModule)
|
||||
self._Transform = TransformModule
|
||||
end
|
||||
|
||||
---Pause the animation
|
||||
--- Temporarily halt the animation without losing progress
|
||||
--- Use this to freeze animations during pause menus or cutscenes
|
||||
function Animation:pause()
|
||||
if self._state == "playing" or self._state == "pending" then
|
||||
self._paused = true
|
||||
@@ -425,7 +430,8 @@ function Animation:pause()
|
||||
end
|
||||
end
|
||||
|
||||
---Resume the animation
|
||||
--- Continue a paused animation from where it left off
|
||||
--- Use this to unpause animations when returning from pause menus
|
||||
function Animation:resume()
|
||||
if self._state == "paused" then
|
||||
self._paused = false
|
||||
@@ -433,24 +439,28 @@ function Animation:resume()
|
||||
end
|
||||
end
|
||||
|
||||
---Check if animation is paused
|
||||
--- Query pause state to conditionally handle animation logic
|
||||
--- Use this to sync UI behavior with animation state
|
||||
---@return boolean paused
|
||||
function Animation:isPaused()
|
||||
return self._paused
|
||||
end
|
||||
|
||||
---Reverse the animation direction
|
||||
--- Flip the animation to play backwards, creating smooth transitions in both directions
|
||||
--- Use this for hover effects that reverse on mouse-out or toggleable UI elements
|
||||
function Animation:reverse()
|
||||
self._reversed = not self._reversed
|
||||
end
|
||||
|
||||
---Check if animation is reversed
|
||||
--- Determine current playback direction for conditional animation logic
|
||||
--- Use this to track which direction the animation is playing
|
||||
---@return boolean reversed
|
||||
function Animation:isReversed()
|
||||
return self._reversed
|
||||
end
|
||||
|
||||
---Set animation playback speed
|
||||
--- Control animation tempo for slow-motion or fast-forward effects
|
||||
--- Use this for bullet-time, game speed multipliers, or debugging
|
||||
---@param speed number Speed multiplier (1.0 = normal, 2.0 = double speed, 0.5 = half speed)
|
||||
function Animation:setSpeed(speed)
|
||||
if type(speed) == "number" and speed > 0 then
|
||||
@@ -458,13 +468,15 @@ function Animation:setSpeed(speed)
|
||||
end
|
||||
end
|
||||
|
||||
---Get animation playback speed
|
||||
--- Check current playback speed for debugging or UI display
|
||||
--- Use this to show animation speed in dev tools
|
||||
---@return number speed Current speed multiplier
|
||||
function Animation:getSpeed()
|
||||
return self._speed
|
||||
end
|
||||
|
||||
---Seek to a specific time in the animation
|
||||
--- Jump to any point in the animation timeline for previewing or state restoration
|
||||
--- Use this to skip ahead, rewind, or restore saved animation states
|
||||
---@param time number Time in seconds (clamped to 0-duration)
|
||||
function Animation:seek(time)
|
||||
if type(time) == "number" then
|
||||
@@ -473,13 +485,15 @@ function Animation:seek(time)
|
||||
end
|
||||
end
|
||||
|
||||
---Get current animation state
|
||||
--- Query animation lifecycle state for conditional logic and debugging
|
||||
--- Use this to determine if cleanup is needed or to prevent duplicate animations
|
||||
---@return string state Current state: "pending", "playing", "paused", "completed", "cancelled"
|
||||
function Animation:getState()
|
||||
return self._state
|
||||
end
|
||||
|
||||
---Cancel the animation
|
||||
--- Stop the animation immediately without completing, triggering the onCancel callback
|
||||
--- Use this to abort animations when UI elements are removed or user cancels an action
|
||||
---@param element table? Optional element reference for callback
|
||||
function Animation:cancel(element)
|
||||
if self._state ~= "cancelled" and self._state ~= "completed" then
|
||||
@@ -493,7 +507,8 @@ function Animation:cancel(element)
|
||||
end
|
||||
end
|
||||
|
||||
---Reset the animation to its initial state
|
||||
--- Return the animation to the beginning for replay
|
||||
--- Use this to reuse animation instances without recreating them
|
||||
function Animation:reset()
|
||||
self.elapsed = 0
|
||||
self._hasStarted = false
|
||||
@@ -502,13 +517,15 @@ function Animation:reset()
|
||||
self._resultDirty = true
|
||||
end
|
||||
|
||||
---Get the current progress of the animation
|
||||
--- Get normalized animation progress for progress bars or synchronized effects
|
||||
--- Use this to drive secondary animations or display completion percentage
|
||||
---@return number progress Progress from 0 to 1
|
||||
function Animation:getProgress()
|
||||
return math.min(self.elapsed / self.duration, 1)
|
||||
end
|
||||
|
||||
---Chain another animation after this one completes
|
||||
--- Create sequential animation flows that play one after another
|
||||
--- Use this to build complex multi-step animations like slide-in-then-fade
|
||||
---@param nextAnimation Animation|function Animation instance or factory function that returns an animation
|
||||
---@return Animation nextAnimation The chained animation (for further chaining)
|
||||
function Animation:chain(nextAnimation)
|
||||
@@ -528,7 +545,8 @@ function Animation:chain(nextAnimation)
|
||||
end
|
||||
end
|
||||
|
||||
---Add delay before animation starts
|
||||
--- Introduce a wait period before animation begins for staggered effects
|
||||
--- Use this to create cascading animations or timed sequences
|
||||
---@param seconds number Delay duration in seconds
|
||||
---@return Animation self For chaining
|
||||
function Animation:delay(seconds)
|
||||
@@ -545,7 +563,8 @@ function Animation:delay(seconds)
|
||||
return self
|
||||
end
|
||||
|
||||
---Repeat animation multiple times
|
||||
--- Loop the animation for pulsing effects, loading indicators, or continuous motion
|
||||
--- Use this for idle animations and attention-grabbing elements
|
||||
---@param count number Number of times to repeat (0 = infinite loop)
|
||||
---@return Animation self For chaining
|
||||
function Animation:repeatCount(count)
|
||||
@@ -562,7 +581,8 @@ function Animation:repeatCount(count)
|
||||
return self
|
||||
end
|
||||
|
||||
---Enable yoyo mode (animation reverses direction on each repeat)
|
||||
--- Make repeating animations play forwards then backwards for smooth oscillation
|
||||
--- Use this for breathing effects, pulsing highlights, or pendulum motions
|
||||
---@param enabled boolean? Enable yoyo mode (default: true)
|
||||
---@return Animation self For chaining
|
||||
function Animation:yoyo(enabled)
|
||||
@@ -573,7 +593,8 @@ function Animation:yoyo(enabled)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a simple fade animation
|
||||
--- Quickly create fade in/out effects without manually specifying start/end states
|
||||
--- Use this convenience method for common opacity transitions in tooltips, notifications, and overlays
|
||||
---@param duration number Duration in seconds
|
||||
---@param fromOpacity number Starting opacity (0-1)
|
||||
---@param toOpacity number Ending opacity (0-1)
|
||||
@@ -601,7 +622,8 @@ function Animation.fade(duration, fromOpacity, toOpacity, easing)
|
||||
})
|
||||
end
|
||||
|
||||
--- Create a simple scale animation
|
||||
--- Quickly create grow/shrink effects without manually specifying dimensions
|
||||
--- Use this convenience method for bounce effects, pop-ups, and attention animations
|
||||
---@param duration number Duration in seconds
|
||||
---@param fromScale {width:number,height:number} Starting scale
|
||||
---@param toScale {width:number,height:number} Ending scale
|
||||
|
||||
@@ -13,7 +13,8 @@ local ErrorHandler = nil
|
||||
---@field onComplete function? Called when all animations complete: (group)
|
||||
---@field onStart function? Called when group starts: (group)
|
||||
|
||||
--- Create a new animation group
|
||||
--- Coordinate multiple animations to play together, in sequence, or staggered for complex choreographed effects
|
||||
--- Use this to synchronize related UI changes like simultaneous fades or sequential reveals
|
||||
---@param props AnimationGroupProps
|
||||
---@return AnimationGroup group
|
||||
function AnimationGroup.new(props)
|
||||
@@ -142,7 +143,8 @@ function AnimationGroup:_updateStagger(dt, element)
|
||||
return allFinished
|
||||
end
|
||||
|
||||
--- Update the animation group
|
||||
--- Advance all animations in the group according to their coordination mode
|
||||
--- Call this each frame to progress parallel, sequential, or staggered animations
|
||||
---@param dt number Delta time
|
||||
---@param element table? Optional element reference for callbacks
|
||||
---@return boolean finished True if group is complete
|
||||
@@ -191,7 +193,8 @@ function AnimationGroup:update(dt, element)
|
||||
return finished
|
||||
end
|
||||
|
||||
--- Pause all animations in the group
|
||||
--- Freeze the entire animation sequence in unison
|
||||
--- Use this to pause complex multi-part animations during game pauses
|
||||
function AnimationGroup:pause()
|
||||
self._paused = true
|
||||
for _, anim in ipairs(self.animations) do
|
||||
@@ -201,7 +204,8 @@ function AnimationGroup:pause()
|
||||
end
|
||||
end
|
||||
|
||||
--- Resume all animations in the group
|
||||
--- Continue all paused animations simultaneously from their paused states
|
||||
--- Use this to unpause coordinated animation sequences
|
||||
function AnimationGroup:resume()
|
||||
self._paused = false
|
||||
for _, anim in ipairs(self.animations) do
|
||||
@@ -211,13 +215,15 @@ function AnimationGroup:resume()
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if group is paused
|
||||
--- Determine if the entire group is currently paused
|
||||
--- Use this to sync other game logic with animation group state
|
||||
---@return boolean paused
|
||||
function AnimationGroup:isPaused()
|
||||
return self._paused
|
||||
end
|
||||
|
||||
--- Reverse all animations in the group
|
||||
--- Flip all animations to play backwards together
|
||||
--- Use this to reverse complex transitions like panel opens/closes
|
||||
function AnimationGroup:reverse()
|
||||
for _, anim in ipairs(self.animations) do
|
||||
if type(anim.reverse) == "function" then
|
||||
@@ -226,7 +232,8 @@ function AnimationGroup:reverse()
|
||||
end
|
||||
end
|
||||
|
||||
--- Set speed for all animations in the group
|
||||
--- Control the tempo of all animations simultaneously
|
||||
--- Use this for slow-motion effects or debugging without adjusting individual animations
|
||||
---@param speed number Speed multiplier
|
||||
function AnimationGroup:setSpeed(speed)
|
||||
for _, anim in ipairs(self.animations) do
|
||||
@@ -236,7 +243,8 @@ function AnimationGroup:setSpeed(speed)
|
||||
end
|
||||
end
|
||||
|
||||
--- Cancel all animations in the group
|
||||
--- Abort all animations in the group immediately without completion
|
||||
--- Use this when UI is dismissed mid-animation or transitions are interrupted
|
||||
---@param element table? Optional element reference for callbacks
|
||||
function AnimationGroup:cancel(element)
|
||||
if self._state ~= "cancelled" and self._state ~= "completed" then
|
||||
@@ -249,7 +257,8 @@ function AnimationGroup:cancel(element)
|
||||
end
|
||||
end
|
||||
|
||||
--- Reset the animation group to initial state
|
||||
--- Restart the entire group from the beginning for reuse
|
||||
--- Use this to replay animation sequences without recreating objects
|
||||
function AnimationGroup:reset()
|
||||
self._currentIndex = 1
|
||||
self._staggerElapsed = 0
|
||||
@@ -265,13 +274,15 @@ function AnimationGroup:reset()
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the current state of the group
|
||||
--- Check the overall lifecycle state of the animation group
|
||||
--- Use this to conditionally trigger follow-up actions or cleanup
|
||||
---@return string state "ready", "playing", "completed", "cancelled"
|
||||
function AnimationGroup:getState()
|
||||
return self._state
|
||||
end
|
||||
|
||||
--- Get the overall progress of the group (0-1)
|
||||
--- Calculate completion percentage across all animations in the group
|
||||
--- Use this for progress bars or to synchronize other effects with the group
|
||||
---@return number progress
|
||||
function AnimationGroup:getProgress()
|
||||
if #self.animations == 0 then
|
||||
@@ -305,7 +316,8 @@ function AnimationGroup:getProgress()
|
||||
end
|
||||
end
|
||||
|
||||
--- Apply this animation group to an element
|
||||
--- Attach this group to an element for automatic updates and integration
|
||||
--- Use this for hands-off animation management within FlexLove's system
|
||||
---@param element Element The element to apply animations to
|
||||
function AnimationGroup:apply(element)
|
||||
if not element or type(element) ~= "table" then
|
||||
|
||||
@@ -53,7 +53,8 @@ local NAMED_COLORS = {
|
||||
local Color = {}
|
||||
Color.__index = Color
|
||||
|
||||
--- Create a new color instance
|
||||
--- Build type-safe color objects with automatic validation and clamping
|
||||
--- Use this to avoid invalid color values and ensure consistent LÖVE-compatible colors (0-1 range)
|
||||
---@param r number? Red component (0-1), defaults to 0
|
||||
---@param g number? Green component (0-1), defaults to 0
|
||||
---@param b number? Blue component (0-1), defaults to 0
|
||||
@@ -75,7 +76,8 @@ function Color.new(r, g, b, a)
|
||||
return self
|
||||
end
|
||||
|
||||
---Convert color to RGBA components
|
||||
--- Extract individual color channels for use with love.graphics.setColor()
|
||||
--- Use this to pass colors to LÖVE's rendering functions
|
||||
---@return number r Red component (0-1)
|
||||
---@return number g Green component (0-1)
|
||||
---@return number b Blue component (0-1)
|
||||
@@ -84,8 +86,8 @@ function Color:toRGBA()
|
||||
return self.r, self.g, self.b, self.a
|
||||
end
|
||||
|
||||
--- Convert hex string to color
|
||||
--- Supports both 6-digit (#RRGGBB) and 8-digit (#RRGGBBAA) hex formats
|
||||
--- Parse CSS-style hex colors into Color objects for designer-friendly workflows
|
||||
--- Use this to work with colors from design tools that export hex values
|
||||
---@param hexWithTag string Hex color string (e.g. "#RRGGBB" or "#RRGGBBAA")
|
||||
---@return Color color The parsed color (returns white on error with warning)
|
||||
function Color.fromHex(hexWithTag)
|
||||
@@ -146,7 +148,8 @@ function Color.fromHex(hexWithTag)
|
||||
end
|
||||
end
|
||||
|
||||
--- Validate a single color channel value
|
||||
--- Verify and sanitize individual color components to prevent rendering errors
|
||||
--- Use this to safely process user input or external color data
|
||||
---@param value any Value to validate
|
||||
---@param max number? Maximum value (255 for 0-255 range, 1 for 0-1 range), defaults to 1
|
||||
---@return boolean valid True if valid
|
||||
@@ -307,7 +310,8 @@ function Color.isValidColorFormat(value)
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Validate a color value
|
||||
--- Check if a color value is usable before processing to provide clear error messages
|
||||
--- Use this for config validation and debugging malformed color data
|
||||
---@param value any Color value to validate
|
||||
---@param options table? Validation options {allowNamed: boolean, requireAlpha: boolean}
|
||||
---@return boolean valid True if valid
|
||||
@@ -342,7 +346,8 @@ function Color.validateColor(value, options)
|
||||
return true, nil
|
||||
end
|
||||
|
||||
--- Sanitize a color value (always returns a valid Color)
|
||||
--- Convert any color format to a valid Color object with graceful fallbacks
|
||||
--- Use this to robustly handle colors from any source without crashes
|
||||
---@param value any Color value to sanitize (hex, named, table, or Color instance)
|
||||
---@param default Color? Default color if invalid (defaults to black)
|
||||
---@return Color color Sanitized color instance (guaranteed non-nil)
|
||||
@@ -418,14 +423,16 @@ function Color.sanitizeColor(value, default)
|
||||
return default
|
||||
end
|
||||
|
||||
--- Parse a color from various formats (always returns a valid Color)
|
||||
--- Universally convert any color format (hex, named, table) into a Color object
|
||||
--- Use this as your main color input handler to accept flexible color specifications
|
||||
---@param value any Color value (hex string, named color, table, or Color instance)
|
||||
---@return Color color Parsed color instance (defaults to black on error)
|
||||
function Color.parse(value)
|
||||
return Color.sanitizeColor(value, Color.new(0, 0, 0, 1))
|
||||
end
|
||||
|
||||
--- Linear interpolation between two colors
|
||||
--- Smoothly transition between two colors for animations and gradients
|
||||
--- Use this to create color-based animations without manual channel calculations
|
||||
---@param colorA Color Starting color
|
||||
---@param colorB Color Ending color
|
||||
---@param t number Interpolation factor (0-1)
|
||||
|
||||
@@ -1415,13 +1415,15 @@ function Element.new(props, deps)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get element bounds (content box)
|
||||
--- Retrieve the element's screen-space rectangle for collision detection and positioning calculations
|
||||
--- Use this for custom layout logic, tooltips, or detecting overlaps between elements
|
||||
---@return { x:number, y:number, width:number, height:number }
|
||||
function Element:getBounds()
|
||||
return { x = self.x, y = self.y, width = self:getBorderBoxWidth(), height = self:getBorderBoxHeight() }
|
||||
end
|
||||
|
||||
--- Check if point is inside element bounds
|
||||
--- Test if a screen coordinate falls within the element's clickable area
|
||||
--- Use this for custom hit detection or determining which element the mouse is over
|
||||
--- @param x number
|
||||
--- @param y number
|
||||
--- @return boolean
|
||||
@@ -1430,13 +1432,15 @@ function Element:contains(x, y)
|
||||
return bounds.x <= x and bounds.y <= y and bounds.x + bounds.width >= x and bounds.y + bounds.height >= y
|
||||
end
|
||||
|
||||
--- Get border-box width (including padding)
|
||||
--- Get the element's total width including padding for layout calculations
|
||||
--- Use this when you need the full visual width rather than just content width
|
||||
---@return number
|
||||
function Element:getBorderBoxWidth()
|
||||
return self._borderBoxWidth or (self.width + self.padding.left + self.padding.right)
|
||||
end
|
||||
|
||||
--- Get border-box height (including padding)
|
||||
--- Get the element's total height including padding for layout calculations
|
||||
--- Use this when you need the full visual height rather than just content height
|
||||
---@return number
|
||||
function Element:getBorderBoxHeight()
|
||||
return self._borderBoxHeight or (self.height + self.padding.top + self.padding.bottom)
|
||||
@@ -1473,7 +1477,8 @@ function Element:_detectOverflow()
|
||||
end
|
||||
end
|
||||
|
||||
--- Set scroll position with bounds clamping (delegates to ScrollManager)
|
||||
--- Programmatically scroll content to any position for implementing "scroll to top" buttons or navigation anchors
|
||||
--- Use this to create custom scrolling controls or jump to specific content sections
|
||||
---@param x number? -- X scroll position (nil to keep current)
|
||||
---@param y number? -- Y scroll position (nil to keep current)
|
||||
function Element:setScrollPosition(x, y)
|
||||
@@ -1561,7 +1566,8 @@ function Element:_handleWheelScroll(x, y)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Get current scroll position (delegates to ScrollManager)
|
||||
--- Query how far content is scrolled to implement scroll-aware UI like "back to top" buttons
|
||||
--- Use this to create scroll position indicators or trigger lazy-loading
|
||||
---@return number scrollX, number scrollY
|
||||
function Element:getScrollPosition()
|
||||
if self._scrollManager then
|
||||
@@ -1570,7 +1576,8 @@ function Element:getScrollPosition()
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
--- Get maximum scroll bounds (delegates to ScrollManager)
|
||||
--- Find the scroll limits for validation and scroll position clamping
|
||||
--- Use this to determine if content is fully scrolled or calculate remaining scroll distance
|
||||
---@return number maxScrollX, number maxScrollY
|
||||
function Element:getMaxScroll()
|
||||
if self._scrollManager then
|
||||
@@ -1579,7 +1586,8 @@ function Element:getMaxScroll()
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
--- Get scroll percentage (0-1) (delegates to ScrollManager)
|
||||
--- Get normalized scroll progress for scroll-based animations or position indicators
|
||||
--- Use this to drive progress bars or parallax effects based on scroll position
|
||||
---@return number percentX, number percentY
|
||||
function Element:getScrollPercentage()
|
||||
if self._scrollManager then
|
||||
@@ -1588,7 +1596,8 @@ function Element:getScrollPercentage()
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
--- Check if element has overflow (delegates to ScrollManager)
|
||||
--- Determine if content extends beyond visible bounds to conditionally show scrollbars or overflow indicators
|
||||
--- Use this to decide whether to display scroll hints or enable scroll interactions
|
||||
---@return boolean hasOverflowX, boolean hasOverflowY
|
||||
function Element:hasOverflow()
|
||||
if self._scrollManager then
|
||||
@@ -1597,7 +1606,8 @@ function Element:hasOverflow()
|
||||
return false, false
|
||||
end
|
||||
|
||||
--- Get content dimensions (including overflow) (delegates to ScrollManager)
|
||||
--- Measure total content size including overflowed areas for scroll calculations
|
||||
--- Use this to understand how much content exists beyond the visible viewport
|
||||
---@return number contentWidth, number contentHeight
|
||||
function Element:getContentSize()
|
||||
if self._scrollManager then
|
||||
@@ -1606,7 +1616,8 @@ function Element:getContentSize()
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
--- Scroll by delta amount (delegates to ScrollManager)
|
||||
--- Scroll content by a relative amount for smooth scrolling animations or gesture-based scrolling
|
||||
--- Use this to implement custom scroll controls or smooth scroll transitions
|
||||
---@param dx number? -- X delta (nil for no change)
|
||||
---@param dy number? -- Y delta (nil for no change)
|
||||
function Element:scrollBy(dx, dy)
|
||||
@@ -1616,7 +1627,8 @@ function Element:scrollBy(dx, dy)
|
||||
end
|
||||
end
|
||||
|
||||
--- Scroll to top
|
||||
--- Jump to the beginning of scrollable content instantly
|
||||
--- Use this for "back to top" buttons or resetting scroll position
|
||||
function Element:scrollToTop()
|
||||
self:setScrollPosition(nil, 0)
|
||||
end
|
||||
@@ -1634,7 +1646,8 @@ function Element:scrollToLeft()
|
||||
self:setScrollPosition(0, nil)
|
||||
end
|
||||
|
||||
--- Scroll to right
|
||||
--- Jump to the rightmost position of horizontally scrollable content
|
||||
--- Use this to navigate to the end of horizontal lists or carousels
|
||||
function Element:scrollToRight()
|
||||
if self._scrollManager then
|
||||
local maxScrollX, _ = self._scrollManager:getMaxScroll()
|
||||
@@ -1718,7 +1731,8 @@ function Element:getAvailableContentHeight()
|
||||
return math.max(0, availableHeight)
|
||||
end
|
||||
|
||||
--- Add child to element
|
||||
--- Dynamically insert a child element into the hierarchy for runtime UI construction
|
||||
--- Use this to build interfaces procedurally or add elements based on application state
|
||||
---@param child Element
|
||||
function Element:addChild(child)
|
||||
child.parent = self
|
||||
@@ -1790,7 +1804,8 @@ function Element:addChild(child)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove a specific child from this element
|
||||
--- Remove a child element from the hierarchy to dynamically update UIs
|
||||
--- Use this to delete elements when they're no longer needed or respond to user actions
|
||||
---@param child Element
|
||||
function Element:removeChild(child)
|
||||
for i, c in ipairs(self.children) do
|
||||
@@ -1822,7 +1837,8 @@ function Element:removeChild(child)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove all children from this element
|
||||
--- Delete all child elements at once for resetting containers or clearing lists
|
||||
--- Use this to efficiently empty containers when rebuilding UI from scratch
|
||||
function Element:clearChildren()
|
||||
-- Clear parent references for all children
|
||||
for _, child in ipairs(self.children) do
|
||||
@@ -2661,21 +2677,24 @@ end
|
||||
-- Input Handling - Focus Management
|
||||
-- ====================
|
||||
|
||||
--- Focus this element for keyboard input
|
||||
--- Give this element keyboard focus to enable text input or keyboard navigation
|
||||
--- Use this to automatically focus text fields when showing forms or dialogs
|
||||
function Element:focus()
|
||||
if self._textEditor then
|
||||
self._textEditor:focus()
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove focus from this element
|
||||
--- Remove keyboard focus to stop capturing input events
|
||||
--- Use this when closing popups or switching focus to other elements
|
||||
function Element:blur()
|
||||
if self._textEditor then
|
||||
self._textEditor:blur()
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if this element is focused
|
||||
--- Query focus state to conditionally render focus indicators or handle keyboard input
|
||||
--- Use this to style focused elements or determine which element receives keyboard events
|
||||
---@return boolean
|
||||
function Element:isFocused()
|
||||
if self._textEditor then
|
||||
@@ -2688,7 +2707,8 @@ end
|
||||
-- Input Handling - Text Buffer Management
|
||||
-- ====================
|
||||
|
||||
--- Get current text buffer
|
||||
--- Retrieve the element's current text content for processing or validation
|
||||
--- Use this to read user input from text fields or get display text
|
||||
---@return string
|
||||
function Element:getText()
|
||||
if self._textEditor then
|
||||
@@ -2697,7 +2717,8 @@ function Element:getText()
|
||||
return self.text or ""
|
||||
end
|
||||
|
||||
--- Set text buffer and mark dirty
|
||||
--- Update the element's text content programmatically for dynamic labels or resetting inputs
|
||||
--- Use this to change text without user input, like clearing fields or updating status messages
|
||||
---@param text string
|
||||
function Element:setText(text)
|
||||
if self._textEditor then
|
||||
@@ -2709,7 +2730,8 @@ function Element:setText(text)
|
||||
self.text = text
|
||||
end
|
||||
|
||||
--- Insert text at position
|
||||
--- Programmatically insert text at any position for autocomplete or text manipulation
|
||||
--- Use this to implement suggestions, templates, or text snippets
|
||||
---@param text string -- Text to insert
|
||||
---@param position number? -- Position to insert at (default: cursor position)
|
||||
function Element:insertText(text, position)
|
||||
@@ -2899,7 +2921,8 @@ function Element:_trackActiveAnimations()
|
||||
end
|
||||
end
|
||||
|
||||
--- Set image tint color
|
||||
--- Change the tint color of an image element dynamically for hover effects or state indication
|
||||
--- Use this to recolor images without replacing the asset, like highlighting selected items
|
||||
---@param color Color Color to tint the image
|
||||
function Element:setImageTint(color)
|
||||
self.imageTint = color
|
||||
@@ -2908,7 +2931,8 @@ function Element:setImageTint(color)
|
||||
end
|
||||
end
|
||||
|
||||
--- Set image opacity
|
||||
--- Adjust image transparency independently from the element for fade effects
|
||||
--- Use this to create image-specific fade animations or disabled states
|
||||
---@param opacity number Opacity 0-1
|
||||
function Element:setImageOpacity(opacity)
|
||||
if opacity ~= nil then
|
||||
@@ -2938,7 +2962,8 @@ function Element:setImageRepeat(repeatMode)
|
||||
end
|
||||
end
|
||||
|
||||
--- Rotate element by angle
|
||||
--- Apply rotation transform to create spinning animations or rotated layouts
|
||||
--- Use this for loading spinners, compass needles, or angled UI elements
|
||||
---@param angle number Angle in radians
|
||||
function Element:rotate(angle)
|
||||
if not self.transform then
|
||||
@@ -2947,7 +2972,8 @@ function Element:rotate(angle)
|
||||
self.transform.rotate = angle
|
||||
end
|
||||
|
||||
--- Scale element
|
||||
--- Resize element visually using scale transforms for zoom effects
|
||||
--- Use this for hover magnification, shrinking animations, or responsive scaling
|
||||
---@param scaleX number X-axis scale
|
||||
---@param scaleY number? Y-axis scale (defaults to scaleX)
|
||||
function Element:scale(scaleX, scaleY)
|
||||
@@ -2958,7 +2984,8 @@ function Element:scale(scaleX, scaleY)
|
||||
self.transform.scaleY = scaleY or scaleX
|
||||
end
|
||||
|
||||
--- Translate element
|
||||
--- Offset element position using transforms for smooth movement without layout recalculation
|
||||
--- Use this for parallax effects, draggable elements, or position animations
|
||||
---@param x number X translation
|
||||
---@param y number Y translation
|
||||
function Element:translate(x, y)
|
||||
@@ -2969,7 +2996,8 @@ function Element:translate(x, y)
|
||||
self.transform.translateY = y
|
||||
end
|
||||
|
||||
--- Set transform origin
|
||||
--- Define the pivot point for rotation and scaling transforms
|
||||
--- Use this to rotate around corners, edges, or custom points rather than the center
|
||||
---@param originX number X origin (0-1, where 0.5 is center)
|
||||
---@param originY number Y origin (0-1, where 0.5 is center)
|
||||
function Element:setTransformOrigin(originX, originY)
|
||||
|
||||
@@ -124,7 +124,8 @@ Theme.__index = Theme
|
||||
local themes = {}
|
||||
local activeTheme = nil
|
||||
|
||||
---Create a new theme instance
|
||||
--- Create reusable design systems with consistent styling, 9-patch assets, and component states
|
||||
--- Use this to build professional-looking UIs with minimal per-element configuration
|
||||
---@param definition ThemeDefinition Theme definition table
|
||||
---@return Theme theme The new theme instance
|
||||
function Theme.new(definition)
|
||||
@@ -312,7 +313,8 @@ function Theme.new(definition)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Load a theme from a Lua file
|
||||
--- Import a theme definition from a file to enable hot-reloading and modular design systems
|
||||
--- Use this to load bundled or user-created themes dynamically
|
||||
---@param path string Path to theme definition file (e.g., "space" or "mytheme")
|
||||
---@return Theme? theme The loaded theme, or nil on error
|
||||
function Theme.load(path)
|
||||
@@ -348,7 +350,8 @@ function Theme.load(path)
|
||||
return theme
|
||||
end
|
||||
|
||||
---Set the active theme
|
||||
--- Switch the global theme to instantly restyle all themed UI elements
|
||||
--- Use this to implement light/dark mode toggles or user-selectable skins
|
||||
---@param themeOrName Theme|string Theme instance or theme name to activate
|
||||
function Theme.setActive(themeOrName)
|
||||
if type(themeOrName) == "string" then
|
||||
@@ -371,13 +374,15 @@ function Theme.setActive(themeOrName)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the active theme
|
||||
--- Access the current theme to query colors, fonts, or create theme-aware components
|
||||
--- Use this to build UI that adapts to the active design system
|
||||
---@return Theme? theme The active theme, or nil if none is active
|
||||
function Theme.getActive()
|
||||
return activeTheme
|
||||
end
|
||||
|
||||
--- Get a component from the active theme
|
||||
--- Retrieve pre-configured visual styles for UI components to maintain consistency
|
||||
--- Use this to apply theme definitions to custom elements
|
||||
---@param componentName string Name of the component (e.g., "button", "panel")
|
||||
---@param state string? Optional state (e.g., "hover", "pressed", "disabled")
|
||||
---@return ThemeComponent? component Returns component or nil if not found
|
||||
@@ -399,7 +404,8 @@ function Theme.getComponent(componentName, state)
|
||||
return component
|
||||
end
|
||||
|
||||
--- Get a font from the active theme
|
||||
--- Access theme-defined fonts for consistent typography across your UI
|
||||
--- Use this to load fonts specified in your theme definition
|
||||
---@param fontName string Name of the font family (e.g., "default", "heading")
|
||||
---@return string? fontPath Returns font path or nil if not found
|
||||
function Theme.getFont(fontName)
|
||||
@@ -410,7 +416,8 @@ function Theme.getFont(fontName)
|
||||
return activeTheme.fonts and activeTheme.fonts[fontName]
|
||||
end
|
||||
|
||||
--- Get a color from the active theme
|
||||
--- Retrieve semantic colors from the theme palette for consistent brand identity
|
||||
--- Use this instead of hardcoding colors to support themeing and color scheme switches
|
||||
---@param colorName string Name of the color (e.g., "primary", "secondary")
|
||||
---@return Color? color Returns Color instance or nil if not found
|
||||
function Theme.getColor(colorName)
|
||||
@@ -461,7 +468,8 @@ function Theme.getAllColors()
|
||||
return activeTheme.colors
|
||||
end
|
||||
|
||||
--- Get a color with a fallback if not found
|
||||
--- Safely get theme colors with guaranteed fallbacks to prevent missing color errors
|
||||
--- Use this when you need a color value no matter what
|
||||
---@param colorName string Name of the color to retrieve
|
||||
---@param fallback Color? Fallback color if not found (default: white)
|
||||
---@return Color color The color or fallback (guaranteed non-nil)
|
||||
@@ -721,7 +729,8 @@ end
|
||||
-- Export both Theme and ThemeManager
|
||||
Theme.Manager = ThemeManager
|
||||
|
||||
---Validate a theme definition for structural correctness (non-aggressive)
|
||||
--- Check theme definitions for correctness before use to catch configuration errors early
|
||||
--- Use this during development to verify custom themes are properly structured
|
||||
---@param theme table? The theme to validate
|
||||
---@param options table? Optional validation options {strict: boolean}
|
||||
---@return boolean valid, table errors List of validation errors
|
||||
@@ -908,7 +917,8 @@ function Theme.validateTheme(theme, options)
|
||||
return #errors == 0, errors
|
||||
end
|
||||
|
||||
---Sanitize a theme definition by removing invalid values and providing defaults
|
||||
--- Clean up malformed theme data to make it usable without crashing
|
||||
--- Use this to robustly handle user-created or external themes
|
||||
---@param theme table? The theme to sanitize
|
||||
---@return table sanitized The sanitized theme
|
||||
function Theme.sanitizeTheme(theme)
|
||||
|
||||
@@ -86,12 +86,19 @@ function Transform.lerp(from, to, t)
|
||||
if type(to) ~= "table" then
|
||||
to = Transform.new()
|
||||
end
|
||||
if type(t) ~= "number" or t ~= t or t == math.huge or t == -math.huge then
|
||||
if type(t) ~= "number" or t ~= t then
|
||||
-- NaN or invalid type
|
||||
t = 0
|
||||
end
|
||||
|
||||
elseif t == math.huge then
|
||||
-- Positive infinity
|
||||
t = 1
|
||||
elseif t == -math.huge then
|
||||
-- Negative infinity
|
||||
t = 0
|
||||
else
|
||||
-- Clamp t to 0-1 range
|
||||
t = math.max(0, math.min(1, t))
|
||||
end
|
||||
|
||||
return Transform.new({
|
||||
rotate = (from.rotate or 0) * (1 - t) + (to.rotate or 0) * t,
|
||||
|
||||
@@ -544,4 +544,6 @@ function TestAnimationProperties:testEdgeCase_ResultInvalidatedOnUpdate()
|
||||
luaunit.assertAlmostEquals(result1.x, 75, 0.01)
|
||||
end
|
||||
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
|
||||
@@ -92,55 +92,60 @@ end
|
||||
|
||||
-- Test: warn() prints with correct format (backward compatibility)
|
||||
function TestErrorHandler:test_warn_prints_with_format()
|
||||
-- Capture print output by mocking print
|
||||
-- Capture io.write output by mocking io.write
|
||||
local captured = nil
|
||||
local originalPrint = print
|
||||
print = function(msg)
|
||||
local originalWrite = io.write
|
||||
io.write = function(msg)
|
||||
captured = msg
|
||||
end
|
||||
|
||||
ErrorHandler.setLogTarget("console")
|
||||
ErrorHandler.warn("TestModule", "This is a warning")
|
||||
ErrorHandler.setLogTarget("none")
|
||||
|
||||
print = originalPrint
|
||||
io.write = originalWrite
|
||||
|
||||
luaunit.assertNotNil(captured, "warn() should print")
|
||||
luaunit.assertEquals(captured, "[FlexLove - TestModule] Warning: This is a warning")
|
||||
luaunit.assertStrContains(captured, "[WARNING] [TestModule] This is a warning")
|
||||
end
|
||||
|
||||
-- Test: warn() with error code
|
||||
function TestErrorHandler:test_warn_with_code()
|
||||
local captured = nil
|
||||
local originalPrint = print
|
||||
print = function(msg)
|
||||
local originalWrite = io.write
|
||||
io.write = function(msg)
|
||||
captured = msg
|
||||
end
|
||||
|
||||
ErrorHandler.setLogTarget("console")
|
||||
ErrorHandler.warn("TestModule", "VAL_001", "Potentially invalid property")
|
||||
ErrorHandler.setLogTarget("none")
|
||||
|
||||
print = originalPrint
|
||||
io.write = originalWrite
|
||||
|
||||
luaunit.assertNotNil(captured, "warn() should print")
|
||||
luaunit.assertStrContains(captured, "[FlexLove - TestModule] Warning [FLEXLOVE_VAL_001]")
|
||||
luaunit.assertStrContains(captured, "[WARNING] [TestModule] [VAL_001]")
|
||||
luaunit.assertStrContains(captured, "Potentially invalid property")
|
||||
end
|
||||
|
||||
-- Test: warn() with details
|
||||
function TestErrorHandler:test_warn_with_details()
|
||||
local captured = nil
|
||||
local originalPrint = print
|
||||
print = function(msg)
|
||||
captured = msg
|
||||
local originalWrite = io.write
|
||||
io.write = function(msg)
|
||||
captured = (captured or "") .. msg
|
||||
end
|
||||
|
||||
ErrorHandler.setLogTarget("console")
|
||||
ErrorHandler.warn("TestModule", "VAL_001", "Check this property", {
|
||||
property = "height",
|
||||
value = "auto",
|
||||
})
|
||||
ErrorHandler.setLogTarget("none")
|
||||
|
||||
print = originalPrint
|
||||
io.write = originalWrite
|
||||
|
||||
luaunit.assertNotNil(captured, "warn() should print")
|
||||
luaunit.assertStrContains(captured, "Details:")
|
||||
luaunit.assertStrContains(captured, "Property: height")
|
||||
luaunit.assertStrContains(captured, "Value: auto")
|
||||
end
|
||||
@@ -225,14 +230,16 @@ end
|
||||
-- Test: warnDeprecated prints deprecation warning
|
||||
function TestErrorHandler:test_warnDeprecated_prints_message()
|
||||
local captured = nil
|
||||
local originalPrint = print
|
||||
print = function(msg)
|
||||
local originalWrite = io.write
|
||||
io.write = function(msg)
|
||||
captured = msg
|
||||
end
|
||||
|
||||
ErrorHandler.setLogTarget("console")
|
||||
ErrorHandler.warnDeprecated("TestModule", "oldFunction", "newFunction")
|
||||
ErrorHandler.setLogTarget("none")
|
||||
|
||||
print = originalPrint
|
||||
io.write = originalWrite
|
||||
|
||||
luaunit.assertNotNil(captured, "warnDeprecated should print")
|
||||
luaunit.assertStrContains(captured, "'oldFunction' is deprecated. Use 'newFunction' instead")
|
||||
@@ -241,14 +248,16 @@ end
|
||||
-- Test: warnCommonMistake prints helpful message
|
||||
function TestErrorHandler:test_warnCommonMistake_prints_message()
|
||||
local captured = nil
|
||||
local originalPrint = print
|
||||
print = function(msg)
|
||||
local originalWrite = io.write
|
||||
io.write = function(msg)
|
||||
captured = msg
|
||||
end
|
||||
|
||||
ErrorHandler.setLogTarget("console")
|
||||
ErrorHandler.warnCommonMistake("TestModule", "Width is zero", "Set width to positive value")
|
||||
ErrorHandler.setLogTarget("none")
|
||||
|
||||
print = originalPrint
|
||||
io.write = originalWrite
|
||||
|
||||
luaunit.assertNotNil(captured, "warnCommonMistake should print")
|
||||
luaunit.assertStrContains(captured, "Width is zero. Suggestion: Set width to positive value")
|
||||
|
||||
@@ -21,7 +21,7 @@ end
|
||||
function TestFlexLove:testModuleLoads()
|
||||
luaunit.assertNotNil(FlexLove)
|
||||
luaunit.assertNotNil(FlexLove._VERSION)
|
||||
luaunit.assertEquals(FlexLove._VERSION, "0.2.2")
|
||||
luaunit.assertEquals(FlexLove._VERSION, "0.2.3")
|
||||
luaunit.assertNotNil(FlexLove._DESCRIPTION)
|
||||
luaunit.assertNotNil(FlexLove._URL)
|
||||
luaunit.assertNotNil(FlexLove._LICENSE)
|
||||
|
||||
@@ -16,8 +16,12 @@ TestImageTiling = {}
|
||||
function TestImageTiling:setUp()
|
||||
-- Create a mock image
|
||||
self.mockImage = {
|
||||
getDimensions = function() return 64, 64 end,
|
||||
type = function() return "Image" end,
|
||||
getDimensions = function()
|
||||
return 64, 64
|
||||
end,
|
||||
type = function()
|
||||
return "Image"
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -401,5 +405,6 @@ function TestImageTiling:testElementSetImageOpacity()
|
||||
luaunit.assertEquals(element.imageOpacity, 0.7)
|
||||
end
|
||||
|
||||
-- Run the tests
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
|
||||
@@ -46,7 +46,9 @@ function TestPerformanceInstrumentation:testMultipleTimers()
|
||||
Performance.startTimer("render")
|
||||
|
||||
local sum = 0
|
||||
for i = 1, 100 do sum = sum + i end
|
||||
for i = 1, 100 do
|
||||
sum = sum + i
|
||||
end
|
||||
|
||||
Performance.stopTimer("layout")
|
||||
Performance.stopTimer("render")
|
||||
@@ -159,9 +161,6 @@ function TestPerformanceInstrumentation:testExportCSV()
|
||||
luaunit.assertTrue(string.find(csv, "test_op") ~= nil)
|
||||
end
|
||||
|
||||
-- Run tests if executed directly
|
||||
if arg and arg[0]:find("performance_instrumentation_test%.lua$") then
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
|
||||
return TestPerformanceInstrumentation
|
||||
|
||||
@@ -153,4 +153,6 @@ function TestPerformanceWarnings:testLayoutRecalculationTracking()
|
||||
luaunit.assertNotNil(root)
|
||||
end
|
||||
|
||||
return TestPerformanceWarnings
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
|
||||
@@ -243,8 +243,8 @@ function TestTransform:testClone_AllProperties()
|
||||
luaunit.assertAlmostEquals(clone.originX, 0.25, 0.01)
|
||||
luaunit.assertAlmostEquals(clone.originY, 0.75, 0.01)
|
||||
|
||||
-- Ensure it's a different object
|
||||
luaunit.assertNotEquals(clone, original)
|
||||
-- Ensure it's a different object (use raw comparison)
|
||||
luaunit.assertFalse(rawequal(clone, original), "Clone should be a different table instance")
|
||||
end
|
||||
|
||||
function TestTransform:testClone_Nil()
|
||||
@@ -289,4 +289,6 @@ function TestTransform:testTransformAnimation()
|
||||
luaunit.assertAlmostEquals(result.transform.scaleX, 1.5, 0.01)
|
||||
end
|
||||
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
|
||||
@@ -105,6 +105,9 @@ function love_helper.graphics.newCanvas(width, height)
|
||||
getDimensions = function()
|
||||
return width or mockWindowWidth, height or mockWindowHeight
|
||||
end,
|
||||
release = function()
|
||||
-- Mock canvas release
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user