8#include "absl/status/status.h"
9#include "absl/strings/str_format.h"
33#define SHORTCUT_CTRL(key) gui::FormatCtrlShortcut(ImGuiKey_##key).c_str()
34#define SHORTCUT_CTRL_SHIFT(key) \
35 gui::FormatCtrlShiftShortcut(ImGuiKey_##key).c_str()
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) {}
81 ImGui::OpenPopup(
"Save Layout Snapshot##menu_orch_save_snapshot");
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 =
91 ImGuiInputTextFlags_EnterReturnsTrue);
94 if ((ImGui::Button(
"Save", ImVec2(120, 0)) || submitted) && has_name) {
99 ImGui::CloseCurrentPopup();
102 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
104 ImGui::CloseCurrentPopup();
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); });
299 absl::StrFormat(
"%s Window Browser",
ICON_MD_APPS).c_str(),
322 if (all_categories.empty()) {
323 ImGui::TextDisabled(
"No windows available");
328 for (
const auto& category : all_categories) {
330 std::string label = category;
331 if (category == active_category) {
337 if (ImGui::BeginMenu(label.c_str())) {
341 ImGui::TextDisabled(
"No windows in this category");
355 for (
const auto& card : cards) {
358 const char* shortcut =
359 card.shortcut_hint.empty() ? nullptr : card.shortcut_hint.c_str();
362 std::string item_label =
369 if (ImGui::MenuItem(item_label.c_str(), shortcut)) {
396#ifdef YAZE_ENABLE_TESTING
409 AddCollaborationMenuItems();
432 std::map<std::string, std::vector<WorkflowItem>> grouped_items;
437 for (
const auto& category : categories) {
438 for (
const auto& descriptor :
440 if (descriptor.workflow_group.empty()) {
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;
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]() {
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));
468 const std::string group = action.group.empty() ?
"General" : action.group;
469 grouped_items[group].push_back(action);
472 if (grouped_items.empty()) {
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;
483 return lhs.label < rhs.label;
486 for (
const auto& item : items) {
489 item.label.c_str(), item.callback,
490 item.shortcut.empty() ? nullptr : item.shortcut.c_str(), enabled);
497void MenuOrchestrator::AddRomAnalysisMenuItems() {
501 "ROM Information",
ICON_MD_INFO, [
this]() { OnShowRomInfo(); },
502 nullptr, [
this]() {
return HasActiveRom(); })
505 nullptr, [
this]() {
return HasActiveRom(); })
508 [
this]() { popup_manager_.Show(PopupID::kRomBackups); },
nullptr,
509 [
this]() {
return HasActiveRom(); })
512 nullptr, [
this]() {
return HasActiveRom(); })
515 [
this]() { OnRunDataIntegrityCheck(); },
nullptr,
516 [
this]() {
return HasActiveRom(); })
519 nullptr, [
this]() {
return HasActiveRom(); })
523 [
this]() { OnExportBpsPatch(); },
nullptr,
524 [
this]() {
return HasActiveRom(); })
526 "Apply BPS Patch...",
ICON_MD_BUILD, [
this]() { OnApplyBpsPatch(); },
527 nullptr, [
this]() {
return HasActiveRom(); })
531 menu_builder_.BeginSubMenu(
"ZSCustomOverworld",
ICON_MD_CODE)
533 "Check ROM Version",
ICON_MD_INFO, [
this]() { OnCheckRomVersion(); },
534 nullptr, [
this]() {
return HasActiveRom(); })
537 [
this]() {
return HasActiveRom(); })
539 [
this]() { OnToggleCustomLoading(); })
543void MenuOrchestrator::AddAsarIntegrationMenuItems() {
545 menu_builder_.BeginSubMenu(
"Asar Integration",
ICON_MD_BUILD)
547 [
this]() { popup_manager_.Show(PopupID::kAsarIntegration); })
549 "Toggle ASM Patch",
ICON_MD_CODE, [
this]() { OnToggleAsarPatch(); },
550 nullptr, [
this]() {
return HasActiveRom(); })
555void MenuOrchestrator::AddDevelopmentMenuItems() {
559 "Memory Editor",
ICON_MD_MEMORY, [
this]() { OnShowMemoryEditor(); },
560 nullptr, [
this]() {
return HasActiveRom(); })
562 [
this]() { OnShowAssemblyEditor(); })
564 [
this]() { popup_manager_.Show(PopupID::kFeatureFlags); })
566 [
this]() { OnShowPerformanceDashboard(); })
570void MenuOrchestrator::AddTestingMenuItems() {
573#ifdef YAZE_ENABLE_TESTING
581 [
this]() { OnRunIntegrationTests(); })
584 menu_builder_.DisabledItem(
585 "Testing support disabled (YAZE_ENABLE_TESTING=OFF)",
ICON_MD_INFO);
587 menu_builder_.EndMenu();
591void MenuOrchestrator::AddCollaborationMenuItems() {
595 [
this]() { OnStartCollaboration(); })
597 [
this]() { OnJoinCollaboration(); })
599 [
this]() { OnShowNetworkStatus(); })
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();
616 nullptr,
false, HasActiveRom())) {
617 OnDuplicateCurrentSession();
622 OnCloseCurrentSession();
629 OnShowSessionSwitcher();
633 OnShowSessionManager();
641void MenuOrchestrator::AddLayoutSubmenu() {
642 const bool layout_enabled = HasCurrentEditor();
643 auto apply_preset = [
this](
const char* name) {
645 editor_manager_->ApplyLayoutPreset(name);
647 auto apply_profile = [
this](
const char* name) {
649 editor_manager_->ApplyLayoutProfile(name);
652 if (ImGui::BeginMenu(
654 if (ImGui::MenuItem(absl::StrFormat(
"%s Open Layout Designer",
657 nullptr,
false, window_manager_ !=
nullptr)) {
658 OnShowLayoutDesigner();
662 if (ImGui::MenuItem(absl::StrFormat(
"%s Save Layout",
ICON_MD_SAVE).c_str(),
664 OnSaveWorkspaceLayout();
669 OnLoadWorkspaceLayout();
673 OnResetWorkspaceLayout();
678 nullptr,
false, layout_enabled)) {
680 editor_manager_->ResetCurrentEditorLayout();
684 if (ImGui::BeginMenu(
690 nullptr,
false, layout_enabled)) {
691 save_snapshot_name_buffer_[0] =
'\0';
692 open_save_snapshot_modal_ =
true;
696 std::vector<std::string> named =
697 editor_manager_ ? editor_manager_->ListLayoutSnapshots()
698 : std::vector<std::string>{};
699 if (!named.empty()) {
701 for (
const auto& name : named) {
702 ImGui::PushID(name.c_str());
705 nullptr,
false, layout_enabled)) {
707 editor_manager_->RestoreLayoutSnapshot(name);
709 ImGui::SameLine(ImGui::GetContentRegionAvail().x);
712 editor_manager_->DeleteLayoutSnapshot(name);
723 nullptr,
false, layout_enabled)) {
725 editor_manager_->CaptureTemporaryLayoutSnapshot();
729 nullptr,
false, layout_enabled)) {
731 editor_manager_->RestoreTemporaryLayoutSnapshot();
736 nullptr,
false, layout_enabled)) {
738 editor_manager_->ClearTemporaryLayoutSnapshot();
744 if (ImGui::BeginMenu(
746 if (ImGui::MenuItem(absl::StrFormat(
"%s Code",
ICON_MD_CODE).c_str(),
747 nullptr,
false, layout_enabled)) {
748 apply_profile(
"code");
752 false, layout_enabled)) {
753 apply_profile(
"debug");
755 if (ImGui::MenuItem(absl::StrFormat(
"%s Mapping",
ICON_MD_MAP).c_str(),
756 nullptr,
false, layout_enabled)) {
757 apply_profile(
"mapping");
761 nullptr,
false, layout_enabled)) {
762 apply_profile(
"chat");
767 nullptr,
false, layout_enabled)) {
768 apply_preset(
"Minimal");
772 nullptr,
false, layout_enabled)) {
773 OnLoadDeveloperLayout();
777 nullptr,
false, layout_enabled)) {
778 OnLoadDesignerLayout();
780 if (ImGui::MenuItem(absl::StrFormat(
"%s Modder",
ICON_MD_BUILD).c_str(),
781 nullptr,
false, layout_enabled)) {
782 OnLoadModderLayout();
785 absl::StrFormat(
"%s Overworld Expert",
ICON_MD_MAP).c_str(),
786 nullptr,
false, layout_enabled)) {
787 apply_preset(
"Overworld Expert");
791 nullptr,
false, layout_enabled)) {
792 apply_preset(
"Dungeon Expert");
796 false, layout_enabled)) {
797 apply_preset(
"Testing");
801 false, layout_enabled)) {
802 apply_preset(
"Audio");
806 absl::StrFormat(
"%s Manage Presets...",
ICON_MD_TUNE).c_str())) {
807 OnShowLayoutPresets();
817void MenuOrchestrator::AddSidebarSubmenu() {
818 if (!user_settings_) {
822 if (!ImGui::BeginMenu(
827 auto persist = [
this]() {
828 (void)user_settings_->Save();
830 auto& prefs = user_settings_->prefs();
834 nullptr,
false, !prefs.sidebar_order.empty())) {
835 prefs.sidebar_order.clear();
840 nullptr,
false, !prefs.sidebar_hidden.empty())) {
841 prefs.sidebar_hidden.clear();
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);
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)
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);
865 if (ImGui::BeginMenu(
867 if (pinned_list.empty()) {
868 ImGui::TextDisabled(
"(none)");
870 for (
const auto& cat : pinned_list) {
871 ImGui::PushID(cat.c_str());
873 absl::StrFormat(
"%s Unpin %s",
ICON_MD_CLOSE, cat).c_str())) {
874 prefs.sidebar_pinned.erase(cat);
883 if (ImGui::BeginMenu(
885 if (hidden_list.empty()) {
886 ImGui::TextDisabled(
"(none)");
888 for (
const auto& cat : hidden_list) {
889 ImGui::PushID(cat.c_str());
893 prefs.sidebar_hidden.erase(cat);
906 if (ImGui::BeginMenu(absl::StrFormat(
"%s Customize",
ICON_MD_TUNE).c_str())) {
907 if (categories.empty()) {
908 ImGui::TextDisabled(
"No categories available");
910 for (
const auto& cat : categories) {
911 if (cat == WorkspaceWindowManager::kDashboardCategory)
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,
920 prefs.sidebar_pinned.erase(cat);
922 prefs.sidebar_pinned.insert(cat);
926 if (ImGui::MenuItem(hidden ?
"Show on sidebar" :
"Hide from sidebar",
929 prefs.sidebar_hidden.erase(cat);
931 prefs.sidebar_hidden.insert(cat);
946void MenuOrchestrator::BuildHelpMenu() {
947 menu_builder_.BeginMenu(
"Help");
949 menu_builder_.EndMenu();
952void MenuOrchestrator::AddHelpMenuItems() {
956 [
this]() { OnShowGettingStarted(); })
960 if (window_manager_) {
961 window_manager_->TriggerShowShortcuts();
966 [
this]() { OnShowBuildInstructions(); })
970 [
this]() { OnShowSupportedFeatures(); })
974 [
this]() { OnShowTroubleshooting(); })
976 [
this]() { OnShowContributing(); })
978 .Item(
"About",
ICON_MD_INFO, [
this]() { OnShowAbout(); },
"F1");
980 menu_builder_.Separator();
982 for (
const std::string& locale :
985 locale.c_str(),
nullptr,
992 menu_builder_.EndMenu();
996void MenuOrchestrator::ClearMenu() {
997 menu_builder_.Clear();
1000void MenuOrchestrator::RefreshMenu() {
1001 menu_needs_refresh_ =
true;
1005void MenuOrchestrator::OnOpenRom() {
1007 if (editor_manager_) {
1008 auto status = editor_manager_->LoadRom();
1010 toast_manager_.Show(
1011 absl::StrFormat(
"Failed to load ROM: %s", status.message()),
1017void MenuOrchestrator::OnSaveRom() {
1019 if (editor_manager_) {
1020 auto status = editor_manager_->SaveRom();
1022 if (absl::IsCancelled(status)) {
1025 toast_manager_.Show(
1026 absl::StrFormat(
"Failed to save ROM: %s", status.message()),
1032void MenuOrchestrator::OnSaveRomAs() {
1033 popup_manager_.Show(PopupID::kSaveAs);
1036void MenuOrchestrator::OnCreateProject() {
1038 if (editor_manager_) {
1039 auto status = editor_manager_->CreateNewProject();
1041 toast_manager_.Show(
1042 absl::StrFormat(
"Failed to create project: %s", status.message()),
1048void MenuOrchestrator::OnOpenProject() {
1050 if (editor_manager_) {
1051 auto status = editor_manager_->OpenProject();
1053 toast_manager_.Show(
1054 absl::StrFormat(
"Failed to open project: %s", status.message()),
1060void MenuOrchestrator::OnSaveProject() {
1062 if (editor_manager_) {
1063 auto status = editor_manager_->SaveProject();
1065 toast_manager_.Show(
1066 absl::StrFormat(
"Failed to save project: %s", status.message()),
1069 toast_manager_.Show(
"Project saved successfully", ToastType::kSuccess);
1074void MenuOrchestrator::OnSaveProjectAs() {
1076 if (editor_manager_) {
1077 auto status = editor_manager_->SaveProjectAs();
1079 toast_manager_.Show(
1080 absl::StrFormat(
"Failed to save project as: %s", status.message()),
1086void MenuOrchestrator::OnShowProjectManagement() {
1088 if (editor_manager_) {
1089 editor_manager_->ShowProjectManagement();
1093void MenuOrchestrator::OnShowProjectFileEditor() {
1095 if (editor_manager_) {
1096 editor_manager_->ShowProjectFileEditor();
1101void MenuOrchestrator::OnUndo() {
1102 if (editor_manager_) {
1103 auto* current_editor = editor_manager_->GetCurrentEditor();
1104 if (current_editor) {
1107 auto status = current_editor->
Undo();
1109 if (!desc.empty()) {
1110 toast_manager_.Show(absl::StrFormat(
"Undid: %s", desc),
1111 ToastType::kInfo, 2.0f);
1114 toast_manager_.Show(
1115 absl::StrFormat(
"Undo failed: %s", status.message()),
1122void MenuOrchestrator::OnRedo() {
1123 if (editor_manager_) {
1124 auto* current_editor = editor_manager_->GetCurrentEditor();
1125 if (current_editor) {
1128 auto status = current_editor->
Redo();
1130 if (!desc.empty()) {
1131 toast_manager_.Show(absl::StrFormat(
"Redid: %s", desc),
1132 ToastType::kInfo, 2.0f);
1135 toast_manager_.Show(
1136 absl::StrFormat(
"Redo failed: %s", status.message()),
1143void MenuOrchestrator::OnCut() {
1144 if (editor_manager_) {
1145 auto* current_editor = editor_manager_->GetCurrentEditor();
1146 if (current_editor) {
1147 auto status = current_editor->
Cut();
1149 toast_manager_.Show(absl::StrFormat(
"Cut failed: %s", status.message()),
1156void MenuOrchestrator::OnCopy() {
1157 if (editor_manager_) {
1158 auto* current_editor = editor_manager_->GetCurrentEditor();
1159 if (current_editor) {
1160 auto status = current_editor->
Copy();
1162 toast_manager_.Show(
1163 absl::StrFormat(
"Copy failed: %s", status.message()),
1170void MenuOrchestrator::OnPaste() {
1171 if (editor_manager_) {
1172 auto* current_editor = editor_manager_->GetCurrentEditor();
1173 if (current_editor) {
1174 auto status = current_editor->
Paste();
1176 toast_manager_.Show(
1177 absl::StrFormat(
"Paste failed: %s", status.message()),
1184void MenuOrchestrator::OnFind() {
1185 if (editor_manager_) {
1186 auto* current_editor = editor_manager_->GetCurrentEditor();
1187 if (current_editor) {
1188 auto status = current_editor->
Find();
1190 toast_manager_.Show(
1191 absl::StrFormat(
"Find failed: %s", status.message()),
1201 if (editor_manager_) {
1202 editor_manager_->SwitchToEditor(editor_type);
1206void MenuOrchestrator::OnShowEditorSelection() {
1208 if (editor_manager_) {
1209 if (
auto* ui = editor_manager_->ui_coordinator()) {
1210 ui->ShowEditorSelection();
1215void MenuOrchestrator::OnShowDisplaySettings() {
1216 popup_manager_.Show(PopupID::kDisplaySettings);
1219void MenuOrchestrator::OnShowHexEditor() {
1221 if (editor_manager_) {
1222 editor_manager_->window_manager().OpenWindow(
1223 editor_manager_->GetCurrentSessionId(),
"Hex Editor");
1227void MenuOrchestrator::OnShowPanelBrowser() {
1228 if (editor_manager_) {
1229 if (
auto* ui = editor_manager_->ui_coordinator()) {
1230 ui->SetWindowBrowserVisible(
true);
1235void MenuOrchestrator::OnShowPanelFinder() {
1236 if (editor_manager_) {
1237 if (
auto* ui = editor_manager_->ui_coordinator()) {
1238 ui->ShowPanelFinder();
1243void MenuOrchestrator::OnShowWelcomeScreen() {
1244 if (editor_manager_) {
1245 if (
auto* ui = editor_manager_->ui_coordinator()) {
1246 ui->SetWelcomeScreenVisible(
true);
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);
1260void MenuOrchestrator::OnShowProposalDrawer() {
1261 if (editor_manager_) {
1262 if (
auto* ui = editor_manager_->ui_coordinator()) {
1263 ui->SetProposalDrawerVisible(
true);
1270void MenuOrchestrator::OnCreateNewSession() {
1271 session_coordinator_.CreateNewSession();
1274void MenuOrchestrator::OnDuplicateCurrentSession() {
1275 session_coordinator_.DuplicateCurrentSession();
1278void MenuOrchestrator::OnCloseCurrentSession() {
1279 if (editor_manager_) {
1280 editor_manager_->CloseCurrentSession();
1282 session_coordinator_.CloseCurrentSession();
1286void MenuOrchestrator::OnShowSessionSwitcher() {
1288 if (editor_manager_) {
1289 if (
auto* ui = editor_manager_->ui_coordinator()) {
1290 ui->ShowSessionSwitcher();
1295void MenuOrchestrator::OnShowSessionManager() {
1296 popup_manager_.Show(PopupID::kSessionManager);
1300void MenuOrchestrator::OnShowAllWindows() {
1302 if (editor_manager_) {
1303 if (
auto* ui = editor_manager_->ui_coordinator()) {
1304 ui->ShowAllWindows();
1309void MenuOrchestrator::OnHideAllWindows() {
1311 if (editor_manager_) {
1312 editor_manager_->HideAllWindows();
1316void MenuOrchestrator::OnResetWorkspaceLayout() {
1318 if (editor_manager_) {
1319 editor_manager_->QueueDeferredAction([
this]() {
1320 editor_manager_->ResetWorkspaceLayout();
1321 toast_manager_.Show(
"Layout reset to default", ToastType::kInfo);
1326void MenuOrchestrator::OnSaveWorkspaceLayout() {
1328 if (editor_manager_) {
1329 editor_manager_->SaveWorkspaceLayout();
1333void MenuOrchestrator::OnLoadWorkspaceLayout() {
1335 if (editor_manager_) {
1336 editor_manager_->LoadWorkspaceLayout();
1340void MenuOrchestrator::OnShowLayoutPresets() {
1341 popup_manager_.Show(PopupID::kLayoutPresets);
1344void MenuOrchestrator::OnShowLayoutDesigner() {
1346 if (manager ==
nullptr && editor_manager_ !=
nullptr) {
1347 manager = &editor_manager_->window_manager();
1349 if (manager ==
nullptr) {
1350 toast_manager_.Show(
"Layout Designer unavailable: no window manager",
1358 WorkspaceWindowManager::kDashboardCategory) {
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",
1378void MenuOrchestrator::OnLoadDeveloperLayout() {
1379 if (editor_manager_) {
1380 editor_manager_->ApplyLayoutPreset(
"Developer");
1384void MenuOrchestrator::OnLoadDesignerLayout() {
1385 if (editor_manager_) {
1386 editor_manager_->ApplyLayoutPreset(
"Designer");
1390void MenuOrchestrator::OnLoadModderLayout() {
1391 if (editor_manager_) {
1392 editor_manager_->ApplyLayoutPreset(
"Modder");
1397void MenuOrchestrator::OnShowGlobalSearch() {
1398 if (editor_manager_) {
1399 if (
auto* ui = editor_manager_->ui_coordinator()) {
1400 ui->ShowGlobalSearch();
1405void MenuOrchestrator::OnShowCommandPalette() {
1406 if (editor_manager_) {
1407 if (
auto* ui = editor_manager_->ui_coordinator()) {
1408 ui->ShowCommandPalette();
1413void MenuOrchestrator::OnShowPerformanceDashboard() {
1414 if (editor_manager_) {
1415 if (
auto* ui = editor_manager_->ui_coordinator()) {
1416 ui->SetPerformanceDashboardVisible(
true);
1421void MenuOrchestrator::OnShowImGuiDemo() {
1422 if (editor_manager_) {
1423 editor_manager_->ShowImGuiDemo();
1427void MenuOrchestrator::OnShowImGuiMetrics() {
1428 if (editor_manager_) {
1429 editor_manager_->ShowImGuiMetrics();
1433void MenuOrchestrator::OnShowMemoryEditor() {
1434 if (editor_manager_) {
1435 editor_manager_->window_manager().OpenWindow(
1436 editor_manager_->GetCurrentSessionId(),
"Memory Editor");
1440void MenuOrchestrator::OnShowResourceLabelManager() {
1441 if (editor_manager_) {
1442 if (
auto* ui = editor_manager_->ui_coordinator()) {
1443 ui->SetResourceLabelManagerVisible(
true);
1448#ifdef YAZE_ENABLE_TESTING
1449void MenuOrchestrator::OnShowTestDashboard() {
1450 if (editor_manager_) {
1451 editor_manager_->ShowTestDashboard();
1455void MenuOrchestrator::OnRunAllTests() {
1456 toast_manager_.Show(
"Running all tests...", ToastType::kInfo);
1460void MenuOrchestrator::OnRunUnitTests() {
1461 toast_manager_.Show(
"Running unit tests...", ToastType::kInfo);
1465void MenuOrchestrator::OnRunIntegrationTests() {
1466 toast_manager_.Show(
"Running integration tests...", ToastType::kInfo);
1470void MenuOrchestrator::OnRunE2ETests() {
1471 toast_manager_.Show(
1472 "E2E runner is not wired in-app yet. Use scripts/agents/run-tests.sh or "
1474 ToastType::kWarning);
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);
1486void MenuOrchestrator::OnJoinCollaboration() {
1487 toast_manager_.Show(
1488 "Join collaboration is not wired yet. Use the web client + yaze-server.",
1489 ToastType::kWarning);
1492void MenuOrchestrator::OnShowNetworkStatus() {
1493 toast_manager_.Show(
"Network status panel is not implemented yet.",
1494 ToastType::kWarning);
1499void MenuOrchestrator::OnShowAbout() {
1500 popup_manager_.Show(PopupID::kAbout);
1503void MenuOrchestrator::OnShowGettingStarted() {
1504 popup_manager_.Show(PopupID::kGettingStarted);
1507void MenuOrchestrator::OnShowBuildInstructions() {
1508 popup_manager_.Show(PopupID::kBuildInstructions);
1511void MenuOrchestrator::OnShowCLIUsage() {
1512 popup_manager_.Show(PopupID::kCLIUsage);
1515void MenuOrchestrator::OnShowTroubleshooting() {
1516 popup_manager_.Show(PopupID::kTroubleshooting);
1519void MenuOrchestrator::OnShowContributing() {
1520 popup_manager_.Show(PopupID::kContributing);
1523void MenuOrchestrator::OnShowWhatsNew() {
1524 popup_manager_.Show(PopupID::kWhatsNew);
1527void MenuOrchestrator::OnShowSupportedFeatures() {
1528 popup_manager_.Show(PopupID::kSupportedFeatures);
1532void MenuOrchestrator::OnShowRomInfo() {
1533 popup_manager_.Show(PopupID::kRomInfo);
1536void MenuOrchestrator::OnCreateBackup() {
1537 if (editor_manager_) {
1538 auto status = rom_manager_.CreateBackup(editor_manager_->GetCurrentRom());
1540 toast_manager_.Show(
"Backup created successfully", ToastType::kSuccess);
1542 toast_manager_.Show(
1543 absl::StrFormat(
"Backup failed: %s", status.message()),
1549void MenuOrchestrator::OnValidateRom() {
1550 if (editor_manager_) {
1551 auto status = rom_manager_.ValidateRom(editor_manager_->GetCurrentRom());
1553 toast_manager_.Show(
"ROM validation passed", ToastType::kSuccess);
1555 toast_manager_.Show(
1556 absl::StrFormat(
"ROM validation failed: %s", status.message()),
1562void MenuOrchestrator::OnShowSettings() {
1564 if (editor_manager_) {
1565 editor_manager_->SwitchToEditor(EditorType::kSettings);
1569void MenuOrchestrator::OnQuit() {
1570 if (editor_manager_) {
1571 editor_manager_->Quit();
1576bool MenuOrchestrator::CanSaveRom()
const {
1577 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() :
nullptr;
1578 return rom ? rom_manager_.IsRomLoaded(rom) :
false;
1581bool MenuOrchestrator::CanSaveProject()
const {
1582 return project_manager_.HasActiveProject();
1585bool MenuOrchestrator::HasActiveRom()
const {
1586 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() :
nullptr;
1587 return rom ? rom_manager_.IsRomLoaded(rom) :
false;
1590bool MenuOrchestrator::HasActiveProject()
const {
1591 return project_manager_.HasActiveProject();
1594bool MenuOrchestrator::HasProjectFile()
const {
1597 const auto* project =
1598 editor_manager_ ? editor_manager_->GetCurrentProject() :
nullptr;
1599 return project && !project->filepath.empty();
1602bool MenuOrchestrator::HasCurrentEditor()
const {
1603 return editor_manager_ && editor_manager_->GetCurrentEditor() !=
nullptr;
1606bool MenuOrchestrator::HasMultipleSessions()
const {
1607 return session_coordinator_.HasMultipleSessions();
1611std::string MenuOrchestrator::GetRomFilename()
const {
1612 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() :
nullptr;
1613 return rom ? rom_manager_.GetRomFilename(rom) :
"";
1616std::string MenuOrchestrator::GetProjectName()
const {
1617 return project_manager_.GetProjectName();
1620std::string MenuOrchestrator::GetCurrentEditorName()
const {
1622 return "Unknown Editor";
1626std::string MenuOrchestrator::GetShortcutForAction(
1627 const std::string& action)
const {
1632void MenuOrchestrator::RegisterGlobalShortcuts() {
1640void MenuOrchestrator::OnRunDataIntegrityCheck() {
1641#ifdef YAZE_ENABLE_TESTING
1642 if (!editor_manager_)
1644 auto* rom = editor_manager_->GetCurrentRom();
1648 toast_manager_.Show(
"Running ROM integrity tests...", ToastType::kInfo);
1651 toast_manager_.Show(
"Data integrity check completed", ToastType::kSuccess,
1654 toast_manager_.Show(
"Testing not enabled in this build", ToastType::kWarning);
1658void MenuOrchestrator::OnTestSaveLoad() {
1659#ifdef YAZE_ENABLE_TESTING
1660 if (!editor_manager_)
1662 auto* rom = editor_manager_->GetCurrentRom();
1666 toast_manager_.Show(
"Running ROM save/load tests...", ToastType::kInfo);
1668 toast_manager_.Show(
"Save/load test completed", ToastType::kSuccess, 3.0f);
1670 toast_manager_.Show(
"Testing not enabled in this build", ToastType::kWarning);
1674void MenuOrchestrator::OnCheckRomVersion() {
1675 if (!editor_manager_)
1677 auto* rom = editor_manager_->GetCurrentRom();
1683 std::string version_str =
1684 (version == 0xFF) ?
"Vanilla" : absl::StrFormat(
"v%d", version);
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);
1692void MenuOrchestrator::OnUpgradeRom() {
1693 if (!editor_manager_)
1695 auto* rom = editor_manager_->GetCurrentRom();
1699 toast_manager_.Show(
"Use Overworld Editor to upgrade ROM version",
1700 ToastType::kInfo, 4.0f);
1703void MenuOrchestrator::OnToggleCustomLoading() {
1705 flags.overworld.kLoadCustomOverworld = !flags.overworld.kLoadCustomOverworld;
1707 toast_manager_.Show(
1709 "Custom Overworld Loading: %s",
1710 flags.overworld.kLoadCustomOverworld ?
"Enabled" :
"Disabled"),
1714void MenuOrchestrator::OnToggleAsarPatch() {
1715 if (!editor_manager_)
1717 auto* rom = editor_manager_->GetCurrentRom();
1722 flags.overworld.kApplyZSCustomOverworldASM =
1723 !flags.overworld.kApplyZSCustomOverworldASM;
1725 toast_manager_.Show(
1727 "ZSCustomOverworld ASM Application: %s",
1728 flags.overworld.kApplyZSCustomOverworldASM ?
"Enabled" :
"Disabled"),
1732void MenuOrchestrator::OnLoadAsmFile() {
1733 toast_manager_.Show(
"ASM file loading not yet implemented",
1734 ToastType::kWarning);
1737void MenuOrchestrator::OnShowAssemblyEditor() {
1738 if (editor_manager_) {
1739 editor_manager_->SwitchToEditor(EditorType::kAssembly);
1743void MenuOrchestrator::OnExportBpsPatch() {
1744 if (!editor_manager_)
1746 auto* rom = editor_manager_->GetCurrentRom();
1752 std::string original_path =
1754 if (original_path.empty()) {
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()),
1769 std::vector<uint8_t> patch_data;
1770 auto create_status =
1772 if (!create_status.ok()) {
1773 toast_manager_.Show(absl::StrFormat(
"Failed to create BPS patch: %s",
1774 create_status.message()),
1780 std::string default_name = rom->
short_name() +
".bps";
1781 std::string save_path =
1783 if (save_path.empty()) {
1788 if (save_path.size() < 4 ||
1789 save_path.substr(save_path.size() - 4) !=
".bps") {
1790 save_path +=
".bps";
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),
1802 file.write(
reinterpret_cast<const char*
>(patch_data.data()),
1807 toast_manager_.Show(
1808 absl::StrFormat(
"Failed to write patch file: %s", save_path),
1813 toast_manager_.Show(absl::StrFormat(
"BPS patch exported: %s (%zu bytes)",
1814 save_path, patch_data.size()),
1815 ToastType::kSuccess);
1818void MenuOrchestrator::OnApplyBpsPatch() {
1819 if (!editor_manager_)
1821 auto* rom = editor_manager_->GetCurrentRom();
1827 options.
filters.push_back({
"BPS Patch",
"bps"});
1829 if (patch_path.empty()) {
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),
1842 std::vector<uint8_t> patch_data((std::istreambuf_iterator<char>(file)),
1843 std::istreambuf_iterator<char>());
1846 if (patch_data.empty()) {
1847 toast_manager_.Show(
"Patch file is empty", ToastType::kError);
1852 std::vector<uint8_t> patched_rom;
1855 if (!apply_status.ok()) {
1856 toast_manager_.Show(absl::StrFormat(
"Failed to apply BPS patch: %s",
1857 apply_status.message()),
1864 if (!load_status.ok()) {
1865 toast_manager_.Show(absl::StrFormat(
"Failed to load patched ROM data: %s",
1866 load_status.message()),
1872 toast_manager_.Show(
"BPS patch applied successfully", ToastType::kSuccess);
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
void set_dirty(bool dirty)
const auto & vector() const
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
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
virtual absl::Status Find()=0
virtual absl::Status Paste()=0
virtual absl::Status Undo()=0
virtual std::string GetUndoDescription() const
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.
Central registry for all editor cards with session awareness and dependency injection.
void HideAllWindowsInCategory(size_t session_id, const std::string &category)
size_t GetActiveSessionId() const
std::vector< WindowDescriptor > GetWindowsInCategory(size_t session_id, const std::string &category) const
void ToggleSidebarVisibility()
void SetWindowPinned(size_t session_id, const std::string &base_window_id, bool pinned)
void SetActiveCategory(const std::string &category, bool notify=true)
std::string GetActiveCategory() const
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
void HideAllWindowsInSession(size_t session_id)
void ShowAllWindowsInSession(size_t session_id)
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
bool IsSidebarVisible() const
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
#define ICON_MD_FOLDER_OPEN
#define ICON_MD_CONTENT_CUT
#define ICON_MD_VOLUNTEER_ACTIVISM
#define ICON_MD_FILE_OPEN
#define ICON_MD_CHECK_BOX
#define ICON_MD_EXIT_TO_APP
#define ICON_MD_VIEW_QUILT
#define ICON_MD_WORKSPACE_PREMIUM
#define ICON_MD_BOOKMARKS
#define ICON_MD_FOLDER_SPECIAL
#define ICON_MD_VIEW_LIST
#define ICON_MD_NEW_RELEASES
#define ICON_MD_PLAY_ARROW
#define ICON_MD_SWAP_HORIZ
#define ICON_MD_DESIGN_SERVICES
#define ICON_MD_INTEGRATION_INSTRUCTIONS
#define ICON_MD_DIFFERENCE
#define ICON_MD_SWITCH_ACCOUNT
#define ICON_MD_VISIBILITY
#define ICON_MD_BUG_REPORT
#define ICON_MD_BUILD_CIRCLE
#define ICON_MD_MUSIC_NOTE
#define ICON_MD_CONTENT_PASTE
#define ICON_MD_VISIBILITY_OFF
#define ICON_MD_DISPLAY_SETTINGS
#define ICON_MD_BOOKMARK_ADD
#define ICON_MD_VIEW_COMPACT
#define ICON_MD_DASHBOARD_CUSTOMIZE
#define ICON_MD_PLAY_CIRCLE
#define ICON_MD_CHECK_CIRCLE
#define ICON_MD_DESCRIPTION
#define ICON_MD_HORIZONTAL_RULE
#define ICON_MD_CREATE_NEW_FOLDER
#define ICON_MD_DASHBOARD
#define ICON_MD_CONTENT_COPY
#define ICON_MD_ANALYTICS
#define ICON_MD_RESTART_ALT
#define ICON_MD_CHECK_BOX_OUTLINE_BLANK
#define ICON_MD_VERTICAL_SPLIT
#define ICON_MD_VIEW_SIDEBAR
#define ICON_MD_BOOKMARK_REMOVE
#define ICON_MD_SMART_TOY
#define ICON_MD_GROUP_ADD
std::vector< ActionDef > GetAll()
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)
absl::Status CreateBpsPatch(const std::vector< uint8_t > &source, const std::vector< uint8_t > &target, std::vector< uint8_t > &patch)
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
constexpr int OverworldCustomASMHasBeenApplied
One entry in the shared right-drawer catalog (header / overflow / View).
std::vector< FileDialogFilter > filters