GroveEngine/docs/UI_MODULE_DEMO.md
StillHammer 1b7703f07b feat(IIO)!: BREAKING CHANGE - Callback-based message dispatch
## 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>
2026-01-19 14:19:27 +07:00

12 KiB

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

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

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

// 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

// 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

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:

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:
{
  "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
}
  1. Run demo and press 'R' to reload

  2. (Optional) Handle action in demo code:

if (action == "demo:new_action") {
    eventLog.add("New action triggered!");
}

Modify Styling

Change colors, fonts, sizes in 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: