8#include <initializer_list>
10#include "absl/status/status.h"
11#include "absl/strings/match.h"
12#include "absl/strings/str_format.h"
23#include "imgui/misc/cpp/imgui_stdlib.h"
34 : editor_manager_(editor_manager), status_(absl::OkStatus()) {}
156 for (
auto& [name, params] :
popups_) {
157 if (params.is_visible) {
158 OpenPopup(name.c_str());
161 ImGuiWindowFlags popup_flags = params.allow_resize
162 ? ImGuiWindowFlags_None
163 : ImGuiWindowFlags_AlwaysAutoResize;
165 if (BeginPopupModal(name.c_str(),
nullptr, popup_flags)) {
166 params.draw_function();
178 std::string name_str(name);
179 auto it =
popups_.find(name_str);
181 it->second.is_visible =
true;
185 "[PopupManager] Warning: Popup '%s' not registered. Available popups: ",
187 for (
const auto& [key, _] :
popups_) {
188 printf(
"'%s' ", key.c_str());
199 std::string name_str(name);
200 auto it =
popups_.find(name_str);
202 it->second.is_visible =
false;
212 std::string name_str(name);
213 auto it =
popups_.find(name_str);
215 return it->second.is_visible;
229 ImGuiIO
const& io = GetIO();
230 ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
231 SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
232 ImGuiWindowFlags flags =
233 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
234 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;
235 return Begin(name,
nullptr, flags);
249 IsKeyPressed(ImGuiKey_Space)) {
262 Text(tr(
"Yet Another Zelda3 Editor - v%s"),
264 Text(tr(
"Written by: scawful"));
266 Text(tr(
"Special Thanks: Zarby89, JaredBrian"));
279 Text(tr(
"Title: %s"), current_rom->title().c_str());
286 if (project && project->project_opened()) {
290 Text(tr(
"Write Policy: %s"),
293 Text(tr(
"Expected Hash: %s"),
294 project->rom_metadata.expected_hash.empty()
296 : project->rom_metadata.expected_hash.c_str());
300 tr(
"ROM hash mismatch detected"));
305 IsKeyPressed(ImGuiKey_Escape)) {
306 Hide(
"ROM Information");
311 using namespace ImGui;
316 static std::string save_as_filename =
"";
321 InputText(tr(
"Filename"), &save_as_filename);
328 if (!file_path.empty()) {
329 save_as_filename = file_path;
334 if (Button(absl::StrFormat(
"%s Save",
ICON_MD_SAVE).c_str(),
336 if (!save_as_filename.empty()) {
338 std::string final_filename = save_as_filename;
339 if (final_filename.find(
".sfc") == std::string::npos &&
340 final_filename.find(
".smc") == std::string::npos) {
341 final_filename +=
".sfc";
346 save_as_filename =
"";
355 save_as_filename =
"";
361 using namespace ImGui;
366 tr(
"Controls which data is written during File > Save ROM. "
367 "Changes apply immediately."));
370 if (CollapsingHeader(tr(
"Overworld"), ImGuiTreeNodeFlags_DefaultOpen)) {
371 Checkbox(tr(
"Save Overworld Maps"),
373 Checkbox(tr(
"Save Overworld Entrances"),
375 Checkbox(tr(
"Save Overworld Exits"),
377 Checkbox(tr(
"Save Overworld Items"),
379 Checkbox(tr(
"Save Overworld Properties"),
383 if (CollapsingHeader(tr(
"Dungeon"), ImGuiTreeNodeFlags_DefaultOpen)) {
384 Checkbox(tr(
"Save Dungeon Maps"),
386 Checkbox(tr(
"Save Objects"),
388 Checkbox(tr(
"Save Sprites"),
390 Checkbox(tr(
"Save Room Headers"),
392 Checkbox(tr(
"Save Torches"),
396 Checkbox(tr(
"Save Collision"),
399 Checkbox(tr(
"Save Pot Items"),
401 Checkbox(tr(
"Save Palettes"),
405 if (CollapsingHeader(tr(
"Graphics"), ImGuiTreeNodeFlags_DefaultOpen)) {
406 Checkbox(tr(
"Save Graphics Sheets"),
408 Checkbox(tr(
"Save All Palettes"),
413 if (CollapsingHeader(tr(
"Messages"), ImGuiTreeNodeFlags_DefaultOpen)) {
424 using namespace ImGui;
428 Text(tr(
"No ROM loaded."));
436 std::string backup_dir;
437 if (project && project->project_opened() &&
438 !project->rom_backup_folder.empty()) {
441 backup_dir = std::filesystem::path(rom->
filename()).parent_path().string();
446 TextWrapped(tr(
"Backup folder: %s"), backup_dir.c_str());
451 tr(
"A restored backup is staged in this session. Save ROM to commit "
452 "it. Discard reloads the backing ROM and abandons staged ROM-buffer "
453 "edits; resolve pending graphics, dungeon, or palette edits "
459 toast->Show(absl::StrFormat(
"Discard failed: %s", status.message()),
463 toast->Show(
"Restored backup discarded; reloaded ROM from disk",
474 toast->Show(absl::StrFormat(
"Prune failed: %s", status.message()),
484 if (backups.empty()) {
485 TextDisabled(tr(
"No backups found."));
486 }
else if (BeginTable(
"RomBackupTable", 4,
487 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
488 ImGuiTableFlags_Resizable)) {
489 TableSetupColumn(
"Timestamp");
490 TableSetupColumn(
"Size");
491 TableSetupColumn(
"Filename");
492 TableSetupColumn(
"Actions");
495 auto format_size = [](uintmax_t bytes) {
496 if (bytes > (1024 * 1024)) {
497 return absl::StrFormat(
"%.2f MB",
498 static_cast<double>(bytes) / (1024 * 1024));
501 return absl::StrFormat(
"%.1f KB",
static_cast<double>(bytes) / 1024.0);
503 return absl::StrFormat(
"%llu B",
static_cast<unsigned long long>(bytes));
506 for (
size_t i = 0; i < backups.size(); ++i) {
507 const auto& backup = backups[i];
510 char time_buffer[32] =
"unknown";
511 if (backup.timestamp != 0) {
514 localtime_s(&local_tm, &backup.timestamp);
516 localtime_r(&backup.timestamp, &local_tm);
518 std::strftime(time_buffer,
sizeof(time_buffer),
"%Y-%m-%d %H:%M:%S",
521 TextUnformatted(time_buffer);
524 TextUnformatted(format_size(backup.size_bytes).c_str());
527 TextUnformatted(backup.filename.c_str());
530 PushID(
static_cast<int>(i));
535 toast->Show(absl::StrFormat(
"Restore failed: %s", status.message()),
539 toast->Show(
"Backup loaded; inspect it, then save ROM to commit",
548 toast->Show(absl::StrFormat(
"Open failed: %s", status.message()),
555 SetClipboardText(backup.path.c_str());
569 using namespace ImGui;
571 static std::string project_name =
"";
572 static std::string project_filepath =
"";
573 static std::string rom_filename =
"";
574 static std::string labels_filename =
"";
575 static std::string code_folder =
"";
577 InputText(tr(
"Project Name"), &project_name);
579 if (Button(absl::StrFormat(
"%s Destination Folder",
ICON_MD_FOLDER).c_str(),
584 Text(
"%s", project_filepath.empty() ?
"(Not set)" : project_filepath.c_str());
592 Text(
"%s", rom_filename.empty() ?
"(Not set)" : rom_filename.c_str());
594 if (Button(absl::StrFormat(
"%s Labels File",
ICON_MD_LABEL).c_str(),
599 Text(
"%s", labels_filename.empty() ?
"(Not set)" : labels_filename.c_str());
601 if (Button(absl::StrFormat(
"%s Code Folder",
ICON_MD_CODE).c_str(),
606 Text(
"%s", code_folder.empty() ?
"(Not set)" : code_folder.c_str());
610 if (Button(absl::StrFormat(
"%s Choose Project File Location",
ICON_MD_SAVE)
613 auto project_file_path =
615 if (!project_file_path.empty()) {
616 if (!(absl::EndsWith(project_file_path,
".yaze") ||
617 absl::EndsWith(project_file_path,
".yazeproj"))) {
618 project_file_path +=
".yaze";
620 project_filepath = project_file_path;
624 if (Button(absl::StrFormat(
"%s Create Project",
ICON_MD_ADD).c_str(),
626 if (!project_filepath.empty() && !project_name.empty() &&
627 !rom_filename.empty()) {
629 "Basic ROM Hack", rom_filename, project_name, project_filepath);
633 if (!labels_filename.empty()) {
636 if (!code_folder.empty()) {
637 project->code_folder = code_folder;
639 if (!labels_filename.empty() || !code_folder.empty()) {
648 project_filepath =
"";
650 labels_filename =
"";
663 project_filepath =
"";
665 labels_filename =
"";
678 auto status_color = [&](
const char* status) -> ImVec4 {
679 if (strcmp(status,
"Stable") == 0 || strcmp(status,
"Working") == 0) {
682 if (strcmp(status,
"Beta") == 0 || strcmp(status,
"Experimental") == 0) {
685 if (strcmp(status,
"Preview") == 0) {
688 if (strcmp(status,
"Not available") == 0) {
697 const char* persistence;
701 auto draw_table = [&](
const char* table_id,
702 std::initializer_list<FeatureRow> rows) {
703 ImGuiTableFlags flags = ImGuiTableFlags_BordersInnerH |
704 ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
705 if (!BeginTable(table_id, 4, flags)) {
708 TableSetupColumn(
"Feature", ImGuiTableColumnFlags_WidthStretch);
709 TableSetupColumn(
"Status", ImGuiTableColumnFlags_WidthFixed, 120.0f);
710 TableSetupColumn(
"Save/Load", ImGuiTableColumnFlags_WidthFixed, 180.0f);
711 TableSetupColumn(
"Notes", ImGuiTableColumnFlags_WidthStretch);
714 for (
const auto& row : rows) {
716 TableSetColumnIndex(0);
717 TextUnformatted(row.feature);
718 TableSetColumnIndex(1);
719 TextColored(status_color(row.status),
"%s", row.status);
720 TableSetColumnIndex(2);
721 TextUnformatted(row.persistence);
722 TableSetColumnIndex(3);
723 TextWrapped(
"%s", row.notes);
730 tr(
"Status: Stable = production ready, Beta = usable with gaps, "
731 "Experimental = WIP, Preview = web parity in progress."));
732 TextDisabled(tr(
"See Settings > Feature Flags for ROM-specific toggles."));
735 if (CollapsingHeader(tr(
"Desktop App (yaze)"),
736 ImGuiTreeNodeFlags_DefaultOpen)) {
737 draw_table(
"desktop_features",
739 {
"ROM load/save",
"Stable",
"ROM + backups",
740 "Backups on save when enabled."},
741 {
"Overworld Editor",
"Stable",
"ROM",
742 "Maps/entrances/exits/items; version-gated."},
743 {
"Dungeon Editor",
"Stable",
"ROM",
744 "Room objects/tiles/palettes persist."},
745 {
"Palette Editor",
"Stable",
"ROM",
746 "Palette edits persist; JSON IO pending."},
747 {
"Graphics Editor",
"Beta",
"ROM",
748 "Sheet edits persist; tooling still expanding."},
749 {
"Sprite Editor",
"Stable",
"ROM",
"Sprite edits persist."},
750 {
"Message Editor",
"Stable",
"ROM",
"Text edits persist."},
751 {
"Screen Editor",
"Experimental",
"ROM (partial)",
752 "Save coverage incomplete."},
753 {
"Hex Editor",
"Beta",
"ROM",
"Search UX incomplete."},
754 {
"Assembly/Asar",
"Beta",
"ROM + project",
755 "Patch apply + symbol export."},
756 {
"Emulator",
"Beta",
"Runtime only",
757 "Save-state UI partially wired."},
758 {
"Music Editor",
"Experimental",
"ROM (partial)",
759 "Serialization in progress."},
760 {
"Agent UI",
"Experimental",
".yaze/agent",
761 "Requires AI provider configuration."},
762 {
"Settings/Layouts",
"Beta",
".yaze config",
763 "Layout serialization improving."},
767 if (CollapsingHeader(tr(
"z3ed CLI"))) {
768 draw_table(
"cli_features",
770 {
"ROM read/write/validate",
"Stable",
"ROM file",
771 "Direct command execution."},
772 {
"Agent workflows",
"Stable",
".yaze/proposals + sandboxes",
773 "Commit writes ROM; revert reloads."},
774 {
"Snapshots/restore",
"Stable",
"Sandbox copies",
775 "Supports YAZE_SANDBOX_ROOT override."},
776 {
"Doctor/test suites",
"Stable",
"Reports",
777 "Structured output for automation."},
778 {
"TUI/REPL",
"Stable",
"Session history",
779 "Interactive command palette + logs."},
783 if (CollapsingHeader(tr(
"Web/WASM Preview"))) {
787 {
"ROM load/save",
"Preview",
"IndexedDB + download",
788 "Drag/drop or picker; download for backups."},
789 {
"Editors (OW/Dungeon/Palette/etc.)",
"Preview",
790 "IndexedDB + download",
"Parity work in progress."},
791 {
"Hex Editor",
"Working",
"IndexedDB + download",
792 "Direct ROM editing available."},
793 {
"Asar patching",
"Preview",
"ROM",
"Basic patch apply support."},
794 {
"Emulator",
"Not available",
"N/A",
"Desktop only."},
795 {
"Collaboration",
"Experimental",
"Server",
796 "Requires yaze-server."},
797 {
"AI features",
"Preview",
"Server",
"Requires AI-enabled server."},
807 Text(tr(
"File -> Open"));
808 Text(tr(
"Select a ROM file to open"));
809 Text(tr(
"Supported ROMs (headered or unheadered):"));
810 Text(tr(
"The Legend of Zelda: A Link to the Past"));
811 Text(tr(
"US Version 1.0"));
812 Text(tr(
"JP Version 1.0"));
815 tr(
"ROM files are not bundled. Use a clean, legally obtained copy."));
823 Text(tr(
"Project Menu"));
824 Text(tr(
"Create a new project or open an existing one."));
825 Text(tr(
"Save the project to save the current state of the project."));
827 tr(
"To save a project, you need to first open a ROM and initialize your "
828 "code path and labels file. Label resource manager can be found in "
829 "the View menu. Code path is set in the Code editor after opening a "
833 Hide(
"Manage Project");
840 "YAZE lets you modify 'The Legend of Zelda: A Link to the Past' (US or "
841 "JP) ROMs with modern tooling."));
843 TextWrapped(tr(
"Release Highlights:"));
845 tr(
"AI-assisted workflows via z3ed agent and in-app panels "
846 "(Ollama/Gemini/OpenAI/Anthropic)"));
847 BulletText(tr(
"Clear feature status panels and improved help/tooltips"));
848 BulletText(tr(
"Unified .yaze storage across desktop/CLI/web"));
850 TextWrapped(tr(
"General Tips:"));
851 BulletText(tr(
"Open a clean ROM and save a backup before editing"));
852 BulletText(tr(
"Use Help (F1) for context-aware guidance and shortcuts"));
854 "Configure AI providers (Ollama/Gemini/OpenAI/Anthropic) in Settings > "
858 Hide(
"Getting Started");
863 TextWrapped(tr(
"Asar 65816 Assembly Integration"));
865 tr(
"YAZE includes full Asar assembler support for ROM patching."));
867 TextWrapped(tr(
"Features:"));
868 BulletText(tr(
"Cross-platform ROM patching with assembly code"));
869 BulletText(tr(
"Symbol export with addresses and opcodes"));
870 BulletText(tr(
"Assembly validation with detailed error reporting"));
871 BulletText(tr(
"Memory-safe patch application with size checks"));
874 Hide(
"Asar Integration");
879 TextWrapped(tr(
"Build Instructions"));
880 TextWrapped(tr(
"YAZE uses modern CMake for cross-platform builds."));
882 TextWrapped(tr(
"Quick Start (examples):"));
883 BulletText(tr(
"cmake --preset mac-dbg | lin-dbg | win-dbg"));
884 BulletText(tr(
"cmake --build --preset <preset> --target yaze"));
886 TextWrapped(tr(
"AI Builds:"));
887 BulletText(tr(
"cmake --preset mac-ai | lin-ai | win-ai"));
888 BulletText(tr(
"cmake --build --preset <preset> --target yaze z3ed"));
890 TextWrapped(tr(
"Docs: docs/public/build/quick-reference.md"));
893 Hide(
"Build Instructions");
898 TextWrapped(tr(
"Command Line Interface (z3ed)"));
899 TextWrapped(tr(
"Scriptable ROM editing and AI agent workflows."));
901 TextWrapped(tr(
"Commands:"));
902 BulletText(tr(
"z3ed rom-info --rom=zelda3.sfc"));
903 BulletText(tr(
"z3ed agent simple-chat --rom=zelda3.sfc --ai_provider=auto"));
904 BulletText(tr(
"z3ed agent plan --rom=zelda3.sfc"));
905 BulletText(tr(
"z3ed test-list --format json"));
906 BulletText(tr(
"z3ed patch apply-asar patch.asm --rom=zelda3.sfc"));
907 BulletText(tr(
"z3ed help dungeon-place-sprite"));
909 TextWrapped(tr(
"Storage:"));
911 tr(
"Agent plans/proposals live under ~/.yaze (see docs for details)"));
919 TextWrapped(tr(
"Troubleshooting"));
920 TextWrapped(tr(
"Common issues and solutions:"));
922 BulletText(tr(
"ROM won't load: Check file format (SFC/SMC supported)"));
924 tr(
"AI agent missing: Start Ollama or set GEMINI_API_KEY/OPENAI_API_KEY/"
925 "ANTHROPIC_API_KEY (web uses AI_AGENT_ENDPOINT)"));
926 BulletText(tr(
"Graphics issues: Disable experimental flags in Settings"));
928 tr(
"Performance: Enable hardware acceleration in display settings"));
929 BulletText(tr(
"Crashes: Check ROM file integrity and available memory"));
930 BulletText(tr(
"Layout issues: Reset workspace layouts from View > Layouts"));
933 Hide(
"Troubleshooting");
938 TextWrapped(tr(
"Contributing to YAZE"));
939 TextWrapped(tr(
"YAZE is open source and welcomes contributions!"));
941 TextWrapped(tr(
"How to contribute:"));
942 BulletText(tr(
"Fork the repository on GitHub"));
943 BulletText(tr(
"Create feature branches for new work"));
944 BulletText(tr(
"Follow C++ coding standards"));
945 BulletText(tr(
"Include tests for new features"));
946 BulletText(tr(
"Submit pull requests for review"));
949 Hide(
"Contributing");
957 if (CollapsingHeader(
960 ImGuiTreeNodeFlags_DefaultOpen)) {
962 tr(
"Feature status/persistence summaries across desktop/CLI/web"));
963 BulletText(tr(
"Shortcut/help panels now match configured keybindings"));
964 BulletText(tr(
"Refined onboarding tips and error messaging"));
965 BulletText(tr(
"Help text refreshed across desktop, CLI, and web"));
968 if (CollapsingHeader(
969 absl::StrFormat(
"%s Development & Build System",
ICON_MD_BUILD)
971 ImGuiTreeNodeFlags_DefaultOpen)) {
972 BulletText(tr(
"Asar 65816 assembler integration for ROM patching"));
973 BulletText(tr(
"z3ed CLI + TUI for scripting, test/doctor, and automation"));
974 BulletText(tr(
"Modern CMake presets for desktop, AI, and web builds"));
975 BulletText(tr(
"Unified version + storage references for 0.5.1"));
978 if (CollapsingHeader(
980 BulletText(tr(
"Improved project metadata + .yaze storage alignment"));
981 BulletText(tr(
"Stronger error reporting and status feedback"));
982 BulletText(tr(
"Performance and stability improvements across editors"));
983 BulletText(tr(
"Expanded logging and diagnostics tooling"));
986 if (CollapsingHeader(
987 absl::StrFormat(
"%s Editor Features",
ICON_MD_EDIT).c_str())) {
988 BulletText(tr(
"Music editor updates with SPC parsing/playback"));
990 tr(
"AI agent-assisted editing workflows (multi-provider + vision)"));
991 BulletText(tr(
"Expanded overworld/dungeon tooling and palette accuracy"));
992 BulletText(tr(
"Web/WASM preview with collaboration hooks"));
1010 TextWrapped(tr(
"Workspace Management"));
1012 "YAZE supports multiple ROM sessions and flexible workspace layouts."));
1015 TextWrapped(tr(
"Session Management:"));
1016 BulletText(tr(
"Ctrl+Shift+N: Create new session"));
1017 BulletText(tr(
"Ctrl+Shift+W: Close current session"));
1018 BulletText(tr(
"Ctrl+Tab: Quick session switcher"));
1019 BulletText(tr(
"Each session maintains its own ROM and editor state"));
1022 TextWrapped(tr(
"Layout Management:"));
1023 BulletText(tr(
"Drag window tabs to dock/undock"));
1024 BulletText(tr(
"Ctrl+Shift+S: Save current layout"));
1025 BulletText(tr(
"Ctrl+Shift+O: Load saved layout"));
1026 BulletText(tr(
"F11: Maximize current window"));
1029 TextWrapped(tr(
"Preset Layouts:"));
1030 BulletText(tr(
"Developer: Code, memory, testing tools"));
1031 BulletText(tr(
"Designer: Graphics, palettes, sprites"));
1032 BulletText(tr(
"Modder: All gameplay editing tools"));
1035 Hide(
"Workspace Help");
1041 TextWrapped(tr(
"You have reached the recommended session limit."));
1042 TextWrapped(tr(
"Having too many sessions open may impact performance."));
1044 TextWrapped(tr(
"Consider closing unused sessions or saving your work."));
1047 Hide(
"Session Limit Warning");
1051 Hide(
"Session Limit Warning");
1058 TextWrapped(tr(
"This will reset your current workspace layout to default."));
1059 TextWrapped(tr(
"Any custom window arrangements will be lost."));
1061 TextWrapped(tr(
"Do you want to continue?"));
1064 Hide(
"Layout Reset Confirm");
1069 Hide(
"Layout Reset Confirm");
1079 tr(
"Choose a workspace preset to quickly configure your layout:"));
1086 const char* description;
1090 PresetInfo presets[] = {
1092 "Essential cards only - maximum editing space",
1095 "Debug and development focused - CPU/Memory/Breakpoints",
1098 "Visual and artistic focused - Graphics/Palettes/Sprites",
1101 "Full-featured - All tools available for comprehensive editing",
1104 "Complete overworld editing toolkit with all map tools",
1107 "Complete dungeon editing toolkit with room tools",
1109 {
"Testing",
ICON_MD_SCIENCE,
"Quality assurance and ROM testing layout",
1115 constexpr int kPresetCount = 8;
1118 float button_width = 200.0f;
1119 float button_height = 50.0f;
1121 for (
int i = 0; i < kPresetCount; i++) {
1127 ImVec2(0.0f, 0.5f));
1128 if (Button(absl::StrFormat(
"%s %s", presets[i].icon, presets[i].name)
1130 ImVec2(button_width, button_height))) {
1132 auto preset = presets[i].getter();
1137 for (
const auto& panel_id : preset.default_visible_panels) {
1138 window_manager.OpenWindow(panel_id);
1144 if (IsItemHovered()) {
1146 TextUnformatted(presets[i].description);
1161 if (current_editor) {
1162 auto current_type = current_editor->
type();
1163 window_manager.ResetToDefaults(0, current_type);
1169 if (Button(tr(
"Close"), ImVec2(-1, 0))) {
1182 Text(tr(
"Active Sessions: %zu"), session_count);
1186 if (BeginTable(
"SessionTable", 4,
1187 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
1188 TableSetupColumn(
"#", ImGuiTableColumnFlags_WidthFixed, 30.0f);
1189 TableSetupColumn(
"ROM", ImGuiTableColumnFlags_WidthStretch);
1190 TableSetupColumn(
"Status", ImGuiTableColumnFlags_WidthFixed, 80.0f);
1191 TableSetupColumn(
"Actions", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1194 for (
size_t i = 0; i < session_count; i++) {
1198 TableSetColumnIndex(0);
1202 TableSetColumnIndex(1);
1203 if (i == active_session) {
1206 TextUnformatted(rom->
filename().c_str());
1208 TextDisabled(tr(
"(No ROM loaded)"));
1211 TextDisabled(tr(
"Session %zu"), i + 1);
1215 TableSetColumnIndex(2);
1216 if (i == active_session) {
1220 TextDisabled(tr(
"Inactive"));
1224 TableSetColumnIndex(3);
1225 PushID(
static_cast<int>(i));
1227 if (i != active_session) {
1228 if (SmallButton(tr(
"Switch"))) {
1234 BeginDisabled(session_count <= 1);
1235 if (SmallButton(tr(
"Close"))) {
1251 if (Button(absl::StrFormat(
"%s New Session",
ICON_MD_ADD).c_str(),
1257 if (Button(tr(
"Close"), ImVec2(-1, 0))) {
1264 SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
1265 SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
1268 TextWrapped(tr(
"Customize your YAZE experience - accessible anytime!"));
1273 float available_height =
1274 GetContentRegionAvail().y - 60;
1275 if (BeginChild(
"DisplaySettingsContent", ImVec2(0, available_height),
true,
1276 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1285 ImGuiIO& io = GetIO();
1287 Text(tr(
"Global Font Scale"));
1288 float font_global_scale = io.FontGlobalScale;
1289 if (SliderFloat(
"##global_scale", &font_global_scale, 0.5f, 2.0f,
"%.2f")) {
1293 io.FontGlobalScale = font_global_scale;
1301 Hide(
"Display Settings");
1306 using namespace ImGui;
1309 Text(tr(
"Feature Flags Configuration"));
1312 BeginChild(
"##FlagsContent", ImVec2(0, -30),
true);
1317 if (BeginTabBar(
"FlagCategories")) {
1318 if (BeginTabItem(tr(
"Overworld"))) {
1322 if (BeginTabItem(tr(
"Dungeon"))) {
1326 if (BeginTabItem(tr(
"Resources"))) {
1330 if (BeginTabItem(tr(
"System"))) {
1346 using namespace ImGui;
1348 Text(tr(
"Data Integrity Check Results"));
1351 BeginChild(
"##IntegrityContent", ImVec2(0, -30),
true);
1355 Text(tr(
"ROM Data Integrity:"));
1363 Text(tr(
"No issues detected."));
1374 using namespace ImGui;
1377 Text(tr(
"Editor manager unavailable."));
1387 Text(tr(
"Pot Item Save Confirmation"));
1389 TextWrapped(tr(
"Dungeon pot item saving is enabled, but %d of %d rooms are "
1394 tr(
"Saving now can overwrite pot items in unloaded rooms. Choose how to "
1398 if (Button(tr(
"Save without pot items"), ImVec2(0, 0))) {
1405 const bool save_anyway = Button(tr(
"Save anyway"), ImVec2(0, 0));
1406 if (ImGui::GetItemID() != 0) {
1408 "dungeon.pot_item_save_confirm/button:Save anyway",
"button",
1410 "Continue the pending dungeon save with pot item writes enabled");
1419 if (Button(tr(
"Cancel"), ImVec2(0, 0))) {
1427 using namespace ImGui;
1430 Text(tr(
"Editor manager unavailable."));
1446 const auto editable_path =
1447 project && project->hack_manifest.loaded() &&
1448 !project->hack_manifest.build_pipeline().dev_rom.empty()
1449 ? project->GetAbsolutePath(
1450 project->hack_manifest.build_pipeline().dev_rom)
1451 : (project ? project->rom_filename : std::string());
1453 Text(tr(
"ROM Write Confirmation"));
1456 tr(
"The loaded ROM hash does not match the project's expected hash."));
1458 Text(tr(
"Role: %s"), role.c_str());
1459 Text(tr(
"Write policy: %s"), policy.c_str());
1460 Text(tr(
"Loaded ROM: %s"),
1461 actual_path.empty() ?
"(unknown)" : actual_path.c_str());
1462 Text(tr(
"Editable target: %s"),
1463 editable_path.empty() ?
"(unset)" : editable_path.c_str());
1464 Text(tr(
"Expected: %s"), expected.empty() ?
"(unset)" : expected.c_str());
1465 Text(tr(
"Actual: %s"), actual.empty() ?
"(unknown)" : actual.c_str());
1468 "Proceeding will write to the current ROM file. This may corrupt a base "
1469 "or release ROM if it is not the intended editable project ROM."));
1472 if (Button(tr(
"Save anyway"), ImVec2(0, 0))) {
1476 if (!status.ok() && !absl::IsCancelled(status)) {
1478 toast->Show(absl::StrFormat(
"Save failed: %s", status.message()),
1485 if (Button(tr(
"Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1492 using namespace ImGui;
1495 Text(tr(
"Editor manager unavailable."));
1508 tr(
"The following ROM addresses are owned by ASM hooks and will be "
1509 "overwritten on next build. Saving now will write data that asar "
1513 if (!conflicts.empty()) {
1514 if (BeginTable(
"WriteConflictTable", 3,
1515 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
1516 ImGuiTableFlags_Resizable)) {
1517 TableSetupColumn(
"Address", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1518 TableSetupColumn(
"Ownership", ImGuiTableColumnFlags_WidthFixed, 140.0f);
1519 TableSetupColumn(
"Module", ImGuiTableColumnFlags_WidthStretch);
1522 for (
const auto& conflict : conflicts) {
1525 Text(
"$%06X", conflict.address);
1530 if (!conflict.module.empty()) {
1531 TextUnformatted(conflict.module.c_str());
1533 TextDisabled(tr(
"(unknown)"));
1541 Text(tr(
"%zu conflict(s) detected."), conflicts.size());
1544 if (Button(tr(
"Save Anyway"), ImVec2(0, 0))) {
1548 if (!status.ok() && !absl::IsCancelled(status)) {
1550 toast->Show(absl::StrFormat(
"Save failed: %s", status.message()),
1557 if (Button(tr(
"Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1564 using namespace ImGui;
1582 const std::string save_label =
1590 const std::string continue_label =
1599 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()
bool IsRomBackupRestorePending() const
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()
absl::Status DiscardPendingRomBackupRestore()
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.