Files
yaze/docs/internal/architecture/ui_layout_system.md

177 lines
7.6 KiB
Markdown

# YAZE UI Layout Documentation
This document describes the layout logic for the YAZE editor interface, specifically focusing on the menu bar and sidebar interactions.
## Menu Bar Layout
The main menu bar in `UICoordinator::DrawMenuBarExtras` handles the right-aligned status cluster.
### Right-Aligned Status Cluster
The status cluster in `DrawMenuBarExtras` includes (in order from left to right):
1. **Version**: `vX.Y.Z` (May be hidden on narrow windows)
2. **Dirty Indicator**: Warning-colored dot (Visible when ROM has unsaved changes)
3. **Session Switcher**: Layers icon (Visible when multiple sessions are open, may be hidden on narrow windows)
4. **Notification Bell**: Bell icon (Always visible - high priority)
### Panel Toggle Buttons
Panel toggle buttons are drawn at the end of the menu bar using screen coordinates:
1. **Panel Toggles**: Icons for Agent, Proposals, Settings, Properties
2. **WASM Toggle**: Chevron icon (Visible only in Emscripten builds)
These are positioned using `ImGui::SetCursorScreenPos()` with coordinates calculated from the true viewport (not the dockspace window). This ensures they remain in a fixed position even when panels open/close and the dockspace resizes.
### Button Styling
All menu bar icon buttons use consistent styling via `DrawMenuBarIconButton()`:
- Transparent background
- `SurfaceContainerHigh` color on hover
- `SurfaceContainerHighest` color when active/pressed
- `TextSecondary` color for inactive icons
- `Primary` color for active icons (e.g., when a panel is open)
### Sizing Calculation
The `cluster_width` is calculated dynamically using `GetMenuBarIconButtonWidth()` which accounts for:
- Icon text width (using `ImGui::CalcTextSize`)
- Frame padding (`FramePadding.x * 2`)
- Item spacing between elements (6px)
The number of panel toggle buttons is determined at compile time:
- With `YAZE_WITH_GRPC`: 4 buttons (Agent, Proposals, Settings, Properties)
- Without `YAZE_WITH_GRPC`: 3 buttons (Proposals, Settings, Properties)
### Responsive Behavior
When the window is too narrow to display all elements, they are hidden progressively based on priority:
1. **Always shown**: Notification bell, WASM toggle, dirty indicator
2. **High priority**: Version text
3. **Medium priority**: Session switcher button
4. **Low priority**: Panel toggle buttons
The available width is calculated as:
```cpp
float available_width = menu_bar_end - menu_items_end - padding;
```
### Right Panel Interaction
When the Right Panel (Agent, Settings, etc.) is expanded, it occupies the right side of the viewport.
The menubar uses **screen coordinate positioning** for optimal UX:
1. **Fixed Panel Toggles**: Panel toggle buttons are positioned using `ImGui::SetCursorScreenPos()` with coordinates calculated from the true viewport. This keeps them at a fixed screen position regardless of dockspace resizing.
2. **Status Cluster**: Version, dirty indicator, session button, and notification bell are drawn inside the dockspace menu bar using relative positioning. They shift naturally when panels open/close as the dockspace resizes.
```cpp
// Panel toggle screen positioning (in DrawMenuBarExtras)
const ImGuiViewport* viewport = ImGui::GetMainViewport();
float panel_screen_x = viewport->WorkPos.x + viewport->WorkSize.x - panel_region_width;
if (panel_manager->IsPanelExpanded()) {
panel_screen_x -= panel_manager->GetPanelWidth();
}
ImGui::SetCursorScreenPos(ImVec2(panel_screen_x, menu_bar_y));
```
This ensures users can quickly toggle panels without chasing moving buttons.
## Menu Bar Positioning Patterns
When adding or modifying menu bar elements, choose the appropriate positioning strategy:
### Pattern 1: Relative Positioning (Elements That Shift)
Use standard `ImGui::SameLine()` with window-relative coordinates for elements that should move naturally when the dockspace resizes:
```cpp
const float window_width = ImGui::GetWindowWidth();
float start_pos = window_width - element_width - padding;
ImGui::SameLine(start_pos);
ImGui::Text("Shifting Element");
```
**Use for:** Version text, dirty indicator, session button, notification bell
**Behavior:** These elements shift left when a panel opens (dockspace shrinks)
### Pattern 2: Screen Positioning (Elements That Stay Fixed)
Use `ImGui::SetCursorScreenPos()` with true viewport coordinates for elements that should remain at a fixed screen position:
```cpp
// Get TRUE viewport dimensions (not affected by dockspace resize)
const ImGuiViewport* viewport = ImGui::GetMainViewport();
float screen_x = viewport->WorkPos.x + viewport->WorkSize.x - element_width;
// Adjust for any open panels
if (panel_manager->IsPanelExpanded()) {
screen_x -= panel_manager->GetPanelWidth();
}
// Keep Y from current menu bar context
float screen_y = ImGui::GetCursorScreenPos().y;
// Position and draw
ImGui::SetCursorScreenPos(ImVec2(screen_x, screen_y));
ImGui::Button("Fixed Element");
```
**Use for:** Panel toggle buttons, any UI that should stay accessible when panels open
**Behavior:** These elements stay at a fixed screen position regardless of dockspace size
### Key Coordinate Functions
| Function | Returns | Use Case |
|----------|---------|----------|
| `ImGui::GetWindowWidth()` | Dockspace window width | Relative positioning within menu bar |
| `ImGui::GetMainViewport()->WorkSize.x` | True viewport width | Fixed screen positioning |
| `ImGui::GetWindowPos()` | Window screen position | Converting between coordinate systems |
| `ImGui::GetCursorScreenPos()` | Current cursor screen position | Getting Y coordinate for screen positioning |
| `ImGui::SetCursorScreenPos()` | N/A (sets position) | Positioning at absolute screen coordinates |
### Common Pitfall
Do NOT use `ImGui::GetWindowWidth()` when calculating fixed positions. The window width changes when panels open/close, causing elements to shift. Always use `ImGui::GetMainViewport()` for fixed positioning.
## Right Panel Styling
### Panel Header
The panel header uses an elevated background (`SurfaceContainerHigh`) with:
- Icon in primary color
- Title in standard text color
- Large close button (28x28) with rounded corners
- Keyboard shortcut: **Escape** closes the panel
### Panel Content Styling
Content uses consistent styling helpers:
- `BeginPanelSection()` / `EndPanelSection()`: Collapsible sections with icons
- `DrawPanelDivider()`: Themed separators
- `DrawPanelLabel()`: Secondary text color labels
- `DrawPanelValue()`: Label + value pairs
- `DrawPanelDescription()`: Wrapped disabled text for descriptions
### Color Scheme
- **Backgrounds**: `SurfaceContainer` for panel, `SurfaceContainerHigh` for sections
- **Borders**: `Outline` color
- **Text**: Primary for titles, Secondary for labels, Disabled for descriptions
- **Accents**: Primary color for icons and active states
## Sidebar Layout
The left sidebar (`EditorCardRegistry`) provides navigation for editor cards.
### Placeholder Sidebar
When no ROM is loaded, `EditorManager::DrawPlaceholderSidebar` renders a placeholder.
- **Theme**: Uses `Surface Container` color for background to distinguish it from the main window.
- **Content**: Displays "Open ROM" and "New Project" buttons.
- **Behavior**: Fills the full height of the viewport work area (below the dockspace menu bar).
### Active Sidebar
When a ROM is loaded, the sidebar displays editor categories and cards.
- **Width**: Fixed width defined in `EditorCardRegistry`.
- **Collapse**: Can be collapsed via the hamburger menu in the menu bar or `Ctrl+B`.
- **Theme**: Matches the placeholder sidebar for consistency.
## Theme Integration
The UI uses `ThemeManager` for consistent colors:
- **Sidebar Background**: `gui::GetSurfaceContainerVec4()`
- **Sidebar Border**: `gui::GetOutlineVec4()`
- **Text**: `gui::GetTextSecondaryVec4()` (for placeholders)