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#include "util/i18n/tr.h"
3
4#include <cstring>
5#include <ctime>
6#include <filesystem>
7#include <functional>
8#include <initializer_list>
9
10#include "absl/status/status.h"
11#include "absl/strings/ascii.h"
12#include "absl/strings/match.h"
13#include "absl/strings/str_format.h"
18#include "app/gui/core/icons.h"
19#include "app/gui/core/input.h"
20#include "app/gui/core/style.h"
24#include "imgui/misc/cpp/imgui_stdlib.h"
25#include "util/file_util.h"
26#include "util/hex.h"
27#include "yaze.h"
29
30namespace yaze {
31namespace editor {
32
33using namespace ImGui;
34
36 : editor_manager_(editor_manager), status_(absl::OkStatus()) {}
37
39 // ============================================================================
40 // POPUP REGISTRATION
41 // ============================================================================
42 // All popups must be registered here BEFORE any menu callbacks can trigger
43 // them. This method is called in EditorManager constructor BEFORE
44 // MenuOrchestrator and UICoordinator are created, ensuring safe
45 // initialization order.
46 //
47 // Popup Registration Format:
48 // popups_[PopupID::kConstant] = {
49 // .name = PopupID::kConstant,
50 // .type = PopupType::kXxx,
51 // .is_visible = false,
52 // .allow_resize = false/true,
53 // .draw_function = [this]() { DrawXxxPopup(); }
54 // };
55 // ============================================================================
56
57 // File Operations
59 false, false, [this]() { DrawSaveAsPopup(); }};
61 false, true,
62 [this]() { DrawSaveScopePopup(); }};
64 PopupType::kFileOperation, false, false,
65 [this]() { DrawNewProjectPopup(); }};
67 PopupType::kFileOperation, false, false,
68 [this]() { DrawManageProjectPopup(); }};
70 PopupType::kFileOperation, false, true,
71 [this]() { DrawRomBackupManagerPopup(); }};
72
73 // Information
75 [this]() { DrawAboutPopup(); }};
77 false, [this]() { DrawRomInfoPopup(); }};
80 [this]() { DrawSupportedFeaturesPopup(); }};
82 false, false,
83 [this]() { DrawOpenRomHelpPopup(); }};
84
85 // Help Documentation
87 PopupType::kHelp, false, false,
88 [this]() { DrawGettingStartedPopup(); }};
91 [this]() { DrawAsarIntegrationPopup(); }};
94 [this]() { DrawBuildInstructionsPopup(); }};
96 false, [this]() { DrawCLIUsagePopup(); }};
99 [this]() { DrawTroubleshootingPopup(); }};
101 false, false,
102 [this]() { DrawContributingPopup(); }};
104 false, [this]() { DrawWhatsNewPopup(); }};
107 true, // Resizable — concept map is longer than a short tip
108 [this]() { DrawComingFromZScreamPopup(); }};
109
110 // Settings
113 true, // Resizable
114 [this]() { DrawDisplaySettingsPopup(); }};
116 PopupID::kFeatureFlags, PopupType::kSettings, false, true, // Resizable
117 [this]() { DrawFeatureFlagsPopup(); }};
118
119 // Workspace
121 false, false,
122 [this]() { DrawWorkspaceHelpPopup(); }};
125 [this]() { DrawSessionLimitWarningPopup(); }};
128 [this]() { DrawLayoutResetConfirmPopup(); }};
129
131 PopupType::kSettings, false, false,
132 [this]() { DrawLayoutPresetsPopup(); }};
133
135 PopupType::kSettings, false, true,
136 [this]() { DrawSessionManagerPopup(); }};
137
138 // Debug/Testing
140 false, true, // Resizable
141 [this]() { DrawDataIntegrityPopup(); }};
142
145 false, [this]() { DrawDungeonPotItemSaveConfirmPopup(); }};
148 [this]() { DrawRomWriteConfirmPopup(); }};
151 [this]() { DrawWriteConflictWarningPopup(); }};
154 [this]() { DrawUnsavedSessionChangesPopup(); }};
155}
156
158 // Draw status popup if needed
160
161 // Draw only the most recently shown popup. All popups open at the same
162 // level, and opening one closes any other open there, so drawing every
163 // visible popup reopened each of them every frame: none stayed on screen,
164 // and the open modal blocked all input. Older popups stay visible and
165 // return when the newer one is hidden.
166 PopupParams* top = nullptr;
167 for (auto& [name, params] : popups_) {
168 if (params.is_visible &&
169 (top == nullptr || params.shown_order > top->shown_order)) {
170 top = &params;
171 }
172 }
173 if (top == nullptr) {
174 return;
175 }
176 OpenPopup(top->name.c_str());
177
178 // Use allow_resize flag from popup definition
179 ImGuiWindowFlags popup_flags = top->allow_resize
180 ? ImGuiWindowFlags_None
181 : ImGuiWindowFlags_AlwaysAutoResize;
182
183 if (BeginPopupModal(top->name.c_str(), nullptr, popup_flags)) {
184 top->draw_function();
185 EndPopup();
186 }
187}
188
189void PopupManager::Show(const char* name) {
190 if (!name) {
191 return; // Safety check for null pointer
192 }
193
194 std::string name_str(name);
195 auto it = popups_.find(name_str);
196 if (it != popups_.end()) {
197 if (!it->second.is_visible) {
198 if (name_str == PopupID::kSaveAs) {
200 }
201 it->second.shown_order = next_shown_order_++;
202 }
203 it->second.is_visible = true;
204 } else {
205 // Log warning for unregistered popup
206 printf(
207 "[PopupManager] Warning: Popup '%s' not registered. Available popups: ",
208 name);
209 for (const auto& [key, _] : popups_) {
210 printf("'%s' ", key.c_str());
211 }
212 printf("\n");
213 }
214}
215
216void PopupManager::Hide(const char* name) {
217 if (!name) {
218 return; // Safety check for null pointer
219 }
220
221 std::string name_str(name);
222 auto it = popups_.find(name_str);
223 if (it != popups_.end()) {
224 it->second.is_visible = false;
225 if (name_str == PopupID::kSaveAs) {
227 }
228 CloseCurrentPopup();
229 }
230}
231
232void PopupManager::RegisterPopup(const std::string& name, PopupType type,
233 std::function<void()> draw_function,
234 bool allow_resize) {
235 PopupParams params;
236 params.name = name;
237 params.type = type;
238 params.allow_resize = allow_resize;
239 params.draw_function = std::move(draw_function);
240 popups_[name] = std::move(params);
241}
242
243bool PopupManager::IsVisible(const char* name) const {
244 if (!name) {
245 return false; // Safety check for null pointer
246 }
247
248 std::string name_str(name);
249 auto it = popups_.find(name_str);
250 if (it != popups_.end()) {
251 return it->second.is_visible;
252 }
253 return false;
254}
255
256void PopupManager::SetStatus(const absl::Status& status) {
257 if (!status.ok()) {
258 show_status_ = true;
259 prev_status_ = status;
260 status_ = status;
261 }
262}
263
264bool PopupManager::BeginCentered(const char* name) {
265 ImGuiIO const& io = GetIO();
266 ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
267 SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
268 ImGuiWindowFlags flags =
269 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
270 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;
271 return Begin(name, nullptr, flags);
272}
273
275 if (show_status_ && BeginCentered("StatusWindow")) {
276 Text("%s", ICON_MD_ERROR);
277 Text("%s", prev_status_.ToString().c_str());
278 Spacing();
279 NextColumn();
280 Columns(1);
281 Separator();
282 NewLine();
283 SameLine(128);
284 if (Button(tr("OK"), ::yaze::gui::kDefaultModalSize) ||
285 IsKeyPressed(ImGuiKey_Space)) {
286 show_status_ = false;
287 status_ = absl::OkStatus();
288 }
289 SameLine();
290 if (Button(ICON_MD_CONTENT_COPY, ImVec2(50, 0))) {
291 SetClipboardText(prev_status_.ToString().c_str());
292 }
293 End();
294 }
295}
296
298 Text(tr("Yet Another Zelda3 Editor - v%s"),
299 editor_manager_->version().c_str());
300 Text(tr("Written by: scawful"));
301 Spacing();
302 Text(tr("Special Thanks: Zarby89, JaredBrian"));
303 Separator();
304
305 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
306 Hide("About");
307 }
308}
309
311 auto* current_rom = editor_manager_->GetCurrentRom();
312 if (!current_rom)
313 return;
314
315 Text(tr("Title: %s"), current_rom->title().c_str());
316 Text(tr("ROM Size: %s"), util::HexLongLong(current_rom->size()).c_str());
317 Text(tr("ROM Hash: %s"), editor_manager_->GetCurrentRomHash().empty()
318 ? "(unknown)"
320
321 const auto profile = zelda3::DetectOverworldRomProfile(*current_rom);
322 const auto& layout = profile.lyra_layout;
323 if (layout.presence != rom::LyraLayoutPresence::kAbsent) {
324 Separator();
325 TextUnformatted("Overworld Format: Lyra descriptor");
326 Text("ROM Format Revision: %u", layout.revision);
327 Text("Area Capacity: %u", layout.capacity);
328 Text("Active Areas: %u", layout.active_count);
329 TextUnformatted(layout.presence == rom::LyraLayoutPresence::kValid
330 ? "Validation: valid"
331 : "Validation: invalid");
332 TextUnformatted("Write Support: inspection only");
333 if (!layout.error.empty()) {
334 TextWrapped("Reason: %s", layout.error.c_str());
335 }
336 } else if (profile.layout_kind ==
338 Separator();
339 TextUnformatted("Overworld Format: older $EA tail-map expansion");
340 }
341
342 auto* project = editor_manager_->GetCurrentProject();
343 if (project && project->project_opened()) {
344 Separator();
345 Text(tr("Role: %s"),
346 project::RomRoleToString(project->rom_metadata.role).c_str());
347 Text(tr("Write Policy: %s"),
348 project::RomWritePolicyToString(project->rom_metadata.write_policy)
349 .c_str());
350 Text(tr("Expected Hash: %s"),
351 project->rom_metadata.expected_hash.empty()
352 ? "(unset)"
353 : project->rom_metadata.expected_hash.c_str());
355 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
356 TextColored(gui::ConvertColorToImVec4(theme.warning),
357 tr("ROM hash mismatch detected"));
358 }
359 }
360
361 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize) ||
362 IsKeyPressed(ImGuiKey_Escape)) {
363 Hide("ROM Information");
364 }
365}
366
370
372 using namespace ImGui;
373 namespace fs = std::filesystem;
374
375 auto register_widget = [](const char* name, const char* type) {
377 std::string("SaveAs/") + type + ":" + name, type, GetItemID());
378 };
379 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() : nullptr;
380 if (!rom || !rom->is_loaded()) {
381 TextUnformatted(tr("No ROM loaded."));
382 if (Button(tr("Close"))) {
384 }
385 return;
386 }
387
388 const auto session_id = editor_manager_->GetCurrentSessionId();
390 save_as_.session_id != session_id) {
392 save_as_.initialized = true;
394 save_as_.session_id = session_id;
395 std::error_code ec;
396 auto source = fs::absolute(fs::path(rom->filename()), ec);
397 if (ec || rom->filename().empty()) {
399 tr("The current ROM has no usable folder. Choose Browse.");
400 } else {
401 save_as_.folder = source.parent_path().string();
402 }
403 auto extension = source.extension().string();
404 const auto lower_extension = absl::AsciiStrToLower(extension);
405 if (lower_extension != ".sfc" && lower_extension != ".smc") {
406 extension = ".sfc";
407 }
408 const auto stem =
409 source.stem().empty() ? std::string("rom") : source.stem().string();
410 save_as_.filename = stem + "-copy" + extension;
411 for (int copy = 2;
412 !save_as_.folder.empty() &&
413 fs::exists(fs::path(save_as_.folder) / save_as_.filename, ec);
414 ++copy) {
415 save_as_.filename = stem + "-copy-" + std::to_string(copy) + extension;
416 }
417 }
418
419 Text(tr("%s Save ROM to new location"), ICON_MD_SAVE_AS);
420 Separator();
421 TextUnformatted(tr("Folder:"));
422 PushTextWrapPos(GetCursorPosX() + 480.0f);
423 TextUnformatted(save_as_.folder.c_str());
424 PopTextWrapPos();
425 SetNextItemWidth(360.0f);
426 InputText(tr("Filename"), &save_as_.filename);
427 register_widget("Filename", "input");
428 if (!save_as_.error.empty()) {
429 TextWrapped("%s", save_as_.error.c_str());
430 }
431 Separator();
432
433 const bool browse = Button(
434 absl::StrFormat("%s Browse folder...", ICON_MD_FOLDER_OPEN).c_str(),
436 register_widget("Browse", "button");
437 if (browse) {
439 if (!selected.empty()) {
440 std::error_code ec;
441 const auto destination = fs::absolute(fs::path(selected), ec);
442 if (!ec) {
443 save_as_.folder = destination.string();
444 save_as_.error.clear();
445 }
446 }
447 }
448
449 SameLine();
450 const bool save = Button(absl::StrFormat("%s Save", ICON_MD_SAVE).c_str(),
452 register_widget("Save", "button");
453 if (save) {
454 fs::path filename(save_as_.filename);
455 if (filename.empty() || filename == "." || filename == ".." ||
456 filename.has_parent_path() || save_as_.folder.empty()) {
458 tr("Enter a filename only. Use Browse to choose a different folder.");
459 } else {
460 const auto extension =
461 absl::AsciiStrToLower(filename.extension().string());
462 if (extension != ".sfc" && extension != ".smc") {
463 filename += ".sfc";
464 }
465 // SaveRomAs owns the complete destination across any confirmation popup.
466 const auto destination = (fs::path(save_as_.folder) / filename).string();
467 const auto status = editor_manager_->SaveRomAs(destination);
468 if (status.ok()) {
470 return;
471 }
472 if (!absl::IsCancelled(status)) {
473 save_as_.error = std::string(status.message());
474 }
475 }
476 }
477
478 SameLine();
479 const bool cancel =
480 Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(),
482 register_widget("Cancel", "button");
483 if (cancel || IsKeyPressed(ImGuiKey_Escape)) {
485 }
486}
487
489 using namespace ImGui;
490
491 Text(tr("%s Save Scope"), ICON_MD_SAVE);
492 Separator();
493 TextWrapped(
494 tr("Controls which data is written during File > Save ROM. Dungeon "
495 "choices also control Apply Room. "
496 "Changes apply immediately."));
497 Separator();
498
499 if (CollapsingHeader(tr("Overworld"), ImGuiTreeNodeFlags_DefaultOpen)) {
500 Checkbox(tr("Save Overworld Maps"),
501 &core::FeatureFlags::get().overworld.kSaveOverworldMaps);
502 Checkbox(tr("Save Overworld Entrances"),
503 &core::FeatureFlags::get().overworld.kSaveOverworldEntrances);
504 Checkbox(tr("Save Overworld Exits"),
505 &core::FeatureFlags::get().overworld.kSaveOverworldExits);
506 Checkbox(tr("Save Overworld Items"),
507 &core::FeatureFlags::get().overworld.kSaveOverworldItems);
508 Checkbox(tr("Save Overworld Properties"),
509 &core::FeatureFlags::get().overworld.kSaveOverworldProperties);
510 }
511
512 if (CollapsingHeader(tr("Dungeon"), ImGuiTreeNodeFlags_DefaultOpen)) {
513 Checkbox(tr("Save Dungeon Maps"),
514 &core::FeatureFlags::get().kSaveDungeonMaps);
515 Checkbox(tr("Save Objects"),
516 &core::FeatureFlags::get().dungeon.kSaveObjects);
517 Checkbox(tr("Save Sprites"),
518 &core::FeatureFlags::get().dungeon.kSaveSprites);
519 Checkbox(tr("Save Room Headers"),
520 &core::FeatureFlags::get().dungeon.kSaveRoomHeaders);
521 Checkbox(tr("Save Torches"),
522 &core::FeatureFlags::get().dungeon.kSaveTorches);
523 Checkbox(tr("Save Pits"), &core::FeatureFlags::get().dungeon.kSavePits);
524 Checkbox(tr("Save Blocks"), &core::FeatureFlags::get().dungeon.kSaveBlocks);
525 Checkbox(tr("Save Collision"),
526 &core::FeatureFlags::get().dungeon.kSaveCollision);
527 Checkbox(tr("Save Chests"), &core::FeatureFlags::get().dungeon.kSaveChests);
528 Checkbox(tr("Save Pot Items"),
529 &core::FeatureFlags::get().dungeon.kSavePotItems);
530 if (IsItemHovered()) {
531 SetTooltip(
532 tr("Enable to save pending pot item edits, then retry Save "
533 "or Apply Room. No project reopen is needed."));
534 }
535 Checkbox(tr("Save Entrances"),
536 &core::FeatureFlags::get().dungeon.kSaveEntrances);
537 Checkbox(tr("Save Palettes"),
538 &core::FeatureFlags::get().dungeon.kSavePalettes);
539 }
540
541 if (CollapsingHeader(tr("Graphics"), ImGuiTreeNodeFlags_DefaultOpen)) {
542 Checkbox(tr("Save Graphics Sheets"),
543 &core::FeatureFlags::get().kSaveGraphicsSheet);
544 Checkbox(tr("Save All Palettes"),
545 &core::FeatureFlags::get().kSaveAllPalettes);
546 Checkbox(tr("Save Gfx Groups"), &core::FeatureFlags::get().kSaveGfxGroups);
547 }
548
549 if (CollapsingHeader(tr("Messages"), ImGuiTreeNodeFlags_DefaultOpen)) {
550 Checkbox(tr("Save Message Text"), &core::FeatureFlags::get().kSaveMessages);
551 }
552
553 Separator();
554 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
556 }
557}
558
560 using namespace ImGui;
561
562 auto* rom = editor_manager_->GetCurrentRom();
563 if (!rom || !rom->is_loaded()) {
564 Text(tr("No ROM loaded."));
565 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
567 }
568 return;
569 }
570
571 const auto* project = editor_manager_->GetCurrentProject();
572 std::string backup_dir;
573 if (project && project->project_opened() &&
574 !project->rom_backup_folder.empty()) {
575 backup_dir = project->GetAbsolutePath(project->rom_backup_folder);
576 } else {
577 backup_dir = std::filesystem::path(rom->filename()).parent_path().string();
578 }
579
580 Text(tr("%s ROM Backups"), ICON_MD_BACKUP);
581 Separator();
582 TextWrapped(tr("Backup folder: %s"), backup_dir.c_str());
583
585 Separator();
586 TextWrapped(
587 tr("A restored backup is staged in this session. Save ROM to commit "
588 "it. Discard reloads the backing ROM and abandons staged ROM-buffer "
589 "edits; resolve pending graphics, dungeon, or palette edits "
590 "first."));
591 if (Button(ICON_MD_UNDO " Discard Restored Backup")) {
593 if (!status.ok()) {
594 if (auto* toast = editor_manager_->toast_manager()) {
595 toast->Show(absl::StrFormat("Discard failed: %s", status.message()),
597 }
598 } else if (auto* toast = editor_manager_->toast_manager()) {
599 toast->Show("Restored backup discarded; reloaded ROM from disk",
601 }
602 }
603 Separator();
604 }
605
606 if (Button(ICON_MD_DELETE_SWEEP " Prune Backups")) {
607 auto status = editor_manager_->PruneRomBackups();
608 if (!status.ok()) {
609 if (auto* toast = editor_manager_->toast_manager()) {
610 toast->Show(absl::StrFormat("Prune failed: %s", status.message()),
612 }
613 } else if (auto* toast = editor_manager_->toast_manager()) {
614 toast->Show("Backups pruned", ToastType::kSuccess);
615 }
616 }
617
618 Separator();
619 auto backups = editor_manager_->GetRomBackups();
620 if (backups.empty()) {
621 TextDisabled(tr("No backups found."));
622 } else if (BeginTable("RomBackupTable", 4,
623 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
624 ImGuiTableFlags_Resizable)) {
625 TableSetupColumn("Timestamp");
626 TableSetupColumn("Size");
627 TableSetupColumn("Filename");
628 TableSetupColumn("Actions");
629 TableHeadersRow();
630
631 auto format_size = [](uintmax_t bytes) {
632 if (bytes > (1024 * 1024)) {
633 return absl::StrFormat("%.2f MB",
634 static_cast<double>(bytes) / (1024 * 1024));
635 }
636 if (bytes > 1024) {
637 return absl::StrFormat("%.1f KB", static_cast<double>(bytes) / 1024.0);
638 }
639 return absl::StrFormat("%llu B", static_cast<unsigned long long>(bytes));
640 };
641
642 for (size_t i = 0; i < backups.size(); ++i) {
643 const auto& backup = backups[i];
644 TableNextRow();
645 TableNextColumn();
646 char time_buffer[32] = "unknown";
647 if (backup.timestamp != 0) {
648 std::tm local_tm{};
649#ifdef _WIN32
650 localtime_s(&local_tm, &backup.timestamp);
651#else
652 localtime_r(&backup.timestamp, &local_tm);
653#endif
654 std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S",
655 &local_tm);
656 }
657 TextUnformatted(time_buffer);
658
659 TableNextColumn();
660 TextUnformatted(format_size(backup.size_bytes).c_str());
661
662 TableNextColumn();
663 TextUnformatted(backup.filename.c_str());
664
665 TableNextColumn();
666 PushID(static_cast<int>(i));
667 if (Button(ICON_MD_RESTORE " Restore")) {
668 auto status = editor_manager_->RestoreRomBackup(backup.path);
669 if (!status.ok()) {
670 if (auto* toast = editor_manager_->toast_manager()) {
671 toast->Show(absl::StrFormat("Restore failed: %s", status.message()),
673 }
674 } else if (auto* toast = editor_manager_->toast_manager()) {
675 toast->Show("Backup loaded; inspect it, then save ROM to commit",
677 }
678 }
679 SameLine();
680 if (Button(ICON_MD_OPEN_IN_NEW " Open")) {
681 auto status = editor_manager_->OpenRomOrProject(backup.path);
682 if (!status.ok()) {
683 if (auto* toast = editor_manager_->toast_manager()) {
684 toast->Show(absl::StrFormat("Open failed: %s", status.message()),
686 }
687 }
688 }
689 SameLine();
690 if (Button(ICON_MD_CONTENT_COPY " Copy")) {
691 SetClipboardText(backup.path.c_str());
692 }
693 PopID();
694 }
695 EndTable();
696 }
697
698 Separator();
699 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
701 }
702}
703
705 using namespace ImGui;
706
707 static std::string project_name = "";
708 static std::string project_filepath = "";
709 static std::string rom_filename = "";
710 static std::string labels_filename = "";
711 static std::string code_folder = "";
712
713 InputText(tr("Project Name"), &project_name);
714
715 if (Button(absl::StrFormat("%s Destination Folder", ICON_MD_FOLDER).c_str(),
718 }
719 SameLine();
720 Text("%s", project_filepath.empty() ? "(Not set)" : project_filepath.c_str());
721
722 if (Button(absl::StrFormat("%s ROM File", ICON_MD_VIDEOGAME_ASSET).c_str(),
726 }
727 SameLine();
728 Text("%s", rom_filename.empty() ? "(Not set)" : rom_filename.c_str());
729
730 if (Button(absl::StrFormat("%s Labels File", ICON_MD_LABEL).c_str(),
733 }
734 SameLine();
735 Text("%s", labels_filename.empty() ? "(Not set)" : labels_filename.c_str());
736
737 if (Button(absl::StrFormat("%s Code Folder", ICON_MD_CODE).c_str(),
740 }
741 SameLine();
742 Text("%s", code_folder.empty() ? "(Not set)" : code_folder.c_str());
743
744 Separator();
745
746 if (Button(absl::StrFormat("%s Choose Project File Location", ICON_MD_SAVE)
747 .c_str(),
749 auto project_file_path =
751 if (!project_file_path.empty()) {
752 if (!(absl::EndsWith(project_file_path, ".yaze") ||
753 absl::EndsWith(project_file_path, ".yazeproj"))) {
754 project_file_path += ".yaze";
755 }
756 project_filepath = project_file_path;
757 }
758 }
759
760 if (Button(absl::StrFormat("%s Create Project", ICON_MD_ADD).c_str(),
762 if (!project_filepath.empty() && !project_name.empty() &&
763 !rom_filename.empty()) {
765 "Basic ROM Hack", rom_filename, project_name, project_filepath);
766 if (status.ok()) {
767 auto* project = editor_manager_->GetCurrentProject();
768 if (project) {
769 if (!labels_filename.empty()) {
770 project->labels_filename = labels_filename;
771 }
772 if (!code_folder.empty()) {
773 project->code_folder = code_folder;
774 }
775 if (!labels_filename.empty() || !code_folder.empty()) {
777 status = editor_manager_->SaveProject();
778 }
779 }
780 }
781 if (status.ok()) {
782 // Clear fields
783 project_name = "";
784 project_filepath = "";
785 rom_filename = "";
786 labels_filename = "";
787 code_folder = "";
789 } else {
790 SetStatus(status);
791 }
792 }
793 }
794 SameLine();
795 if (Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(),
797 // Clear fields
798 project_name = "";
799 project_filepath = "";
800 rom_filename = "";
801 labels_filename = "";
802 code_folder = "";
804 }
805}
806
808 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
809 const ImVec4 status_ok = gui::ConvertColorToImVec4(theme.success);
810 const ImVec4 status_warn = gui::ConvertColorToImVec4(theme.warning);
811 const ImVec4 status_info = gui::ConvertColorToImVec4(theme.info);
812 const ImVec4 status_error = gui::ConvertColorToImVec4(theme.error);
813
814 auto status_color = [&](const char* status) -> ImVec4 {
815 if (strcmp(status, "Stable") == 0 || strcmp(status, "Working") == 0) {
816 return status_ok;
817 }
818 if (strcmp(status, "Beta") == 0 || strcmp(status, "Experimental") == 0) {
819 return status_warn;
820 }
821 if (strcmp(status, "Preview") == 0) {
822 return status_info;
823 }
824 if (strcmp(status, "Not available") == 0) {
825 return status_error;
826 }
827 return status_info;
828 };
829
830 struct FeatureRow {
831 const char* feature;
832 const char* status;
833 const char* persistence;
834 const char* notes;
835 };
836
837 auto draw_table = [&](const char* table_id,
838 std::initializer_list<FeatureRow> rows) {
839 ImGuiTableFlags flags = ImGuiTableFlags_BordersInnerH |
840 ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
841 if (!BeginTable(table_id, 4, flags)) {
842 return;
843 }
844 TableSetupColumn("Feature", ImGuiTableColumnFlags_WidthStretch);
845 TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 120.0f);
846 TableSetupColumn("Save/Load", ImGuiTableColumnFlags_WidthFixed, 180.0f);
847 TableSetupColumn("Notes", ImGuiTableColumnFlags_WidthStretch);
848 TableHeadersRow();
849
850 for (const auto& row : rows) {
851 TableNextRow();
852 TableSetColumnIndex(0);
853 TextUnformatted(row.feature);
854 TableSetColumnIndex(1);
855 TextColored(status_color(row.status), "%s", row.status);
856 TableSetColumnIndex(2);
857 TextUnformatted(row.persistence);
858 TableSetColumnIndex(3);
859 TextWrapped("%s", row.notes);
860 }
861
862 EndTable();
863 };
864
865 TextDisabled(
866 tr("Status: Stable = production ready, Beta = usable with gaps, "
867 "Experimental = WIP, Preview = web parity in progress."));
868 TextDisabled(tr("See Settings > Feature Flags for ROM-specific toggles."));
869 Spacing();
870
871 if (CollapsingHeader(tr("Desktop App (yaze)"),
872 ImGuiTreeNodeFlags_DefaultOpen)) {
873 draw_table("desktop_features",
874 {
875 {"ROM load/save", "Stable", "ROM + backups",
876 "Backups on save when enabled."},
877 {"Overworld Editor", "Stable", "ROM",
878 "Maps/entrances/exits/items; version-gated."},
879 {"Dungeon Editor", "Stable", "ROM",
880 "Room objects/tiles/palettes persist."},
881 {"Palette Editor", "Stable", "ROM",
882 "Palette edits persist; JSON IO pending."},
883 {"Graphics Editor", "Beta", "ROM",
884 "Sheet edits persist; tooling still expanding."},
885 {"Sprite Editor", "Stable", "ROM", "Sprite edits persist."},
886 {"Message Editor", "Stable", "ROM", "Text edits persist."},
887 {"Screen Editor", "Experimental", "ROM (partial)",
888 "Save coverage incomplete."},
889 {"Hex Editor", "Beta", "ROM", "Search UX incomplete."},
890 {"Assembly/Asar", "Beta", "ROM + project",
891 "Patch apply + symbol export."},
892 {"Emulator", "Beta", "Runtime only",
893 "Save-state UI partially wired."},
894 {"Music Editor", "Experimental", "ROM (partial)",
895 "Serialization in progress."},
896 {"Agent UI", "Experimental", ".yaze/agent",
897 "Requires AI provider configuration."},
898 {"Settings/Layouts", "Beta", ".yaze config",
899 "Layout serialization improving."},
900 });
901 }
902
903 if (CollapsingHeader(tr("z3ed CLI"))) {
904 draw_table("cli_features",
905 {
906 {"ROM read/write/validate", "Stable", "ROM file",
907 "Direct command execution."},
908 {"Agent workflows", "Stable", ".yaze/proposals + sandboxes",
909 "Commit writes ROM; revert reloads."},
910 {"Snapshots/restore", "Stable", "Sandbox copies",
911 "Supports YAZE_SANDBOX_ROOT override."},
912 {"Doctor/test suites", "Stable", "Reports",
913 "Structured output for automation."},
914 {"TUI/REPL", "Stable", "Session history",
915 "Interactive command palette + logs."},
916 });
917 }
918
919 if (CollapsingHeader(tr("Web/WASM Preview"))) {
920 draw_table(
921 "web_features",
922 {
923 {"ROM load/save", "Preview", "IndexedDB + download",
924 "Drag/drop or picker; download for backups."},
925 {"Editors (OW/Dungeon/Palette/etc.)", "Preview",
926 "IndexedDB + download", "Parity work in progress."},
927 {"Hex Editor", "Working", "IndexedDB + download",
928 "Direct ROM editing available."},
929 {"Asar patching", "Preview", "ROM", "Basic patch apply support."},
930 {"Emulator", "Not available", "N/A", "Desktop only."},
931 {"Collaboration", "Experimental", "Server",
932 "Requires yaze-server."},
933 {"AI features", "Preview", "Server", "Requires AI-enabled server."},
934 });
935 }
936
937 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
939 }
940}
941
943 Text(tr("File -> Open"));
944 Text(tr("Select a ROM file to open"));
945 Text(tr("Supported ROMs (headered or unheadered):"));
946 Text(tr("The Legend of Zelda: A Link to the Past"));
947 Text(tr("US Version 1.0"));
948 Text(tr("JP Version 1.0"));
949 Spacing();
950 TextWrapped(
951 tr("ROM files are not bundled. Use a clean, legally obtained copy."));
952
953 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
954 Hide("Open a ROM");
955 }
956}
957
959 Text(tr("Project Menu"));
960 Text(tr("Create a new project or open an existing one."));
961 Text(tr("Save the project to save the current state of the project."));
962 TextWrapped(
963 tr("To save a project, you need to first open a ROM and initialize your "
964 "code path and labels file. Label resource manager can be found in "
965 "the View menu. Code path is set in the Code editor after opening a "
966 "folder."));
967
968 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
969 Hide("Manage Project");
970 }
971}
972
974 TextWrapped(tr("Welcome to YAZE v%s!"), YAZE_VERSION_STRING);
975 TextWrapped(tr(
976 "YAZE lets you modify 'The Legend of Zelda: A Link to the Past' (US or "
977 "JP) ROMs with modern tooling."));
978 Spacing();
979 TextWrapped(tr("Release Highlights:"));
980 BulletText(
981 tr("AI-assisted workflows via z3ed agent and in-app panels "
982 "(Ollama/Gemini/OpenAI/Anthropic)"));
983 BulletText(tr("Clear feature status panels and improved help/tooltips"));
984 BulletText(tr("Unified .yaze storage across desktop/CLI/web"));
985 Spacing();
986 TextWrapped(tr("General Tips:"));
987 BulletText(tr("Open a clean ROM and save a backup before editing"));
988 BulletText(tr("Use Help (F1) for context-aware guidance and shortcuts"));
989 BulletText(tr("Coming from ZScream? Open Help → Coming from ZScream"));
990 BulletText(tr(
991 "Configure AI providers (Ollama/Gemini/OpenAI/Anthropic) in Settings > "
992 "Agent"));
993
994 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
995 Hide("Getting Started");
996 }
997}
998
1000 TextWrapped(tr("Asar 65816 Assembly Integration"));
1001 TextWrapped(
1002 tr("YAZE includes full Asar assembler support for ROM patching."));
1003 Spacing();
1004 TextWrapped(tr("Features:"));
1005 BulletText(tr("Cross-platform ROM patching with assembly code"));
1006 BulletText(tr("Symbol export with addresses and opcodes"));
1007 BulletText(tr("Assembly validation with detailed error reporting"));
1008 BulletText(tr("Memory-safe patch application with size checks"));
1009
1010 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1011 Hide("Asar Integration");
1012 }
1013}
1014
1016 TextWrapped(tr("Build Instructions"));
1017 TextWrapped(tr("YAZE uses modern CMake for cross-platform builds."));
1018 Spacing();
1019 TextWrapped(tr("Quick Start (examples):"));
1020 BulletText(tr("cmake --preset mac-dbg | lin-dbg | win-dbg"));
1021 BulletText(tr("cmake --build --preset <preset> --target yaze"));
1022 Spacing();
1023 TextWrapped(tr("AI Builds:"));
1024 BulletText(tr("cmake --preset mac-ai | lin-ai | win-ai"));
1025 BulletText(tr("cmake --build --preset <preset> --target yaze z3ed"));
1026 Spacing();
1027 TextWrapped(tr("Docs: docs/public/build/quick-reference.md"));
1028
1029 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1030 Hide("Build Instructions");
1031 }
1032}
1033
1035 TextWrapped(tr("Command Line Interface (z3ed)"));
1036 TextWrapped(tr("Scriptable ROM editing and AI agent workflows."));
1037 Spacing();
1038 TextWrapped(tr("Commands:"));
1039 BulletText(tr("z3ed rom-info --rom=zelda3.sfc"));
1040 BulletText(tr("z3ed agent simple-chat --rom=zelda3.sfc --ai_provider=auto"));
1041 BulletText(tr("z3ed agent plan --rom=zelda3.sfc"));
1042 BulletText(tr("z3ed test-list --format json"));
1043 BulletText(tr("z3ed patch apply-asar patch.asm --rom=zelda3.sfc"));
1044 BulletText(tr("z3ed help dungeon-place-sprite"));
1045 Spacing();
1046 TextWrapped(tr("Storage:"));
1047 BulletText(
1048 tr("Agent plans/proposals live under ~/.yaze (see docs for details)"));
1049
1050 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1051 Hide("CLI Usage");
1052 }
1053}
1054
1056 TextWrapped(tr("Troubleshooting"));
1057 TextWrapped(tr("Common issues and solutions:"));
1058 Spacing();
1059 BulletText(tr("ROM won't load: Check file format (SFC/SMC supported)"));
1060 BulletText(
1061 tr("AI agent missing: Start Ollama or set GEMINI_API_KEY/OPENAI_API_KEY/"
1062 "ANTHROPIC_API_KEY (web uses AI_AGENT_ENDPOINT)"));
1063 BulletText(tr("Graphics issues: Disable experimental flags in Settings"));
1064 BulletText(
1065 tr("Performance: Enable hardware acceleration in display settings"));
1066 BulletText(tr("Crashes: Check ROM file integrity and available memory"));
1067 BulletText(tr("Layout issues: Reset workspace layouts from View > Layouts"));
1068
1069 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1070 Hide("Troubleshooting");
1071 }
1072}
1073
1075 TextWrapped(tr("Contributing to YAZE"));
1076 TextWrapped(tr("YAZE is open source and welcomes contributions!"));
1077 Spacing();
1078 TextWrapped(tr("How to contribute:"));
1079 BulletText(tr("Fork the repository on GitHub"));
1080 BulletText(tr("Create feature branches for new work"));
1081 BulletText(tr("Follow C++ coding standards"));
1082 BulletText(tr("Include tests for new features"));
1083 BulletText(tr("Submit pull requests for review"));
1084
1085 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1086 Hide("Contributing");
1087 }
1088}
1089
1091 TextWrapped(tr("What's New in YAZE v%s"), YAZE_VERSION_STRING);
1092 Spacing();
1093
1094 if (CollapsingHeader(
1095 absl::StrFormat("%s User Interface & Theming", ICON_MD_PALETTE)
1096 .c_str(),
1097 ImGuiTreeNodeFlags_DefaultOpen)) {
1098 BulletText(
1099 tr("Feature status/persistence summaries across desktop/CLI/web"));
1100 BulletText(tr("Shortcut/help panels now match configured keybindings"));
1101 BulletText(tr("Refined onboarding tips and error messaging"));
1102 BulletText(tr("Help text refreshed across desktop, CLI, and web"));
1103 }
1104
1105 if (CollapsingHeader(
1106 absl::StrFormat("%s Development & Build System", ICON_MD_BUILD)
1107 .c_str(),
1108 ImGuiTreeNodeFlags_DefaultOpen)) {
1109 BulletText(tr("Asar 65816 assembler integration for ROM patching"));
1110 BulletText(tr("z3ed CLI + TUI for scripting, test/doctor, and automation"));
1111 BulletText(tr("Modern CMake presets for desktop, AI, and web builds"));
1112 BulletText(tr("Unified version + storage references for 0.5.1"));
1113 }
1114
1115 if (CollapsingHeader(
1116 absl::StrFormat("%s Core Improvements", ICON_MD_SETTINGS).c_str())) {
1117 BulletText(tr("Improved project metadata + .yaze storage alignment"));
1118 BulletText(tr("Stronger error reporting and status feedback"));
1119 BulletText(tr("Performance and stability improvements across editors"));
1120 BulletText(tr("Expanded logging and diagnostics tooling"));
1121 }
1122
1123 if (CollapsingHeader(
1124 absl::StrFormat("%s Editor Features", ICON_MD_EDIT).c_str())) {
1125 BulletText(tr("Music editor updates with SPC parsing/playback"));
1126 BulletText(
1127 tr("AI agent-assisted editing workflows (multi-provider + vision)"));
1128 BulletText(tr("Expanded overworld/dungeon tooling and palette accuracy"));
1129 BulletText(tr("Web/WASM preview with collaboration hooks"));
1130 }
1131
1132 Spacing();
1133 if (Button(
1134 absl::StrFormat("%s View Release Notes", ICON_MD_DESCRIPTION).c_str(),
1135 ImVec2(-1, 30))) {
1136 // Close this popup and show theme settings
1138 // Could trigger release notes panel opening here
1139 }
1140
1141 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1143 }
1144}
1145
1147 TextWrapped(tr("Coming from ZScream?"));
1148 TextWrapped(tr(
1149 "yaze covers the same Zelda 3 editing surfaces with a modern workspace, "
1150 "projects, and CLI. Use this map to find familiar tools."));
1151 Spacing();
1152
1153 if (CollapsingHeader(absl::StrFormat("%s Editors", ICON_MD_APPS).c_str(),
1154 ImGuiTreeNodeFlags_DefaultOpen)) {
1155 BulletText(tr("Overworld Editor ≈ ZScream overworld map canvas + tile16"));
1156 BulletText(
1157 tr("Dungeon Editor ≈ underworld rooms (objects, sprites, properties)"));
1158 BulletText(tr("Graphics / Sprite Editors ≈ GFX + sprite drawing"));
1159 BulletText(tr("Palette Editor ≈ palette groups and edits"));
1160 BulletText(tr("Message Editor ≈ dialogue / text"));
1161 BulletText(
1162 tr("Screen Editor → Overworld Map ≈ pause-menu map art "
1163 "(not the playable overworld)"));
1164 }
1165
1166 if (CollapsingHeader(
1167 absl::StrFormat("%s Layout & navigation", ICON_MD_DASHBOARD).c_str(),
1168 ImGuiTreeNodeFlags_DefaultOpen)) {
1169 BulletText(
1170 tr("Left activity bar opens editor categories (like ZScream "
1171 "tool tabs)"));
1172 BulletText(
1173 tr("Dungeon workbench defaults to ZScream-style: selectors "
1174 "left, inspector right"));
1175 BulletText(tr("Ctrl+Shift+P opens the command palette for any action"));
1176 BulletText(
1177 tr("F1 / Help drawer shows context shortcuts for the active "
1178 "editor"));
1179 }
1180
1181 if (CollapsingHeader(
1182 absl::StrFormat("%s Projects & ROM files", ICON_MD_FOLDER).c_str(),
1183 ImGuiTreeNodeFlags_DefaultOpen)) {
1184 BulletText(
1185 tr(".yaze / .yazeproj track ROM path, flags, and workspace "
1186 "settings"));
1187 BulletText(
1188 tr(".zsproj can be opened when present — same Open ROM / "
1189 "Project flow"));
1190 BulletText(
1191 tr("Always keep a clean backup; Backup Before Save is on by "
1192 "default"));
1193 BulletText(
1194 tr("ZSO / ZSCustomOverworld versions are detected from the ROM "
1195 "(vanilla, v1, v2, v3)"));
1196 }
1197
1198 if (CollapsingHeader(
1199 absl::StrFormat("%s Overworld specifics", ICON_MD_LANDSCAPE).c_str(),
1200 ImGuiTreeNodeFlags_DefaultOpen)) {
1201 BulletText(tr("Tile16 selector / workbench ≈ ZScream tile picker + paint"));
1202 BulletText(
1203 tr("Map Properties gates ZSO fields (area size, BG colors, "
1204 "animated GFX) by detected version"));
1205 BulletText(tr("Screen Editor → Overworld Map is pause-menu art only"));
1206 }
1207
1208 if (CollapsingHeader(absl::StrFormat("%s Saving", ICON_MD_SAVE).c_str())) {
1209 BulletText(tr("File → Save Scope chooses ROM, project, or both"));
1210 BulletText(tr("Autosave can be tuned under Settings → Editor Behavior"));
1211 BulletText(tr("ROM Backups lists timestamped copies for restore"));
1212 }
1213
1214 Spacing();
1215 TextWrapped(tr(
1216 "Tip: first-run toasts point at this guide once per tip. Reset tips in "
1217 "Settings → Editor Behavior if you want them again."));
1218
1219 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1221 }
1222}
1223
1225 TextWrapped(tr("Workspace Management"));
1226 TextWrapped(tr(
1227 "YAZE supports multiple ROM sessions and flexible workspace layouts."));
1228 Spacing();
1229
1230 TextWrapped(tr("Session Management:"));
1231 BulletText(tr("Ctrl+Shift+N: Create new session"));
1232 BulletText(tr("Ctrl+Shift+W: Close current session"));
1233 BulletText(tr("Ctrl+Tab: Quick session switcher"));
1234 BulletText(tr("Each session maintains its own ROM and editor state"));
1235
1236 Spacing();
1237 TextWrapped(tr("Layout Management:"));
1238 BulletText(tr("Drag window tabs to dock/undock"));
1239 BulletText(tr("Ctrl+Shift+S: Save current layout"));
1240 BulletText(tr("Ctrl+Shift+O: Load saved layout"));
1241 BulletText(tr("F11: Maximize current window"));
1242
1243 Spacing();
1244 TextWrapped(tr("Preset Layouts:"));
1245 BulletText(tr("Developer: Code, memory, testing tools"));
1246 BulletText(tr("Designer: Graphics, palettes, sprites"));
1247 BulletText(tr("Modder: All gameplay editing tools"));
1248
1249 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1250 Hide("Workspace Help");
1251 }
1252}
1253
1255 TextColored(gui::GetWarningColor(), tr("%s Warning"), ICON_MD_WARNING);
1256 TextWrapped(tr("You have reached the recommended session limit."));
1257 TextWrapped(tr("Having too many sessions open may impact performance."));
1258 Spacing();
1259 TextWrapped(tr("Consider closing unused sessions or saving your work."));
1260
1261 if (Button(tr("Understood"), ::yaze::gui::kDefaultModalSize)) {
1262 Hide("Session Limit Warning");
1263 }
1264 SameLine();
1265 if (Button(tr("Open Session Manager"), ::yaze::gui::kDefaultModalSize)) {
1266 Hide("Session Limit Warning");
1267 // This would trigger the session manager to open
1268 }
1269}
1270
1272 TextColored(gui::GetWarningColor(), tr("%s Confirm Reset"), ICON_MD_WARNING);
1273 TextWrapped(tr("This will reset your current workspace layout to default."));
1274 TextWrapped(tr("Any custom window arrangements will be lost."));
1275 Spacing();
1276 TextWrapped(tr("Do you want to continue?"));
1277
1278 if (Button(tr("Reset Layout"), ::yaze::gui::kDefaultModalSize)) {
1279 Hide("Layout Reset Confirm");
1280 // This would trigger the actual reset
1281 }
1282 SameLine();
1283 if (Button(tr("Cancel"), ::yaze::gui::kDefaultModalSize)) {
1284 Hide("Layout Reset Confirm");
1285 }
1286}
1287
1289 TextColored(gui::GetInfoColor(), tr("%s Layout Presets"), ICON_MD_DASHBOARD);
1290 Separator();
1291 Spacing();
1292
1293 TextWrapped(
1294 tr("Choose a workspace preset to quickly configure your layout:"));
1295 Spacing();
1296
1297 // Get named presets from LayoutPresets
1298 struct PresetInfo {
1299 const char* name;
1300 const char* icon;
1301 const char* description;
1302 std::function<PanelLayoutPreset()> getter;
1303 };
1304
1305 PresetInfo presets[] = {
1306 {"Minimal", ICON_MD_CROP_FREE,
1307 "Essential cards only - maximum editing space",
1308 []() { return LayoutPresets::GetMinimalPreset(); }},
1309 {"Developer", ICON_MD_BUG_REPORT,
1310 "Debug and development focused - CPU/Memory/Breakpoints",
1311 []() { return LayoutPresets::GetDeveloperPreset(); }},
1312 {"Designer", ICON_MD_PALETTE,
1313 "Visual and artistic focused - Graphics/Palettes/Sprites",
1314 []() { return LayoutPresets::GetDesignerPreset(); }},
1315 {"Modder", ICON_MD_BUILD,
1316 "Full-featured - All tools available for comprehensive editing",
1317 []() { return LayoutPresets::GetModderPreset(); }},
1318 {"Overworld Expert", ICON_MD_MAP,
1319 "Complete overworld editing toolkit with all map tools",
1320 []() { return LayoutPresets::GetOverworldArtistPreset(); }},
1321 {"Dungeon Expert", ICON_MD_DOOR_SLIDING,
1322 "Complete dungeon editing toolkit with room tools",
1323 []() { return LayoutPresets::GetDungeonMasterPreset(); }},
1324 {"Testing", ICON_MD_SCIENCE, "Quality assurance and ROM testing layout",
1325 []() { return LayoutPresets::GetLogicDebuggerPreset(); }},
1326 {"Audio", ICON_MD_MUSIC_NOTE, "Music and sound editing layout",
1327 []() { return LayoutPresets::GetAudioEngineerPreset(); }},
1328 };
1329
1330 constexpr int kPresetCount = 8;
1331
1332 // Draw preset buttons in a grid
1333 float button_width = 200.0f;
1334 float button_height = 50.0f;
1335
1336 for (int i = 0; i < kPresetCount; i++) {
1337 if (i % 2 != 0)
1338 SameLine();
1339
1340 {
1341 gui::StyleVarGuard align_guard(ImGuiStyleVar_ButtonTextAlign,
1342 ImVec2(0.0f, 0.5f));
1343 if (Button(absl::StrFormat("%s %s", presets[i].icon, presets[i].name)
1344 .c_str(),
1345 ImVec2(button_width, button_height))) {
1346 // Apply the preset
1347 auto preset = presets[i].getter();
1348 auto& window_manager = editor_manager_->window_manager();
1349 // Hide all panels first
1350 window_manager.HideAll();
1351 // Show preset panels
1352 for (const auto& panel_id : preset.default_visible_panels) {
1353 window_manager.OpenWindow(panel_id);
1354 }
1356 }
1357 }
1358
1359 if (IsItemHovered()) {
1360 BeginTooltip();
1361 TextUnformatted(presets[i].description);
1362 EndTooltip();
1363 }
1364 }
1365
1366 Spacing();
1367 Separator();
1368 Spacing();
1369
1370 // Reset current editor to defaults
1371 if (Button(
1372 absl::StrFormat("%s Reset Current Editor", ICON_MD_REFRESH).c_str(),
1373 ImVec2(-1, 0))) {
1374 auto& window_manager = editor_manager_->window_manager();
1375 auto* current_editor = editor_manager_->GetCurrentEditor();
1376 if (current_editor) {
1377 auto current_type = current_editor->type();
1378 window_manager.ResetToDefaults(0, current_type);
1379 }
1381 }
1382
1383 Spacing();
1384 if (Button(tr("Close"), ImVec2(-1, 0))) {
1386 }
1387}
1388
1390 TextColored(gui::GetInfoColor(), tr("%s Session Manager"), ICON_MD_TAB);
1391 Separator();
1392 Spacing();
1393
1394 size_t session_count = editor_manager_->GetActiveSessionCount();
1395 size_t active_session = editor_manager_->GetCurrentSessionIndex();
1396
1397 Text(tr("Active Sessions: %zu"), session_count);
1398 Spacing();
1399
1400 // Session table
1401 if (BeginTable("SessionTable", 4,
1402 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
1403 TableSetupColumn("#", ImGuiTableColumnFlags_WidthFixed, 30.0f);
1404 TableSetupColumn("ROM", ImGuiTableColumnFlags_WidthStretch);
1405 TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 80.0f);
1406 TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1407 TableHeadersRow();
1408
1409 for (size_t i = 0; i < session_count; i++) {
1410 TableNextRow();
1411
1412 // Session number
1413 TableSetColumnIndex(0);
1414 Text("%zu", i + 1);
1415
1416 // ROM name (simplified - show current ROM for active session)
1417 TableSetColumnIndex(1);
1418 if (i == active_session) {
1419 auto* rom = editor_manager_->GetCurrentRom();
1420 if (rom && rom->is_loaded()) {
1421 TextUnformatted(rom->filename().c_str());
1422 } else {
1423 TextDisabled(tr("(No ROM loaded)"));
1424 }
1425 } else {
1426 TextDisabled(tr("Session %zu"), i + 1);
1427 }
1428
1429 // Status indicator
1430 TableSetColumnIndex(2);
1431 if (i == active_session) {
1432 TextColored(gui::GetSuccessColor(), tr("%s Active"),
1434 } else {
1435 TextDisabled(tr("Inactive"));
1436 }
1437
1438 // Actions
1439 TableSetColumnIndex(3);
1440 PushID(static_cast<int>(i));
1441
1442 if (i != active_session) {
1443 if (SmallButton(tr("Switch"))) {
1445 }
1446 SameLine();
1447 }
1448
1449 BeginDisabled(session_count <= 1);
1450 if (SmallButton(tr("Close"))) {
1452 }
1453 EndDisabled();
1454
1455 PopID();
1456 }
1457
1458 EndTable();
1459 }
1460
1461 Spacing();
1462 Separator();
1463 Spacing();
1464
1465 // New session button
1466 if (Button(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str(),
1467 ImVec2(-1, 0))) {
1469 }
1470
1471 Spacing();
1472 if (Button(tr("Close"), ImVec2(-1, 0))) {
1474 }
1475}
1476
1478 // Set a comfortable default size with natural constraints
1479 SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
1480 SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
1481
1482 Text(tr("%s Display & Theme Settings"), ICON_MD_DISPLAY_SETTINGS);
1483 TextWrapped(tr("Customize your YAZE experience - accessible anytime!"));
1484 Separator();
1485
1486 // Create a child window for scrollable content to avoid table conflicts
1487 // Use remaining space minus the close button area
1488 float available_height =
1489 GetContentRegionAvail().y - 60; // Reserve space for close button
1490 if (BeginChild("DisplaySettingsContent", ImVec2(0, available_height), true,
1491 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1492 // Use the popup-safe version to avoid table conflicts
1494
1495 Separator();
1496 gui::TextWithSeparators("Font Manager");
1498
1499 // Global font scale (moved from the old display settings window)
1500 ImGuiIO& io = GetIO();
1501 Separator();
1502 Text(tr("Global Font Scale"));
1503 float font_global_scale = io.FontGlobalScale;
1504 if (SliderFloat("##global_scale", &font_global_scale, 0.5f, 2.0f, "%.2f")) {
1505 if (editor_manager_) {
1506 editor_manager_->SetFontGlobalScale(font_global_scale);
1507 } else {
1508 io.FontGlobalScale = font_global_scale;
1509 }
1510 }
1511 }
1512 EndChild();
1513
1514 Separator();
1515 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1516 Hide("Display Settings");
1517 }
1518}
1519
1521 using namespace ImGui;
1522
1523 // Display feature flags editor using the existing FlagsMenu system
1524 Text(tr("Feature Flags Configuration"));
1525 Separator();
1526
1527 BeginChild("##FlagsContent", ImVec2(0, -30), true);
1528
1529 // Use the feature flags menu system
1530 static gui::FlagsMenu flags_menu;
1531
1532 if (BeginTabBar("FlagCategories")) {
1533 if (BeginTabItem(tr("Overworld"))) {
1534 flags_menu.DrawOverworldFlags();
1535 EndTabItem();
1536 }
1537 if (BeginTabItem(tr("Dungeon"))) {
1538 flags_menu.DrawDungeonFlags();
1539 EndTabItem();
1540 }
1541 if (BeginTabItem(tr("Resources"))) {
1542 flags_menu.DrawResourceFlags();
1543 EndTabItem();
1544 }
1545 if (BeginTabItem(tr("System"))) {
1546 flags_menu.DrawSystemFlags();
1547 EndTabItem();
1548 }
1549 EndTabBar();
1550 }
1551
1552 EndChild();
1553
1554 Separator();
1555 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1557 }
1558}
1559
1561 using namespace ImGui;
1562
1563 Text(tr("Data Integrity Check Results"));
1564 Separator();
1565
1566 BeginChild("##IntegrityContent", ImVec2(0, -30), true);
1567
1568 // Placeholder for data integrity results
1569 // In a full implementation, this would show test results
1570 Text(tr("ROM Data Integrity:"));
1571 Separator();
1572 TextColored(gui::GetSuccessColor(), tr("✓ ROM header valid"));
1573 TextColored(gui::GetSuccessColor(), tr("✓ Checksum valid"));
1574 TextColored(gui::GetSuccessColor(), tr("✓ Graphics data intact"));
1575 TextColored(gui::GetSuccessColor(), tr("✓ Map data intact"));
1576
1577 Spacing();
1578 Text(tr("No issues detected."));
1579
1580 EndChild();
1581
1582 Separator();
1583 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1585 }
1586}
1587
1589 using namespace ImGui;
1590
1591 if (!editor_manager_) {
1592 Text(tr("Editor manager unavailable."));
1593 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1595 }
1596 return;
1597 }
1598
1599 const int unloaded = editor_manager_->pending_pot_item_unloaded_rooms();
1600 const int total = editor_manager_->pending_pot_item_total_rooms();
1601
1602 Text(tr("Pot Item Save Confirmation"));
1603 Separator();
1604 TextWrapped(tr("Dungeon pot item saving is enabled, but %d of %d rooms are "
1605 "not loaded."),
1606 unloaded, total);
1607 Spacing();
1608 TextWrapped(
1609 tr("Saving now can overwrite pot items in unloaded rooms. Choose how to "
1610 "proceed:"));
1611
1612 Spacing();
1613 if (Button(tr("Save without pot items"), ImVec2(0, 0))) {
1617 return;
1618 }
1619 SameLine();
1620 const bool save_anyway = Button(tr("Save anyway"), ImVec2(0, 0));
1621 if (ImGui::GetItemID() != 0) {
1623 "dungeon.pot_item_save_confirm/button:Save anyway", "button",
1624 ImGui::GetItemID(),
1625 "Continue the pending dungeon save with pot item writes enabled");
1626 }
1627 if (save_anyway) {
1631 return;
1632 }
1633 SameLine();
1634 if (Button(tr("Cancel"), ImVec2(0, 0))) {
1638 }
1639}
1640
1642 using namespace ImGui;
1643
1644 if (!editor_manager_) {
1645 Text(tr("Editor manager unavailable."));
1646 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1648 }
1649 return;
1650 }
1651
1653 auto policy = project::RomWritePolicyToString(
1655 const auto expected = editor_manager_->GetProjectExpectedRomHash();
1656 const auto actual = editor_manager_->GetCurrentRomHash();
1657 const auto* project = editor_manager_->GetCurrentProject();
1658 const auto actual_path = editor_manager_->GetCurrentRom()
1660 : std::string();
1661 const auto editable_path =
1662 project && project->hack_manifest.loaded() &&
1663 !project->hack_manifest.build_pipeline().dev_rom.empty()
1664 ? project->GetAbsolutePath(
1665 project->hack_manifest.build_pipeline().dev_rom)
1666 : (project ? project->rom_filename : std::string());
1667
1668 Text(tr("ROM Write Confirmation"));
1669 Separator();
1670 TextWrapped(
1671 tr("The loaded ROM hash does not match the project's expected hash."));
1672 Spacing();
1673 Text(tr("Role: %s"), role.c_str());
1674 Text(tr("Write policy: %s"), policy.c_str());
1675 Text(tr("Loaded ROM: %s"),
1676 actual_path.empty() ? "(unknown)" : actual_path.c_str());
1677 Text(tr("Editable target: %s"),
1678 editable_path.empty() ? "(unset)" : editable_path.c_str());
1679 Text(tr("Expected: %s"), expected.empty() ? "(unset)" : expected.c_str());
1680 Text(tr("Actual: %s"), actual.empty() ? "(unknown)" : actual.c_str());
1681 Spacing();
1682 TextWrapped(tr(
1683 "Proceeding will write to the current ROM file. This may corrupt a base "
1684 "or release ROM if it is not the intended editable project ROM."));
1685
1686 Spacing();
1687 const bool save_anyway = Button(tr("Save anyway"), ImVec2(0, 0));
1689 "RomWriteConfirm/button:Save anyway", "button", GetItemID());
1690 if (save_anyway) {
1693 auto status = editor_manager_->ResumePendingRomSave();
1694 if (!status.ok() && !absl::IsCancelled(status)) {
1695 if (auto* toast = editor_manager_->toast_manager()) {
1696 toast->Show(absl::StrFormat("Save failed: %s", status.message()),
1698 }
1699 }
1700 return;
1701 }
1702 SameLine();
1703 if (Button(tr("Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1706 }
1707}
1708
1710 using namespace ImGui;
1711
1712 if (!editor_manager_) {
1713 Text(tr("Editor manager unavailable."));
1714 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1716 }
1717 return;
1718 }
1719
1720 const auto& conflicts = editor_manager_->pending_write_conflicts();
1721
1722 TextColored(gui::GetWarningColor(), tr("%s Write Conflict Warning"),
1724 Separator();
1725 TextWrapped(
1726 tr("The following ROM addresses are owned by ASM hooks and will be "
1727 "overwritten on next build. Saving now will write data that asar "
1728 "will replace."));
1729 Spacing();
1730
1731 if (!conflicts.empty()) {
1732 if (BeginTable("WriteConflictTable", 3,
1733 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
1734 ImGuiTableFlags_Resizable)) {
1735 TableSetupColumn("Address", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1736 TableSetupColumn("Ownership", ImGuiTableColumnFlags_WidthFixed, 140.0f);
1737 TableSetupColumn("Module", ImGuiTableColumnFlags_WidthStretch);
1738 TableHeadersRow();
1739
1740 for (const auto& conflict : conflicts) {
1741 TableNextRow();
1742 TableNextColumn();
1743 Text("$%06X", conflict.address);
1744 TableNextColumn();
1745 TextUnformatted(
1746 core::AddressOwnershipToString(conflict.ownership).c_str());
1747 TableNextColumn();
1748 if (!conflict.module.empty()) {
1749 TextUnformatted(conflict.module.c_str());
1750 } else {
1751 TextDisabled(tr("(unknown)"));
1752 }
1753 }
1754 EndTable();
1755 }
1756 }
1757
1758 Spacing();
1759 Text(tr("%zu conflict(s) detected."), conflicts.size());
1760 Spacing();
1761
1762 if (Button(tr("Save Anyway"), ImVec2(0, 0))) {
1765 auto status = editor_manager_->ResumePendingRomSave();
1766 if (!status.ok() && !absl::IsCancelled(status)) {
1767 if (auto* toast = editor_manager_->toast_manager()) {
1768 toast->Show(absl::StrFormat("Save failed: %s", status.message()),
1770 }
1771 }
1772 return;
1773 }
1774 SameLine();
1775 if (Button(tr("Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1778 }
1779}
1780
1782 using namespace ImGui;
1783
1784 if (!editor_manager_) {
1786 return;
1787 }
1788
1791 return;
1792 }
1793
1794 Text(tr("%s Unsaved Session Changes"), ICON_MD_WARNING);
1795 Separator();
1796 TextWrapped("%s",
1798 Spacing();
1799
1800 // An empty save label means saving first is meaningless for this action
1801 // (for example Revert to Saved), so only Continue and Cancel are offered.
1802 const std::string save_label =
1804 if (!save_label.empty()) {
1805 if (Button(save_label.c_str(), ::yaze::gui::kDefaultModalSize)) {
1807 return;
1808 }
1809 SameLine();
1810 }
1811 const std::string continue_label =
1813 if (Button(continue_label.c_str(), ::yaze::gui::kDefaultModalSize)) {
1815 return;
1816 }
1817
1818 SameLine();
1819 if (Button(tr("Cancel"), ::yaze::gui::kDefaultModalSize) ||
1820 IsKeyPressed(ImGuiKey_Escape)) {
1822 }
1823}
1824
1825} // namespace editor
1826} // namespace yaze
auto filename() const
Definition rom.h:207
bool is_loaded() const
Definition rom.h:187
static Flags & get()
Definition features.h:119
The EditorManager controls the main editor window and manages the various editor classes.
void ConfirmPendingUnsavedSessionActionSaveAndContinue()
absl::Status SaveRomAs(const std::string &filename)
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 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 SetFontGlobalScale(float scale)
void ResolvePotItemSaveConfirmation(PotItemSaveDecision decision)
auto GetCurrentEditor() const -> Editor *override
WorkspaceWindowManager & window_manager()
std::string GetProjectExpectedRomHash() const
absl::Status DiscardPendingRomBackupRestore()
const std::vector< core::WriteConflict > & pending_write_conflicts() const
std::string GetPendingUnsavedSessionActionContinueLabel() const
std::string GetPendingUnsavedSessionActionPrompt() const
project::RomRole GetProjectRomRole() const
size_t GetCurrentSessionId() const
Stable workspace identity; unlike the UI index, it does not compact.
project::YazeProject * GetCurrentProject()
int pending_pot_item_unloaded_rooms() const
absl::Status OpenRomOrProject(const std::string &filename)
void RemoveSession(size_t index)
std::string GetPendingUnsavedSessionActionSaveLabel() const
EditorType type() const
Definition editor.h:343
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 SetStatus(const absl::Status &status)
bool IsVisible(const char *name) const
void Show(const char *name)
void Hide(const char *name)
struct yaze::editor::PopupManager::SaveAsState save_as_
PopupManager(EditorManager *editor_manager)
std::unordered_map< std::string, PopupParams > popups_
void RegisterPopup(const std::string &name, PopupType type, std::function< void()> draw_function, bool allow_resize=false)
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()
void RegisterWidget(const std::string &full_path, const std::string &type, ImGuiID imgui_id, const std::string &description="", const WidgetMetadata &metadata=WidgetMetadata())
static WidgetIdRegistry & Instance()
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_APPS
Definition icons.h:168
#define ICON_MD_CANCEL
Definition icons.h:364
#define ICON_MD_LANDSCAPE
Definition icons.h:1059
#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_UNDO
Definition icons.h:2039
#define ICON_MD_CROP_FREE
Definition icons.h:495
#define ICON_MD_DELETE_SWEEP
Definition icons.h:533
Definition input.cc:30
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 * kComingFromZScream
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 * kUnsavedSessionChanges
constexpr const char * kBuildInstructions
constexpr const char * kWorkspaceHelp
constexpr const char * kRomWriteConfirm
PopupType
Type classification for popups to enable future filtering and organization.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:140
void DrawFontManager()
Definition style.cc:1350
ImVec4 GetSuccessColor()
Definition ui_helpers.cc:49
ImVec4 GetWarningColor()
Definition ui_helpers.cc:54
void DrawDisplaySettingsForPopup(ImGuiStyle *ref)
Definition style.cc:895
constexpr ImVec2 kDefaultModalSize
Definition input.h:21
ImVec4 GetInfoColor()
Definition ui_helpers.cc:64
void TextWithSeparators(const absl::string_view &text)
Definition style.cc:1344
std::string RomRoleToString(RomRole role)
Definition project.cc:396
std::string RomWritePolicyToString(RomWritePolicy policy)
Definition project.cc:424
std::string HexLongLong(uint64_t qword, HexStringParams params)
Definition hex.cc:66
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
Definition file_util.cc:87
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
Definition overworld.h:316
Room transition destination.
Definition zelda.h:448
Defines default panel visibility for an editor type.
Runtime state for a registered popup.
std::function< void()> draw_function
std::string labels_filename
Definition project.h:314
std::string GetAbsolutePath(const std::string &relative_path) const
Definition project.cc:2028
Public YAZE API umbrella header.