17#include <initializer_list>
22#include <unordered_set>
27#include <TargetConditionals.h>
31#define IMGUI_DEFINE_MATH_OPERATORS
32#include "absl/status/status.h"
33#include "absl/status/statusor.h"
34#include "absl/strings/ascii.h"
35#include "absl/strings/match.h"
36#include "absl/strings/str_format.h"
37#include "absl/strings/str_join.h"
38#include "absl/strings/str_split.h"
39#include "absl/strings/string_view.h"
40#include "imgui/imgui.h"
89#include "yaze_config.h"
111#ifdef YAZE_ENABLE_TESTING
118#ifdef YAZE_ENABLE_GTEST
126#ifdef YAZE_BUILD_AGENT_UI
140 std::initializer_list<const char*> keys) {
141 for (
const char* key : keys) {
156 std::vector<std::string> warnings;
161 const auto rom_size = rom.
size();
162 auto warn = [&](
const std::string& message) {
163 warnings.push_back(message);
166 auto check_range = [&](
const std::string& label, uint32_t addr,
size_t span) {
167 const size_t addr_size =
static_cast<size_t>(addr);
168 if (addr_size >= rom_size || addr_size + span > rom_size) {
169 warn(absl::StrFormat(
"ROM override '%s' out of range: 0x%X (size 0x%X)",
170 label, addr, rom_size));
174 for (
const auto& [key, value] : overrides.
addresses) {
175 check_range(key, value, 1);
182 constexpr uint32_t kExpandedMessageStartDefault = 0x178000;
183 constexpr uint32_t kExpandedMessageEndDefault = 0x17FFFF;
184 const uint32_t start =
186 .value_or(kExpandedMessageStartDefault);
189 .value_or(kExpandedMessageEndDefault);
190 if (start >= rom_size || end >= rom_size) {
191 warn(absl::StrFormat(
192 "Expanded message range out of ROM bounds: 0x%X-0x%X", start, end));
193 }
else if (end < start) {
194 warn(absl::StrFormat(
"Expanded message range invalid: 0x%X-0x%X", start,
202 if (*hook < rom_size) {
204 if (opcode.ok() && opcode.value() != 0x22) {
205 warn(absl::StrFormat(
206 "Expanded music hook at 0x%X is not a JSL opcode (0x%02X)", *hook,
226 const uint32_t marker =
229 const uint32_t magic =
232 check_range(
"overworld_ptr_marker", marker, 1);
233 if (marker < rom_size) {
234 if (rom.
data()[marker] !=
static_cast<uint8_t
>(magic)) {
235 warn(absl::StrFormat(
236 "Overworld expanded pointer marker mismatch at 0x%X: expected "
237 "0x%02X, found 0x%02X",
238 marker,
static_cast<uint8_t
>(magic), rom.
data()[marker]));
248 const uint32_t flag_addr =
252 check_range(
"overworld_entrance_flag_expanded", flag_addr, 1);
253 if (flag_addr < rom_size && rom.
data()[flag_addr] == 0xB8) {
255 absl::StrFormat(
"Overworld entrance flag at 0x%X is still 0xB8 "
256 "(vanilla); expanded entrance tables may be ignored",
265 const std::string lower = absl::AsciiStrToLower(std::string(name));
267 const std::string candidate = absl::AsciiStrToLower(
269 if (candidate == lower) {
277 if (panel_id.size() > 2 && panel_id[0] ==
's' &&
278 absl::ascii_isdigit(panel_id[1])) {
279 const size_t dot = panel_id.find(
'.');
280 if (dot != absl::string_view::npos) {
281 return std::string(panel_id.substr(dot + 1));
284 return std::string(panel_id);
288 namespace fs = std::filesystem;
290 std::vector<fs::path> roots;
291 if (
const char* home = std::getenv(
"HOME");
292 home !=
nullptr && std::strlen(home) > 0) {
293 roots.push_back(fs::path(home) /
"src" /
"hobby" /
"oracle-of-secrets");
296 std::vector<fs::path> candidates;
297 std::unordered_set<std::string> seen;
298 auto add_candidate = [&](
const fs::path& path) {
300 if (!fs::exists(path, ec) || ec) {
303 std::string ext = path.extension().string();
304 absl::AsciiStrToLower(&ext);
305 if (ext !=
".yaze" && ext !=
".yazeproj") {
308 const std::string normalized = fs::weakly_canonical(path, ec).string();
309 const std::string key = normalized.empty() ? path.string() : normalized;
310 if (key.empty() || seen.count(key) > 0) {
314 candidates.push_back(path);
317 for (
const auto& root : roots) {
319 if (!fs::exists(root, ec) || ec) {
324 add_candidate(root /
"Oracle-of-Secrets.yaze");
325 add_candidate(root /
"Oracle of Secrets.yaze");
326 add_candidate(root /
"Oracle-of-Secrets.yazeproj");
327 add_candidate(root /
"Oracle of Secrets.yazeproj");
328 add_candidate(root /
"Roms" /
"Oracle of Secrets.yaze");
331 fs::recursive_directory_iterator it(
332 root, fs::directory_options::skip_permission_denied, ec);
333 fs::recursive_directory_iterator end;
337 for (; it != end; it.increment(ec)) {
342 if (it.depth() > 2) {
343 it.disable_recursion_pending();
346 add_candidate(it->path());
350 if (candidates.empty()) {
356 for (
auto it = candidates.rbegin(); it != candidates.rend(); ++it) {
357 manager.AddFile(it->string());
391 current_type, &applied_profile)) {
401 std::max(default_width, 480.0f));
405 absl::StrFormat(
"Layout Profile: %s", applied_profile.
label),
424 clear_after_restore)) {
463#ifdef YAZE_BUILD_AGENT_UI
464void EditorManager::ShowAIAgent() {
471 for (
const auto& panel_id :
477void EditorManager::ShowChatHistory() {
483 : project_manager_(&toast_manager_), rom_file_manager_(&toast_manager_) {
484 std::stringstream ss;
485 ss << YAZE_VERSION_MAJOR <<
"." << YAZE_VERSION_MINOR <<
"."
486 << YAZE_VERSION_PATCH;
551 [
this](
const std::string& preset_name) {
555 [
this](
const std::string& preset_name) {
566 [
this](
const std::string& prompt) {
567#if defined(YAZE_BUILD_AGENT_UI)
577 chat->SendMessage(prompt);
583#if defined(YAZE_BUILD_AGENT_UI)
606 if (!rom_path.empty()) {
623 absl::StrFormat(
"Failed to reload ROM: %s", status.message()),
634 absl::StrFormat(
"Failed to save project: %s", status.message()),
639 [
this](
const std::string& type) {
641 if (!folder_path.empty()) {
642 if (type ==
"code") {
647#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
648 editor_set->OpenAssemblyFolder(folder_path);
652 }
else if (type ==
"assets") {
656 folder_path.c_str()),
702 return dungeon_editor->IsWorkbenchWorkflowEnabled();
707 [
this](
bool enabled) {
711 dungeon_editor->QueueWorkbenchWorkflowMode(enabled);
727 for (
auto& panel : registry_panels) {
736 dashboard_definition.
id =
"dashboard.main";
739 dashboard_definition.
category =
"Dashboard";
747 {.card_id =
"dashboard.main",
748 .display_name =
"Dashboard",
749 .window_title =
" Dashboard",
751 .category =
"Dashboard",
752 .shortcut_hint =
"F1",
788 std::vector<std::function<void()>> actions_to_execute;
790 const int processed_count =
static_cast<int>(actions_to_execute.size());
791 for (
auto& action : actions_to_execute) {
794 if (processed_count > 0) {
796 processed_count, std::memory_order_relaxed) -
814 if (e.category.empty() ||
842 for (
const auto& [type, labels] : src) {
843 auto& out = (*dst)[type];
844 for (
const auto& [key, value] : labels) {
850 merged_labels.clear();
851 std::vector<std::string> source_parts;
857 source_parts.push_back(
"rom");
867 source_parts.push_back(
"registry");
874 source_parts.push_back(
"project");
877 auto* label_source = merged_labels.empty() ? &empty_labels : &merged_labels;
879 source_parts.empty() ?
"empty" : absl::StrJoin(source_parts,
"+");
881 provider.SetProjectLabels(label_source);
887 const bool prefer_hmagic =
891 provider.SetPreferHMagicNames(prefer_hmagic);
894 "ResourceLabelProvider refreshed (source=%s, project_open=%s)",
927#ifdef YAZE_ENABLE_TESTING
931 LOG_DEBUG(
"EditorManager",
"Session switched to %zu via EventBus", new_index);
937 LOG_INFO(
"EditorManager",
"Session %zu created via EventBus", index);
951#ifdef YAZE_ENABLE_TESTING
956 LOG_INFO(
"EditorManager",
"Session %zu closed via EventBus", index);
975#ifdef YAZE_ENABLE_TESTING
981 LOG_INFO(
"EditorManager",
"ROM loaded in session %zu via EventBus", index);
987 case Action::kShowEmulator:
993 case Action::kShowSettings:
1003 case Action::kShowPanelBrowser:
1009 case Action::kShowSearch:
1015 case Action::kShowShortcuts:
1020 case Action::kShowCommandPalette:
1026 case Action::kShowHelp:
1036 case Action::kShowAgentChatSidebar:
1045 case Action::kShowAgentProposalsSidebar:
1052 case Action::kOpenRom: {
1056 std::string(
"Open failed: ") + std::string(status.message()),
1061 case Action::kSaveRom:
1066 }
else if (!absl::IsCancelled(status)) {
1068 std::string(
"Save failed: ") + std::string(status.message()),
1076 auto status = current_editor->
Undo();
1079 std::string(
"Undo failed: ") + std::string(status.message()),
1087 auto status = current_editor->
Redo();
1090 std::string(
"Redo failed: ") + std::string(status.message()),
1096 case Action::kResetLayout:
1105#ifdef YAZE_ENABLE_TESTING
1107 test_manager.RegisterTestSuite(
1108 std::make_unique<test::CoreSystemsTestSuite>());
1109 test_manager.RegisterTestSuite(std::make_unique<test::IntegratedTestSuite>());
1110 test_manager.RegisterTestSuite(
1111 std::make_unique<test::PerformanceTestSuite>());
1112 test_manager.RegisterTestSuite(std::make_unique<test::UITestSuite>());
1113 test_manager.RegisterTestSuite(
1114 std::make_unique<test::RomDependentTestSuite>());
1117 test_manager.RegisterTestSuite(std::make_unique<test::E2ETestSuite>());
1118 test_manager.RegisterTestSuite(
1119 std::make_unique<test::ZSCustomOverworldTestSuite>());
1123#ifdef YAZE_ENABLE_GTEST
1124 test_manager.RegisterTestSuite(std::make_unique<test::UnitTestSuite>());
1128#ifdef YAZE_WITH_GRPC
1133 test_manager.UpdateResourceStats();
1137 const std::string& filename) {
1140 SeedOracleProjectInRecents();
1149 if (!filename.empty()) {
1175 if (!category.empty()) {
1192#ifdef YAZE_ENABLE_TESTING
1203 const std::vector<PanelDefinition> panel_definitions = {
1204 {.id =
"emulator.cpu_debugger",
1205 .display_name =
"CPU Debugger",
1207 .category =
"Emulator",
1209 {.id =
"emulator.ppu_viewer",
1210 .display_name =
"PPU Viewer",
1212 .category =
"Emulator",
1214 {.id =
"emulator.memory_viewer",
1215 .display_name =
"Memory Viewer",
1217 .category =
"Emulator",
1219 {.id =
"emulator.breakpoints",
1220 .display_name =
"Breakpoints",
1222 .category =
"Emulator",
1224 {.id =
"emulator.performance",
1225 .display_name =
"Performance",
1227 .category =
"Emulator",
1229 {.id =
"emulator.ai_agent",
1230 .display_name =
"AI Agent",
1232 .category =
"Emulator",
1234 {.id =
"emulator.save_states",
1235 .display_name =
"Save States",
1237 .category =
"Emulator",
1239 {.id =
"emulator.keyboard_config",
1240 .display_name =
"Keyboard Config",
1242 .category =
"Emulator",
1244 {.id =
"emulator.virtual_controller",
1245 .display_name =
"Virtual Controller",
1247 .category =
"Emulator",
1249 {.id =
"emulator.apu_debugger",
1250 .display_name =
"APU Debugger",
1252 .category =
"Emulator",
1254 {.id =
"emulator.audio_mixer",
1255 .display_name =
"Audio Mixer",
1257 .category =
"Emulator",
1259 {.id =
"memory.hex_editor",
1260 .display_name =
"Hex Editor",
1262 .category =
"Memory",
1265 .legacy_ids = {
"Memory Editor"}},
1273 for (
const auto& definition : panel_definitions) {
1275 descriptor.
card_id = definition.id;
1278 descriptor.
icon = definition.icon;
1279 descriptor.
category = definition.category;
1281 descriptor.
priority = definition.priority;
1282 descriptor.
scope = definition.scope;
1286 descriptor.
on_show = definition.on_show;
1287 descriptor.
on_hide = definition.on_hide;
1289 for (
const auto& legacy_id : definition.legacy_ids) {
1294 if (definition.visible_by_default) {
1315 LOG_WARN(
"EditorManager",
"Failed to load user settings: %s",
1322 prefs.reduced_motion,
1355 if (ImGui::GetCurrentContext() !=
nullptr) {
1359 "ImGui context not available; skipping FontGlobalScale update");
1363#ifdef __EMSCRIPTEN__
1366 LOG_INFO(
"EditorManager",
"WASM Control and Session APIs initialized");
1383 flags.overworld.kSaveOverworldEntrances =
1411 LOG_INFO(
"EditorManager",
"ROM load options applied: preset=%s",
1429 [
this](
const std::string& template_name) {
1446#ifdef YAZE_BUILD_AGENT_UI
1458 absl::StrFormat(
"Failed to open project: %s",
status_.message()),
1485 [
this](
bool visible,
bool expanded) {
1497 [
this](
float width) {
1504 [
this](
const std::string& category) {
1513 if (it != prefs.panel_visibility_state.end()) {
1523 bool any_visible =
false;
1524 for (
const auto& desc :
1526 if (desc.visibility_flag && *desc.visibility_flag) {
1546 [
this](
const std::string& category) ->
Editor* {
1558 [
this](
const std::string& category) {
1563 if (category ==
"Agent") {
1564#ifdef YAZE_BUILD_AGENT_UI
1579 [
this](
const std::string& category,
const std::string& path) {
1580 if (category ==
"Assembly") {
1582 editor_set->ChangeActiveAssemblyFile(path);
1610 const std::string& editor_name,
const std::string& panels_str) {
1611 const bool has_editor = !editor_name.empty();
1612 const bool has_panels = !panels_str.empty();
1614 if (!has_editor && !has_panels) {
1619 "Processing startup flags: editor='%s', panels='%s'",
1620 editor_name.c_str(), panels_str.c_str());
1622 std::optional<EditorType> editor_type_to_open =
1623 has_editor ? ParseEditorTypeFromString(editor_name) : std::nullopt;
1624 if (has_editor && !editor_type_to_open.has_value()) {
1625 LOG_WARN(
"EditorManager",
"Unknown editor specified via flag: %s",
1626 editor_name.c_str());
1627 }
else if (editor_type_to_open.has_value()) {
1639 bool applied_category_from_panel =
false;
1641 for (absl::string_view token :
1642 absl::StrSplit(panels_str,
',', absl::SkipWhitespace())) {
1643 if (token.empty()) {
1646 std::string panel_name = std::string(absl::StripAsciiWhitespace(token));
1647 LOG_DEBUG(
"EditorManager",
"Attempting to open panel: '%s'",
1648 panel_name.c_str());
1650 const std::string lower_name = absl::AsciiStrToLower(panel_name);
1651 if (lower_name ==
"welcome" || lower_name ==
"welcome_screen") {
1657 if (lower_name ==
"dashboard" || lower_name ==
"dashboard.main" ||
1658 lower_name ==
"editor_selection") {
1671 if (absl::StartsWith(panel_name,
"Room ")) {
1674 int room_id = std::stoi(panel_name.substr(5));
1677 }
catch (
const std::exception& e) {
1678 LOG_WARN(
"EditorManager",
"Invalid room ID format: %s",
1679 panel_name.c_str());
1685 std::optional<std::string> resolved_panel;
1687 resolved_panel = panel_name;
1689 for (
const auto& [prefixed_id, descriptor] :
1691 const std::string base_id = StripSessionPrefix(prefixed_id);
1692 const std::string card_lower = absl::AsciiStrToLower(base_id);
1693 const std::string display_lower =
1694 absl::AsciiStrToLower(descriptor.display_name);
1696 if (card_lower == lower_name || display_lower == lower_name) {
1697 resolved_panel = base_id;
1703 if (!resolved_panel.has_value()) {
1705 "Unknown panel '%s' from --open_panels (known count: %zu)",
1712 const auto* descriptor =
1714 if (descriptor && !applied_category_from_panel &&
1717 applied_category_from_panel =
true;
1718 }
else if (!applied_category_from_panel && descriptor &&
1719 descriptor->category.empty() && !last_known_category.empty()) {
1723 LOG_WARN(
"EditorManager",
"Failed to show panel '%s'",
1724 resolved_panel->c_str());
1737 constexpr int kTargetRevision =
1748 "Applied panel layout defaults migration revision %d",
1753 const std::string& saved_category,
1754 const std::vector<std::string>& available_categories)
const {
1756 if (!saved_category.empty() && saved_category !=
"Emulator") {
1758 if (available_categories.empty()) {
1759 return saved_category;
1761 for (
const auto& cat : available_categories) {
1762 if (cat == saved_category)
1763 return saved_category;
1767 for (
const auto& cat : available_categories) {
1768 if (cat !=
"Emulator")
1785 const bool sidebar_visible =
1812 std::string panels_str;
1813 for (
size_t i = 0; i < config.
open_panels.size(); ++i) {
1857 if (index < session->editor_initialized.size()) {
1867 if (index < session->editor_assets_loaded.size()) {
1893 return editor_set ? editor_set->
GetEditor(type) :
nullptr;
1909#ifdef YAZE_BUILD_AGENT_UI
1926 }
else if (!category.empty() &&
1928 LOG_DEBUG(
"EditorManager",
"No editor context available for category '%s'",
1937 return absl::FailedPreconditionError(
"No editor set available");
1942 return absl::OkStatus();
1944 editor->Initialize();
1945 return absl::OkStatus();
1953 return absl::FailedPreconditionError(
"No active session");
1955 if (session->game_data_loaded) {
1956 return absl::OkStatus();
1958 if (!session->rom.is_loaded()) {
1959 return absl::FailedPreconditionError(
"ROM not loaded");
1965 auto* game_data = &session->game_data;
1966 auto* editor_set = &session->editors;
1971 if (
auto* editor = editor_set->GetEditor(type)) {
1972 editor->SetGameData(game_data);
1977 session->game_data_loaded =
true;
1979 return absl::OkStatus();
1984 return absl::OkStatus();
1988 return absl::OkStatus();
1994 if (!session || !session->rom.is_loaded()) {
1995 return absl::OkStatus();
1999 if (index >= session->editor_initialized.size()) {
2000 return absl::InvalidArgumentError(
"Invalid editor type");
2007 if (!session->editor_initialized[index]) {
2017 if (!session->editor_assets_loaded[index]) {
2025 return absl::OkStatus();
2072 bool is_emulator_visible =
2083 if (!save_status.ok()) {
2084 LOG_WARN(
"EditorManager",
"Failed to save user settings: %s",
2085 save_status.ToString().c_str());
2095 static Rom* last_test_rom =
nullptr;
2097 if (last_test_rom != current_rom) {
2100 "EditorManager::Update - ROM changed, updating TestManager: %p -> %p",
2101 (
void*)last_test_rom, (
void*)current_rom);
2103 last_test_rom = current_rom;
2108 current_rom->dirty()) {
2115 auto st = current_rom->SaveToFile(s);
2128 if (current_rom && current_rom->is_loaded()) {
2194 std::unordered_set<std::string> active_editor_categories;
2198 for (
size_t session_idx = 0;
2203 if (!session || !session->rom.is_loaded()) {
2207 for (
auto* editor : session->editors.active_editors_) {
2209 std::string category =
2211 active_editor_categories.insert(category);
2217 active_editor_categories.insert(
"Emulator");
2223 if (sidebar_category.empty() && !all_categories.empty()) {
2225 if (!sidebar_category.empty()) {
2237 auto has_rom_callback = [
this]() ->
bool {
2244 all_categories, active_editor_categories,
2262 bool has_agent_info =
false;
2263#if defined(YAZE_BUILD_AGENT_UI)
2265 auto* chat = agent_editor->GetAgentChat();
2269 bool active = chat && *chat->active();
2271 has_agent_info =
true;
2275 if (!has_agent_info) {
2305 if (ImGui::BeginMenuBar()) {
2310 {{ImGuiCol_Button, ImVec4(0, 0, 0, 0)},
2317 if (ImGui::SmallButton(icon)) {
2322 if (ImGui::IsItemHovered()) {
2324 ?
"Hide Activity Bar (Ctrl+B)"
2325 :
"Show Activity Bar (Ctrl+B)";
2326 ImGui::SetTooltip(
"%s", tooltip);
2339 ImGui::EndMenuBar();
2348 bool visible =
true;
2349 ImGui::ShowDemoWindow(&visible);
2355 bool visible =
true;
2356 ImGui::ShowMetricsWindow(&visible);
2364 bool* hex_visibility =
2366 if (hex_visibility) {
2370 editor->set_active(*hex_visibility);
2372 *hex_visibility = *editor->active();
2378 editor->set_active(
true);
2380 if (!*editor->active()) {
2399#ifdef YAZE_ENABLE_TESTING
2400 if (show_test_dashboard_) {
2417 bool visible =
true;
2471 auto load_from_path = [
this](
const std::string& file_name) -> absl::Status {
2472 if (file_name.empty()) {
2473 return absl::OkStatus();
2477 if (absl::EndsWith(file_name,
".yaze") ||
2478 absl::EndsWith(file_name,
".zsproj") ||
2479 absl::EndsWith(file_name,
".yazeproj")) {
2486 return absl::OkStatus();
2494 std::move(temp_rom), file_name);
2495 if (!session_or.ok()) {
2496 return session_or.status();
2511#ifdef YAZE_ENABLE_TESTING
2516 const auto& recent_files = manager.GetRecentFiles();
2517 const bool is_first_time_rom_path =
2518 std::find(recent_files.begin(), recent_files.end(), file_name) ==
2520 manager.AddFile(file_name);
2533 return absl::OkStatus();
2536#if defined(__APPLE__) && TARGET_OS_IOS == 1
2539 [
this, load_from_path](
const std::string& file_name) {
2540 auto status = load_from_path(file_name);
2543 absl::StrFormat(
"Failed to load ROM: %s", status.message()),
2547 return absl::OkStatus();
2551 return load_from_path(file_name);
2558 if (!current_rom || !current_editor_set) {
2559 return absl::FailedPreconditionError(
"No ROM or editor set loaded");
2563 if (!current_session) {
2564 return absl::FailedPreconditionError(
"No active ROM session");
2568 auto start_time = std::chrono::steady_clock::now();
2570#ifdef __EMSCRIPTEN__
2572 auto loading_handle =
2574 ?
static_cast<app::platform::WasmLoadingManager::LoadingHandle
>(
2576 : app::platform::WasmLoadingManager::BeginLoading(
2577 "Loading Editor Assets");
2580 constexpr float kStartProgress = 0.10f;
2581 constexpr float kEndProgress = 1.0f;
2582 constexpr int kTotalSteps = 11;
2583 int current_step = 0;
2584 auto update_progress = [&](
const std::string& message) {
2587 kStartProgress + (kEndProgress - kStartProgress) *
2588 (
static_cast<float>(current_step) / kTotalSteps);
2589 app::platform::WasmLoadingManager::UpdateProgress(loading_handle, progress);
2590 app::platform::WasmLoadingManager::UpdateMessage(loading_handle, message);
2593 auto cleanup_loading = [&]() {
2594 app::platform::WasmLoadingManager::EndLoading(loading_handle);
2596 struct LoadingGuard {
2597 std::function<void()> cleanup;
2598 bool dismissed =
false;
2603 void dismiss() { dismissed =
true; }
2604 } loading_guard{cleanup_loading};
2606 (void)passed_handle;
2620 const InitStep init_steps[] = {
2627 for (
const auto& step : init_steps) {
2628 if (
auto* editor = current_editor_set->GetEditor(step.type)) {
2629 editor->Initialize();
2631 if (step.mark_loaded) {
2637#ifdef __EMSCRIPTEN__
2638 update_progress(
"Loading graphics sheets...");
2643 current_session->game_data_loaded =
true;
2647 current_session->game_data.gfx_bitmaps;
2650 auto* game_data = ¤t_session->game_data;
2655 if (
auto* editor = current_editor_set->GetEditor(type)) {
2656 editor->SetGameData(game_data);
2662 const char* progress_message;
2664 const LoadStep load_steps[] = {
2674 for (
const auto& step : load_steps) {
2675#ifdef __EMSCRIPTEN__
2676 update_progress(step.progress_message);
2678 if (
auto* editor = current_editor_set->GetEditor(step.type)) {
2684#ifdef __EMSCRIPTEN__
2685 update_progress(
"Finishing up...");
2690 auto* settings = current_editor_set->GetSettingsPanel();
2699#ifdef __EMSCRIPTEN__
2701 loading_guard.dismiss();
2702 app::platform::WasmLoadingManager::EndLoading(loading_handle);
2705 auto end_time = std::chrono::steady_clock::now();
2706 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
2707 end_time - start_time);
2708 LOG_DEBUG(
"EditorManager",
"ROM assets loaded in %lld ms", duration.count());
2710 return absl::OkStatus();
2716 if (!current_rom || !current_editor_set) {
2717 return absl::FailedPreconditionError(
"No ROM or editor set loaded");
2721 if (!current_session) {
2722 return absl::FailedPreconditionError(
"No active ROM session");
2726#ifdef __EMSCRIPTEN__
2728 auto loading_handle =
2730 ?
static_cast<app::platform::WasmLoadingManager::LoadingHandle
>(
2732 : app::platform::WasmLoadingManager::BeginLoading(
2733 "Loading ROM (lazy assets)");
2734 auto cleanup_loading = [&]() {
2735 app::platform::WasmLoadingManager::EndLoading(loading_handle);
2737 struct LoadingGuard {
2738 std::function<void()> cleanup;
2739 bool dismissed =
false;
2745 void dismiss() { dismissed =
true; }
2746 } loading_guard{cleanup_loading};
2748 (void)passed_handle;
2758 auto* settings = current_editor_set->GetSettingsPanel();
2765#ifdef __EMSCRIPTEN__
2766 loading_guard.dismiss();
2767 app::platform::WasmLoadingManager::EndLoading(loading_handle);
2770 LOG_INFO(
"EditorManager",
"Lazy asset mode: editor assets deferred");
2771 return absl::OkStatus();
2800 if (!current_rom || !current_editor_set) {
2801 return absl::FailedPreconditionError(
"No ROM or editor set loaded");
2806 return absl::CancelledError(
"Save pending confirmation");
2812 return absl::CancelledError(
"Save pending confirmation");
2815 const bool pot_items_enabled =
2819 const int loaded_rooms = current_editor_set->LoadedDungeonRoomCount();
2820 const int total_rooms = current_editor_set->TotalDungeonRoomCount();
2821 if (loaded_rooms < total_rooms) {
2829 "Save paused: pot items enabled with %d unloaded rooms",
2832 return absl::CancelledError(
"Pot item save confirmation required");
2840 struct PotItemFlagGuard {
2841 bool restore =
false;
2842 bool previous =
false;
2843 ~PotItemFlagGuard() {
2845 core::FeatureFlags::get().dungeon.kSavePotItems = previous;
2850 if (suppress_pot_items) {
2852 pot_item_guard.restore =
true;
2854 }
else if (bypass_confirm) {
2903 std::vector<std::pair<uint32_t, uint32_t>> write_ranges;
2904 bool diff_computed =
false;
2906 if (!current_rom->filename().empty()) {
2907 std::ifstream file(current_rom->filename(), std::ios::binary);
2908 if (file.is_open()) {
2909 file.seekg(0, std::ios::end);
2910 const std::streampos end = file.tellg();
2912 std::vector<uint8_t> disk_data(
static_cast<size_t>(end));
2913 file.seekg(0, std::ios::beg);
2914 file.read(
reinterpret_cast<char*
>(disk_data.data()),
2915 static_cast<std::streamsize
>(disk_data.size()));
2917 diff_computed =
true;
2919 disk_data, current_rom->vector());
2920 if (!diff.ranges.empty()) {
2922 "ROM save diff: %zu bytes changed in %zu range(s)",
2923 diff.total_bytes_changed, diff.ranges.size());
2924 write_ranges = std::move(diff.ranges);
2931 if (write_ranges.empty() && !diff_computed) {
2932 write_ranges = current_editor_set->CollectDungeonWriteRanges();
2935 if (!write_ranges.empty()) {
2938 if (!conflicts.empty()) {
2945 "Save paused: %zu write conflict(s) with ASM hooks",
2948 return absl::CancelledError(
2949 "Write conflict confirmation required");
2960 if (save_status.ok()) {
2970 return absl::FailedPreconditionError(
"No ROM loaded");
2978 if (save_status.ok()) {
2983 session->filepath = filename;
2989 manager.AddFile(filename);
2997 LOG_INFO(
"EditorManager",
"OpenRomOrProject called with: '%s'",
2999 if (filename.empty()) {
3000 LOG_INFO(
"EditorManager",
"Empty filename provided, skipping load.");
3001 return absl::OkStatus();
3004#ifdef __EMSCRIPTEN__
3006 auto loading_handle =
3007 app::platform::WasmLoadingManager::BeginLoading(
"Loading ROM");
3008 app::platform::WasmLoadingManager::UpdateMessage(loading_handle,
3009 "Reading ROM file...");
3011 struct LoadingGuard {
3012 app::platform::WasmLoadingManager::LoadingHandle handle;
3013 bool dismissed =
false;
3016 app::platform::WasmLoadingManager::EndLoading(handle);
3018 void dismiss() { dismissed =
true; }
3019 } loading_guard{loading_handle};
3022 if (absl::EndsWith(filename,
".yaze") ||
3023 absl::EndsWith(filename,
".zsproj") ||
3024 absl::EndsWith(filename,
".yazeproj")) {
3037#ifdef __EMSCRIPTEN__
3038 app::platform::WasmLoadingManager::UpdateProgress(loading_handle, 0.05f);
3039 app::platform::WasmLoadingManager::UpdateMessage(loading_handle,
3040 "Loading ROM data...");
3046 std::move(temp_rom), filename);
3047 if (!session_or.ok()) {
3048 return session_or.status();
3066#ifdef YAZE_ENABLE_TESTING
3067 LOG_DEBUG(
"EditorManager",
"Setting ROM in TestManager - %p ('%s')",
3075 const std::string absolute_code_folder =
3080#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
3081 editor_set->OpenAssemblyFolder(absolute_code_folder);
3087#ifdef __EMSCRIPTEN__
3088 app::platform::WasmLoadingManager::UpdateProgress(loading_handle, 0.10f);
3089 app::platform::WasmLoadingManager::UpdateMessage(loading_handle,
3090 "Initializing editors...");
3093 loading_guard.dismiss();
3108 return absl::OkStatus();
3121#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
3132 auto open_project_from_path =
3133 [
this](
const std::string& file_path) -> absl::Status {
3134 if (file_path.empty()) {
3135 return absl::OkStatus();
3142 auto validation_status = new_project.
Validate();
3143 if (!validation_status.ok()) {
3145 validation_status.message()),
3163#if defined(__APPLE__) && TARGET_OS_IOS == 1
3167 return absl::OkStatus();
3170 return open_project_from_path(file_path);
3179 "Project has no ROM file configured. Please select a ROM.",
3181#if defined(__APPLE__) && TARGET_OS_IOS == 1
3184 [
this](
const std::string& rom_path) {
3185 if (rom_path.empty()) {
3190 if (!save_status.ok()) {
3192 absl::StrFormat(
"Failed to update project ROM: %s",
3193 save_status.message()),
3200 absl::StrFormat(
"Failed to load project ROM: %s",
3205 return absl::OkStatus();
3209 if (rom_path.empty()) {
3210 return absl::OkStatus();
3222 if (!load_status.ok()) {
3225 absl::StrFormat(
"Could not load ROM '%s': %s. Please select a new ROM.",
3228#if defined(__APPLE__) && TARGET_OS_IOS == 1
3231 [
this](
const std::string& rom_path) {
3232 if (rom_path.empty()) {
3237 if (!save_status.ok()) {
3239 absl::StrFormat(
"Failed to update project ROM: %s",
3240 save_status.message()),
3247 absl::StrFormat(
"Failed to load project ROM: %s",
3252 return absl::OkStatus();
3256 if (rom_path.empty()) {
3257 return absl::OkStatus();
3267 if (!session_or.ok()) {
3268 return session_or.status();
3282 "Project has custom object data but 'enable_custom_objects' was "
3283 "disabled. Enabling at runtime.");
3295 "Feature flags applied: kEnableCustomObjects=%s, "
3296 "custom_objects_folder='%s', custom_object_files=%zu entries",
3329 "Project ROM hash mismatch detected. Check ROM Identity settings.",
3332 auto warnings = ValidateRomAddressOverrides(
3334 if (!warnings.empty()) {
3335 for (
const auto& warning : warnings) {
3336 LOG_WARN(
"EditorManager",
"%s", warning.c_str());
3346#ifdef YAZE_ENABLE_TESTING
3347 LOG_DEBUG(
"EditorManager",
"Setting ROM in TestManager - %p ('%s')",
3355 const std::string absolute_code_folder =
3358#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
3359 editor_set->OpenAssemblyFolder(absolute_code_folder);
3411 return absl::OkStatus();
3440 for (
const auto& file : manager.GetRecentFiles()) {
3451 auto lifecycle_decision =
3453 static_cast<int>(decision));
3464 }
else if (!absl::IsCancelled(status)) {
3466 absl::StrFormat(
"Failed to save ROM: %s", status.message()),
3475 :
"untitled_project";
3479 if (file_path.empty()) {
3480 return absl::OkStatus();
3484 if (!(absl::EndsWith(file_path,
".yaze") ||
3485 absl::EndsWith(file_path,
".yazeproj"))) {
3486 file_path +=
".yaze";
3494 if (save_status.ok()) {
3499 manager.AddFile(file_path);
3508 absl::StrFormat(
"Failed to save project: %s", save_status.message()),
3521 return absl::OkStatus();
3526 return absl::FailedPreconditionError(
"No project is currently open");
3533 return absl::OkStatus();
3538 return editor_set->GetOverworldData();
3545 return absl::InvalidArgumentError(
"Invalid ROM pointer");
3554 if (session && &session->rom == rom) {
3560 return absl::OkStatus();
3566 return absl::NotFoundError(
"ROM not found in existing sessions");
3588 return absl::FailedPreconditionError(
"No ROM loaded");
3590 const std::string original_filename = rom->
filename();
3592 if (!original_filename.empty()) {
3654 int pending_editor =
3656 if (pending_editor < 0) {
3662 if (pending_layout < 0) {
3677 EditorType type,
size_t session_index)
const {
3678 const char* base_name =
kEditorNames[
static_cast<int>(type)];
3680 base_name, session_index)
3681 : std::string(base_name);
3687#ifdef YAZE_BUILD_AGENT_UI
3697 absl::StrFormat(
"Failed to prepare %s: %s",
3726 : manager_(manager),
3727 prev_rom_(manager->GetCurrentRom()),
3728 prev_editor_set_(manager->GetCurrentEditorSet()),
3729 prev_session_id_(manager->GetCurrentSessionId()) {
3736 manager_->session_coordinator_->SwitchToSession(prev_session_id_);
3786 absl::StrFormat(
"Failed to load project file: %s", status.message()),
3798 size_t session_id) {
void Publish(const T &event)
HandlerId Subscribe(std::function< void(const T &)> handler)
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
project::ResourceLabelManager * resource_label()
absl::StatusOr< uint8_t > ReadByte(int offset) const
auto set_filename(std::string_view name)
static TimingManager & Get()
float Update()
Update the timing manager (call once per frame)
float GetElapsedTime() const
Get total elapsed time since first update.
const ProjectRegistry & project_registry() const
bool HasProjectRegistry() const
std::vector< WriteConflict > AnalyzePcWriteRanges(const std::vector< std::pair< uint32_t, uint32_t > > &pc_ranges) const
Analyze a set of PC-offset ranges for write conflicts.
bool loaded() const
Check if the manifest has been loaded.
static RomSettings & Get()
void SetAddressOverrides(const RomAddressOverrides &overrides)
void set_active(bool active)
AgentChat * GetAgentChat()
AgentConfigState & agent_config()
void SetRomContext(Rom *rom)
AgentUIContext * GetContext()
void Initialize(ToastManager *toast_manager, ProposalDrawer *proposal_drawer, RightPanelManager *right_panel_manager, PanelManager *panel_manager, UserSettings *user_settings)
void SetProjectContext(project::YazeProject *project)
void ApplyUserSettingsDefaults(bool force=false)
AgentEditor * GetAgentEditor()
void SetAsarWrapperContext(core::AsarWrapper *asar_wrapper)
DungeonEditorV2 - Simplified dungeon editor using component delegation.
void SwitchToEditor(EditorType type, bool force_visible=false, bool from_dialog=false)
Switch to an editor, optionally forcing visibility.
void Initialize(const Dependencies &deps)
SessionScope(EditorManager *manager, size_t session_id)
The EditorManager controls the main editor window and manages the various editor classes.
absl::Status SaveProjectAs()
std::unique_ptr< SessionCoordinator > session_coordinator_
std::unique_ptr< PanelHost > panel_host_
RomLifecycleManager rom_lifecycle_
StartupVisibility welcome_mode_override_
void InitializeTestSuites()
void ApplyDefaultBackupPolicy()
void SwitchToEditor(EditorType editor_type, bool force_visible=false, bool from_dialog=false) override
std::unique_ptr< GlobalEditorContext > editor_context_
absl::Status SaveRomAs(const std::string &filename)
project::YazeProject current_project_
AgentUiController agent_ui_
void SetCurrentEditor(Editor *editor) override
absl::Status LoadProjectWithRom()
absl::Status LoadAssetsForMode(uint64_t loading_handle=0)
MenuBuilder menu_builder_
float settings_dirty_timestamp_
std::string GetPreferredStartupCategory(const std::string &saved_category, const std::vector< std::string > &available_categories) const
void InitializeServices()
void ApplyLayoutDefaultsMigrationIfNeeded()
void SwitchToSession(size_t index)
absl::Status RestoreRomBackup(const std::string &backup_path)
absl::Status EnsureGameDataLoaded()
size_t GetActiveSessionCount() const
absl::Status OpenProject()
ProjectManager project_manager_
void CloseCurrentSession()
gfx::IRenderer * renderer_
Rom * GetCurrentRom() const override
bool HasDuplicateSession(const std::string &filepath)
absl::Status RepairCurrentProject()
std::unique_ptr< LayoutManager > layout_manager_
std::unique_ptr< DashboardPanel > dashboard_panel_
void HandleSessionClosed(size_t index)
void ResetAssetState(RomSession *session)
void DrawSecondaryWindows()
void ProcessStartupActions(const AppConfig &config)
std::string GenerateUniqueEditorTitle(EditorType type, size_t session_index) const
std::vector< editor::RomFileManager::BackupEntry > GetRomBackups() const
absl::Status CheckRomWritePolicy()
Save the current ROM file.
SharedClipboard shared_clipboard_
bool EditorInitRequiresGameData(EditorType type) const
void SyncEditorContextForCategory(const std::string &category)
void ShowProjectManagement()
Injects dependencies into all editors within an EditorSet.
void SetupWelcomeScreenCallbacks()
Editor * ResolveEditorForCategory(const std::string &category)
void DuplicateCurrentSession()
void Initialize(gfx::IRenderer *renderer, const std::string &filename="")
EditorRegistry editor_registry_
void SetupDialogCallbacks()
void MarkEditorLoaded(RomSession *session, EditorType type)
void ApplyStartupVisibilityOverrides()
void ResetWorkspaceLayout()
absl::Status CreateNewProject(const std::string &template_name="Basic ROM Hack")
absl::Status InitializeEditorForType(EditorType type, EditorSet *editor_set, Rom *rom)
ToastManager toast_manager_
LayoutCoordinator layout_coordinator_
absl::Status LoadAssets(uint64_t loading_handle=0)
bool pending_layout_defaults_reset_
auto GetCurrentEditorSet() const -> EditorSet *
absl::Status PruneRomBackups()
std::unique_ptr< MenuOrchestrator > menu_orchestrator_
void HandleUIActionRequest(UIActionRequestEvent::Action action)
void ResolvePotItemSaveConfirmation(PotItemSaveDecision decision)
void HandleSessionRomLoaded(size_t index, Rom *rom)
ProjectFileEditor project_file_editor_
void HandleHostVisibilityChanged(bool visible)
void ApplyLayoutPreset(const std::string &preset_name)
void RestoreTemporaryLayoutSnapshot(bool clear_after_restore=false)
void ApplyStartupVisibility(const AppConfig &config)
auto GetCurrentEditor() const -> Editor *
bool show_rom_load_options_
absl::Status SaveProject()
std::unique_ptr< RightPanelManager > right_panel_manager_
absl::Status LoadAssetsLazy(uint64_t loading_handle=0)
void SetAssetLoadMode(AssetLoadMode mode)
void DismissEditorSelection() override
std::atomic< uint64_t > ui_sync_frame_id_
bool ApplyLayoutProfile(const std::string &profile_id)
std::unique_ptr< core::VersionManager > version_manager_
Editor * GetEditorByType(EditorType type, EditorSet *editor_set) const
void UpdateCurrentRomHash()
StartupVisibility sidebar_mode_override_
RomLoadOptionsDialog rom_load_options_dialog_
absl::Status LoadRom()
Load a ROM file into a new or existing session.
void SetupComponentCallbacks()
std::vector< std::function< void()> > deferred_actions_
void RegisterEmulatorPanels()
void OpenEditorAndPanelsFromFlags(const std::string &editor_name, const std::string &panels_str)
StartupVisibility dashboard_mode_override_
void InitializeSubsystems()
void ShowProjectFileEditor()
static bool IsPanelBasedEditor(EditorType type)
absl::Status Update()
Main update loop for the editor application.
void SetupSidebarCallbacks()
size_t GetCurrentSessionIndex() const
absl::Status ImportProject(const std::string &project_path)
size_t GetCurrentSessionId() const
void ClearTemporaryLayoutSnapshot()
void QueueDeferredAction(std::function< void()> action)
SelectionPropertiesPanel selection_properties_panel_
WindowDelegate window_delegate_
void ConfigureSession(RomSession *session) override
std::unique_ptr< ActivityBar > activity_bar_
ShortcutManager shortcut_manager_
bool IsRomHashMismatch() const
void RefreshResourceLabelProvider()
void MarkEditorInitialized(RomSession *session, EditorType type)
void SyncLayoutScopeFromCurrentProject()
UserSettings user_settings_
WorkspaceManager workspace_manager_
yaze::zelda3::Overworld * overworld() const
ProposalDrawer proposal_drawer_
void ConfigureEditorDependencies(EditorSet *editor_set, Rom *rom, size_t session_id)
WelcomeScreen welcome_screen_
std::unique_ptr< ProjectManagementPanel > project_management_panel_
absl::Status OpenRomOrProject(const std::string &filename)
void RemoveSession(size_t index)
absl::Status CheckOracleRomSafetyPreSave(Rom *rom)
UiSyncState GetUiSyncStateSnapshot() const
PanelManager panel_manager_
void HandleSessionSwitched(size_t new_index, RomSession *session)
AssetLoadMode asset_load_mode_
absl::Status EnsureEditorAssetsLoaded(EditorType type)
std::unique_ptr< PopupManager > popup_manager_
std::atomic< int > pending_editor_deferred_actions_
std::unique_ptr< UICoordinator > ui_coordinator_
EditorActivator editor_activator_
absl::Status SetCurrentRom(Rom *rom)
void InitializeShortcutSystem()
void CaptureTemporaryLayoutSnapshot()
void HandleSessionCreated(size_t index, RomSession *session)
bool EditorRequiresGameData(EditorType type) const
ToastManager * toast_manager()
RomFileManager rom_file_manager_
void ResetCurrentEditorLayout()
static EditorType GetEditorTypeFromCategory(const std::string &category)
static std::vector< std::string > GetAllEditorCategories()
Get all editor categories in display order for sidebar.
static bool IsPanelBasedEditor(EditorType type)
static std::string GetEditorCategory(EditorType type)
Contains a complete set of editors for a single ROM instance.
size_t session_id() const
void ApplyDependencies(const EditorDependencies &dependencies)
Editor * GetEditor(EditorType type) const
void set_user_settings(UserSettings *settings)
SettingsPanel * GetSettingsPanel() const
Interface for editor classes.
virtual absl::Status Redo()=0
virtual absl::Status Undo()=0
void ProcessDeferredActions()
Process all queued deferred actions.
void ResetWorkspaceLayout()
Reset the workspace layout to defaults.
void ProcessLayoutRebuild(EditorType current_editor_type, bool is_emulator_visible)
Process pending layout rebuild requests.
void InitializeEditorLayout(EditorType type)
Initialize layout for an editor type on first activation.
void ResetCurrentEditorLayout(EditorType editor_type, size_t session_id)
Reset current editor layout to its default configuration.
int PendingDeferredActionCount() const
Approximate pending deferred layout actions for sync diagnostics.
void ApplyLayoutPreset(const std::string &preset_name, size_t session_id)
Apply a named layout preset.
void Initialize(const Dependencies &deps)
Initialize with all dependencies.
Centralized definition of default layouts per editor.
static std::vector< std::string > GetDefaultPanels(EditorType type)
Get default visible panels for an editor.
void ToggleSidebarVisibility()
void SetPanelExpanded(bool expanded, bool notify=true)
void SetOnCategorySelectedCallback(std::function< void(const std::string &)> callback)
void SetSidebarStateChangedCallback(std::function< void(bool, bool)> cb)
void SetFileBrowserPath(const std::string &category, const std::string &path)
void SetSidebarVisible(bool visible, bool notify=true)
const PanelDescriptor * GetPanelDescriptor(size_t session_id, const std::string &base_card_id) const
void SetCategoryChangedCallback(std::function< void(const std::string &)> cb)
void RestorePinnedState(const std::unordered_map< std::string, bool > &state)
Restore pinned panel state from persistence.
void RestoreVisibilityState(size_t session_id, const std::unordered_map< std::string, bool > &state, bool publish_events=false)
Restore panel visibility state from persistence.
void SetActiveCategory(const std::string &category, bool notify=true)
bool * GetVisibilityFlag(size_t session_id, const std::string &base_card_id)
void RegisterPanelAlias(const std::string &legacy_base_id, const std::string &canonical_base_id)
Register a legacy panel ID alias that resolves to a canonical ID.
void SetOnPanelClickedCallback(std::function< void(const std::string &)> callback)
void SetEditorResolver(std::function< Editor *(const std::string &)> resolver)
std::vector< PanelDescriptor > GetPanelsInCategory(size_t session_id, const std::string &category) const
bool ShowPanel(size_t session_id, const std::string &base_card_id)
void RegisterPanel(size_t session_id, const PanelDescriptor &base_info)
std::string GetActiveCategory() const
void EnableFileBrowser(const std::string &category, const std::string &root_path="")
void SetEventBus(EventBus *event_bus)
void RegisterRegistryPanelsForSession(size_t session_id)
Register descriptors for all registry panels in a session.
void SetPanelBrowserCategoryWidth(float width, bool notify=true)
void DrawAllVisiblePanels()
Draw all visible EditorPanel instances (central drawing)
bool IsSidebarVisible() const
void SetStoredSidePanelWidth(float width, bool notify=false)
static constexpr const char * kDashboardCategory
void RegisterRegistryPanel(std::unique_ptr< EditorPanel > panel)
Register a ContentRegistry-managed EditorPanel instance.
const std::unordered_map< std::string, PanelDescriptor > & GetAllPanelDescriptors() const
Get all panel descriptors (for layout designer, panel browser, etc.)
void SetPanelBrowserCategoryWidthChangedCallback(std::function< void(float)> cb)
void SetSidePanelWidthChangedCallback(std::function< void(float)> cb)
void SetFileClickedCallback(std::function< void(const std::string &category, const std::string &path)> callback)
size_t GetActiveSessionId() const
absl::Status LoadFile(const std::string &filepath)
Load a project file into the editor.
void SetProject(project::YazeProject *project)
Set the project pointer for label import operations.
void set_active(bool active)
Set whether the editor window is active.
void SetToastManager(ToastManager *toast_manager)
Set toast manager for notifications.
absl::Status FinalizeProjectCreation(const std::string &project_name, const std::string &project_path)
Complete project creation after ROM is loaded.
absl::Status SetProjectRom(const std::string &rom_path)
Set the ROM for the current project.
absl::Status CreateNewProject(const std::string &template_name="")
absl::Status ImportProject(const std::string &project_path)
project::YazeProject & GetCurrentProject()
static float GetDefaultPanelWidth(PanelType type, EditorType editor=EditorType::kUnknown)
Get the default width for a specific panel type.
void SetBackupRetentionCount(int count)
void SetBackupBeforeSave(bool enabled)
void SetBackupFolder(const std::string &folder)
void SetBackupKeepDailyDays(int days)
absl::Status LoadRom(Rom *rom, const std::string &filename)
absl::Status SaveRom(Rom *rom)
void SetBackupKeepDaily(bool enabled)
absl::Status SaveRomAs(Rom *rom, const std::string &filename)
void UpdateCurrentRomHash(Rom *rom)
Recompute the hash of the current ROM.
bool ShouldBypassWriteConflict() const
std::vector< RomFileManager::BackupEntry > GetRomBackups(Rom *rom) const
void SetPotItemConfirmPending(int unloaded_rooms, int total_rooms)
Set pot-item confirmation pending (called by SaveRom when needed).
bool ShouldSuppressPotItemSave() const
bool HasPendingPotItemSaveConfirmation() const
void CancelRomWriteConfirm()
void ClearPotItemBypass()
PotItemSaveDecision ResolvePotItemSaveConfirmation(PotItemSaveDecision decision)
int pending_pot_item_unloaded_rooms() const
void ConsumeWriteConflictBypass()
bool ShouldBypassPotItemConfirm() const
const std::vector< core::WriteConflict > & pending_write_conflicts() const
void SetPendingWriteConflicts(std::vector< core::WriteConflict > conflicts)
absl::Status CheckRomWritePolicy(Rom *rom)
Enforce project write policy; may set pending_rom_write_confirm.
absl::Status CheckOracleRomSafetyPreSave(Rom *rom)
Run Oracle-specific ROM safety preflight before saving.
void Initialize(Dependencies deps)
absl::Status PruneRomBackups(Rom *rom)
bool IsRomWriteConfirmPending() const
void ApplyDefaultBackupPolicy(bool enabled, const std::string &folder, int retention_count, bool keep_daily, int keep_daily_days)
Apply default backup policy from user settings.
void Open(Rom *rom, const std::string &rom_filename)
Open the dialog after ROM detection.
void SetConfirmCallback(std::function< void(const LoadOptions &)> callback)
Set callback for when options are confirmed.
void Draw(bool *p_open)
Draw the dialog (wrapper around Show)
void SetAgentCallbacks(std::function< void(const std::string &)> send_callback, std::function< void()> focus_callback)
void SetSessionInfo(size_t session_id, size_t total_sessions)
Set session information.
void SetRom(Rom *rom)
Set the current ROM for dirty status and filename display.
void SetEnabled(bool enabled)
Enable or disable the status bar.
void Initialize(GlobalEditorContext *context)
void Draw()
Draw the status bar.
void SetAgentToggleCallback(std::function< void()> callback)
void SetAgentInfo(const std::string &provider, const std::string &model, bool active)
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
bool ApplyPanelLayoutDefaultsRevision(int target_revision)
static constexpr int kLatestPanelLayoutDefaultsRevision
void SetNewProjectCallback(std::function< void()> callback)
Set callback for creating new project.
void SetOpenAgentCallback(std::function< void()> callback)
Set callback for opening AI Agent.
void SetOpenRomCallback(std::function< void()> callback)
Set callback for opening ROM.
void SetOpenProjectDialogCallback(std::function< void()> callback)
Set callback for opening the project file dialog.
void SetOpenProjectManagementCallback(std::function< void()> callback)
Set callback for showing project management.
void SetOpenProjectFileEditorCallback(std::function< void()> callback)
Set callback for showing the project file editor.
void SetNewProjectWithTemplateCallback(std::function< void(const std::string &)> callback)
Set callback for creating project with template.
void SetOpenProjectCallback(std::function< void(const std::string &)> callback)
Set callback for opening project.
void set_apply_preset_callback(std::function< void(const std::string &)> callback)
void set_apply_preset_callback(std::function< void(const std::string &)> callback)
void set_layout_manager(LayoutManager *manager)
void set_panel_manager(PanelManager *manager)
bool is_audio_focus_mode() const
void set_renderer(gfx::IRenderer *renderer)
bool is_snes_initialized() const
auto running() const -> bool
void set_panel_manager(editor::PanelManager *manager)
auto mutable_gfx_sheets()
Get mutable reference to all graphics sheets.
Defines an abstract interface for all rendering operations.
static MotionProfile ClampMotionProfile(int raw_profile)
void SetMotionPreferences(bool reduced_motion, MotionProfile profile)
void ClearAllAnimations()
RAII guard for ImGui style colors.
static RecentFilesManager & GetInstance()
void SetCurrentRom(Rom *rom)
void DrawTestDashboard(bool *show_dashboard=nullptr)
static TestManager & Get()
void UpdateResourceStats()
static void ShowOpenFileDialogAsync(const FileDialogOptions &options, std::function< void(const std::string &)> callback)
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...
void SetObjectFileMap(const std::unordered_map< int, std::vector< std::string > > &map)
static CustomObjectManager & Get()
void Initialize(const std::string &custom_objects_folder)
void ClearObjectFileMap()
void RefreshFeatureFlagMappings()
static DrawRoutineRegistry & Get()
Represents the full Overworld data, light and dark world.
std::unordered_map< std::string, LabelMap > ProjectLabels
int main(int argc, char **argv)
#define ICON_MD_VIDEOGAME_ASSET
#define ICON_MD_BUG_REPORT
#define ICON_MD_AUDIOTRACK
#define ICON_MD_DASHBOARD
#define ICON_MD_SPORTS_ESPORTS
#define ICON_MD_AUDIO_FILE
#define ICON_MD_SMART_TOY
#define ICON_MD_MENU_OPEN
#define LOG_DEBUG(category, format,...)
#define LOG_WARN(category, format,...)
#define LOG_INFO(category, format,...)
#define PRINT_IF_ERROR(expression)
constexpr char kOverworldExpandedPtrHigh[]
constexpr char kOverworldEntrancePosExpanded[]
constexpr char kExpandedMusicHook[]
constexpr char kExpandedMusicMain[]
constexpr char kOverworldExpandedPtrMagic[]
constexpr char kExpandedMessageEnd[]
constexpr char kOverworldExpandedPtrMarker[]
constexpr char kOverworldEntranceMapExpanded[]
constexpr char kOverworldEntranceFlagExpanded[]
constexpr char kExpandedMessageStart[]
constexpr char kOverworldEntranceIdExpanded[]
constexpr char kOverworldExpandedPtrLow[]
constexpr char kExpandedMusicAux[]
void SetGlobalContext(GlobalEditorContext *ctx)
void SetEventBus(::yaze::EventBus *bus)
Set the current EventBus instance.
void SetRom(Rom *rom)
Set the current ROM instance.
void SetGameData(::yaze::zelda3::GameData *data)
Set the current game data instance.
void Clear()
Clear all context state.
void SetCurrentProject(::yaze::project::YazeProject *project)
Set the current project instance.
std::vector< std::unique_ptr< EditorPanel > > CreateAll()
Create new instances of all registered panels.
std::string GetEditorName(EditorType type)
bool HasAnyOverride(const core::RomAddressOverrides &overrides, std::initializer_list< const char * > keys)
bool ProjectUsesCustomObjects(const project::YazeProject &project)
std::string StripSessionPrefix(absl::string_view panel_id)
std::vector< std::string > ValidateRomAddressOverrides(const core::RomAddressOverrides &overrides, const Rom &rom)
std::optional< EditorType > ParseEditorTypeFromString(absl::string_view name)
void SeedOracleProjectInRecents()
Editors are the view controllers for the application.
constexpr std::array< const char *, 14 > kEditorNames
void ConfigureMenuShortcuts(const ShortcutDependencies &deps, ShortcutManager *shortcut_manager)
void RegisterDefaultEditorFactories(EditorRegistry *registry)
void ConfigurePanelShortcuts(const ShortcutDependencies &deps, ShortcutManager *shortcut_manager)
Register configurable panel shortcuts from user settings.
size_t EditorTypeIndex(EditorType type)
void ConfigureEditorShortcuts(const ShortcutDependencies &deps, ShortcutManager *shortcut_manager)
void ExecuteShortcuts(const ShortcutManager &shortcut_manager)
ImVec4 GetSurfaceContainerHighestVec4()
ImVec4 GetTextSecondaryVec4()
ImVec4 GetSurfaceContainerHighVec4()
DiffSummary ComputeDiffRanges(const std::vector< uint8_t > &before, const std::vector< uint8_t > &after)
void RegisterZ3edTestSuites()
FileDialogOptions MakeRomFileDialogOptions(bool include_all_files)
absl::Status LoadGameData(Rom &rom, GameData &data, const LoadOptions &options)
Loads all Zelda3-specific game data from a generic ROM.
constexpr int kExpandedPtrTableMarker
absl::Status SaveAllGraphicsData(Rom &rom, const std::array< gfx::Bitmap, kNumGfxSheets > &sheets)
Saves all graphics sheets back to ROM.
void SetPreferHmagicSpriteNames(bool prefer)
constexpr uint8_t kExpandedPtrTableMagic
constexpr int kOverworldEntranceExpandedFlagPos
ResourceLabelProvider & GetResourceLabels()
Get the global ResourceLabelProvider instance.
AssetLoadMode
Asset loading mode for editor resources.
#define RETURN_IF_ERROR(expr)
Configuration options for the application startup.
std::string startup_editor
StartupVisibility welcome_mode
std::vector< std::string > open_panels
StartupVisibility sidebar_mode
StartupVisibility dashboard_mode
bool kEnableCustomObjects
struct yaze::core::FeatureFlags::Flags::Dungeon dungeon
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > all_resource_labels
std::unordered_map< std::string, uint32_t > addresses
std::optional< uint32_t > GetAddress(const std::string &key) const
LayoutManager * layout_manager
PanelManager * panel_manager
std::function< EditorSet *()> get_current_editor_set
std::function< void(std::function< void()>)> queue_deferred_action
ToastManager * toast_manager
RightPanelManager * right_panel_manager
UICoordinator * ui_coordinator
std::function< size_t()> get_current_session_id
std::function< absl::Status(EditorType)> ensure_editor_assets_loaded
Unified dependency container for all editor types.
project::YazeProject * project
GlobalEditorContext * global_context
ToastManager * toast_manager
SharedClipboard * shared_clipboard
gfx::IRenderer * renderer
ShortcutManager * shortcut_manager
UserSettings * user_settings
core::VersionManager * version_manager
PanelManager * panel_manager
PopupManager * popup_manager
bool layout_rebuild_pending
int pending_layout_actions
int pending_editor_actions
Published after ImGui::NewFrame and dockspace creation.
static JumpToMapRequestEvent Create(int map, size_t session=0)
static JumpToRoomRequestEvent Create(int room, size_t session=0)
All dependencies required by LayoutCoordinator.
PanelManager * panel_manager
ToastManager * toast_manager
UICoordinator * ui_coordinator
RightPanelManager * right_panel_manager
LayoutManager * layout_manager
Built-in workflow-oriented layout profiles.
Declarative registration contract for editor panels.
std::string shortcut_hint
Metadata for an editor panel (formerly PanelInfo)
std::function< void()> on_show
PanelCategory panel_category
PanelContextScope context_scope
std::string shortcut_hint
std::function< void()> on_hide
Published when panel visibility changes.
bool save_overworld_items
std::string selected_preset
bool save_overworld_exits
bool enable_custom_overworld
bool save_overworld_entrances
Published when a ROM is successfully loaded into a session.
Represents a single session, containing a ROM and its associated editors.
core::FeatureFlags::Flags feature_flags
std::array< bool, kEditorTypeCount > editor_initialized
zelda3::GameData game_data
std::array< bool, kEditorTypeCount > editor_assets_loaded
Published when a session is closed.
Published when a new session is created.
Published when the active session changes.
UserSettings * user_settings
SessionCoordinator * session_coordinator
WorkspaceManager * workspace_manager
EditorRegistry * editor_registry
MenuOrchestrator * menu_orchestrator
ToastManager * toast_manager
RomFileManager * rom_file_manager
EditorManager * editor_manager
ProjectManager * project_manager
UICoordinator * ui_coordinator
PopupManager * popup_manager
PanelManager * panel_manager
Activity bar or menu action request.
float sidebar_panel_width
bool sidebar_panel_expanded
std::unordered_map< std::string, float > right_panel_widths
bool show_welcome_on_startup
int switch_motion_profile
std::string sidebar_active_category
std::unordered_map< std::string, std::unordered_map< std::string, bool > > panel_visibility_state
std::unordered_map< std::string, bool > pinned_panels
bool prefer_hmagic_sprite_names
float panel_browser_category_width
void DisplayLabels(bool *p_open)
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > labels_
int backup_keep_daily_days
int backup_retention_count
float autosave_interval_secs
std::vector< std::string > recent_files
Modern project structure with comprehensive settings consolidation.
std::string rom_backup_folder
std::unordered_map< int, std::vector< std::string > > custom_object_files
std::string custom_objects_folder
absl::Status RepairProject()
std::string MakeStorageKey(absl::string_view suffix) const
bool project_opened() const
core::HackManifest hack_manifest
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > resource_labels
std::string assets_folder
std::string labels_filename
std::string GetDisplayName() const
WorkspaceSettings workspace_settings
std::string GetAbsolutePath(const std::string &relative_path) const
absl::Status Open(const std::string &project_path)
absl::Status Validate() const
core::FeatureFlags::Flags feature_flags
core::RomAddressOverrides rom_address_overrides