19#include <initializer_list>
24#include <unordered_set>
29#include <TargetConditionals.h>
33#define IMGUI_DEFINE_MATH_OPERATORS
34#include "absl/status/status.h"
35#include "absl/status/statusor.h"
36#include "absl/strings/ascii.h"
37#include "absl/strings/match.h"
38#include "absl/strings/str_format.h"
39#include "absl/strings/str_join.h"
40#include "absl/strings/str_split.h"
41#include "absl/strings/string_view.h"
42#include "imgui/imgui.h"
95#include "yaze_config.h"
117#ifdef YAZE_ENABLE_TESTING
124#ifdef YAZE_ENABLE_GTEST
132#ifdef YAZE_BUILD_AGENT_UI
140 std::initializer_list<const char*> keys) {
141 for (
const char* key : keys) {
150 std::vector<std::string> lines = absl::StrSplit(text,
'\n');
151 for (
auto it = lines.rbegin(); it != lines.rend(); ++it) {
152 std::string line = std::string(*it);
153 absl::StripAsciiWhitespace(&line);
165 if (status_bar !=
nullptr) {
168 if (project_panel !=
nullptr) {
177 if (status_bar !=
nullptr) {
180 if (project_panel !=
nullptr) {
187 const std::string& output_log) {
191 .output_log = output_log,
192 .timestamp = std::chrono::system_clock::now()});
203 std::string* warning) {
204 if (project ==
nullptr) {
215 const auto& defaults =
218 if (defaults.empty()) {
223 if (warning !=
nullptr) {
224 *warning = absl::StrFormat(
225 "Project defines custom_objects_folder but is missing "
226 "custom_object_files[0x%02X]. Seeded default mapping (%d entries).",
234 std::vector<std::string> warnings;
239 const auto rom_size = rom.
size();
240 auto warn = [&](
const std::string& message) {
241 warnings.push_back(message);
244 auto check_range = [&](
const std::string& label, uint32_t addr,
size_t span) {
245 const size_t addr_size =
static_cast<size_t>(addr);
246 if (addr_size >= rom_size || addr_size + span > rom_size) {
247 warn(absl::StrFormat(
"ROM override '%s' out of range: 0x%X (size 0x%X)",
248 label, addr, rom_size));
252 for (
const auto& [key, value] : overrides.
addresses) {
253 check_range(key, value, 1);
260 constexpr uint32_t kExpandedMessageStartDefault = 0x178000;
261 constexpr uint32_t kExpandedMessageEndDefault = 0x17FFFF;
262 const uint32_t start =
264 .value_or(kExpandedMessageStartDefault);
267 .value_or(kExpandedMessageEndDefault);
268 if (start >= rom_size || end >= rom_size) {
269 warn(absl::StrFormat(
270 "Expanded message range out of ROM bounds: 0x%X-0x%X", start, end));
271 }
else if (end < start) {
272 warn(absl::StrFormat(
"Expanded message range invalid: 0x%X-0x%X", start,
280 if (*hook < rom_size) {
282 if (opcode.ok() && opcode.value() != 0x22) {
283 warn(absl::StrFormat(
284 "Expanded music hook at 0x%X is not a JSL opcode (0x%02X)", *hook,
304 const uint32_t marker =
307 const uint32_t magic =
310 check_range(
"overworld_ptr_marker", marker, 1);
311 if (marker < rom_size) {
312 if (rom.
data()[marker] !=
static_cast<uint8_t
>(magic)) {
313 warn(absl::StrFormat(
314 "Overworld expanded pointer marker mismatch at 0x%X: expected "
315 "0x%02X, found 0x%02X",
316 marker,
static_cast<uint8_t
>(magic), rom.
data()[marker]));
326 const uint32_t flag_addr =
330 check_range(
"overworld_entrance_flag_expanded", flag_addr, 1);
331 if (flag_addr < rom_size && rom.
data()[flag_addr] == 0xB8) {
333 absl::StrFormat(
"Overworld entrance flag at 0x%X is still 0xB8 "
334 "(vanilla); expanded entrance tables may be ignored",
343 const std::string lower = absl::AsciiStrToLower(std::string(name));
345 const std::string candidate = absl::AsciiStrToLower(
347 if (candidate == lower) {
355 if (panel_id.size() > 2 && panel_id[0] ==
's' &&
356 absl::ascii_isdigit(panel_id[1])) {
357 const size_t dot = panel_id.find(
'.');
358 if (dot != absl::string_view::npos) {
359 return std::string(panel_id.substr(dot + 1));
362 return std::string(panel_id);
366 namespace fs = std::filesystem;
368 std::vector<fs::path> roots;
369 if (
const char* home = std::getenv(
"HOME");
370 home !=
nullptr && std::strlen(home) > 0) {
371 roots.push_back(fs::path(home) /
"src" /
"hobby" /
"oracle-of-secrets");
374 std::vector<fs::path> candidates;
375 std::unordered_set<std::string> seen;
376 auto add_candidate = [&](
const fs::path& path) {
378 if (!fs::exists(path, ec) || ec) {
381 std::string ext = path.extension().string();
382 absl::AsciiStrToLower(&ext);
383 if (ext !=
".yaze" && ext !=
".yazeproj") {
386 const std::string normalized = fs::weakly_canonical(path, ec).string();
387 const std::string key = normalized.empty() ? path.string() : normalized;
388 if (key.empty() || seen.count(key) > 0) {
392 candidates.push_back(path);
395 for (
const auto& root : roots) {
397 if (!fs::exists(root, ec) || ec) {
402 add_candidate(root /
"Oracle-of-Secrets.yaze");
403 add_candidate(root /
"Oracle of Secrets.yaze");
404 add_candidate(root /
"Oracle-of-Secrets.yazeproj");
405 add_candidate(root /
"Oracle of Secrets.yazeproj");
406 add_candidate(root /
"Roms" /
"Oracle of Secrets.yaze");
409 fs::recursive_directory_iterator it(
410 root, fs::directory_options::skip_permission_denied, ec);
411 fs::recursive_directory_iterator end;
415 for (; it != end; it.increment(ec)) {
420 if (it.depth() > 2) {
421 it.disable_recursion_pending();
424 add_candidate(it->path());
428 if (candidates.empty()) {
434 for (
auto it = candidates.rbegin(); it != candidates.rend(); ++it) {
435 manager.AddFile(it->string());
469 current_type, &applied_profile)) {
480 std::max(default_width, 480.0f));
484 absl::StrFormat(
"Layout Profile: %s", applied_profile.
label),
503 clear_after_restore)) {
540 bool remove_after_restore) {
594#ifdef YAZE_BUILD_AGENT_UI
595void EditorManager::ShowAIAgent() {
602 for (
const auto& window_id :
608void EditorManager::ShowChatHistory() {
614 : project_manager_(&toast_manager_), rom_file_manager_(&toast_manager_) {
615 std::stringstream ss;
616 ss << YAZE_VERSION_MAJOR <<
"." << YAZE_VERSION_MINOR <<
"."
617 << YAZE_VERSION_PATCH;
684 [
this](
const std::string& preset_name) {
688 [
this](
const std::string& preset_name) {
699 [
this](
const std::string& prompt) {
700#if defined(YAZE_BUILD_AGENT_UI)
710 chat->SendMessage(prompt);
716#if defined(YAZE_BUILD_AGENT_UI)
736 std::make_unique<workflow::ProjectWorkflowOutputPanel>());
741 if (!rom_path.empty()) {
758 absl::StrFormat(
"Failed to reload ROM: %s", status.message()),
769 absl::StrFormat(
"Failed to save project: %s", status.message()),
774 [
this](
const std::string& type) {
776 if (!folder_path.empty()) {
777 if (type ==
"code") {
782#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
783 editor_set->OpenAssemblyFolder(folder_path);
787 }
else if (type ==
"assets") {
791 folder_path.c_str()),
853 return dungeon_editor->IsWorkbenchWorkflowEnabled();
858 [
this](
bool enabled) {
862 dungeon_editor->QueueWorkbenchWorkflowMode(enabled);
873 registry.Register({
"command_palette",
878 registry.Register({
"keyboard_shortcuts",
879 "Keyboard Shortcuts",
883 registry.Register({
"open_rom_project",
884 "Open ROM / Project",
888 registry.Register({
"settings",
905 for (
auto& panel : registry_panels) {
914 dashboard_definition.
id =
"dashboard.main";
917 dashboard_definition.
category =
"Dashboard";
925 {.card_id =
"dashboard.main",
926 .display_name =
"Dashboard",
927 .window_title =
" Dashboard",
929 .category =
"Dashboard",
930 .shortcut_hint =
"F1",
966 std::vector<std::function<void()>> actions_to_execute;
968 const int processed_count =
static_cast<int>(actions_to_execute.size());
969 for (
auto& action : actions_to_execute) {
972 if (processed_count > 0) {
974 processed_count, std::memory_order_relaxed) -
992 if (e.category.empty() ||
1026 for (
const auto& [type, labels] : src) {
1027 auto& out = (*dst)[type];
1028 for (
const auto& [key, value] : labels) {
1034 merged_labels.clear();
1035 std::vector<std::string> source_parts;
1041 source_parts.push_back(
"rom");
1051 source_parts.push_back(
"registry");
1058 source_parts.push_back(
"project");
1061 auto* label_source = merged_labels.empty() ? &empty_labels : &merged_labels;
1062 std::string source =
1063 source_parts.empty() ?
"empty" : absl::StrJoin(source_parts,
"+");
1065 provider.SetProjectLabels(label_source);
1071 const bool prefer_hmagic =
1075 provider.SetPreferHMagicNames(prefer_hmagic);
1078 "ResourceLabelProvider refreshed (source=%s, project_open=%s)",
1105 if (!category.empty() &&
1113#ifdef YAZE_ENABLE_TESTING
1117 LOG_DEBUG(
"EditorManager",
"Session switched to %zu via EventBus", new_index);
1123 LOG_INFO(
"EditorManager",
"Session %zu created via EventBus", index);
1137#ifdef YAZE_ENABLE_TESTING
1142 LOG_INFO(
"EditorManager",
"Session %zu closed via EventBus", index);
1161#ifdef YAZE_ENABLE_TESTING
1167 LOG_INFO(
"EditorManager",
"ROM loaded in session %zu via EventBus", index);
1173 case Action::kShowEmulator:
1179 case Action::kShowSettings:
1189 case Action::kShowPanelBrowser:
1195 case Action::kShowSearch:
1201 case Action::kShowShortcuts:
1206 case Action::kShowCommandPalette:
1212 case Action::kShowHelp:
1223 case Action::kShowAgentChatSidebar:
1232 case Action::kShowAgentProposalsSidebar:
1239 case Action::kOpenRom: {
1243 std::string(
"Open failed: ") + std::string(status.message()),
1248 case Action::kSaveRom:
1253 }
else if (!absl::IsCancelled(status)) {
1255 std::string(
"Save failed: ") + std::string(status.message()),
1263 auto status = current_editor->
Undo();
1266 std::string(
"Undo failed: ") + std::string(status.message()),
1274 auto status = current_editor->
Redo();
1277 std::string(
"Redo failed: ") + std::string(status.message()),
1283 case Action::kResetLayout:
1292#ifdef YAZE_ENABLE_TESTING
1294 test_manager.RegisterTestSuite(
1295 std::make_unique<test::CoreSystemsTestSuite>());
1296 test_manager.RegisterTestSuite(std::make_unique<test::IntegratedTestSuite>());
1297 test_manager.RegisterTestSuite(
1298 std::make_unique<test::PerformanceTestSuite>());
1299 test_manager.RegisterTestSuite(std::make_unique<test::UITestSuite>());
1300 test_manager.RegisterTestSuite(
1301 std::make_unique<test::RomDependentTestSuite>());
1304 test_manager.RegisterTestSuite(std::make_unique<test::E2ETestSuite>());
1305 test_manager.RegisterTestSuite(
1306 std::make_unique<test::ZSCustomOverworldTestSuite>());
1310#ifdef YAZE_ENABLE_GTEST
1311 test_manager.RegisterTestSuite(std::make_unique<test::UnitTestSuite>());
1315#ifdef YAZE_WITH_GRPC
1320 test_manager.UpdateResourceStats();
1324 const std::string& filename) {
1327 SeedOracleProjectInRecents();
1336 if (!filename.empty()) {
1361 const bool prefer_dashboard_only =
1364 if (!prefer_dashboard_only) {
1367 if (!category.empty()) {
1385#ifdef YAZE_ENABLE_TESTING
1396 const std::vector<WindowDefinition> panel_definitions = {
1397 {.id =
"emulator.cpu_debugger",
1398 .display_name =
"CPU Debugger",
1400 .category =
"Emulator",
1402 {.id =
"emulator.ppu_viewer",
1403 .display_name =
"PPU Viewer",
1405 .category =
"Emulator",
1407 {.id =
"emulator.memory_viewer",
1408 .display_name =
"Memory Viewer",
1410 .category =
"Emulator",
1412 {.id =
"emulator.breakpoints",
1413 .display_name =
"Breakpoints",
1415 .category =
"Emulator",
1417 {.id =
"emulator.performance",
1418 .display_name =
"Performance",
1420 .category =
"Emulator",
1422 {.id =
"emulator.ai_agent",
1423 .display_name =
"AI Agent",
1425 .category =
"Emulator",
1427 {.id =
"emulator.save_states",
1428 .display_name =
"Save States",
1430 .category =
"Emulator",
1432 {.id =
"emulator.keyboard_config",
1433 .display_name =
"Keyboard Config",
1435 .category =
"Emulator",
1437 {.id =
"emulator.virtual_controller",
1438 .display_name =
"Virtual Controller",
1440 .category =
"Emulator",
1442 {.id =
"emulator.apu_debugger",
1443 .display_name =
"APU Debugger",
1445 .category =
"Emulator",
1447 {.id =
"emulator.audio_mixer",
1448 .display_name =
"Audio Mixer",
1450 .category =
"Emulator",
1452 {.id =
"memory.hex_editor",
1453 .display_name =
"Hex Editor",
1455 .category =
"Memory",
1458 .legacy_ids = {
"Memory Editor"}},
1466 for (
const auto& definition : panel_definitions) {
1468 descriptor.
card_id = definition.id;
1471 descriptor.
icon = definition.icon;
1472 descriptor.
category = definition.category;
1474 descriptor.
priority = definition.priority;
1475 descriptor.
scope = definition.scope;
1479 descriptor.
on_show = definition.on_show;
1480 descriptor.
on_hide = definition.on_hide;
1482 for (
const auto& legacy_id : definition.legacy_ids) {
1487 if (definition.visible_by_default) {
1508 LOG_WARN(
"EditorManager",
"Failed to load user settings: %s",
1518 [
this](
const std::string& theme_name) {
1527 prefs.reduced_motion,
1560 if (ImGui::GetCurrentContext() !=
nullptr) {
1564 "ImGui context not available; skipping FontGlobalScale update");
1571 if (!last_theme.empty() && last_theme !=
"Custom Accent") {
1576#ifdef __EMSCRIPTEN__
1579 LOG_INFO(
"EditorManager",
"WASM Control and Session APIs initialized");
1596 flags.overworld.kSaveOverworldEntrances =
1624 LOG_INFO(
"EditorManager",
"ROM load options applied: preset=%s",
1642 [
this](
const std::string& template_name) {
1659#ifdef YAZE_BUILD_AGENT_UI
1689 absl::StrFormat(
"Failed to open project: %s",
status_.message()),
1716 [
this](
bool visible,
bool expanded) {
1728 [
this](
float width) {
1735 const std::string& category) {
1736 if (category.empty() ||
1745 if (it != prefs.panel_visibility_state.end()) {
1755 bool any_visible =
false;
1756 for (
const auto& desc :
1758 if (desc.visibility_flag && *desc.visibility_flag) {
1778 [
this](
const std::string& category) ->
Editor* {
1785 [
this](
const std::string& category) {
1793 [
this](
const std::string& category) {
1798 if (category ==
"Agent") {
1799#ifdef YAZE_BUILD_AGENT_UI
1814 [
this](
const std::string& category,
const std::string& path) {
1815 if (category ==
"Assembly") {
1817 editor_set->ChangeActiveAssemblyFile(path);
1845 const std::string& editor_name,
const std::string& panels_str) {
1846 const bool has_editor = !editor_name.empty();
1847 const bool has_panels = !panels_str.empty();
1849 if (!has_editor && !has_panels) {
1854 "Processing startup flags: editor='%s', panels='%s'",
1855 editor_name.c_str(), panels_str.c_str());
1857 std::optional<EditorType> editor_type_to_open =
1858 has_editor ? ParseEditorTypeFromString(editor_name) : std::nullopt;
1859 if (has_editor && !editor_type_to_open.has_value()) {
1860 LOG_WARN(
"EditorManager",
"Unknown editor specified via flag: %s",
1861 editor_name.c_str());
1862 }
else if (editor_type_to_open.has_value()) {
1874 bool applied_category_from_panel =
false;
1876 for (absl::string_view token :
1877 absl::StrSplit(panels_str,
',', absl::SkipWhitespace())) {
1878 if (token.empty()) {
1881 std::string panel_name = std::string(absl::StripAsciiWhitespace(token));
1882 LOG_DEBUG(
"EditorManager",
"Attempting to open panel: '%s'",
1883 panel_name.c_str());
1885 const std::string lower_name = absl::AsciiStrToLower(panel_name);
1886 if (lower_name ==
"welcome" || lower_name ==
"welcome_screen") {
1892 if (lower_name ==
"dashboard" || lower_name ==
"dashboard.main" ||
1893 lower_name ==
"editor_selection") {
1907 if (absl::StartsWith(panel_name,
"Room ")) {
1910 int room_id = std::stoi(panel_name.substr(5));
1913 }
catch (
const std::exception& e) {
1914 LOG_WARN(
"EditorManager",
"Invalid room ID format: %s",
1915 panel_name.c_str());
1921 std::optional<std::string> resolved_panel;
1923 resolved_panel = panel_name;
1925 for (
const auto& [prefixed_id, descriptor] :
1927 const std::string base_id = StripSessionPrefix(prefixed_id);
1928 const std::string card_lower = absl::AsciiStrToLower(base_id);
1929 const std::string display_lower =
1930 absl::AsciiStrToLower(descriptor.display_name);
1932 if (card_lower == lower_name || display_lower == lower_name) {
1933 resolved_panel = base_id;
1939 if (!resolved_panel.has_value()) {
1941 "Unknown panel '%s' from --open_panels (known count: %zu)",
1948 const auto* descriptor =
1950 if (descriptor !=
nullptr) {
1954 if (!ensure_status.ok()) {
1955 LOG_WARN(
"EditorManager",
"Failed to load assets for panel '%s': %s",
1956 resolved_panel->c_str(), ensure_status.message().data());
1959 if (descriptor && !applied_category_from_panel &&
1962 applied_category_from_panel =
true;
1963 }
else if (!applied_category_from_panel && descriptor &&
1964 descriptor->category.empty() && !last_known_category.empty()) {
1968 LOG_WARN(
"EditorManager",
"Failed to show panel '%s'",
1969 resolved_panel->c_str());
1990 constexpr int kTargetRevision =
2001 "Applied panel layout defaults migration revision %d",
2006 const std::string& saved_category,
2007 const std::vector<std::string>& available_categories)
const {
2009 if (!saved_category.empty() && saved_category !=
"Emulator") {
2011 if (available_categories.empty()) {
2012 return saved_category;
2014 for (
const auto& cat : available_categories) {
2015 if (cat == saved_category)
2016 return saved_category;
2020 for (
const auto& cat : available_categories) {
2021 if (cat !=
"Emulator")
2038 const bool sidebar_visible =
2065 std::string panels_str;
2066 for (
size_t i = 0; i < config.
open_panels.size(); ++i) {
2110 if (index < session->editor_initialized.size()) {
2120 if (index < session->editor_assets_loaded.size()) {
2146 std::unordered_set<EditorType> types;
2161 auto add_category = [&](
const std::string& category) {
2162 if (category.empty() ||
2170 bool used_startup_hints =
false;
2174 add_type(*startup_type);
2175 used_startup_hints =
true;
2180 if (panel_name.empty()) {
2184 if (
const auto* descriptor =
2186 add_category(descriptor->category);
2187 used_startup_hints =
true;
2191 const std::string lower_name = absl::AsciiStrToLower(panel_name);
2192 for (
const auto& [prefixed_id, descriptor] :
2194 const std::string base_id = StripSessionPrefix(prefixed_id);
2195 const std::string card_lower = absl::AsciiStrToLower(base_id);
2196 const std::string display_lower =
2197 absl::AsciiStrToLower(descriptor.display_name);
2198 if (card_lower == lower_name || display_lower == lower_name) {
2199 add_category(descriptor.category);
2200 used_startup_hints =
true;
2206 if (used_startup_hints) {
2207 return std::vector<EditorType>(types.begin(), types.end());
2216 if (editor !=
nullptr && *editor->active()) {
2217 add_type(editor->type());
2228 for (
const auto& window_id :
2230 if (
const auto* descriptor =
2232 add_category(descriptor->category);
2236 return std::vector<EditorType>(types.begin(), types.end());
2241 return editor_set ? editor_set->
GetEditor(type) :
nullptr;
2245 if (category.empty() ||
2258#ifdef YAZE_BUILD_AGENT_UI
2275 }
else if (!category.empty() &&
2277 LOG_DEBUG(
"EditorManager",
"No editor context available for category '%s'",
2286 return absl::FailedPreconditionError(
"No editor set available");
2291 return absl::OkStatus();
2293 editor->Initialize();
2294 return absl::OkStatus();
2302 return absl::FailedPreconditionError(
"No active session");
2304 if (session->game_data_loaded) {
2305 return absl::OkStatus();
2307 if (!session->rom.is_loaded()) {
2308 return absl::FailedPreconditionError(
"ROM not loaded");
2314 auto* game_data = &session->game_data;
2315 auto* editor_set = &session->editors;
2316 editor_set->SetGameData(game_data);
2319 session->game_data_loaded =
true;
2321 return absl::OkStatus();
2326 return absl::OkStatus();
2333 return absl::OkStatus();
2336 if (!session->rom.is_loaded()) {
2338 return absl::OkStatus();
2341 if (index >= session->editor_initialized.size()) {
2342 return absl::InvalidArgumentError(
"Invalid editor type");
2345 return absl::OkStatus();
2347 if (!session->editor_initialized[index]) {
2352 return absl::OkStatus();
2356 if (index >= session->editor_initialized.size()) {
2357 return absl::InvalidArgumentError(
"Invalid editor type");
2364 if (!session->editor_initialized[index]) {
2374 if (!session->editor_assets_loaded[index]) {
2382 return absl::OkStatus();
2433 bool is_emulator_visible =
2444 if (!save_status.ok()) {
2445 LOG_WARN(
"EditorManager",
"Failed to save user settings: %s",
2446 save_status.ToString().c_str());
2456 static Rom* last_test_rom =
nullptr;
2458 if (last_test_rom != current_rom) {
2461 "EditorManager::Update - ROM changed, updating TestManager: %p -> %p",
2462 (
void*)last_test_rom, (
void*)current_rom);
2464 last_test_rom = current_rom;
2469 current_rom->dirty()) {
2476 auto st = current_rom->SaveToFile(s);
2489 if (current_rom && current_rom->is_loaded()) {
2497 &editor_set->GetAssemblySymbols());
2513 UpdateBuildWorkflowStatus(
2518 : (snapshot.status.ok() ?
"Build succeeded" :
"Build failed"),
2519 snapshot.output_tail.empty()
2522 "Running the configured project build command")
2523 : std::string(snapshot.status.message()))
2524 : snapshot.output_tail,
2529 snapshot.output_tail, snapshot.running));
2540 if (!snapshot.status.ok()) {
2541 AppendWorkflowHistoryEntry(
2543 MakeBuildStatus(
"Build failed", std::string(snapshot.status.message()),
2548 absl::StrFormat(
"Build failed: %s", snapshot.status.message()),
2549 snapshot.status.code() == absl::StatusCode::kCancelled
2555 AppendWorkflowHistoryEntry(
2559 snapshot.output_tail.empty() ? std::string(
"Project build completed")
2560 : snapshot.output_tail,
2564 ?
"Project build completed"
2565 : absl::StrFormat(
"Project build completed: %s",
2566 snapshot.output_tail),
2622 std::unordered_set<std::string> active_editor_categories;
2626 for (
size_t session_idx = 0;
2631 if (!session || !session->rom.is_loaded()) {
2635 for (
auto* editor : session->editors.active_editors_) {
2637 std::string category =
2639 active_editor_categories.insert(category);
2645 active_editor_categories.insert(
"Emulator");
2650 const bool prefer_dashboard_only =
2654 if (!prefer_dashboard_only && sidebar_category.empty() &&
2655 !all_categories.empty()) {
2657 if (!sidebar_category.empty()) {
2669 auto has_rom_callback = [
this]() ->
bool {
2675 auto is_rom_dirty_callback = [
this]() ->
bool {
2680 all_categories, active_editor_categories,
2681 has_rom_callback, is_rom_dirty_callback);
2698 bool has_agent_info =
false;
2699#if defined(YAZE_BUILD_AGENT_UI)
2701 auto* chat = agent_editor->GetAgentChat();
2705 bool active = chat && *chat->active();
2707 has_agent_info =
true;
2711 if (!has_agent_info) {
2753 if (ImGui::BeginMenuBar()) {
2758 {{ImGuiCol_Button, ImVec4(0, 0, 0, 0)},
2765 if (ImGui::SmallButton(icon)) {
2770 if (ImGui::IsItemHovered()) {
2772 ?
"Hide Activity Bar (Ctrl+B)"
2773 :
"Show Activity Bar (Ctrl+B)";
2774 ImGui::SetTooltip(
"%s", tooltip);
2787 ImGui::EndMenuBar();
2796 bool visible =
true;
2797 ImGui::ShowDemoWindow(&visible);
2803 bool visible =
true;
2804 ImGui::ShowMetricsWindow(&visible);
2812 bool* hex_visibility =
2814 if (hex_visibility) {
2818 editor->set_active(*hex_visibility);
2820 *hex_visibility = *editor->active();
2826 editor->set_active(
true);
2828 if (!*editor->active()) {
2847#ifdef YAZE_ENABLE_TESTING
2848 if (show_test_dashboard_) {
2865 bool visible =
true;
2933 auto load_from_path = [
this](
const std::string& file_name) -> absl::Status {
2934 if (file_name.empty()) {
2935 return absl::OkStatus();
2939 if (absl::EndsWith(file_name,
".yaze") ||
2940 absl::EndsWith(file_name,
".zsproj") ||
2941 absl::EndsWith(file_name,
".yazeproj")) {
2948 return absl::OkStatus();
2956 std::move(temp_rom), file_name);
2957 if (!session_or.ok()) {
2958 return session_or.status();
2973#ifdef YAZE_ENABLE_TESTING
2978 const auto& recent_files = manager.GetRecentFiles();
2979 const bool is_first_time_rom_path =
2980 std::find(recent_files.begin(), recent_files.end(), file_name) ==
2982 manager.AddFile(file_name);
2995 return absl::OkStatus();
2998#if defined(__APPLE__) && TARGET_OS_IOS == 1
3005 return absl::OkStatus();
3009 return load_from_path(file_name);
3016 if (!current_rom || !current_editor_set) {
3017 return absl::FailedPreconditionError(
"No ROM or editor set loaded");
3021 if (!current_session) {
3022 return absl::FailedPreconditionError(
"No active ROM session");
3026 auto start_time = std::chrono::steady_clock::now();
3028#ifdef __EMSCRIPTEN__
3030 auto loading_handle =
3032 ?
static_cast<app::platform::WasmLoadingManager::LoadingHandle
>(
3034 : app::platform::WasmLoadingManager::BeginLoading(
3035 "Loading Editor Assets");
3038 constexpr float kStartProgress = 0.10f;
3039 constexpr float kEndProgress = 1.0f;
3040 constexpr int kTotalSteps = 11;
3041 int current_step = 0;
3042 auto update_progress = [&](
const std::string& message) {
3045 kStartProgress + (kEndProgress - kStartProgress) *
3046 (
static_cast<float>(current_step) / kTotalSteps);
3047 app::platform::WasmLoadingManager::UpdateProgress(loading_handle, progress);
3048 app::platform::WasmLoadingManager::UpdateMessage(loading_handle, message);
3051 auto cleanup_loading = [&]() {
3052 app::platform::WasmLoadingManager::EndLoading(loading_handle);
3054 struct LoadingGuard {
3055 std::function<void()> cleanup;
3056 bool dismissed =
false;
3061 void dismiss() { dismissed =
true; }
3062 } loading_guard{cleanup_loading};
3064 (void)passed_handle;
3073 const std::unordered_set<EditorType> preload_types(
3074 preload_editor_list.begin(), preload_editor_list.end());
3082 const InitStep init_steps[] = {
3089 for (
const auto& step : init_steps) {
3090 if (!preload_types.contains(step.type)) {
3093 if (
auto* editor = current_editor_set->GetEditor(step.type)) {
3094 editor->Initialize();
3096 if (step.mark_loaded) {
3102#ifdef __EMSCRIPTEN__
3103 update_progress(
"Loading graphics sheets...");
3108 current_session->game_data_loaded =
true;
3112 current_session->game_data.gfx_bitmaps;
3116 auto* game_data = ¤t_session->game_data;
3117 current_editor_set->SetGameData(game_data);
3121 const char* progress_message;
3123 const LoadStep load_steps[] = {
3133 for (
const auto& step : load_steps) {
3134 if (!preload_types.contains(step.type)) {
3137#ifdef __EMSCRIPTEN__
3138 update_progress(step.progress_message);
3140 if (
auto* editor = current_editor_set->GetEditor(step.type)) {
3146#ifdef __EMSCRIPTEN__
3147 update_progress(
"Finishing up...");
3152 auto* settings = current_editor_set->GetSettingsPanel();
3161#ifdef __EMSCRIPTEN__
3163 loading_guard.dismiss();
3164 app::platform::WasmLoadingManager::EndLoading(loading_handle);
3167 auto end_time = std::chrono::steady_clock::now();
3168 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
3169 end_time - start_time);
3170 LOG_DEBUG(
"EditorManager",
"ROM assets loaded in %lld ms", duration.count());
3172 return absl::OkStatus();
3178 if (!current_rom || !current_editor_set) {
3179 return absl::FailedPreconditionError(
"No ROM or editor set loaded");
3183 if (!current_session) {
3184 return absl::FailedPreconditionError(
"No active ROM session");
3188#ifdef __EMSCRIPTEN__
3190 auto loading_handle =
3192 ?
static_cast<app::platform::WasmLoadingManager::LoadingHandle
>(
3194 : app::platform::WasmLoadingManager::BeginLoading(
3195 "Loading ROM (lazy assets)");
3196 auto cleanup_loading = [&]() {
3197 app::platform::WasmLoadingManager::EndLoading(loading_handle);
3199 struct LoadingGuard {
3200 std::function<void()> cleanup;
3201 bool dismissed =
false;
3207 void dismiss() { dismissed =
true; }
3208 } loading_guard{cleanup_loading};
3210 (void)passed_handle;
3220 auto* settings = current_editor_set->GetSettingsPanel();
3227#ifdef __EMSCRIPTEN__
3228 loading_guard.dismiss();
3229 app::platform::WasmLoadingManager::EndLoading(loading_handle);
3232 LOG_INFO(
"EditorManager",
"Lazy asset mode: editor assets deferred");
3233 return absl::OkStatus();
3262 if (!current_rom || !current_editor_set) {
3263 return absl::FailedPreconditionError(
"No ROM or editor set loaded");
3268 return absl::CancelledError(
"Save pending confirmation");
3274 return absl::CancelledError(
"Save pending confirmation");
3277 const bool pot_items_enabled =
3281 const int loaded_rooms = current_editor_set->LoadedDungeonRoomCount();
3282 const int total_rooms = current_editor_set->TotalDungeonRoomCount();
3283 if (loaded_rooms < total_rooms) {
3291 "Save paused: pot items enabled with %d unloaded rooms",
3294 return absl::CancelledError(
"Pot item save confirmation required");
3302 struct PotItemFlagGuard {
3303 bool restore =
false;
3304 bool previous =
false;
3305 ~PotItemFlagGuard() {
3307 core::FeatureFlags::get().dungeon.kSavePotItems = previous;
3312 if (suppress_pot_items) {
3314 pot_item_guard.restore =
true;
3316 }
else if (bypass_confirm) {
3365 std::vector<std::pair<uint32_t, uint32_t>> write_ranges;
3366 bool diff_computed =
false;
3368 if (!current_rom->filename().empty()) {
3369 std::ifstream file(current_rom->filename(), std::ios::binary);
3370 if (file.is_open()) {
3371 file.seekg(0, std::ios::end);
3372 const std::streampos end = file.tellg();
3374 std::vector<uint8_t> disk_data(
static_cast<size_t>(end));
3375 file.seekg(0, std::ios::beg);
3376 file.read(
reinterpret_cast<char*
>(disk_data.data()),
3377 static_cast<std::streamsize
>(disk_data.size()));
3379 diff_computed =
true;
3381 current_rom->vector());
3382 if (!diff.ranges.empty()) {
3384 "ROM save diff: %zu bytes changed in %zu range(s)",
3385 diff.total_bytes_changed, diff.ranges.size());
3386 write_ranges = std::move(diff.ranges);
3393 if (write_ranges.empty() && !diff_computed) {
3394 write_ranges = current_editor_set->CollectDungeonWriteRanges();
3397 if (!write_ranges.empty()) {
3400 if (!conflicts.empty()) {
3407 "Save paused: %zu write conflict(s) with ASM hooks",
3410 return absl::CancelledError(
"Write conflict confirmation required");
3421 if (save_status.ok()) {
3431 return absl::FailedPreconditionError(
"No ROM loaded");
3439 if (save_status.ok()) {
3444 session->filepath = filename;
3450 manager.AddFile(filename);
3458 LOG_INFO(
"EditorManager",
"OpenRomOrProject called with: '%s'",
3460 if (filename.empty()) {
3461 LOG_INFO(
"EditorManager",
"Empty filename provided, skipping load.");
3462 return absl::OkStatus();
3465#ifdef __EMSCRIPTEN__
3467 auto loading_handle =
3468 app::platform::WasmLoadingManager::BeginLoading(
"Loading ROM");
3469 app::platform::WasmLoadingManager::UpdateMessage(loading_handle,
3470 "Reading ROM file...");
3472 struct LoadingGuard {
3473 app::platform::WasmLoadingManager::LoadingHandle handle;
3474 bool dismissed =
false;
3477 app::platform::WasmLoadingManager::EndLoading(handle);
3479 void dismiss() { dismissed =
true; }
3480 } loading_guard{loading_handle};
3483 if (absl::EndsWith(filename,
".yaze") ||
3484 absl::EndsWith(filename,
".zsproj") ||
3485 absl::EndsWith(filename,
".yazeproj")) {
3499#ifdef __EMSCRIPTEN__
3500 app::platform::WasmLoadingManager::UpdateProgress(loading_handle, 0.05f);
3501 app::platform::WasmLoadingManager::UpdateMessage(loading_handle,
3502 "Loading ROM data...");
3509 std::move(temp_rom), filename);
3510 if (!session_or.ok()) {
3511 return session_or.status();
3529#ifdef YAZE_ENABLE_TESTING
3530 LOG_DEBUG(
"EditorManager",
"Setting ROM in TestManager - %p ('%s')",
3538 const std::string absolute_code_folder =
3543#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
3544 editor_set->OpenAssemblyFolder(absolute_code_folder);
3550#ifdef __EMSCRIPTEN__
3551 app::platform::WasmLoadingManager::UpdateProgress(loading_handle, 0.10f);
3552 app::platform::WasmLoadingManager::UpdateMessage(loading_handle,
3553 "Initializing editors...");
3556 loading_guard.dismiss();
3572 return absl::OkStatus();
3585#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
3596 auto open_project_from_path =
3597 [
this](
const std::string& file_path) -> absl::Status {
3598 if (file_path.empty()) {
3599 return absl::OkStatus();
3606 auto validation_status = new_project.
Validate();
3607 if (!validation_status.ok()) {
3609 validation_status.message()),
3627#if defined(__APPLE__) && TARGET_OS_IOS == 1
3631 return absl::OkStatus();
3634 return open_project_from_path(file_path);
3643 "Project has no ROM file configured. Please select a ROM.",
3645#if defined(__APPLE__) && TARGET_OS_IOS == 1
3653 auto bundle_parent =
3655 if (bundle_parent.extension() ==
".yazeproj") {
3657 "ROM is downloading from iCloud. Reopen the project in a few "
3660 return absl::OkStatus();
3665 [
this](
const std::string& rom_path) {
3666 if (rom_path.empty()) {
3671 if (!save_status.ok()) {
3673 absl::StrFormat(
"Failed to update project ROM: %s",
3674 save_status.message()),
3681 absl::StrFormat(
"Failed to load project ROM: %s",
3686 return absl::OkStatus();
3690 if (rom_path.empty()) {
3691 return absl::OkStatus();
3703 if (!load_status.ok()) {
3706 absl::StrFormat(
"Could not load ROM '%s': %s. Please select a new ROM.",
3709#if defined(__APPLE__) && TARGET_OS_IOS == 1
3717 if (rom_parent.extension() ==
".yazeproj") {
3719 "ROM is still downloading from iCloud. Try reopening the project "
3722 return absl::OkStatus();
3727 [
this](
const std::string& rom_path) {
3728 if (rom_path.empty()) {
3733 if (!save_status.ok()) {
3735 absl::StrFormat(
"Failed to update project ROM: %s",
3736 save_status.message()),
3743 absl::StrFormat(
"Failed to load project ROM: %s",
3748 return absl::OkStatus();
3752 if (rom_path.empty()) {
3753 return absl::OkStatus();
3765 if (!session_or.ok()) {
3766 return session_or.status();
3780 "Project has custom object data but 'enable_custom_objects' was "
3781 "disabled. Enabling at runtime.");
3785 std::string legacy_mapping_warning;
3787 &legacy_mapping_warning)) {
3788 LOG_WARN(
"EditorManager",
"%s", legacy_mapping_warning.c_str());
3790 "Seeded default custom object mapping for object 0x31 (save project "
3802 "Feature flags applied: kEnableCustomObjects=%s, "
3803 "custom_objects_folder='%s', custom_object_files=%zu entries",
3839 "Project ROM hash mismatch detected. Check ROM Identity settings.",
3842 auto warnings = ValidateRomAddressOverrides(
3844 if (!warnings.empty()) {
3845 for (
const auto& warning : warnings) {
3846 LOG_WARN(
"EditorManager",
"%s", warning.c_str());
3856#ifdef YAZE_ENABLE_TESTING
3857 LOG_DEBUG(
"EditorManager",
"Setting ROM in TestManager - %p ('%s')",
3865 const std::string absolute_code_folder =
3868#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
3869 editor_set->OpenAssemblyFolder(absolute_code_folder);
3936 return absl::OkStatus();
3965 for (
const auto& file : manager.GetRecentFiles()) {
3976 auto lifecycle_decision =
3978 static_cast<int>(decision));
3989 }
else if (!absl::IsCancelled(status)) {
3991 absl::StrFormat(
"Failed to save ROM: %s", status.message()),
4000 :
"untitled_project";
4004 if (file_path.empty()) {
4005 return absl::OkStatus();
4009 if (!(absl::EndsWith(file_path,
".yaze") ||
4010 absl::EndsWith(file_path,
".yazeproj"))) {
4011 file_path +=
".yaze";
4019 if (save_status.ok()) {
4024 manager.AddFile(file_path);
4033 absl::StrFormat(
"Failed to save project: %s", save_status.message()),
4042 return absl::FailedPreconditionError(
"No project open");
4049 if (command.empty()) {
4050 return absl::NotFoundError(
"Project does not define a build command");
4057 return absl::FailedPreconditionError(
"No project open");
4064 if (target.empty()) {
4067 if (target.empty()) {
4068 return absl::NotFoundError(
"Project does not define a run target ROM");
4074 const std::string& summary,
const std::string& detail,
4076 bool can_cancel)
const {
4078 .can_cancel = can_cancel,
4082 .output_tail = output_tail,
4087 const std::string& summary,
const std::string& detail,
4098 if (!command_or.ok()) {
4099 return command_or.status();
4102 const std::string command = *command_or;
4103 const std::filesystem::path project_root =
4106 auto start_status = task.
Start(command, project_root.string());
4107 if (!start_status.ok()) {
4108 return start_status;
4110 auto wait_status = task.
Wait();
4112 if (!wait_status.ok()) {
4115 const std::string summary = LastNonEmptyLine(snapshot.output);
4116 return summary.empty() ? command : summary;
4120 const std::string running_detail =
4121 "Running the configured project build command";
4122 UpdateBuildWorkflowStatus(
4128 if (!result_or.ok()) {
4129 UpdateBuildWorkflowStatus(
4132 std::string(result_or.status().message()),
4135 absl::StrFormat(
"Build unavailable: %s", result_or.status().message()),
4137 return result_or.status();
4140 const std::string summary = *result_or;
4145 summary.empty() ?
"Project build completed"
4146 : absl::StrFormat(
"Project build completed: %s", summary),
4148 LOG_INFO(
"EditorManager",
"Project build completed: %s", summary.c_str());
4149 return absl::OkStatus();
4155 if (snapshot.running) {
4163 if (!command_or.ok()) {
4164 UpdateBuildWorkflowStatus(
4167 std::string(command_or.status().message()),
4170 absl::StrFormat(
"Build unavailable: %s", command_or.status().message()),
4175 const std::filesystem::path project_root =
4180 if (!start_status.ok()) {
4181 UpdateBuildWorkflowStatus(
4184 std::string(start_status.message()),
4187 absl::StrFormat(
"Build unavailable: %s", start_status.message()),
4194 UpdateBuildWorkflowStatus(
4197 "Running the configured project build command",
4211 if (!snapshot.running) {
4216 UpdateBuildWorkflowStatus(
4218 MakeBuildStatus(
"Cancelling build",
"Stopping the active project build",
4224 UpdateRunWorkflowStatus(
4227 "Preparing the project output for emulator reload",
4231 if (!run_target_or.ok()) {
4232 UpdateRunWorkflowStatus(
4235 std::string(run_target_or.status().message()),
4238 run_target_or.status().message()),
4240 return run_target_or.status();
4242 const std::string run_target = *run_target_or;
4243 if (!std::filesystem::exists(run_target)) {
4249 return absl::NotFoundError(
"Run target ROM not found");
4252#ifdef YAZE_WITH_GRPC
4254 auto load_status = emulator_backend->LoadRom(run_target);
4255 if (load_status.ok()) {
4256 AppendWorkflowHistoryEntry(
4268 absl::StrFormat(
"Reloaded project output in emulator backend: %s",
4271 return absl::OkStatus();
4278 if (!load_rom_status.ok()) {
4279 UpdateRunWorkflowStatus(
4281 MakeRunStatus(
"Run load failed", std::string(load_rom_status.message()),
4284 load_rom_status.message()),
4286 return load_rom_status;
4290 if (!reload_status.ok()) {
4291 UpdateRunWorkflowStatus(
4293 MakeRunStatus(
"Reload failed", std::string(reload_status.message()),
4296 reload_status.message()),
4298 return reload_status;
4304 AppendWorkflowHistoryEntry(
"Run",
4312 absl::StrFormat(
"Reloaded project output in emulator: %s", run_target),
4314 return absl::OkStatus();
4324 return absl::OkStatus();
4329 return absl::FailedPreconditionError(
"No project is currently open");
4336 return absl::OkStatus();
4341 return editor_set->GetOverworldData();
4348 return absl::InvalidArgumentError(
"Invalid ROM pointer");
4357 if (session && &session->rom == rom) {
4363 return absl::OkStatus();
4369 return absl::NotFoundError(
"ROM not found in existing sessions");
4391 return absl::FailedPreconditionError(
"No ROM loaded");
4393 const std::string original_filename = rom->
filename();
4395 if (!original_filename.empty()) {
4457 int pending_editor =
4459 if (pending_editor < 0) {
4465 if (pending_layout < 0) {
4480 EditorType type,
size_t session_index)
const {
4481 const char* base_name =
kEditorNames[
static_cast<int>(type)];
4483 base_name, session_index)
4484 : std::string(base_name);
4490#ifdef YAZE_BUILD_AGENT_UI
4500 absl::StrFormat(
"Failed to prepare %s: %s",
4529 : manager_(manager),
4530 prev_rom_(manager->GetCurrentRom()),
4531 prev_editor_set_(manager->GetCurrentEditorSet()),
4532 prev_session_id_(manager->GetCurrentSessionId()) {
4539 manager_->session_coordinator_->SwitchToSession(prev_session_id_);
4590 absl::StrFormat(
"Failed to load project file: %s", status.message()),
4602 size_t session_id) {
static Application & Instance()
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
const auto & vector() 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.
const BuildPipeline & build_pipeline() const
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 SetProjectContext(project::YazeProject *project)
void ApplyUserSettingsDefaults(bool force=false)
void SetAssemblySymbolTableContext(const std::map< std::string, core::AsarSymbol > *table)
AgentEditor * GetAgentEditor()
void Initialize(ToastManager *toast_manager, ProposalDrawer *proposal_drawer, RightDrawerManager *right_drawer_manager, WorkspaceWindowManager *window_manager, UserSettings *user_settings)
void SetAsarWrapperContext(core::AsarWrapper *asar_wrapper)
Snapshot GetSnapshot() const
absl::Status Start(const std::string &command, const std::string &directory)
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_
RomLifecycleManager rom_lifecycle_
StartupVisibility welcome_mode_override_
void InitializeTestSuites()
void ApplyDefaultBackupPolicy()
std::vector< EditorType > CollectEditorsToPreload(EditorSet *editor_set) const
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_
void QueueBuildCurrentProject()
std::unique_ptr< RightDrawerManager > right_drawer_manager_
AgentUiController agent_ui_
void SetCurrentEditor(Editor *editor) override
bool SaveLayoutSnapshotAs(const std::string &name)
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
absl::StatusOr< std::string > RunProjectBuildCommand()
void InitializeServices()
void ApplyLayoutDefaultsMigrationIfNeeded()
void SwitchToSession(size_t index)
bool active_project_build_reported_
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.
std::vector< std::string > ListLayoutSnapshots() const
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()
absl::Status RunCurrentProject()
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_
std::string startup_editor_hint_
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)
WorkspaceWindowManager window_manager_
auto GetCurrentEditor() const -> Editor *
bool show_rom_load_options_
absl::Status SaveProject()
void SetStartupLoadHints(const AppConfig &config)
absl::Status LoadAssetsLazy(uint64_t loading_handle=0)
absl::StatusOr< std::string > ResolveProjectBuildCommand() const
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()
absl::Status BuildCurrentProject()
StartupVisibility sidebar_mode_override_
RomLoadOptionsDialog rom_load_options_dialog_
absl::Status LoadRom()
Load a ROM file into a new or existing session.
std::vector< std::string > startup_panel_hints_
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()
void RefreshHackWorkflowBackend()
static bool IsPanelBasedEditor(EditorType type)
absl::Status Update()
Main update loop for the editor application.
void SetupSidebarCallbacks()
size_t GetCurrentSessionIndex() const
absl::StatusOr< std::string > ResolveProjectRunTarget() const
absl::Status ImportProject(const std::string &project_path)
size_t GetCurrentSessionId() const
void ClearTemporaryLayoutSnapshot()
ProjectWorkflowStatus MakeRunStatus(const std::string &summary, const std::string &detail, ProjectWorkflowState state) const
void QueueDeferredAction(std::function< void()> action)
SelectionPropertiesPanel selection_properties_panel_
WindowDelegate window_delegate_
bool DeleteLayoutSnapshot(const std::string &name)
void ConfigureSession(RomSession *session) override
std::unique_ptr< ActivityBar > activity_bar_
ShortcutManager shortcut_manager_
bool IsRomHashMismatch() const
bool RestoreLayoutSnapshot(const std::string &name, bool remove_after_restore=false)
void RefreshResourceLabelProvider()
void MarkEditorInitialized(RomSession *session, EditorType type)
void SyncLayoutScopeFromCurrentProject()
std::unique_ptr< BackgroundCommandTask > active_project_build_
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_
std::unique_ptr< workflow::HackWorkflowBackend > hack_workflow_backend_
absl::Status OpenRomOrProject(const std::string &filename)
void RemoveSession(size_t index)
absl::Status CheckOracleRomSafetyPreSave(Rom *rom)
UiSyncState GetUiSyncStateSnapshot() const
void PollProjectWorkflowTasks()
ProjectWorkflowStatus MakeBuildStatus(const std::string &summary, const std::string &detail, ProjectWorkflowState state, const std::string &output_tail="", bool can_cancel=false) const
void HandleSessionSwitched(size_t new_index, RomSession *session)
void CancelQueuedProjectBuild()
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()
std::unique_ptr< WindowHost > window_host_
void CaptureTemporaryLayoutSnapshot()
void HandleSessionCreated(size_t index, RomSession *session)
bool EditorRequiresGameData(EditorType type) const
ToastManager * toast_manager()
RomFileManager rom_file_manager_
void ResetCurrentEditorLayout()
static bool UpdateAllowedWithoutLoadedRom(EditorType type)
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 GetEditorName(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)
GfxGroupWorkspaceState * gfx_group_workspace()
SettingsPanel * GetSettingsPanel() const
std::vector< Editor * > active_editors_
Interface for editor classes.
virtual void ContributeStatus(StatusBar *)
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 > GetDefaultWindows(EditorType type)
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.
Panel for managing project settings, ROM versions, and snapshots.
void SetBuildStatus(const ProjectWorkflowStatus &status)
void SetRunStatus(const ProjectWorkflowStatus &status)
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 GetDefaultDrawerWidth(DrawerType type, EditorType editor=EditorType::kUnknown)
Get the default width for a specific drawer 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()
absl::Status CheckRomOpenPolicy(Rom *rom)
Validate that the loaded ROM is a safe project target to open/edit.
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)
A session-aware status bar displayed at the bottom of the application.
void ClearProjectWorkflowStatus()
void SetSessionInfo(size_t session_id, size_t total_sessions)
Set session information.
void SetBuildStatus(const ProjectWorkflowStatus &status)
void SetRunStatus(const ProjectWorkflowStatus &status)
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 ClearEditorContributions()
Clear frame-scoped editor contributions.
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 SetOpenAssemblyEditorNoRomCallback(std::function< void()> callback)
Open the assembly editor for file/folder work (no ROM required).
void SetOpenRomCallback(std::function< void()> callback)
Set callback for opening ROM.
void SetOpenPrototypeResearchCallback(std::function< void()> callback)
Open the graphics editor focused on prototype research (no 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_window_manager(WorkspaceWindowManager *manager)
void set_layout_manager(LayoutManager *manager)
void EnableFileBrowser(const std::string &category, const std::string &root_path="")
void SetEventBus(EventBus *event_bus)
size_t GetActiveSessionId() const
void SetSidebarVisible(bool visible, bool notify=true)
std::vector< WindowDescriptor > GetWindowsInCategory(size_t session_id, const std::string &category) const
void TriggerShowShortcuts()
void SetEditorResolver(std::function< Editor *(const std::string &)> resolver)
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 SetPanelBrowserCategoryWidthChangedCallback(std::function< void(float)> cb)
const WindowDescriptor * GetWindowDescriptor(size_t session_id, const std::string &base_window_id) const
void ToggleSidebarVisibility()
const std::unordered_map< std::string, WindowDescriptor > & GetAllWindowDescriptors() const
Get all panel descriptors (for layout designer, panel browser, etc.)
void SetActiveCategory(const std::string &category, bool notify=true)
void SetSidebarStateChangedCallback(std::function< void(bool, bool)> cb)
void TriggerShowCommandPalette()
void RegisterRegistryWindowContent(std::unique_ptr< WindowContent > window)
Register a ContentRegistry-managed WindowContent instance.
std::string GetActiveCategory() const
void RegisterWindowContent(std::unique_ptr< WindowContent > window)
Register a WindowContent instance for central drawing.
static constexpr const char * kDashboardCategory
std::vector< std::string > GetVisibleWindowIds(size_t session_id) const
Get list of currently visible panel IDs for a session.
void RegisterWindow(size_t session_id, const WindowDescriptor &descriptor)
void SetStoredSidePanelWidth(float width, bool notify=false)
void SetCategoryChangedCallback(std::function< void(const std::string &)> cb)
void SetFileBrowserPath(const std::string &category, const std::string &path)
void SetOnWindowCategorySelectedCallback(std::function< void(const std::string &)> callback)
void SetOnWindowClickedCallback(std::function< void(const std::string &)> callback)
bool OpenWindow(size_t session_id, const std::string &base_window_id)
void DrawVisibleWindows()
void TriggerShowSettings()
void SetSidePanelWidthChangedCallback(std::function< void(float)> cb)
void SetWindowBrowserCategoryWidth(float width, bool notify=true)
void RegisterRegistryWindowContentsForSession(size_t session_id)
Register descriptors for all registry window contents in a session.
void SetFileClickedCallback(std::function< void(const std::string &category, const std::string &path)> callback)
bool IsSidebarVisible() const
void SetSidebarExpanded(bool expanded, bool notify=true)
bool * GetWindowVisibilityFlag(size_t session_id, const std::string &base_window_id)
void RestorePinnedState(const std::unordered_map< std::string, bool > &state)
Restore pinned panel state from persistence.
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 MarkWindowRecentlyUsed(const std::string &window_id)
void set_window_manager(editor::WorkspaceWindowManager *manager)
bool is_audio_focus_mode() const
void set_renderer(gfx::IRenderer *renderer)
bool is_snes_initialized() const
auto running() const -> bool
absl::Status ReloadRuntimeRom(const std::vector< uint8_t > &rom_data)
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 ClearWorkspaceTransitionState()
RAII guard for ImGui style colors.
void ApplyTheme(const std::string &theme_name)
void SetOnThemeChangedCallback(ThemeChangedCallback callback)
static ThemeManager & Get()
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...
static const std::vector< std::string > & DefaultSubtypeFilenamesForObject(int object_id)
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_FOLDER_OPEN
#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 ClearWorkflowHistory()
void SetGlobalContext(GlobalEditorContext *ctx)
void SetShowWorkflowOutputCallback(std::function< void()> callback)
void SetEditorWindowContext(const std::string &category, Editor *editor)
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 AppendWorkflowHistory(const ProjectWorkflowHistoryEntry &entry)
void SetRunProjectWorkflowCallback(std::function< void()> callback)
void SetBuildWorkflowStatus(const ProjectWorkflowStatus &status)
void SetCancelBuildWorkflowCallback(std::function< void()> callback)
void SetBuildWorkflowLog(const std::string &output)
void SetStartBuildWorkflowCallback(std::function< void()> callback)
void SetRunWorkflowStatus(const ProjectWorkflowStatus &status)
void SetHackWorkflowBackend(workflow::HackWorkflowBackend *backend)
void Clear()
Clear all context state.
void SetCurrentProject(::yaze::project::YazeProject *project)
Set the current project instance.
std::vector< std::unique_ptr< WindowContent > > CreateAll()
Create new instances of all registered panels.
void UpdateBuildWorkflowStatus(StatusBar *status_bar, ProjectManagementPanel *project_panel, const ProjectWorkflowStatus &status)
void UpdateRunWorkflowStatus(StatusBar *status_bar, ProjectManagementPanel *project_panel, const ProjectWorkflowStatus &status)
constexpr int kTrackCustomObjectId
std::string LastNonEmptyLine(const std::string &text)
bool HasAnyOverride(const core::RomAddressOverrides &overrides, std::initializer_list< const char * > keys)
bool ProjectUsesCustomObjects(const project::YazeProject &project)
void AppendWorkflowHistoryEntry(const std::string &kind, const ProjectWorkflowStatus &status, const std::string &output_log)
std::string StripSessionPrefix(absl::string_view panel_id)
bool SeedLegacyTrackObjectMapping(project::YazeProject *project, std::string *warning)
std::vector< std::string > ValidateRomAddressOverrides(const core::RomAddressOverrides &overrides, const Rom &rom)
std::optional< EditorType > ParseEditorTypeFromString(absl::string_view name)
void SeedOracleProjectInRecents()
std::unique_ptr< HackWorkflowBackend > CreateHackWorkflowBackendForProject(const project::YazeProject *project)
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
std::function< EditorSet *()> get_current_editor_set
std::function< void(std::function< void()>)> queue_deferred_action
ToastManager * toast_manager
RightDrawerManager * right_drawer_manager
UICoordinator * ui_coordinator
std::function< size_t()> get_current_session_id
std::function< absl::Status(EditorType)> ensure_editor_assets_loaded
WorkspaceWindowManager * window_manager
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
WorkspaceWindowManager * window_manager
PopupManager * popup_manager
GfxGroupWorkspaceState * gfx_group_workspace
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.
ToastManager * toast_manager
UICoordinator * ui_coordinator
LayoutManager * layout_manager
WorkspaceWindowManager * window_manager
RightDrawerManager * right_drawer_manager
Built-in workflow-oriented layout profiles.
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
WorkspaceWindowManager * window_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
std::string last_theme_name
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
Declarative registration contract for editor windows.
std::string shortcut_hint
Metadata for a dockable editor window (formerly PanelInfo)
std::function< void()> on_show
std::string shortcut_hint
std::function< void()> on_hide
WindowContextScope context_scope
WindowLifecycle window_lifecycle
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