239 lines
6.2 KiB
Markdown
239 lines
6.2 KiB
Markdown
# FlexLove Theme System
|
|
|
|
## Overview
|
|
|
|
FlexLove supports a flexible 9-slice/9-patch theming system that allows you to create scalable UI components using texture atlases.
|
|
|
|
## Image Organization Options
|
|
|
|
You have **three ways** to organize your theme images:
|
|
|
|
### Option 1: Separate Images Per Component (Recommended for Beginners)
|
|
|
|
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)
|
|
button_hover.png (24x24 pixels - hover state)
|
|
button_pressed.png (24x24 pixels - pressed state)
|
|
input.png (24x24 pixels - 9-slice for inputs)
|
|
```
|
|
|
|
**Theme definition:**
|
|
```lua
|
|
return {
|
|
name = "My Theme",
|
|
components = {
|
|
panel = {
|
|
atlas = "themes/panel.png",
|
|
regions = { ... }
|
|
},
|
|
button = {
|
|
atlas = "themes/button_normal.png",
|
|
regions = { ... },
|
|
states = {
|
|
hover = {
|
|
atlas = "themes/button_hover.png",
|
|
regions = { ... }
|
|
},
|
|
pressed = {
|
|
atlas = "themes/button_pressed.png",
|
|
regions = { ... }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Option 2: Single Atlas (Recommended for Performance)
|
|
|
|
All components in one texture atlas:
|
|
|
|
```
|
|
themes/
|
|
default_atlas.png (96x48 pixels containing all components)
|
|
```
|
|
|
|
**Theme definition:**
|
|
```lua
|
|
return {
|
|
name = "My Theme",
|
|
atlas = "themes/default_atlas.png", -- Global atlas
|
|
components = {
|
|
panel = {
|
|
regions = {
|
|
topLeft = {x=0, y=0, w=8, h=8},
|
|
-- ... regions reference positions in atlas
|
|
}
|
|
},
|
|
button = {
|
|
regions = {
|
|
topLeft = {x=24, y=0, w=8, h=8}, -- Different position in same atlas
|
|
-- ...
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Option 3: Hybrid (Best of Both Worlds)
|
|
|
|
Mix global atlas with component-specific images:
|
|
|
|
```lua
|
|
return {
|
|
name = "My Theme",
|
|
atlas = "themes/global_atlas.png", -- Fallback atlas
|
|
components = {
|
|
panel = {
|
|
-- Uses global atlas
|
|
regions = {x=0, y=0, ...}
|
|
},
|
|
button = {
|
|
atlas = "themes/button.png", -- Override with specific image
|
|
regions = {x=0, y=0, ...}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 9-Slice Structure
|
|
|
|
Each component image is divided into 9 regions:
|
|
|
|
```
|
|
┌─────┬──────────┬─────┐
|
|
│ TL │ TC │ TR │ (Top: fixed height)
|
|
├─────┼──────────┼─────┤
|
|
│ ML │ MC │ MR │ (Middle: stretches)
|
|
├─────┼──────────┼─────┤
|
|
│ BL │ BC │ BR │ (Bottom: fixed height)
|
|
└─────┴──────────┴─────┘
|
|
Fixed Stretch Fixed
|
|
```
|
|
|
|
- **Corners** (TL, TR, BL, BR): Fixed size, never stretched
|
|
- **Edges** (TC, BC, ML, MR): Stretched in one direction
|
|
- **Center** (MC): Stretched in both directions
|
|
|
|
## Creating Theme Images
|
|
|
|
### Minimum Image Size
|
|
|
|
For a 9-slice image, you need at least **24x24 pixels**:
|
|
- 8px for each corner
|
|
- 8px for stretchable middle section
|
|
|
|
### Image Requirements
|
|
|
|
1. **Format**: PNG with transparency
|
|
2. **Color Mode**: RGBA
|
|
3. **Border Style**: Draw borders in the corner/edge regions
|
|
4. **Center**: Can be solid color or transparent
|
|
|
|
## Example: Creating a Button Image
|
|
|
|
For a button with rounded corners and a border:
|
|
|
|
```
|
|
button_normal.png (24x24 pixels)
|
|
|
|
Pixel layout:
|
|
┌────────┬────────────┬────────┐
|
|
│ ●●●●●● │ ██████████ │ ●●●●●● │ 8px
|
|
│ ●●●●●● │ ██████████ │ ●●●●●● │
|
|
├────────┼────────────┼────────┤
|
|
│ ██████ │ ░░░░░░░░░░ │ ██████ │ 8px (stretch)
|
|
│ ██████ │ ░░░░░░░░░░ │ ██████ │
|
|
├────────┼────────────┼────────┤
|
|
│ ●●●●●● │ ██████████ │ ●●●●●● │ 8px
|
|
│ ●●●●●● │ ██████████ │ ●●●●●● │
|
|
└────────┴────────────┴────────┘
|
|
8px 8px(stretch) 8px
|
|
|
|
Legend:
|
|
● = Corner (fixed)
|
|
█ = Border edge (stretched)
|
|
░ = Fill/background (stretched both ways)
|
|
```
|
|
|
|
## Usage in Code
|
|
|
|
```lua
|
|
local FlexLove = require("FlexLove")
|
|
local Theme = FlexLove.Theme
|
|
local Gui = FlexLove.GUI
|
|
|
|
-- Load theme
|
|
Theme.load("my_theme")
|
|
Theme.setActive("my_theme")
|
|
|
|
-- Create themed button
|
|
local button = Gui.new({
|
|
width = 150,
|
|
height = 40,
|
|
text = "Click Me",
|
|
theme = "button", -- Uses button component from active theme
|
|
callback = function(element, event)
|
|
print("Clicked!")
|
|
end
|
|
})
|
|
|
|
-- Create themed panel
|
|
local panel = Gui.new({
|
|
width = 300,
|
|
height = 200,
|
|
theme = "panel"
|
|
})
|
|
```
|
|
|
|
## Component States
|
|
|
|
Buttons automatically handle three states:
|
|
- **normal**: Default appearance
|
|
- **hover**: When mouse is over the button
|
|
- **pressed**: When button is being clicked
|
|
|
|
Define state-specific images in your theme:
|
|
|
|
```lua
|
|
button = {
|
|
atlas = "themes/button_normal.png",
|
|
regions = { ... },
|
|
states = {
|
|
hover = {
|
|
atlas = "themes/button_hover.png",
|
|
regions = { ... }
|
|
},
|
|
pressed = {
|
|
atlas = "themes/button_pressed.png",
|
|
regions = { ... }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 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
|
|
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
|
|
|
|
## Tools for Creating Atlases
|
|
|
|
- **TexturePacker**: Professional sprite sheet tool
|
|
- **Aseprite**: Pixel art editor with export options
|
|
- **Shoebox**: Free sprite sheet packer
|
|
- **GIMP/Photoshop**: Manual layout with guides
|
|
|
|
## See Also
|
|
|
|
- `default.lua` - Example theme with single atlas
|
|
- `separate_images_example.lua` - Example with separate images per component
|
|
- `ThemeSystemDemo.lua` - Interactive demo of theme system
|