Update UI Component Hierarchy
parent
be82d944ca
commit
b5d39573c6
1 changed files with 283 additions and 283 deletions
|
|
@ -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*
|
||||
Loading…
Add table
Add a link
Reference in a new issue