diff --git a/modules/EventHandler.lua b/modules/EventHandler.lua index daef180..65e8d72 100644 --- a/modules/EventHandler.lua +++ b/modules/EventHandler.lua @@ -35,37 +35,28 @@ function EventHandler.new(config, deps) local self = setmetatable({}, EventHandler) - -- Store dependencies self._InputEvent = deps.InputEvent self._GuiState = deps.GuiState - -- Event callback self.onEvent = config.onEvent - -- Mouse button state tracking {button -> boolean} self._pressed = config._pressed or {} - -- Click detection state self._lastClickTime = config._lastClickTime self._lastClickButton = config._lastClickButton self._clickCount = config._clickCount or 0 - -- Drag tracking per button {button -> position} self._dragStartX = config._dragStartX or {} self._dragStartY = config._dragStartY or {} self._lastMouseX = config._lastMouseX or {} self._lastMouseY = config._lastMouseY or {} - -- Touch state tracking {touchId -> boolean} self._touchPressed = config._touchPressed or {} - -- Hover state self._hovered = config._hovered or false - -- Reference to parent element (set via initialize) self._element = nil - -- Scrollbar press tracking flag self._scrollbarPressHandled = false return self diff --git a/modules/Grid.lua b/modules/Grid.lua index 982a9eb..08238ab 100644 --- a/modules/Grid.lua +++ b/modules/Grid.lua @@ -57,7 +57,6 @@ function Grid.layoutGridItems(element) local cellWidth = (availableWidth - totalColumnGaps) / columns local cellHeight = (availableHeight - totalRowGaps) / rows - -- Get children that participate in grid layout local gridChildren = {} for _, child in ipairs(element.children) do if not (child.positioning == Positioning.ABSOLUTE and child._explicitlyAbsolute) then @@ -65,14 +64,12 @@ function Grid.layoutGridItems(element) end end - -- Place children in grid cells for i, child in ipairs(gridChildren) do -- Calculate row and column (0-indexed for calculation) local index = i - 1 local col = index % columns local row = math.floor(index / columns) - -- Skip if we've exceeded the grid if row >= rows then break end @@ -84,7 +81,6 @@ function Grid.layoutGridItems(element) -- Apply alignment within grid cell (default to stretch) local effectiveAlignItems = element.alignItems or AlignItems.STRETCH - -- Stretch child to fill cell by default -- BORDER-BOX MODEL: Set border-box dimensions, content area adjusts automatically if effectiveAlignItems == AlignItems.STRETCH or effectiveAlignItems == "stretch" then child.x = cellX @@ -110,7 +106,6 @@ function Grid.layoutGridItems(element) child.x = cellX + cellWidth - childBorderBoxWidth child.y = cellY + cellHeight - childBorderBoxHeight else - -- Default to stretch child.x = cellX child.y = cellY child._borderBoxWidth = cellWidth @@ -122,7 +117,6 @@ function Grid.layoutGridItems(element) child.autosizing.height = false end - -- Layout child's children if it has any if #child.children > 0 then child:layoutChildren() end diff --git a/modules/GuiState.lua b/modules/GuiState.lua index fc209ef..41b9344 100644 --- a/modules/GuiState.lua +++ b/modules/GuiState.lua @@ -46,7 +46,6 @@ function GuiState.registerElement(element) return end - -- Add element to the z-index ordered list table.insert(GuiState._zIndexOrderedElements, element) end @@ -81,7 +80,6 @@ end ---@param y number Screen Y coordinate ---@return boolean True if point is inside element bounds local function isPointInElement(element, x, y) - -- Get element bounds local bx = element.x local by = element.y local bw = element._borderBoxWidth or (element.width + element.padding.left + element.padding.right) @@ -95,7 +93,6 @@ local function isPointInElement(element, x, y) -- Check if parent clips content (overflow: hidden, scroll, auto) if overflowX == "hidden" or overflowX == "scroll" or overflowX == "auto" or overflowY == "hidden" or overflowY == "scroll" or overflowY == "auto" then - -- Check if point is outside parent's clipping region local parentX = current.x + current.padding.left local parentY = current.y + current.padding.top local parentW = current.width @@ -109,7 +106,6 @@ local function isPointInElement(element, x, y) current = current.parent end - -- Check if point is inside element bounds return x >= bx and x <= bx + bw and y >= by and y <= by + bh end @@ -139,14 +135,11 @@ function GuiState.getTopElementAt(x, y) for i = #GuiState._zIndexOrderedElements, 1, -1 do local element = GuiState._zIndexOrderedElements[i] - -- Check if point is inside this element if isPointInElement(element, x, y) then - -- Return the first interactive ancestor (or the element itself if interactive) local interactive = findInteractiveAncestor(element) if interactive then return interactive end - -- If no interactive ancestor, return the element itself -- This preserves backward compatibility for non-interactive overlays return element end diff --git a/modules/ImageCache.lua b/modules/ImageCache.lua index e44f7cf..2b273d3 100644 --- a/modules/ImageCache.lua +++ b/modules/ImageCache.lua @@ -7,11 +7,8 @@ ImageCache._cache = {} ---@param path string -- File path to normalize ---@return string -- Normalized path local function normalizePath(path) - -- Remove leading/trailing whitespace path = path:match("^%s*(.-)%s*$") - -- Convert backslashes to forward slashes path = path:gsub("\\", "/") - -- Remove redundant slashes path = path:gsub("/+", "/") return path end @@ -29,12 +26,10 @@ function ImageCache.load(imagePath, loadImageData) local normalizedPath = normalizePath(imagePath) - -- Check if already cached if ImageCache._cache[normalizedPath] then return ImageCache._cache[normalizedPath].image, nil end - -- Try to load the image local success, imageOrError = pcall(love.graphics.newImage, normalizedPath) if not success then return nil, string.format("Failed to load image '%s': %s", imagePath, tostring(imageOrError)) @@ -43,7 +38,6 @@ function ImageCache.load(imagePath, loadImageData) local image = imageOrError local imgData = nil - -- Load ImageData if requested if loadImageData then local dataSuccess, dataOrError = pcall(love.image.newImageData, normalizedPath) if dataSuccess then @@ -51,7 +45,6 @@ function ImageCache.load(imagePath, loadImageData) end end - -- Cache the image ImageCache._cache[normalizedPath] = { image = image, imageData = imgData, @@ -96,7 +89,6 @@ function ImageCache.remove(imagePath) local normalizedPath = normalizePath(imagePath) if ImageCache._cache[normalizedPath] then - -- Release the image local cached = ImageCache._cache[normalizedPath] if cached.image then cached.image:release() @@ -112,7 +104,6 @@ end --- Clear all cached images function ImageCache.clear() - -- Release all images for path, cached in pairs(ImageCache._cache) do if cached.image then cached.image:release() diff --git a/modules/ImageDataReader.lua b/modules/ImageDataReader.lua index 5df3ab2..00f1823 100644 --- a/modules/ImageDataReader.lua +++ b/modules/ImageDataReader.lua @@ -6,13 +6,8 @@ local function formatError(module, message) return string.format("[FlexLove.%s] %s", module, message) end --- ==================== --- ImageDataReader --- ==================== - local ImageDataReader = {} ---- Load ImageData from a file path ---@param imagePath string ---@return love.ImageData function ImageDataReader.loadImageData(imagePath) diff --git a/modules/ImageRenderer.lua b/modules/ImageRenderer.lua index f1637a8..028e1e1 100644 --- a/modules/ImageRenderer.lua +++ b/modules/ImageRenderer.lua @@ -6,10 +6,6 @@ local function formatError(module, message) return string.format("[FlexLove.%s] %s", module, message) end --- ==================== --- ImageRenderer --- ==================== - ---@class ImageRenderer local ImageRenderer = {} @@ -26,7 +22,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds fitMode = fitMode or "fill" objectPosition = objectPosition or "center center" - -- Validate inputs if imageWidth <= 0 or imageHeight <= 0 or boundsWidth <= 0 or boundsHeight <= 0 then error(formatError("ImageRenderer", "Dimensions must be positive")) end @@ -44,7 +39,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds scaleY = 1, -- Scale factor Y } - -- Calculate based on fit mode if fitMode == "fill" then -- Stretch to fill bounds (may distort) result.scaleX = boundsWidth / imageWidth diff --git a/modules/ThemeManager.lua b/modules/ThemeManager.lua index 05fddbb..803ed86 100644 --- a/modules/ThemeManager.lua +++ b/modules/ThemeManager.lua @@ -1,9 +1,9 @@ ---@class ThemeManager ----@field theme string? -- Theme name to use ----@field themeComponent string? -- Component name from theme (e.g., "button", "panel") +---@field theme string? +---@field themeComponent string? ---@field _themeState string -- Current theme state (normal, hover, pressed, active, disabled) ----@field disabled boolean -- If true, element is disabled ----@field active boolean -- If true, element is in active state (e.g., focused input) +---@field disabled boolean +---@field active boolean ---@field disableHighlight boolean -- If true, disable pressed highlight overlay ---@field scaleCorners number? -- Scale multiplier for 9-patch corners/edges ---@field scalingAlgorithm string? -- "nearest" or "bilinear" scaling for 9-patch @@ -12,7 +12,6 @@ local ThemeManager = {} ThemeManager.__index = ThemeManager ---- Create new ThemeManager instance ---@param config table Configuration options ---@param deps table Dependencies {Theme: Theme module} ---@return ThemeManager @@ -20,10 +19,8 @@ function ThemeManager.new(config, deps) local Theme = deps.Theme local self = setmetatable({}, ThemeManager) - -- Store dependency for instance methods self._Theme = Theme - -- Theme configuration self.theme = config.theme self.themeComponent = config.themeComponent self.disabled = config.disabled or false @@ -32,20 +29,17 @@ function ThemeManager.new(config, deps) self.scaleCorners = config.scaleCorners self.scalingAlgorithm = config.scalingAlgorithm - -- Internal state self._themeState = "normal" self._element = nil return self end ---- Initialize ThemeManager with parent element reference ---@param element table The parent Element function ThemeManager:initialize(element) self._element = element end ---- Update theme state based on interaction state ---@param isHovered boolean Whether element is hovered ---@param isPressed boolean Whether element is pressed ---@param isFocused boolean Whether element is focused @@ -54,7 +48,6 @@ end function ThemeManager:updateState(isHovered, isPressed, isFocused, isDisabled) local newState = "normal" - -- State priority: disabled > active > pressed > hover > normal if isDisabled or self.disabled then newState = "disabled" elseif self.active then @@ -69,31 +62,21 @@ function ThemeManager:updateState(isHovered, isPressed, isFocused, isDisabled) return newState end ---- Get current theme state ---@return string The current theme state function ThemeManager:getState() return self._themeState end ---- Set theme state directly ---@param state string The theme state to set function ThemeManager:setState(state) self._themeState = state end ---- Check if this ThemeManager has a theme component ---@return boolean function ThemeManager:hasThemeComponent() return self.themeComponent ~= nil end ---- Get the theme component name ----@return string? -function ThemeManager:getThemeComponent() - return self.themeComponent -end - ---- Get the theme to use (element-specific or active theme) ---@return table? The theme object or nil function ThemeManager:getTheme() if self.theme then @@ -102,7 +85,6 @@ function ThemeManager:getTheme() return self._Theme.getActive() end ---- Get the component definition from the theme ---@return table? The component definition or nil function ThemeManager:getComponent() if not self.themeComponent then @@ -117,7 +99,6 @@ function ThemeManager:getComponent() return themeToUse.components[self.themeComponent] end ---- Get the current state's component definition (including state-specific overrides) ---@return table? The component definition for current state or nil function ThemeManager:getStateComponent() local component = self:getComponent() @@ -125,7 +106,6 @@ function ThemeManager:getStateComponent() return nil end - -- Check for state-specific override local state = self._themeState if state and state ~= "normal" and component.states and component.states[state] then return component.states[state] @@ -134,7 +114,6 @@ function ThemeManager:getStateComponent() return component end ---- Get property value from theme for current state ---@param property string The property name ---@return any? The property value or nil function ThemeManager:getStyle(property) @@ -146,9 +125,8 @@ function ThemeManager:getStyle(property) return stateComponent[property] end ---- Get the scaled content padding for current theme state ----@param borderBoxWidth number The element's border box width ----@param borderBoxHeight number The element's border box height +---@param borderBoxWidth number +---@param borderBoxHeight number ---@return table? {left, top, right, bottom} or nil if no contentPadding function ThemeManager:getScaledContentPadding(borderBoxWidth, borderBoxHeight) if not self.themeComponent then @@ -162,7 +140,6 @@ function ThemeManager:getScaledContentPadding(borderBoxWidth, borderBoxHeight) local component = themeToUse.components[self.themeComponent] - -- Check for state-specific override local state = self._themeState or "normal" if state and state ~= "normal" and component.states and component.states[state] then component = component.states[state] @@ -174,7 +151,6 @@ function ThemeManager:getScaledContentPadding(borderBoxWidth, borderBoxHeight) local contentPadding = component._ninePatchData.contentPadding - -- Scale contentPadding to match the actual rendered size local atlasImage = component._loadedAtlas or themeToUse.atlas if atlasImage and type(atlasImage) ~= "string" then local originalWidth, originalHeight = atlasImage:getDimensions() @@ -192,7 +168,6 @@ function ThemeManager:getScaledContentPadding(borderBoxWidth, borderBoxHeight) return nil end ---- Get contentAutoSizingMultiplier from theme ---@return number? The multiplier or nil function ThemeManager:getContentAutoSizingMultiplier() if not self.themeComponent then @@ -204,7 +179,6 @@ function ThemeManager:getContentAutoSizingMultiplier() return nil end - -- First check if themeComponent has a multiplier if self.themeComponent then local component = themeToUse.components[self.themeComponent] if component and component.contentAutoSizingMultiplier then @@ -233,7 +207,6 @@ function ThemeManager:getDefaultFontFamily() return nil end ---- Set theme and component ---@param themeName string? The theme name ---@param componentName string? The component name function ThemeManager:setTheme(themeName, componentName) @@ -241,16 +214,4 @@ function ThemeManager:setTheme(themeName, componentName) self.themeComponent = componentName end ---- Get scale corners multiplier ----@return number? -function ThemeManager:getScaleCorners() - return self.scaleCorners -end - ---- Get scaling algorithm ----@return string? -function ThemeManager:getScalingAlgorithm() - return self.scalingAlgorithm -end - return ThemeManager diff --git a/modules/Units.lua b/modules/Units.lua index b9cd8b3..a64b719 100644 --- a/modules/Units.lua +++ b/modules/Units.lua @@ -1,6 +1,5 @@ local Units = {} ---- Parse a unit value (string or number) into value and unit type ---@param value string|number ---@return number, string -- Returns numeric value and unit type ("px", "%", "vw", "vh") function Units.parse(value) @@ -71,7 +70,6 @@ function Units.getViewport() return Gui._cachedViewport.width, Gui._cachedViewport.height end - -- Query viewport dimensions normally if love.graphics and love.graphics.getDimensions then return love.graphics.getDimensions() else @@ -80,9 +78,8 @@ function Units.getViewport() end end ---- Apply base scaling to a value ---@param value number ----@param axis "x"|"y" -- Which axis to scale on +---@param axis "x"|"y" ---@param scaleFactors {x:number, y:number} ---@return number function Units.applyBaseScale(value, axis, scaleFactors) @@ -93,7 +90,6 @@ function Units.applyBaseScale(value, axis, scaleFactors) end end ---- Resolve units for spacing properties (padding, margin) ---@param spacingProps table? ---@param parentWidth number ---@param parentHeight number @@ -106,7 +102,6 @@ function Units.resolveSpacing(spacingProps, parentWidth, parentHeight) local viewportWidth, viewportHeight = Units.getViewport() local result = {} - -- Handle shorthand properties first local vertical = spacingProps.vertical local horizontal = spacingProps.horizontal @@ -124,7 +119,6 @@ function Units.resolveSpacing(spacingProps, parentWidth, parentHeight) end end - -- Handle individual sides for _, side in ipairs({ "top", "right", "bottom", "left" }) do local value = spacingProps[side] if value then @@ -136,7 +130,6 @@ function Units.resolveSpacing(spacingProps, parentWidth, parentHeight) result[side] = value end else - -- Use fallbacks if side == "top" or side == "bottom" then result[side] = vertical or 0 else @@ -148,9 +141,8 @@ function Units.resolveSpacing(spacingProps, parentWidth, parentHeight) return result end ---- Check if a unit string is valid ----@param unitStr string -- Unit string to validate (e.g., "10px", "50%", "20vw") ----@return boolean -- Returns true if unit string is valid +---@param unitStr string +---@return boolean function Units.isValid(unitStr) if type(unitStr) ~= "string" then return false @@ -161,7 +153,6 @@ function Units.isValid(unitStr) return validUnits[unit] == true end ---- Parse and resolve a unit value in one call ---@param value string|number -- Value to parse and resolve ---@param viewportWidth number -- Current viewport width ---@param viewportHeight number -- Current viewport height