yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
popup_manager.cc
Go to the documentation of this file.
1#include "popup_manager.h"
2
3#include <cstring>
4#include <ctime>
5#include <filesystem>
6#include <functional>
7#include <initializer_list>
8
9#include "absl/status/status.h"
10#include "absl/strings/match.h"
11#include "absl/strings/str_format.h"
15#include "app/gui/core/icons.h"
16#include "app/gui/core/input.h"
17#include "app/gui/core/style.h"
21#include "imgui/misc/cpp/imgui_stdlib.h"
22#include "util/file_util.h"
23#include "util/hex.h"
24#include "yaze.h"
25
26namespace yaze {
27namespace editor {
28
29using namespace ImGui;
30
32 : editor_manager_(editor_manager), status_(absl::OkStatus()) {}
33
35 // ============================================================================
36 // POPUP REGISTRATION
37 // ============================================================================
38 // All popups must be registered here BEFORE any menu callbacks can trigger
39 // them. This method is called in EditorManager constructor BEFORE
40 // MenuOrchestrator and UICoordinator are created, ensuring safe
41 // initialization order.
42 //
43 // Popup Registration Format:
44 // popups_[PopupID::kConstant] = {
45 // .name = PopupID::kConstant,
46 // .type = PopupType::kXxx,
47 // .is_visible = false,
48 // .allow_resize = false/true,
49 // .draw_function = [this]() { DrawXxxPopup(); }
50 // };
51 // ============================================================================
52
53 // File Operations
55 false, false, [this]() {
57 }};
59 false, true, [this]() {
61 }};
63 PopupID::kNewProject, PopupType::kFileOperation, false, false, [this]() {
65 }};
67 PopupType::kFileOperation, false, false,
68 [this]() {
70 }};
72 PopupType::kFileOperation, false, true,
73 [this]() { DrawRomBackupManagerPopup(); }};
74
75 // Information
77 [this]() {
79 }};
81 false, [this]() {
83 }};
85 PopupID::kSupportedFeatures, PopupType::kInfo, false, false, [this]() {
87 }};
89 false, false, [this]() {
91 }};
92
93 // Help Documentation
95 PopupID::kGettingStarted, PopupType::kHelp, false, false, [this]() {
97 }};
99 PopupID::kAsarIntegration, PopupType::kHelp, false, false, [this]() {
101 }};
103 PopupID::kBuildInstructions, PopupType::kHelp, false, false, [this]() {
105 }};
107 false, [this]() {
109 }};
111 PopupID::kTroubleshooting, PopupType::kHelp, false, false, [this]() {
113 }};
115 false, false, [this]() {
117 }};
119 false, [this]() {
121 }};
122
123 // Settings
126 true, // Resizable
127 [this]() {
129 }};
131 PopupID::kFeatureFlags, PopupType::kSettings, false, true, // Resizable
132 [this]() {
134 }};
135
136 // Workspace
138 false, false, [this]() {
140 }};
142 PopupType::kWarning, false, false,
143 [this]() {
145 }};
148 false, [this]() {
150 }};
151
153 PopupID::kLayoutPresets, PopupType::kSettings, false, false, [this]() {
155 }};
156
158 PopupID::kSessionManager, PopupType::kSettings, false, true, [this]() {
160 }};
161
162 // Debug/Testing
164 false, true, // Resizable
165 [this]() {
167 }};
168
171 false, [this]() { DrawDungeonPotItemSaveConfirmPopup(); }};
174 [this]() { DrawRomWriteConfirmPopup(); }};
177 [this]() { DrawWriteConflictWarningPopup(); }};
178}
179
181 // Draw status popup if needed
183
184 // Draw all registered popups
185 for (auto& [name, params] : popups_) {
186 if (params.is_visible) {
187 OpenPopup(name.c_str());
188
189 // Use allow_resize flag from popup definition
190 ImGuiWindowFlags popup_flags = params.allow_resize
191 ? ImGuiWindowFlags_None
192 : ImGuiWindowFlags_AlwaysAutoResize;
193
194 if (BeginPopupModal(name.c_str(), nullptr, popup_flags)) {
195 params.draw_function();
196 EndPopup();
197 }
198 }
199 }
200}
201
202void PopupManager::Show(const char* name) {
203 if (!name) {
204 return; // Safety check for null pointer
205 }
206
207 std::string name_str(name);
208 auto it = popups_.find(name_str);
209 if (it != popups_.end()) {
210 it->second.is_visible = true;
211 } else {
212 // Log warning for unregistered popup
213 printf(
214 "[PopupManager] Warning: Popup '%s' not registered. Available popups: ",
215 name);
216 for (const auto& [key, _] : popups_) {
217 printf("'%s' ", key.c_str());
218 }
219 printf("\n");
220 }
221}
222
223void PopupManager::Hide(const char* name) {
224 if (!name) {
225 return; // Safety check for null pointer
226 }
227
228 std::string name_str(name);
229 auto it = popups_.find(name_str);
230 if (it != popups_.end()) {
231 it->second.is_visible = false;
232 CloseCurrentPopup();
233 }
234}
235
236bool PopupManager::IsVisible(const char* name) const {
237 if (!name) {
238 return false; // Safety check for null pointer
239 }
240
241 std::string name_str(name);
242 auto it = popups_.find(name_str);
243 if (it != popups_.end()) {
244 return it->second.is_visible;
245 }
246 return false;
247}
248
249void PopupManager::SetStatus(const absl::Status& status) {
250 if (!status.ok()) {
251 show_status_ = true;
252 prev_status_ = status;
253 status_ = status;
254 }
255}
256
257bool PopupManager::BeginCentered(const char* name) {
258 ImGuiIO const& io = GetIO();
259 ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
260 SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
261 ImGuiWindowFlags flags =
262 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
263 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;
264 return Begin(name, nullptr, flags);
265}
266
268 if (show_status_ && BeginCentered("StatusWindow")) {
269 Text("%s", ICON_MD_ERROR);
270 Text("%s", prev_status_.ToString().c_str());
271 Spacing();
272 NextColumn();
273 Columns(1);
274 Separator();
275 NewLine();
276 SameLine(128);
277 if (Button("OK", ::yaze::gui::kDefaultModalSize) || IsKeyPressed(ImGuiKey_Space)) {
278 show_status_ = false;
279 status_ = absl::OkStatus();
280 }
281 SameLine();
282 if (Button(ICON_MD_CONTENT_COPY, ImVec2(50, 0))) {
283 SetClipboardText(prev_status_.ToString().c_str());
284 }
285 End();
286 }
287}
288
290 Text("Yet Another Zelda3 Editor - v%s", editor_manager_->version().c_str());
291 Text("Written by: scawful");
292 Spacing();
293 Text("Special Thanks: Zarby89, JaredBrian");
294 Separator();
295
296 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
297 Hide("About");
298 }
299}
300
302 auto* current_rom = editor_manager_->GetCurrentRom();
303 if (!current_rom)
304 return;
305
306 Text("Title: %s", current_rom->title().c_str());
307 Text("ROM Size: %s", util::HexLongLong(current_rom->size()).c_str());
308 Text("ROM Hash: %s",
310 ? "(unknown)"
312
313 auto* project = editor_manager_->GetCurrentProject();
314 if (project && project->project_opened()) {
315 Separator();
316 Text("Role: %s", project::RomRoleToString(project->rom_metadata.role).c_str());
317 Text("Write Policy: %s",
318 project::RomWritePolicyToString(project->rom_metadata.write_policy)
319 .c_str());
320 Text("Expected Hash: %s",
321 project->rom_metadata.expected_hash.empty()
322 ? "(unset)"
323 : project->rom_metadata.expected_hash.c_str());
325 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
326 TextColored(gui::ConvertColorToImVec4(theme.warning),
327 "ROM hash mismatch detected");
328 }
329 }
330
331 if (Button("Close", ::yaze::gui::kDefaultModalSize) ||
332 IsKeyPressed(ImGuiKey_Escape)) {
333 Hide("ROM Information");
334 }
335}
336
338 using namespace ImGui;
339
340 Text("%s Save ROM to new location", ICON_MD_SAVE_AS);
341 Separator();
342
343 static std::string save_as_filename = "";
344 if (editor_manager_->GetCurrentRom() && save_as_filename.empty()) {
345 save_as_filename = editor_manager_->GetCurrentRom()->title();
346 }
347
348 InputText("Filename", &save_as_filename);
349 Separator();
350
351 if (Button(absl::StrFormat("%s Browse...", ICON_MD_FOLDER_OPEN).c_str(),
353 auto file_path =
354 util::FileDialogWrapper::ShowSaveFileDialog(save_as_filename, "sfc");
355 if (!file_path.empty()) {
356 save_as_filename = file_path;
357 }
358 }
359
360 SameLine();
361 if (Button(absl::StrFormat("%s Save", ICON_MD_SAVE).c_str(),
363 if (!save_as_filename.empty()) {
364 // Ensure proper file extension
365 std::string final_filename = save_as_filename;
366 if (final_filename.find(".sfc") == std::string::npos &&
367 final_filename.find(".smc") == std::string::npos) {
368 final_filename += ".sfc";
369 }
370
371 auto status = editor_manager_->SaveRomAs(final_filename);
372 if (status.ok()) {
373 save_as_filename = "";
375 }
376 }
377 }
378
379 SameLine();
380 if (Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(),
382 save_as_filename = "";
384 }
385}
386
388 using namespace ImGui;
389
390 Text("%s Save Scope", ICON_MD_SAVE);
391 Separator();
392 TextWrapped(
393 "Controls which data is written during File > Save ROM. "
394 "Changes apply immediately.");
395 Separator();
396
397 if (CollapsingHeader("Overworld", ImGuiTreeNodeFlags_DefaultOpen)) {
398 Checkbox("Save Overworld Maps",
399 &core::FeatureFlags::get().overworld.kSaveOverworldMaps);
400 Checkbox("Save Overworld Entrances",
401 &core::FeatureFlags::get().overworld.kSaveOverworldEntrances);
402 Checkbox("Save Overworld Exits",
403 &core::FeatureFlags::get().overworld.kSaveOverworldExits);
404 Checkbox("Save Overworld Items",
405 &core::FeatureFlags::get().overworld.kSaveOverworldItems);
406 Checkbox("Save Overworld Properties",
407 &core::FeatureFlags::get().overworld.kSaveOverworldProperties);
408 }
409
410 if (CollapsingHeader("Dungeon", ImGuiTreeNodeFlags_DefaultOpen)) {
411 Checkbox("Save Dungeon Maps", &core::FeatureFlags::get().kSaveDungeonMaps);
412 Checkbox("Save Objects", &core::FeatureFlags::get().dungeon.kSaveObjects);
413 Checkbox("Save Sprites", &core::FeatureFlags::get().dungeon.kSaveSprites);
414 Checkbox("Save Room Headers",
415 &core::FeatureFlags::get().dungeon.kSaveRoomHeaders);
416 Checkbox("Save Torches", &core::FeatureFlags::get().dungeon.kSaveTorches);
417 Checkbox("Save Pits", &core::FeatureFlags::get().dungeon.kSavePits);
418 Checkbox("Save Blocks", &core::FeatureFlags::get().dungeon.kSaveBlocks);
419 Checkbox("Save Collision",
420 &core::FeatureFlags::get().dungeon.kSaveCollision);
421 Checkbox("Save Chests", &core::FeatureFlags::get().dungeon.kSaveChests);
422 Checkbox("Save Pot Items",
423 &core::FeatureFlags::get().dungeon.kSavePotItems);
424 Checkbox("Save Palettes",
425 &core::FeatureFlags::get().dungeon.kSavePalettes);
426 }
427
428 if (CollapsingHeader("Graphics", ImGuiTreeNodeFlags_DefaultOpen)) {
429 Checkbox("Save Graphics Sheets",
430 &core::FeatureFlags::get().kSaveGraphicsSheet);
431 Checkbox("Save All Palettes", &core::FeatureFlags::get().kSaveAllPalettes);
432 Checkbox("Save Gfx Groups", &core::FeatureFlags::get().kSaveGfxGroups);
433 }
434
435 if (CollapsingHeader("Messages", ImGuiTreeNodeFlags_DefaultOpen)) {
436 Checkbox("Save Message Text", &core::FeatureFlags::get().kSaveMessages);
437 }
438
439 Separator();
440 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
442 }
443}
444
446 using namespace ImGui;
447
448 auto* rom = editor_manager_->GetCurrentRom();
449 if (!rom || !rom->is_loaded()) {
450 Text("No ROM loaded.");
451 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
453 }
454 return;
455 }
456
457 const auto* project = editor_manager_->GetCurrentProject();
458 std::string backup_dir;
459 if (project && project->project_opened() &&
460 !project->rom_backup_folder.empty()) {
461 backup_dir = project->GetAbsolutePath(project->rom_backup_folder);
462 } else {
463 backup_dir = std::filesystem::path(rom->filename()).parent_path().string();
464 }
465
466 Text("%s ROM Backups", ICON_MD_BACKUP);
467 Separator();
468 TextWrapped("Backup folder: %s", backup_dir.c_str());
469
470 if (Button(ICON_MD_DELETE_SWEEP " Prune Backups")) {
471 auto status = editor_manager_->PruneRomBackups();
472 if (!status.ok()) {
473 if (auto* toast = editor_manager_->toast_manager()) {
474 toast->Show(absl::StrFormat("Prune failed: %s", status.message()),
476 }
477 } else if (auto* toast = editor_manager_->toast_manager()) {
478 toast->Show("Backups pruned", ToastType::kSuccess);
479 }
480 }
481
482 Separator();
483 auto backups = editor_manager_->GetRomBackups();
484 if (backups.empty()) {
485 TextDisabled("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");
493 TableHeadersRow();
494
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));
499 }
500 if (bytes > 1024) {
501 return absl::StrFormat("%.1f KB",
502 static_cast<double>(bytes) / 1024.0);
503 }
504 return absl::StrFormat("%llu B",
505 static_cast<unsigned long long>(bytes));
506 };
507
508 for (size_t i = 0; i < backups.size(); ++i) {
509 const auto& backup = backups[i];
510 TableNextRow();
511 TableNextColumn();
512 char time_buffer[32] = "unknown";
513 if (backup.timestamp != 0) {
514 std::tm local_tm{};
515#ifdef _WIN32
516 localtime_s(&local_tm, &backup.timestamp);
517#else
518 localtime_r(&backup.timestamp, &local_tm);
519#endif
520 std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S",
521 &local_tm);
522 }
523 TextUnformatted(time_buffer);
524
525 TableNextColumn();
526 TextUnformatted(format_size(backup.size_bytes).c_str());
527
528 TableNextColumn();
529 TextUnformatted(backup.filename.c_str());
530
531 TableNextColumn();
532 PushID(static_cast<int>(i));
533 if (Button(ICON_MD_RESTORE " Restore")) {
534 auto status = editor_manager_->RestoreRomBackup(backup.path);
535 if (!status.ok()) {
536 if (auto* toast = editor_manager_->toast_manager()) {
537 toast->Show(
538 absl::StrFormat("Restore failed: %s", status.message()),
540 }
541 } else if (auto* toast = editor_manager_->toast_manager()) {
542 toast->Show("ROM restored from backup", ToastType::kSuccess);
543 }
544 }
545 SameLine();
546 if (Button(ICON_MD_OPEN_IN_NEW " Open")) {
547 auto status = editor_manager_->OpenRomOrProject(backup.path);
548 if (!status.ok()) {
549 if (auto* toast = editor_manager_->toast_manager()) {
550 toast->Show(
551 absl::StrFormat("Open failed: %s", status.message()),
553 }
554 }
555 }
556 SameLine();
557 if (Button(ICON_MD_CONTENT_COPY " Copy")) {
558 SetClipboardText(backup.path.c_str());
559 }
560 PopID();
561 }
562 EndTable();
563 }
564
565 Separator();
566 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
568 }
569}
570
572 using namespace ImGui;
573
574 static std::string project_name = "";
575 static std::string project_filepath = "";
576 static std::string rom_filename = "";
577 static std::string labels_filename = "";
578 static std::string code_folder = "";
579
580 InputText("Project Name", &project_name);
581
582 if (Button(absl::StrFormat("%s Destination Folder", ICON_MD_FOLDER).c_str(),
585 }
586 SameLine();
587 Text("%s", project_filepath.empty() ? "(Not set)" : project_filepath.c_str());
588
589 if (Button(absl::StrFormat("%s ROM File", ICON_MD_VIDEOGAME_ASSET).c_str(),
593 }
594 SameLine();
595 Text("%s", rom_filename.empty() ? "(Not set)" : rom_filename.c_str());
596
597 if (Button(absl::StrFormat("%s Labels File", ICON_MD_LABEL).c_str(),
600 }
601 SameLine();
602 Text("%s", labels_filename.empty() ? "(Not set)" : labels_filename.c_str());
603
604 if (Button(absl::StrFormat("%s Code Folder", ICON_MD_CODE).c_str(),
607 }
608 SameLine();
609 Text("%s", code_folder.empty() ? "(Not set)" : code_folder.c_str());
610
611 Separator();
612
613 if (Button(absl::StrFormat("%s Choose Project File Location", ICON_MD_SAVE)
614 .c_str(),
616 auto project_file_path =
618 if (!project_file_path.empty()) {
619 if (!(absl::EndsWith(project_file_path, ".yaze") ||
620 absl::EndsWith(project_file_path, ".yazeproj"))) {
621 project_file_path += ".yaze";
622 }
623 project_filepath = project_file_path;
624 }
625 }
626
627 if (Button(absl::StrFormat("%s Create Project", ICON_MD_ADD).c_str(),
629 if (!project_filepath.empty() && !project_name.empty()) {
630 auto status = editor_manager_->CreateNewProject();
631 if (status.ok()) {
632 // Clear fields
633 project_name = "";
634 project_filepath = "";
635 rom_filename = "";
636 labels_filename = "";
637 code_folder = "";
639 }
640 }
641 }
642 SameLine();
643 if (Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(),
645 // Clear fields
646 project_name = "";
647 project_filepath = "";
648 rom_filename = "";
649 labels_filename = "";
650 code_folder = "";
652 }
653}
654
656 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
657 const ImVec4 status_ok = gui::ConvertColorToImVec4(theme.success);
658 const ImVec4 status_warn = gui::ConvertColorToImVec4(theme.warning);
659 const ImVec4 status_info = gui::ConvertColorToImVec4(theme.info);
660 const ImVec4 status_error = gui::ConvertColorToImVec4(theme.error);
661
662 auto status_color = [&](const char* status) -> ImVec4 {
663 if (strcmp(status, "Stable") == 0 || strcmp(status, "Working") == 0) {
664 return status_ok;
665 }
666 if (strcmp(status, "Beta") == 0 || strcmp(status, "Experimental") == 0) {
667 return status_warn;
668 }
669 if (strcmp(status, "Preview") == 0) {
670 return status_info;
671 }
672 if (strcmp(status, "Not available") == 0) {
673 return status_error;
674 }
675 return status_info;
676 };
677
678 struct FeatureRow {
679 const char* feature;
680 const char* status;
681 const char* persistence;
682 const char* notes;
683 };
684
685 auto draw_table = [&](const char* table_id,
686 std::initializer_list<FeatureRow> rows) {
687 ImGuiTableFlags flags = ImGuiTableFlags_BordersInnerH |
688 ImGuiTableFlags_RowBg |
689 ImGuiTableFlags_Resizable;
690 if (!BeginTable(table_id, 4, flags)) {
691 return;
692 }
693 TableSetupColumn("Feature", ImGuiTableColumnFlags_WidthStretch);
694 TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 120.0f);
695 TableSetupColumn("Save/Load", ImGuiTableColumnFlags_WidthFixed, 180.0f);
696 TableSetupColumn("Notes", ImGuiTableColumnFlags_WidthStretch);
697 TableHeadersRow();
698
699 for (const auto& row : rows) {
700 TableNextRow();
701 TableSetColumnIndex(0);
702 TextUnformatted(row.feature);
703 TableSetColumnIndex(1);
704 TextColored(status_color(row.status), "%s", row.status);
705 TableSetColumnIndex(2);
706 TextUnformatted(row.persistence);
707 TableSetColumnIndex(3);
708 TextWrapped("%s", row.notes);
709 }
710
711 EndTable();
712 };
713
714 TextDisabled(
715 "Status: Stable = production ready, Beta = usable with gaps, "
716 "Experimental = WIP, Preview = web parity in progress.");
717 TextDisabled("See Settings > Feature Flags for ROM-specific toggles.");
718 Spacing();
719
720 if (CollapsingHeader("Desktop App (yaze)", ImGuiTreeNodeFlags_DefaultOpen)) {
721 draw_table(
722 "desktop_features",
723 {
724 {"ROM load/save", "Stable", "ROM + backups",
725 "Backups on save when enabled."},
726 {"Overworld Editor", "Stable", "ROM",
727 "Maps/entrances/exits/items; version-gated."},
728 {"Dungeon Editor", "Stable", "ROM",
729 "Room objects/tiles/palettes persist."},
730 {"Palette Editor", "Stable", "ROM",
731 "Palette edits persist; JSON IO pending."},
732 {"Graphics Editor", "Beta", "ROM",
733 "Sheet edits persist; tooling still expanding."},
734 {"Sprite Editor", "Stable", "ROM", "Sprite edits persist."},
735 {"Message Editor", "Stable", "ROM", "Text edits persist."},
736 {"Screen Editor", "Experimental", "ROM (partial)",
737 "Save coverage incomplete."},
738 {"Hex Editor", "Beta", "ROM", "Search UX incomplete."},
739 {"Assembly/Asar", "Beta", "ROM + project",
740 "Patch apply + symbol export."},
741 {"Emulator", "Beta", "Runtime only",
742 "Save-state UI partially wired."},
743 {"Music Editor", "Experimental", "ROM (partial)",
744 "Serialization in progress."},
745 {"Agent UI", "Experimental", ".yaze/agent",
746 "Requires AI provider configuration."},
747 {"Settings/Layouts", "Beta", ".yaze config",
748 "Layout serialization improving."},
749 });
750 }
751
752 if (CollapsingHeader("z3ed CLI")) {
753 draw_table(
754 "cli_features",
755 {
756 {"ROM read/write/validate", "Stable", "ROM file",
757 "Direct command execution."},
758 {"Agent workflows", "Stable", ".yaze/proposals + sandboxes",
759 "Commit writes ROM; revert reloads."},
760 {"Snapshots/restore", "Stable", "Sandbox copies",
761 "Supports YAZE_SANDBOX_ROOT override."},
762 {"Doctor/test suites", "Stable", "Reports",
763 "Structured output for automation."},
764 {"TUI/REPL", "Stable", "Session history",
765 "Interactive command palette + logs."},
766 });
767 }
768
769 if (CollapsingHeader("Web/WASM Preview")) {
770 draw_table(
771 "web_features",
772 {
773 {"ROM load/save", "Preview", "IndexedDB + download",
774 "Drag/drop or picker; download for backups."},
775 {"Editors (OW/Dungeon/Palette/etc.)", "Preview",
776 "IndexedDB + download", "Parity work in progress."},
777 {"Hex Editor", "Working", "IndexedDB + download",
778 "Direct ROM editing available."},
779 {"Asar patching", "Preview", "ROM",
780 "Basic patch apply support."},
781 {"Emulator", "Not available", "N/A", "Desktop only."},
782 {"Collaboration", "Experimental", "Server",
783 "Requires yaze-server."},
784 {"AI features", "Preview", "Server",
785 "Requires AI-enabled server."},
786 });
787 }
788
789 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
791 }
792}
793
795 Text("File -> Open");
796 Text("Select a ROM file to open");
797 Text("Supported ROMs (headered or unheadered):");
798 Text("The Legend of Zelda: A Link to the Past");
799 Text("US Version 1.0");
800 Text("JP Version 1.0");
801 Spacing();
802 TextWrapped("ROM files are not bundled. Use a clean, legally obtained copy.");
803
804 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
805 Hide("Open a ROM");
806 }
807}
808
810 Text("Project Menu");
811 Text("Create a new project or open an existing one.");
812 Text("Save the project to save the current state of the project.");
813 TextWrapped(
814 "To save a project, you need to first open a ROM and initialize your "
815 "code path and labels file. Label resource manager can be found in "
816 "the View menu. Code path is set in the Code editor after opening a "
817 "folder.");
818
819 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
820 Hide("Manage Project");
821 }
822}
823
825 TextWrapped("Welcome to YAZE v%s!", YAZE_VERSION_STRING);
826 TextWrapped(
827 "YAZE lets you modify 'The Legend of Zelda: A Link to the Past' (US or "
828 "JP) ROMs with modern tooling.");
829 Spacing();
830 TextWrapped("Release Highlights:");
831 BulletText(
832 "AI-assisted workflows via z3ed agent and in-app panels "
833 "(Ollama/Gemini/OpenAI/Anthropic)");
834 BulletText("Clear feature status panels and improved help/tooltips");
835 BulletText("Unified .yaze storage across desktop/CLI/web");
836 Spacing();
837 TextWrapped("General Tips:");
838 BulletText("Open a clean ROM and save a backup before editing");
839 BulletText("Use Help (F1) for context-aware guidance and shortcuts");
840 BulletText(
841 "Configure AI providers (Ollama/Gemini/OpenAI/Anthropic) in Settings > "
842 "Agent");
843
844 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
845 Hide("Getting Started");
846 }
847}
848
850 TextWrapped("Asar 65816 Assembly Integration");
851 TextWrapped(
852 "YAZE includes full Asar assembler support for ROM patching.");
853 Spacing();
854 TextWrapped("Features:");
855 BulletText("Cross-platform ROM patching with assembly code");
856 BulletText("Symbol export with addresses and opcodes");
857 BulletText("Assembly validation with detailed error reporting");
858 BulletText("Memory-safe patch application with size checks");
859
860 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
861 Hide("Asar Integration");
862 }
863}
864
866 TextWrapped("Build Instructions");
867 TextWrapped("YAZE uses modern CMake for cross-platform builds.");
868 Spacing();
869 TextWrapped("Quick Start (examples):");
870 BulletText("cmake --preset mac-dbg | lin-dbg | win-dbg");
871 BulletText("cmake --build --preset <preset> --target yaze");
872 Spacing();
873 TextWrapped("AI Builds:");
874 BulletText("cmake --preset mac-ai | lin-ai | win-ai");
875 BulletText("cmake --build --preset <preset> --target yaze z3ed");
876 Spacing();
877 TextWrapped("Docs: docs/public/build/quick-reference.md");
878
879 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
880 Hide("Build Instructions");
881 }
882}
883
885 TextWrapped("Command Line Interface (z3ed)");
886 TextWrapped("Scriptable ROM editing and AI agent workflows.");
887 Spacing();
888 TextWrapped("Commands:");
889 BulletText("z3ed rom-info --rom=zelda3.sfc");
890 BulletText("z3ed agent simple-chat --rom=zelda3.sfc --ai_provider=auto");
891 BulletText("z3ed agent plan --rom=zelda3.sfc");
892 BulletText("z3ed test-list --format json");
893 BulletText("z3ed patch apply-asar patch.asm --rom=zelda3.sfc");
894 BulletText("z3ed help dungeon-place-sprite");
895 Spacing();
896 TextWrapped("Storage:");
897 BulletText("Agent plans/proposals live under ~/.yaze (see docs for details)");
898
899 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
900 Hide("CLI Usage");
901 }
902}
903
905 TextWrapped("Troubleshooting");
906 TextWrapped("Common issues and solutions:");
907 Spacing();
908 BulletText("ROM won't load: Check file format (SFC/SMC supported)");
909 BulletText(
910 "AI agent missing: Start Ollama or set GEMINI_API_KEY/OPENAI_API_KEY/"
911 "ANTHROPIC_API_KEY (web uses AI_AGENT_ENDPOINT)");
912 BulletText("Graphics issues: Disable experimental flags in Settings");
913 BulletText("Performance: Enable hardware acceleration in display settings");
914 BulletText("Crashes: Check ROM file integrity and available memory");
915 BulletText("Layout issues: Reset workspace layouts from View > Layouts");
916
917 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
918 Hide("Troubleshooting");
919 }
920}
921
923 TextWrapped("Contributing to YAZE");
924 TextWrapped("YAZE is open source and welcomes contributions!");
925 Spacing();
926 TextWrapped("How to contribute:");
927 BulletText("Fork the repository on GitHub");
928 BulletText("Create feature branches for new work");
929 BulletText("Follow C++ coding standards");
930 BulletText("Include tests for new features");
931 BulletText("Submit pull requests for review");
932
933 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
934 Hide("Contributing");
935 }
936}
937
939 TextWrapped("What's New in YAZE v%s", YAZE_VERSION_STRING);
940 Spacing();
941
942 if (CollapsingHeader(
943 absl::StrFormat("%s User Interface & Theming", ICON_MD_PALETTE)
944 .c_str(),
945 ImGuiTreeNodeFlags_DefaultOpen)) {
946 BulletText("Feature status/persistence summaries across desktop/CLI/web");
947 BulletText("Shortcut/help panels now match configured keybindings");
948 BulletText("Refined onboarding tips and error messaging");
949 BulletText("Help text refreshed across desktop, CLI, and web");
950 }
951
952 if (CollapsingHeader(
953 absl::StrFormat("%s Development & Build System", ICON_MD_BUILD)
954 .c_str(),
955 ImGuiTreeNodeFlags_DefaultOpen)) {
956 BulletText("Asar 65816 assembler integration for ROM patching");
957 BulletText("z3ed CLI + TUI for scripting, test/doctor, and automation");
958 BulletText("Modern CMake presets for desktop, AI, and web builds");
959 BulletText("Unified version + storage references for 0.5.1");
960 }
961
962 if (CollapsingHeader(
963 absl::StrFormat("%s Core Improvements", ICON_MD_SETTINGS).c_str())) {
964 BulletText("Improved project metadata + .yaze storage alignment");
965 BulletText("Stronger error reporting and status feedback");
966 BulletText("Performance and stability improvements across editors");
967 BulletText("Expanded logging and diagnostics tooling");
968 }
969
970 if (CollapsingHeader(
971 absl::StrFormat("%s Editor Features", ICON_MD_EDIT).c_str())) {
972 BulletText("Music editor updates with SPC parsing/playback");
973 BulletText("AI agent-assisted editing workflows (multi-provider + vision)");
974 BulletText("Expanded overworld/dungeon tooling and palette accuracy");
975 BulletText("Web/WASM preview with collaboration hooks");
976 }
977
978 Spacing();
979 if (Button(
980 absl::StrFormat("%s View Release Notes", ICON_MD_DESCRIPTION).c_str(),
981 ImVec2(-1, 30))) {
982 // Close this popup and show theme settings
984 // Could trigger release notes panel opening here
985 }
986
987 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
989 }
990}
991
993 TextWrapped("Workspace Management");
994 TextWrapped(
995 "YAZE supports multiple ROM sessions and flexible workspace layouts.");
996 Spacing();
997
998 TextWrapped("Session Management:");
999 BulletText("Ctrl+Shift+N: Create new session");
1000 BulletText("Ctrl+Shift+W: Close current session");
1001 BulletText("Ctrl+Tab: Quick session switcher");
1002 BulletText("Each session maintains its own ROM and editor state");
1003
1004 Spacing();
1005 TextWrapped("Layout Management:");
1006 BulletText("Drag window tabs to dock/undock");
1007 BulletText("Ctrl+Shift+S: Save current layout");
1008 BulletText("Ctrl+Shift+O: Load saved layout");
1009 BulletText("F11: Maximize current window");
1010
1011 Spacing();
1012 TextWrapped("Preset Layouts:");
1013 BulletText("Developer: Code, memory, testing tools");
1014 BulletText("Designer: Graphics, palettes, sprites");
1015 BulletText("Modder: All gameplay editing tools");
1016
1017 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1018 Hide("Workspace Help");
1019 }
1020}
1021
1023 TextColored(gui::GetWarningColor(), "%s Warning", ICON_MD_WARNING);
1024 TextWrapped("You have reached the recommended session limit.");
1025 TextWrapped("Having too many sessions open may impact performance.");
1026 Spacing();
1027 TextWrapped("Consider closing unused sessions or saving your work.");
1028
1029 if (Button("Understood", ::yaze::gui::kDefaultModalSize)) {
1030 Hide("Session Limit Warning");
1031 }
1032 SameLine();
1033 if (Button("Open Session Manager", ::yaze::gui::kDefaultModalSize)) {
1034 Hide("Session Limit Warning");
1035 // This would trigger the session manager to open
1036 }
1037}
1038
1040 TextColored(gui::GetWarningColor(), "%s Confirm Reset",
1042 TextWrapped("This will reset your current workspace layout to default.");
1043 TextWrapped("Any custom window arrangements will be lost.");
1044 Spacing();
1045 TextWrapped("Do you want to continue?");
1046
1047 if (Button("Reset Layout", ::yaze::gui::kDefaultModalSize)) {
1048 Hide("Layout Reset Confirm");
1049 // This would trigger the actual reset
1050 }
1051 SameLine();
1052 if (Button("Cancel", ::yaze::gui::kDefaultModalSize)) {
1053 Hide("Layout Reset Confirm");
1054 }
1055}
1056
1058 TextColored(gui::GetInfoColor(), "%s Layout Presets",
1060 Separator();
1061 Spacing();
1062
1063 TextWrapped("Choose a workspace preset to quickly configure your layout:");
1064 Spacing();
1065
1066 // Get named presets from LayoutPresets
1067 struct PresetInfo {
1068 const char* name;
1069 const char* icon;
1070 const char* description;
1071 std::function<PanelLayoutPreset()> getter;
1072 };
1073
1074 PresetInfo presets[] = {
1075 {"Minimal", ICON_MD_CROP_FREE,
1076 "Essential cards only - maximum editing space",
1077 []() {
1079 }},
1080 {"Developer", ICON_MD_BUG_REPORT,
1081 "Debug and development focused - CPU/Memory/Breakpoints",
1082 []() {
1084 }},
1085 {"Designer", ICON_MD_PALETTE,
1086 "Visual and artistic focused - Graphics/Palettes/Sprites",
1087 []() {
1089 }},
1090 {"Modder", ICON_MD_BUILD,
1091 "Full-featured - All tools available for comprehensive editing",
1092 []() {
1094 }},
1095 {"Overworld Expert", ICON_MD_MAP,
1096 "Complete overworld editing toolkit with all map tools",
1097 []() {
1099 }},
1100 {"Dungeon Expert", ICON_MD_DOOR_SLIDING,
1101 "Complete dungeon editing toolkit with room tools",
1102 []() {
1104 }},
1105 {"Testing", ICON_MD_SCIENCE, "Quality assurance and ROM testing layout",
1106 []() {
1108 }},
1109 {"Audio", ICON_MD_MUSIC_NOTE, "Music and sound editing layout",
1110 []() {
1112 }},
1113 };
1114
1115 constexpr int kPresetCount = 8;
1116
1117 // Draw preset buttons in a grid
1118 float button_width = 200.0f;
1119 float button_height = 50.0f;
1120
1121 for (int i = 0; i < kPresetCount; i++) {
1122 if (i % 2 != 0)
1123 SameLine();
1124
1125 {
1126 gui::StyleVarGuard align_guard(ImGuiStyleVar_ButtonTextAlign,
1127 ImVec2(0.0f, 0.5f));
1128 if (Button(
1129 absl::StrFormat("%s %s", presets[i].icon, presets[i].name).c_str(),
1130 ImVec2(button_width, button_height))) {
1131 // Apply the preset
1132 auto preset = presets[i].getter();
1133 auto& panel_manager = editor_manager_->panel_manager();
1134 // Hide all panels first
1135 panel_manager.HideAll();
1136 // Show preset panels
1137 for (const auto& panel_id : preset.default_visible_panels) {
1138 panel_manager.ShowPanel(panel_id);
1139 }
1141 }
1142 }
1143
1144 if (IsItemHovered()) {
1145 BeginTooltip();
1146 TextUnformatted(presets[i].description);
1147 EndTooltip();
1148 }
1149 }
1150
1151 Spacing();
1152 Separator();
1153 Spacing();
1154
1155 // Reset current editor to defaults
1156 if (Button(
1157 absl::StrFormat("%s Reset Current Editor", ICON_MD_REFRESH).c_str(),
1158 ImVec2(-1, 0))) {
1159 auto& panel_manager = editor_manager_->card_registry();
1160 auto* current_editor = editor_manager_->GetCurrentEditor();
1161 if (current_editor) {
1162 auto current_type = current_editor->type();
1163 panel_manager.ResetToDefaults(0, current_type);
1164 }
1166 }
1167
1168 Spacing();
1169 if (Button("Close", ImVec2(-1, 0))) {
1171 }
1172}
1173
1175 TextColored(gui::GetInfoColor(), "%s Session Manager",
1176 ICON_MD_TAB);
1177 Separator();
1178 Spacing();
1179
1180 size_t session_count = editor_manager_->GetActiveSessionCount();
1181 size_t active_session = editor_manager_->GetCurrentSessionId();
1182
1183 Text("Active Sessions: %zu", session_count);
1184 Spacing();
1185
1186 // Session table
1187 if (BeginTable("SessionTable", 4,
1188 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
1189 TableSetupColumn("#", ImGuiTableColumnFlags_WidthFixed, 30.0f);
1190 TableSetupColumn("ROM", ImGuiTableColumnFlags_WidthStretch);
1191 TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 80.0f);
1192 TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1193 TableHeadersRow();
1194
1195 for (size_t i = 0; i < session_count; i++) {
1196 TableNextRow();
1197
1198 // Session number
1199 TableSetColumnIndex(0);
1200 Text("%zu", i + 1);
1201
1202 // ROM name (simplified - show current ROM for active session)
1203 TableSetColumnIndex(1);
1204 if (i == active_session) {
1205 auto* rom = editor_manager_->GetCurrentRom();
1206 if (rom && rom->is_loaded()) {
1207 TextUnformatted(rom->filename().c_str());
1208 } else {
1209 TextDisabled("(No ROM loaded)");
1210 }
1211 } else {
1212 TextDisabled("Session %zu", i + 1);
1213 }
1214
1215 // Status indicator
1216 TableSetColumnIndex(2);
1217 if (i == active_session) {
1218 TextColored(gui::GetSuccessColor(), "%s Active",
1220 } else {
1221 TextDisabled("Inactive");
1222 }
1223
1224 // Actions
1225 TableSetColumnIndex(3);
1226 PushID(static_cast<int>(i));
1227
1228 if (i != active_session) {
1229 if (SmallButton("Switch")) {
1231 }
1232 SameLine();
1233 }
1234
1235 BeginDisabled(session_count <= 1);
1236 if (SmallButton("Close")) {
1238 }
1239 EndDisabled();
1240
1241 PopID();
1242 }
1243
1244 EndTable();
1245 }
1246
1247 Spacing();
1248 Separator();
1249 Spacing();
1250
1251 // New session button
1252 if (Button(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str(),
1253 ImVec2(-1, 0))) {
1255 }
1256
1257 Spacing();
1258 if (Button("Close", ImVec2(-1, 0))) {
1260 }
1261}
1262
1264 // Set a comfortable default size with natural constraints
1265 SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
1266 SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
1267
1268 Text("%s Display & Theme Settings", ICON_MD_DISPLAY_SETTINGS);
1269 TextWrapped("Customize your YAZE experience - accessible anytime!");
1270 Separator();
1271
1272 // Create a child window for scrollable content to avoid table conflicts
1273 // Use remaining space minus the close button area
1274 float available_height =
1275 GetContentRegionAvail().y - 60; // Reserve space for close button
1276 if (BeginChild("DisplaySettingsContent", ImVec2(0, available_height), true,
1277 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1278 // Use the popup-safe version to avoid table conflicts
1280
1281 Separator();
1282 gui::TextWithSeparators("Font Manager");
1284
1285 // Global font scale (moved from the old display settings window)
1286 ImGuiIO& io = GetIO();
1287 Separator();
1288 Text("Global Font Scale");
1289 float font_global_scale = io.FontGlobalScale;
1290 if (SliderFloat("##global_scale", &font_global_scale, 0.5f, 1.8f, "%.2f")) {
1291 if (editor_manager_) {
1292 editor_manager_->SetFontGlobalScale(font_global_scale);
1293 } else {
1294 io.FontGlobalScale = font_global_scale;
1295 }
1296 }
1297 }
1298 EndChild();
1299
1300 Separator();
1301 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1302 Hide("Display Settings");
1303 }
1304}
1305
1307 using namespace ImGui;
1308
1309 // Display feature flags editor using the existing FlagsMenu system
1310 Text("Feature Flags Configuration");
1311 Separator();
1312
1313 BeginChild("##FlagsContent", ImVec2(0, -30), true);
1314
1315 // Use the feature flags menu system
1316 static gui::FlagsMenu flags_menu;
1317
1318 if (BeginTabBar("FlagCategories")) {
1319 if (BeginTabItem("Overworld")) {
1320 flags_menu.DrawOverworldFlags();
1321 EndTabItem();
1322 }
1323 if (BeginTabItem("Dungeon")) {
1324 flags_menu.DrawDungeonFlags();
1325 EndTabItem();
1326 }
1327 if (BeginTabItem("Resources")) {
1328 flags_menu.DrawResourceFlags();
1329 EndTabItem();
1330 }
1331 if (BeginTabItem("System")) {
1332 flags_menu.DrawSystemFlags();
1333 EndTabItem();
1334 }
1335 EndTabBar();
1336 }
1337
1338 EndChild();
1339
1340 Separator();
1341 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1343 }
1344}
1345
1347 using namespace ImGui;
1348
1349 Text("Data Integrity Check Results");
1350 Separator();
1351
1352 BeginChild("##IntegrityContent", ImVec2(0, -30), true);
1353
1354 // Placeholder for data integrity results
1355 // In a full implementation, this would show test results
1356 Text("ROM Data Integrity:");
1357 Separator();
1358 TextColored(gui::GetSuccessColor(), "✓ ROM header valid");
1359 TextColored(gui::GetSuccessColor(), "✓ Checksum valid");
1360 TextColored(gui::GetSuccessColor(), "✓ Graphics data intact");
1361 TextColored(gui::GetSuccessColor(), "✓ Map data intact");
1362
1363 Spacing();
1364 Text("No issues detected.");
1365
1366 EndChild();
1367
1368 Separator();
1369 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1371 }
1372}
1373
1375 using namespace ImGui;
1376
1377 if (!editor_manager_) {
1378 Text("Editor manager unavailable.");
1379 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1381 }
1382 return;
1383 }
1384
1385 const int unloaded = editor_manager_->pending_pot_item_unloaded_rooms();
1386 const int total = editor_manager_->pending_pot_item_total_rooms();
1387
1388 Text("Pot Item Save Confirmation");
1389 Separator();
1390 TextWrapped(
1391 "Dungeon pot item saving is enabled, but %d of %d rooms are not loaded.",
1392 unloaded, total);
1393 Spacing();
1394 TextWrapped(
1395 "Saving now can overwrite pot items in unloaded rooms. Choose how to "
1396 "proceed:");
1397
1398 Spacing();
1399 if (Button("Save without pot items", ImVec2(0, 0))) {
1403 return;
1404 }
1405 SameLine();
1406 if (Button("Save anyway", ImVec2(0, 0))) {
1410 return;
1411 }
1412 SameLine();
1413 if (Button("Cancel", ImVec2(0, 0))) {
1417 }
1418}
1419
1421 using namespace ImGui;
1422
1423 if (!editor_manager_) {
1424 Text("Editor manager unavailable.");
1425 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1427 }
1428 return;
1429 }
1430
1432 auto policy =
1434 const auto expected = editor_manager_->GetProjectExpectedRomHash();
1435 const auto actual = editor_manager_->GetCurrentRomHash();
1436
1437 Text("ROM Write Confirmation");
1438 Separator();
1439 TextWrapped(
1440 "The loaded ROM hash does not match the project's expected hash.");
1441 Spacing();
1442 Text("Role: %s", role.c_str());
1443 Text("Write policy: %s", policy.c_str());
1444 Text("Expected: %s", expected.empty() ? "(unset)" : expected.c_str());
1445 Text("Actual: %s", actual.empty() ? "(unknown)" : actual.c_str());
1446 Spacing();
1447 TextWrapped(
1448 "Proceeding will write to the current ROM file. This may corrupt a base "
1449 "or release ROM if it is not the intended dev ROM.");
1450
1451 Spacing();
1452 if (Button("Save anyway", ImVec2(0, 0))) {
1455 auto status = editor_manager_->SaveRom();
1456 if (!status.ok() && !absl::IsCancelled(status)) {
1457 if (auto* toast = editor_manager_->toast_manager()) {
1458 toast->Show(
1459 absl::StrFormat("Save failed: %s", status.message()),
1461 }
1462 }
1463 return;
1464 }
1465 SameLine();
1466 if (Button("Cancel", ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1469 }
1470}
1471
1473 using namespace ImGui;
1474
1475 if (!editor_manager_) {
1476 Text("Editor manager unavailable.");
1477 if (Button("Close", ::yaze::gui::kDefaultModalSize)) {
1479 }
1480 return;
1481 }
1482
1483 const auto& conflicts = editor_manager_->pending_write_conflicts();
1484
1485 TextColored(gui::GetWarningColor(), "%s Write Conflict Warning",
1487 Separator();
1488 TextWrapped(
1489 "The following ROM addresses are owned by ASM hooks and will be "
1490 "overwritten on next build. Saving now will write data that asar "
1491 "will replace.");
1492 Spacing();
1493
1494 if (!conflicts.empty()) {
1495 if (BeginTable("WriteConflictTable", 3,
1496 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
1497 ImGuiTableFlags_Resizable)) {
1498 TableSetupColumn("Address", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1499 TableSetupColumn("Ownership", ImGuiTableColumnFlags_WidthFixed, 140.0f);
1500 TableSetupColumn("Module", ImGuiTableColumnFlags_WidthStretch);
1501 TableHeadersRow();
1502
1503 for (const auto& conflict : conflicts) {
1504 TableNextRow();
1505 TableNextColumn();
1506 Text("$%06X", conflict.address);
1507 TableNextColumn();
1508 TextUnformatted(
1509 core::AddressOwnershipToString(conflict.ownership).c_str());
1510 TableNextColumn();
1511 if (!conflict.module.empty()) {
1512 TextUnformatted(conflict.module.c_str());
1513 } else {
1514 TextDisabled("(unknown)");
1515 }
1516 }
1517 EndTable();
1518 }
1519 }
1520
1521 Spacing();
1522 Text("%zu conflict(s) detected.", conflicts.size());
1523 Spacing();
1524
1525 if (Button("Save Anyway", ImVec2(0, 0))) {
1528 auto status = editor_manager_->SaveRom();
1529 if (!status.ok() && !absl::IsCancelled(status)) {
1530 if (auto* toast = editor_manager_->toast_manager()) {
1531 toast->Show(absl::StrFormat("Save failed: %s", status.message()),
1533 }
1534 }
1535 return;
1536 }
1537 SameLine();
1538 if (Button("Cancel", ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1541 }
1542}
1543
1544} // namespace editor
1545} // namespace yaze
auto filename() const
Definition rom.h:145
bool is_loaded() const
Definition rom.h:132
auto title() const
Definition rom.h:137
static Flags & get()
Definition features.h:118
The EditorManager controls the main editor window and manages the various editor classes.
absl::Status SaveRomAs(const std::string &filename)
void SwitchToSession(size_t index)
absl::Status RestoreRomBackup(const std::string &backup_path)
Rom * GetCurrentRom() const override
std::vector< editor::RomFileManager::BackupEntry > GetRomBackups() const
project::RomWritePolicy GetProjectRomWritePolicy() const
absl::Status CreateNewProject(const std::string &template_name="Basic ROM Hack")
std::string GetCurrentRomHash() const
void SetFontGlobalScale(float scale)
void ResolvePotItemSaveConfirmation(PotItemSaveDecision decision)
auto GetCurrentEditor() const -> Editor *
std::string GetProjectExpectedRomHash() const
const std::vector< core::WriteConflict > & pending_write_conflicts() const
project::RomRole GetProjectRomRole() const
project::YazeProject * GetCurrentProject()
int pending_pot_item_unloaded_rooms() const
absl::Status OpenRomOrProject(const std::string &filename)
void RemoveSession(size_t index)
EditorType type() const
Definition editor.h:283
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)
void SetStatus(const absl::Status &status)
bool IsVisible(const char *name) const
void Show(const char *name)
void Hide(const char *name)
PopupManager(EditorManager *editor_manager)
std::unordered_map< std::string, PopupParams > popups_
EditorManager * editor_manager_
bool BeginCentered(const char *name)
RAII guard for ImGui style vars.
Definition style_guard.h:68
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
Definition icons.h:813
#define ICON_MD_SETTINGS
Definition icons.h:1699
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_DOOR_SLIDING
Definition icons.h:614
#define ICON_MD_SAVE_AS
Definition icons.h:1646
#define ICON_MD_REFRESH
Definition icons.h:1572
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_CODE
Definition icons.h:434
#define ICON_MD_LABEL
Definition icons.h:1053
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2076
#define ICON_MD_BUG_REPORT
Definition icons.h:327
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_ERROR
Definition icons.h:686
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_RESTORE
Definition icons.h:1605
#define ICON_MD_DISPLAY_SETTINGS
Definition icons.h:587
#define ICON_MD_ADD
Definition icons.h:86
#define ICON_MD_SCIENCE
Definition icons.h:1656
#define ICON_MD_CHECK_CIRCLE
Definition icons.h:400
#define ICON_MD_DESCRIPTION
Definition icons.h:539
#define ICON_MD_BUILD
Definition icons.h:328
#define ICON_MD_DASHBOARD
Definition icons.h:517
#define ICON_MD_SAVE
Definition icons.h:1644
#define ICON_MD_TAB
Definition icons.h:1930
#define ICON_MD_FOLDER
Definition icons.h:809
#define ICON_MD_BACKUP
Definition icons.h:231
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_OPEN_IN_NEW
Definition icons.h:1354
#define ICON_MD_CONTENT_COPY
Definition icons.h:465
#define ICON_MD_CROP_FREE
Definition icons.h:495
#define ICON_MD_DELETE_SWEEP
Definition icons.h:533
Definition input.cc:22
std::string AddressOwnershipToString(AddressOwnership ownership)
constexpr const char * kRomInfo
constexpr const char * kLayoutPresets
constexpr const char * kSaveScope
constexpr const char * kAbout
constexpr const char * kSessionManager
constexpr const char * kTroubleshooting
constexpr const char * kRomBackups
constexpr const char * kWhatsNew
constexpr const char * kSupportedFeatures
constexpr const char * kDataIntegrity
constexpr const char * kManageProject
constexpr const char * kNewProject
constexpr const char * kSaveAs
constexpr const char * kDisplaySettings
constexpr const char * kSessionLimitWarning
constexpr const char * kCLIUsage
constexpr const char * kLayoutResetConfirm
constexpr const char * kWriteConflictWarning
constexpr const char * kAsarIntegration
constexpr const char * kOpenRomHelp
constexpr const char * kFeatureFlags
constexpr const char * kDungeonPotItemSaveConfirm
constexpr const char * kGettingStarted
constexpr const char * kContributing
constexpr const char * kBuildInstructions
constexpr const char * kWorkspaceHelp
constexpr const char * kRomWriteConfirm
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:134
void DrawFontManager()
Definition style.cc:1321
ImVec4 GetSuccessColor()
Definition ui_helpers.cc:48
ImVec4 GetWarningColor()
Definition ui_helpers.cc:53
void DrawDisplaySettingsForPopup(ImGuiStyle *ref)
Definition style.cc:867
constexpr ImVec2 kDefaultModalSize
Definition input.h:21
ImVec4 GetInfoColor()
Definition ui_helpers.cc:63
void TextWithSeparators(const absl::string_view &text)
Definition style.cc:1315
std::string RomRoleToString(RomRole role)
Definition project.cc:164
std::string RomWritePolicyToString(RomWritePolicy policy)
Definition project.cc:192
std::string HexLongLong(uint64_t qword, HexStringParams params)
Definition hex.cc:63
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
Definition file_util.cc:87
Defines default panel visibility for an editor type.
std::string GetAbsolutePath(const std::string &relative_path) const
Definition project.cc:1287
Public YAZE API umbrella header.