backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)

This commit is contained in:
scawful
2025-12-22 00:20:49 +00:00
parent 2934c82b75
commit 5c4cd57ff8
1259 changed files with 239160 additions and 43801 deletions

View File

@@ -0,0 +1,532 @@
# Editor Panel (Card) and Layout System Architecture
> Migration note: Phase 2 renames Card → Panel (`PanelWindow`, `PanelManager`,
> `PanelDescriptor`). The concepts below still use legacy Card naming; apply the
> new Panel terms when implementing changes.
This document describes the yaze editor's card-based UI system, layout management, and how they integrate with the agent system.
## Overview
The yaze editor uses a modular card-based architecture inspired by VSCode's workspace model:
- **Cards** = Dockable ImGui windows representing editor components
- **Categories** = Logical groupings (Dungeon, Overworld, Graphics, etc.)
- **Layouts** = DockBuilder configurations defining window arrangements
- **Presets** = Named visibility configurations for quick switching
## System Components
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ EditorManager │
│ (Central coordinator - owns all components below) │
├──────────────────────┬───────────────────────┬──────────────────────────────┤
│ EditorCardRegistry │ LayoutManager │ UICoordinator │
│ ───────────────── │ ───────────── │ ───────────── │
│ • Card metadata │ • DockBuilder │ • UI state flags │
│ • Visibility mgmt │ • Default layouts │ • Menu drawing │
│ • Session prefixes │ • Window arrange │ • Popup coordination │
│ • Workspace presets│ • Per-editor setup │ • Command palette │
├──────────────────────┴───────────────────────┴──────────────────────────────┤
│ LayoutPresets │
│ (Static definitions - default cards per editor type) │
└─────────────────────────────────────────────────────────────────────────────┘
```
## Component Relationships
```
┌──────────────────┐
│ EditorManager │
│ (coordinator) │
└────────┬─────────┘
│ owns
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌──────────────┐ ┌───────────────┐
│EditorCardRegistry│ │LayoutManager │ │ UICoordinator │
└────────┬────────┘ └───────┬──────┘ └───────┬───────┘
│ │ │
│ queries │ uses │ delegates
▼ ▼ ▼
┌─────────────────┐ ┌──────────────┐ ┌───────────────┐
│ LayoutPresets │ │ EditorCard │ │ EditorCard │
│ (card defaults)│ │ Registry │ │ Registry │
└─────────────────┘ │ (window │ │ (emulator │
│ titles) │ │ visibility) │
└──────────────┘ └───────────────┘
```
---
## EditorCardRegistry
**File:** `src/app/editor/system/editor_card_registry.h`
### CardInfo Structure
Every card is registered with complete metadata:
```cpp
struct CardInfo {
std::string card_id; // "dungeon.room_selector"
std::string display_name; // "Room Selector"
std::string window_title; // " Rooms List" (matches ImGui::Begin)
std::string icon; // ICON_MD_LIST
std::string category; // "Dungeon"
std::string shortcut_hint; // "Ctrl+Shift+R"
bool* visibility_flag; // &show_room_selector_
EditorCard* card_instance; // Optional card pointer
std::function<void()> on_show; // Callback when shown
std::function<void()> on_hide; // Callback when hidden
int priority; // Menu ordering (lower = higher)
// Disabled state support
std::function<bool()> enabled_condition; // ROM-dependent cards
std::string disabled_tooltip; // "Load a ROM first"
};
```
### Card Categories
| Category | Icon | Purpose |
|-------------|---------------------------|------------------------------|
| Dungeon | `ICON_MD_CASTLE` | Dungeon room editing |
| Overworld | `ICON_MD_MAP` | Overworld map editing |
| Graphics | `ICON_MD_IMAGE` | Graphics/tile sheet editing |
| Palette | `ICON_MD_PALETTE` | Palette editing |
| Sprite | `ICON_MD_PERSON` | Sprite management |
| Music | `ICON_MD_MUSIC_NOTE` | Audio/music editing |
| Message | `ICON_MD_MESSAGE` | Text/message editing |
| Screen | `ICON_MD_TV` | Screen/UI editing |
| Emulator | `ICON_MD_VIDEOGAME_ASSET` | Emulation & debugging |
| Assembly | `ICON_MD_CODE` | ASM code editing |
| Settings | `ICON_MD_SETTINGS` | Application settings |
| Memory | `ICON_MD_MEMORY` | Memory inspection |
| Agent | `ICON_MD_SMART_TOY` | AI agent controls |
### Session-Aware Card IDs
Cards support multi-session (multiple ROMs open):
```
Single session: "dungeon.room_selector"
Multiple sessions: "s0.dungeon.room_selector", "s1.dungeon.room_selector"
```
The registry automatically prefixes card IDs using `MakeCardId()` and `GetPrefixedCardId()`.
### VSCode-Style Sidebar Layout
```
┌────┬─────────────────────────────────┬────────────────────────────────────────────┐
│ AB │ Side Panel │ Main Docking Space │
│ │ (250px width) │ │
│ ├─────────────────────────────────┤ │
│ 48 │ ▶ Dungeon │ ┌────────────────────────────────────┐ │
│ px │ ☑ Control Panel │ │ │ │
│ │ ☑ Room Selector │ │ Docked Editor Windows │ │
│ w │ ☐ Object Editor │ │ │ │
│ i │ ☐ Room Matrix │ │ │ │
│ d │ │ │ │ │
│ e │ ▶ Graphics │ │ │ │
│ │ ☐ Sheet Browser │ │ │ │
│ │ ☐ Tile Editor │ │ │ │
│ │ │ └────────────────────────────────────┘ │
│ │ ▶ Palette │ │
│ │ ☐ Control Panel │ │
├────┴─────────────────────────────────┴───────────────────────────────────────────┤
│ Status Bar │
└──────────────────────────────────────────────────────────────────────────────────┘
Activity Bar (category icons)
```
### Unified Visibility Management
The registry is the **single source of truth** for component visibility:
```cpp
// Emulator visibility (delegated from UICoordinator)
bool IsEmulatorVisible() const;
void SetEmulatorVisible(bool visible);
void ToggleEmulatorVisible();
void SetEmulatorVisibilityChangedCallback(std::function<void(bool)> cb);
```
### Card Validation System
Catches window title mismatches during development:
```cpp
struct CardValidationResult {
std::string card_id;
std::string expected_title; // From CardInfo::GetWindowTitle()
bool found_in_imgui; // Whether ImGui found window
std::string message; // Human-readable status
};
std::vector<CardValidationResult> ValidateCards() const;
void DrawValidationReport(bool* p_open);
```
---
## LayoutPresets
**File:** `src/app/editor/ui/layout_presets.h`
### Default Layouts Per Editor
Each editor type has a defined set of default and optional cards:
```cpp
struct PanelLayoutPreset {
std::string name; // "Overworld Default"
std::string description; // Human-readable
EditorType editor_type; // EditorType::kOverworld
std::vector<std::string> default_visible_cards; // Shown on first open
std::vector<std::string> optional_cards; // Available but hidden
};
```
### Editor Default Cards
| Editor | Default Cards | Optional Cards |
|------------|-------------------------------------------|---------------------------------------|
| Overworld | Canvas, Tile16 Selector | Tile8, Area GFX, Scratch, Usage Stats |
| Dungeon | Control Panel, Room Selector | Object Editor, Palette, Room Matrix |
| Graphics | Sheet Browser, Sheet Editor | Player Animations, Prototype Viewer |
| Palette | Control Panel, OW Main | Quick Access, OW Animated, Dungeon |
| Sprite | Vanilla Editor | Custom Editor |
| Screen | Dungeon Maps | Title, Inventory, OW Map, Naming |
| Music | Tracker | Instrument Editor, Assembly |
| Message | Message List, Message Editor | Font Atlas, Dictionary |
| Assembly | Editor | File Browser |
| Emulator | PPU Viewer | CPU Debugger, Memory, Breakpoints |
| Agent | Configuration, Status, Chat | Prompt Editor, Profiles, History |
### Named Workspace Presets
| Preset Name | Focus | Key Cards |
|-------------------|----------------------|-------------------------------------------|
| Minimal | Essential editing | Main canvas only |
| Developer | Debug/development | Emulator, Assembly, Memory, CPU Debugger |
| Designer | Visual/artistic | Graphics, Palette, Sprites, Screens |
| Modder | Full-featured | Everything enabled |
| Overworld Expert | Complete OW toolkit | All OW cards + Palette + Graphics |
| Dungeon Expert | Complete dungeon | All dungeon cards + Palette + Graphics |
| Testing | QA focused | Emulator, Save States, CPU, Memory, Agent |
| Audio | Music focused | Tracker, Instruments, Assembly, APU |
---
## LayoutManager
**File:** `src/app/editor/ui/layout_manager.h`
Manages ImGui DockBuilder layouts for each editor type.
### Default Layout Patterns
**Overworld Editor:**
```
┌─────────────────────────────┬──────────────┐
│ │ │
│ Overworld Canvas (75%) │ Tile16 (25%) │
│ (Main editing area) │ Selector │
│ │ │
└─────────────────────────────┴──────────────┘
```
**Dungeon Editor:**
```
┌─────┬───────────────────────────────────┐
│ │ │
│Room │ Dungeon Controls (85%) │
│(15%)│ (Main editing area, maximized) │
│ │ │
└─────┴───────────────────────────────────┘
```
**Graphics Editor:**
```
┌──────────────┬──────────────────────────┐
│ │ │
│ Sheet │ Sheet Editor (75%) │
│ Browser │ (Main canvas with tabs) │
│ (25%) │ │
└──────────────┴──────────────────────────┘
```
**Message Editor:**
```
┌─────────────┬──────────────────┬──────────┐
│ Message │ Message │ Font │
│ List (25%) │ Editor (50%) │ Atlas │
│ │ │ (25%) │
│ ├──────────────────┤ │
│ │ │Dictionary│
└─────────────┴──────────────────┴──────────┘
```
---
## Agent UI System
The agent UI system provides AI-assisted editing with a multi-agent architecture.
### Component Hierarchy
```
┌────────────────────────────────────────────────────────────────────────┐
│ AgentUiController │
│ (Central coordinator for all agent UI components) │
├─────────────────────┬─────────────────────┬────────────────────────────┤
│ AgentSessionManager│ AgentSidebar │ AgentChatCard[] │
│ ──────────────────│ ───────────── │ ─────────────── │
│ • Session lifecycle│ • Tab bar │ • Dockable windows │
│ • Active session │ • Model selector │ • Full chat view │
│ • Card open state │ • Chat compact │ • Per-agent instance │
│ │ • Proposals panel│ │
├─────────────────────┼─────────────────────┼────────────────────────────┤
│ AgentEditor │ AgentChatView │ AgentProposalsPanel │
│ ───────────── │ ────────────── │ ─────────────────── │
│ • Configuration │ • Message list │ • Code proposals │
│ • Profile mgmt │ • Input box │ • Accept/reject │
│ • Status display │ • Send button │ • Apply changes │
└─────────────────────┴─────────────────────┴────────────────────────────┘
```
### AgentSession Structure
```cpp
struct AgentSession {
std::string agent_id; // Unique identifier (UUID)
std::string display_name; // "Agent 1", "Agent 2"
AgentUIContext context; // Shared state with all views
bool is_active = false; // Currently selected in tab bar
bool has_card_open = false; // Pop-out card is visible
// Callbacks shared between sidebar and pop-out cards
ChatCallbacks chat_callbacks;
ProposalCallbacks proposal_callbacks;
CollaborationCallbacks collaboration_callbacks;
};
```
### AgentSessionManager
Manages multiple concurrent agent sessions:
```cpp
class AgentSessionManager {
public:
std::string CreateSession(const std::string& name = "");
void CloseSession(const std::string& agent_id);
AgentSession* GetActiveSession();
AgentSession* GetSession(const std::string& agent_id);
void SetActiveSession(const std::string& agent_id);
void OpenCardForSession(const std::string& agent_id);
void CloseCardForSession(const std::string& agent_id);
size_t GetSessionCount() const;
std::vector<AgentSession>& GetAllSessions();
};
```
### Sidebar Layout
```
┌─────────────────────────────────────────┐
│ [Agent 1] [Agent 2] [+] │ ← Tab bar with new agent button
├─────────────────────────────────────────┤
│ Model: gemini-2 ▼ 👤 [↗ Pop-out] │ ← Header with model selector
├─────────────────────────────────────────┤
│ │
│ 💬 User: How do I edit tiles? │
│ │
│ 🤖 Agent: You can use the Tile16... │ ← Chat messages (scrollable)
│ │
├─────────────────────────────────────────┤
│ [Type a message...] [Send] │ ← Input box
├─────────────────────────────────────────┤
│ ▶ Proposals (3) │ ← Collapsible section
│ • prop-001 ✓ Applied │
│ • prop-002 ⏳ Pending │
│ • prop-003 ❌ Rejected │
└─────────────────────────────────────────┘
```
### Pop-Out Card Flow
```
User clicks [↗ Pop-out] button in sidebar
AgentSidebar::pop_out_callback_()
AgentUiController::PopOutAgent(agent_id)
├─► Create AgentChatCard(agent_id, &session_manager_)
├─► card->SetToastManager(toast_manager_)
├─► card->SetAgentService(agent_service)
├─► session_manager_.OpenCardForSession(agent_id)
└─► open_cards_.push_back(std::move(card))
Each frame in Update():
AgentUiController::DrawOpenCards()
├─► For each card in open_cards_:
│ bool open = true;
│ card->Draw(&open);
│ if (!open) {
│ session_manager_.CloseCardForSession(card->agent_id());
│ Remove from open_cards_
│ }
└─► Pop-out cards render in main docking space
```
### State Synchronization
Both sidebar and pop-out cards share the same `AgentSession::context`:
```
┌─────────────────────────────────────────────────────────────────────────┐
│ AgentUIContext │
│ (Shared state for all views of same agent session) │
├─────────────────────────────────────────────────────────────────────────┤
│ agent_config_ │ Provider, model, API keys, flags │
│ chat_messages_ │ Conversation history │
│ pending_proposals_│ Code changes awaiting approval │
│ collaboration_ │ Multi-user collaboration state │
│ rom_ │ Reference to loaded ROM │
│ changed_ │ Flag for detecting config changes │
└─────────────────────────────────────────────────────────────────────────┘
┌───────────────┼───────────────┐
│ │ │
┌─────────┴───────┐ ┌────┴────┐ ┌──────┴──────┐
│ AgentSidebar │ │AgentChat │ │AgentChat │
│ (compact view) │ │ Card 1 │ │ Card 2 │
│ (right panel) │ │ (docked) │ │ (floating) │
└─────────────────┘ └──────────┘ └────────────┘
```
---
## Card Registration Pattern
Cards are registered during editor initialization:
```cpp
void DungeonEditor::Initialize(EditorDependencies& deps) {
deps.card_registry->RegisterCard({
.card_id = MakeCardId("dungeon.room_selector"),
.display_name = "Room Selector",
.window_title = " Rooms List", // Must match ImGui::Begin()
.icon = ICON_MD_LIST,
.category = "Dungeon",
.shortcut_hint = "Ctrl+Shift+R",
.visibility_flag = &show_room_selector_,
.enabled_condition = [this]() { return rom_ && rom_->is_loaded(); },
.disabled_tooltip = "Load a ROM to access room selection",
.priority = 10
});
}
```
### Registration Best Practices
1. **Use `MakeCardId()`** - Applies session prefixing if needed
2. **Match window_title exactly** - Must match ImGui::Begin() call
3. **Use Material Design icons** - `ICON_MD_*` constants
4. **Set category correctly** - Groups in sidebar
5. **Provide visibility_flag** - Points to bool member variable
6. **Include enabled_condition** - For ROM-dependent cards
7. **Set priority** - Lower = higher in menus
---
## Initialization Flow
```
Application Startup
EditorManager::Initialize()
├─► Create EditorCardRegistry
├─► Create LayoutManager (linked to registry)
├─► Create UICoordinator (with registry reference)
└─► For each Editor:
└─► Editor::Initialize(deps)
└─► deps.card_registry->RegisterCard(...)
(registers all cards for this editor)
```
## Editor Switch Flow
```
User clicks editor in menu
EditorManager::SwitchToEditor(EditorType type)
├─► HideCurrentEditorCards()
│ └─► card_registry_.HideAllCardsInCategory(old_category)
├─► LayoutManager::InitializeEditorLayout(type, dockspace_id)
│ └─► Build{EditorType}Layout() using DockBuilder
├─► LayoutPresets::GetDefaultCards(type)
│ └─► Returns default_visible_cards for this editor
├─► For each default card:
│ card_registry_.ShowCard(session_id, card_id)
└─► current_editor_ = editors_[type]
```
---
## File Locations
| Component | Header | Implementation |
|----------------------|--------------------------------------------------|--------------------------------------------------|
| EditorCardRegistry | `src/app/editor/system/editor_card_registry.h` | `src/app/editor/system/editor_card_registry.cc` |
| LayoutManager | `src/app/editor/ui/layout_manager.h` | `src/app/editor/ui/layout_manager.cc` |
| LayoutPresets | `src/app/editor/ui/layout_presets.h` | `src/app/editor/ui/layout_presets.cc` |
| UICoordinator | `src/app/editor/ui/ui_coordinator.h` | `src/app/editor/ui/ui_coordinator.cc` |
| EditorManager | `src/app/editor/editor_manager.h` | `src/app/editor/editor_manager.cc` |
| AgentUiController | `src/app/editor/agent/agent_ui_controller.h` | `src/app/editor/agent/agent_ui_controller.cc` |
| AgentSessionManager | `src/app/editor/agent/agent_session.h` | `src/app/editor/agent/agent_session.cc` |
| AgentSidebar | `src/app/editor/agent/agent_sidebar.h` | `src/app/editor/agent/agent_sidebar.cc` |
| AgentChatCard | `src/app/editor/agent/agent_chat_card.h` | `src/app/editor/agent/agent_chat_card.cc` |
| AgentChatView | `src/app/editor/agent/agent_chat_view.h` | `src/app/editor/agent/agent_chat_view.cc` |
| AgentProposalsPanel | `src/app/editor/agent/agent_proposals_panel.h` | `src/app/editor/agent/agent_proposals_panel.cc` |
| AgentState | `src/app/editor/agent/agent_state.h` | (header-only) |
---
## See Also
- [Graphics System Architecture](graphics_system_architecture.md)
- [Dungeon Editor System](dungeon_editor_system.md)
- [Overworld Editor System](overworld_editor_system.md)