Widget Interface
All widgets in Fern inherit from the baseWidget class, which defines the core contract:
Widget Lifecycle
Creation
Widgets are typically created using factory functions that returnstd::shared_ptr<Widget>:
Registration
Widgets must be added to the WidgetManager to participate in rendering and input:- Widget appears in the render list
- Widget receives input events
- Widget persists until explicitly removed
Update Phase
Each frame, the WidgetManager distributes input to widgets:- Reverse iteration (top widgets first)
- First widget to return
truestops propagation - Allows proper click handling on overlapping widgets
Render Phase
Widgets render in the order they were added (bottom to top):Removal
Widgets can be removed explicitly:- Removed from WidgetManager and no other references exist
- WidgetManager is cleared
- Application shuts down
Widget Implementation Patterns
Display-Only Widgets
Widgets that only render (no interaction):Interactive Widgets
Widgets with user interaction use the signal/slot pattern:Stateful Widgets
Widgets that maintain internal state:Layout Widgets
Widgets that contain and arrange children:Widget Manager Architecture
The WidgetManager is a singleton that coordinates all widgets:Z-Order Management
Z-order (visual layering) is determined by insertion order:Widget Configuration Patterns
Many widgets use configuration structs for initialization:- Named parameters (clear intent)
- Default values (minimal configuration)
- Easy customization (override specific values)
- Forward compatibility (add new fields without breaking existing code)
Widget Communication
Signals and Slots
The primary communication mechanism:Shared State
Using static or global variables:Parent-Child Communication
Layout widgets coordinate with children:Responsive Widgets
Widgets can respond to window resize events:Performance Considerations
Rendering Performance
- Each widget’s
render()is called every frame - Avoid heavy computations in
render() - Cache calculated values when possible
- Use dirty flags for conditional rendering
Input Processing
- Input distribution is O(n) with early exit
- Proper bounds checking prevents unnecessary processing
- Return
truefromhandleInput()to stop propagation
Memory Management
- Use
std::shared_ptrfor widget ownership - Avoid circular references between widgets
- Clear widgets when transitioning scenes
- Let WidgetManager manage lifecycle
Best Practices
Widget Design
- Single Responsibility: Each widget should have one clear purpose
- Composability: Build complex widgets from simple ones
- Configurability: Use config structs for flexible initialization
- Signals for Events: Use signal/slot for external communication
Implementation Guidelines
Resource Management
See Also
- Architecture Overview - Overall system design
- Layout Engine - Layout widget details
- Event System - Signal/slot communication
- Rendering Pipeline - How widgets render to screen