Skip to content

[Tracking] PME2: GPU Layout System - Interactive UI Framework #104

@Pluglug

Description

@Pluglug

Overview

Build a complete GPU-based UI layout system that mirrors Blender's UILayout API, enabling rich interactive panels, menus, and tooltips rendered via GPU.

This system provides:

  • Declarative API similar to bpy.types.UILayout
  • Interactive widgets (buttons, props, sliders)
  • Hit testing for mouse interaction
  • Theme integration with Blender's UI themes

Related Issues

Architecture

ui/gpu/
├── __init__.py      # Public exports
├── style.py         # GPULayoutStyle, theme integration
├── drawing.py       # GPUDrawing, BLFDrawing, IconDrawing
├── items.py         # LayoutItem, LabelItem, ButtonItem, etc.
├── layout.py        # GPULayout (main API)
├── tooltip.py       # GPUTooltip
├── interactive.py   # HitRect, HitTestManager, InteractionState
└── test_layout.py   # Test operators

Sub-issues (Phases)

Phase A: Foundation

Phase B: Interaction

Phase C: Visual Quality

Future: Widgets

  • layout.prop() implementation (slider, checkbox, enum)
  • layout.template_*() methods

Completed

  • Basic GPULayout with label(), separator(), row(), column()
  • ButtonItem with hover/press states
  • HitTestManager for mouse interaction
  • GPULayoutStyle.from_blender_theme()
  • GPUTooltip for structured tooltips
  • Region targeting - Draw only in invoking region (commit 160e33e)
  • Panel drag & close - Title bar with platform-aware close button (commit 4389902)

Design Principles

  1. UILayout-compatible API: layout.label(), layout.operator(), layout.prop()
  2. Automatic HitRect registration: Interactive items auto-register with HitTestManager
  3. Theme-aware: Colors from Blender theme, respects ui_scale
  4. Region-scoped: Draw only in the invoking region, not all regions of same type

Key Patterns Discovered

Position State Management (from #107)

When UI is rebuilt each frame, externalize mutable state to the operator:

# Store position in operator
self._panel_x = self._layout.x
self._panel_y = self._layout.y
# Use stored position on rebuild
layout = GPULayout(x=self._panel_x, y=self._panel_y, ...)

References

Notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestui/uxUser interface and experience

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions