8#include <initializer_list>
10#include "absl/status/status.h"
11#include "absl/strings/match.h"
12#include "absl/strings/str_format.h"
22#include "imgui/misc/cpp/imgui_stdlib.h"
33 : editor_manager_(editor_manager), status_(absl::OkStatus()) {}
155 for (
auto& [name, params] :
popups_) {
156 if (params.is_visible) {
157 OpenPopup(name.c_str());
160 ImGuiWindowFlags popup_flags = params.allow_resize
161 ? ImGuiWindowFlags_None
162 : ImGuiWindowFlags_AlwaysAutoResize;
164 if (BeginPopupModal(name.c_str(),
nullptr, popup_flags)) {
165 params.draw_function();
177 std::string name_str(name);
178 auto it =
popups_.find(name_str);
180 it->second.is_visible =
true;
184 "[PopupManager] Warning: Popup '%s' not registered. Available popups: ",
186 for (
const auto& [key, _] :
popups_) {
187 printf(
"'%s' ", key.c_str());
198 std::string name_str(name);
199 auto it =
popups_.find(name_str);
201 it->second.is_visible =
false;
211 std::string name_str(name);
212 auto it =
popups_.find(name_str);
214 return it->second.is_visible;
228 ImGuiIO
const& io = GetIO();
229 ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
230 SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
231 ImGuiWindowFlags flags =
232 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
233 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;
234 return Begin(name,
nullptr, flags);
248 IsKeyPressed(ImGuiKey_Space)) {
261 Text(tr(
"Yet Another Zelda3 Editor - v%s"),
263 Text(tr(
"Written by: scawful"));
265 Text(tr(
"Special Thanks: Zarby89, JaredBrian"));
278 Text(tr(
"Title: %s"), current_rom->title().c_str());
285 if (project && project->project_opened()) {
289 Text(tr(
"Write Policy: %s"),
292 Text(tr(
"Expected Hash: %s"),
293 project->rom_metadata.expected_hash.empty()
295 : project->rom_metadata.expected_hash.c_str());
299 tr(
"ROM hash mismatch detected"));
304 IsKeyPressed(ImGuiKey_Escape)) {
305 Hide(
"ROM Information");
310 using namespace ImGui;
315 static std::string save_as_filename =
"";
320 InputText(tr(
"Filename"), &save_as_filename);
327 if (!file_path.empty()) {
328 save_as_filename = file_path;
333 if (Button(absl::StrFormat(
"%s Save",
ICON_MD_SAVE).c_str(),
335 if (!save_as_filename.empty()) {
337 std::string final_filename = save_as_filename;
338 if (final_filename.find(
".sfc") == std::string::npos &&
339 final_filename.find(
".smc") == std::string::npos) {
340 final_filename +=
".sfc";
345 save_as_filename =
"";
354 save_as_filename =
"";
360 using namespace ImGui;
365 tr(
"Controls which data is written during File > Save ROM. "
366 "Changes apply immediately."));
369 if (CollapsingHeader(tr(
"Overworld"), ImGuiTreeNodeFlags_DefaultOpen)) {
370 Checkbox(tr(
"Save Overworld Maps"),
372 Checkbox(tr(
"Save Overworld Entrances"),
374 Checkbox(tr(
"Save Overworld Exits"),
376 Checkbox(tr(
"Save Overworld Items"),
378 Checkbox(tr(
"Save Overworld Properties"),
382 if (CollapsingHeader(tr(
"Dungeon"), ImGuiTreeNodeFlags_DefaultOpen)) {
383 Checkbox(tr(
"Save Dungeon Maps"),
385 Checkbox(tr(
"Save Objects"),
387 Checkbox(tr(
"Save Sprites"),
389 Checkbox(tr(
"Save Room Headers"),
391 Checkbox(tr(
"Save Torches"),
395 Checkbox(tr(
"Save Collision"),
398 Checkbox(tr(
"Save Pot Items"),
400 Checkbox(tr(
"Save Palettes"),
404 if (CollapsingHeader(tr(
"Graphics"), ImGuiTreeNodeFlags_DefaultOpen)) {
405 Checkbox(tr(
"Save Graphics Sheets"),
407 Checkbox(tr(
"Save All Palettes"),
412 if (CollapsingHeader(tr(
"Messages"), ImGuiTreeNodeFlags_DefaultOpen)) {
423 using namespace ImGui;
427 Text(tr(
"No ROM loaded."));
435 std::string backup_dir;
436 if (project && project->project_opened() &&
437 !project->rom_backup_folder.empty()) {
440 backup_dir = std::filesystem::path(rom->
filename()).parent_path().string();
445 TextWrapped(tr(
"Backup folder: %s"), backup_dir.c_str());
451 toast->Show(absl::StrFormat(
"Prune failed: %s", status.message()),
461 if (backups.empty()) {
462 TextDisabled(tr(
"No backups found."));
463 }
else if (BeginTable(
"RomBackupTable", 4,
464 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
465 ImGuiTableFlags_Resizable)) {
466 TableSetupColumn(
"Timestamp");
467 TableSetupColumn(
"Size");
468 TableSetupColumn(
"Filename");
469 TableSetupColumn(
"Actions");
472 auto format_size = [](uintmax_t bytes) {
473 if (bytes > (1024 * 1024)) {
474 return absl::StrFormat(
"%.2f MB",
475 static_cast<double>(bytes) / (1024 * 1024));
478 return absl::StrFormat(
"%.1f KB",
static_cast<double>(bytes) / 1024.0);
480 return absl::StrFormat(
"%llu B",
static_cast<unsigned long long>(bytes));
483 for (
size_t i = 0; i < backups.size(); ++i) {
484 const auto& backup = backups[i];
487 char time_buffer[32] =
"unknown";
488 if (backup.timestamp != 0) {
491 localtime_s(&local_tm, &backup.timestamp);
493 localtime_r(&backup.timestamp, &local_tm);
495 std::strftime(time_buffer,
sizeof(time_buffer),
"%Y-%m-%d %H:%M:%S",
498 TextUnformatted(time_buffer);
501 TextUnformatted(format_size(backup.size_bytes).c_str());
504 TextUnformatted(backup.filename.c_str());
507 PushID(
static_cast<int>(i));
512 toast->Show(absl::StrFormat(
"Restore failed: %s", status.message()),
524 toast->Show(absl::StrFormat(
"Open failed: %s", status.message()),
531 SetClipboardText(backup.path.c_str());
545 using namespace ImGui;
547 static std::string project_name =
"";
548 static std::string project_filepath =
"";
549 static std::string rom_filename =
"";
550 static std::string labels_filename =
"";
551 static std::string code_folder =
"";
553 InputText(tr(
"Project Name"), &project_name);
555 if (Button(absl::StrFormat(
"%s Destination Folder",
ICON_MD_FOLDER).c_str(),
560 Text(
"%s", project_filepath.empty() ?
"(Not set)" : project_filepath.c_str());
568 Text(
"%s", rom_filename.empty() ?
"(Not set)" : rom_filename.c_str());
570 if (Button(absl::StrFormat(
"%s Labels File",
ICON_MD_LABEL).c_str(),
575 Text(
"%s", labels_filename.empty() ?
"(Not set)" : labels_filename.c_str());
577 if (Button(absl::StrFormat(
"%s Code Folder",
ICON_MD_CODE).c_str(),
582 Text(
"%s", code_folder.empty() ?
"(Not set)" : code_folder.c_str());
586 if (Button(absl::StrFormat(
"%s Choose Project File Location",
ICON_MD_SAVE)
589 auto project_file_path =
591 if (!project_file_path.empty()) {
592 if (!(absl::EndsWith(project_file_path,
".yaze") ||
593 absl::EndsWith(project_file_path,
".yazeproj"))) {
594 project_file_path +=
".yaze";
596 project_filepath = project_file_path;
600 if (Button(absl::StrFormat(
"%s Create Project",
ICON_MD_ADD).c_str(),
602 if (!project_filepath.empty() && !project_name.empty() &&
603 !rom_filename.empty()) {
605 "Basic ROM Hack", rom_filename, project_name, project_filepath);
609 if (!labels_filename.empty()) {
612 if (!code_folder.empty()) {
613 project->code_folder = code_folder;
615 if (!labels_filename.empty() || !code_folder.empty()) {
624 project_filepath =
"";
626 labels_filename =
"";
639 project_filepath =
"";
641 labels_filename =
"";
654 auto status_color = [&](
const char* status) -> ImVec4 {
655 if (strcmp(status,
"Stable") == 0 || strcmp(status,
"Working") == 0) {
658 if (strcmp(status,
"Beta") == 0 || strcmp(status,
"Experimental") == 0) {
661 if (strcmp(status,
"Preview") == 0) {
664 if (strcmp(status,
"Not available") == 0) {
673 const char* persistence;
677 auto draw_table = [&](
const char* table_id,
678 std::initializer_list<FeatureRow> rows) {
679 ImGuiTableFlags flags = ImGuiTableFlags_BordersInnerH |
680 ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
681 if (!BeginTable(table_id, 4, flags)) {
684 TableSetupColumn(
"Feature", ImGuiTableColumnFlags_WidthStretch);
685 TableSetupColumn(
"Status", ImGuiTableColumnFlags_WidthFixed, 120.0f);
686 TableSetupColumn(
"Save/Load", ImGuiTableColumnFlags_WidthFixed, 180.0f);
687 TableSetupColumn(
"Notes", ImGuiTableColumnFlags_WidthStretch);
690 for (
const auto& row : rows) {
692 TableSetColumnIndex(0);
693 TextUnformatted(row.feature);
694 TableSetColumnIndex(1);
695 TextColored(status_color(row.status),
"%s", row.status);
696 TableSetColumnIndex(2);
697 TextUnformatted(row.persistence);
698 TableSetColumnIndex(3);
699 TextWrapped(
"%s", row.notes);
706 tr(
"Status: Stable = production ready, Beta = usable with gaps, "
707 "Experimental = WIP, Preview = web parity in progress."));
708 TextDisabled(tr(
"See Settings > Feature Flags for ROM-specific toggles."));
711 if (CollapsingHeader(tr(
"Desktop App (yaze)"),
712 ImGuiTreeNodeFlags_DefaultOpen)) {
713 draw_table(
"desktop_features",
715 {
"ROM load/save",
"Stable",
"ROM + backups",
716 "Backups on save when enabled."},
717 {
"Overworld Editor",
"Stable",
"ROM",
718 "Maps/entrances/exits/items; version-gated."},
719 {
"Dungeon Editor",
"Stable",
"ROM",
720 "Room objects/tiles/palettes persist."},
721 {
"Palette Editor",
"Stable",
"ROM",
722 "Palette edits persist; JSON IO pending."},
723 {
"Graphics Editor",
"Beta",
"ROM",
724 "Sheet edits persist; tooling still expanding."},
725 {
"Sprite Editor",
"Stable",
"ROM",
"Sprite edits persist."},
726 {
"Message Editor",
"Stable",
"ROM",
"Text edits persist."},
727 {
"Screen Editor",
"Experimental",
"ROM (partial)",
728 "Save coverage incomplete."},
729 {
"Hex Editor",
"Beta",
"ROM",
"Search UX incomplete."},
730 {
"Assembly/Asar",
"Beta",
"ROM + project",
731 "Patch apply + symbol export."},
732 {
"Emulator",
"Beta",
"Runtime only",
733 "Save-state UI partially wired."},
734 {
"Music Editor",
"Experimental",
"ROM (partial)",
735 "Serialization in progress."},
736 {
"Agent UI",
"Experimental",
".yaze/agent",
737 "Requires AI provider configuration."},
738 {
"Settings/Layouts",
"Beta",
".yaze config",
739 "Layout serialization improving."},
743 if (CollapsingHeader(tr(
"z3ed CLI"))) {
744 draw_table(
"cli_features",
746 {
"ROM read/write/validate",
"Stable",
"ROM file",
747 "Direct command execution."},
748 {
"Agent workflows",
"Stable",
".yaze/proposals + sandboxes",
749 "Commit writes ROM; revert reloads."},
750 {
"Snapshots/restore",
"Stable",
"Sandbox copies",
751 "Supports YAZE_SANDBOX_ROOT override."},
752 {
"Doctor/test suites",
"Stable",
"Reports",
753 "Structured output for automation."},
754 {
"TUI/REPL",
"Stable",
"Session history",
755 "Interactive command palette + logs."},
759 if (CollapsingHeader(tr(
"Web/WASM Preview"))) {
763 {
"ROM load/save",
"Preview",
"IndexedDB + download",
764 "Drag/drop or picker; download for backups."},
765 {
"Editors (OW/Dungeon/Palette/etc.)",
"Preview",
766 "IndexedDB + download",
"Parity work in progress."},
767 {
"Hex Editor",
"Working",
"IndexedDB + download",
768 "Direct ROM editing available."},
769 {
"Asar patching",
"Preview",
"ROM",
"Basic patch apply support."},
770 {
"Emulator",
"Not available",
"N/A",
"Desktop only."},
771 {
"Collaboration",
"Experimental",
"Server",
772 "Requires yaze-server."},
773 {
"AI features",
"Preview",
"Server",
"Requires AI-enabled server."},
783 Text(tr(
"File -> Open"));
784 Text(tr(
"Select a ROM file to open"));
785 Text(tr(
"Supported ROMs (headered or unheadered):"));
786 Text(tr(
"The Legend of Zelda: A Link to the Past"));
787 Text(tr(
"US Version 1.0"));
788 Text(tr(
"JP Version 1.0"));
791 tr(
"ROM files are not bundled. Use a clean, legally obtained copy."));
799 Text(tr(
"Project Menu"));
800 Text(tr(
"Create a new project or open an existing one."));
801 Text(tr(
"Save the project to save the current state of the project."));
803 tr(
"To save a project, you need to first open a ROM and initialize your "
804 "code path and labels file. Label resource manager can be found in "
805 "the View menu. Code path is set in the Code editor after opening a "
809 Hide(
"Manage Project");
816 "YAZE lets you modify 'The Legend of Zelda: A Link to the Past' (US or "
817 "JP) ROMs with modern tooling."));
819 TextWrapped(tr(
"Release Highlights:"));
821 tr(
"AI-assisted workflows via z3ed agent and in-app panels "
822 "(Ollama/Gemini/OpenAI/Anthropic)"));
823 BulletText(tr(
"Clear feature status panels and improved help/tooltips"));
824 BulletText(tr(
"Unified .yaze storage across desktop/CLI/web"));
826 TextWrapped(tr(
"General Tips:"));
827 BulletText(tr(
"Open a clean ROM and save a backup before editing"));
828 BulletText(tr(
"Use Help (F1) for context-aware guidance and shortcuts"));
830 "Configure AI providers (Ollama/Gemini/OpenAI/Anthropic) in Settings > "
834 Hide(
"Getting Started");
839 TextWrapped(tr(
"Asar 65816 Assembly Integration"));
841 tr(
"YAZE includes full Asar assembler support for ROM patching."));
843 TextWrapped(tr(
"Features:"));
844 BulletText(tr(
"Cross-platform ROM patching with assembly code"));
845 BulletText(tr(
"Symbol export with addresses and opcodes"));
846 BulletText(tr(
"Assembly validation with detailed error reporting"));
847 BulletText(tr(
"Memory-safe patch application with size checks"));
850 Hide(
"Asar Integration");
855 TextWrapped(tr(
"Build Instructions"));
856 TextWrapped(tr(
"YAZE uses modern CMake for cross-platform builds."));
858 TextWrapped(tr(
"Quick Start (examples):"));
859 BulletText(tr(
"cmake --preset mac-dbg | lin-dbg | win-dbg"));
860 BulletText(tr(
"cmake --build --preset <preset> --target yaze"));
862 TextWrapped(tr(
"AI Builds:"));
863 BulletText(tr(
"cmake --preset mac-ai | lin-ai | win-ai"));
864 BulletText(tr(
"cmake --build --preset <preset> --target yaze z3ed"));
866 TextWrapped(tr(
"Docs: docs/public/build/quick-reference.md"));
869 Hide(
"Build Instructions");
874 TextWrapped(tr(
"Command Line Interface (z3ed)"));
875 TextWrapped(tr(
"Scriptable ROM editing and AI agent workflows."));
877 TextWrapped(tr(
"Commands:"));
878 BulletText(tr(
"z3ed rom-info --rom=zelda3.sfc"));
879 BulletText(tr(
"z3ed agent simple-chat --rom=zelda3.sfc --ai_provider=auto"));
880 BulletText(tr(
"z3ed agent plan --rom=zelda3.sfc"));
881 BulletText(tr(
"z3ed test-list --format json"));
882 BulletText(tr(
"z3ed patch apply-asar patch.asm --rom=zelda3.sfc"));
883 BulletText(tr(
"z3ed help dungeon-place-sprite"));
885 TextWrapped(tr(
"Storage:"));
887 tr(
"Agent plans/proposals live under ~/.yaze (see docs for details)"));
895 TextWrapped(tr(
"Troubleshooting"));
896 TextWrapped(tr(
"Common issues and solutions:"));
898 BulletText(tr(
"ROM won't load: Check file format (SFC/SMC supported)"));
900 tr(
"AI agent missing: Start Ollama or set GEMINI_API_KEY/OPENAI_API_KEY/"
901 "ANTHROPIC_API_KEY (web uses AI_AGENT_ENDPOINT)"));
902 BulletText(tr(
"Graphics issues: Disable experimental flags in Settings"));
904 tr(
"Performance: Enable hardware acceleration in display settings"));
905 BulletText(tr(
"Crashes: Check ROM file integrity and available memory"));
906 BulletText(tr(
"Layout issues: Reset workspace layouts from View > Layouts"));
909 Hide(
"Troubleshooting");
914 TextWrapped(tr(
"Contributing to YAZE"));
915 TextWrapped(tr(
"YAZE is open source and welcomes contributions!"));
917 TextWrapped(tr(
"How to contribute:"));
918 BulletText(tr(
"Fork the repository on GitHub"));
919 BulletText(tr(
"Create feature branches for new work"));
920 BulletText(tr(
"Follow C++ coding standards"));
921 BulletText(tr(
"Include tests for new features"));
922 BulletText(tr(
"Submit pull requests for review"));
925 Hide(
"Contributing");
933 if (CollapsingHeader(
936 ImGuiTreeNodeFlags_DefaultOpen)) {
938 tr(
"Feature status/persistence summaries across desktop/CLI/web"));
939 BulletText(tr(
"Shortcut/help panels now match configured keybindings"));
940 BulletText(tr(
"Refined onboarding tips and error messaging"));
941 BulletText(tr(
"Help text refreshed across desktop, CLI, and web"));
944 if (CollapsingHeader(
945 absl::StrFormat(
"%s Development & Build System",
ICON_MD_BUILD)
947 ImGuiTreeNodeFlags_DefaultOpen)) {
948 BulletText(tr(
"Asar 65816 assembler integration for ROM patching"));
949 BulletText(tr(
"z3ed CLI + TUI for scripting, test/doctor, and automation"));
950 BulletText(tr(
"Modern CMake presets for desktop, AI, and web builds"));
951 BulletText(tr(
"Unified version + storage references for 0.5.1"));
954 if (CollapsingHeader(
956 BulletText(tr(
"Improved project metadata + .yaze storage alignment"));
957 BulletText(tr(
"Stronger error reporting and status feedback"));
958 BulletText(tr(
"Performance and stability improvements across editors"));
959 BulletText(tr(
"Expanded logging and diagnostics tooling"));
962 if (CollapsingHeader(
963 absl::StrFormat(
"%s Editor Features",
ICON_MD_EDIT).c_str())) {
964 BulletText(tr(
"Music editor updates with SPC parsing/playback"));
966 tr(
"AI agent-assisted editing workflows (multi-provider + vision)"));
967 BulletText(tr(
"Expanded overworld/dungeon tooling and palette accuracy"));
968 BulletText(tr(
"Web/WASM preview with collaboration hooks"));
986 TextWrapped(tr(
"Workspace Management"));
988 "YAZE supports multiple ROM sessions and flexible workspace layouts."));
991 TextWrapped(tr(
"Session Management:"));
992 BulletText(tr(
"Ctrl+Shift+N: Create new session"));
993 BulletText(tr(
"Ctrl+Shift+W: Close current session"));
994 BulletText(tr(
"Ctrl+Tab: Quick session switcher"));
995 BulletText(tr(
"Each session maintains its own ROM and editor state"));
998 TextWrapped(tr(
"Layout Management:"));
999 BulletText(tr(
"Drag window tabs to dock/undock"));
1000 BulletText(tr(
"Ctrl+Shift+S: Save current layout"));
1001 BulletText(tr(
"Ctrl+Shift+O: Load saved layout"));
1002 BulletText(tr(
"F11: Maximize current window"));
1005 TextWrapped(tr(
"Preset Layouts:"));
1006 BulletText(tr(
"Developer: Code, memory, testing tools"));
1007 BulletText(tr(
"Designer: Graphics, palettes, sprites"));
1008 BulletText(tr(
"Modder: All gameplay editing tools"));
1011 Hide(
"Workspace Help");
1017 TextWrapped(tr(
"You have reached the recommended session limit."));
1018 TextWrapped(tr(
"Having too many sessions open may impact performance."));
1020 TextWrapped(tr(
"Consider closing unused sessions or saving your work."));
1023 Hide(
"Session Limit Warning");
1027 Hide(
"Session Limit Warning");
1034 TextWrapped(tr(
"This will reset your current workspace layout to default."));
1035 TextWrapped(tr(
"Any custom window arrangements will be lost."));
1037 TextWrapped(tr(
"Do you want to continue?"));
1040 Hide(
"Layout Reset Confirm");
1045 Hide(
"Layout Reset Confirm");
1055 tr(
"Choose a workspace preset to quickly configure your layout:"));
1062 const char* description;
1066 PresetInfo presets[] = {
1068 "Essential cards only - maximum editing space",
1071 "Debug and development focused - CPU/Memory/Breakpoints",
1074 "Visual and artistic focused - Graphics/Palettes/Sprites",
1077 "Full-featured - All tools available for comprehensive editing",
1080 "Complete overworld editing toolkit with all map tools",
1083 "Complete dungeon editing toolkit with room tools",
1085 {
"Testing",
ICON_MD_SCIENCE,
"Quality assurance and ROM testing layout",
1091 constexpr int kPresetCount = 8;
1094 float button_width = 200.0f;
1095 float button_height = 50.0f;
1097 for (
int i = 0; i < kPresetCount; i++) {
1103 ImVec2(0.0f, 0.5f));
1104 if (Button(absl::StrFormat(
"%s %s", presets[i].icon, presets[i].name)
1106 ImVec2(button_width, button_height))) {
1108 auto preset = presets[i].getter();
1113 for (
const auto& panel_id : preset.default_visible_panels) {
1114 window_manager.OpenWindow(panel_id);
1120 if (IsItemHovered()) {
1122 TextUnformatted(presets[i].description);
1137 if (current_editor) {
1138 auto current_type = current_editor->
type();
1139 window_manager.ResetToDefaults(0, current_type);
1145 if (Button(tr(
"Close"), ImVec2(-1, 0))) {
1158 Text(tr(
"Active Sessions: %zu"), session_count);
1162 if (BeginTable(
"SessionTable", 4,
1163 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
1164 TableSetupColumn(
"#", ImGuiTableColumnFlags_WidthFixed, 30.0f);
1165 TableSetupColumn(
"ROM", ImGuiTableColumnFlags_WidthStretch);
1166 TableSetupColumn(
"Status", ImGuiTableColumnFlags_WidthFixed, 80.0f);
1167 TableSetupColumn(
"Actions", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1170 for (
size_t i = 0; i < session_count; i++) {
1174 TableSetColumnIndex(0);
1178 TableSetColumnIndex(1);
1179 if (i == active_session) {
1182 TextUnformatted(rom->
filename().c_str());
1184 TextDisabled(tr(
"(No ROM loaded)"));
1187 TextDisabled(tr(
"Session %zu"), i + 1);
1191 TableSetColumnIndex(2);
1192 if (i == active_session) {
1196 TextDisabled(tr(
"Inactive"));
1200 TableSetColumnIndex(3);
1201 PushID(
static_cast<int>(i));
1203 if (i != active_session) {
1204 if (SmallButton(tr(
"Switch"))) {
1210 BeginDisabled(session_count <= 1);
1211 if (SmallButton(tr(
"Close"))) {
1227 if (Button(absl::StrFormat(
"%s New Session",
ICON_MD_ADD).c_str(),
1233 if (Button(tr(
"Close"), ImVec2(-1, 0))) {
1240 SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
1241 SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
1244 TextWrapped(tr(
"Customize your YAZE experience - accessible anytime!"));
1249 float available_height =
1250 GetContentRegionAvail().y - 60;
1251 if (BeginChild(
"DisplaySettingsContent", ImVec2(0, available_height),
true,
1252 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1261 ImGuiIO& io = GetIO();
1263 Text(tr(
"Global Font Scale"));
1264 float font_global_scale = io.FontGlobalScale;
1265 if (SliderFloat(
"##global_scale", &font_global_scale, 0.5f, 2.0f,
"%.2f")) {
1269 io.FontGlobalScale = font_global_scale;
1277 Hide(
"Display Settings");
1282 using namespace ImGui;
1285 Text(tr(
"Feature Flags Configuration"));
1288 BeginChild(
"##FlagsContent", ImVec2(0, -30),
true);
1293 if (BeginTabBar(
"FlagCategories")) {
1294 if (BeginTabItem(tr(
"Overworld"))) {
1298 if (BeginTabItem(tr(
"Dungeon"))) {
1302 if (BeginTabItem(tr(
"Resources"))) {
1306 if (BeginTabItem(tr(
"System"))) {
1322 using namespace ImGui;
1324 Text(tr(
"Data Integrity Check Results"));
1327 BeginChild(
"##IntegrityContent", ImVec2(0, -30),
true);
1331 Text(tr(
"ROM Data Integrity:"));
1339 Text(tr(
"No issues detected."));
1350 using namespace ImGui;
1353 Text(tr(
"Editor manager unavailable."));
1363 Text(tr(
"Pot Item Save Confirmation"));
1365 TextWrapped(tr(
"Dungeon pot item saving is enabled, but %d of %d rooms are "
1370 tr(
"Saving now can overwrite pot items in unloaded rooms. Choose how to "
1374 if (Button(tr(
"Save without pot items"), ImVec2(0, 0))) {
1381 if (Button(tr(
"Save anyway"), ImVec2(0, 0))) {
1388 if (Button(tr(
"Cancel"), ImVec2(0, 0))) {
1396 using namespace ImGui;
1399 Text(tr(
"Editor manager unavailable."));
1415 const auto editable_path =
1416 project && project->hack_manifest.loaded() &&
1417 !project->hack_manifest.build_pipeline().dev_rom.empty()
1418 ? project->GetAbsolutePath(
1419 project->hack_manifest.build_pipeline().dev_rom)
1420 : (project ? project->rom_filename : std::string());
1422 Text(tr(
"ROM Write Confirmation"));
1425 tr(
"The loaded ROM hash does not match the project's expected hash."));
1427 Text(tr(
"Role: %s"), role.c_str());
1428 Text(tr(
"Write policy: %s"), policy.c_str());
1429 Text(tr(
"Loaded ROM: %s"),
1430 actual_path.empty() ?
"(unknown)" : actual_path.c_str());
1431 Text(tr(
"Editable target: %s"),
1432 editable_path.empty() ?
"(unset)" : editable_path.c_str());
1433 Text(tr(
"Expected: %s"), expected.empty() ?
"(unset)" : expected.c_str());
1434 Text(tr(
"Actual: %s"), actual.empty() ?
"(unknown)" : actual.c_str());
1437 "Proceeding will write to the current ROM file. This may corrupt a base "
1438 "or release ROM if it is not the intended editable project ROM."));
1441 if (Button(tr(
"Save anyway"), ImVec2(0, 0))) {
1445 if (!status.ok() && !absl::IsCancelled(status)) {
1447 toast->Show(absl::StrFormat(
"Save failed: %s", status.message()),
1454 if (Button(tr(
"Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1461 using namespace ImGui;
1464 Text(tr(
"Editor manager unavailable."));
1477 tr(
"The following ROM addresses are owned by ASM hooks and will be "
1478 "overwritten on next build. Saving now will write data that asar "
1482 if (!conflicts.empty()) {
1483 if (BeginTable(
"WriteConflictTable", 3,
1484 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
1485 ImGuiTableFlags_Resizable)) {
1486 TableSetupColumn(
"Address", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1487 TableSetupColumn(
"Ownership", ImGuiTableColumnFlags_WidthFixed, 140.0f);
1488 TableSetupColumn(
"Module", ImGuiTableColumnFlags_WidthStretch);
1491 for (
const auto& conflict : conflicts) {
1494 Text(
"$%06X", conflict.address);
1499 if (!conflict.module.empty()) {
1500 TextUnformatted(conflict.module.c_str());
1502 TextDisabled(tr(
"(unknown)"));
1510 Text(tr(
"%zu conflict(s) detected."), conflicts.size());
1513 if (Button(tr(
"Save Anyway"), ImVec2(0, 0))) {
1517 if (!status.ok() && !absl::IsCancelled(status)) {
1519 toast->Show(absl::StrFormat(
"Save failed: %s", status.message()),
1526 if (Button(tr(
"Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1533 using namespace ImGui;
1551 const std::string save_label =
1559 const std::string continue_label =
1568 IsKeyPressed(ImGuiKey_Escape)) {
The EditorManager controls the main editor window and manages the various editor classes.
void ConfirmPendingUnsavedSessionActionSaveAndContinue()
absl::Status SaveRomAs(const std::string &filename)
void CancelPendingUnsavedSessionAction()
void SwitchToSession(size_t index)
absl::Status RestoreRomBackup(const std::string &backup_path)
size_t GetActiveSessionCount() const
Rom * GetCurrentRom() const override
std::vector< editor::RomFileManager::BackupEntry > GetRomBackups() const
void MarkCurrentProjectDirty()
project::RomWritePolicy GetProjectRomWritePolicy() const
absl::Status CreateNewProjectFromRom(const std::string &template_name, const std::string &rom_path, const std::string &project_name, const std::string &project_path=std::string())
void ConfirmPendingUnsavedSessionActionDiscardAndContinue()
std::string GetCurrentRomHash() const
bool HasPendingUnsavedSessionAction() const
void CancelRomWriteConfirm()
absl::Status PruneRomBackups()
void SetFontGlobalScale(float scale)
void ResolvePotItemSaveConfirmation(PotItemSaveDecision decision)
auto GetCurrentEditor() const -> Editor *override
WorkspaceWindowManager & window_manager()
std::string GetProjectExpectedRomHash() const
absl::Status SaveProject()
const std::vector< core::WriteConflict > & pending_write_conflicts() const
std::string GetPendingUnsavedSessionActionContinueLabel() const
std::string GetPendingUnsavedSessionActionPrompt() const
project::RomRole GetProjectRomRole() const
void BypassWriteConflictOnce()
void ClearPendingWriteConflicts()
size_t GetCurrentSessionIndex() const
project::YazeProject * GetCurrentProject()
bool IsRomHashMismatch() const
absl::Status ResumePendingRomSave()
int pending_pot_item_unloaded_rooms() const
int pending_pot_item_total_rooms() const
absl::Status OpenRomOrProject(const std::string &filename)
void RemoveSession(size_t index)
std::string GetPendingUnsavedSessionActionSaveLabel() const
ToastManager * toast_manager()
static PanelLayoutPreset GetLogicDebuggerPreset()
Get the "logic debugger" workspace preset (QA and debug focused)
static PanelLayoutPreset GetDungeonMasterPreset()
Get the "dungeon master" workspace preset.
static PanelLayoutPreset GetAudioEngineerPreset()
Get the "audio engineer" workspace preset (music focused)
static PanelLayoutPreset GetDesignerPreset()
Get the "designer" workspace preset (visual-focused)
static PanelLayoutPreset GetOverworldArtistPreset()
Get the "overworld artist" workspace preset.
static PanelLayoutPreset GetModderPreset()
Get the "modder" workspace preset (full-featured)
static PanelLayoutPreset GetMinimalPreset()
Get the "minimal" workspace preset (minimal cards)
static PanelLayoutPreset GetDeveloperPreset()
Get the "developer" workspace preset (debug-focused)
void HideAll(size_t session_id)
RAII guard for ImGui style vars.
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
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...
static std::string ShowOpenFolderDialog()
ShowOpenFolderDialog opens a file dialog and returns the selected folder path. Uses global feature fl...
#define YAZE_VERSION_STRING
#define ICON_MD_FOLDER_OPEN
#define ICON_MD_DOOR_SLIDING
#define ICON_MD_VIDEOGAME_ASSET
#define ICON_MD_BUG_REPORT
#define ICON_MD_MUSIC_NOTE
#define ICON_MD_DISPLAY_SETTINGS
#define ICON_MD_CHECK_CIRCLE
#define ICON_MD_DESCRIPTION
#define ICON_MD_DASHBOARD
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_CONTENT_COPY
#define ICON_MD_CROP_FREE
#define ICON_MD_DELETE_SWEEP
std::string AddressOwnershipToString(AddressOwnership ownership)
ImVec4 ConvertColorToImVec4(const Color &color)
void DrawDisplaySettingsForPopup(ImGuiStyle *ref)
constexpr ImVec2 kDefaultModalSize
void TextWithSeparators(const absl::string_view &text)
std::string RomRoleToString(RomRole role)
std::string RomWritePolicyToString(RomWritePolicy policy)
std::string HexLongLong(uint64_t qword, HexStringParams params)
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
Defines default panel visibility for an editor type.
std::string labels_filename
std::string GetAbsolutePath(const std::string &relative_path) const
Public YAZE API umbrella header.