## Breaking Change
IIO API redesigned from manual pull+if-forest to callback dispatch.
All modules must update their subscribe() calls to pass handlers.
### Before (OLD API)
```cpp
io->subscribe("input:mouse");
void process(...) {
while (io->hasMessages()) {
auto msg = io->pullMessage();
if (msg.topic == "input:mouse") {
handleMouse(msg);
} else if (msg.topic == "input:keyboard") {
handleKeyboard(msg);
}
}
}
```
### After (NEW API)
```cpp
io->subscribe("input:mouse", [this](const Message& msg) {
handleMouse(msg);
});
void process(...) {
while (io->hasMessages()) {
io->pullAndDispatch(); // Callbacks invoked automatically
}
}
```
## Changes
**Core API (include/grove/IIO.h)**
- Added: `using MessageHandler = std::function<void(const Message&)>`
- Changed: `subscribe()` now requires `MessageHandler` callback parameter
- Changed: `subscribeLowFreq()` now requires `MessageHandler` callback
- Removed: `pullMessage()`
- Added: `pullAndDispatch()` - pulls and auto-dispatches to handlers
**Implementation (src/IntraIO.cpp)**
- Store callbacks in `Subscription.handler`
- `pullAndDispatch()` matches topic against ALL subscriptions (not just first)
- Fixed: Regex pattern compilation supports both wildcards (*) and regex (.*)
- Performance: ~1000 msg/s throughput (unchanged from before)
**Files Updated**
- 31 test/module files migrated to callback API (via parallel agents)
- 8 documentation files updated (DEVELOPER_GUIDE, USER_GUIDE, module READMEs)
## Bugs Fixed During Migration
1. **pullAndDispatch() early return bug**: Was only calling FIRST matching handler
- Fix: Loop through ALL subscriptions, invoke all matching handlers
2. **Regex pattern compilation bug**: Pattern "player:.*" failed to match
- Fix: Detect ".*" in pattern → use as regex, otherwise escape and convert wildcards
## Testing
✅ test_11_io_system: PASSED (IIO pub/sub, pattern matching, batching)
✅ test_threaded_module_system: 6/6 PASSED
✅ test_threaded_stress: 5/5 PASSED (50 modules, 100x reload, concurrent ops)
✅ test_12_datanode: PASSED
✅ 10 TopicTree scenarios: 10/10 PASSED
✅ benchmark_e2e: ~1000 msg/s throughput
Total: 23+ tests passing
## Performance Impact
No performance regression from callback dispatch:
- IIO throughput: ~1000 msg/s (same as before)
- ThreadedModuleSystem: Speedup ~1.0x (barrier pattern expected)
## Migration Guide
For all modules using IIO:
1. Update subscribe() calls to include handler lambda
2. Replace pullMessage() loops with pullAndDispatch()
3. Move topic-specific logic from if-forest into callbacks
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
417 lines
12 KiB
Markdown
417 lines
12 KiB
Markdown
# UIModule Interactive Showcase Demo
|
|
|
|
**Date**: 2025-11-29
|
|
**Status**: ✅ **COMPLETE**
|
|
|
|
## Overview
|
|
|
|
The UIModule Interactive Showcase Demo is a **complete, interactive application** that demonstrates **all features** of the UIModule in a real window with live user interaction.
|
|
|
|
This is **NOT a test** - it's a **real application** showing how to use UIModule in production.
|
|
|
|
## What It Demonstrates
|
|
|
|
### All Widgets (9 types)
|
|
- ✅ **Buttons** - 4 colors (Primary, Success, Warning, Danger)
|
|
- ✅ **Sliders** - Volume, Brightness, Difficulty
|
|
- ✅ **TextInput** - Username, Search fields with placeholders
|
|
- ✅ **Checkboxes** - Fullscreen, VSync, Shadows, Particles
|
|
- ✅ **Progress Bars** - Health, Loading, Experience
|
|
- ✅ **Labels** - Headers, descriptions, info text
|
|
- ✅ **Panels** - Sidebar, content panels with backgrounds
|
|
- ✅ **ScrollPanel** - Main scrollable content + nested scroll
|
|
- ✅ **Tooltips** - All widgets have hover tooltips
|
|
|
|
### Features
|
|
- ✅ **Live event console** - See all UI events in real-time
|
|
- ✅ **Event statistics** - Counts clicks, actions, value changes, hovers
|
|
- ✅ **Hot-reload** - Press 'R' to reload UI from JSON
|
|
- ✅ **Mouse interaction** - Click, hover, drag, wheel
|
|
- ✅ **Keyboard input** - Text fields, shortcuts
|
|
- ✅ **Layouts** - Vertical, horizontal, nested
|
|
- ✅ **Styling** - Colors, fonts, borders, padding
|
|
- ✅ **Tooltips** - Smart positioning with edge avoidance
|
|
|
|
## Files
|
|
|
|
```
|
|
tests/demo/
|
|
└── demo_ui_showcase.cpp # Main demo application (370 lines)
|
|
|
|
assets/ui/
|
|
└── demo_showcase.json # Full UI layout (1100+ lines)
|
|
```
|
|
|
|
## Building
|
|
|
|
### Prerequisites
|
|
- SDL2 installed
|
|
- BgfxRenderer module built
|
|
- UIModule built
|
|
- X11 (Linux) or native Windows environment
|
|
|
|
### Build Commands
|
|
|
|
```bash
|
|
cd /path/to/GroveEngine
|
|
|
|
# Configure with UI and renderer enabled
|
|
cmake -DGROVE_BUILD_UI_MODULE=ON -DGROVE_BUILD_BGFX_RENDERER=ON -B build-bgfx
|
|
|
|
# Build the demo
|
|
cmake --build build-bgfx --target demo_ui_showcase -j4
|
|
```
|
|
|
|
## Running
|
|
|
|
```bash
|
|
cd build-bgfx/tests
|
|
./demo_ui_showcase
|
|
```
|
|
|
|
### Controls
|
|
|
|
| Key | Action |
|
|
|-----|--------|
|
|
| **Mouse** | Click, hover, drag widgets |
|
|
| **Mouse Wheel** | Scroll panels |
|
|
| **Keyboard** | Type in text fields |
|
|
| **ESC** | Quit demo |
|
|
| **R** | Hot-reload UI from JSON |
|
|
|
|
### Expected Output
|
|
|
|
```
|
|
========================================
|
|
UIModule Interactive Showcase Demo
|
|
========================================
|
|
|
|
Controls:
|
|
- Mouse: Click, hover, drag widgets
|
|
- Keyboard: Type in text fields
|
|
- Mouse wheel: Scroll panels
|
|
- ESC: Quit
|
|
- R: Reload UI from JSON
|
|
|
|
[0.0] Demo starting...
|
|
[0.02] SDL window created
|
|
[0.10] BgfxRenderer loaded
|
|
[0.12] Renderer configured
|
|
[0.15] UIModule loaded
|
|
[0.18] UIModule configured
|
|
[0.18] Ready! Interact with widgets below.
|
|
✅ Renderer healthy
|
|
```
|
|
|
|
Then a **1200x800 window** opens with:
|
|
- **Left sidebar** (250px) - Controls and info
|
|
- **Main content** (950px) - Scrollable showcase of all widgets
|
|
|
|
### Interacting
|
|
|
|
1. **Hover** over any widget → Tooltip appears after 500ms
|
|
2. **Click buttons** → Event logged in console
|
|
3. **Drag sliders** → Value changes logged
|
|
4. **Type in text fields** → Text changes logged
|
|
5. **Check checkboxes** → State changes logged
|
|
6. **Scroll** with mouse wheel → Smooth scrolling
|
|
7. **Click "Clear Log"** → Clears event console
|
|
8. **Click "Reset Stats"** → Resets all counters
|
|
9. **Press 'R'** → Reloads UI from JSON (hot-reload)
|
|
|
|
## Architecture
|
|
|
|
### Module Stack
|
|
|
|
```
|
|
┌─────────────────────┐
|
|
│ demo_ui_showcase │ SDL2 event loop
|
|
│ (main app) │ Input forwarding
|
|
└──────────┬──────────┘
|
|
│ IIO pub/sub
|
|
┌──────┴──────┬─────────┐
|
|
│ │ │
|
|
┌───▼────┐ ┌───▼────┐ ┌▼─────────┐
|
|
│BgfxRend│ │UIModule│ │ Event │
|
|
│erer │ │ │ │ Console │
|
|
└────────┘ └────────┘ └──────────┘
|
|
```
|
|
|
|
### Event Flow
|
|
|
|
```
|
|
User Input (SDL)
|
|
↓
|
|
Input Events (IIO topics)
|
|
input:mouse:move
|
|
input:mouse:button
|
|
input:mouse:wheel
|
|
input:key:press
|
|
input:text
|
|
↓
|
|
UIModule (processes events)
|
|
↓
|
|
UI Events (IIO topics)
|
|
ui:click
|
|
ui:action
|
|
ui:value_changed
|
|
ui:text_changed
|
|
ui:text_submit
|
|
ui:hover
|
|
ui:focus_gained
|
|
ui:focus_lost
|
|
↓
|
|
Demo App (logs events)
|
|
```
|
|
|
|
### Hot-Reload Flow
|
|
|
|
1. Press 'R' key
|
|
2. Demo calls `uiModule->setConfiguration(uiConfig, ...)`
|
|
3. UIModule reloads `demo_showcase.json`
|
|
4. UI updates **without restarting app**
|
|
5. Event log shows "🔄 Reloading UI from JSON..."
|
|
|
|
## Layout Structure
|
|
|
|
The `demo_showcase.json` layout is organized as:
|
|
|
|
```
|
|
root (horizontal layout)
|
|
├── sidebar (250px)
|
|
│ ├── Title + Info
|
|
│ ├── Controls panel
|
|
│ ├── Features checklist
|
|
│ ├── Clear Log button
|
|
│ └── Reset Stats button
|
|
│
|
|
└── main_content (950px, scrollable)
|
|
├── Welcome header
|
|
├── Buttons panel (4 buttons)
|
|
├── Sliders panel (3 sliders)
|
|
├── Text Input panel (2 text fields)
|
|
├── Checkboxes panel (4 checkboxes)
|
|
├── Progress Bars panel (3 bars)
|
|
├── Nested ScrollPanel (20 items)
|
|
└── End message
|
|
```
|
|
|
|
## Code Highlights
|
|
|
|
### SDL Event Forwarding
|
|
|
|
```cpp
|
|
// Mouse move
|
|
auto mouseMove = std::make_unique<JsonDataNode>("mouse_move");
|
|
mouseMove->setDouble("x", static_cast<double>(event.motion.x));
|
|
mouseMove->setDouble("y", static_cast<double>(event.motion.y));
|
|
uiIO->publish("input:mouse:move", std::move(mouseMove));
|
|
|
|
// Mouse wheel
|
|
auto mouseWheel = std::make_unique<JsonDataNode>("mouse_wheel");
|
|
mouseWheel->setDouble("delta", static_cast<double>(event.wheel.y));
|
|
uiIO->publish("input:mouse:wheel", std::move(mouseWheel));
|
|
|
|
// Text input
|
|
auto textInput = std::make_unique<JsonDataNode>("text_input");
|
|
textInput->setString("text", event.text.text);
|
|
uiIO->publish("input:text", std::move(textInput));
|
|
```
|
|
|
|
### Event Logging
|
|
|
|
```cpp
|
|
// Subscribe to UI events with callbacks (during setup)
|
|
uiIO->subscribe("ui:click", [&clickCount, &eventLog](const grove::Message& msg) {
|
|
clickCount++;
|
|
std::string widgetId = msg.data->getString("widgetId", "");
|
|
eventLog.add("🖱️ Click: " + widgetId);
|
|
});
|
|
|
|
uiIO->subscribe("ui:action", [&actionCount, &eventLog](const grove::Message& msg) {
|
|
actionCount++;
|
|
std::string action = msg.data->getString("action", "");
|
|
eventLog.add("⚡ Action: " + action);
|
|
});
|
|
|
|
// In main loop - pull and dispatch to callbacks
|
|
while (uiIO->hasMessages() > 0) {
|
|
uiIO->pullAndDispatch(); // Callbacks invoked automatically
|
|
}
|
|
```
|
|
|
|
### Hot-Reload Implementation
|
|
|
|
```cpp
|
|
if (event.key.keysym.sym == SDLK_r) {
|
|
eventLog.add("🔄 Reloading UI from JSON...");
|
|
uiModule->setConfiguration(uiConfig, uiIO.get(), nullptr);
|
|
eventLog.add("✅ UI reloaded!");
|
|
}
|
|
```
|
|
|
|
## Known Limitations
|
|
|
|
### WSL / Headless Environments
|
|
- ⚠️ **Requires graphical environment** (X11, Wayland, or Windows native)
|
|
- ⚠️ **WSL without X server**: Renderer fails to initialize
|
|
- Demo runs in "UI-only mode" (no visual output)
|
|
- Events still processed correctly
|
|
- Safe fallback with health checks
|
|
|
|
### Renderer Health Check
|
|
The demo checks renderer health and gracefully handles failures:
|
|
|
|
```cpp
|
|
auto rendererHealth = renderer->getHealthStatus();
|
|
bool rendererOK = rendererHealth &&
|
|
rendererHealth->getString("status", "") == "healthy";
|
|
|
|
if (!rendererOK) {
|
|
std::cout << "⚠️ Renderer not healthy, running in UI-only mode\n";
|
|
}
|
|
|
|
// In main loop
|
|
if (rendererOK) {
|
|
renderer->process(frameInput);
|
|
}
|
|
```
|
|
|
|
This prevents segfaults when running in environments without GPU/display.
|
|
|
|
## Performance
|
|
|
|
- **60 FPS** target (16ms frame time)
|
|
- **Main loop**: ~0.2ms per frame (UI + event processing)
|
|
- **Renderer**: ~5ms per frame (when active)
|
|
- **Total**: ~5-6ms per frame = **~165 FPS capable**
|
|
|
|
Bottleneck is SDL_Delay(16) to cap at 60 FPS.
|
|
|
|
## Use Cases
|
|
|
|
### 1. Learning UIModule
|
|
- See all widgets in action
|
|
- Understand event flow
|
|
- Learn JSON layout syntax
|
|
- Try hot-reload
|
|
|
|
### 2. Testing New Features
|
|
- Add new widgets to `demo_showcase.json`
|
|
- Press 'R' to reload without restarting
|
|
- See changes immediately
|
|
|
|
### 3. Visual Regression Testing
|
|
- Run demo after changes
|
|
- Verify all widgets still work
|
|
- Check tooltips, hover states, interactions
|
|
|
|
### 4. Integration Example
|
|
- Shows proper BgfxRenderer + UIModule integration
|
|
- SDL2 event forwarding patterns
|
|
- IIO pub/sub communication
|
|
- Module lifecycle management
|
|
|
|
### 5. Showcase / Portfolio
|
|
- Demonstrates GroveEngine capabilities
|
|
- Shows hot-reload system
|
|
- Production-quality UI
|
|
|
|
## Extending the Demo
|
|
|
|
### Add a New Widget
|
|
|
|
1. Edit `assets/ui/demo_showcase.json`:
|
|
```json
|
|
{
|
|
"type": "button",
|
|
"id": "my_new_button",
|
|
"text": "New Feature",
|
|
"tooltip": "This is a new button I added",
|
|
"onClick": "demo:new_action",
|
|
"width": 150,
|
|
"height": 40
|
|
}
|
|
```
|
|
|
|
2. Run demo and press 'R' to reload
|
|
|
|
3. (Optional) Handle action in demo code:
|
|
```cpp
|
|
if (action == "demo:new_action") {
|
|
eventLog.add("New action triggered!");
|
|
}
|
|
```
|
|
|
|
### Modify Styling
|
|
|
|
Change colors, fonts, sizes in JSON:
|
|
```json
|
|
"style": {
|
|
"fontSize": 20.0,
|
|
"normal": {
|
|
"bgColor": "0xFF5722FF", // Material Orange
|
|
"textColor": "0xFFFFFFFF"
|
|
}
|
|
}
|
|
```
|
|
|
|
Press 'R' to see changes instantly.
|
|
|
|
## Troubleshooting
|
|
|
|
### Window doesn't appear
|
|
- **WSL**: Install X server (VcXsrv, Xming) and set DISPLAY
|
|
- **Linux**: Ensure X11 is running
|
|
- **Windows**: Should work natively
|
|
|
|
### Renderer fails to initialize
|
|
- Expected in WSL/headless environments
|
|
- Demo runs in UI-only mode (events work, no visual)
|
|
- To fix: Use native display or X server
|
|
|
|
### No events logged
|
|
- Check that widgets have `onClick`, `onChange`, etc.
|
|
- Verify IIO subscriptions
|
|
- Look for errors in console output
|
|
|
|
### Hot-reload doesn't work
|
|
- Ensure JSON file path is correct
|
|
- Check JSON syntax (use validator)
|
|
- Look for parsing errors in log
|
|
|
|
## Conclusion
|
|
|
|
The UIModule Interactive Showcase Demo is a **complete, production-quality application** that:
|
|
|
|
- ✅ Shows **all UIModule features** in one place
|
|
- ✅ Provides **live interaction** and **real-time feedback**
|
|
- ✅ Demonstrates **hot-reload** capability
|
|
- ✅ Serves as **integration example** for new projects
|
|
- ✅ Works as **visual test** for regression checking
|
|
- ✅ Handles **failures gracefully** (renderer health checks)
|
|
|
|
**Perfect starting point** for anyone building UIs with GroveEngine! 🚀
|
|
|
|
## Summary Table
|
|
|
|
| Feature | Status | Description |
|
|
|---------|--------|-------------|
|
|
| All 9 widgets | ✅ | Complete showcase |
|
|
| Tooltips | ✅ | Every widget has one |
|
|
| Scrolling | ✅ | Main + nested panels |
|
|
| Hot-reload | ✅ | Press 'R' to reload |
|
|
| Event console | ✅ | Live event logging |
|
|
| Stats tracking | ✅ | Click/action counters |
|
|
| Keyboard input | ✅ | Text fields work |
|
|
| Mouse interaction | ✅ | All input types |
|
|
| Graceful degradation | ✅ | Handles renderer failure |
|
|
| Documentation | ✅ | This file |
|
|
|
|
---
|
|
|
|
**Related Documentation**:
|
|
- [UIModule Phase 7 Complete](./UI_MODULE_PHASE7_COMPLETE.md)
|
|
- [UIModule Architecture](./UI_MODULE_ARCHITECTURE.md)
|
|
- [Integration Tests](../tests/integration/README.md)
|