yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
menu_orchestrator.cc
Go to the documentation of this file.
1#include "menu_orchestrator.h"
2
3#include <algorithm>
4#include <fstream>
5#include <map>
6#include <string>
7
8#include "absl/status/status.h"
9#include "absl/strings/str_format.h"
11#include "app/editor/editor.h"
23#include "app/gui/core/icons.h"
25#include "core/features.h"
26#include "rom/rom.h"
27#include "util/bps.h"
28#include "util/file_util.h"
31
32// Platform-aware shortcut macros for menu display
33#define SHORTCUT_CTRL(key) gui::FormatCtrlShortcut(ImGuiKey_##key).c_str()
34#define SHORTCUT_CTRL_SHIFT(key) \
35 gui::FormatCtrlShiftShortcut(ImGuiKey_##key).c_str()
36
37namespace yaze {
38namespace editor {
39
40namespace {
41
42constexpr const char* kLayoutDesignerWindowId = "layout.designer";
43
44} // namespace
45
47 EditorManager* editor_manager, MenuBuilder& menu_builder,
48 RomFileManager& rom_manager, ProjectManager& project_manager,
49 EditorRegistry& editor_registry, SessionCoordinator& session_coordinator,
50 ToastManager& toast_manager, PopupManager& popup_manager)
51 : editor_manager_(editor_manager),
52 menu_builder_(menu_builder),
53 rom_manager_(rom_manager),
54 project_manager_(project_manager),
55 editor_registry_(editor_registry),
56 session_coordinator_(session_coordinator),
57 toast_manager_(toast_manager),
58 popup_manager_(popup_manager) {}
59
61 ClearMenu();
62
63 // Build all menu sections in order
64 // Traditional order: File, Edit, View, then app-specific menus
68 // Windows menu now owns what used to live in the legacy "Window" menu
69 // (Sessions, Layout, Snapshots) in addition to the dynamic category
70 // toggles from WorkspaceWindowManager.
72 BuildToolsMenu(); // Debug menu items merged into Tools
74
75 // Draw the constructed menu
77
78 // Render any deferred modal popups owned by the menu layer. These run
79 // after the menu stack unwinds so the popup has a clean ImGui stack.
81 ImGui::OpenPopup("Save Layout Snapshot##menu_orch_save_snapshot");
83 }
84 if (ImGui::BeginPopupModal("Save Layout Snapshot##menu_orch_save_snapshot",
85 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
86 ImGui::TextUnformatted("Snapshot name:");
87 ImGui::SetNextItemWidth(320.0f);
88 const bool submitted =
89 ImGui::InputText("##snapshot_name", save_snapshot_name_buffer_,
91 ImGuiInputTextFlags_EnterReturnsTrue);
92 const bool has_name = save_snapshot_name_buffer_[0] != '\0';
93 ImGui::Separator();
94 if ((ImGui::Button("Save", ImVec2(120, 0)) || submitted) && has_name) {
95 if (editor_manager_) {
97 }
99 ImGui::CloseCurrentPopup();
100 }
101 ImGui::SameLine();
102 if (ImGui::Button("Cancel", ImVec2(120, 0))) {
104 ImGui::CloseCurrentPopup();
105 }
106 ImGui::EndPopup();
107 }
108
109 menu_needs_refresh_ = false;
110}
111
117
119 // ROM Operations
121 .Item(
122 "Open ROM / Project...", ICON_MD_FILE_OPEN, [this]() { OnOpenRom(); },
123 SHORTCUT_CTRL(O))
124 .Item(
125 "Save ROM", ICON_MD_SAVE, [this]() { OnSaveRom(); }, SHORTCUT_CTRL(S),
126 [this]() { return CanSaveRom(); })
127 .Item(
128 "Save As...", ICON_MD_SAVE_AS, [this]() { OnSaveRomAs(); }, nullptr,
129 [this]() { return CanSaveRom(); })
130 .Item(
131 "Save Scope...", ICON_MD_TUNE,
132 [this]() { popup_manager_.Show(PopupID::kSaveScope); }, nullptr,
133 [this]() { return CanSaveRom(); })
134 .Separator();
135
136 // Project Operations
138 .Item("New Project", ICON_MD_CREATE_NEW_FOLDER,
139 [this]() { OnCreateProject(); })
140 .Item("Open Project Only...", ICON_MD_FOLDER_OPEN,
141 [this]() { OnOpenProject(); })
142 .Item(
143 "Save Project", ICON_MD_SAVE, [this]() { OnSaveProject(); }, nullptr,
144 [this]() { return CanSaveProject(); })
145 .Item(
146 "Save Project As...", ICON_MD_SAVE_AS,
147 [this]() { OnSaveProjectAs(); }, nullptr,
148 [this]() { return CanSaveProject(); })
149 .Item(
150 "Project Management...", ICON_MD_FOLDER_SPECIAL,
151 [this]() { OnShowProjectManagement(); }, nullptr,
152 [this]() { return CanSaveProject(); })
153 .Item(
154 "Edit Project File...", ICON_MD_DESCRIPTION,
155 [this]() { OnShowProjectFileEditor(); }, nullptr,
156 [this]() { return HasProjectFile(); })
157 .Separator();
158
159 // Settings and Quit (ROM analysis / backup / BPS live under Tools)
161 .Item("Settings", ICON_MD_SETTINGS, [this]() { OnShowSettings(); })
162 .Separator()
163 .Item(
164 "Quit", ICON_MD_EXIT_TO_APP, [this]() { OnQuit(); },
165 SHORTCUT_CTRL(Q));
166}
167
173
175 // Undo/Redo operations - delegate to current editor
177 .Item(
178 "Undo", ICON_MD_UNDO, [this]() { OnUndo(); }, SHORTCUT_CTRL(Z),
179 [this]() { return HasCurrentEditor(); })
180 .Item(
181 "Redo", ICON_MD_REDO, [this]() { OnRedo(); }, SHORTCUT_CTRL(Y),
182 [this]() { return HasCurrentEditor(); })
183 .Separator();
184
185 // Clipboard operations - delegate to current editor
187 .Item(
188 "Cut", ICON_MD_CONTENT_CUT, [this]() { OnCut(); }, SHORTCUT_CTRL(X),
189 [this]() { return HasCurrentEditor(); })
190 .Item(
191 "Copy", ICON_MD_CONTENT_COPY, [this]() { OnCopy(); },
192 SHORTCUT_CTRL(C), [this]() { return HasCurrentEditor(); })
193 .Item(
194 "Paste", ICON_MD_CONTENT_PASTE, [this]() { OnPaste(); },
195 SHORTCUT_CTRL(V), [this]() { return HasCurrentEditor(); })
196 .Separator();
197
198 // Search operations (Find in Files moved to Tools > Global Search)
200 "Find", ICON_MD_SEARCH, [this]() { OnFind(); }, SHORTCUT_CTRL(F),
201 [this]() { return HasCurrentEditor(); });
202}
203
209
213
214 // Right drawers — shared catalog with menu-bar overflow / header switcher.
217
218 // Editor selection (Switch Editor)
220 "Switch Editor...", ICON_MD_SWAP_HORIZ,
221 [this]() { OnShowEditorSelection(); }, SHORTCUT_CTRL(E),
222 [this]() { return HasActiveRom(); });
223}
224
226 // Appearance/Layout controls
228 .Item(
229 "Show Sidebar", ICON_MD_VIEW_SIDEBAR,
230 [this]() {
231 if (window_manager_)
233 },
234 SHORTCUT_CTRL(B), nullptr,
235 [this]() {
237 })
238 .Item(
239 "Show Status Bar", ICON_MD_HORIZONTAL_RULE,
240 [this]() {
241 if (user_settings_) {
245 if (status_bar_) {
248 }
249 }
250 },
251 nullptr, nullptr,
252 [this]() {
254 })
255 .Separator()
256 .Item("Display Settings", ICON_MD_DISPLAY_SETTINGS,
257 [this]() { OnShowDisplaySettings(); })
258 .Item("Welcome Screen", ICON_MD_HOME,
259 [this]() { OnShowWelcomeScreen(); });
260}
261
263 auto* drawers =
265 if (!drawers) {
266 return;
267 }
268
270 for (const DrawerCatalogEntry& entry : GetDrawerCatalog()) {
271 const auto type = entry.type;
273 entry.name, entry.icon,
274 [drawers, type]() { drawers->ToggleDrawer(type); }, nullptr, nullptr,
275 [drawers, type]() { return drawers->IsDrawerActive(type); });
276 }
278}
279
280// Layout presets remain under Windows > Layout (AddLayoutSubmenu).
281// The former View > Layout duplicate was removed to keep one home for layout.
282
284 // Use CustomMenu to integrate dynamic panel content with the menu builder
285 menu_builder_.CustomMenu("Windows", [this]() { AddPanelsMenuItems(); });
286}
287
289 if (!window_manager_) {
290 return;
291 }
292
293 const size_t session_id = session_coordinator_.GetActiveSessionId();
294 std::string active_category = window_manager_->GetActiveCategory();
295 auto all_categories = window_manager_->GetAllCategories(session_id);
296
297 // Window Browser action at top
298 if (ImGui::MenuItem(
299 absl::StrFormat("%s Window Browser", ICON_MD_APPS).c_str(),
302 }
303 if (ImGui::MenuItem(
304 absl::StrFormat("%s Show All Windows", ICON_MD_VISIBILITY).c_str())) {
306 }
307 if (ImGui::MenuItem(
308 absl::StrFormat("%s Hide All Windows", ICON_MD_VISIBILITY_OFF)
309 .c_str())) {
311 }
312 ImGui::Separator();
313
314 // Sessions and Layout — folded in from the former "Window" top-level menu.
315 // These draw directly against ImGui (not through MenuBuilder) because
316 // CustomMenu's callback runs *inside* an already-open BeginMenu scope.
320 ImGui::Separator();
321
322 if (all_categories.empty()) {
323 ImGui::TextDisabled("No windows available");
324 return;
325 }
326
327 // Show all categories as direct submenus (no nested "All Categories" wrapper)
328 for (const auto& category : all_categories) {
329 // Mark active category with icon
330 std::string label = category;
331 if (category == active_category) {
332 label = absl::StrFormat("%s %s", ICON_MD_FOLDER_OPEN, category);
333 } else {
334 label = absl::StrFormat("%s %s", ICON_MD_FOLDER, category);
335 }
336
337 if (ImGui::BeginMenu(label.c_str())) {
338 auto cards = window_manager_->GetWindowsInCategory(session_id, category);
339
340 if (cards.empty()) {
341 ImGui::TextDisabled("No windows in this category");
342 } else {
343 if (ImGui::MenuItem(
344 absl::StrFormat("%s Show Category", ICON_MD_VISIBILITY)
345 .c_str())) {
346 window_manager_->ShowAllWindowsInCategory(session_id, category);
347 }
348 if (ImGui::MenuItem(
349 absl::StrFormat("%s Hide Category", ICON_MD_VISIBILITY_OFF)
350 .c_str())) {
351 window_manager_->HideAllWindowsInCategory(session_id, category);
352 }
353 ImGui::Separator();
354
355 for (const auto& card : cards) {
356 bool is_visible =
357 window_manager_->IsWindowOpen(session_id, card.card_id);
358 const char* shortcut =
359 card.shortcut_hint.empty() ? nullptr : card.shortcut_hint.c_str();
360
361 // Show icon for visible panels
362 std::string item_label =
363 is_visible
364 ? absl::StrFormat("%s %s", ICON_MD_CHECK_BOX,
365 card.display_name)
366 : absl::StrFormat("%s %s", ICON_MD_CHECK_BOX_OUTLINE_BLANK,
367 card.display_name);
368
369 if (ImGui::MenuItem(item_label.c_str(), shortcut)) {
370 window_manager_->ToggleWindow(session_id, card.card_id);
371 }
372 }
373 }
374 ImGui::EndMenu();
375 }
376 }
377}
378
384
389
393
395
396#ifdef YAZE_ENABLE_TESTING
398#endif
399
400 // ImGui Debug (moved from Debug menu)
402 .Item("ImGui Demo", ICON_MD_HELP, [this]() { OnShowImGuiDemo(); })
403 .Item("ImGui Metrics", ICON_MD_ANALYTICS,
404 [this]() { OnShowImGuiMetrics(); })
405 .EndMenu()
406 .Separator();
407
408#ifdef YAZE_WITH_GRPC
409 AddCollaborationMenuItems();
410#endif
411}
412
414 // Search & Navigation
416 .Item(
417 "Global Search", ICON_MD_SEARCH, [this]() { OnShowGlobalSearch(); },
419 .Item(
420 "Command Palette", ICON_MD_SEARCH,
421 [this]() { OnShowCommandPalette(); }, SHORTCUT_CTRL_SHIFT(P))
422 .Item(
423 "Find Window…", ICON_MD_DASHBOARD, [this]() { OnShowPanelFinder(); },
424 SHORTCUT_CTRL(P))
425 .Item("Resource Label Manager", ICON_MD_LABEL,
426 [this]() { OnShowResourceLabelManager(); });
427}
428
431
432 std::map<std::string, std::vector<WorkflowItem>> grouped_items;
433
434 if (window_manager_) {
435 const size_t session_id = session_coordinator_.GetActiveSessionId();
436 const auto categories = window_manager_->GetAllCategories(session_id);
437 for (const auto& category : categories) {
438 for (const auto& descriptor :
439 window_manager_->GetWindowsInCategory(session_id, category)) {
440 if (descriptor.workflow_group.empty()) {
441 continue;
442 }
443 WorkflowItem item;
444 item.id = absl::StrFormat("panel.%s", descriptor.card_id);
445 item.group = descriptor.workflow_group;
446 item.label = descriptor.workflow_label.empty()
447 ? descriptor.display_name
448 : descriptor.workflow_label;
449 item.description =
450 descriptor.workflow_description.empty()
451 ? absl::StrFormat("Open %s", descriptor.display_name)
452 : descriptor.workflow_description;
453 item.shortcut = descriptor.shortcut_hint;
454 item.priority = descriptor.workflow_priority;
455 item.callback = [this, session_id, panel_id = descriptor.card_id]() {
456 if (window_manager_) {
457 window_manager_->OpenWindow(session_id, panel_id);
458 }
459 };
460 item.enabled = descriptor.enabled_condition;
461 const std::string group = item.group.empty() ? "General" : item.group;
462 grouped_items[group].push_back(std::move(item));
463 }
464 }
465 }
466
467 for (const auto& action : ContentRegistry::WorkflowActions::GetAll()) {
468 const std::string group = action.group.empty() ? "General" : action.group;
469 grouped_items[group].push_back(action);
470 }
471
472 if (grouped_items.empty()) {
473 return;
474 }
475
476 menu_builder_.BeginSubMenu("Hack Workflows", ICON_MD_ROUTE);
477 for (auto& [group, items] : grouped_items) {
478 std::sort(items.begin(), items.end(),
479 [](const WorkflowItem& lhs, const WorkflowItem& rhs) {
480 if (lhs.priority != rhs.priority) {
481 return lhs.priority < rhs.priority;
482 }
483 return lhs.label < rhs.label;
484 });
486 for (const auto& item : items) {
487 MenuBuilder::EnabledCheck enabled = item.enabled;
489 item.label.c_str(), item.callback,
490 item.shortcut.empty() ? nullptr : item.shortcut.c_str(), enabled);
491 }
493 }
494 menu_builder_.EndMenu();
495}
496
497void MenuOrchestrator::AddRomAnalysisMenuItems() {
498 // ROM Analysis (document tooling moved from File)
499 menu_builder_.BeginSubMenu("ROM Analysis", ICON_MD_STORAGE)
500 .Item(
501 "ROM Information", ICON_MD_INFO, [this]() { OnShowRomInfo(); },
502 nullptr, [this]() { return HasActiveRom(); })
503 .Item(
504 "Create Backup", ICON_MD_BACKUP, [this]() { OnCreateBackup(); },
505 nullptr, [this]() { return HasActiveRom(); })
506 .Item(
507 "ROM Backups...", ICON_MD_BACKUP,
508 [this]() { popup_manager_.Show(PopupID::kRomBackups); }, nullptr,
509 [this]() { return HasActiveRom(); })
510 .Item(
511 "Validate ROM", ICON_MD_CHECK_CIRCLE, [this]() { OnValidateRom(); },
512 nullptr, [this]() { return HasActiveRom(); })
513 .Item(
514 "Data Integrity Check", ICON_MD_ANALYTICS,
515 [this]() { OnRunDataIntegrityCheck(); }, nullptr,
516 [this]() { return HasActiveRom(); })
517 .Item(
518 "Test Save/Load", ICON_MD_SAVE_ALT, [this]() { OnTestSaveLoad(); },
519 nullptr, [this]() { return HasActiveRom(); })
520 .Separator()
521 .Item(
522 "Export BPS Patch...", ICON_MD_DIFFERENCE,
523 [this]() { OnExportBpsPatch(); }, nullptr,
524 [this]() { return HasActiveRom(); })
525 .Item(
526 "Apply BPS Patch...", ICON_MD_BUILD, [this]() { OnApplyBpsPatch(); },
527 nullptr, [this]() { return HasActiveRom(); })
528 .EndMenu();
529
530 // ZSCustomOverworld (moved from Debug menu)
531 menu_builder_.BeginSubMenu("ZSCustomOverworld", ICON_MD_CODE)
532 .Item(
533 "Check ROM Version", ICON_MD_INFO, [this]() { OnCheckRomVersion(); },
534 nullptr, [this]() { return HasActiveRom(); })
535 .Item(
536 "Upgrade ROM", ICON_MD_UPGRADE, [this]() { OnUpgradeRom(); }, nullptr,
537 [this]() { return HasActiveRom(); })
538 .Item("Toggle Custom Loading", ICON_MD_SETTINGS,
539 [this]() { OnToggleCustomLoading(); })
540 .EndMenu();
541}
542
543void MenuOrchestrator::AddAsarIntegrationMenuItems() {
544 // Asar Integration (moved from Debug menu)
545 menu_builder_.BeginSubMenu("Asar Integration", ICON_MD_BUILD)
546 .Item("Asar Status", ICON_MD_INFO,
547 [this]() { popup_manager_.Show(PopupID::kAsarIntegration); })
548 .Item(
549 "Toggle ASM Patch", ICON_MD_CODE, [this]() { OnToggleAsarPatch(); },
550 nullptr, [this]() { return HasActiveRom(); })
551 .Item("Load ASM File", ICON_MD_FOLDER_OPEN, [this]() { OnLoadAsmFile(); })
552 .EndMenu();
553}
554
555void MenuOrchestrator::AddDevelopmentMenuItems() {
556 // Development Tools — Agent drawers live under View > Drawers.
557 menu_builder_.BeginSubMenu("Development", ICON_MD_DEVELOPER_MODE)
558 .Item(
559 "Memory Editor", ICON_MD_MEMORY, [this]() { OnShowMemoryEditor(); },
560 nullptr, [this]() { return HasActiveRom(); })
561 .Item("Assembly Editor", ICON_MD_CODE,
562 [this]() { OnShowAssemblyEditor(); })
563 .Item("Feature Flags", ICON_MD_FLAG,
564 [this]() { popup_manager_.Show(PopupID::kFeatureFlags); })
565 .Item("Performance Dashboard", ICON_MD_SPEED,
566 [this]() { OnShowPerformanceDashboard(); })
567 .EndMenu();
568}
569
570void MenuOrchestrator::AddTestingMenuItems() {
571 // Testing (moved from Debug menu)
572 menu_builder_.BeginSubMenu("Testing", ICON_MD_SCIENCE);
573#ifdef YAZE_ENABLE_TESTING
574 menu_builder_
575 .Item(
576 "Test Dashboard", ICON_MD_DASHBOARD,
577 [this]() { OnShowTestDashboard(); }, SHORTCUT_CTRL(T))
578 .Item("Run All Tests", ICON_MD_PLAY_ARROW, [this]() { OnRunAllTests(); })
579 .Item("Run Unit Tests", ICON_MD_CHECK_BOX, [this]() { OnRunUnitTests(); })
580 .Item("Run Integration Tests", ICON_MD_INTEGRATION_INSTRUCTIONS,
581 [this]() { OnRunIntegrationTests(); })
582 .Item("Run E2E Tests", ICON_MD_VISIBILITY, [this]() { OnRunE2ETests(); });
583#else
584 menu_builder_.DisabledItem(
585 "Testing support disabled (YAZE_ENABLE_TESTING=OFF)", ICON_MD_INFO);
586#endif
587 menu_builder_.EndMenu();
588}
589
590#ifdef YAZE_WITH_GRPC
591void MenuOrchestrator::AddCollaborationMenuItems() {
592 // Collaboration (GRPC builds only)
593 menu_builder_.BeginSubMenu("Collaborate", ICON_MD_PEOPLE)
594 .Item("Start Collaboration Session", ICON_MD_PLAY_CIRCLE,
595 [this]() { OnStartCollaboration(); })
596 .Item("Join Collaboration Session", ICON_MD_GROUP_ADD,
597 [this]() { OnJoinCollaboration(); })
598 .Item("Network Status", ICON_MD_CLOUD,
599 [this]() { OnShowNetworkStatus(); })
600 .EndMenu();
601}
602#endif
603
604// Sessions submenu (folded from the former top-level "Window" menu).
605// Drawn inline inside the "Windows" CustomMenu callback using raw ImGui
606// calls so the entries land in the same menu scope.
607void MenuOrchestrator::AddSessionsSubmenu() {
608 if (ImGui::BeginMenu(absl::StrFormat("%s Sessions", ICON_MD_TAB).c_str())) {
609 if (ImGui::MenuItem(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str(),
611 OnCreateNewSession();
612 }
613 if (ImGui::MenuItem(
614 absl::StrFormat("%s Duplicate Session", ICON_MD_CONTENT_COPY)
615 .c_str(),
616 nullptr, false, HasActiveRom())) {
617 OnDuplicateCurrentSession();
618 }
619 if (ImGui::MenuItem(
620 absl::StrFormat("%s Close Session", ICON_MD_CLOSE).c_str(),
621 SHORTCUT_CTRL_SHIFT(W), false, HasMultipleSessions())) {
622 OnCloseCurrentSession();
623 }
624 ImGui::Separator();
625 if (ImGui::MenuItem(
626 absl::StrFormat("%s Session Switcher", ICON_MD_SWITCH_ACCOUNT)
627 .c_str(),
628 SHORTCUT_CTRL(Tab), false, HasMultipleSessions())) {
629 OnShowSessionSwitcher();
630 }
631 if (ImGui::MenuItem(
632 absl::StrFormat("%s Session Manager", ICON_MD_VIEW_LIST).c_str())) {
633 OnShowSessionManager();
634 }
635 ImGui::EndMenu();
636 }
637}
638
639// Layout submenu (folded from the former top-level "Window" menu).
640// Contains Save/Load/Reset, session snapshots, and named presets.
641void MenuOrchestrator::AddLayoutSubmenu() {
642 const bool layout_enabled = HasCurrentEditor();
643 auto apply_preset = [this](const char* name) {
644 if (editor_manager_)
645 editor_manager_->ApplyLayoutPreset(name);
646 };
647 auto apply_profile = [this](const char* name) {
648 if (editor_manager_)
649 editor_manager_->ApplyLayoutProfile(name);
650 };
651
652 if (ImGui::BeginMenu(
653 absl::StrFormat("%s Layout", ICON_MD_VIEW_QUILT).c_str())) {
654 if (ImGui::MenuItem(absl::StrFormat("%s Open Layout Designer",
656 .c_str(),
657 nullptr, false, window_manager_ != nullptr)) {
658 OnShowLayoutDesigner();
659 }
660 ImGui::Separator();
661
662 if (ImGui::MenuItem(absl::StrFormat("%s Save Layout", ICON_MD_SAVE).c_str(),
664 OnSaveWorkspaceLayout();
665 }
666 if (ImGui::MenuItem(
667 absl::StrFormat("%s Load Layout", ICON_MD_FOLDER_OPEN).c_str(),
669 OnLoadWorkspaceLayout();
670 }
671 if (ImGui::MenuItem(
672 absl::StrFormat("%s Reset Layout", ICON_MD_RESET_TV).c_str())) {
673 OnResetWorkspaceLayout();
674 }
675 if (ImGui::MenuItem(
676 absl::StrFormat("%s Reset Active Editor Layout", ICON_MD_REFRESH)
677 .c_str(),
678 nullptr, false, layout_enabled)) {
679 if (editor_manager_)
680 editor_manager_->ResetCurrentEditorLayout();
681 }
682
683 ImGui::Separator();
684 if (ImGui::BeginMenu(
685 absl::StrFormat("%s Snapshots", ICON_MD_BOOKMARKS).c_str(),
686 layout_enabled)) {
687 if (ImGui::MenuItem(
688 absl::StrFormat("%s Save Snapshot As...", ICON_MD_BOOKMARK_ADD)
689 .c_str(),
690 nullptr, false, layout_enabled)) {
691 save_snapshot_name_buffer_[0] = '\0';
692 open_save_snapshot_modal_ = true;
693 }
694
695 // Named snapshots (session-scoped, in-memory).
696 std::vector<std::string> named =
697 editor_manager_ ? editor_manager_->ListLayoutSnapshots()
698 : std::vector<std::string>{};
699 if (!named.empty()) {
700 ImGui::Separator();
701 for (const auto& name : named) {
702 ImGui::PushID(name.c_str());
703 if (ImGui::MenuItem(
704 absl::StrFormat("%s %s", ICON_MD_RESTORE, name).c_str(),
705 nullptr, false, layout_enabled)) {
706 if (editor_manager_)
707 editor_manager_->RestoreLayoutSnapshot(name);
708 }
709 ImGui::SameLine(ImGui::GetContentRegionAvail().x);
710 if (ImGui::SmallButton(ICON_MD_DELETE)) {
711 if (editor_manager_)
712 editor_manager_->DeleteLayoutSnapshot(name);
713 }
714 ImGui::PopID();
715 }
716 }
717
718 ImGui::Separator();
719 // Legacy unnamed temporary slot (backward-compatible Capture/Restore).
720 if (ImGui::MenuItem(
721 absl::StrFormat("%s Capture Unnamed", ICON_MD_BOOKMARK_ADD)
722 .c_str(),
723 nullptr, false, layout_enabled)) {
724 if (editor_manager_)
725 editor_manager_->CaptureTemporaryLayoutSnapshot();
726 }
727 if (ImGui::MenuItem(
728 absl::StrFormat("%s Restore Unnamed", ICON_MD_RESTORE).c_str(),
729 nullptr, false, layout_enabled)) {
730 if (editor_manager_)
731 editor_manager_->RestoreTemporaryLayoutSnapshot();
732 }
733 if (ImGui::MenuItem(
734 absl::StrFormat("%s Clear Unnamed", ICON_MD_BOOKMARK_REMOVE)
735 .c_str(),
736 nullptr, false, layout_enabled)) {
737 if (editor_manager_)
738 editor_manager_->ClearTemporaryLayoutSnapshot();
739 }
740 ImGui::EndMenu();
741 }
742
743 ImGui::Separator();
744 if (ImGui::BeginMenu(
745 absl::StrFormat("%s Presets", ICON_MD_DASHBOARD).c_str())) {
746 if (ImGui::MenuItem(absl::StrFormat("%s Code", ICON_MD_CODE).c_str(),
747 nullptr, false, layout_enabled)) {
748 apply_profile("code");
749 }
750 if (ImGui::MenuItem(
751 absl::StrFormat("%s Debug", ICON_MD_BUG_REPORT).c_str(), nullptr,
752 false, layout_enabled)) {
753 apply_profile("debug");
754 }
755 if (ImGui::MenuItem(absl::StrFormat("%s Mapping", ICON_MD_MAP).c_str(),
756 nullptr, false, layout_enabled)) {
757 apply_profile("mapping");
758 }
759 if (ImGui::MenuItem(
760 absl::StrFormat("%s Chat + Agent", ICON_MD_SMART_TOY).c_str(),
761 nullptr, false, layout_enabled)) {
762 apply_profile("chat");
763 }
764 ImGui::Separator();
765 if (ImGui::MenuItem(
766 absl::StrFormat("%s Minimal", ICON_MD_VIEW_COMPACT).c_str(),
767 nullptr, false, layout_enabled)) {
768 apply_preset("Minimal");
769 }
770 if (ImGui::MenuItem(
771 absl::StrFormat("%s Developer", ICON_MD_DEVELOPER_MODE).c_str(),
772 nullptr, false, layout_enabled)) {
773 OnLoadDeveloperLayout();
774 }
775 if (ImGui::MenuItem(
776 absl::StrFormat("%s Designer", ICON_MD_DESIGN_SERVICES).c_str(),
777 nullptr, false, layout_enabled)) {
778 OnLoadDesignerLayout();
779 }
780 if (ImGui::MenuItem(absl::StrFormat("%s Modder", ICON_MD_BUILD).c_str(),
781 nullptr, false, layout_enabled)) {
782 OnLoadModderLayout();
783 }
784 if (ImGui::MenuItem(
785 absl::StrFormat("%s Overworld Expert", ICON_MD_MAP).c_str(),
786 nullptr, false, layout_enabled)) {
787 apply_preset("Overworld Expert");
788 }
789 if (ImGui::MenuItem(
790 absl::StrFormat("%s Dungeon Expert", ICON_MD_CASTLE).c_str(),
791 nullptr, false, layout_enabled)) {
792 apply_preset("Dungeon Expert");
793 }
794 if (ImGui::MenuItem(
795 absl::StrFormat("%s Testing", ICON_MD_SCIENCE).c_str(), nullptr,
796 false, layout_enabled)) {
797 apply_preset("Testing");
798 }
799 if (ImGui::MenuItem(
800 absl::StrFormat("%s Audio", ICON_MD_MUSIC_NOTE).c_str(), nullptr,
801 false, layout_enabled)) {
802 apply_preset("Audio");
803 }
804 ImGui::Separator();
805 if (ImGui::MenuItem(
806 absl::StrFormat("%s Manage Presets...", ICON_MD_TUNE).c_str())) {
807 OnShowLayoutPresets();
808 }
809 ImGui::EndMenu();
810 }
811 ImGui::EndMenu();
812 }
813}
814
815// Sidebar submenu — surfaces ActivityBar pin/hide/reorder operations so the
816// feature is discoverable from the menubar without touching the rail.
817void MenuOrchestrator::AddSidebarSubmenu() {
818 if (!user_settings_) {
819 return;
820 }
821
822 if (!ImGui::BeginMenu(
823 absl::StrFormat("%s Sidebar", ICON_MD_VIEW_SIDEBAR).c_str())) {
824 return;
825 }
826
827 auto persist = [this]() {
828 (void)user_settings_->Save();
829 };
830 auto& prefs = user_settings_->prefs();
831
832 if (ImGui::MenuItem(
833 absl::StrFormat("%s Reset Order", ICON_MD_RESTART_ALT).c_str(),
834 nullptr, false, !prefs.sidebar_order.empty())) {
835 prefs.sidebar_order.clear();
836 persist();
837 }
838 if (ImGui::MenuItem(
839 absl::StrFormat("%s Show All Categories", ICON_MD_VISIBILITY).c_str(),
840 nullptr, false, !prefs.sidebar_hidden.empty())) {
841 prefs.sidebar_hidden.clear();
842 persist();
843 }
844
845 ImGui::Separator();
846
847 const size_t session_id = session_coordinator_.GetActiveSessionId();
848 std::vector<std::string> categories;
849 if (window_manager_) {
850 categories = window_manager_->GetAllCategories(session_id);
851 }
852
853 // Build pinned list (in canonical category order).
854 std::vector<std::string> pinned_list;
855 std::vector<std::string> hidden_list;
856 for (const auto& cat : categories) {
857 if (cat == WorkspaceWindowManager::kDashboardCategory)
858 continue;
859 if (prefs.sidebar_pinned.count(cat))
860 pinned_list.push_back(cat);
861 if (prefs.sidebar_hidden.count(cat))
862 hidden_list.push_back(cat);
863 }
864
865 if (ImGui::BeginMenu(
866 absl::StrFormat("%s Pinned", ICON_MD_PUSH_PIN).c_str())) {
867 if (pinned_list.empty()) {
868 ImGui::TextDisabled("(none)");
869 } else {
870 for (const auto& cat : pinned_list) {
871 ImGui::PushID(cat.c_str());
872 if (ImGui::MenuItem(
873 absl::StrFormat("%s Unpin %s", ICON_MD_CLOSE, cat).c_str())) {
874 prefs.sidebar_pinned.erase(cat);
875 persist();
876 }
877 ImGui::PopID();
878 }
879 }
880 ImGui::EndMenu();
881 }
882
883 if (ImGui::BeginMenu(
884 absl::StrFormat("%s Hidden", ICON_MD_VISIBILITY_OFF).c_str())) {
885 if (hidden_list.empty()) {
886 ImGui::TextDisabled("(none)");
887 } else {
888 for (const auto& cat : hidden_list) {
889 ImGui::PushID(cat.c_str());
890 if (ImGui::MenuItem(
891 absl::StrFormat("%s Show %s", ICON_MD_VISIBILITY, cat)
892 .c_str())) {
893 prefs.sidebar_hidden.erase(cat);
894 persist();
895 }
896 ImGui::PopID();
897 }
898 }
899 ImGui::EndMenu();
900 }
901
902 ImGui::Separator();
903
904 // Per-category toggles (pin/hide) for all categories. Keeps the menu
905 // discoverable even for users who haven't right-clicked the rail.
906 if (ImGui::BeginMenu(absl::StrFormat("%s Customize", ICON_MD_TUNE).c_str())) {
907 if (categories.empty()) {
908 ImGui::TextDisabled("No categories available");
909 } else {
910 for (const auto& cat : categories) {
911 if (cat == WorkspaceWindowManager::kDashboardCategory)
912 continue;
913 ImGui::PushID(cat.c_str());
914 const bool pinned = prefs.sidebar_pinned.count(cat) > 0;
915 const bool hidden = prefs.sidebar_hidden.count(cat) > 0;
916 if (ImGui::BeginMenu(cat.c_str())) {
917 if (ImGui::MenuItem(pinned ? "Unpin from top" : "Pin to top", nullptr,
918 pinned)) {
919 if (pinned) {
920 prefs.sidebar_pinned.erase(cat);
921 } else {
922 prefs.sidebar_pinned.insert(cat);
923 }
924 persist();
925 }
926 if (ImGui::MenuItem(hidden ? "Show on sidebar" : "Hide from sidebar",
927 nullptr, hidden)) {
928 if (hidden) {
929 prefs.sidebar_hidden.erase(cat);
930 } else {
931 prefs.sidebar_hidden.insert(cat);
932 }
933 persist();
934 }
935 ImGui::EndMenu();
936 }
937 ImGui::PopID();
938 }
939 }
940 ImGui::EndMenu();
941 }
942
943 ImGui::EndMenu();
944}
945
946void MenuOrchestrator::BuildHelpMenu() {
947 menu_builder_.BeginMenu("Help");
948 AddHelpMenuItems();
949 menu_builder_.EndMenu();
950}
951
952void MenuOrchestrator::AddHelpMenuItems() {
953 // Note: Asar Integration moved to Tools menu to reduce redundancy
954 menu_builder_
955 .Item("Getting Started", ICON_MD_PLAY_ARROW,
956 [this]() { OnShowGettingStarted(); })
957 .Item(
958 "Keyboard Shortcuts", ICON_MD_KEYBOARD,
959 [this]() {
960 if (window_manager_) {
961 window_manager_->TriggerShowShortcuts();
962 }
963 },
964 SHORTCUT_CTRL_SHIFT(Slash))
965 .Item("Build Instructions", ICON_MD_BUILD,
966 [this]() { OnShowBuildInstructions(); })
967 .Item("CLI Usage", ICON_MD_TERMINAL, [this]() { OnShowCLIUsage(); })
968 .Separator()
969 .Item("Supported Features", ICON_MD_CHECK_CIRCLE,
970 [this]() { OnShowSupportedFeatures(); })
971 .Item("What's New", ICON_MD_NEW_RELEASES, [this]() { OnShowWhatsNew(); })
972 .Separator()
973 .Item("Troubleshooting", ICON_MD_BUILD_CIRCLE,
974 [this]() { OnShowTroubleshooting(); })
975 .Item("Contributing", ICON_MD_VOLUNTEER_ACTIVISM,
976 [this]() { OnShowContributing(); })
977 .Separator()
978 .Item("About", ICON_MD_INFO, [this]() { OnShowAbout(); }, "F1");
979
980 menu_builder_.Separator();
981 menu_builder_.BeginSubMenu("Language", ICON_MD_LANGUAGE);
982 for (const std::string& locale :
984 menu_builder_.Item(
985 locale.c_str(), nullptr,
986 [locale]() { i18n::LanguageManager::Get().SetLanguage(locale); },
987 nullptr, nullptr,
988 [locale]() {
989 return i18n::LanguageManager::Get().GetCurrentLocale() == locale;
990 });
991 }
992 menu_builder_.EndMenu();
993}
994
995// Menu state management
996void MenuOrchestrator::ClearMenu() {
997 menu_builder_.Clear();
998}
999
1000void MenuOrchestrator::RefreshMenu() {
1001 menu_needs_refresh_ = true;
1002}
1003
1004// Menu item callbacks - delegate to appropriate managers
1005void MenuOrchestrator::OnOpenRom() {
1006 // Delegate to EditorManager's LoadRom which handles session management
1007 if (editor_manager_) {
1008 auto status = editor_manager_->LoadRom();
1009 if (!status.ok()) {
1010 toast_manager_.Show(
1011 absl::StrFormat("Failed to load ROM: %s", status.message()),
1012 ToastType::kError);
1013 }
1014 }
1015}
1016
1017void MenuOrchestrator::OnSaveRom() {
1018 // Delegate to EditorManager's SaveRom which handles editor data saving
1019 if (editor_manager_) {
1020 auto status = editor_manager_->SaveRom();
1021 if (!status.ok()) {
1022 if (absl::IsCancelled(status)) {
1023 return;
1024 }
1025 toast_manager_.Show(
1026 absl::StrFormat("Failed to save ROM: %s", status.message()),
1027 ToastType::kError);
1028 }
1029 }
1030}
1031
1032void MenuOrchestrator::OnSaveRomAs() {
1033 popup_manager_.Show(PopupID::kSaveAs);
1034}
1035
1036void MenuOrchestrator::OnCreateProject() {
1037 // Delegate to EditorManager which handles the full project creation flow
1038 if (editor_manager_) {
1039 auto status = editor_manager_->CreateNewProject();
1040 if (!status.ok()) {
1041 toast_manager_.Show(
1042 absl::StrFormat("Failed to create project: %s", status.message()),
1043 ToastType::kError);
1044 }
1045 }
1046}
1047
1048void MenuOrchestrator::OnOpenProject() {
1049 // Delegate to EditorManager which handles ROM loading and session creation
1050 if (editor_manager_) {
1051 auto status = editor_manager_->OpenProject();
1052 if (!status.ok()) {
1053 toast_manager_.Show(
1054 absl::StrFormat("Failed to open project: %s", status.message()),
1055 ToastType::kError);
1056 }
1057 }
1058}
1059
1060void MenuOrchestrator::OnSaveProject() {
1061 // Delegate to EditorManager which updates project with current state
1062 if (editor_manager_) {
1063 auto status = editor_manager_->SaveProject();
1064 if (!status.ok()) {
1065 toast_manager_.Show(
1066 absl::StrFormat("Failed to save project: %s", status.message()),
1067 ToastType::kError);
1068 } else {
1069 toast_manager_.Show("Project saved successfully", ToastType::kSuccess);
1070 }
1071 }
1072}
1073
1074void MenuOrchestrator::OnSaveProjectAs() {
1075 // Delegate to EditorManager
1076 if (editor_manager_) {
1077 auto status = editor_manager_->SaveProjectAs();
1078 if (!status.ok()) {
1079 toast_manager_.Show(
1080 absl::StrFormat("Failed to save project as: %s", status.message()),
1081 ToastType::kError);
1082 }
1083 }
1084}
1085
1086void MenuOrchestrator::OnShowProjectManagement() {
1087 // Show project management panel in right sidebar
1088 if (editor_manager_) {
1089 editor_manager_->ShowProjectManagement();
1090 }
1091}
1092
1093void MenuOrchestrator::OnShowProjectFileEditor() {
1094 // Open the project file editor with the current project file
1095 if (editor_manager_) {
1096 editor_manager_->ShowProjectFileEditor();
1097 }
1098}
1099
1100// Edit menu actions - delegate to current editor
1101void MenuOrchestrator::OnUndo() {
1102 if (editor_manager_) {
1103 auto* current_editor = editor_manager_->GetCurrentEditor();
1104 if (current_editor) {
1105 // Capture description before undo moves the action to the redo stack
1106 std::string desc = current_editor->GetUndoDescription();
1107 auto status = current_editor->Undo();
1108 if (status.ok()) {
1109 if (!desc.empty()) {
1110 toast_manager_.Show(absl::StrFormat("Undid: %s", desc),
1111 ToastType::kInfo, 2.0f);
1112 }
1113 } else {
1114 toast_manager_.Show(
1115 absl::StrFormat("Undo failed: %s", status.message()),
1116 ToastType::kError);
1117 }
1118 }
1119 }
1120}
1121
1122void MenuOrchestrator::OnRedo() {
1123 if (editor_manager_) {
1124 auto* current_editor = editor_manager_->GetCurrentEditor();
1125 if (current_editor) {
1126 // Capture description before redo moves the action to the undo stack
1127 std::string desc = current_editor->GetRedoDescription();
1128 auto status = current_editor->Redo();
1129 if (status.ok()) {
1130 if (!desc.empty()) {
1131 toast_manager_.Show(absl::StrFormat("Redid: %s", desc),
1132 ToastType::kInfo, 2.0f);
1133 }
1134 } else {
1135 toast_manager_.Show(
1136 absl::StrFormat("Redo failed: %s", status.message()),
1137 ToastType::kError);
1138 }
1139 }
1140 }
1141}
1142
1143void MenuOrchestrator::OnCut() {
1144 if (editor_manager_) {
1145 auto* current_editor = editor_manager_->GetCurrentEditor();
1146 if (current_editor) {
1147 auto status = current_editor->Cut();
1148 if (!status.ok()) {
1149 toast_manager_.Show(absl::StrFormat("Cut failed: %s", status.message()),
1150 ToastType::kError);
1151 }
1152 }
1153 }
1154}
1155
1156void MenuOrchestrator::OnCopy() {
1157 if (editor_manager_) {
1158 auto* current_editor = editor_manager_->GetCurrentEditor();
1159 if (current_editor) {
1160 auto status = current_editor->Copy();
1161 if (!status.ok()) {
1162 toast_manager_.Show(
1163 absl::StrFormat("Copy failed: %s", status.message()),
1164 ToastType::kError);
1165 }
1166 }
1167 }
1168}
1169
1170void MenuOrchestrator::OnPaste() {
1171 if (editor_manager_) {
1172 auto* current_editor = editor_manager_->GetCurrentEditor();
1173 if (current_editor) {
1174 auto status = current_editor->Paste();
1175 if (!status.ok()) {
1176 toast_manager_.Show(
1177 absl::StrFormat("Paste failed: %s", status.message()),
1178 ToastType::kError);
1179 }
1180 }
1181 }
1182}
1183
1184void MenuOrchestrator::OnFind() {
1185 if (editor_manager_) {
1186 auto* current_editor = editor_manager_->GetCurrentEditor();
1187 if (current_editor) {
1188 auto status = current_editor->Find();
1189 if (!status.ok()) {
1190 toast_manager_.Show(
1191 absl::StrFormat("Find failed: %s", status.message()),
1192 ToastType::kError);
1193 }
1194 }
1195 }
1196}
1197
1198// Editor-specific menu actions
1199void MenuOrchestrator::OnSwitchToEditor(EditorType editor_type) {
1200 // Delegate to EditorManager which manages editor switching
1201 if (editor_manager_) {
1202 editor_manager_->SwitchToEditor(editor_type);
1203 }
1204}
1205
1206void MenuOrchestrator::OnShowEditorSelection() {
1207 // Delegate to UICoordinator for editor selection dialog display
1208 if (editor_manager_) {
1209 if (auto* ui = editor_manager_->ui_coordinator()) {
1210 ui->ShowEditorSelection();
1211 }
1212 }
1213}
1214
1215void MenuOrchestrator::OnShowDisplaySettings() {
1216 popup_manager_.Show(PopupID::kDisplaySettings);
1217}
1218
1219void MenuOrchestrator::OnShowHexEditor() {
1220 // Show hex editor window via WorkspaceWindowManager
1221 if (editor_manager_) {
1222 editor_manager_->window_manager().OpenWindow(
1223 editor_manager_->GetCurrentSessionId(), "Hex Editor");
1224 }
1225}
1226
1227void MenuOrchestrator::OnShowPanelBrowser() {
1228 if (editor_manager_) {
1229 if (auto* ui = editor_manager_->ui_coordinator()) {
1230 ui->SetWindowBrowserVisible(true);
1231 }
1232 }
1233}
1234
1235void MenuOrchestrator::OnShowPanelFinder() {
1236 if (editor_manager_) {
1237 if (auto* ui = editor_manager_->ui_coordinator()) {
1238 ui->ShowPanelFinder();
1239 }
1240 }
1241}
1242
1243void MenuOrchestrator::OnShowWelcomeScreen() {
1244 if (editor_manager_) {
1245 if (auto* ui = editor_manager_->ui_coordinator()) {
1246 ui->SetWelcomeScreenVisible(true);
1247 }
1248 }
1249}
1250
1251#ifdef YAZE_BUILD_AGENT_UI
1252void MenuOrchestrator::OnShowAIAgent() {
1253 if (editor_manager_) {
1254 if (auto* ui = editor_manager_->ui_coordinator()) {
1255 ui->SetAIAgentVisible(true);
1256 }
1257 }
1258}
1259
1260void MenuOrchestrator::OnShowProposalDrawer() {
1261 if (editor_manager_) {
1262 if (auto* ui = editor_manager_->ui_coordinator()) {
1263 ui->SetProposalDrawerVisible(true);
1264 }
1265 }
1266}
1267#endif
1268
1269// Session management menu actions
1270void MenuOrchestrator::OnCreateNewSession() {
1271 session_coordinator_.CreateNewSession();
1272}
1273
1274void MenuOrchestrator::OnDuplicateCurrentSession() {
1275 session_coordinator_.DuplicateCurrentSession();
1276}
1277
1278void MenuOrchestrator::OnCloseCurrentSession() {
1279 if (editor_manager_) {
1280 editor_manager_->CloseCurrentSession();
1281 } else {
1282 session_coordinator_.CloseCurrentSession();
1283 }
1284}
1285
1286void MenuOrchestrator::OnShowSessionSwitcher() {
1287 // Delegate to UICoordinator for session switcher UI
1288 if (editor_manager_) {
1289 if (auto* ui = editor_manager_->ui_coordinator()) {
1290 ui->ShowSessionSwitcher();
1291 }
1292 }
1293}
1294
1295void MenuOrchestrator::OnShowSessionManager() {
1296 popup_manager_.Show(PopupID::kSessionManager);
1297}
1298
1299// Window management menu actions
1300void MenuOrchestrator::OnShowAllWindows() {
1301 // Delegate to EditorManager
1302 if (editor_manager_) {
1303 if (auto* ui = editor_manager_->ui_coordinator()) {
1304 ui->ShowAllWindows();
1305 }
1306 }
1307}
1308
1309void MenuOrchestrator::OnHideAllWindows() {
1310 // Delegate to EditorManager
1311 if (editor_manager_) {
1312 editor_manager_->HideAllWindows();
1313 }
1314}
1315
1316void MenuOrchestrator::OnResetWorkspaceLayout() {
1317 // Queue as deferred action to avoid modifying ImGui state during menu rendering
1318 if (editor_manager_) {
1319 editor_manager_->QueueDeferredAction([this]() {
1320 editor_manager_->ResetWorkspaceLayout();
1321 toast_manager_.Show("Layout reset to default", ToastType::kInfo);
1322 });
1323 }
1324}
1325
1326void MenuOrchestrator::OnSaveWorkspaceLayout() {
1327 // Delegate to EditorManager
1328 if (editor_manager_) {
1329 editor_manager_->SaveWorkspaceLayout();
1330 }
1331}
1332
1333void MenuOrchestrator::OnLoadWorkspaceLayout() {
1334 // Delegate to EditorManager
1335 if (editor_manager_) {
1336 editor_manager_->LoadWorkspaceLayout();
1337 }
1338}
1339
1340void MenuOrchestrator::OnShowLayoutPresets() {
1341 popup_manager_.Show(PopupID::kLayoutPresets);
1342}
1343
1344void MenuOrchestrator::OnShowLayoutDesigner() {
1345 WorkspaceWindowManager* manager = window_manager_;
1346 if (manager == nullptr && editor_manager_ != nullptr) {
1347 manager = &editor_manager_->window_manager();
1348 }
1349 if (manager == nullptr) {
1350 toast_manager_.Show("Layout Designer unavailable: no window manager",
1351 ToastType::kError);
1352 return;
1353 }
1354
1355 const size_t session_id = session_coordinator_.GetActiveSessionId();
1356 if (manager->GetActiveCategory().empty() ||
1357 manager->GetActiveCategory() ==
1358 WorkspaceWindowManager::kDashboardCategory) {
1359 manager->SetActiveCategory("Settings");
1360 }
1361
1362 const bool already_open =
1363 manager->IsWindowOpen(session_id, kLayoutDesignerWindowId);
1364 if (!already_open &&
1365 !manager->OpenWindow(session_id, kLayoutDesignerWindowId)) {
1366 toast_manager_.Show(
1367 "Layout Designer is not registered in the active session",
1368 ToastType::kError);
1369 return;
1370 }
1371
1372 // Cross-editor Settings-category panels are only drawn from another editor
1373 // when pinned. Opening the designer from the menubar should make it visible
1374 // immediately instead of merely flipping an off-category visibility flag.
1375 manager->SetWindowPinned(session_id, kLayoutDesignerWindowId, true);
1376}
1377
1378void MenuOrchestrator::OnLoadDeveloperLayout() {
1379 if (editor_manager_) {
1380 editor_manager_->ApplyLayoutPreset("Developer");
1381 }
1382}
1383
1384void MenuOrchestrator::OnLoadDesignerLayout() {
1385 if (editor_manager_) {
1386 editor_manager_->ApplyLayoutPreset("Designer");
1387 }
1388}
1389
1390void MenuOrchestrator::OnLoadModderLayout() {
1391 if (editor_manager_) {
1392 editor_manager_->ApplyLayoutPreset("Modder");
1393 }
1394}
1395
1396// Tool menu actions
1397void MenuOrchestrator::OnShowGlobalSearch() {
1398 if (editor_manager_) {
1399 if (auto* ui = editor_manager_->ui_coordinator()) {
1400 ui->ShowGlobalSearch();
1401 }
1402 }
1403}
1404
1405void MenuOrchestrator::OnShowCommandPalette() {
1406 if (editor_manager_) {
1407 if (auto* ui = editor_manager_->ui_coordinator()) {
1408 ui->ShowCommandPalette();
1409 }
1410 }
1411}
1412
1413void MenuOrchestrator::OnShowPerformanceDashboard() {
1414 if (editor_manager_) {
1415 if (auto* ui = editor_manager_->ui_coordinator()) {
1416 ui->SetPerformanceDashboardVisible(true);
1417 }
1418 }
1419}
1420
1421void MenuOrchestrator::OnShowImGuiDemo() {
1422 if (editor_manager_) {
1423 editor_manager_->ShowImGuiDemo();
1424 }
1425}
1426
1427void MenuOrchestrator::OnShowImGuiMetrics() {
1428 if (editor_manager_) {
1429 editor_manager_->ShowImGuiMetrics();
1430 }
1431}
1432
1433void MenuOrchestrator::OnShowMemoryEditor() {
1434 if (editor_manager_) {
1435 editor_manager_->window_manager().OpenWindow(
1436 editor_manager_->GetCurrentSessionId(), "Memory Editor");
1437 }
1438}
1439
1440void MenuOrchestrator::OnShowResourceLabelManager() {
1441 if (editor_manager_) {
1442 if (auto* ui = editor_manager_->ui_coordinator()) {
1443 ui->SetResourceLabelManagerVisible(true);
1444 }
1445 }
1446}
1447
1448#ifdef YAZE_ENABLE_TESTING
1449void MenuOrchestrator::OnShowTestDashboard() {
1450 if (editor_manager_) {
1451 editor_manager_->ShowTestDashboard();
1452 }
1453}
1454
1455void MenuOrchestrator::OnRunAllTests() {
1456 toast_manager_.Show("Running all tests...", ToastType::kInfo);
1457 // TODO: Implement test runner integration
1458}
1459
1460void MenuOrchestrator::OnRunUnitTests() {
1461 toast_manager_.Show("Running unit tests...", ToastType::kInfo);
1462 // TODO: Implement unit test runner
1463}
1464
1465void MenuOrchestrator::OnRunIntegrationTests() {
1466 toast_manager_.Show("Running integration tests...", ToastType::kInfo);
1467 // TODO: Implement integration test runner
1468}
1469
1470void MenuOrchestrator::OnRunE2ETests() {
1471 toast_manager_.Show(
1472 "E2E runner is not wired in-app yet. Use scripts/agents/run-tests.sh or "
1473 "z3ed test-run.",
1474 ToastType::kWarning);
1475}
1476#endif
1477
1478#ifdef YAZE_WITH_GRPC
1479void MenuOrchestrator::OnStartCollaboration() {
1480 toast_manager_.Show(
1481 "Collaboration session start is not wired yet. Run yaze-server and use "
1482 "the web client for live sync.",
1483 ToastType::kWarning);
1484}
1485
1486void MenuOrchestrator::OnJoinCollaboration() {
1487 toast_manager_.Show(
1488 "Join collaboration is not wired yet. Use the web client + yaze-server.",
1489 ToastType::kWarning);
1490}
1491
1492void MenuOrchestrator::OnShowNetworkStatus() {
1493 toast_manager_.Show("Network status panel is not implemented yet.",
1494 ToastType::kWarning);
1495}
1496#endif
1497
1498// Help menu actions
1499void MenuOrchestrator::OnShowAbout() {
1500 popup_manager_.Show(PopupID::kAbout);
1501}
1502
1503void MenuOrchestrator::OnShowGettingStarted() {
1504 popup_manager_.Show(PopupID::kGettingStarted);
1505}
1506
1507void MenuOrchestrator::OnShowBuildInstructions() {
1508 popup_manager_.Show(PopupID::kBuildInstructions);
1509}
1510
1511void MenuOrchestrator::OnShowCLIUsage() {
1512 popup_manager_.Show(PopupID::kCLIUsage);
1513}
1514
1515void MenuOrchestrator::OnShowTroubleshooting() {
1516 popup_manager_.Show(PopupID::kTroubleshooting);
1517}
1518
1519void MenuOrchestrator::OnShowContributing() {
1520 popup_manager_.Show(PopupID::kContributing);
1521}
1522
1523void MenuOrchestrator::OnShowWhatsNew() {
1524 popup_manager_.Show(PopupID::kWhatsNew);
1525}
1526
1527void MenuOrchestrator::OnShowSupportedFeatures() {
1528 popup_manager_.Show(PopupID::kSupportedFeatures);
1529}
1530
1531// Additional File menu actions
1532void MenuOrchestrator::OnShowRomInfo() {
1533 popup_manager_.Show(PopupID::kRomInfo);
1534}
1535
1536void MenuOrchestrator::OnCreateBackup() {
1537 if (editor_manager_) {
1538 auto status = rom_manager_.CreateBackup(editor_manager_->GetCurrentRom());
1539 if (status.ok()) {
1540 toast_manager_.Show("Backup created successfully", ToastType::kSuccess);
1541 } else {
1542 toast_manager_.Show(
1543 absl::StrFormat("Backup failed: %s", status.message()),
1544 ToastType::kError);
1545 }
1546 }
1547}
1548
1549void MenuOrchestrator::OnValidateRom() {
1550 if (editor_manager_) {
1551 auto status = rom_manager_.ValidateRom(editor_manager_->GetCurrentRom());
1552 if (status.ok()) {
1553 toast_manager_.Show("ROM validation passed", ToastType::kSuccess);
1554 } else {
1555 toast_manager_.Show(
1556 absl::StrFormat("ROM validation failed: %s", status.message()),
1557 ToastType::kError);
1558 }
1559 }
1560}
1561
1562void MenuOrchestrator::OnShowSettings() {
1563 // Activate settings editor
1564 if (editor_manager_) {
1565 editor_manager_->SwitchToEditor(EditorType::kSettings);
1566 }
1567}
1568
1569void MenuOrchestrator::OnQuit() {
1570 if (editor_manager_) {
1571 editor_manager_->Quit();
1572 }
1573}
1574
1575// Menu item validation helpers
1576bool MenuOrchestrator::CanSaveRom() const {
1577 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() : nullptr;
1578 return rom ? rom_manager_.IsRomLoaded(rom) : false;
1579}
1580
1581bool MenuOrchestrator::CanSaveProject() const {
1582 return project_manager_.HasActiveProject();
1583}
1584
1585bool MenuOrchestrator::HasActiveRom() const {
1586 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() : nullptr;
1587 return rom ? rom_manager_.IsRomLoaded(rom) : false;
1588}
1589
1590bool MenuOrchestrator::HasActiveProject() const {
1591 return project_manager_.HasActiveProject();
1592}
1593
1594bool MenuOrchestrator::HasProjectFile() const {
1595 // Check if EditorManager has a project with a valid filepath
1596 // This is separate from HasActiveProject which checks ProjectManager
1597 const auto* project =
1598 editor_manager_ ? editor_manager_->GetCurrentProject() : nullptr;
1599 return project && !project->filepath.empty();
1600}
1601
1602bool MenuOrchestrator::HasCurrentEditor() const {
1603 return editor_manager_ && editor_manager_->GetCurrentEditor() != nullptr;
1604}
1605
1606bool MenuOrchestrator::HasMultipleSessions() const {
1607 return session_coordinator_.HasMultipleSessions();
1608}
1609
1610// Menu item text generation
1611std::string MenuOrchestrator::GetRomFilename() const {
1612 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() : nullptr;
1613 return rom ? rom_manager_.GetRomFilename(rom) : "";
1614}
1615
1616std::string MenuOrchestrator::GetProjectName() const {
1617 return project_manager_.GetProjectName();
1618}
1619
1620std::string MenuOrchestrator::GetCurrentEditorName() const {
1621 // TODO: Get current editor name
1622 return "Unknown Editor";
1623}
1624
1625// Shortcut key management
1626std::string MenuOrchestrator::GetShortcutForAction(
1627 const std::string& action) const {
1628 // TODO: Implement shortcut mapping
1629 return "";
1630}
1631
1632void MenuOrchestrator::RegisterGlobalShortcuts() {
1633 // TODO: Register global keyboard shortcuts
1634}
1635
1636// ============================================================================
1637// Debug Menu Actions
1638// ============================================================================
1639
1640void MenuOrchestrator::OnRunDataIntegrityCheck() {
1641#ifdef YAZE_ENABLE_TESTING
1642 if (!editor_manager_)
1643 return;
1644 auto* rom = editor_manager_->GetCurrentRom();
1645 if (!rom || !rom->is_loaded())
1646 return;
1647
1648 toast_manager_.Show("Running ROM integrity tests...", ToastType::kInfo);
1649 // This would integrate with the test system in master
1650 // For now, just show a placeholder
1651 toast_manager_.Show("Data integrity check completed", ToastType::kSuccess,
1652 3.0f);
1653#else
1654 toast_manager_.Show("Testing not enabled in this build", ToastType::kWarning);
1655#endif
1656}
1657
1658void MenuOrchestrator::OnTestSaveLoad() {
1659#ifdef YAZE_ENABLE_TESTING
1660 if (!editor_manager_)
1661 return;
1662 auto* rom = editor_manager_->GetCurrentRom();
1663 if (!rom || !rom->is_loaded())
1664 return;
1665
1666 toast_manager_.Show("Running ROM save/load tests...", ToastType::kInfo);
1667 // This would integrate with the test system in master
1668 toast_manager_.Show("Save/load test completed", ToastType::kSuccess, 3.0f);
1669#else
1670 toast_manager_.Show("Testing not enabled in this build", ToastType::kWarning);
1671#endif
1672}
1673
1674void MenuOrchestrator::OnCheckRomVersion() {
1675 if (!editor_manager_)
1676 return;
1677 auto* rom = editor_manager_->GetCurrentRom();
1678 if (!rom || !rom->is_loaded())
1679 return;
1680
1681 // Check ZSCustomOverworld version
1682 uint8_t version = (*rom)[zelda3::OverworldCustomASMHasBeenApplied];
1683 std::string version_str =
1684 (version == 0xFF) ? "Vanilla" : absl::StrFormat("v%d", version);
1685
1686 toast_manager_.Show(
1687 absl::StrFormat("ROM: %s | ZSCustomOverworld: %s", rom->title().c_str(),
1688 version_str.c_str()),
1689 ToastType::kInfo, 5.0f);
1690}
1691
1692void MenuOrchestrator::OnUpgradeRom() {
1693 if (!editor_manager_)
1694 return;
1695 auto* rom = editor_manager_->GetCurrentRom();
1696 if (!rom || !rom->is_loaded())
1697 return;
1698
1699 toast_manager_.Show("Use Overworld Editor to upgrade ROM version",
1700 ToastType::kInfo, 4.0f);
1701}
1702
1703void MenuOrchestrator::OnToggleCustomLoading() {
1704 auto& flags = core::FeatureFlags::get();
1705 flags.overworld.kLoadCustomOverworld = !flags.overworld.kLoadCustomOverworld;
1706
1707 toast_manager_.Show(
1708 absl::StrFormat(
1709 "Custom Overworld Loading: %s",
1710 flags.overworld.kLoadCustomOverworld ? "Enabled" : "Disabled"),
1711 ToastType::kInfo);
1712}
1713
1714void MenuOrchestrator::OnToggleAsarPatch() {
1715 if (!editor_manager_)
1716 return;
1717 auto* rom = editor_manager_->GetCurrentRom();
1718 if (!rom || !rom->is_loaded())
1719 return;
1720
1721 auto& flags = core::FeatureFlags::get();
1722 flags.overworld.kApplyZSCustomOverworldASM =
1723 !flags.overworld.kApplyZSCustomOverworldASM;
1724
1725 toast_manager_.Show(
1726 absl::StrFormat(
1727 "ZSCustomOverworld ASM Application: %s",
1728 flags.overworld.kApplyZSCustomOverworldASM ? "Enabled" : "Disabled"),
1729 ToastType::kInfo);
1730}
1731
1732void MenuOrchestrator::OnLoadAsmFile() {
1733 toast_manager_.Show("ASM file loading not yet implemented",
1734 ToastType::kWarning);
1735}
1736
1737void MenuOrchestrator::OnShowAssemblyEditor() {
1738 if (editor_manager_) {
1739 editor_manager_->SwitchToEditor(EditorType::kAssembly);
1740 }
1741}
1742
1743void MenuOrchestrator::OnExportBpsPatch() {
1744 if (!editor_manager_)
1745 return;
1746 auto* rom = editor_manager_->GetCurrentRom();
1747 if (!rom || !rom->is_loaded())
1748 return;
1749
1750 // Ask user to select the original/clean ROM to diff against
1751 auto options = util::MakeRomFileDialogOptions();
1752 std::string original_path =
1754 if (original_path.empty()) {
1755 return; // User cancelled
1756 }
1757
1758 // Load the original ROM
1759 Rom original_rom;
1760 auto load_status = original_rom.LoadFromFile(original_path);
1761 if (!load_status.ok()) {
1762 toast_manager_.Show(absl::StrFormat("Failed to load original ROM: %s",
1763 load_status.message()),
1764 ToastType::kError);
1765 return;
1766 }
1767
1768 // Generate BPS patch
1769 std::vector<uint8_t> patch_data;
1770 auto create_status =
1771 util::CreateBpsPatch(original_rom.vector(), rom->vector(), patch_data);
1772 if (!create_status.ok()) {
1773 toast_manager_.Show(absl::StrFormat("Failed to create BPS patch: %s",
1774 create_status.message()),
1775 ToastType::kError);
1776 return;
1777 }
1778
1779 // Ask user where to save the patch
1780 std::string default_name = rom->short_name() + ".bps";
1781 std::string save_path =
1783 if (save_path.empty()) {
1784 return; // User cancelled
1785 }
1786
1787 // Ensure .bps extension
1788 if (save_path.size() < 4 ||
1789 save_path.substr(save_path.size() - 4) != ".bps") {
1790 save_path += ".bps";
1791 }
1792
1793 // Write the patch file
1794 std::ofstream file(save_path, std::ios::binary);
1795 if (!file.is_open()) {
1796 toast_manager_.Show(
1797 absl::StrFormat("Failed to open file for writing: %s", save_path),
1798 ToastType::kError);
1799 return;
1800 }
1801
1802 file.write(reinterpret_cast<const char*>(patch_data.data()),
1803 patch_data.size());
1804 file.close();
1805
1806 if (file.fail()) {
1807 toast_manager_.Show(
1808 absl::StrFormat("Failed to write patch file: %s", save_path),
1809 ToastType::kError);
1810 return;
1811 }
1812
1813 toast_manager_.Show(absl::StrFormat("BPS patch exported: %s (%zu bytes)",
1814 save_path, patch_data.size()),
1815 ToastType::kSuccess);
1816}
1817
1818void MenuOrchestrator::OnApplyBpsPatch() {
1819 if (!editor_manager_)
1820 return;
1821 auto* rom = editor_manager_->GetCurrentRom();
1822 if (!rom || !rom->is_loaded())
1823 return;
1824
1825 // Ask user to select a .bps file
1827 options.filters.push_back({"BPS Patch", "bps"});
1828 std::string patch_path = util::FileDialogWrapper::ShowOpenFileDialog(options);
1829 if (patch_path.empty()) {
1830 return; // User cancelled
1831 }
1832
1833 // Read the patch file
1834 std::ifstream file(patch_path, std::ios::binary);
1835 if (!file.is_open()) {
1836 toast_manager_.Show(
1837 absl::StrFormat("Failed to open patch file: %s", patch_path),
1838 ToastType::kError);
1839 return;
1840 }
1841
1842 std::vector<uint8_t> patch_data((std::istreambuf_iterator<char>(file)),
1843 std::istreambuf_iterator<char>());
1844 file.close();
1845
1846 if (patch_data.empty()) {
1847 toast_manager_.Show("Patch file is empty", ToastType::kError);
1848 return;
1849 }
1850
1851 // Apply the patch
1852 std::vector<uint8_t> patched_rom;
1853 auto apply_status =
1854 util::ApplyBpsPatch(rom->vector(), patch_data, patched_rom);
1855 if (!apply_status.ok()) {
1856 toast_manager_.Show(absl::StrFormat("Failed to apply BPS patch: %s",
1857 apply_status.message()),
1858 ToastType::kError);
1859 return;
1860 }
1861
1862 // Load the patched data into the ROM
1863 auto load_status = rom->LoadFromData(patched_rom);
1864 if (!load_status.ok()) {
1865 toast_manager_.Show(absl::StrFormat("Failed to load patched ROM data: %s",
1866 load_status.message()),
1867 ToastType::kError);
1868 return;
1869 }
1870
1871 rom->set_dirty(true);
1872 toast_manager_.Show("BPS patch applied successfully", ToastType::kSuccess);
1873}
1874
1875} // namespace editor
1876} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:270
void set_dirty(bool dirty)
Definition rom.h:157
const auto & vector() const
Definition rom.h:173
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:379
auto short_name() const
Definition rom.h:177
bool is_loaded() const
Definition rom.h:155
auto title() const
Definition rom.h:167
static Flags & get()
Definition features.h:119
The EditorManager controls the main editor window and manages the various editor classes.
bool SaveLayoutSnapshotAs(const std::string &name)
RightDrawerManager * right_drawer_manager()
Manages editor types, categories, and lifecycle.
virtual absl::Status Cut()=0
virtual absl::Status Copy()=0
virtual absl::Status Redo()=0
virtual std::string GetRedoDescription() const
Definition editor.h:295
virtual absl::Status Find()=0
virtual absl::Status Paste()=0
virtual absl::Status Undo()=0
virtual std::string GetUndoDescription() const
Definition editor.h:292
Fluent interface for building ImGui menus with icons.
MenuBuilder & Item(const char *label, const char *icon, Callback callback, const char *shortcut=nullptr, EnabledCheck enabled=nullptr, EnabledCheck checked=nullptr)
Add a menu item.
MenuBuilder & CustomMenu(const char *label, Callback draw_callback)
Add a custom menu with a callback for drawing dynamic content.
void Draw()
Draw the menu bar (call in main menu bar)
std::function< bool()> EnabledCheck
MenuBuilder & BeginMenu(const char *label, const char *icon=nullptr)
Begin a top-level menu.
MenuBuilder & Separator()
Add a separator.
MenuBuilder & EndMenu()
End the current menu/submenu.
MenuBuilder & BeginSubMenu(const char *label, const char *icon=nullptr, EnabledCheck enabled=nullptr)
Begin a submenu.
SessionCoordinator & session_coordinator_
WorkspaceWindowManager * window_manager_
MenuOrchestrator(EditorManager *editor_manager, MenuBuilder &menu_builder, RomFileManager &rom_manager, ProjectManager &project_manager, EditorRegistry &editor_registry, SessionCoordinator &session_coordinator, ToastManager &toast_manager, PopupManager &popup_manager)
void Show(const char *name)
Handles all project file operations with ROM-first workflow.
Handles all ROM file I/O operations.
High-level orchestrator for multi-session UI.
size_t GetActiveSessionId() const
Stable workspace identity that is never reused while this coordinator lives.
void SetEnabled(bool enabled)
Enable or disable the status bar.
Definition status_bar.h:71
Central registry for all editor cards with session awareness and dependency injection.
void HideAllWindowsInCategory(size_t session_id, const std::string &category)
std::vector< WindowDescriptor > GetWindowsInCategory(size_t session_id, const std::string &category) const
void SetWindowPinned(size_t session_id, const std::string &base_window_id, bool pinned)
void SetActiveCategory(const std::string &category, bool notify=true)
bool IsWindowOpen(size_t session_id, const std::string &base_window_id) const
bool OpenWindow(size_t session_id, const std::string &base_window_id)
std::vector< std::string > GetAllCategories(size_t session_id) const
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
void ShowAllWindowsInCategory(size_t session_id, const std::string &category)
std::vector< std::string > GetAvailableLocales() const
void SetLanguage(const std::string &locale)
static LanguageManager & Get()
const std::string & GetCurrentLocale() const
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
#define ICON_MD_DEVELOPER_MODE
Definition icons.h:549
#define ICON_MD_FOLDER_OPEN
Definition icons.h:813
#define ICON_MD_CONTENT_CUT
Definition icons.h:466
#define ICON_MD_SAVE_ALT
Definition icons.h:1645
#define ICON_MD_VOLUNTEER_ACTIVISM
Definition icons.h:2112
#define ICON_MD_SETTINGS
Definition icons.h:1699
#define ICON_MD_FILE_OPEN
Definition icons.h:747
#define ICON_MD_CHECK_BOX
Definition icons.h:398
#define ICON_MD_EXIT_TO_APP
Definition icons.h:699
#define ICON_MD_VIEW_QUILT
Definition icons.h:2094
#define ICON_MD_APPS
Definition icons.h:168
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_WORKSPACE_PREMIUM
Definition icons.h:2185
#define ICON_MD_BOOKMARKS
Definition icons.h:291
#define ICON_MD_MEMORY
Definition icons.h:1195
#define ICON_MD_STORAGE
Definition icons.h:1865
#define ICON_MD_UPGRADE
Definition icons.h:2047
#define ICON_MD_FOLDER_SPECIAL
Definition icons.h:815
#define ICON_MD_VIEW_LIST
Definition icons.h:2092
#define ICON_MD_SEARCH
Definition icons.h:1673
#define ICON_MD_NEW_RELEASES
Definition icons.h:1291
#define ICON_MD_PLAY_ARROW
Definition icons.h:1479
#define ICON_MD_SWAP_HORIZ
Definition icons.h:1896
#define ICON_MD_SAVE_AS
Definition icons.h:1646
#define ICON_MD_DESIGN_SERVICES
Definition icons.h:541
#define ICON_MD_INTEGRATION_INSTRUCTIONS
Definition icons.h:1008
#define ICON_MD_RESET_TV
Definition icons.h:1601
#define ICON_MD_TUNE
Definition icons.h:2022
#define ICON_MD_REFRESH
Definition icons.h:1572
#define ICON_MD_DIFFERENCE
Definition icons.h:559
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_CODE
Definition icons.h:434
#define ICON_MD_LABEL
Definition icons.h:1053
#define ICON_MD_REDO
Definition icons.h:1570
#define ICON_MD_SWITCH_ACCOUNT
Definition icons.h:1913
#define ICON_MD_VISIBILITY
Definition icons.h:2101
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_LANGUAGE
Definition icons.h:1061
#define ICON_MD_SPEED
Definition icons.h:1817
#define ICON_MD_CASTLE
Definition icons.h:380
#define ICON_MD_BUILD_CIRCLE
Definition icons.h:329
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_RESTORE
Definition icons.h:1605
#define ICON_MD_CONTENT_PASTE
Definition icons.h:467
#define ICON_MD_HOME
Definition icons.h:953
#define ICON_MD_ROUTE
Definition icons.h:1627
#define ICON_MD_VISIBILITY_OFF
Definition icons.h:2102
#define ICON_MD_DISPLAY_SETTINGS
Definition icons.h:587
#define ICON_MD_BOOKMARK_ADD
Definition icons.h:286
#define ICON_MD_VIEW_COMPACT
Definition icons.h:2085
#define ICON_MD_ADD
Definition icons.h:86
#define ICON_MD_DASHBOARD_CUSTOMIZE
Definition icons.h:518
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_SCIENCE
Definition icons.h:1656
#define ICON_MD_PLAY_CIRCLE
Definition icons.h:1480
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#define ICON_MD_TERMINAL
Definition icons.h:1951
#define ICON_MD_FLAG
Definition icons.h:784
#define ICON_MD_DESCRIPTION
Definition icons.h:539
#define ICON_MD_BUILD
Definition icons.h:328
#define ICON_MD_HORIZONTAL_RULE
Definition icons.h:960
#define ICON_MD_CREATE_NEW_FOLDER
Definition icons.h:483
#define ICON_MD_DASHBOARD
Definition icons.h:517
#define ICON_MD_SAVE
Definition icons.h:1644
#define ICON_MD_DELETE
Definition icons.h:530
#define ICON_MD_TAB
Definition icons.h:1930
#define ICON_MD_PEOPLE
Definition icons.h:1401
#define ICON_MD_FOLDER
Definition icons.h:809
#define ICON_MD_BACKUP
Definition icons.h:231
#define ICON_MD_CONTENT_COPY
Definition icons.h:465
#define ICON_MD_PUSH_PIN
Definition icons.h:1529
#define ICON_MD_CLOUD
Definition icons.h:423
#define ICON_MD_CLOSE
Definition icons.h:418
#define ICON_MD_ANALYTICS
Definition icons.h:154
#define ICON_MD_HELP
Definition icons.h:933
#define ICON_MD_RESTART_ALT
Definition icons.h:1602
#define ICON_MD_CHECK_BOX_OUTLINE_BLANK
Definition icons.h:399
#define ICON_MD_VERTICAL_SPLIT
Definition icons.h:2063
#define ICON_MD_VIEW_SIDEBAR
Definition icons.h:2095
#define ICON_MD_BOOKMARK_REMOVE
Definition icons.h:290
#define ICON_MD_UNDO
Definition icons.h:2039
#define ICON_MD_SMART_TOY
Definition icons.h:1781
#define ICON_MD_GROUP_ADD
Definition icons.h:899
#define SHORTCUT_CTRL_SHIFT(key)
#define SHORTCUT_CTRL(key)
constexpr const char * kSaveScope
absl::Span< const DrawerCatalogEntry > GetDrawerCatalog()
Switchable drawers in header-cycle order (excludes Tool Output).
absl::Status ApplyBpsPatch(const std::vector< uint8_t > &source, const std::vector< uint8_t > &patch, std::vector< uint8_t > &output)
Definition bps.cc:75
absl::Status CreateBpsPatch(const std::vector< uint8_t > &source, const std::vector< uint8_t > &target, std::vector< uint8_t > &patch)
Definition bps.cc:228
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
Definition file_util.cc:87
constexpr int OverworldCustomASMHasBeenApplied
Definition common.h:89
One entry in the shared right-drawer catalog (header / overflow / View).
std::vector< FileDialogFilter > filters
Definition file_util.h:17