8#include "absl/status/status.h"
9#include "absl/strings/str_format.h"
32#define SHORTCUT_CTRL(key) gui::FormatCtrlShortcut(ImGuiKey_##key).c_str()
33#define SHORTCUT_CTRL_SHIFT(key) \
34 gui::FormatCtrlShiftShortcut(ImGuiKey_##key).c_str()
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) {}
80 ImGui::OpenPopup(
"Save Layout Snapshot##menu_orch_save_snapshot");
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 =
90 ImGuiInputTextFlags_EnterReturnsTrue);
93 if ((ImGui::Button(
"Save", ImVec2(120, 0)) || submitted) && has_name) {
98 ImGui::CloseCurrentPopup();
101 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
103 ImGui::CloseCurrentPopup();
289 const auto layout_enabled = [
this]() {
306 nullptr, layout_enabled)
314 nullptr, layout_enabled)
322 nullptr, layout_enabled)
330 nullptr, layout_enabled)
349 nullptr, layout_enabled)
369 absl::StrFormat(
"%s Window Browser",
ICON_MD_APPS).c_str(),
392 if (all_categories.empty()) {
393 ImGui::TextDisabled(
"No windows available");
398 for (
const auto& category : all_categories) {
400 std::string label = category;
401 if (category == active_category) {
407 if (ImGui::BeginMenu(label.c_str())) {
411 ImGui::TextDisabled(
"No windows in this category");
425 for (
const auto& card : cards) {
428 const char* shortcut =
429 card.shortcut_hint.empty() ? nullptr : card.shortcut_hint.c_str();
432 std::string item_label =
439 if (ImGui::MenuItem(item_label.c_str(), shortcut)) {
466#ifdef YAZE_ENABLE_TESTING
479 AddCollaborationMenuItems();
502 std::map<std::string, std::vector<WorkflowItem>> grouped_items;
507 for (
const auto& category : categories) {
508 for (
const auto& descriptor :
510 if (descriptor.workflow_group.empty()) {
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;
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]() {
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));
538 const std::string group = action.group.empty() ?
"General" : action.group;
539 grouped_items[group].push_back(action);
542 if (grouped_items.empty()) {
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;
553 return lhs.label < rhs.label;
556 for (
const auto& item : items) {
559 item.label.c_str(), item.callback,
560 item.shortcut.empty() ? nullptr : item.shortcut.c_str(), enabled);
567void MenuOrchestrator::AddRomAnalysisMenuItems() {
571 "ROM Information",
ICON_MD_INFO, [
this]() { OnShowRomInfo(); },
572 nullptr, [
this]() {
return HasActiveRom(); })
575 [
this]() { OnRunDataIntegrityCheck(); },
nullptr,
576 [
this]() {
return HasActiveRom(); })
579 nullptr, [
this]() {
return HasActiveRom(); })
583 menu_builder_.BeginSubMenu(
"ZSCustomOverworld",
ICON_MD_CODE)
585 "Check ROM Version",
ICON_MD_INFO, [
this]() { OnCheckRomVersion(); },
586 nullptr, [
this]() {
return HasActiveRom(); })
589 [
this]() {
return HasActiveRom(); })
591 [
this]() { OnToggleCustomLoading(); })
595void MenuOrchestrator::AddAsarIntegrationMenuItems() {
597 menu_builder_.BeginSubMenu(
"Asar Integration",
ICON_MD_BUILD)
599 [
this]() { popup_manager_.Show(PopupID::kAsarIntegration); })
601 "Toggle ASM Patch",
ICON_MD_CODE, [
this]() { OnToggleAsarPatch(); },
602 nullptr, [
this]() {
return HasActiveRom(); })
607void MenuOrchestrator::AddDevelopmentMenuItems() {
611 "Memory Editor",
ICON_MD_MEMORY, [
this]() { OnShowMemoryEditor(); },
612 nullptr, [
this]() {
return HasActiveRom(); })
614 [
this]() { OnShowAssemblyEditor(); })
616 [
this]() { popup_manager_.Show(PopupID::kFeatureFlags); })
618 [
this]() { OnShowPerformanceDashboard(); })
619#ifdef YAZE_BUILD_AGENT_UI
624 [
this]() { OnShowProposalDrawer(); })
629void MenuOrchestrator::AddTestingMenuItems() {
632#ifdef YAZE_ENABLE_TESTING
640 [
this]() { OnRunIntegrationTests(); })
643 menu_builder_.DisabledItem(
644 "Testing support disabled (YAZE_ENABLE_TESTING=OFF)",
ICON_MD_INFO);
646 menu_builder_.EndMenu();
650void MenuOrchestrator::AddCollaborationMenuItems() {
654 [
this]() { OnStartCollaboration(); })
656 [
this]() { OnJoinCollaboration(); })
658 [
this]() { OnShowNetworkStatus(); })
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();
675 nullptr,
false, HasActiveRom())) {
676 OnDuplicateCurrentSession();
681 OnCloseCurrentSession();
688 OnShowSessionSwitcher();
692 OnShowSessionManager();
700void MenuOrchestrator::AddLayoutSubmenu() {
701 const bool layout_enabled = HasCurrentEditor();
702 auto apply_preset = [
this](
const char* name) {
704 editor_manager_->ApplyLayoutPreset(name);
706 auto apply_profile = [
this](
const char* name) {
708 editor_manager_->ApplyLayoutProfile(name);
711 if (ImGui::BeginMenu(
713 if (ImGui::MenuItem(absl::StrFormat(
"%s Open Layout Designer",
716 nullptr,
false, window_manager_ !=
nullptr)) {
717 OnShowLayoutDesigner();
721 if (ImGui::MenuItem(absl::StrFormat(
"%s Save Layout",
ICON_MD_SAVE).c_str(),
723 OnSaveWorkspaceLayout();
728 OnLoadWorkspaceLayout();
732 OnResetWorkspaceLayout();
737 nullptr,
false, layout_enabled)) {
739 editor_manager_->ResetCurrentEditorLayout();
743 if (ImGui::BeginMenu(
749 nullptr,
false, layout_enabled)) {
750 save_snapshot_name_buffer_[0] =
'\0';
751 open_save_snapshot_modal_ =
true;
755 std::vector<std::string> named =
756 editor_manager_ ? editor_manager_->ListLayoutSnapshots()
757 : std::vector<std::string>{};
758 if (!named.empty()) {
760 for (
const auto& name : named) {
761 ImGui::PushID(name.c_str());
764 nullptr,
false, layout_enabled)) {
766 editor_manager_->RestoreLayoutSnapshot(name);
768 ImGui::SameLine(ImGui::GetContentRegionAvail().x);
771 editor_manager_->DeleteLayoutSnapshot(name);
782 nullptr,
false, layout_enabled)) {
784 editor_manager_->CaptureTemporaryLayoutSnapshot();
788 nullptr,
false, layout_enabled)) {
790 editor_manager_->RestoreTemporaryLayoutSnapshot();
795 nullptr,
false, layout_enabled)) {
797 editor_manager_->ClearTemporaryLayoutSnapshot();
803 if (ImGui::BeginMenu(
805 if (ImGui::MenuItem(absl::StrFormat(
"%s Code",
ICON_MD_CODE).c_str(),
806 nullptr,
false, layout_enabled)) {
807 apply_profile(
"code");
811 false, layout_enabled)) {
812 apply_profile(
"debug");
814 if (ImGui::MenuItem(absl::StrFormat(
"%s Mapping",
ICON_MD_MAP).c_str(),
815 nullptr,
false, layout_enabled)) {
816 apply_profile(
"mapping");
820 nullptr,
false, layout_enabled)) {
821 apply_profile(
"chat");
826 nullptr,
false, layout_enabled)) {
827 apply_preset(
"Minimal");
831 nullptr,
false, layout_enabled)) {
832 OnLoadDeveloperLayout();
836 nullptr,
false, layout_enabled)) {
837 OnLoadDesignerLayout();
839 if (ImGui::MenuItem(absl::StrFormat(
"%s Modder",
ICON_MD_BUILD).c_str(),
840 nullptr,
false, layout_enabled)) {
841 OnLoadModderLayout();
844 absl::StrFormat(
"%s Overworld Expert",
ICON_MD_MAP).c_str(),
845 nullptr,
false, layout_enabled)) {
846 apply_preset(
"Overworld Expert");
850 nullptr,
false, layout_enabled)) {
851 apply_preset(
"Dungeon Expert");
855 false, layout_enabled)) {
856 apply_preset(
"Testing");
860 false, layout_enabled)) {
861 apply_preset(
"Audio");
865 absl::StrFormat(
"%s Manage Presets...",
ICON_MD_TUNE).c_str())) {
866 OnShowLayoutPresets();
876void MenuOrchestrator::AddSidebarSubmenu() {
877 if (!user_settings_) {
881 if (!ImGui::BeginMenu(
886 auto persist = [
this]() {
887 (void)user_settings_->Save();
889 auto& prefs = user_settings_->prefs();
893 nullptr,
false, !prefs.sidebar_order.empty())) {
894 prefs.sidebar_order.clear();
899 nullptr,
false, !prefs.sidebar_hidden.empty())) {
900 prefs.sidebar_hidden.clear();
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);
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)
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);
924 if (ImGui::BeginMenu(
926 if (pinned_list.empty()) {
927 ImGui::TextDisabled(
"(none)");
929 for (
const auto& cat : pinned_list) {
930 ImGui::PushID(cat.c_str());
932 absl::StrFormat(
"%s Unpin %s",
ICON_MD_CLOSE, cat).c_str())) {
933 prefs.sidebar_pinned.erase(cat);
942 if (ImGui::BeginMenu(
944 if (hidden_list.empty()) {
945 ImGui::TextDisabled(
"(none)");
947 for (
const auto& cat : hidden_list) {
948 ImGui::PushID(cat.c_str());
952 prefs.sidebar_hidden.erase(cat);
965 if (ImGui::BeginMenu(absl::StrFormat(
"%s Customize",
ICON_MD_TUNE).c_str())) {
966 if (categories.empty()) {
967 ImGui::TextDisabled(
"No categories available");
969 for (
const auto& cat : categories) {
970 if (cat == WorkspaceWindowManager::kDashboardCategory)
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,
979 prefs.sidebar_pinned.erase(cat);
981 prefs.sidebar_pinned.insert(cat);
985 if (ImGui::MenuItem(hidden ?
"Show on sidebar" :
"Hide from sidebar",
988 prefs.sidebar_hidden.erase(cat);
990 prefs.sidebar_hidden.insert(cat);
1005void MenuOrchestrator::BuildHelpMenu() {
1006 menu_builder_.BeginMenu(
"Help");
1008 menu_builder_.EndMenu();
1011void MenuOrchestrator::AddHelpMenuItems() {
1015 [
this]() { OnShowGettingStarted(); })
1017 [
this]() { OnShowSettings(); })
1019 [
this]() { OnShowBuildInstructions(); })
1023 [
this]() { OnShowSupportedFeatures(); })
1027 [
this]() { OnShowTroubleshooting(); })
1029 [
this]() { OnShowContributing(); })
1031 .Item(
"About",
ICON_MD_INFO, [
this]() { OnShowAbout(); },
"F1");
1033 menu_builder_.Separator();
1035 for (
const std::string& locale :
1038 locale.c_str(),
nullptr,
1045 menu_builder_.EndMenu();
1049void MenuOrchestrator::ClearMenu() {
1050 menu_builder_.Clear();
1053void MenuOrchestrator::RefreshMenu() {
1054 menu_needs_refresh_ =
true;
1058void MenuOrchestrator::OnOpenRom() {
1060 if (editor_manager_) {
1061 auto status = editor_manager_->LoadRom();
1063 toast_manager_.Show(
1064 absl::StrFormat(
"Failed to load ROM: %s", status.message()),
1070void MenuOrchestrator::OnSaveRom() {
1072 if (editor_manager_) {
1073 auto status = editor_manager_->SaveRom();
1075 if (absl::IsCancelled(status)) {
1078 toast_manager_.Show(
1079 absl::StrFormat(
"Failed to save ROM: %s", status.message()),
1085void MenuOrchestrator::OnSaveRomAs() {
1086 popup_manager_.Show(PopupID::kSaveAs);
1089void MenuOrchestrator::OnCreateProject() {
1091 if (editor_manager_) {
1092 auto status = editor_manager_->CreateNewProject();
1094 toast_manager_.Show(
1095 absl::StrFormat(
"Failed to create project: %s", status.message()),
1101void MenuOrchestrator::OnOpenProject() {
1103 if (editor_manager_) {
1104 auto status = editor_manager_->OpenProject();
1106 toast_manager_.Show(
1107 absl::StrFormat(
"Failed to open project: %s", status.message()),
1113void MenuOrchestrator::OnSaveProject() {
1115 if (editor_manager_) {
1116 auto status = editor_manager_->SaveProject();
1118 toast_manager_.Show(
1119 absl::StrFormat(
"Failed to save project: %s", status.message()),
1122 toast_manager_.Show(
"Project saved successfully", ToastType::kSuccess);
1127void MenuOrchestrator::OnSaveProjectAs() {
1129 if (editor_manager_) {
1130 auto status = editor_manager_->SaveProjectAs();
1132 toast_manager_.Show(
1133 absl::StrFormat(
"Failed to save project as: %s", status.message()),
1139void MenuOrchestrator::OnShowProjectManagement() {
1141 if (editor_manager_) {
1142 editor_manager_->ShowProjectManagement();
1146void MenuOrchestrator::OnShowProjectFileEditor() {
1148 if (editor_manager_) {
1149 editor_manager_->ShowProjectFileEditor();
1154void MenuOrchestrator::OnUndo() {
1155 if (editor_manager_) {
1156 auto* current_editor = editor_manager_->GetCurrentEditor();
1157 if (current_editor) {
1160 auto status = current_editor->
Undo();
1162 if (!desc.empty()) {
1163 toast_manager_.Show(absl::StrFormat(
"Undid: %s", desc),
1164 ToastType::kInfo, 2.0f);
1167 toast_manager_.Show(
1168 absl::StrFormat(
"Undo failed: %s", status.message()),
1175void MenuOrchestrator::OnRedo() {
1176 if (editor_manager_) {
1177 auto* current_editor = editor_manager_->GetCurrentEditor();
1178 if (current_editor) {
1181 auto status = current_editor->
Redo();
1183 if (!desc.empty()) {
1184 toast_manager_.Show(absl::StrFormat(
"Redid: %s", desc),
1185 ToastType::kInfo, 2.0f);
1188 toast_manager_.Show(
1189 absl::StrFormat(
"Redo failed: %s", status.message()),
1196void MenuOrchestrator::OnCut() {
1197 if (editor_manager_) {
1198 auto* current_editor = editor_manager_->GetCurrentEditor();
1199 if (current_editor) {
1200 auto status = current_editor->
Cut();
1202 toast_manager_.Show(absl::StrFormat(
"Cut failed: %s", status.message()),
1209void MenuOrchestrator::OnCopy() {
1210 if (editor_manager_) {
1211 auto* current_editor = editor_manager_->GetCurrentEditor();
1212 if (current_editor) {
1213 auto status = current_editor->
Copy();
1215 toast_manager_.Show(
1216 absl::StrFormat(
"Copy failed: %s", status.message()),
1223void MenuOrchestrator::OnPaste() {
1224 if (editor_manager_) {
1225 auto* current_editor = editor_manager_->GetCurrentEditor();
1226 if (current_editor) {
1227 auto status = current_editor->
Paste();
1229 toast_manager_.Show(
1230 absl::StrFormat(
"Paste failed: %s", status.message()),
1237void MenuOrchestrator::OnFind() {
1238 if (editor_manager_) {
1239 auto* current_editor = editor_manager_->GetCurrentEditor();
1240 if (current_editor) {
1241 auto status = current_editor->
Find();
1243 toast_manager_.Show(
1244 absl::StrFormat(
"Find failed: %s", status.message()),
1254 if (editor_manager_) {
1255 editor_manager_->SwitchToEditor(editor_type);
1259void MenuOrchestrator::OnShowEditorSelection() {
1261 if (editor_manager_) {
1262 if (
auto* ui = editor_manager_->ui_coordinator()) {
1263 ui->ShowEditorSelection();
1268void MenuOrchestrator::OnShowDisplaySettings() {
1269 popup_manager_.Show(PopupID::kDisplaySettings);
1272void MenuOrchestrator::OnShowHexEditor() {
1274 if (editor_manager_) {
1275 editor_manager_->window_manager().OpenWindow(
1276 editor_manager_->GetCurrentSessionId(),
"Hex Editor");
1280void MenuOrchestrator::OnShowPanelBrowser() {
1281 if (editor_manager_) {
1282 if (
auto* ui = editor_manager_->ui_coordinator()) {
1283 ui->SetWindowBrowserVisible(
true);
1288void MenuOrchestrator::OnShowPanelFinder() {
1289 if (editor_manager_) {
1290 if (
auto* ui = editor_manager_->ui_coordinator()) {
1291 ui->ShowPanelFinder();
1296void MenuOrchestrator::OnShowWelcomeScreen() {
1297 if (editor_manager_) {
1298 if (
auto* ui = editor_manager_->ui_coordinator()) {
1299 ui->SetWelcomeScreenVisible(
true);
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);
1313void MenuOrchestrator::OnShowProposalDrawer() {
1314 if (editor_manager_) {
1315 if (
auto* ui = editor_manager_->ui_coordinator()) {
1316 ui->SetProposalDrawerVisible(
true);
1323void MenuOrchestrator::OnCreateNewSession() {
1324 session_coordinator_.CreateNewSession();
1327void MenuOrchestrator::OnDuplicateCurrentSession() {
1328 session_coordinator_.DuplicateCurrentSession();
1331void MenuOrchestrator::OnCloseCurrentSession() {
1332 if (editor_manager_) {
1333 editor_manager_->CloseCurrentSession();
1335 session_coordinator_.CloseCurrentSession();
1339void MenuOrchestrator::OnShowSessionSwitcher() {
1341 if (editor_manager_) {
1342 if (
auto* ui = editor_manager_->ui_coordinator()) {
1343 ui->ShowSessionSwitcher();
1348void MenuOrchestrator::OnShowSessionManager() {
1349 popup_manager_.Show(PopupID::kSessionManager);
1353void MenuOrchestrator::OnShowAllWindows() {
1355 if (editor_manager_) {
1356 if (
auto* ui = editor_manager_->ui_coordinator()) {
1357 ui->ShowAllWindows();
1362void MenuOrchestrator::OnHideAllWindows() {
1364 if (editor_manager_) {
1365 editor_manager_->HideAllWindows();
1369void MenuOrchestrator::OnResetWorkspaceLayout() {
1371 if (editor_manager_) {
1372 editor_manager_->QueueDeferredAction([
this]() {
1373 editor_manager_->ResetWorkspaceLayout();
1374 toast_manager_.Show(
"Layout reset to default", ToastType::kInfo);
1379void MenuOrchestrator::OnSaveWorkspaceLayout() {
1381 if (editor_manager_) {
1382 editor_manager_->SaveWorkspaceLayout();
1386void MenuOrchestrator::OnLoadWorkspaceLayout() {
1388 if (editor_manager_) {
1389 editor_manager_->LoadWorkspaceLayout();
1393void MenuOrchestrator::OnShowLayoutPresets() {
1394 popup_manager_.Show(PopupID::kLayoutPresets);
1397void MenuOrchestrator::OnShowLayoutDesigner() {
1399 if (manager ==
nullptr && editor_manager_ !=
nullptr) {
1400 manager = &editor_manager_->window_manager();
1402 if (manager ==
nullptr) {
1403 toast_manager_.Show(
"Layout Designer unavailable: no window manager",
1411 WorkspaceWindowManager::kDashboardCategory) {
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",
1431void MenuOrchestrator::OnLoadDeveloperLayout() {
1432 if (editor_manager_) {
1433 editor_manager_->ApplyLayoutPreset(
"Developer");
1437void MenuOrchestrator::OnLoadDesignerLayout() {
1438 if (editor_manager_) {
1439 editor_manager_->ApplyLayoutPreset(
"Designer");
1443void MenuOrchestrator::OnLoadModderLayout() {
1444 if (editor_manager_) {
1445 editor_manager_->ApplyLayoutPreset(
"Modder");
1450void MenuOrchestrator::OnShowGlobalSearch() {
1451 if (editor_manager_) {
1452 if (
auto* ui = editor_manager_->ui_coordinator()) {
1453 ui->ShowGlobalSearch();
1458void MenuOrchestrator::OnShowCommandPalette() {
1459 if (editor_manager_) {
1460 if (
auto* ui = editor_manager_->ui_coordinator()) {
1461 ui->ShowCommandPalette();
1466void MenuOrchestrator::OnShowPerformanceDashboard() {
1467 if (editor_manager_) {
1468 if (
auto* ui = editor_manager_->ui_coordinator()) {
1469 ui->SetPerformanceDashboardVisible(
true);
1474void MenuOrchestrator::OnShowImGuiDemo() {
1475 if (editor_manager_) {
1476 editor_manager_->ShowImGuiDemo();
1480void MenuOrchestrator::OnShowImGuiMetrics() {
1481 if (editor_manager_) {
1482 editor_manager_->ShowImGuiMetrics();
1486void MenuOrchestrator::OnShowMemoryEditor() {
1487 if (editor_manager_) {
1488 editor_manager_->window_manager().OpenWindow(
1489 editor_manager_->GetCurrentSessionId(),
"Memory Editor");
1493void MenuOrchestrator::OnShowResourceLabelManager() {
1494 if (editor_manager_) {
1495 if (
auto* ui = editor_manager_->ui_coordinator()) {
1496 ui->SetResourceLabelManagerVisible(
true);
1501#ifdef YAZE_ENABLE_TESTING
1502void MenuOrchestrator::OnShowTestDashboard() {
1503 if (editor_manager_) {
1504 editor_manager_->ShowTestDashboard();
1508void MenuOrchestrator::OnRunAllTests() {
1509 toast_manager_.Show(
"Running all tests...", ToastType::kInfo);
1513void MenuOrchestrator::OnRunUnitTests() {
1514 toast_manager_.Show(
"Running unit tests...", ToastType::kInfo);
1518void MenuOrchestrator::OnRunIntegrationTests() {
1519 toast_manager_.Show(
"Running integration tests...", ToastType::kInfo);
1523void MenuOrchestrator::OnRunE2ETests() {
1524 toast_manager_.Show(
1525 "E2E runner is not wired in-app yet. Use scripts/agents/run-tests.sh or "
1527 ToastType::kWarning);
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);
1539void MenuOrchestrator::OnJoinCollaboration() {
1540 toast_manager_.Show(
1541 "Join collaboration is not wired yet. Use the web client + yaze-server.",
1542 ToastType::kWarning);
1545void MenuOrchestrator::OnShowNetworkStatus() {
1546 toast_manager_.Show(
"Network status panel is not implemented yet.",
1547 ToastType::kWarning);
1552void MenuOrchestrator::OnShowAbout() {
1553 popup_manager_.Show(PopupID::kAbout);
1556void MenuOrchestrator::OnShowGettingStarted() {
1557 popup_manager_.Show(PopupID::kGettingStarted);
1560void MenuOrchestrator::OnShowBuildInstructions() {
1561 popup_manager_.Show(PopupID::kBuildInstructions);
1564void MenuOrchestrator::OnShowCLIUsage() {
1565 popup_manager_.Show(PopupID::kCLIUsage);
1568void MenuOrchestrator::OnShowTroubleshooting() {
1569 popup_manager_.Show(PopupID::kTroubleshooting);
1572void MenuOrchestrator::OnShowContributing() {
1573 popup_manager_.Show(PopupID::kContributing);
1576void MenuOrchestrator::OnShowWhatsNew() {
1577 popup_manager_.Show(PopupID::kWhatsNew);
1580void MenuOrchestrator::OnShowSupportedFeatures() {
1581 popup_manager_.Show(PopupID::kSupportedFeatures);
1585void MenuOrchestrator::OnShowRomInfo() {
1586 popup_manager_.Show(PopupID::kRomInfo);
1589void MenuOrchestrator::OnCreateBackup() {
1590 if (editor_manager_) {
1591 auto status = rom_manager_.CreateBackup(editor_manager_->GetCurrentRom());
1593 toast_manager_.Show(
"Backup created successfully", ToastType::kSuccess);
1595 toast_manager_.Show(
1596 absl::StrFormat(
"Backup failed: %s", status.message()),
1602void MenuOrchestrator::OnValidateRom() {
1603 if (editor_manager_) {
1604 auto status = rom_manager_.ValidateRom(editor_manager_->GetCurrentRom());
1606 toast_manager_.Show(
"ROM validation passed", ToastType::kSuccess);
1608 toast_manager_.Show(
1609 absl::StrFormat(
"ROM validation failed: %s", status.message()),
1615void MenuOrchestrator::OnShowSettings() {
1617 if (editor_manager_) {
1618 editor_manager_->SwitchToEditor(EditorType::kSettings);
1622void MenuOrchestrator::OnQuit() {
1623 if (editor_manager_) {
1624 editor_manager_->Quit();
1629bool MenuOrchestrator::CanSaveRom()
const {
1630 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() :
nullptr;
1631 return rom ? rom_manager_.IsRomLoaded(rom) :
false;
1634bool MenuOrchestrator::CanSaveProject()
const {
1635 return project_manager_.HasActiveProject();
1638bool MenuOrchestrator::HasActiveRom()
const {
1639 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() :
nullptr;
1640 return rom ? rom_manager_.IsRomLoaded(rom) :
false;
1643bool MenuOrchestrator::HasActiveProject()
const {
1644 return project_manager_.HasActiveProject();
1647bool MenuOrchestrator::HasProjectFile()
const {
1650 const auto* project =
1651 editor_manager_ ? editor_manager_->GetCurrentProject() :
nullptr;
1652 return project && !project->filepath.empty();
1655bool MenuOrchestrator::HasCurrentEditor()
const {
1656 return editor_manager_ && editor_manager_->GetCurrentEditor() !=
nullptr;
1659bool MenuOrchestrator::HasMultipleSessions()
const {
1660 return session_coordinator_.HasMultipleSessions();
1664std::string MenuOrchestrator::GetRomFilename()
const {
1665 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() :
nullptr;
1666 return rom ? rom_manager_.GetRomFilename(rom) :
"";
1669std::string MenuOrchestrator::GetProjectName()
const {
1670 return project_manager_.GetProjectName();
1673std::string MenuOrchestrator::GetCurrentEditorName()
const {
1675 return "Unknown Editor";
1679std::string MenuOrchestrator::GetShortcutForAction(
1680 const std::string& action)
const {
1685void MenuOrchestrator::RegisterGlobalShortcuts() {
1693void MenuOrchestrator::OnRunDataIntegrityCheck() {
1694#ifdef YAZE_ENABLE_TESTING
1695 if (!editor_manager_)
1697 auto* rom = editor_manager_->GetCurrentRom();
1701 toast_manager_.Show(
"Running ROM integrity tests...", ToastType::kInfo);
1704 toast_manager_.Show(
"Data integrity check completed", ToastType::kSuccess,
1707 toast_manager_.Show(
"Testing not enabled in this build", ToastType::kWarning);
1711void MenuOrchestrator::OnTestSaveLoad() {
1712#ifdef YAZE_ENABLE_TESTING
1713 if (!editor_manager_)
1715 auto* rom = editor_manager_->GetCurrentRom();
1719 toast_manager_.Show(
"Running ROM save/load tests...", ToastType::kInfo);
1721 toast_manager_.Show(
"Save/load test completed", ToastType::kSuccess, 3.0f);
1723 toast_manager_.Show(
"Testing not enabled in this build", ToastType::kWarning);
1727void MenuOrchestrator::OnCheckRomVersion() {
1728 if (!editor_manager_)
1730 auto* rom = editor_manager_->GetCurrentRom();
1736 std::string version_str =
1737 (version == 0xFF) ?
"Vanilla" : absl::StrFormat(
"v%d", version);
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);
1745void MenuOrchestrator::OnUpgradeRom() {
1746 if (!editor_manager_)
1748 auto* rom = editor_manager_->GetCurrentRom();
1752 toast_manager_.Show(
"Use Overworld Editor to upgrade ROM version",
1753 ToastType::kInfo, 4.0f);
1756void MenuOrchestrator::OnToggleCustomLoading() {
1758 flags.overworld.kLoadCustomOverworld = !flags.overworld.kLoadCustomOverworld;
1760 toast_manager_.Show(
1762 "Custom Overworld Loading: %s",
1763 flags.overworld.kLoadCustomOverworld ?
"Enabled" :
"Disabled"),
1767void MenuOrchestrator::OnToggleAsarPatch() {
1768 if (!editor_manager_)
1770 auto* rom = editor_manager_->GetCurrentRom();
1775 flags.overworld.kApplyZSCustomOverworldASM =
1776 !flags.overworld.kApplyZSCustomOverworldASM;
1778 toast_manager_.Show(
1780 "ZSCustomOverworld ASM Application: %s",
1781 flags.overworld.kApplyZSCustomOverworldASM ?
"Enabled" :
"Disabled"),
1785void MenuOrchestrator::OnLoadAsmFile() {
1786 toast_manager_.Show(
"ASM file loading not yet implemented",
1787 ToastType::kWarning);
1790void MenuOrchestrator::OnShowAssemblyEditor() {
1791 if (editor_manager_) {
1792 editor_manager_->SwitchToEditor(EditorType::kAssembly);
1796void MenuOrchestrator::OnExportBpsPatch() {
1797 if (!editor_manager_)
1799 auto* rom = editor_manager_->GetCurrentRom();
1805 std::string original_path =
1807 if (original_path.empty()) {
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()),
1822 std::vector<uint8_t> patch_data;
1823 auto create_status =
1825 if (!create_status.ok()) {
1826 toast_manager_.Show(absl::StrFormat(
"Failed to create BPS patch: %s",
1827 create_status.message()),
1833 std::string default_name = rom->
short_name() +
".bps";
1834 std::string save_path =
1836 if (save_path.empty()) {
1841 if (save_path.size() < 4 ||
1842 save_path.substr(save_path.size() - 4) !=
".bps") {
1843 save_path +=
".bps";
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),
1855 file.write(
reinterpret_cast<const char*
>(patch_data.data()),
1860 toast_manager_.Show(
1861 absl::StrFormat(
"Failed to write patch file: %s", save_path),
1866 toast_manager_.Show(absl::StrFormat(
"BPS patch exported: %s (%zu bytes)",
1867 save_path, patch_data.size()),
1868 ToastType::kSuccess);
1871void MenuOrchestrator::OnApplyBpsPatch() {
1872 if (!editor_manager_)
1874 auto* rom = editor_manager_->GetCurrentRom();
1880 options.
filters.push_back({
"BPS Patch",
"bps"});
1882 if (patch_path.empty()) {
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),
1895 std::vector<uint8_t> patch_data((std::istreambuf_iterator<char>(file)),
1896 std::istreambuf_iterator<char>());
1899 if (patch_data.empty()) {
1900 toast_manager_.Show(
"Patch file is empty", ToastType::kError);
1905 std::vector<uint8_t> patched_rom;
1908 if (!apply_status.ok()) {
1909 toast_manager_.Show(absl::StrFormat(
"Failed to apply BPS patch: %s",
1910 apply_status.message()),
1917 if (!load_status.ok()) {
1918 toast_manager_.Show(absl::StrFormat(
"Failed to load patched ROM data: %s",
1919 load_status.message()),
1925 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 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_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