GroveEngine/docs/UI_WIDGETS.md
StillHammer 0441a9d648 feat: UIModule - Dynamic text updates, documentation restructure, and IIO improvements
UIModule Enhancements:
- Add ui:set_text topic handler to update widget text dynamically (UILabel support)
- Add example: slider value updates linked label via game module coordination
- Add timestamp logging for IIO latency measurement (T0-T3 tracking)

Documentation Restructure:
- Split UIModule README.md (600+ lines) into focused docs:
  * docs/UI_WIDGETS.md - Widget properties and JSON configuration
  * docs/UI_TOPICS.md - IIO topics reference and usage patterns
  * docs/UI_ARCHITECTURE.md - Threading model, limitations, design principles
- Update CLAUDE.md with clear references to UIModule docs
- Add warning: "READ BEFORE WORKING ON UI" for essential docs

Asset Path Fixes:
- Change test_ui_showcase texture paths from ../../assets to assets/
- Tests now run from project root (./build/tests/test_ui_showcase)
- Add texture loading success/failure logs to TextureLoader and ResourceCache

IIO Performance:
- Re-enable batch flush thread in IntraIOManager (was disabled for debugging)
- Document message latency: ~16ms in single-threaded tests, <1ms with threading
- Clarify intentional architecture: no direct data binding, all via IIO topics

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 22:34:36 +07:00

6.9 KiB

UIModule - Widget Reference

Complete reference for all available widgets and their properties.

Widget Overview

Widget Purpose Events
UIButton Clickable button ui:click, ui:action
UILabel Static/dynamic text -
UIPanel Container widget -
UICheckbox Toggle checkbox ui:value_changed
UISlider Value slider ui:value_changed
UITextInput Text entry field ui:value_changed, ui:text_submitted
UIProgressBar Progress indicator -
UIImage Sprite/texture display -
UIScrollPanel Scrollable container ui:scroll
UITooltip Hover tooltip -

Common Properties

All widgets support these base properties:

{
  "type": "WidgetType",
  "id": "unique_id",
  "x": 0,
  "y": 0,
  "width": 100,
  "height": 100,
  "visible": true,
  "tooltip": "Optional tooltip text"
}

UIButton

Clickable button with hover/press states.

{
  "type": "button",
  "id": "my_button",
  "x": 100,
  "y": 100,
  "width": 200,
  "height": 50,
  "text": "Click Me",
  "onClick": "button_action",
  "style": {
    "normal": {
      "bgColor": "0x0984e3FF",
      "textColor": "0xFFFFFFFF",
      "textureId": 0
    },
    "hover": {
      "bgColor": "0x74b9ffFF",
      "textColor": "0xFFFFFFFF"
    },
    "pressed": {
      "bgColor": "0x0652a1FF",
      "textColor": "0xFFFFFFFF"
    }
  }
}

Properties:

  • text - Button label text
  • onClick - Action name published to ui:action
  • style - Visual states (normal, hover, pressed)
    • bgColor - Background color (hex RGBA)
    • textColor - Text color (hex RGBA)
    • textureId - Sprite texture ID (0 = solid color)

Events:

  • ui:click - {widgetId, x, y}
  • ui:action - {widgetId, action} where action = onClick value

UILabel

Static or dynamic text display.

{
  "type": "label",
  "id": "my_label",
  "x": 100,
  "y": 100,
  "width": 300,
  "height": 50,
  "text": "Hello World",
  "style": {
    "fontSize": 24,
    "color": "0xFFFFFFFF"
  }
}

Properties:

  • text - Label text (can be updated via ui:set_text)
  • style.fontSize - Font size in pixels
  • style.color - Text color (hex RGBA)

Dynamic Updates:

auto msg = std::make_unique<JsonDataNode>("set_text");
msg->setString("id", "my_label");
msg->setString("text", "New Text");
m_io->publish("ui:set_text", std::move(msg));

UIPanel

Container widget with background color.

{
  "type": "panel",
  "id": "my_panel",
  "x": 0,
  "y": 0,
  "width": 400,
  "height": 300,
  "style": {
    "bgColor": "0x2d3436FF"
  }
}

Properties:

  • style.bgColor - Background color (hex RGBA, use 0x00000000 for transparent)

UICheckbox

Toggle checkbox with check state.

{
  "type": "checkbox",
  "id": "enable_vsync",
  "x": 100,
  "y": 100,
  "width": 24,
  "height": 24,
  "checked": true,
  "text": "Enable VSync"
}

Properties:

  • checked - Initial checked state
  • text - Optional label text next to checkbox

Events:

  • ui:value_changed - {widgetId, checked}

UISlider

Horizontal or vertical value slider.

{
  "type": "slider",
  "id": "volume_slider",
  "x": 100,
  "y": 100,
  "width": 300,
  "height": 24,
  "min": 0.0,
  "max": 100.0,
  "value": 50.0,
  "orientation": "horizontal"
}

Properties:

  • min - Minimum value
  • max - Maximum value
  • value - Current value
  • orientation - "horizontal" or "vertical"

Events:

  • ui:value_changed - {widgetId, value, min, max}

UITextInput

Text entry field with cursor and focus state.

{
  "type": "textinput",
  "id": "player_name",
  "x": 100,
  "y": 100,
  "width": 300,
  "height": 40,
  "text": "",
  "placeholder": "Enter name...",
  "maxLength": 32,
  "style": {
    "fontSize": 20,
    "textColor": "0xFFFFFFFF",
    "bgColor": "0x34495eFF",
    "borderColor": "0x666666FF"
  }
}

Properties:

  • text - Initial text
  • placeholder - Placeholder text when empty
  • maxLength - Maximum character limit
  • style.fontSize - Font size
  • style.textColor - Text color
  • style.bgColor - Background color
  • style.borderColor - Border color (changes to blue when focused)

Events:

  • ui:value_changed - {widgetId, text} - on each character change
  • ui:text_submitted - {widgetId, text} - on Enter key

UIProgressBar

Progress indicator (0.0 to 1.0).

{
  "type": "progressbar",
  "id": "loading_bar",
  "x": 100,
  "y": 100,
  "width": 400,
  "height": 30,
  "value": 0.65,
  "style": {
    "bgColor": "0x34495eFF",
    "fillColor": "0x2ecc71FF"
  }
}

Properties:

  • value - Progress value (0.0 = empty, 1.0 = full)
  • style.bgColor - Background color
  • style.fillColor - Fill color

Dynamic Updates:

auto msg = std::make_unique<JsonDataNode>("set_value");
msg->setString("id", "loading_bar");
msg->setDouble("value", 0.75);  // 75%
m_io->publish("ui:set_value", std::move(msg));

UIImage

Display a sprite/texture.

{
  "type": "image",
  "id": "logo",
  "x": 100,
  "y": 100,
  "width": 200,
  "height": 200,
  "textureId": 5
}

Properties:

  • textureId - Texture ID from BgfxRenderer

UIScrollPanel

Scrollable container with vertical scrollbar.

{
  "type": "scrollpanel",
  "id": "inventory_panel",
  "x": 100,
  "y": 100,
  "width": 400,
  "height": 600,
  "contentHeight": 1200,
  "scrollY": 0.0,
  "scrollbarWidth": 20,
  "style": {
    "bgColor": "0x2d3436FF"
  }
}

Properties:

  • contentHeight - Total height of scrollable content
  • scrollY - Initial scroll position (0.0 = top)
  • scrollbarWidth - Width of scrollbar in pixels
  • style.bgColor - Background color

Events:

  • ui:scroll - {widgetId, scrollY}

UITooltip

Hover tooltip (managed automatically by UIModule).

{
  "type": "tooltip",
  "id": "help_tooltip",
  "x": 100,
  "y": 100,
  "width": 200,
  "height": 60,
  "text": "This is a helpful tooltip",
  "visible": false,
  "style": {
    "fontSize": 14,
    "bgColor": "0x2c3e50FF",
    "textColor": "0xFFFFFFFF"
  }
}

Note: Tooltips are automatically shown when tooltip property is set on any widget:

{
  "type": "button",
  "id": "save_button",
  "tooltip": "Save your progress",
  ...
}

Creating Custom Widgets

  1. Create Widgets/MyWidget.h/.cpp
  2. Inherit from UIWidget
  3. Implement required methods:
class MyWidget : public UIWidget {
public:
    void update(UIContext& ctx, float deltaTime) override;
    void render(UIRenderer& renderer) override;
    std::string getType() const override { return "mywidget"; }

    // Event handlers
    bool onMouseButton(int button, bool pressed, float x, float y) override;
    void onMouseMove(float x, float y) override;
};
  1. Register in UITree::createWidget():
if (type == "mywidget") {
    auto widget = std::make_unique<MyWidget>();
    // ... configure from JSON
    return widget;
}
  1. Use in JSON layouts:
{
  "type": "mywidget",
  "id": "custom1",
  ...
}