Update UI Component Hierarchy

John McCardle 2026-02-07 23:50:46 +00:00
commit b5d39573c6

@ -1,284 +1,284 @@
# UI Component Hierarchy
The UI Component Hierarchy defines how visual elements are structured, rendered, and managed in McRogueFace.
## Quick Reference
**Key Files:**
- `src/UIDrawable.h` - Base class for all UI components
- `src/UIFrame.h` / `.cpp` - Container with children
- `src/UICaption.h` / `.cpp` - Text rendering
- `src/UISprite.h` / `.cpp` - Image/sprite rendering
- `src/UIGrid.h` / `.cpp` - Tilemap grid (see [[Grid-System]])
- `src/UIEntity.h` / `.cpp` - Grid entities (see [[Entity-Management]])
- `src/UIArc.h`, `src/UICircle.h`, `src/UILine.h` - Geometry primitives
---
## Class Hierarchy
```
UIDrawable (base class)
+-- UIFrame - Rectangle container with children
+-- UICaption - Text labels
+-- UISprite - Images and sprite sheets
+-- UIGrid - Tilemap rendering
+-- UIEntity - Grid-based game entities
+-- UIArc - Arc/partial circle outline
+-- UICircle - Filled/outlined circle
+-- UILine - Line segment
```
---
## UIDrawable (Base Class)
All UI components inherit from `UIDrawable`, providing a consistent interface for positioning, visibility, hierarchy, and interaction.
### Position and Geometry
| Property | Type | Description |
|----------|------|-------------|
| `pos` | `(x, y)` | Position as tuple |
| `x`, `y` | `float` | Position components |
| `w`, `h` | `float` | Dimensions (Frame, Grid) |
| `bounds` | `(x, y, w, h)` | Bounding rectangle |
| `global_bounds` | `(x, y, w, h)` | Bounds in screen coordinates |
| `global_position` | `(x, y)` | Position in screen coordinates (accounts for parent chain) |
**Methods:**
- `move(dx, dy)` - Relative movement
- `resize(w, h)` - Change dimensions
### Hierarchy
| Property | Type | Description |
|----------|------|-------------|
| `parent` | `UIDrawable` | Parent element (read-only, set automatically) |
| `z_index` | `int` | Render order (higher = front) |
Children are positioned relative to their parent. When a child is added to a Frame's `children` collection, its `parent` property is set automatically.
### Visibility
| Property | Type | Description |
|----------|------|-------------|
| `visible` | `bool` | Show/hide element |
| `opacity` | `float` | Transparency (0.0 = invisible, 1.0 = opaque) |
### Interaction Callbacks
All UIDrawable types support mouse event callbacks:
| Property | Signature | Description |
|----------|-----------|-------------|
| `on_click` | `(pos: Vector, button: MouseButton, action: InputState) -> None` | Mouse click |
| `on_enter` | `(pos: Vector) -> None` | Mouse enters element bounds |
| `on_exit` | `(pos: Vector) -> None` | Mouse leaves element bounds |
| `on_move` | `(pos: Vector) -> None` | Mouse moves within element |
```python
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150))
def on_click(pos, button, action):
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED:
print(f"Clicked at ({pos.x}, {pos.y})")
frame.on_click = on_click
frame.on_enter = lambda pos: print("Mouse entered")
frame.on_exit = lambda pos: print("Mouse left")
frame.on_move = lambda pos: print(f"Mouse at ({pos.x}, {pos.y})")
```
### Animation
All UIDrawable types support the `.animate()` method:
```python
obj.animate("property", target_value, duration_secs, easing, callback=None)
```
See [[Animation-System]] for details on animatable properties per type.
### Utility
| Property | Type | Description |
|----------|------|-------------|
| `name` | `str` | Optional identifier for debugging/lookup |
---
## Concrete Types
### UIFrame
Rectangle container that can hold child elements. Primary building block for UI layouts.
```python
frame = mcrfpy.Frame(pos=(50, 50), size=(200, 150),
fill_color=mcrfpy.Color(40, 40, 50))
frame.outline_color = mcrfpy.Color(100, 100, 120)
frame.outline = 2
# Child elements are positioned relative to parent
label = mcrfpy.Caption(text="Title", pos=(10, 5))
frame.children.append(label)
```
**Unique properties:** `children` (UICollection), `fill_color`, `outline_color`, `outline`, `clip_children`
**Animatable:** `x`, `y`, `w`, `h`, `opacity`, `outline`, `fill_color`, `outline_color`
### UICaption
Text rendering with font support.
```python
text = mcrfpy.Caption(text="Hello World!", pos=(10, 10))
text.font_size = 24
text.fill_color = mcrfpy.Color(255, 255, 255)
```
**Unique properties:** `text`, `font`, `font_size`, `fill_color`
**Animatable:** `x`, `y`, `opacity`, `outline`, `fill_color`, `outline_color`
### UISprite
Image and sprite sheet rendering.
```python
texture = mcrfpy.Texture("assets/sprites/tileset.png", 16, 16)
sprite = mcrfpy.Sprite(x=100, y=100)
sprite.texture = texture
sprite.sprite_index = 5
```
**Unique properties:** `texture`, `sprite_index`, `scale`
**Animatable:** `x`, `y`, `scale`, `sprite_index`, `opacity`
### UIGrid
Tilemap container for roguelike game maps. See [[Grid-System]] for complete documentation.
```python
terrain = mcrfpy.TileLayer(name="terrain", z_index=-1, texture=texture)
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(100, 100), size=(400, 300),
layers=[terrain])
```
**Unique properties:** `grid_size`, `center`, `zoom`, `layers`, `entities`, `fill_color`, `perspective`
**Animatable:** `x`, `y`, `w`, `h`, `center_x`, `center_y`, `zoom`
### UIEntity
Game entities that live on grids. See [[Entity-Management]] for complete documentation.
```python
entity = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=0, name="player")
grid.entities.append(entity)
```
**Unique properties:** `grid_x`, `grid_y`, `sprite_index`, `grid` (parent reference)
**Animatable:** `x`, `y`, `draw_x`, `draw_y`, `sprite_index`, `sprite_scale`
### UIArc, UICircle, UILine
Geometry primitives for shapes and decorations.
```python
arc = mcrfpy.Arc(radius=50, start_angle=0, end_angle=90)
circle = mcrfpy.Circle(radius=30)
line = mcrfpy.Line(start=(0, 0), end=(100, 100))
```
---
## Collections
### UICollection
Container for Frame, Caption, Sprite, Grid, and geometry primitives. Used by `Frame.children` and `Scene.children`.
```python
scene = mcrfpy.Scene("test")
ui = scene.children # UICollection
ui.append(frame)
ui.extend([caption, sprite])
ui.remove(frame)
# Sequence protocol
for item in ui:
print(type(item).__name__)
obj = ui[0]
count = len(ui)
```
### UIEntityCollection
Container for Entity objects on a Grid.
```python
grid.entities.append(entity)
grid.entities.extend([e1, e2, e3])
grid.entities.remove(entity)
for e in grid.entities:
print(f"{e.name} at ({e.grid_x}, {e.grid_y})")
```
---
## Rendering
### Z-Index Order
1. Scene sorts UI elements by z_index (lower = back)
2. Elements rendered in sorted order
3. Children rendered after parents
### Parent-Child Coordinates
Children use coordinates relative to their parent's position:
```python
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150))
label = mcrfpy.Caption(text="Hello", pos=(10, 10))
frame.children.append(label)
print(label.x, label.y) # 10, 10 (relative)
print(label.global_position) # (110, 110) (absolute)
```
---
## Type Preservation
When retrieving from collections, the correct Python type is preserved:
```python
scene.children.append(mcrfpy.Sprite(x=0, y=0, sprite_index=0))
obj = scene.children[0]
print(type(obj).__name__) # "Sprite" (not "UIDrawable")
```
**Implementation:** `RET_PY_INSTANCE` macro in `UIDrawable.h` handles type dispatch.
---
## Related Systems
- [[Animation-System]] - Animatable properties per type
- [[Python-Binding-Layer]] - How UI classes are exposed to Python
- [[Grid-System]] - UIGrid specifics
- [[Input-and-Events]] - Event dispatch and handling
- [[UI-Widget-Patterns]] - Buttons, dialogs, menus, HUD elements
- [[Grid-Interaction-Patterns]] - Grid clicks, entity selection
---
# UI Component Hierarchy
The UI Component Hierarchy defines how visual elements are structured, rendered, and managed in McRogueFace.
## Quick Reference
**Key Files:**
- `src/UIDrawable.h` - Base class for all UI components
- `src/UIFrame.h` / `.cpp` - Container with children
- `src/UICaption.h` / `.cpp` - Text rendering
- `src/UISprite.h` / `.cpp` - Image/sprite rendering
- `src/UIGrid.h` / `.cpp` - Tilemap grid (see [[Grid-System]])
- `src/UIEntity.h` / `.cpp` - Grid entities (see [[Entity-Management]])
- `src/UIArc.h`, `src/UICircle.h`, `src/UILine.h` - Geometry primitives
---
## Class Hierarchy
```
UIDrawable (base class)
+-- UIFrame - Rectangle container with children
+-- UICaption - Text labels
+-- UISprite - Images and sprite sheets
+-- UIGrid - Tilemap rendering
+-- UIEntity - Grid-based game entities
+-- UIArc - Arc/partial circle outline
+-- UICircle - Filled/outlined circle
+-- UILine - Line segment
```
---
## UIDrawable (Base Class)
All UI components inherit from `UIDrawable`, providing a consistent interface for positioning, visibility, hierarchy, and interaction.
### Position and Geometry
| Property | Type | Description |
|----------|------|-------------|
| `pos` | `(x, y)` | Position as tuple |
| `x`, `y` | `float` | Position components |
| `w`, `h` | `float` | Dimensions (Frame, Grid) |
| `bounds` | `(x, y, w, h)` | Bounding rectangle |
| `global_bounds` | `(x, y, w, h)` | Bounds in screen coordinates |
| `global_position` | `(x, y)` | Position in screen coordinates (accounts for parent chain) |
**Methods:**
- `move(dx, dy)` - Relative movement
- `resize(w, h)` - Change dimensions
### Hierarchy
| Property | Type | Description |
|----------|------|-------------|
| `parent` | `UIDrawable` | Parent element (read-only, set automatically) |
| `z_index` | `int` | Render order (higher = front) |
Children are positioned relative to their parent. When a child is added to a Frame's `children` collection, its `parent` property is set automatically.
### Visibility
| Property | Type | Description |
|----------|------|-------------|
| `visible` | `bool` | Show/hide element |
| `opacity` | `float` | Transparency (0.0 = invisible, 1.0 = opaque) |
### Interaction Callbacks
All UIDrawable types support mouse event callbacks:
| Property | Signature | Description |
|----------|-----------|-------------|
| `on_click` | `(pos: Vector, button: MouseButton, action: InputState) -> None` | Mouse click |
| `on_enter` | `(pos: Vector) -> None` | Mouse enters element bounds |
| `on_exit` | `(pos: Vector) -> None` | Mouse leaves element bounds |
| `on_move` | `(pos: Vector) -> None` | Mouse moves within element |
```python
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150))
def on_click(pos, button, action):
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED:
print(f"Clicked at ({pos.x}, {pos.y})")
frame.on_click = on_click
frame.on_enter = lambda pos: print("Mouse entered")
frame.on_exit = lambda pos: print("Mouse left")
frame.on_move = lambda pos: print(f"Mouse at ({pos.x}, {pos.y})")
```
### Animation
All UIDrawable types support the `.animate()` method:
```python
obj.animate("property", target_value, duration_secs, easing, callback=None)
```
See [[Animation-System]] for details on animatable properties per type.
### Utility
| Property | Type | Description |
|----------|------|-------------|
| `name` | `str` | Optional identifier for debugging/lookup |
---
## Concrete Types
### UIFrame
Rectangle container that can hold child elements. Primary building block for UI layouts.
```python
frame = mcrfpy.Frame(pos=(50, 50), size=(200, 150),
fill_color=mcrfpy.Color(40, 40, 50))
frame.outline_color = mcrfpy.Color(100, 100, 120)
frame.outline = 2
# Child elements are positioned relative to parent
label = mcrfpy.Caption(text="Title", pos=(10, 5))
frame.children.append(label)
```
**Unique properties:** `children` (UICollection), `fill_color`, `outline_color`, `outline`, `clip_children`
**Animatable:** `x`, `y`, `w`, `h`, `opacity`, `outline`, `fill_color`, `outline_color`
### UICaption
Text rendering with font support.
```python
text = mcrfpy.Caption(text="Hello World!", pos=(10, 10))
text.font_size = 24
text.fill_color = mcrfpy.Color(255, 255, 255)
```
**Unique properties:** `text`, `font`, `font_size`, `fill_color`
**Animatable:** `x`, `y`, `opacity`, `outline`, `fill_color`, `outline_color`
### UISprite
Image and sprite sheet rendering.
```python
texture = mcrfpy.Texture("assets/sprites/tileset.png", 16, 16)
sprite = mcrfpy.Sprite(x=100, y=100)
sprite.texture = texture
sprite.sprite_index = 5
```
**Unique properties:** `texture`, `sprite_index`, `scale`
**Animatable:** `x`, `y`, `scale`, `sprite_index`, `opacity`
### UIGrid
Tilemap container for roguelike game maps. See [[Grid-System]] for complete documentation.
```python
terrain = mcrfpy.TileLayer(name="terrain", z_index=-1, texture=texture)
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(100, 100), size=(400, 300),
layers=[terrain])
```
**Unique properties:** `grid_size`, `center`, `zoom`, `layers`, `entities`, `fill_color`, `perspective`
**Animatable:** `x`, `y`, `w`, `h`, `center_x`, `center_y`, `zoom`
### UIEntity
Game entities that live on grids. See [[Entity-Management]] for complete documentation.
```python
entity = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=0, name="player")
grid.entities.append(entity)
```
**Unique properties:** `grid_x`, `grid_y`, `sprite_index`, `grid` (parent reference)
**Animatable:** `x`, `y`, `draw_x`, `draw_y`, `sprite_index`, `sprite_scale`
### UIArc, UICircle, UILine
Geometry primitives for shapes and decorations.
```python
arc = mcrfpy.Arc(radius=50, start_angle=0, end_angle=90)
circle = mcrfpy.Circle(radius=30)
line = mcrfpy.Line(start=(0, 0), end=(100, 100))
```
---
## Collections
### UICollection
Container for Frame, Caption, Sprite, Grid, and geometry primitives. Used by `Frame.children` and `Scene.children`.
```python
scene = mcrfpy.Scene("test")
ui = scene.children # UICollection
ui.append(frame)
ui.extend([caption, sprite])
ui.remove(frame)
# Sequence protocol
for item in ui:
print(type(item).__name__)
obj = ui[0]
count = len(ui)
```
### UIEntityCollection
Container for Entity objects on a Grid.
```python
grid.entities.append(entity)
grid.entities.extend([e1, e2, e3])
grid.entities.remove(entity)
for e in grid.entities:
print(f"{e.name} at ({e.grid_x}, {e.grid_y})")
```
---
## Rendering
### Z-Index Order
1. Scene sorts UI elements by z_index (lower = back)
2. Elements rendered in sorted order
3. Children rendered after parents
### Parent-Child Coordinates
Children use coordinates relative to their parent's position:
```python
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150))
label = mcrfpy.Caption(text="Hello", pos=(10, 10))
frame.children.append(label)
print(label.x, label.y) # 10, 10 (relative)
print(label.global_position) # (110, 110) (absolute)
```
---
## Type Preservation
When retrieving from collections, the correct Python type is preserved:
```python
scene.children.append(mcrfpy.Sprite(x=0, y=0, sprite_index=0))
obj = scene.children[0]
print(type(obj).__name__) # "Sprite" (not "UIDrawable")
```
**Implementation:** `RET_PY_INSTANCE` macro in `UIDrawable.h` handles type dispatch.
---
## Related Systems
- [[Animation-System]] - Animatable properties per type
- [[Python-Binding-Layer]] - How UI classes are exposed to Python
- [[Grid-System]] - UIGrid specifics
- [[Input-and-Events]] - Event dispatch and handling
- [[UI-Widget-Patterns]] - Buttons, dialogs, menus, HUD elements
- [[Grid-Interaction-Patterns]] - Grid clicks, entity selection
---
*Last updated: 2026-02-07*