diff --git a/README.md b/README.md index 1605b72..703a3e6 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The following features are currently being actively developed: - **Grid Layout**: CSS-like (but simplified) grid system for structured layouts - **Element Management**: Hierarchical element structures with automatic sizing - **Interactive Elements**: Buttons with click detection, event system, and callbacks -- **Theme System**: 9-slice/9-patch theming with state support (normal, hover, pressed, disabled) +- **Theme System**: 9-patch (NinePatch) theming with state support (normal, hover, pressed, disabled) - **Android 9-Patch Auto-Parsing**: Automatic parsing of *.9.png files with multi-region support - **Animations**: Built-in animation support for transitions and effects - **Responsive Design**: Automatic resizing with viewport units (vw, vh, %) diff --git a/modules/Element.lua b/modules/Element.lua index 2a3c967..d51a707 100644 --- a/modules/Element.lua +++ b/modules/Element.lua @@ -15,7 +15,7 @@ local Color = req("Color") local Units = req("Units") local Blur = req("Blur") local ImageRenderer = req("ImageRenderer") -local NineSlice = req("NineSlice") +local NinePatch = req("NinePatch") local RoundedRect = req("RoundedRect") --local Animation = req("Animation") local ImageCache = req("ImageCache") @@ -135,8 +135,8 @@ Public API methods to access internal state: ---@field active boolean? -- Whether the element is active/focused (for inputs, default: false) ---@field disableHighlight boolean? -- Whether to disable the pressed state highlight overlay (default: false) ---@field contentAutoSizingMultiplier {width:number?, height:number?}? -- Multiplier for auto-sized content dimensions ----@field scaleCorners number? -- Scale multiplier for 9-slice corners/edges. E.g., 2 = 2x size (overrides theme setting) ----@field scalingAlgorithm "nearest"|"bilinear"? -- Scaling algorithm for 9-slice corners: "nearest" (sharp/pixelated) or "bilinear" (smooth) (overrides theme setting) +---@field scaleCorners number? -- Scale multiplier for 9-patch corners/edges. E.g., 2 = 2x size (overrides theme setting) +---@field scalingAlgorithm "nearest"|"bilinear"? -- Scaling algorithm for 9-patch corners: "nearest" (sharp/pixelated) or "bilinear" (smooth) (overrides theme setting) ---@field contentBlur {intensity:number, quality:number}? -- Blur the element's content including children (intensity: 0-100, quality: 1-10) ---@field backdropBlur {intensity:number, quality:number}? -- Blur content behind the element (intensity: 0-100, quality: 1-10) ---@field _blurInstance table? -- Internal: cached blur effect instance @@ -270,7 +270,7 @@ function Element.new(props) end end - -- Initialize 9-slice corner scaling properties + -- Initialize 9-patch corner scaling properties -- These override theme component settings when specified self.scaleCorners = props.scaleCorners self.scalingAlgorithm = props.scalingAlgorithm @@ -1841,7 +1841,7 @@ function Element:getBlurInstance() return self._blurInstance end ---- Get available content width for children (accounting for 9-slice content padding) +--- Get available content width for children (accounting for 9-patch content padding) --- This is the width that children should use when calculating percentage widths ---@return number function Element:getAvailableContentWidth() @@ -1865,7 +1865,7 @@ function Element:getAvailableContentWidth() return math.max(0, availableWidth) end ---- Get available content height for children (accounting for 9-slice content padding) +--- Get available content height for children (accounting for 9-patch content padding) --- This is the height that children should use when calculating percentage heights ---@return number function Element:getAvailableContentHeight() @@ -2534,7 +2534,7 @@ function Element:draw(backdropCanvas) local borderBoxWidth = self.width + self.padding.left + self.padding.right local borderBoxHeight = self.height + self.padding.top + self.padding.bottom -- Pass element-level overrides for scaleCorners and scalingAlgorithm - NineSlice.draw(component, atlasToUse, self.x, self.y, borderBoxWidth, borderBoxHeight, self.opacity, self.scaleCorners, self.scalingAlgorithm) + NinePatch.draw(component, atlasToUse, self.x, self.y, borderBoxWidth, borderBoxHeight, self.opacity, self.scaleCorners, self.scalingAlgorithm) else -- Silently skip drawing if component structure is invalid end @@ -2609,13 +2609,13 @@ function Element:draw(backdropCanvas) local tx, ty -- Text is drawn in the content box (inside padding) - -- For 9-slice components, use contentPadding if available + -- For 9-patch components, use contentPadding if available local textPaddingLeft = self.padding.left local textPaddingTop = self.padding.top local textAreaWidth = self.width local textAreaHeight = self.height - -- Check if we should use 9-slice contentPadding for text positioning + -- Check if we should use 9-patch contentPadding for text positioning local scaledContentPadding = self:getScaledContentPadding() if scaledContentPadding then local borderBoxWidth = self._borderBoxWidth or (self.width + self.padding.left + self.padding.right) diff --git a/modules/NineSlice.lua b/modules/NinePatch.lua similarity index 97% rename from modules/NineSlice.lua rename to modules/NinePatch.lua index 25eab21..136ea4a 100644 --- a/modules/NineSlice.lua +++ b/modules/NinePatch.lua @@ -1,5 +1,5 @@ --[[ -NineSlice - 9-Patch Renderer for FlexLove +NinePatch - 9-Patch Renderer for FlexLove Handles rendering of 9-patch components with Android-style scaling. Corners can be scaled independently while edges stretch in one dimension. ]] @@ -15,7 +15,7 @@ local function formatError(module, message) return string.format("[FlexLove.%s] %s", module, message) end -local NineSlice = {} +local NinePatch = {} --- Draw a 9-patch component using Android-style rendering --- Corners are scaled by scaleCorners multiplier, edges stretch in one dimension only @@ -28,7 +28,7 @@ local NineSlice = {} ---@param opacity number? ---@param elementScaleCorners number? -- Element-level override for scaleCorners (scale multiplier) ---@param elementScalingAlgorithm "nearest"|"bilinear"? -- Element-level override for scalingAlgorithm -function NineSlice.draw(component, atlas, x, y, width, height, opacity, elementScaleCorners, elementScalingAlgorithm) +function NinePatch.draw(component, atlas, x, y, width, height, opacity, elementScaleCorners, elementScalingAlgorithm) if not component or not atlas then return end @@ -98,7 +98,7 @@ function NineSlice.draw(component, atlas, x, y, width, height, opacity, elementS -- Get ImageData from component (stored during theme loading) local atlasData = component._loadedAtlasData if not atlasData then - error(formatError("NineSlice", "No ImageData available for atlas. Image must be loaded with safeLoadImage.")) + error(formatError("NinePatch", "No ImageData available for atlas. Image must be loaded with safeLoadImage.")) end local scaledData @@ -195,4 +195,4 @@ function NineSlice.draw(component, atlas, x, y, width, height, opacity, elementS love.graphics.setColor(1, 1, 1, 1) end -return NineSlice +return NinePatch diff --git a/modules/NinePatchParser.lua b/modules/NinePatchParser.lua index e01d032..d4657c5 100644 --- a/modules/NinePatchParser.lua +++ b/modules/NinePatchParser.lua @@ -130,7 +130,7 @@ function NinePatchParser.parse(imagePath) local firstStretchY = stretchY[1] local lastStretchY = stretchY[#stretchY] - -- Stretch insets define the 9-slice regions + -- Stretch insets define the 9-patch regions local stretchLeft = firstStretchX.start local stretchRight = #topStretchPixels - lastStretchX["end"] local stretchTop = firstStretchY.start diff --git a/modules/utils.lua b/modules/utils.lua index 4a70ae5..c47b124 100644 --- a/modules/utils.lua +++ b/modules/utils.lua @@ -53,8 +53,8 @@ ---@field active boolean? -- Whether the element is active/focused (for inputs, default: false) ---@field disableHighlight boolean? -- Whether to disable the pressed state highlight overlay (default: false) ---@field contentAutoSizingMultiplier {width:number?, height:number?}? -- Multiplier for auto-sized content dimensions (default: sourced from theme) ----@field scaleCorners number? -- Scale multiplier for 9-slice corners/edges. E.g., 2 = 2x size (overrides theme setting) ----@field scalingAlgorithm "nearest"|"bilinear"? -- Scaling algorithm for 9-slice corners: "nearest" (sharp/pixelated) or "bilinear" (smooth) (overrides theme setting) +---@field scaleCorners number? -- Scale multiplier for 9-patch corners/edges. E.g., 2 = 2x size (overrides theme setting) +---@field scalingAlgorithm "nearest"|"bilinear"? -- Scaling algorithm for 9-patch corners: "nearest" (sharp/pixelated) or "bilinear" (smooth) (overrides theme setting) ---@field contentBlur {intensity:number, quality:number}? -- Blur the element's content including children (intensity: 0-100, quality: 1-10, default: nil) ---@field backdropBlur {intensity:number, quality:number}? -- Blur content behind the element (intensity: 0-100, quality: 1-10, default: nil) ---@field editable boolean? -- Whether the element is editable (default: false) diff --git a/themes/README.md b/themes/README.md index 8afb843..59c637f 100644 --- a/themes/README.md +++ b/themes/README.md @@ -2,7 +2,7 @@ ## Overview -FlexLove supports a flexible 9-slice/9-patch theming system that allows you to create scalable UI components using texture atlases. Themes provide state-based visual feedback and automatically handle element sizing. +FlexLove supports a flexible 9-patch (NinePatch) theming system that allows you to create scalable UI components using texture atlases. Themes provide state-based visual feedback and automatically handle element sizing. ## Key Features @@ -22,11 +22,11 @@ Each component gets its own image file: ``` themes/ - panel.png (24x24 pixels - 9-slice for panels) - button_normal.png (24x24 pixels - 9-slice for buttons) + panel.png (24x24 pixels - 9-patch for panels) + button_normal.png (24x24 pixels - 9-patch for buttons) button_hover.png (24x24 pixels - hover state) button_pressed.png (24x24 pixels - pressed state) - input.png (24x24 pixels - 9-slice for inputs) + input.png (24x24 pixels - 9-patch for inputs) ``` **Theme definition:** @@ -207,7 +207,7 @@ local panel = Gui.new({ Elements with themes render in this order: 1. **backgroundColor** - Rendered first (behind everything) -2. **Theme 9-slice** - Rendered on top of backgroundColor +2. **Theme 9-patch** - Rendered on top of backgroundColor 3. **Borders** - Rendered on top of theme (if specified) 4. **Text** - Rendered last (on top of everything) @@ -346,7 +346,7 @@ Gui.new({ ## Corner Scaling -By default, 9-slice corners and non-stretched edges are rendered at their original pixel size (1:1). You can scale corners using a numeric multiplier: +By default, 9-patch corners and non-stretched edges are rendered at their original pixel size (1:1). You can scale corners using a numeric multiplier: ### Corner Scaling @@ -405,7 +405,7 @@ button = { ## Tips 1. **Start Simple**: Begin with one component (button) before creating a full theme -2. **Test Scaling**: Make sure your 9-slice regions stretch properly at different sizes +2. **Test Scaling**: Make sure your 9-patch regions stretch properly at different sizes 3. **Consistent Style**: Keep corner sizes consistent across components 4. **State Variations**: For button states, change colors/brightness rather than structure 5. **Atlas Packing**: Use tools like TexturePacker or Aseprite to create efficient atlases