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 } else if (profile.layout_kind ==
342 Separator();
343 Text("Overworld Format: %s",
344 zelda3::zscream::LayoutName(profile.zscream_layout));
345 TextUnformatted("Collision metadata: per-sheet, read-only");
346 TextUnformatted("Preview: static full-load sheets");
347 TextUnformatted("Tail-map expansion: unavailable");
348 } else if (profile.layout_kind ==
350 Separator();
351 Text("Overworld Format: %s (raw marker $%02X)",
352 zelda3::zscream::LayoutName(profile.zscream_layout),
353 static_cast<unsigned>(profile.asm_version));
354 TextUnformatted("Write Support: unqualified for this custom layout");
355 TextUnformatted("Compatibility: unqualified");
356 }
357
358 auto* project = editor_manager_->GetCurrentProject();
359 if (project && project->project_opened()) {
360 Separator();
361 Text(tr("Role: %s"),
362 project::RomRoleToString(project->rom_metadata.role).c_str());
363 Text(tr("Write Policy: %s"),
364 project::RomWritePolicyToString(project->rom_metadata.write_policy)
365 .c_str());
366 Text(tr("Expected Hash: %s"),
367 project->rom_metadata.expected_hash.empty()
368 ? "(unset)"
369 : project->rom_metadata.expected_hash.c_str());
371 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
372 TextColored(gui::ConvertColorToImVec4(theme.warning),
373 tr("ROM hash mismatch detected"));
374 }
375 }
376
377 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize) ||
378 IsKeyPressed(ImGuiKey_Escape)) {
379 Hide("ROM Information");
380 }
381}
382
386
388 using namespace ImGui;
389 namespace fs = std::filesystem;
390
391 auto register_widget = [](const char* name, const char* type) {
393 std::string("SaveAs/") + type + ":" + name, type, GetItemID());
394 };
395 auto* rom = editor_manager_ ? editor_manager_->GetCurrentRom() : nullptr;
396 if (!rom || !rom->is_loaded()) {
397 TextUnformatted(tr("No ROM loaded."));
398 if (Button(tr("Close"))) {
400 }
401 return;
402 }
403
404 const auto session_id = editor_manager_->GetCurrentSessionId();
406 save_as_.session_id != session_id) {
408 save_as_.initialized = true;
410 save_as_.session_id = session_id;
411 std::error_code ec;
412 auto source = fs::absolute(fs::path(rom->filename()), ec);
413 if (ec || rom->filename().empty()) {
415 tr("The current ROM has no usable folder. Choose Browse.");
416 } else {
417 save_as_.folder = source.parent_path().string();
418 }
419 auto extension = source.extension().string();
420 const auto lower_extension = absl::AsciiStrToLower(extension);
421 if (lower_extension != ".sfc" && lower_extension != ".smc") {
422 extension = ".sfc";
423 }
424 const auto stem =
425 source.stem().empty() ? std::string("rom") : source.stem().string();
426 save_as_.filename = stem + "-copy" + extension;
427 for (int copy = 2;
428 !save_as_.folder.empty() &&
429 fs::exists(fs::path(save_as_.folder) / save_as_.filename, ec);
430 ++copy) {
431 save_as_.filename = stem + "-copy-" + std::to_string(copy) + extension;
432 }
433 }
434
435 Text(tr("%s Save ROM to new location"), ICON_MD_SAVE_AS);
436 Separator();
437 TextUnformatted(tr("Folder:"));
438 PushTextWrapPos(GetCursorPosX() + 480.0f);
439 TextUnformatted(save_as_.folder.c_str());
440 PopTextWrapPos();
441 SetNextItemWidth(360.0f);
442 InputText(tr("Filename"), &save_as_.filename);
443 register_widget("Filename", "input");
444 if (!save_as_.error.empty()) {
445 TextWrapped("%s", save_as_.error.c_str());
446 }
447 Separator();
448
449 const bool browse = Button(
450 absl::StrFormat("%s Browse folder...", ICON_MD_FOLDER_OPEN).c_str(),
452 register_widget("Browse", "button");
453 if (browse) {
455 if (!selected.empty()) {
456 std::error_code ec;
457 const auto destination = fs::absolute(fs::path(selected), ec);
458 if (!ec) {
459 save_as_.folder = destination.string();
460 save_as_.error.clear();
461 }
462 }
463 }
464
465 SameLine();
466 const bool save = Button(absl::StrFormat("%s Save", ICON_MD_SAVE).c_str(),
468 register_widget("Save", "button");
469 if (save) {
470 fs::path filename(save_as_.filename);
471 if (filename.empty() || filename == "." || filename == ".." ||
472 filename.has_parent_path() || save_as_.folder.empty()) {
474 tr("Enter a filename only. Use Browse to choose a different folder.");
475 } else {
476 const auto extension =
477 absl::AsciiStrToLower(filename.extension().string());
478 if (extension != ".sfc" && extension != ".smc") {
479 filename += ".sfc";
480 }
481 // SaveRomAs owns the complete destination across any confirmation popup.
482 const auto destination = (fs::path(save_as_.folder) / filename).string();
483 const auto status = editor_manager_->SaveRomAs(destination);
484 if (status.ok()) {
486 return;
487 }
488 if (!absl::IsCancelled(status)) {
489 save_as_.error = std::string(status.message());
490 }
491 }
492 }
493
494 SameLine();
495 const bool cancel =
496 Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(),
498 register_widget("Cancel", "button");
499 if (cancel || IsKeyPressed(ImGuiKey_Escape)) {
501 }
502}
503
505 using namespace ImGui;
506
507 Text(tr("%s Save Scope"), ICON_MD_SAVE);
508 Separator();
509 TextWrapped(
510 tr("Controls which data is written during File > Save ROM. Dungeon "
511 "choices also control Apply Room. "
512 "Changes apply immediately."));
513 Separator();
514
515 if (CollapsingHeader(tr("Overworld"), ImGuiTreeNodeFlags_DefaultOpen)) {
516 Checkbox(tr("Save Overworld Maps"),
517 &core::FeatureFlags::get().overworld.kSaveOverworldMaps);
518 Checkbox(tr("Save Overworld Entrances"),
519 &core::FeatureFlags::get().overworld.kSaveOverworldEntrances);
520 Checkbox(tr("Save Overworld Exits"),
521 &core::FeatureFlags::get().overworld.kSaveOverworldExits);
522 Checkbox(tr("Save Overworld Items"),
523 &core::FeatureFlags::get().overworld.kSaveOverworldItems);
524 Checkbox(tr("Save Overworld Sprites"),
525 &core::FeatureFlags::get().overworld.kSaveOverworldSprites);
526 Checkbox(tr("Save Overworld Properties"),
527 &core::FeatureFlags::get().overworld.kSaveOverworldProperties);
528 }
529
530 if (CollapsingHeader(tr("Dungeon"), ImGuiTreeNodeFlags_DefaultOpen)) {
531 Checkbox(tr("Save Dungeon Maps"),
532 &core::FeatureFlags::get().kSaveDungeonMaps);
533 Checkbox(tr("Save Objects"),
534 &core::FeatureFlags::get().dungeon.kSaveObjects);
535 Checkbox(tr("Save Sprites"),
536 &core::FeatureFlags::get().dungeon.kSaveSprites);
537 Checkbox(tr("Save Room Headers"),
538 &core::FeatureFlags::get().dungeon.kSaveRoomHeaders);
539 Checkbox(tr("Save Torches"),
540 &core::FeatureFlags::get().dungeon.kSaveTorches);
541 Checkbox(tr("Save Pits"), &core::FeatureFlags::get().dungeon.kSavePits);
542 Checkbox(tr("Save Blocks"), &core::FeatureFlags::get().dungeon.kSaveBlocks);
543 Checkbox(tr("Save Collision"),
544 &core::FeatureFlags::get().dungeon.kSaveCollision);
545 Checkbox(tr("Save Chests"), &core::FeatureFlags::get().dungeon.kSaveChests);
546 Checkbox(tr("Save Pot Items"),
547 &core::FeatureFlags::get().dungeon.kSavePotItems);
548 if (IsItemHovered()) {
549 SetTooltip(
550 tr("Enable to save pending pot item edits, then retry Save "
551 "or Apply Room. No project reopen is needed."));
552 }
553 Checkbox(tr("Save Entrances"),
554 &core::FeatureFlags::get().dungeon.kSaveEntrances);
555 Checkbox(tr("Save Palettes"),
556 &core::FeatureFlags::get().dungeon.kSavePalettes);
557 }
558
559 if (CollapsingHeader(tr("Graphics"), ImGuiTreeNodeFlags_DefaultOpen)) {
560 Checkbox(tr("Save Graphics Sheets"),
561 &core::FeatureFlags::get().kSaveGraphicsSheet);
562 Checkbox(tr("Save All Palettes"),
563 &core::FeatureFlags::get().kSaveAllPalettes);
564 Checkbox(tr("Save Gfx Groups"), &core::FeatureFlags::get().kSaveGfxGroups);
565 }
566
567 if (CollapsingHeader(tr("Messages"), ImGuiTreeNodeFlags_DefaultOpen)) {
568 Checkbox(tr("Save Message Text"), &core::FeatureFlags::get().kSaveMessages);
569 }
570
571 Separator();
572 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
574 }
575}
576
578 using namespace ImGui;
579
580 auto* rom = editor_manager_->GetCurrentRom();
581 if (!rom || !rom->is_loaded()) {
582 Text(tr("No ROM loaded."));
583 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
585 }
586 return;
587 }
588
589 const auto* project = editor_manager_->GetCurrentProject();
590 std::string backup_dir;
591 if (project && project->project_opened() &&
592 !project->rom_backup_folder.empty()) {
593 backup_dir = project->GetAbsolutePath(project->rom_backup_folder);
594 } else {
595 backup_dir = std::filesystem::path(rom->filename()).parent_path().string();
596 }
597
598 Text(tr("%s ROM Backups"), ICON_MD_BACKUP);
599 Separator();
600 TextWrapped(tr("Backup folder: %s"), backup_dir.c_str());
601
603 Separator();
604 TextWrapped(
605 tr("A restored backup is staged in this session. Save ROM to commit "
606 "it. Discard reloads the backing ROM and abandons staged ROM-buffer "
607 "edits; resolve pending graphics, dungeon, or palette edits "
608 "first."));
609 if (Button(ICON_MD_UNDO " Discard Restored Backup")) {
611 if (!status.ok()) {
612 if (auto* toast = editor_manager_->toast_manager()) {
613 toast->Show(absl::StrFormat("Discard failed: %s", status.message()),
615 }
616 } else if (auto* toast = editor_manager_->toast_manager()) {
617 toast->Show("Restored backup discarded; reloaded ROM from disk",
619 }
620 }
621 Separator();
622 }
623
624 if (Button(ICON_MD_DELETE_SWEEP " Prune Backups")) {
625 auto status = editor_manager_->PruneRomBackups();
626 if (!status.ok()) {
627 if (auto* toast = editor_manager_->toast_manager()) {
628 toast->Show(absl::StrFormat("Prune failed: %s", status.message()),
630 }
631 } else if (auto* toast = editor_manager_->toast_manager()) {
632 toast->Show("Backups pruned", ToastType::kSuccess);
633 }
634 }
635
636 Separator();
637 auto backups = editor_manager_->GetRomBackups();
638 if (backups.empty()) {
639 TextDisabled(tr("No backups found."));
640 } else if (BeginTable("RomBackupTable", 4,
641 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
642 ImGuiTableFlags_Resizable)) {
643 TableSetupColumn("Timestamp");
644 TableSetupColumn("Size");
645 TableSetupColumn("Filename");
646 TableSetupColumn("Actions");
647 TableHeadersRow();
648
649 auto format_size = [](uintmax_t bytes) {
650 if (bytes > (1024 * 1024)) {
651 return absl::StrFormat("%.2f MB",
652 static_cast<double>(bytes) / (1024 * 1024));
653 }
654 if (bytes > 1024) {
655 return absl::StrFormat("%.1f KB", static_cast<double>(bytes) / 1024.0);
656 }
657 return absl::StrFormat("%llu B", static_cast<unsigned long long>(bytes));
658 };
659
660 for (size_t i = 0; i < backups.size(); ++i) {
661 const auto& backup = backups[i];
662 TableNextRow();
663 TableNextColumn();
664 char time_buffer[32] = "unknown";
665 if (backup.timestamp != 0) {
666 std::tm local_tm{};
667#ifdef _WIN32
668 localtime_s(&local_tm, &backup.timestamp);
669#else
670 localtime_r(&backup.timestamp, &local_tm);
671#endif
672 std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S",
673 &local_tm);
674 }
675 TextUnformatted(time_buffer);
676
677 TableNextColumn();
678 TextUnformatted(format_size(backup.size_bytes).c_str());
679
680 TableNextColumn();
681 TextUnformatted(backup.filename.c_str());
682
683 TableNextColumn();
684 PushID(static_cast<int>(i));
685 if (Button(ICON_MD_RESTORE " Restore")) {
686 auto status = editor_manager_->RestoreRomBackup(backup.path);
687 if (!status.ok()) {
688 if (auto* toast = editor_manager_->toast_manager()) {
689 toast->Show(absl::StrFormat("Restore failed: %s", status.message()),
691 }
692 } else if (auto* toast = editor_manager_->toast_manager()) {
693 toast->Show("Backup loaded; inspect it, then save ROM to commit",
695 }
696 }
697 SameLine();
698 if (Button(ICON_MD_OPEN_IN_NEW " Open")) {
699 auto status = editor_manager_->OpenRomOrProject(backup.path);
700 if (!status.ok()) {
701 if (auto* toast = editor_manager_->toast_manager()) {
702 toast->Show(absl::StrFormat("Open failed: %s", status.message()),
704 }
705 }
706 }
707 SameLine();
708 if (Button(ICON_MD_CONTENT_COPY " Copy")) {
709 SetClipboardText(backup.path.c_str());
710 }
711 PopID();
712 }
713 EndTable();
714 }
715
716 Separator();
717 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
719 }
720}
721
723 using namespace ImGui;
724
725 static std::string project_name = "";
726 static std::string project_filepath = "";
727 static std::string rom_filename = "";
728 static std::string labels_filename = "";
729 static std::string code_folder = "";
730
731 InputText(tr("Project Name"), &project_name);
732
733 if (Button(absl::StrFormat("%s Destination Folder", ICON_MD_FOLDER).c_str(),
736 }
737 SameLine();
738 Text("%s", project_filepath.empty() ? "(Not set)" : project_filepath.c_str());
739
740 if (Button(absl::StrFormat("%s ROM File", ICON_MD_VIDEOGAME_ASSET).c_str(),
744 }
745 SameLine();
746 Text("%s", rom_filename.empty() ? "(Not set)" : rom_filename.c_str());
747
748 if (Button(absl::StrFormat("%s Labels File", ICON_MD_LABEL).c_str(),
751 }
752 SameLine();
753 Text("%s", labels_filename.empty() ? "(Not set)" : labels_filename.c_str());
754
755 if (Button(absl::StrFormat("%s Code Folder", ICON_MD_CODE).c_str(),
758 }
759 SameLine();
760 Text("%s", code_folder.empty() ? "(Not set)" : code_folder.c_str());
761
762 Separator();
763
764 if (Button(absl::StrFormat("%s Choose Project File Location", ICON_MD_SAVE)
765 .c_str(),
767 auto project_file_path =
769 if (!project_file_path.empty()) {
770 if (!(absl::EndsWith(project_file_path, ".yaze") ||
771 absl::EndsWith(project_file_path, ".yazeproj"))) {
772 project_file_path += ".yaze";
773 }
774 project_filepath = project_file_path;
775 }
776 }
777
778 if (Button(absl::StrFormat("%s Create Project", ICON_MD_ADD).c_str(),
780 if (!project_filepath.empty() && !project_name.empty() &&
781 !rom_filename.empty()) {
783 "Basic ROM Hack", rom_filename, project_name, project_filepath);
784 if (status.ok()) {
785 auto* project = editor_manager_->GetCurrentProject();
786 if (project) {
787 if (!labels_filename.empty()) {
788 project->labels_filename = labels_filename;
789 }
790 if (!code_folder.empty()) {
791 project->code_folder = code_folder;
792 }
793 if (!labels_filename.empty() || !code_folder.empty()) {
795 status = editor_manager_->SaveProject();
796 }
797 }
798 }
799 if (status.ok()) {
800 // Clear fields
801 project_name = "";
802 project_filepath = "";
803 rom_filename = "";
804 labels_filename = "";
805 code_folder = "";
807 } else {
808 SetStatus(status);
809 }
810 }
811 }
812 SameLine();
813 if (Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(),
815 // Clear fields
816 project_name = "";
817 project_filepath = "";
818 rom_filename = "";
819 labels_filename = "";
820 code_folder = "";
822 }
823}
824
826 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
827 const ImVec4 status_ok = gui::ConvertColorToImVec4(theme.success);
828 const ImVec4 status_warn = gui::ConvertColorToImVec4(theme.warning);
829 const ImVec4 status_info = gui::ConvertColorToImVec4(theme.info);
830 const ImVec4 status_error = gui::ConvertColorToImVec4(theme.error);
831
832 auto status_color = [&](const char* status) -> ImVec4 {
833 if (strcmp(status, "Stable") == 0 || strcmp(status, "Working") == 0) {
834 return status_ok;
835 }
836 if (strcmp(status, "Beta") == 0 || strcmp(status, "Experimental") == 0) {
837 return status_warn;
838 }
839 if (strcmp(status, "Preview") == 0) {
840 return status_info;
841 }
842 if (strcmp(status, "Not available") == 0) {
843 return status_error;
844 }
845 return status_info;
846 };
847
848 struct FeatureRow {
849 const char* feature;
850 const char* status;
851 const char* persistence;
852 const char* notes;
853 };
854
855 auto draw_table = [&](const char* table_id,
856 std::initializer_list<FeatureRow> rows) {
857 ImGuiTableFlags flags = ImGuiTableFlags_BordersInnerH |
858 ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
859 if (!BeginTable(table_id, 4, flags)) {
860 return;
861 }
862 TableSetupColumn("Feature", ImGuiTableColumnFlags_WidthStretch);
863 TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 120.0f);
864 TableSetupColumn("Save/Load", ImGuiTableColumnFlags_WidthFixed, 180.0f);
865 TableSetupColumn("Notes", ImGuiTableColumnFlags_WidthStretch);
866 TableHeadersRow();
867
868 for (const auto& row : rows) {
869 TableNextRow();
870 TableSetColumnIndex(0);
871 TextUnformatted(row.feature);
872 TableSetColumnIndex(1);
873 TextColored(status_color(row.status), "%s", row.status);
874 TableSetColumnIndex(2);
875 TextUnformatted(row.persistence);
876 TableSetColumnIndex(3);
877 TextWrapped("%s", row.notes);
878 }
879
880 EndTable();
881 };
882
883 TextDisabled(
884 tr("Status: Stable = production ready, Beta = usable with gaps, "
885 "Experimental = WIP, Preview = web parity in progress."));
886 TextDisabled(tr("See Settings > Feature Flags for ROM-specific toggles."));
887 Spacing();
888
889 if (CollapsingHeader(tr("Desktop App (yaze)"),
890 ImGuiTreeNodeFlags_DefaultOpen)) {
891 draw_table("desktop_features",
892 {
893 {"ROM load/save", "Stable", "ROM + backups",
894 "Backups on save when enabled."},
895 {"Overworld Editor", "Stable", "ROM",
896 "Maps/entrances/exits/items; version-gated."},
897 {"Dungeon Editor", "Stable", "ROM",
898 "Room objects/tiles/palettes persist."},
899 {"Palette Editor", "Stable", "ROM",
900 "Palette edits persist; JSON IO pending."},
901 {"Graphics Editor", "Beta", "ROM",
902 "Sheet edits persist; tooling still expanding."},
903 {"Sprite Editor", "Stable", "ROM", "Sprite edits persist."},
904 {"Message Editor", "Stable", "ROM", "Text edits persist."},
905 {"Screen Editor", "Experimental", "ROM (partial)",
906 "Save coverage incomplete."},
907 {"Hex Editor", "Beta", "ROM", "Search UX incomplete."},
908 {"Assembly/Asar", "Beta", "ROM + project",
909 "Patch apply + symbol export."},
910 {"Emulator", "Beta", "Runtime only",
911 "Save-state UI partially wired."},
912 {"Music Editor", "Experimental", "ROM (partial)",
913 "Serialization in progress."},
914 {"Agent UI", "Experimental", ".yaze/agent",
915 "Requires AI provider configuration."},
916 {"Settings/Layouts", "Beta", ".yaze config",
917 "Layout serialization improving."},
918 });
919 }
920
921 if (CollapsingHeader(tr("z3ed CLI"))) {
922 draw_table("cli_features",
923 {
924 {"ROM read/write/validate", "Stable", "ROM file",
925 "Direct command execution."},
926 {"Agent workflows", "Stable", ".yaze/proposals + sandboxes",
927 "Commit writes ROM; revert reloads."},
928 {"Snapshots/restore", "Stable", "Sandbox copies",
929 "Supports YAZE_SANDBOX_ROOT override."},
930 {"Doctor/test suites", "Stable", "Reports",
931 "Structured output for automation."},
932 {"TUI/REPL", "Stable", "Session history",
933 "Interactive command palette + logs."},
934 });
935 }
936
937 if (CollapsingHeader(tr("Web/WASM Preview"))) {
938 draw_table(
939 "web_features",
940 {
941 {"ROM load/save", "Preview", "IndexedDB + download",
942 "Drag/drop or picker; download for backups."},
943 {"Editors (OW/Dungeon/Palette/etc.)", "Preview",
944 "IndexedDB + download", "Parity work in progress."},
945 {"Hex Editor", "Working", "IndexedDB + download",
946 "Direct ROM editing available."},
947 {"Asar patching", "Preview", "ROM", "Basic patch apply support."},
948 {"Emulator", "Not available", "N/A", "Desktop only."},
949 {"Collaboration", "Experimental", "Server",
950 "Requires yaze-server."},
951 {"AI features", "Preview", "Server", "Requires AI-enabled server."},
952 });
953 }
954
955 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
957 }
958}
959
961 Text(tr("File -> Open"));
962 Text(tr("Select a ROM file to open"));
963 Text(tr("Supported ROMs (headered or unheadered):"));
964 Text(tr("The Legend of Zelda: A Link to the Past"));
965 Text(tr("US Version 1.0"));
966 Text(tr("JP Version 1.0"));
967 Spacing();
968 TextWrapped(
969 tr("ROM files are not bundled. Use a clean, legally obtained copy."));
970
971 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
972 Hide("Open a ROM");
973 }
974}
975
977 Text(tr("Project Menu"));
978 Text(tr("Create a new project or open an existing one."));
979 Text(tr("Save the project to save the current state of the project."));
980 TextWrapped(
981 tr("To save a project, you need to first open a ROM and initialize your "
982 "code path and labels file. Label resource manager can be found in "
983 "the View menu. Code path is set in the Code editor after opening a "
984 "folder."));
985
986 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
987 Hide("Manage Project");
988 }
989}
990
992 TextWrapped(tr("Welcome to YAZE v%s!"), YAZE_VERSION_STRING);
993 TextWrapped(tr(
994 "YAZE lets you modify 'The Legend of Zelda: A Link to the Past' (US or "
995 "JP) ROMs with modern tooling."));
996 Spacing();
997 TextWrapped(tr("Release Highlights:"));
998 BulletText(
999 tr("AI-assisted workflows via z3ed agent and in-app panels "
1000 "(Ollama/Gemini/OpenAI/Anthropic)"));
1001 BulletText(tr("Clear feature status panels and improved help/tooltips"));
1002 BulletText(tr("Unified .yaze storage across desktop/CLI/web"));
1003 Spacing();
1004 TextWrapped(tr("General Tips:"));
1005 BulletText(tr("Open a clean ROM and save a backup before editing"));
1006 BulletText(tr("Use Help (F1) for context-aware guidance and shortcuts"));
1007 BulletText(tr("Coming from ZScream? Open Help → Coming from ZScream"));
1008 BulletText(tr(
1009 "Configure AI providers (Ollama/Gemini/OpenAI/Anthropic) in Settings > "
1010 "Agent"));
1011
1012 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1013 Hide("Getting Started");
1014 }
1015}
1016
1018 TextWrapped(tr("Asar 65816 Assembly Integration"));
1019 TextWrapped(
1020 tr("YAZE includes full Asar assembler support for ROM patching."));
1021 Spacing();
1022 TextWrapped(tr("Features:"));
1023 BulletText(tr("Cross-platform ROM patching with assembly code"));
1024 BulletText(tr("Symbol export with addresses and opcodes"));
1025 BulletText(tr("Assembly validation with detailed error reporting"));
1026 BulletText(tr("Memory-safe patch application with size checks"));
1027
1028 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1029 Hide("Asar Integration");
1030 }
1031}
1032
1034 TextWrapped(tr("Build Instructions"));
1035 TextWrapped(tr("YAZE uses modern CMake for cross-platform builds."));
1036 Spacing();
1037 TextWrapped(tr("Quick Start (examples):"));
1038 BulletText(tr("cmake --preset mac-dbg | lin-dbg | win-dbg"));
1039 BulletText(tr("cmake --build --preset <preset> --target yaze"));
1040 Spacing();
1041 TextWrapped(tr("AI Builds:"));
1042 BulletText(tr("cmake --preset mac-ai | lin-ai | win-ai"));
1043 BulletText(tr("cmake --build --preset <preset> --target yaze z3ed"));
1044 Spacing();
1045 TextWrapped(tr("Docs: docs/public/build/quick-reference.md"));
1046
1047 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1048 Hide("Build Instructions");
1049 }
1050}
1051
1053 TextWrapped(tr("Command Line Interface (z3ed)"));
1054 TextWrapped(tr("Scriptable ROM editing and AI agent workflows."));
1055 Spacing();
1056 TextWrapped(tr("Commands:"));
1057 BulletText(tr("z3ed rom-info --rom=zelda3.sfc"));
1058 BulletText(tr("z3ed agent simple-chat --rom=zelda3.sfc --ai_provider=auto"));
1059 BulletText(tr("z3ed agent plan --rom=zelda3.sfc"));
1060 BulletText(tr("z3ed test-list --format json"));
1061 BulletText(tr("z3ed patch apply-asar patch.asm --rom=zelda3.sfc"));
1062 BulletText(tr("z3ed help dungeon-place-sprite"));
1063 Spacing();
1064 TextWrapped(tr("Storage:"));
1065 BulletText(
1066 tr("Agent plans/proposals live under ~/.yaze (see docs for details)"));
1067
1068 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1069 Hide("CLI Usage");
1070 }
1071}
1072
1074 TextWrapped(tr("Troubleshooting"));
1075 TextWrapped(tr("Common issues and solutions:"));
1076 Spacing();
1077 BulletText(tr("ROM won't load: Check file format (SFC/SMC supported)"));
1078 BulletText(
1079 tr("AI agent missing: Start Ollama or set GEMINI_API_KEY/OPENAI_API_KEY/"
1080 "ANTHROPIC_API_KEY (web uses AI_AGENT_ENDPOINT)"));
1081 BulletText(tr("Graphics issues: Disable experimental flags in Settings"));
1082 BulletText(
1083 tr("Performance: Enable hardware acceleration in display settings"));
1084 BulletText(tr("Crashes: Check ROM file integrity and available memory"));
1085 BulletText(tr("Layout issues: Reset workspace layouts from View > Layouts"));
1086
1087 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1088 Hide("Troubleshooting");
1089 }
1090}
1091
1093 TextWrapped(tr("Contributing to YAZE"));
1094 TextWrapped(tr("YAZE is open source and welcomes contributions!"));
1095 Spacing();
1096 TextWrapped(tr("How to contribute:"));
1097 BulletText(tr("Fork the repository on GitHub"));
1098 BulletText(tr("Create feature branches for new work"));
1099 BulletText(tr("Follow C++ coding standards"));
1100 BulletText(tr("Include tests for new features"));
1101 BulletText(tr("Submit pull requests for review"));
1102
1103 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1104 Hide("Contributing");
1105 }
1106}
1107
1109 TextWrapped(tr("What's New in YAZE v%s"), YAZE_VERSION_STRING);
1110 Spacing();
1111
1112 if (CollapsingHeader(
1113 absl::StrFormat("%s User Interface & Theming", ICON_MD_PALETTE)
1114 .c_str(),
1115 ImGuiTreeNodeFlags_DefaultOpen)) {
1116 BulletText(
1117 tr("Feature status/persistence summaries across desktop/CLI/web"));
1118 BulletText(tr("Shortcut/help panels now match configured keybindings"));
1119 BulletText(tr("Refined onboarding tips and error messaging"));
1120 BulletText(tr("Help text refreshed across desktop, CLI, and web"));
1121 }
1122
1123 if (CollapsingHeader(
1124 absl::StrFormat("%s Development & Build System", ICON_MD_BUILD)
1125 .c_str(),
1126 ImGuiTreeNodeFlags_DefaultOpen)) {
1127 BulletText(tr("Asar 65816 assembler integration for ROM patching"));
1128 BulletText(tr("z3ed CLI + TUI for scripting, test/doctor, and automation"));
1129 BulletText(tr("Modern CMake presets for desktop, AI, and web builds"));
1130 BulletText(tr("Unified version + storage references for 0.5.1"));
1131 }
1132
1133 if (CollapsingHeader(
1134 absl::StrFormat("%s Core Improvements", ICON_MD_SETTINGS).c_str())) {
1135 BulletText(tr("Improved project metadata + .yaze storage alignment"));
1136 BulletText(tr("Stronger error reporting and status feedback"));
1137 BulletText(tr("Performance and stability improvements across editors"));
1138 BulletText(tr("Expanded logging and diagnostics tooling"));
1139 }
1140
1141 if (CollapsingHeader(
1142 absl::StrFormat("%s Editor Features", ICON_MD_EDIT).c_str())) {
1143 BulletText(tr("Music editor updates with SPC parsing/playback"));
1144 BulletText(
1145 tr("AI agent-assisted editing workflows (multi-provider + vision)"));
1146 BulletText(tr("Expanded overworld/dungeon tooling and palette accuracy"));
1147 BulletText(tr("Web/WASM preview with collaboration hooks"));
1148 }
1149
1150 Spacing();
1151 if (Button(
1152 absl::StrFormat("%s View Release Notes", ICON_MD_DESCRIPTION).c_str(),
1153 ImVec2(-1, 30))) {
1154 // Close this popup and show theme settings
1156 // Could trigger release notes panel opening here
1157 }
1158
1159 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1161 }
1162}
1163
1165 TextWrapped(tr("Coming from ZScream?"));
1166 TextWrapped(tr(
1167 "yaze covers the same Zelda 3 editing surfaces with a modern workspace, "
1168 "projects, and CLI. Use this map to find familiar tools."));
1169 Spacing();
1170
1171 if (CollapsingHeader(absl::StrFormat("%s Editors", ICON_MD_APPS).c_str(),
1172 ImGuiTreeNodeFlags_DefaultOpen)) {
1173 BulletText(tr("Overworld Editor ≈ ZScream overworld map canvas + tile16"));
1174 BulletText(
1175 tr("Dungeon Editor ≈ underworld rooms (objects, sprites, properties)"));
1176 BulletText(tr("Graphics / Sprite Editors ≈ GFX + sprite drawing"));
1177 BulletText(tr("Palette Editor ≈ palette groups and edits"));
1178 BulletText(tr("Message Editor ≈ dialogue / text"));
1179 BulletText(
1180 tr("Screen Editor → Overworld Map ≈ pause-menu map art "
1181 "(not the playable overworld)"));
1182 }
1183
1184 if (CollapsingHeader(
1185 absl::StrFormat("%s Layout & navigation", ICON_MD_DASHBOARD).c_str(),
1186 ImGuiTreeNodeFlags_DefaultOpen)) {
1187 BulletText(
1188 tr("Left activity bar opens editor categories (like ZScream "
1189 "tool tabs)"));
1190 BulletText(
1191 tr("Dungeon workbench defaults to ZScream-style: selectors "
1192 "left, inspector right"));
1193 BulletText(tr("Ctrl+Shift+P opens the command palette for any action"));
1194 BulletText(
1195 tr("F1 / Help drawer shows context shortcuts for the active "
1196 "editor"));
1197 }
1198
1199 if (CollapsingHeader(
1200 absl::StrFormat("%s Projects & ROM files", ICON_MD_FOLDER).c_str(),
1201 ImGuiTreeNodeFlags_DefaultOpen)) {
1202 BulletText(
1203 tr(".yaze / .yazeproj track ROM path, flags, and workspace "
1204 "settings"));
1205 BulletText(
1206 tr(".zsproj can be opened when present — same Open ROM / "
1207 "Project flow"));
1208 BulletText(
1209 tr("Always keep a clean backup; Backup Before Save is on by "
1210 "default"));
1211 BulletText(
1212 tr("ZSO / ZSCustomOverworld versions are detected from the ROM "
1213 "(vanilla, v1, v2, v3)"));
1214 }
1215
1216 if (CollapsingHeader(
1217 absl::StrFormat("%s Overworld specifics", ICON_MD_LANDSCAPE).c_str(),
1218 ImGuiTreeNodeFlags_DefaultOpen)) {
1219 BulletText(tr("Tile16 selector / workbench ≈ ZScream tile picker + paint"));
1220 BulletText(
1221 tr("Map Properties gates ZSO fields (area size, BG colors, "
1222 "animated GFX) by detected version"));
1223 BulletText(tr("Screen Editor → Overworld Map is pause-menu art only"));
1224 }
1225
1226 if (CollapsingHeader(absl::StrFormat("%s Saving", ICON_MD_SAVE).c_str())) {
1227 BulletText(tr("File → Save Scope chooses ROM, project, or both"));
1228 BulletText(tr("Autosave can be tuned under Settings → Editor Behavior"));
1229 BulletText(tr("ROM Backups lists timestamped copies for restore"));
1230 }
1231
1232 Spacing();
1233 TextWrapped(tr(
1234 "Tip: first-run toasts point at this guide once per tip. Reset tips in "
1235 "Settings → Editor Behavior if you want them again."));
1236
1237 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1239 }
1240}
1241
1243 TextWrapped(tr("Workspace Management"));
1244 TextWrapped(tr(
1245 "YAZE supports multiple ROM sessions and flexible workspace layouts."));
1246 Spacing();
1247
1248 TextWrapped(tr("Session Management:"));
1249 BulletText(tr("Ctrl+Shift+N: Create new session"));
1250 BulletText(tr("Ctrl+Shift+W: Close current session"));
1251 BulletText(tr("Ctrl+Tab: Quick session switcher"));
1252 BulletText(tr("Each session maintains its own ROM and editor state"));
1253
1254 Spacing();
1255 TextWrapped(tr("Layout Management:"));
1256 BulletText(tr("Drag window tabs to dock/undock"));
1257 BulletText(tr("Ctrl+Shift+S: Save current layout"));
1258 BulletText(tr("Ctrl+Shift+O: Load saved layout"));
1259 BulletText(tr("F11: Maximize current window"));
1260
1261 Spacing();
1262 TextWrapped(tr("Preset Layouts:"));
1263 BulletText(tr("Developer: Code, memory, testing tools"));
1264 BulletText(tr("Designer: Graphics, palettes, sprites"));
1265 BulletText(tr("Modder: All gameplay editing tools"));
1266
1267 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1268 Hide("Workspace Help");
1269 }
1270}
1271
1273 TextColored(gui::GetWarningColor(), tr("%s Warning"), ICON_MD_WARNING);
1274 TextWrapped(tr("You have reached the recommended session limit."));
1275 TextWrapped(tr("Having too many sessions open may impact performance."));
1276 Spacing();
1277 TextWrapped(tr("Consider closing unused sessions or saving your work."));
1278
1279 if (Button(tr("Understood"), ::yaze::gui::kDefaultModalSize)) {
1280 Hide("Session Limit Warning");
1281 }
1282 SameLine();
1283 if (Button(tr("Open Session Manager"), ::yaze::gui::kDefaultModalSize)) {
1284 Hide("Session Limit Warning");
1285 // This would trigger the session manager to open
1286 }
1287}
1288
1290 TextColored(gui::GetWarningColor(), tr("%s Confirm Reset"), ICON_MD_WARNING);
1291 TextWrapped(tr("This will reset your current workspace layout to default."));
1292 TextWrapped(tr("Any custom window arrangements will be lost."));
1293 Spacing();
1294 TextWrapped(tr("Do you want to continue?"));
1295
1296 if (Button(tr("Reset Layout"), ::yaze::gui::kDefaultModalSize)) {
1297 Hide("Layout Reset Confirm");
1298 // This would trigger the actual reset
1299 }
1300 SameLine();
1301 if (Button(tr("Cancel"), ::yaze::gui::kDefaultModalSize)) {
1302 Hide("Layout Reset Confirm");
1303 }
1304}
1305
1307 TextColored(gui::GetInfoColor(), tr("%s Layout Presets"), ICON_MD_DASHBOARD);
1308 Separator();
1309 Spacing();
1310
1311 TextWrapped(
1312 tr("Choose a workspace preset to quickly configure your layout:"));
1313 Spacing();
1314
1315 // Get named presets from LayoutPresets
1316 struct PresetInfo {
1317 const char* name;
1318 const char* icon;
1319 const char* description;
1320 std::function<PanelLayoutPreset()> getter;
1321 };
1322
1323 PresetInfo presets[] = {
1324 {"Minimal", ICON_MD_CROP_FREE,
1325 "Essential cards only - maximum editing space",
1326 []() { return LayoutPresets::GetMinimalPreset(); }},
1327 {"Developer", ICON_MD_BUG_REPORT,
1328 "Debug and development focused - CPU/Memory/Breakpoints",
1329 []() { return LayoutPresets::GetDeveloperPreset(); }},
1330 {"Designer", ICON_MD_PALETTE,
1331 "Visual and artistic focused - Graphics/Palettes/Sprites",
1332 []() { return LayoutPresets::GetDesignerPreset(); }},
1333 {"Modder", ICON_MD_BUILD,
1334 "Full-featured - All tools available for comprehensive editing",
1335 []() { return LayoutPresets::GetModderPreset(); }},
1336 {"Overworld Expert", ICON_MD_MAP,
1337 "Complete overworld editing toolkit with all map tools",
1338 []() { return LayoutPresets::GetOverworldArtistPreset(); }},
1339 {"Dungeon Expert", ICON_MD_DOOR_SLIDING,
1340 "Complete dungeon editing toolkit with room tools",
1341 []() { return LayoutPresets::GetDungeonMasterPreset(); }},
1342 {"Testing", ICON_MD_SCIENCE, "Quality assurance and ROM testing layout",
1343 []() { return LayoutPresets::GetLogicDebuggerPreset(); }},
1344 {"Audio", ICON_MD_MUSIC_NOTE, "Music and sound editing layout",
1345 []() { return LayoutPresets::GetAudioEngineerPreset(); }},
1346 };
1347
1348 constexpr int kPresetCount = 8;
1349
1350 // Draw preset buttons in a grid
1351 float button_width = 200.0f;
1352 float button_height = 50.0f;
1353
1354 for (int i = 0; i < kPresetCount; i++) {
1355 if (i % 2 != 0)
1356 SameLine();
1357
1358 {
1359 gui::StyleVarGuard align_guard(ImGuiStyleVar_ButtonTextAlign,
1360 ImVec2(0.0f, 0.5f));
1361 if (Button(absl::StrFormat("%s %s", presets[i].icon, presets[i].name)
1362 .c_str(),
1363 ImVec2(button_width, button_height))) {
1364 // Apply the preset
1365 auto preset = presets[i].getter();
1366 auto& window_manager = editor_manager_->window_manager();
1367 // Hide all panels first
1368 window_manager.HideAll();
1369 // Show preset panels
1370 for (const auto& panel_id : preset.default_visible_panels) {
1371 window_manager.OpenWindow(panel_id);
1372 }
1374 }
1375 }
1376
1377 if (IsItemHovered()) {
1378 BeginTooltip();
1379 TextUnformatted(presets[i].description);
1380 EndTooltip();
1381 }
1382 }
1383
1384 Spacing();
1385 Separator();
1386 Spacing();
1387
1388 // Reset current editor to defaults
1389 if (Button(
1390 absl::StrFormat("%s Reset Current Editor", ICON_MD_REFRESH).c_str(),
1391 ImVec2(-1, 0))) {
1392 auto& window_manager = editor_manager_->window_manager();
1393 auto* current_editor = editor_manager_->GetCurrentEditor();
1394 if (current_editor) {
1395 auto current_type = current_editor->type();
1396 window_manager.ResetToDefaults(0, current_type);
1397 }
1399 }
1400
1401 Spacing();
1402 if (Button(tr("Close"), ImVec2(-1, 0))) {
1404 }
1405}
1406
1408 TextColored(gui::GetInfoColor(), tr("%s Session Manager"), ICON_MD_TAB);
1409 Separator();
1410 Spacing();
1411
1412 size_t session_count = editor_manager_->GetActiveSessionCount();
1413 size_t active_session = editor_manager_->GetCurrentSessionIndex();
1414
1415 Text(tr("Active Sessions: %zu"), session_count);
1416 Spacing();
1417
1418 // Session table
1419 if (BeginTable("SessionTable", 4,
1420 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
1421 TableSetupColumn("#", ImGuiTableColumnFlags_WidthFixed, 30.0f);
1422 TableSetupColumn("ROM", ImGuiTableColumnFlags_WidthStretch);
1423 TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 80.0f);
1424 TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1425 TableHeadersRow();
1426
1427 for (size_t i = 0; i < session_count; i++) {
1428 TableNextRow();
1429
1430 // Session number
1431 TableSetColumnIndex(0);
1432 Text("%zu", i + 1);
1433
1434 // ROM name (simplified - show current ROM for active session)
1435 TableSetColumnIndex(1);
1436 if (i == active_session) {
1437 auto* rom = editor_manager_->GetCurrentRom();
1438 if (rom && rom->is_loaded()) {
1439 TextUnformatted(rom->filename().c_str());
1440 } else {
1441 TextDisabled(tr("(No ROM loaded)"));
1442 }
1443 } else {
1444 TextDisabled(tr("Session %zu"), i + 1);
1445 }
1446
1447 // Status indicator
1448 TableSetColumnIndex(2);
1449 if (i == active_session) {
1450 TextColored(gui::GetSuccessColor(), tr("%s Active"),
1452 } else {
1453 TextDisabled(tr("Inactive"));
1454 }
1455
1456 // Actions
1457 TableSetColumnIndex(3);
1458 PushID(static_cast<int>(i));
1459
1460 if (i != active_session) {
1461 if (SmallButton(tr("Switch"))) {
1463 }
1464 SameLine();
1465 }
1466
1467 BeginDisabled(session_count <= 1);
1468 if (SmallButton(tr("Close"))) {
1470 }
1471 EndDisabled();
1472
1473 PopID();
1474 }
1475
1476 EndTable();
1477 }
1478
1479 Spacing();
1480 Separator();
1481 Spacing();
1482
1483 // New session button
1484 if (Button(absl::StrFormat("%s New Session", ICON_MD_ADD).c_str(),
1485 ImVec2(-1, 0))) {
1487 }
1488
1489 Spacing();
1490 if (Button(tr("Close"), ImVec2(-1, 0))) {
1492 }
1493}
1494
1496 // Set a comfortable default size with natural constraints
1497 SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
1498 SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
1499
1500 Text(tr("%s Display & Theme Settings"), ICON_MD_DISPLAY_SETTINGS);
1501 TextWrapped(tr("Customize your YAZE experience - accessible anytime!"));
1502 Separator();
1503
1504 // Create a child window for scrollable content to avoid table conflicts
1505 // Use remaining space minus the close button area
1506 float available_height =
1507 GetContentRegionAvail().y - 60; // Reserve space for close button
1508 if (BeginChild("DisplaySettingsContent", ImVec2(0, available_height), true,
1509 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1510 // Use the popup-safe version to avoid table conflicts
1512
1513 Separator();
1514 gui::TextWithSeparators("Font Manager");
1516
1517 // Global font scale (moved from the old display settings window)
1518 ImGuiIO& io = GetIO();
1519 Separator();
1520 Text(tr("Global Font Scale"));
1521 float font_global_scale = io.FontGlobalScale;
1522 if (SliderFloat("##global_scale", &font_global_scale, 0.5f, 2.0f, "%.2f")) {
1523 if (editor_manager_) {
1524 editor_manager_->SetFontGlobalScale(font_global_scale);
1525 } else {
1526 io.FontGlobalScale = font_global_scale;
1527 }
1528 }
1529 }
1530 EndChild();
1531
1532 Separator();
1533 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1534 Hide("Display Settings");
1535 }
1536}
1537
1539 using namespace ImGui;
1540
1541 // Display feature flags editor using the existing FlagsMenu system
1542 Text(tr("Feature Flags Configuration"));
1543 Separator();
1544
1545 BeginChild("##FlagsContent", ImVec2(0, -30), true);
1546
1547 // Use the feature flags menu system
1548 static gui::FlagsMenu flags_menu;
1549
1550 if (BeginTabBar("FlagCategories")) {
1551 if (BeginTabItem(tr("Overworld"))) {
1552 flags_menu.DrawOverworldFlags();
1553 EndTabItem();
1554 }
1555 if (BeginTabItem(tr("Dungeon"))) {
1556 flags_menu.DrawDungeonFlags();
1557 EndTabItem();
1558 }
1559 if (BeginTabItem(tr("Resources"))) {
1560 flags_menu.DrawResourceFlags();
1561 EndTabItem();
1562 }
1563 if (BeginTabItem(tr("System"))) {
1564 flags_menu.DrawSystemFlags();
1565 EndTabItem();
1566 }
1567 EndTabBar();
1568 }
1569
1570 EndChild();
1571
1572 Separator();
1573 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1575 }
1576}
1577
1579 using namespace ImGui;
1580
1581 Text(tr("Data Integrity Check Results"));
1582 Separator();
1583
1584 BeginChild("##IntegrityContent", ImVec2(0, -30), true);
1585
1586 // Placeholder for data integrity results
1587 // In a full implementation, this would show test results
1588 Text(tr("ROM Data Integrity:"));
1589 Separator();
1590 TextColored(gui::GetSuccessColor(), tr("✓ ROM header valid"));
1591 TextColored(gui::GetSuccessColor(), tr("✓ Checksum valid"));
1592 TextColored(gui::GetSuccessColor(), tr("✓ Graphics data intact"));
1593 TextColored(gui::GetSuccessColor(), tr("✓ Map data intact"));
1594
1595 Spacing();
1596 Text(tr("No issues detected."));
1597
1598 EndChild();
1599
1600 Separator();
1601 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1603 }
1604}
1605
1607 using namespace ImGui;
1608
1609 if (!editor_manager_) {
1610 Text(tr("Editor manager unavailable."));
1611 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1613 }
1614 return;
1615 }
1616
1617 const int unloaded = editor_manager_->pending_pot_item_unloaded_rooms();
1618 const int total = editor_manager_->pending_pot_item_total_rooms();
1619
1620 Text(tr("Pot Item Save Confirmation"));
1621 Separator();
1622 TextWrapped(tr("Dungeon pot item saving is enabled, but %d of %d rooms are "
1623 "not loaded."),
1624 unloaded, total);
1625 Spacing();
1626 TextWrapped(
1627 tr("Saving now can overwrite pot items in unloaded rooms. Choose how to "
1628 "proceed:"));
1629
1630 Spacing();
1631 if (Button(tr("Save without pot items"), ImVec2(0, 0))) {
1635 return;
1636 }
1637 SameLine();
1638 const bool save_anyway = Button(tr("Save anyway"), ImVec2(0, 0));
1639 if (ImGui::GetItemID() != 0) {
1641 "dungeon.pot_item_save_confirm/button:Save anyway", "button",
1642 ImGui::GetItemID(),
1643 "Continue the pending dungeon save with pot item writes enabled");
1644 }
1645 if (save_anyway) {
1649 return;
1650 }
1651 SameLine();
1652 if (Button(tr("Cancel"), ImVec2(0, 0))) {
1656 }
1657}
1658
1660 using namespace ImGui;
1661
1662 if (!editor_manager_) {
1663 Text(tr("Editor manager unavailable."));
1664 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1666 }
1667 return;
1668 }
1669
1671 auto policy = project::RomWritePolicyToString(
1673 const auto expected = editor_manager_->GetProjectExpectedRomHash();
1674 const auto actual = editor_manager_->GetCurrentRomHash();
1675 const auto* project = editor_manager_->GetCurrentProject();
1676 const auto actual_path = editor_manager_->GetCurrentRom()
1678 : std::string();
1679 const auto editable_path =
1680 project && project->hack_manifest.loaded() &&
1681 !project->hack_manifest.build_pipeline().dev_rom.empty()
1682 ? project->GetAbsolutePath(
1683 project->hack_manifest.build_pipeline().dev_rom)
1684 : (project ? project->rom_filename : std::string());
1685
1686 Text(tr("ROM Write Confirmation"));
1687 Separator();
1688 TextWrapped(
1689 tr("The loaded ROM hash does not match the project's expected hash."));
1690 Spacing();
1691 Text(tr("Role: %s"), role.c_str());
1692 Text(tr("Write policy: %s"), policy.c_str());
1693 Text(tr("Loaded ROM: %s"),
1694 actual_path.empty() ? "(unknown)" : actual_path.c_str());
1695 Text(tr("Editable target: %s"),
1696 editable_path.empty() ? "(unset)" : editable_path.c_str());
1697 Text(tr("Expected: %s"), expected.empty() ? "(unset)" : expected.c_str());
1698 Text(tr("Actual: %s"), actual.empty() ? "(unknown)" : actual.c_str());
1699 Spacing();
1700 TextWrapped(tr(
1701 "Proceeding will write to the current ROM file. This may corrupt a base "
1702 "or release ROM if it is not the intended editable project ROM."));
1703
1704 Spacing();
1705 const bool save_anyway = Button(tr("Save anyway"), ImVec2(0, 0));
1707 "RomWriteConfirm/button:Save anyway", "button", GetItemID());
1708 if (save_anyway) {
1711 auto status = editor_manager_->ResumePendingRomSave();
1712 if (!status.ok() && !absl::IsCancelled(status)) {
1713 if (auto* toast = editor_manager_->toast_manager()) {
1714 toast->Show(absl::StrFormat("Save failed: %s", status.message()),
1716 }
1717 }
1718 return;
1719 }
1720 SameLine();
1721 if (Button(tr("Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1724 }
1725}
1726
1728 using namespace ImGui;
1729
1730 if (!editor_manager_) {
1731 Text(tr("Editor manager unavailable."));
1732 if (Button(tr("Close"), ::yaze::gui::kDefaultModalSize)) {
1734 }
1735 return;
1736 }
1737
1738 const auto& conflicts = editor_manager_->pending_write_conflicts();
1739
1740 TextColored(gui::GetWarningColor(), tr("%s Write Conflict Warning"),
1742 Separator();
1743 TextWrapped(
1744 tr("The following ROM addresses are owned by ASM hooks and will be "
1745 "overwritten on next build. Saving now will write data that asar "
1746 "will replace."));
1747 Spacing();
1748
1749 if (!conflicts.empty()) {
1750 if (BeginTable("WriteConflictTable", 3,
1751 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
1752 ImGuiTableFlags_Resizable)) {
1753 TableSetupColumn("Address", ImGuiTableColumnFlags_WidthFixed, 120.0f);
1754 TableSetupColumn("Ownership", ImGuiTableColumnFlags_WidthFixed, 140.0f);
1755 TableSetupColumn("Module", ImGuiTableColumnFlags_WidthStretch);
1756 TableHeadersRow();
1757
1758 for (const auto& conflict : conflicts) {
1759 TableNextRow();
1760 TableNextColumn();
1761 Text("$%06X", conflict.address);
1762 TableNextColumn();
1763 TextUnformatted(
1764 core::AddressOwnershipToString(conflict.ownership).c_str());
1765 TableNextColumn();
1766 if (!conflict.module.empty()) {
1767 TextUnformatted(conflict.module.c_str());
1768 } else {
1769 TextDisabled(tr("(unknown)"));
1770 }
1771 }
1772 EndTable();
1773 }
1774 }
1775
1776 Spacing();
1777 Text(tr("%zu conflict(s) detected."), conflicts.size());
1778 Spacing();
1779
1780 if (Button(tr("Save Anyway"), ImVec2(0, 0))) {
1783 auto status = editor_manager_->ResumePendingRomSave();
1784 if (!status.ok() && !absl::IsCancelled(status)) {
1785 if (auto* toast = editor_manager_->toast_manager()) {
1786 toast->Show(absl::StrFormat("Save failed: %s", status.message()),
1788 }
1789 }
1790 return;
1791 }
1792 SameLine();
1793 if (Button(tr("Cancel"), ImVec2(0, 0)) || IsKeyPressed(ImGuiKey_Escape)) {
1796 }
1797}
1798
1800 using namespace ImGui;
1801
1802 if (!editor_manager_) {
1804 return;
1805 }
1806
1809 return;
1810 }
1811
1812 Text(tr("%s Unsaved Session Changes"), ICON_MD_WARNING);
1813 Separator();
1814 TextWrapped("%s",
1816 Spacing();
1817
1818 // An empty save label means saving first is meaningless for this action
1819 // (for example Revert to Saved), so only Continue and Cancel are offered.
1820 const std::string save_label =
1822 if (!save_label.empty()) {
1823 if (Button(save_label.c_str(), ::yaze::gui::kDefaultModalSize)) {
1825 return;
1826 }
1827 SameLine();
1828 }
1829 const std::string continue_label =
1831 if (Button(continue_label.c_str(), ::yaze::gui::kDefaultModalSize)) {
1833 return;
1834 }
1835
1836 SameLine();
1837 if (Button(tr("Cancel"), ::yaze::gui::kDefaultModalSize) ||
1838 IsKeyPressed(ImGuiKey_Escape)) {
1840 }
1841}
1842
1843} // namespace editor
1844} // namespace yaze
auto filename() const
Definition rom.h:219
bool is_loaded() const
Definition rom.h:199
static Flags & get()
Definition features.h:122
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
absl::Status OpenRomOrProject(const std::string &filename, LoadOptionsPrompt prompt=LoadOptionsPrompt::kAsk)
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
void RemoveSession(size_t index)
std::string GetPendingUnsavedSessionActionSaveLabel() const
EditorType type() const
Definition editor.h:355
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:71
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:834
ImVec4 GetSuccessColor()
Definition ui_helpers.cc:49
ImVec4 GetWarningColor()
Definition ui_helpers.cc:54
void DrawDisplaySettingsForPopup(ImGuiStyle *ref)
Definition style.cc:356
constexpr ImVec2 kDefaultModalSize
Definition input.h:21
ImVec4 GetInfoColor()
Definition ui_helpers.cc:64
void TextWithSeparators(const absl::string_view &text)
Definition style.cc:828
std::string RomRoleToString(RomRole role)
Definition project.cc:461
std::string RomWritePolicyToString(RomWritePolicy policy)
Definition project.cc:489
std::string HexLongLong(uint64_t qword, HexStringParams params)
Definition hex.cc:66
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
Definition file_util.cc:127
const char * LayoutName(LayoutDialect dialect)
OverworldRomProfile DetectOverworldRomProfile(const Rom &rom)
Definition overworld.h:325
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:317
std::string GetAbsolutePath(const std::string &relative_path) const
Definition project.cc:2675
Public YAZE API umbrella header.