Add "UI-Component-Hierarchy"
parent
1f06157855
commit
b8af2bd821
|
|
@ -0,0 +1,299 @@
|
||||||
|
# UI Component Hierarchy
|
||||||
|
|
||||||
|
The UI Component Hierarchy defines how visual elements are structured, rendered, and managed in McRogueFace.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
**Related Issues:**
|
||||||
|
- [#122](../../issues/122) - Parent-Child UI System (Tier 2)
|
||||||
|
- [#118](../../issues/118) - Scene as Drawable (Tier 2)
|
||||||
|
- [#102](../../issues/102) - Add global_position Property (Tier 1)
|
||||||
|
- [#10](../../issues/10) - Visibility System with AABB
|
||||||
|
|
||||||
|
**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]])
|
||||||
|
|
||||||
|
**API Reference:**
|
||||||
|
- See [mcrfpy UI Classes](../../docs/api_reference_dynamic.html) in generated API docs
|
||||||
|
|
||||||
|
## Class Hierarchy
|
||||||
|
|
||||||
|
```
|
||||||
|
UIDrawable (base class)
|
||||||
|
├── UIFrame - Rectangle container with children
|
||||||
|
├── UICaption - Text labels
|
||||||
|
├── UISprite - Images and sprite sheets
|
||||||
|
├── UIGrid - Tilemap rendering (see [[Grid-System]])
|
||||||
|
└── UIEntity - Grid-based game entities
|
||||||
|
```
|
||||||
|
|
||||||
|
**Base Class:** `src/UIDrawable.h::UIDrawable`
|
||||||
|
|
||||||
|
### UIDrawable (Base)
|
||||||
|
|
||||||
|
**Common Properties:**
|
||||||
|
- `x`, `y`, `pos` - Screen position
|
||||||
|
- `w`, `h`, `size` - Dimensions
|
||||||
|
- `visible` - Show/hide flag
|
||||||
|
- `opacity` - 0.0-1.0 transparency
|
||||||
|
- `z_index` - Render order (higher = front)
|
||||||
|
|
||||||
|
**Common Methods:**
|
||||||
|
- `move(dx, dy)` - Relative movement
|
||||||
|
- `resize(w, h)` - Resize
|
||||||
|
- `get_bounds()` - Returns (x, y, w, h)
|
||||||
|
|
||||||
|
**Lifetime:**
|
||||||
|
- All UI objects use `std::shared_ptr` for automatic memory management
|
||||||
|
- Collections (UICollection, UIEntityCollection) hold shared_ptrs
|
||||||
|
- Removal from collection doesn't destroy object if Python still references it
|
||||||
|
|
||||||
|
**Implementation:** `src/UIDrawable.h`, exposed via [[Python-Binding-Layer]]
|
||||||
|
|
||||||
|
### UIFrame
|
||||||
|
|
||||||
|
**Purpose:** Container for grouping UI elements
|
||||||
|
|
||||||
|
**Unique Properties:**
|
||||||
|
- `children` - UICollection of child drawables
|
||||||
|
- `fill_color`, `outline_color` - Rectangle colors
|
||||||
|
- `outline_thickness` - Border width
|
||||||
|
- `clip_children` - Clipping support (opt-in)
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- GUI panels and windows
|
||||||
|
- Button groups
|
||||||
|
- Layout containers
|
||||||
|
|
||||||
|
**File:** `src/UIFrame.h` / `src/UIFrame.cpp`
|
||||||
|
|
||||||
|
### UICaption
|
||||||
|
|
||||||
|
**Purpose:** Text rendering with fonts
|
||||||
|
|
||||||
|
**Unique Properties:**
|
||||||
|
- `text` - String to display
|
||||||
|
- `font` - Font object
|
||||||
|
- `font_size` - Text size
|
||||||
|
- `fill_color` - Text color
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Labels
|
||||||
|
- HUD text
|
||||||
|
- Dialogue
|
||||||
|
|
||||||
|
**File:** `src/UICaption.h` / `src/UICaption.cpp`
|
||||||
|
|
||||||
|
### UISprite
|
||||||
|
|
||||||
|
**Purpose:** Image and sprite sheet rendering
|
||||||
|
|
||||||
|
**Unique Properties:**
|
||||||
|
- `texture` - Texture object
|
||||||
|
- `sprite_index` - Index in sprite sheet
|
||||||
|
- `scale_x`, `scale_y` - Independent scaling
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Character sprites
|
||||||
|
- UI icons
|
||||||
|
- Backgrounds
|
||||||
|
|
||||||
|
**File:** `src/UISprite.h` / `src/UISprite.cpp`
|
||||||
|
|
||||||
|
### UIGrid
|
||||||
|
|
||||||
|
**Purpose:** Tilemap rendering for roguelikes
|
||||||
|
|
||||||
|
See [[Grid-System]] for complete documentation.
|
||||||
|
|
||||||
|
### UIEntity
|
||||||
|
|
||||||
|
**Purpose:** Game entities that live on grids
|
||||||
|
|
||||||
|
See [[Entity-Management]] for complete documentation.
|
||||||
|
|
||||||
|
## Collections
|
||||||
|
|
||||||
|
### UICollection
|
||||||
|
|
||||||
|
**Purpose:** Container for Frame, Caption, Sprite, Grid
|
||||||
|
|
||||||
|
**Type:** `std::vector<std::shared_ptr<UIDrawable>>`
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Python sequence protocol (indexing, slicing, iteration)
|
||||||
|
- Append, remove, extend operations
|
||||||
|
- Preserves z_index order for rendering
|
||||||
|
|
||||||
|
**File:** `src/UICollection.h` / `.cpp`
|
||||||
|
|
||||||
|
### UIEntityCollection
|
||||||
|
|
||||||
|
**Purpose:** Container specifically for Entity objects
|
||||||
|
|
||||||
|
**Type:** `std::list<std::shared_ptr<UIEntity>>`
|
||||||
|
|
||||||
|
**Why std::list?** Allows stable iteration during entity removal
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Python sequence protocol
|
||||||
|
- Entity-specific operations
|
||||||
|
|
||||||
|
**File:** `src/UIEntityCollection.h` / `.cpp`
|
||||||
|
|
||||||
|
## Rendering Pipeline
|
||||||
|
|
||||||
|
### Z-Index Rendering
|
||||||
|
|
||||||
|
**Order:**
|
||||||
|
1. Scene sorts UI elements by z_index (lower = back)
|
||||||
|
2. Elements rendered in sorted order
|
||||||
|
3. Children rendered after parents (relative to parent z_index)
|
||||||
|
|
||||||
|
**Optimization:** Dirty flag prevents re-sorting static scenes
|
||||||
|
|
||||||
|
**Implementation:** `src/Scene.cpp::render()`, issue [#63](../../issues/63) (Closed)
|
||||||
|
|
||||||
|
### Parent-Child Relationships
|
||||||
|
|
||||||
|
**Current State:** No automatic parent tracking
|
||||||
|
|
||||||
|
**Planned:** [#122](../../issues/122) - Add parent field
|
||||||
|
- Children positioned relative to parent
|
||||||
|
- Parent movement affects children
|
||||||
|
- Automatic removal from old parent when added to new
|
||||||
|
|
||||||
|
**Workaround:** Manual coordinate management
|
||||||
|
|
||||||
|
## Type Preservation
|
||||||
|
|
||||||
|
### Challenge: Shared Pointer Type Loss
|
||||||
|
|
||||||
|
When retrieving from collections, C++ shared_ptr may lose Python type info:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Adding derived type
|
||||||
|
frame.children.append(my_sprite) # my_sprite is Sprite
|
||||||
|
|
||||||
|
# Retrieving
|
||||||
|
obj = frame.children[0] # Returns as UIDrawable, not Sprite!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:** `RET_PY_INSTANCE` macro (see [[Python-Binding-Layer]])
|
||||||
|
|
||||||
|
**Issue:** [#112](../../issues/112) - Object splitting bug
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
### Creating UI Elements
|
||||||
|
|
||||||
|
```python
|
||||||
|
import mcrfpy
|
||||||
|
|
||||||
|
# Frame (container)
|
||||||
|
frame = mcrfpy.Frame(100, 100, 200, 150)
|
||||||
|
frame.fill_color = mcrfpy.Color(50, 50, 50)
|
||||||
|
|
||||||
|
# Caption (text)
|
||||||
|
label = mcrfpy.Caption((10, 10), "Hello!")
|
||||||
|
label.font_size = 24
|
||||||
|
|
||||||
|
# Sprite (image)
|
||||||
|
sprite = mcrfpy.Sprite("player.png", 50, 50)
|
||||||
|
sprite.sprite_index = 0 # If using sprite sheet
|
||||||
|
|
||||||
|
# Add to scene
|
||||||
|
mcrfpy.sceneUI("game").append(frame)
|
||||||
|
frame.children.append(label)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Animating Properties
|
||||||
|
|
||||||
|
All UIDrawable properties are animatable:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Animate position
|
||||||
|
mcrfpy.animate(sprite, "x", 300, 1000, "ease_in_out_cubic")
|
||||||
|
|
||||||
|
# Animate color
|
||||||
|
mcrfpy.animate(frame, "fill_color", mcrfpy.Color(255, 0, 0), 500, "linear")
|
||||||
|
|
||||||
|
# Animate opacity
|
||||||
|
mcrfpy.animate(label, "opacity", 0.0, 800, "ease_out_quad")
|
||||||
|
```
|
||||||
|
|
||||||
|
See [[Animation-System]] for complete animation documentation.
|
||||||
|
|
||||||
|
### Z-Index Layering
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Background
|
||||||
|
background = mcrfpy.Sprite("bg.png", 0, 0)
|
||||||
|
background.z_index = 0
|
||||||
|
|
||||||
|
# Middleground
|
||||||
|
entities_grid = mcrfpy.Grid(50, 50, 16, 16)
|
||||||
|
entities_grid.z_index = 10
|
||||||
|
|
||||||
|
# Foreground UI
|
||||||
|
hud_frame = mcrfpy.Frame(0, 0, 800, 50)
|
||||||
|
hud_frame.z_index = 100
|
||||||
|
|
||||||
|
# Add to scene (order doesn't matter, z_index controls rendering)
|
||||||
|
scene_ui = mcrfpy.sceneUI("game")
|
||||||
|
scene_ui.append(hud_frame)
|
||||||
|
scene_ui.append(background)
|
||||||
|
scene_ui.append(entities_grid)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design Decisions
|
||||||
|
|
||||||
|
**Why Shared Pointers?**
|
||||||
|
- Automatic memory management
|
||||||
|
- Python can hold references independently of C++ collections
|
||||||
|
- Safe removal from collections
|
||||||
|
|
||||||
|
**Why Vector for UICollection vs List for EntityCollection?**
|
||||||
|
- Vector: Better cache locality, random access for UI
|
||||||
|
- List: Stable iterators during removal for entities
|
||||||
|
|
||||||
|
**Why No Automatic Parent Tracking?**
|
||||||
|
- Performance: Avoids overhead for simple use cases
|
||||||
|
- Flexibility: Manual control when needed
|
||||||
|
- Planned: [#122](../../issues/122) will add optional parent tracking
|
||||||
|
|
||||||
|
## Related Systems
|
||||||
|
|
||||||
|
- [[Animation-System]] - All UIDrawable properties are animatable
|
||||||
|
- [[Python-Binding-Layer]] - How UI classes exposed to Python
|
||||||
|
- [[Grid-System]] - UIGrid specifics
|
||||||
|
- [[Performance-and-Profiling]] - Rendering performance metrics
|
||||||
|
|
||||||
|
## Planned Improvements
|
||||||
|
|
||||||
|
**[#122](../../issues/122): Parent-Child UI System**
|
||||||
|
- Add `parent` field to UIDrawable
|
||||||
|
- Automatic coordinate transformation
|
||||||
|
- Recursive visibility and opacity
|
||||||
|
|
||||||
|
**[#118](../../issues/118): Scene as Drawable**
|
||||||
|
- Make Scene inherit from UIDrawable
|
||||||
|
- Enable scene composition and transitions as animations
|
||||||
|
- Scenes become first-class UI elements
|
||||||
|
|
||||||
|
**[#102](../../issues/102): Global Position**
|
||||||
|
- Calculate absolute screen position for nested elements
|
||||||
|
- Useful for click detection, tooltips
|
||||||
|
- Depends on parent-child system
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**See Also:**
|
||||||
|
- [UIDrawable API](../../docs/api_reference_dynamic.html#UIDrawable)
|
||||||
|
- [[Python-Binding-Layer]] for implementation details
|
||||||
|
- [[Adding-Python-Bindings]] to add new UI components
|
||||||
Loading…
Reference in New Issue