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