7#include "absl/status/status.h"
8#include "absl/strings/str_format.h"
30#define SHORTCUT_CTRL(key) gui::FormatCtrlShortcut(ImGuiKey_##key).c_str()
31#define SHORTCUT_CTRL_SHIFT(key) \
32 gui::FormatCtrlShiftShortcut(ImGuiKey_##key).c_str()
42 : editor_manager_(editor_manager),
43 menu_builder_(menu_builder),
44 rom_manager_(rom_manager),
45 project_manager_(project_manager),
46 editor_registry_(editor_registry),
47 session_coordinator_(session_coordinator),
48 toast_manager_(toast_manager),
49 popup_manager_(popup_manager) {}
72 ImGui::OpenPopup(
"Save Layout Snapshot##menu_orch_save_snapshot");
75 if (ImGui::BeginPopupModal(
"Save Layout Snapshot##menu_orch_save_snapshot",
76 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
77 ImGui::TextUnformatted(
"Snapshot name:");
78 ImGui::SetNextItemWidth(320.0f);
79 const bool submitted =
82 ImGuiInputTextFlags_EnterReturnsTrue);
85 if ((ImGui::Button(
"Save", ImVec2(120, 0)) || submitted) && has_name) {
90 ImGui::CloseCurrentPopup();
93 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
95 ImGui::CloseCurrentPopup();
279 const auto layout_enabled = [
this]() {
291 nullptr, layout_enabled)
299 nullptr, layout_enabled)
307 nullptr, layout_enabled)
315 nullptr, layout_enabled)
334 nullptr, layout_enabled)
354 absl::StrFormat(
"%s Window Browser",
ICON_MD_APPS).c_str(),
377 if (all_categories.empty()) {
378 ImGui::TextDisabled(
"No windows available");
383 for (
const auto& category : all_categories) {
385 std::string label = category;
386 if (category == active_category) {
392 if (ImGui::BeginMenu(label.c_str())) {
396 ImGui::TextDisabled(
"No windows in this category");
410 for (
const auto& card : cards) {
413 const char* shortcut =
414 card.shortcut_hint.empty() ? nullptr : card.shortcut_hint.c_str();
417 std::string item_label =
424 if (ImGui::MenuItem(item_label.c_str(), shortcut)) {
451#ifdef YAZE_ENABLE_TESTING
464 AddCollaborationMenuItems();
487 std::map<std::string, std::vector<WorkflowItem>> grouped_items;
492 for (
const auto& category : categories) {
493 for (
const auto& descriptor :
495 if (descriptor.workflow_group.empty()) {
499 item.id = absl::StrFormat(
"panel.%s", descriptor.card_id);
500 item.group = descriptor.workflow_group;
501 item.label = descriptor.workflow_label.empty()
502 ? descriptor.display_name
503 : descriptor.workflow_label;
505 descriptor.workflow_description.empty()
506 ? absl::StrFormat(
"Open %s", descriptor.display_name)
507 : descriptor.workflow_description;
508 item.shortcut = descriptor.shortcut_hint;
509 item.priority = descriptor.workflow_priority;
510 item.callback = [
this, session_id, panel_id = descriptor.card_id]() {
515 item.enabled = descriptor.enabled_condition;
516 const std::string group = item.group.empty() ?
"General" : item.group;
517 grouped_items[group].push_back(std::move(item));
523 const std::string group = action.group.empty() ?
"General" : action.group;
524 grouped_items[group].push_back(action);
527 if (grouped_items.empty()) {
532 for (
auto& [group, items] : grouped_items) {
533 std::sort(items.begin(), items.end(),
534 [](
const WorkflowItem& lhs,
const WorkflowItem& rhs) {
535 if (lhs.priority != rhs.priority) {
536 return lhs.priority < rhs.priority;
538 return lhs.label < rhs.label;
541 for (
const auto& item : items) {
544 item.label.c_str(), item.callback,
545 item.shortcut.empty() ? nullptr : item.shortcut.c_str(), enabled);
552void MenuOrchestrator::AddRomAnalysisMenuItems() {
556 "ROM Information",
ICON_MD_INFO, [
this]() { OnShowRomInfo(); },
557 nullptr, [
this]() {
return HasActiveRom(); })
560 [
this]() { OnRunDataIntegrityCheck(); },
nullptr,
561 [
this]() {
return HasActiveRom(); })
564 nullptr, [
this]() {
return HasActiveRom(); })
568 menu_builder_.BeginSubMenu(
"ZSCustomOverworld",
ICON_MD_CODE)
570 "Check ROM Version",
ICON_MD_INFO, [
this]() { OnCheckRomVersion(); },
571 nullptr, [
this]() {
return HasActiveRom(); })
574 [
this]() {
return HasActiveRom(); })
576 [
this]() { OnToggleCustomLoading(); })
580void MenuOrchestrator::AddAsarIntegrationMenuItems() {
582 menu_builder_.BeginSubMenu(
"Asar Integration",
ICON_MD_BUILD)
584 [
this]() { popup_manager_.Show(PopupID::kAsarIntegration); })
586 "Toggle ASM Patch",
ICON_MD_CODE, [
this]() { OnToggleAsarPatch(); },
587 nullptr, [
this]() {
return HasActiveRom(); })
592void MenuOrchestrator::AddDevelopmentMenuItems() {
595 .Item(
"Memory Editor",
ICON_MD_MEMORY, [
this]() { OnShowMemoryEditor(); })
597 [
this]() { OnShowAssemblyEditor(); })
599 [
this]() { popup_manager_.Show(PopupID::kFeatureFlags); })
601 [
this]() { OnShowPerformanceDashboard(); })
602#ifdef YAZE_BUILD_AGENT_UI
607 [
this]() { OnShowProposalDrawer(); })
612void MenuOrchestrator::AddTestingMenuItems() {
615#ifdef YAZE_ENABLE_TESTING
623 [
this]() { OnRunIntegrationTests(); })
626 menu_builder_.DisabledItem(
627 "Testing support disabled (YAZE_ENABLE_TESTING=OFF)",
ICON_MD_INFO);
629 menu_builder_.EndMenu();
633void MenuOrchestrator::AddCollaborationMenuItems() {
637 [
this]() { OnStartCollaboration(); })
639 [
this]() { OnJoinCollaboration(); })
641 [
this]() { OnShowNetworkStatus(); })
649void MenuOrchestrator::AddSessionsSubmenu() {
650 if (ImGui::BeginMenu(absl::StrFormat(
"%s Sessions",
ICON_MD_TAB).c_str())) {
651 if (ImGui::MenuItem(absl::StrFormat(
"%s New Session",
ICON_MD_ADD).c_str(),
653 OnCreateNewSession();
658 nullptr,
false, HasActiveRom())) {
659 OnDuplicateCurrentSession();
664 OnCloseCurrentSession();
671 OnShowSessionSwitcher();
675 OnShowSessionManager();
683void MenuOrchestrator::AddLayoutSubmenu() {
684 const bool layout_enabled = HasCurrentEditor();
685 auto apply_preset = [
this](
const char* name) {
687 editor_manager_->ApplyLayoutPreset(name);
689 auto apply_profile = [
this](
const char* name) {
691 editor_manager_->ApplyLayoutProfile(name);
694 if (ImGui::BeginMenu(
696 if (ImGui::MenuItem(absl::StrFormat(
"%s Save Layout",
ICON_MD_SAVE).c_str(),
698 OnSaveWorkspaceLayout();
703 OnLoadWorkspaceLayout();
707 OnResetWorkspaceLayout();
712 nullptr,
false, layout_enabled)) {
714 editor_manager_->ResetCurrentEditorLayout();
718 if (ImGui::BeginMenu(
724 nullptr,
false, layout_enabled)) {
725 save_snapshot_name_buffer_[0] =
'\0';
726 open_save_snapshot_modal_ =
true;
730 std::vector<std::string> named =
731 editor_manager_ ? editor_manager_->ListLayoutSnapshots()
732 : std::vector<std::string>{};
733 if (!named.empty()) {
735 for (
const auto& name : named) {
736 ImGui::PushID(name.c_str());
739 nullptr,
false, layout_enabled)) {
741 editor_manager_->RestoreLayoutSnapshot(name);
743 ImGui::SameLine(ImGui::GetContentRegionAvail().x);
746 editor_manager_->DeleteLayoutSnapshot(name);
757 nullptr,
false, layout_enabled)) {
759 editor_manager_->CaptureTemporaryLayoutSnapshot();
763 nullptr,
false, layout_enabled)) {
765 editor_manager_->RestoreTemporaryLayoutSnapshot();
770 nullptr,
false, layout_enabled)) {
772 editor_manager_->ClearTemporaryLayoutSnapshot();
778 if (ImGui::BeginMenu(
780 if (ImGui::MenuItem(absl::StrFormat(
"%s Code",
ICON_MD_CODE).c_str(),
781 nullptr,
false, layout_enabled)) {
782 apply_profile(
"code");
786 false, layout_enabled)) {
787 apply_profile(
"debug");
789 if (ImGui::MenuItem(absl::StrFormat(
"%s Mapping",
ICON_MD_MAP).c_str(),
790 nullptr,
false, layout_enabled)) {
791 apply_profile(
"mapping");
795 nullptr,
false, layout_enabled)) {
796 apply_profile(
"chat");
801 nullptr,
false, layout_enabled)) {
802 apply_preset(
"Minimal");
806 nullptr,
false, layout_enabled)) {
807 OnLoadDeveloperLayout();
811 nullptr,
false, layout_enabled)) {
812 OnLoadDesignerLayout();
814 if (ImGui::MenuItem(absl::StrFormat(
"%s Modder",
ICON_MD_BUILD).c_str(),
815 nullptr,
false, layout_enabled)) {
816 OnLoadModderLayout();
819 absl::StrFormat(
"%s Overworld Expert",
ICON_MD_MAP).c_str(),
820 nullptr,
false, layout_enabled)) {
821 apply_preset(
"Overworld Expert");
825 nullptr,
false, layout_enabled)) {
826 apply_preset(
"Dungeon Expert");
830 false, layout_enabled)) {
831 apply_preset(
"Testing");
835 false, layout_enabled)) {
836 apply_preset(
"Audio");
840 absl::StrFormat(
"%s Manage Presets...",
ICON_MD_TUNE).c_str())) {
841 OnShowLayoutPresets();
851void MenuOrchestrator::AddSidebarSubmenu() {
852 if (!user_settings_) {
856 if (!ImGui::BeginMenu(
861 auto persist = [
this]() { (void)user_settings_->Save(); };
862 auto& prefs = user_settings_->prefs();
866 nullptr,
false, !prefs.sidebar_order.empty())) {
867 prefs.sidebar_order.clear();
872 nullptr,
false, !prefs.sidebar_hidden.empty())) {
873 prefs.sidebar_hidden.clear();
879 const size_t session_id = session_coordinator_.GetActiveSessionIndex();
880 std::vector<std::string> categories;
881 if (window_manager_) {
882 categories = window_manager_->GetAllCategories(session_id);
886 std::vector<std::string> pinned_list;
887 std::vector<std::string> hidden_list;
888 for (
const auto& cat : categories) {
889 if (cat == WorkspaceWindowManager::kDashboardCategory)
continue;
890 if (prefs.sidebar_pinned.count(cat)) pinned_list.push_back(cat);
891 if (prefs.sidebar_hidden.count(cat)) hidden_list.push_back(cat);
894 if (ImGui::BeginMenu(
896 if (pinned_list.empty()) {
897 ImGui::TextDisabled(
"(none)");
899 for (
const auto& cat : pinned_list) {
900 ImGui::PushID(cat.c_str());
901 if (ImGui::MenuItem(absl::StrFormat(
"%s Unpin %s",
ICON_MD_CLOSE, cat)
903 prefs.sidebar_pinned.erase(cat);
912 if (ImGui::BeginMenu(
914 if (hidden_list.empty()) {
915 ImGui::TextDisabled(
"(none)");
917 for (
const auto& cat : hidden_list) {
918 ImGui::PushID(cat.c_str());
921 prefs.sidebar_hidden.erase(cat);
934 if (ImGui::BeginMenu(
935 absl::StrFormat(
"%s Customize",
ICON_MD_TUNE).c_str())) {
936 if (categories.empty()) {
937 ImGui::TextDisabled(
"No categories available");
939 for (
const auto& cat : categories) {
940 if (cat == WorkspaceWindowManager::kDashboardCategory)
continue;
941 ImGui::PushID(cat.c_str());
942 const bool pinned = prefs.sidebar_pinned.count(cat) > 0;
943 const bool hidden = prefs.sidebar_hidden.count(cat) > 0;
944 if (ImGui::BeginMenu(cat.c_str())) {
945 if (ImGui::MenuItem(pinned ?
"Unpin from top" :
"Pin to top",
nullptr,
948 prefs.sidebar_pinned.erase(cat);
950 prefs.sidebar_pinned.insert(cat);
954 if (ImGui::MenuItem(hidden ?
"Show on sidebar" :
"Hide from sidebar",
957 prefs.sidebar_hidden.erase(cat);
959 prefs.sidebar_hidden.insert(cat);
974void MenuOrchestrator::BuildHelpMenu() {
975 menu_builder_.BeginMenu(
"Help");
977 menu_builder_.EndMenu();
980void MenuOrchestrator::AddHelpMenuItems() {
984 [
this]() { OnShowGettingStarted(); })
986 [
this]() { OnShowSettings(); })
988 [
this]() { OnShowBuildInstructions(); })
992 [
this]() { OnShowSupportedFeatures(); })
996 [
this]() { OnShowTroubleshooting(); })
998 [
this]() { OnShowContributing(); })
1000 .Item(
"About",
ICON_MD_INFO, [
this]() { OnShowAbout(); },
"F1");
1004void MenuOrchestrator::ClearMenu() {
1005 menu_builder_.Clear();
1008void MenuOrchestrator::RefreshMenu() {
1009 menu_needs_refresh_ =
true;
1013void MenuOrchestrator::OnOpenRom() {
1015 if (editor_manager_) {
1016 auto status = editor_manager_->LoadRom();
1018 toast_manager_.Show(
1019 absl::StrFormat(
"Failed to load ROM: %s", status.message()),
1025void MenuOrchestrator::OnSaveRom() {
1027 if (editor_manager_) {
1028 auto status = editor_manager_->SaveRom();
1030 if (absl::IsCancelled(status)) {
1033 toast_manager_.Show(
1034 absl::StrFormat(
"Failed to save ROM: %s", status.message()),
1037 toast_manager_.Show(
"ROM saved successfully", ToastType::kSuccess);
1042void MenuOrchestrator::OnSaveRomAs() {
1043 popup_manager_.Show(PopupID::kSaveAs);
1046void MenuOrchestrator::OnCreateProject() {
1048 if (editor_manager_) {
1049 auto status = editor_manager_->CreateNewProject();
1051 toast_manager_.Show(
1052 absl::StrFormat(
"Failed to create project: %s", status.message()),
1058void MenuOrchestrator::OnOpenProject() {
1060 if (editor_manager_) {
1061 auto status = editor_manager_->OpenProject();
1063 toast_manager_.Show(
1064 absl::StrFormat(
"Failed to open project: %s", status.message()),
1070void MenuOrchestrator::OnSaveProject() {
1072 if (editor_manager_) {
1073 auto status = editor_manager_->SaveProject();
1075 toast_manager_.Show(
1076 absl::StrFormat(
"Failed to save project: %s", status.message()),
1079 toast_manager_.Show(
"Project saved successfully", ToastType::kSuccess);
1084void MenuOrchestrator::OnSaveProjectAs() {
1086 if (editor_manager_) {
1087 auto status = editor_manager_->SaveProjectAs();
1089 toast_manager_.Show(
1090 absl::StrFormat(
"Failed to save project as: %s", status.message()),
1096void MenuOrchestrator::OnShowProjectManagement() {
1098 if (editor_manager_) {
1099 editor_manager_->ShowProjectManagement();
1103void MenuOrchestrator::OnShowProjectFileEditor() {
1105 if (editor_manager_) {
1106 editor_manager_->ShowProjectFileEditor();
1111void MenuOrchestrator::OnUndo() {
1112 if (editor_manager_) {
1113 auto* current_editor = editor_manager_->GetCurrentEditor();
1114 if (current_editor) {
1117 auto status = current_editor->
Undo();
1119 if (!desc.empty()) {
1120 toast_manager_.Show(absl::StrFormat(
"Undid: %s", desc),
1121 ToastType::kInfo, 2.0f);
1124 toast_manager_.Show(
1125 absl::StrFormat(
"Undo failed: %s", status.message()),
1132void MenuOrchestrator::OnRedo() {
1133 if (editor_manager_) {
1134 auto* current_editor = editor_manager_->GetCurrentEditor();
1135 if (current_editor) {
1138 auto status = current_editor->
Redo();
1140 if (!desc.empty()) {
1141 toast_manager_.Show(absl::StrFormat(
"Redid: %s", desc),
1142 ToastType::kInfo, 2.0f);
1145 toast_manager_.Show(
1146 absl::StrFormat(
"Redo failed: %s", status.message()),
1153void MenuOrchestrator::OnCut() {
1154 if (editor_manager_) {
1155 auto* current_editor = editor_manager_->GetCurrentEditor();
1156 if (current_editor) {
1157 auto status = current_editor->
Cut();
1159 toast_manager_.Show(absl::StrFormat(
"Cut failed: %s", status.message()),
1166void MenuOrchestrator::OnCopy() {
1167 if (editor_manager_) {
1168 auto* current_editor = editor_manager_->GetCurrentEditor();
1169 if (current_editor) {
1170 auto status = current_editor->
Copy();
1172 toast_manager_.Show(
1173 absl::StrFormat(
"Copy failed: %s", status.message()),
1180void MenuOrchestrator::OnPaste() {
1181 if (editor_manager_) {
1182 auto* current_editor = editor_manager_->GetCurrentEditor();
1183 if (current_editor) {
1184 auto status = current_editor->
Paste();
1186 toast_manager_.Show(
1187 absl::StrFormat(
"Paste failed: %s", status.message()),
1194void MenuOrchestrator::OnFind() {
1195 if (editor_manager_) {
1196 auto* current_editor = editor_manager_->GetCurrentEditor();
1197 if (current_editor) {
1198 auto status = current_editor->
Find();
1200 toast_manager_.Show(
1201 absl::StrFormat(
"Find failed: %s", status.message()),
1211 if (editor_manager_) {
1212 editor_manager_->SwitchToEditor(editor_type);
1216void MenuOrchestrator::OnShowEditorSelection() {
1218 if (editor_manager_) {
1219 if (
auto* ui = editor_manager_->ui_coordinator()) {
1220 ui->ShowEditorSelection();
1225void MenuOrchestrator::OnShowDisplaySettings() {
1226 popup_manager_.Show(PopupID::kDisplaySettings);
1229void MenuOrchestrator::OnShowHexEditor() {
1231 if (editor_manager_) {
1232 editor_manager_->window_manager().OpenWindow(
1233 editor_manager_->GetCurrentSessionId(),
"Hex Editor");
1237void MenuOrchestrator::OnShowPanelBrowser() {
1238 if (editor_manager_) {
1239 if (
auto* ui = editor_manager_->ui_coordinator()) {
1240 ui->SetWindowBrowserVisible(
true);
1245void MenuOrchestrator::OnShowPanelFinder() {
1246 if (editor_manager_) {
1247 if (
auto* ui = editor_manager_->ui_coordinator()) {
1248 ui->ShowPanelFinder();
1253void MenuOrchestrator::OnShowWelcomeScreen() {
1254 if (editor_manager_) {
1255 if (
auto* ui = editor_manager_->ui_coordinator()) {
1256 ui->SetWelcomeScreenVisible(
true);
1261#ifdef YAZE_BUILD_AGENT_UI
1262void MenuOrchestrator::OnShowAIAgent() {
1263 if (editor_manager_) {
1264 if (
auto* ui = editor_manager_->ui_coordinator()) {
1265 ui->SetAIAgentVisible(
true);
1270void MenuOrchestrator::OnShowProposalDrawer() {
1271 if (editor_manager_) {
1272 if (
auto* ui = editor_manager_->ui_coordinator()) {
1273 ui->SetProposalDrawerVisible(
true);
1280void MenuOrchestrator::OnCreateNewSession() {
1281 session_coordinator_.CreateNewSession();
1284void MenuOrchestrator::OnDuplicateCurrentSession() {
1285 session_coordinator_.DuplicateCurrentSession();
1288void MenuOrchestrator::OnCloseCurrentSession() {
1289 session_coordinator_.CloseCurrentSession();
1292void MenuOrchestrator::OnShowSessionSwitcher() {
1294 if (editor_manager_) {
1295 if (
auto* ui = editor_manager_->ui_coordinator()) {
1296 ui->ShowSessionSwitcher();
1301void MenuOrchestrator::OnShowSessionManager() {
1302 popup_manager_.Show(PopupID::kSessionManager);
1306void MenuOrchestrator::OnShowAllWindows() {
1308 if (editor_manager_) {
1309 if (
auto* ui = editor_manager_->ui_coordinator()) {
1310 ui->ShowAllWindows();
1315void MenuOrchestrator::OnHideAllWindows() {
1317 if (editor_manager_) {
1318 editor_manager_->HideAllWindows();
1322void MenuOrchestrator::OnResetWorkspaceLayout() {
1324 if (editor_manager_) {
1325 editor_manager_->QueueDeferredAction([
this]() {
1326 editor_manager_->ResetWorkspaceLayout();
1327 toast_manager_.Show(
"Layout reset to default", ToastType::kInfo);
1332void MenuOrchestrator::OnSaveWorkspaceLayout() {
1334 if (editor_manager_) {
1335 editor_manager_->SaveWorkspaceLayout();
1339void MenuOrchestrator::OnLoadWorkspaceLayout() {
1341 if (editor_manager_) {
1342 editor_manager_->LoadWorkspaceLayout();
1346void MenuOrchestrator::OnShowLayoutPresets() {
1347 popup_manager_.Show(PopupID::kLayoutPresets);
1350void MenuOrchestrator::OnLoadDeveloperLayout() {
1351 if (editor_manager_) {
1352 editor_manager_->ApplyLayoutPreset(
"Developer");
1356void MenuOrchestrator::OnLoadDesignerLayout() {
1357 if (editor_manager_) {
1358 editor_manager_->ApplyLayoutPreset(
"Designer");
1362void MenuOrchestrator::OnLoadModderLayout() {
1363 if (editor_manager_) {
1364 editor_manager_->ApplyLayoutPreset(
"Modder");
1369void MenuOrchestrator::OnShowGlobalSearch() {
1370 if (editor_manager_) {
1371 if (
auto* ui = editor_manager_->ui_coordinator()) {
1372 ui->ShowGlobalSearch();
1377void MenuOrchestrator::OnShowCommandPalette() {
1378 if (editor_manager_) {
1379 if (
auto* ui = editor_manager_->ui_coordinator()) {
1380 ui->ShowCommandPalette();
1385void MenuOrchestrator::OnShowPerformanceDashboard() {
1386 if (editor_manager_) {
1387 if (
auto* ui = editor_manager_->ui_coordinator()) {
1388 ui->SetPerformanceDashboardVisible(
true);
1393void MenuOrchestrator::OnShowImGuiDemo() {
1394 if (editor_manager_) {
1395 editor_manager_->ShowImGuiDemo();
1399void MenuOrchestrator::OnShowImGuiMetrics() {
1400 if (editor_manager_) {
1401 editor_manager_->ShowImGuiMetrics();
1405void MenuOrchestrator::OnShowMemoryEditor() {
1406 if (editor_manager_) {
1407 editor_manager_->window_manager().OpenWindow(
1408 editor_manager_->GetCurrentSessionId(),
"Memory Editor");
1412void MenuOrchestrator::OnShowResourceLabelManager() {
1413 if (editor_manager_) {
1414 if (
auto* ui = editor_manager_->ui_coordinator()) {
1415 ui->SetResourceLabelManagerVisible(
true);
1420#ifdef YAZE_ENABLE_TESTING
1421void MenuOrchestrator::OnShowTestDashboard() {
1422 if (editor_manager_) {
1423 editor_manager_->ShowTestDashboard();
1427void MenuOrchestrator::OnRunAllTests() {
1428 toast_manager_.Show(
"Running all tests...", ToastType::kInfo);
1432void MenuOrchestrator::OnRunUnitTests() {
1433 toast_manager_.Show(
"Running unit tests...", ToastType::kInfo);
1437void MenuOrchestrator::OnRunIntegrationTests() {
1438 toast_manager_.Show(
"Running integration tests...", ToastType::kInfo);
1442void MenuOrchestrator::OnRunE2ETests() {
1443 toast_manager_.Show(
1444 "E2E runner is not wired in-app yet. Use scripts/agents/run-tests.sh or "
1446 ToastType::kWarning);
1450#ifdef YAZE_WITH_GRPC
1451void MenuOrchestrator::OnStartCollaboration() {
1452 toast_manager_.Show(
1453 "Collaboration session start is not wired yet. Run yaze-server and use "
1454 "the web client for live sync.",
1455 ToastType::kWarning);
1458void MenuOrchestrator::OnJoinCollaboration() {
1459 toast_manager_.Show(
1460 "Join collaboration is not wired yet. Use the web client + yaze-server.",
1461 ToastType::kWarning);
1464void MenuOrchestrator::OnShowNetworkStatus() {
1465 toast_manager_.Show(
"Network status panel is not implemented yet.",
1466 ToastType::kWarning);
1471void MenuOrchestrator::OnShowAbout() {
1472 popup_manager_.Show(PopupID::kAbout);
1475void MenuOrchestrator::OnShowGettingStarted() {
1476 popup_manager_.Show(PopupID::kGettingStarted);
1479void MenuOrchestrator::OnShowBuildInstructions() {
1480 popup_manager_.Show(PopupID::kBuildInstructions);
1483void MenuOrchestrator::OnShowCLIUsage() {
1484 popup_manager_.Show(PopupID::kCLIUsage);
1487void MenuOrchestrator::OnShowTroubleshooting() {
1488 popup_manager_.Show(PopupID::kTroubleshooting);
1491void MenuOrchestrator::OnShowContributing() {
1492 popup_manager_.Show(PopupID::kContributing);
1495void MenuOrchestrator::OnShowWhatsNew() {
1496 popup_manager_.Show(PopupID::kWhatsNew);
1499void MenuOrchestrator::OnShowSupportedFeatures() {
1500 popup_manager_.Show(PopupID::kSupportedFeatures);
1504void MenuOrchestrator::OnShowRomInfo() {
1505 popup_manager_.Show(PopupID::kRomInfo);
1508void MenuOrchestrator::OnCreateBackup() {
1509 if (editor_manager_) {
1510 auto status = rom_manager_.CreateBackup(editor_manager_->GetCurrentRom());
1512 toast_manager_.Show(
"Backup created successfully", ToastType::kSuccess);
1514 toast_manager_.Show(
1515 absl::StrFormat(
"Backup failed: %s", status.message()),
1521void MenuOrchestrator::OnValidateRom() {
1522 if (editor_manager_) {
1523 auto status = rom_manager_.ValidateRom(editor_manager_->GetCurrentRom());
1525 toast_manager_.Show(
"ROM validation passed", ToastType::kSuccess);
1527 toast_manager_.Show(
1528 absl::StrFormat(
"ROM validation failed: %s", status.message()),
1534void MenuOrchestrator::OnShowSettings() {
1536 if (editor_manager_) {
1537 editor_manager_->SwitchToEditor(EditorType::kSettings);
1541void MenuOrchestrator::OnQuit() {
1542 if (editor_manager_) {
1543 editor_manager_->Quit();
1548bool MenuOrchestrator::CanSaveRom()
const {
1549 auto* rom = editor_manager_->GetCurrentRom();
1550 return rom ? rom_manager_.IsRomLoaded(rom) :
false;
1553bool MenuOrchestrator::CanSaveProject()
const {
1554 return project_manager_.HasActiveProject();
1557bool MenuOrchestrator::HasActiveRom()
const {
1558 auto* rom = editor_manager_->GetCurrentRom();
1559 return rom ? rom_manager_.IsRomLoaded(rom) :
false;
1562bool MenuOrchestrator::HasActiveProject()
const {
1563 return project_manager_.HasActiveProject();
1566bool MenuOrchestrator::HasProjectFile()
const {
1569 const auto* project =
1570 editor_manager_ ? editor_manager_->GetCurrentProject() :
nullptr;
1571 return project && !project->filepath.empty();
1574bool MenuOrchestrator::HasCurrentEditor()
const {
1575 return editor_manager_ && editor_manager_->GetCurrentEditor() !=
nullptr;
1578bool MenuOrchestrator::HasMultipleSessions()
const {
1579 return session_coordinator_.HasMultipleSessions();
1583std::string MenuOrchestrator::GetRomFilename()
const {
1584 auto* rom = editor_manager_->GetCurrentRom();
1585 return rom ? rom_manager_.GetRomFilename(rom) :
"";
1588std::string MenuOrchestrator::GetProjectName()
const {
1589 return project_manager_.GetProjectName();
1592std::string MenuOrchestrator::GetCurrentEditorName()
const {
1594 return "Unknown Editor";
1598std::string MenuOrchestrator::GetShortcutForAction(
1599 const std::string& action)
const {
1604void MenuOrchestrator::RegisterGlobalShortcuts() {
1612void MenuOrchestrator::OnRunDataIntegrityCheck() {
1613#ifdef YAZE_ENABLE_TESTING
1614 if (!editor_manager_)
1616 auto* rom = editor_manager_->GetCurrentRom();
1620 toast_manager_.Show(
"Running ROM integrity tests...", ToastType::kInfo);
1623 toast_manager_.Show(
"Data integrity check completed", ToastType::kSuccess,
1626 toast_manager_.Show(
"Testing not enabled in this build", ToastType::kWarning);
1630void MenuOrchestrator::OnTestSaveLoad() {
1631#ifdef YAZE_ENABLE_TESTING
1632 if (!editor_manager_)
1634 auto* rom = editor_manager_->GetCurrentRom();
1638 toast_manager_.Show(
"Running ROM save/load tests...", ToastType::kInfo);
1640 toast_manager_.Show(
"Save/load test completed", ToastType::kSuccess, 3.0f);
1642 toast_manager_.Show(
"Testing not enabled in this build", ToastType::kWarning);
1646void MenuOrchestrator::OnCheckRomVersion() {
1647 if (!editor_manager_)
1649 auto* rom = editor_manager_->GetCurrentRom();
1655 std::string version_str =
1656 (version == 0xFF) ?
"Vanilla" : absl::StrFormat(
"v%d", version);
1658 toast_manager_.Show(
1659 absl::StrFormat(
"ROM: %s | ZSCustomOverworld: %s", rom->
title().c_str(),
1660 version_str.c_str()),
1661 ToastType::kInfo, 5.0f);
1664void MenuOrchestrator::OnUpgradeRom() {
1665 if (!editor_manager_)
1667 auto* rom = editor_manager_->GetCurrentRom();
1671 toast_manager_.Show(
"Use Overworld Editor to upgrade ROM version",
1672 ToastType::kInfo, 4.0f);
1675void MenuOrchestrator::OnToggleCustomLoading() {
1677 flags.overworld.kLoadCustomOverworld = !flags.overworld.kLoadCustomOverworld;
1679 toast_manager_.Show(
1681 "Custom Overworld Loading: %s",
1682 flags.overworld.kLoadCustomOverworld ?
"Enabled" :
"Disabled"),
1686void MenuOrchestrator::OnToggleAsarPatch() {
1687 if (!editor_manager_)
1689 auto* rom = editor_manager_->GetCurrentRom();
1694 flags.overworld.kApplyZSCustomOverworldASM =
1695 !flags.overworld.kApplyZSCustomOverworldASM;
1697 toast_manager_.Show(
1699 "ZSCustomOverworld ASM Application: %s",
1700 flags.overworld.kApplyZSCustomOverworldASM ?
"Enabled" :
"Disabled"),
1704void MenuOrchestrator::OnLoadAsmFile() {
1705 toast_manager_.Show(
"ASM file loading not yet implemented",
1706 ToastType::kWarning);
1709void MenuOrchestrator::OnShowAssemblyEditor() {
1710 if (editor_manager_) {
1711 editor_manager_->SwitchToEditor(EditorType::kAssembly);
1715void MenuOrchestrator::OnExportBpsPatch() {
1716 if (!editor_manager_)
1718 auto* rom = editor_manager_->GetCurrentRom();
1724 std::string original_path =
1726 if (original_path.empty()) {
1732 auto load_status = original_rom.
LoadFromFile(original_path);
1733 if (!load_status.ok()) {
1734 toast_manager_.Show(absl::StrFormat(
"Failed to load original ROM: %s",
1735 load_status.message()),
1741 std::vector<uint8_t> patch_data;
1742 auto create_status =
1744 if (!create_status.ok()) {
1745 toast_manager_.Show(absl::StrFormat(
"Failed to create BPS patch: %s",
1746 create_status.message()),
1752 std::string default_name = rom->
short_name() +
".bps";
1753 std::string save_path =
1755 if (save_path.empty()) {
1760 if (save_path.size() < 4 ||
1761 save_path.substr(save_path.size() - 4) !=
".bps") {
1762 save_path +=
".bps";
1766 std::ofstream file(save_path, std::ios::binary);
1767 if (!file.is_open()) {
1768 toast_manager_.Show(
1769 absl::StrFormat(
"Failed to open file for writing: %s", save_path),
1774 file.write(
reinterpret_cast<const char*
>(patch_data.data()),
1779 toast_manager_.Show(
1780 absl::StrFormat(
"Failed to write patch file: %s", save_path),
1785 toast_manager_.Show(absl::StrFormat(
"BPS patch exported: %s (%zu bytes)",
1786 save_path, patch_data.size()),
1787 ToastType::kSuccess);
1790void MenuOrchestrator::OnApplyBpsPatch() {
1791 if (!editor_manager_)
1793 auto* rom = editor_manager_->GetCurrentRom();
1799 options.
filters.push_back({
"BPS Patch",
"bps"});
1801 if (patch_path.empty()) {
1806 std::ifstream file(patch_path, std::ios::binary);
1807 if (!file.is_open()) {
1808 toast_manager_.Show(
1809 absl::StrFormat(
"Failed to open patch file: %s", patch_path),
1814 std::vector<uint8_t> patch_data((std::istreambuf_iterator<char>(file)),
1815 std::istreambuf_iterator<char>());
1818 if (patch_data.empty()) {
1819 toast_manager_.Show(
"Patch file is empty", ToastType::kError);
1824 std::vector<uint8_t> patched_rom;
1827 if (!apply_status.ok()) {
1828 toast_manager_.Show(absl::StrFormat(
"Failed to apply BPS patch: %s",
1829 apply_status.message()),
1836 if (!load_status.ok()) {
1837 toast_manager_.Show(absl::StrFormat(
"Failed to load patched ROM data: %s",
1838 load_status.message()),
1844 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)
bool ApplyLayoutProfile(const std::string &profile_id)
void ResetCurrentEditorLayout()
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 GetActiveSessionIndex() const
void SetEnabled(bool enabled)
Enable or disable the status bar.
void HideAllWindowsInCategory(size_t session_id, const std::string &category)
std::vector< WindowDescriptor > GetWindowsInCategory(size_t session_id, const std::string &category) const
void ToggleSidebarVisibility()
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)
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_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_VIEW_SIDEBAR
#define ICON_MD_BOOKMARK_REMOVE
#define ICON_MD_SMART_TOY
#define ICON_MD_GROUP_ADD
std::vector< ActionDef > GetAll()
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
std::vector< FileDialogFilter > filters