# FlexLove Theme System

## Overview

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

- **9-Slice Scaling**: Images scale properly to any size without distortion
- **State Management**: Automatic visual feedback for hover, pressed, disabled, and active states
- **Layered Rendering**: Themes render on top of backgroundColor, with borders on top
- **Flexible Organization**: Use separate images, single atlas, or hybrid approach
- **Automatic Highlight Disable**: Elements with themes automatically disable the pressed overlay

## Image Organization Options

You have **three ways** to organize your theme images:

### Option 1: Separate Images Per Component

Each component gets its own image file:

```
themes/
  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-patch 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

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

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-patch 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 9-patch images

I would recommend using [android studio](https://developer.android.com/studio) to create these, you can read
about how to do it in the editor [here](https://developer.android.com/studio/write/draw9patch)

### 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 Color = FlexLove.Color

FlexLove.init({
  baseScale = { width = 1920, height = 1080 },
  theme = "my_theme" -- only supports autoload of one theme
  immediateMode = true -- Optional: enable immediate mode (default: false)
})

-- you can dynamically add more
Theme.load("my_theme2")

-- Create themed button
local button_my_theme = FlexLove.new({
  width = 150,
  height = 40,
  text = "Click Me",
  textAlign = "center",
  textColor = Color.new(1, 1, 1, 1),
  backgroundColor = Color.new(0.2, 0.4, 0.8, 0.3),  -- Shows behind theme
  themeComponent = "button",  -- Uses button component from active theme
  onEvent = function(element, event)
    if event.type == "click" then
      print("Clicked!")
    end
  end
})

-- set active to switch between
Theme.setActive("my_theme2")

local button_my_theme2 = FlexLove.new({
  width = 150,
  height = 40,
  text = "Click Me",
  textAlign = "center",
  textColor = Color.new(1, 1, 1, 1),
  backgroundColor = Color.new(0.2, 0.4, 0.8, 0.3),  -- Shows behind theme
  themeComponent = "button",  -- Uses button component from active theme
  onEvent = function(element, event)
    if event.type == "click" then
      print("Clicked!")
    end
  end
})

```

## Rendering Layers

Elements with themes render in this order:

1. **backgroundColor** - Rendered first (behind everything)
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)

This allows you to:
- Tint themed elements with backgroundColor
- Add custom borders on top of themes
- Layer visual effects

## Component States

Themes automatically handle visual states for interactive elements:

- **normal**: Default appearance
- **hover**: When mouse is over the element
- **pressed**: When element is being clicked
- **disabled**: When element.disabled = true
- **active**: When element.active = true (for inputs/focused elements)

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 = { ... }
    },
    disabled = {
      atlas = "themes/button_disabled.png",
      regions = { ... }
    }
  }
}
```

## Theme Definition Example

```lua
-- themes/my_theme.lua
return {
  name = "My Theme",
  atlas = "themes/my_theme/atlas.png",
  
  components = {
    panel = {
      regions = {
        topLeft = {x=0, y=0, w=8, h=8},
        topCenter = {x=8, y=0, w=8, h=8},
        topRight = {x=16, y=0, w=8, h=8},
        middleLeft = {x=0, y=8, w=8, h=8},
        middleCenter = {x=8, y=8, w=8, h=8},
        middleRight = {x=16, y=8, w=8, h=8},
        bottomLeft = {x=0, y=16, w=8, h=8},
        bottomCenter = {x=8, y=16, w=8, h=8},
        bottomRight = {x=16, y=16, w=8, h=8}
      }
    },
    
    button = {
      regions = {
        topLeft = {x=24, y=0, w=8, h=8},
        topCenter = {x=32, y=0, w=8, h=8},
        topRight = {x=40, y=0, w=8, h=8},
        middleLeft = {x=24, y=8, w=8, h=8},
        middleCenter = {x=32, y=8, w=8, h=8},
        middleRight = {x=40, y=8, w=8, h=8},
        bottomLeft = {x=24, y=16, w=8, h=8},
        bottomCenter = {x=32, y=16, w=8, h=8},
        bottomRight = {x=40, y=16, w=8, h=8}
      },
      states = {
        hover = {
          regions = {
            -- Different region coordinates for hover state
            topLeft = {x=48, y=0, w=8, h=8},
            -- ... etc
          }
        },
        pressed = {
          regions = {
            -- Different region coordinates for pressed state
            topLeft = {x=72, y=0, w=8, h=8},
            -- ... etc
          }
        }
      }
    }
  }
}
```

## Advanced Features

### Automatic Highlight Disable

Elements with `themeComponent` automatically set `disableHighlight = true` to prevent the default gray pressed overlay from interfering with theme visuals. You can override this:

```lua
FlexLove.new({
  themeComponent = "button",
  disableHighlight = false,  -- Force enable highlight overlay
  -- ...
})
```

## Corner Scaling

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

```lua
-- themes/my_theme.lua
return {
  name = "My Theme",
  components = {
    button = {
      atlas = "themes/button.png",
      insets = { left = 8, top = 8, right = 8, bottom = 8 },
      scaleCorners = 2,                 -- Scale corners by 2x (numeric multiplier)
      scalingAlgorithm = "bilinear"     -- "bilinear" (smooth) or "nearest" (sharp/pixelated)
    }
  }
}
```

**`scaleCorners` values:**
- Number (e.g., `2`, `1.5`, `0.5`) - Direct scale multiplier
  - `2` = double size
  - `0.5` = half size
  - `1` = original size
- `nil` (default) - No scaling, 1:1 pixel perfect

### Scaling Algorithms

- **`bilinear`** (default): Smooth interpolation between pixels. Best for most use cases.
- **`nearest`**: Nearest-neighbor sampling. Best for pixel art that should maintain sharp edges.

### When to Use Corner Scaling

- **Pixel art themes**: Use `scaleCorners = 2` with `scalingAlgorithm = "nearest"` to maintain crisp pixel boundaries
- **High DPI displays**: Use `scaleCorners = 1.5` or `2` with `scalingAlgorithm = "bilinear"` for smooth scaling
- **Fixed-size UI**: Keep `scaleCorners = nil` (default) for pixel-perfect rendering at original size

### Per-State Scaling

You can also set scaling per-state:

```lua
button = {
  atlas = "themes/button_normal.png",
  scaleCorners = 2,
  scalingAlgorithm = "bilinear",
  states = {
    hover = {
      atlas = "themes/button_hover.png",
      scaleCorners = 2.5,              -- Can override per state
      scalingAlgorithm = "nearest"     -- Different algorithm for this state
    }
  }
}
```

## Tips

1. **Start Simple**: Begin with one component (button) before creating a full theme
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
6. **Transparency**: Use semi-transparent backgroundColor to tint themed elements
7. **Corner Scaling**: Enable for pixel art or responsive UIs; disable for pixel-perfect rendering

## 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

## Example Themes

See the `space/` directory for a complete theme example with:
- Panel component
- Button component with states (normal, hover, pressed, disabled)
- Compressed and uncompressed versions

## See Also

- `space.lua` - Complete theme definition example
- `ThemeSystemDemo.lua` - Interactive demo of theme system
- `ThemeLayeringDemo.lua` - Demo of backgroundColor/theme/border layering
