# Handoff: Sidebar, Menu Bar, and Session Systems **Created**: 2025-01-24 **Last Updated**: 2025-01-24 **Status**: Active Reference **Owner**: UI/UX improvements --- ## Overview This document describes the architecture and interactions between three core UI systems: 1. **Sidebar** (`EditorCardRegistry`) - Icon-based card toggle panel 2. **Menu Bar** (`MenuOrchestrator`, `MenuBuilder`) - Application menus and status cluster 3. **Sessions** (`SessionCoordinator`, `RomSession`) - Multi-ROM session management --- ## 1. Sidebar System ### Key Files - `src/app/editor/system/editor_card_registry.h` - Card registration and sidebar state - `src/app/editor/system/editor_card_registry.cc` - Sidebar rendering (`DrawSidebar()`) ### Architecture The sidebar is a VSCode-style icon panel on the left side of the screen. It's managed by `EditorCardRegistry`, which: 1. **Stores card metadata** in `CardInfo` structs: ```cpp struct CardInfo { std::string card_id; // "dungeon.room_selector" std::string display_name; // "Room Selector" std::string window_title; // " Rooms List" (for DockBuilder) std::string icon; // ICON_MD_GRID_VIEW std::string category; // "Dungeon" std::string shortcut_hint; // "Ctrl+Shift+R" bool* visibility_flag; // Pointer to bool controlling visibility int priority; // Display order }; ``` 2. **Tracks collapsed state** via `sidebar_collapsed_` member ### Collapsed State Behavior When `sidebar_collapsed_ == true`: - `DrawSidebar()` returns immediately (no sidebar drawn) - A hamburger icon (≡) appears in the menu bar before "File" menu - Clicking hamburger sets `sidebar_collapsed_ = false` ```cpp // In EditorManager::DrawMenuBar() if (card_registry_.IsSidebarCollapsed()) { if (ImGui::SmallButton(ICON_MD_MENU)) { card_registry_.SetSidebarCollapsed(false); } } ``` ### Card Registration Editors register their cards during initialization: ```cpp card_registry_.RegisterCard({ .card_id = "dungeon.room_selector", .display_name = "Room Selector", .window_title = " Rooms List", .icon = ICON_MD_GRID_VIEW, .category = "Dungeon", .visibility_flag = &show_room_selector_, .priority = 10 }); ``` ### Utility Icons The sidebar has a fixed "utilities" section at the bottom with: - Emulator (ICON_MD_PLAY_ARROW) - Hex Editor (ICON_MD_MEMORY) - Settings (ICON_MD_SETTINGS) - Card Browser (ICON_MD_DASHBOARD) These are wired via callbacks: ```cpp card_registry_.SetShowEmulatorCallback([this]() { ... }); card_registry_.SetShowSettingsCallback([this]() { ... }); card_registry_.SetShowCardBrowserCallback([this]() { ... }); ``` ### Improvement Areas - **Disabled state styling**: Cards could show disabled state when ROM isn't loaded - **Dynamic population**: Cards could auto-hide based on editor type - **Badge indicators**: Cards could show notification badges --- ## 2. Menu Bar System ### Key Files - `src/app/editor/system/menu_orchestrator.h` - Menu structure and callbacks - `src/app/editor/system/menu_orchestrator.cc` - Menu building logic - `src/app/editor/ui/menu_builder.h` - Fluent menu construction API - `src/app/editor/ui/ui_coordinator.cc` - Status cluster rendering ### Architecture The menu system has three layers: 1. **MenuBuilder** - Fluent API for ImGui menu construction 2. **MenuOrchestrator** - Business logic, menu structure, callbacks 3. **UICoordinator** - Status cluster (right side of menu bar) ### Menu Structure ``` [≡] [File] [Edit] [View] [Tools] [Window] [Help] [●][🔔][📄▾][v0.x.x] hamburger menus status cluster (collapsed) ``` ### MenuOrchestrator Builds menus using `MenuBuilder`: ```cpp void MenuOrchestrator::BuildMainMenu() { ClearMenu(); BuildFileMenu(); BuildEditMenu(); BuildViewMenu(); BuildToolsMenu(); // Contains former Debug menu items BuildWindowMenu(); BuildHelpMenu(); menu_builder_.Draw(); } ``` ### Menu Item Pattern ```cpp menu_builder_ .Item( "Open ROM", // Label ICON_MD_FILE_OPEN, // Icon [this]() { OnOpenRom(); }, // Callback "Ctrl+O", // Shortcut hint [this]() { return CanOpenRom(); } // Enabled condition ) ``` ### Enabled Condition Helpers Key helpers in `MenuOrchestrator`: ```cpp bool HasActiveRom() const; // Is a ROM loaded? bool CanSaveRom() const; // Can save (ROM loaded + dirty)? bool HasCurrentEditor() const; // Is an editor active? bool HasMultipleSessions() const; ``` ### Status Cluster (Right Side) Located in `UICoordinator::DrawMenuBarExtras()`: 1. **Dirty badge** - Orange dot when ROM has unsaved changes 2. **Notification bell** - Shows notification history dropdown 3. **Session button** - Only visible with 2+ sessions 4. **Version** - Always visible ```cpp void UICoordinator::DrawMenuBarExtras() { // Right-aligned cluster ImGui::SameLine(ImGui::GetWindowWidth() - 150.0f); // 1. Dirty badge (if unsaved) if (current_rom && current_rom->dirty()) { ... } // 2. Notification bell DrawNotificationBell(); // 3. Session button (if multiple sessions) if (session_coordinator_.HasMultipleSessions()) { DrawSessionButton(); } // 4. Version ImGui::TextDisabled("v%s", version); } ``` ### Notification System `ToastManager` now tracks notification history: ```cpp struct NotificationEntry { std::string message; ToastType type; std::chrono::system_clock::time_point timestamp; bool read = false; }; // Methods size_t GetUnreadCount() const; const std::deque& GetHistory() const; void MarkAllRead(); void ClearHistory(); ``` ### Improvement Areas - **Disabled menu items**: Many items don't gray out when ROM not loaded - **Dynamic menu population**: Submenus could populate based on loaded data - **Context-sensitive menus**: Show different items based on active editor - **Recent files list**: File menu could show recent ROMs/projects --- ## 3. Session System ### Key Files - `src/app/editor/system/session_coordinator.h` - Session management - `src/app/editor/system/session_coordinator.cc` - Session lifecycle - `src/app/editor/system/rom_session.h` - Per-session state ### Architecture Each session contains: - A `Rom` instance - An `EditorSet` (all editor instances) - Session-specific UI state ```cpp struct RomSession : public Session { Rom rom; std::unique_ptr editor_set; size_t session_id; std::string name; }; ``` ### Session Switching ```cpp // In EditorManager void SwitchToSession(size_t session_id) { current_session_id_ = session_id; auto* session = GetCurrentSession(); // Update current_rom_, current_editor_set_, etc. } ``` ### Session UI The session button in the status cluster shows a dropdown: ```cpp void UICoordinator::DrawSessionButton() { if (ImGui::SmallButton(ICON_MD_LAYERS)) { ImGui::OpenPopup("##SessionSwitcherPopup"); } if (ImGui::BeginPopup("##SessionSwitcherPopup")) { for (size_t i = 0; i < session_coordinator_.GetTotalSessionCount(); ++i) { // Draw selectable for each session } ImGui::EndPopup(); } } ``` ### Improvement Areas - **Session naming**: Allow renaming sessions - **Session indicators**: Show which session has unsaved changes - **Session persistence**: Save/restore session state - **Session limit**: Handle max session count gracefully --- ## 4. Integration Points ### EditorManager as Hub `EditorManager` coordinates all three systems: ```cpp class EditorManager { EditorCardRegistry card_registry_; // Sidebar std::unique_ptr menu_orchestrator_; // Menus std::unique_ptr session_coordinator_; // Sessions std::unique_ptr ui_coordinator_; // Status cluster }; ``` ### DrawMenuBar Flow ```cpp void EditorManager::DrawMenuBar() { if (ImGui::BeginMenuBar()) { // 1. Hamburger icon (if sidebar collapsed) if (card_registry_.IsSidebarCollapsed()) { if (ImGui::SmallButton(ICON_MD_MENU)) { card_registry_.SetSidebarCollapsed(false); } } // 2. Main menus menu_orchestrator_->BuildMainMenu(); // 3. Status cluster (right side) ui_coordinator_->DrawMenuBarExtras(); ImGui::EndMenuBar(); } } ``` ### Sidebar Drawing Flow ```cpp // In EditorManager::Update() if (ui_coordinator_ && ui_coordinator_->IsCardSidebarVisible()) { card_registry_.DrawSidebar( category, // Current editor category active_categories, // All active editor categories category_switch_callback, collapse_callback // Now empty (hamburger handles expand) ); } ``` --- ## 5. Key Patterns ### Disabled State Pattern Current pattern for enabling/disabling: ```cpp menu_builder_.Item( "Save ROM", ICON_MD_SAVE, [this]() { OnSaveRom(); }, "Ctrl+S", [this]() { return CanSaveRom(); } // Enabled condition ); ``` To improve: Add visual distinction for disabled items in sidebar. ### Callback Wiring Pattern Components communicate via callbacks set during initialization: ```cpp // In EditorManager::Initialize() card_registry_.SetShowEmulatorCallback([this]() { ui_coordinator_->SetEmulatorVisible(true); }); welcome_screen_.SetOpenRomCallback([this]() { status_ = LoadRom(); }); ``` ### State Query Pattern Use getter methods to check state: ```cpp bool HasActiveRom() const { return rom_manager_.HasActiveRom(); } bool IsSidebarCollapsed() const { return sidebar_collapsed_; } bool HasMultipleSessions() const { return session_coordinator_.HasMultipleSessions(); } ``` --- ## 6. Common Tasks ### Adding a New Menu Item 1. Add callback method to `MenuOrchestrator`: ```cpp void OnMyNewAction(); ``` 2. Add to appropriate `Add*MenuItems()` method: ```cpp menu_builder_.Item("My Action", ICON_MD_STAR, [this]() { OnMyNewAction(); }); ``` 3. Implement the callback. ### Adding a New Sidebar Card 1. Add visibility flag to editor: ```cpp bool show_my_card_ = false; ``` 2. Register in editor's `Initialize()`: ```cpp card_registry.RegisterCard({ .card_id = "editor.my_card", .display_name = "My Card", .icon = ICON_MD_STAR, .category = "MyEditor", .visibility_flag = &show_my_card_ }); ``` 3. Draw in editor's `Update()` when visible. ### Adding Disabled State to Sidebar Currently not implemented. Suggested approach: ```cpp struct CardInfo { // ... existing fields ... std::function enabled_condition; // NEW }; // In DrawSidebar() bool enabled = card.enabled_condition ? card.enabled_condition() : true; if (!enabled) { ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); } // Draw button if (!enabled) { ImGui::PopStyleVar(); } ``` --- ## 7. Files Quick Reference | File | Purpose | |------|---------| | `editor_card_registry.h/cc` | Sidebar + card management | | `menu_orchestrator.h/cc` | Menu structure + callbacks | | `menu_builder.h` | Fluent menu API | | `ui_coordinator.h/cc` | Status cluster + UI state | | `session_coordinator.h/cc` | Multi-session management | | `editor_manager.h/cc` | Central coordinator | | `toast_manager.h` | Notifications + history | --- ## 8. Next Steps for Improvement 1. **Disabled menu items**: Ensure all menu items properly disable when ROM not loaded 2. **Sidebar disabled state**: Add visual feedback for cards that require ROM 3. **Dynamic population**: Auto-populate cards based on ROM type/features 4. **Session indicators**: Show dirty state per-session in session dropdown 5. **Context menus**: Right-click menus for cards and session items