diff --git a/src/app/editor/dungeon/dungeon_editor.cc b/src/app/editor/dungeon/dungeon_editor.cc index cca59107..27f503fc 100644 --- a/src/app/editor/dungeon/dungeon_editor.cc +++ b/src/app/editor/dungeon/dungeon_editor.cc @@ -1,6 +1,7 @@ #include "dungeon_editor.h" #include "absl/strings/str_format.h" +#include "app/core/performance_monitor.h" #include "app/core/window.h" #include "app/gfx/arena.h" #include "app/gfx/snes_palette.h" @@ -46,6 +47,8 @@ void DungeonEditor::Initialize() { } absl::Status DungeonEditor::Load() { + core::ScopedTimer timer("DungeonEditor::Load"); + if (!rom_ || !rom_->is_loaded()) { return absl::FailedPreconditionError("ROM not loaded"); } @@ -53,22 +56,38 @@ absl::Status DungeonEditor::Load() { auto dungeon_man_pal_group = rom()->palette_group().dungeon_main; // Use room loader component for loading rooms - RETURN_IF_ERROR(room_loader_.LoadAllRooms(rooms_)); - RETURN_IF_ERROR(room_loader_.LoadRoomEntrances(entrances_)); + { + core::ScopedTimer rooms_timer("DungeonEditor::LoadAllRooms"); + RETURN_IF_ERROR(room_loader_.LoadAllRooms(rooms_)); + } + + { + core::ScopedTimer entrances_timer("DungeonEditor::LoadRoomEntrances"); + RETURN_IF_ERROR(room_loader_.LoadRoomEntrances(entrances_)); + } // Load the palette group and palette for the dungeon - full_palette_ = dungeon_man_pal_group[current_palette_group_id_]; - ASSIGN_OR_RETURN(current_palette_group_, - gfx::CreatePaletteGroupFromLargePalette(full_palette_)); + { + core::ScopedTimer palette_timer("DungeonEditor::LoadPalettes"); + full_palette_ = dungeon_man_pal_group[current_palette_group_id_]; + ASSIGN_OR_RETURN(current_palette_group_, + gfx::CreatePaletteGroupFromLargePalette(full_palette_)); + } // Calculate usage statistics - usage_tracker_.CalculateUsageStats(rooms_); + { + core::ScopedTimer usage_timer("DungeonEditor::CalculateUsageStats"); + usage_tracker_.CalculateUsageStats(rooms_); + } // Initialize the new editor system - if (dungeon_editor_system_) { - auto status = dungeon_editor_system_->Initialize(); - if (!status.ok()) { - return status; + { + core::ScopedTimer init_timer("DungeonEditor::InitializeSystem"); + if (dungeon_editor_system_) { + auto status = dungeon_editor_system_->Initialize(); + if (!status.ok()) { + return status; + } } } diff --git a/src/app/editor/editor_manager.cc b/src/app/editor/editor_manager.cc index 4e966059..5723b503 100644 --- a/src/app/editor/editor_manager.cc +++ b/src/app/editor/editor_manager.cc @@ -8,6 +8,7 @@ #include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "app/core/features.h" +#include "app/core/performance_monitor.h" #include "app/core/platform/file_dialog.h" #include "app/core/project.h" #include "app/editor/code/assembly_editor.h" @@ -20,18 +21,18 @@ #include "app/editor/sprite/sprite_editor.h" #include "app/emu/emulator.h" #include "app/gfx/arena.h" +#include "app/gui/background_renderer.h" #include "app/gui/icons.h" #include "app/gui/input.h" #include "app/gui/style.h" #include "app/gui/theme_manager.h" -#include "app/gui/background_renderer.h" #include "app/rom.h" -#include "app/zelda3/overworld/overworld_map.h" #include "app/test/test_manager.h" +#include "app/zelda3/overworld/overworld_map.h" #ifdef YAZE_ENABLE_TESTING +#include "app/test/e2e_test_suite.h" #include "app/test/integrated_test_suite.h" #include "app/test/rom_dependent_test_suite.h" -#include "app/test/e2e_test_suite.h" #include "app/test/zscustomoverworld_test_suite.h" #endif #ifdef YAZE_ENABLE_GTEST @@ -66,17 +67,20 @@ void EditorManager::LoadUserSettings() { std::string line; while (std::getline(ss, line)) { auto eq = line.find('='); - if (eq == std::string::npos) continue; + if (eq == std::string::npos) + continue; auto key = line.substr(0, eq); auto val = line.substr(eq + 1); - if (key == "font_global_scale") font_global_scale_ = std::stof(val); - if (key == "autosave_enabled") autosave_enabled_ = (val == "1"); - if (key == "autosave_interval_secs") autosave_interval_secs_ = std::stof(val); + if (key == "font_global_scale") + font_global_scale_ = std::stof(val); + if (key == "autosave_enabled") + autosave_enabled_ = (val == "1"); + if (key == "autosave_interval_secs") + autosave_interval_secs_ = std::stof(val); } ImGui::GetIO().FontGlobalScale = font_global_scale_; } - } catch (...) { - } + } catch (...) {} } void EditorManager::SaveUserSettings() { @@ -92,7 +96,7 @@ void EditorManager::RefreshWorkspacePresets() { try { // Create a new vector instead of clearing to avoid corruption std::vector new_presets; - + // Try to read a simple index file of presets try { auto data = core::LoadConfigFile("workspace_presets.txt"); @@ -103,7 +107,8 @@ void EditorManager::RefreshWorkspacePresets() { // Trim whitespace and validate name.erase(0, name.find_first_not_of(" \t\r\n")); name.erase(name.find_last_not_of(" \t\r\n") + 1); - if (!name.empty() && name.length() < 256) { // Reasonable length limit + if (!name.empty() && + name.length() < 256) { // Reasonable length limit new_presets.emplace_back(std::move(name)); } } @@ -111,35 +116,39 @@ void EditorManager::RefreshWorkspacePresets() { } catch (const std::exception& e) { util::logf("Warning: Failed to load workspace presets: %s", e.what()); } - + // Safely replace the vector workspace_presets_ = std::move(new_presets); workspace_presets_loaded_ = true; - + } catch (const std::exception& e) { util::logf("Error in RefreshWorkspacePresets: %s", e.what()); // Ensure we have a valid empty vector workspace_presets_ = std::vector(); - workspace_presets_loaded_ = true; // Mark as loaded even if empty to avoid retry + workspace_presets_loaded_ = + true; // Mark as loaded even if empty to avoid retry } } -void EditorManager::SaveWorkspacePreset(const std::string &name) { - if (name.empty()) return; +void EditorManager::SaveWorkspacePreset(const std::string& name) { + if (name.empty()) + return; std::string ini_name = absl::StrCat("yaze_workspace_", name, ".ini"); ImGui::SaveIniSettingsToDisk(ini_name.c_str()); - + // Ensure presets are loaded before updating if (!workspace_presets_loaded_) { RefreshWorkspacePresets(); } - + // Update index - if (std::find(workspace_presets_.begin(), workspace_presets_.end(), name) == workspace_presets_.end()) { + if (std::find(workspace_presets_.begin(), workspace_presets_.end(), name) == + workspace_presets_.end()) { workspace_presets_.emplace_back(name); try { std::ostringstream ss; - for (const auto &n : workspace_presets_) ss << n << "\n"; + for (const auto& n : workspace_presets_) + ss << n << "\n"; core::SaveFile("workspace_presets.txt", ss.str()); } catch (const std::exception& e) { util::logf("Warning: Failed to save workspace presets: %s", e.what()); @@ -148,8 +157,9 @@ void EditorManager::SaveWorkspacePreset(const std::string &name) { last_workspace_preset_ = name; } -void EditorManager::LoadWorkspacePreset(const std::string &name) { - if (name.empty()) return; +void EditorManager::LoadWorkspacePreset(const std::string& name) { + if (name.empty()) + return; std::string ini_name = absl::StrCat("yaze_workspace_", name, ".ini"); ImGui::LoadIniSettingsFromDisk(ini_name.c_str()); last_workspace_preset_ = name; @@ -157,40 +167,43 @@ void EditorManager::LoadWorkspacePreset(const std::string &name) { void EditorManager::InitializeTestSuites() { auto& test_manager = test::TestManager::Get(); - + #ifdef YAZE_ENABLE_TESTING // Register comprehensive test suites test_manager.RegisterTestSuite(std::make_unique()); - test_manager.RegisterTestSuite(std::make_unique()); + test_manager.RegisterTestSuite( + std::make_unique()); test_manager.RegisterTestSuite(std::make_unique()); - test_manager.RegisterTestSuite(std::make_unique()); - + test_manager.RegisterTestSuite( + std::make_unique()); + // Register new E2E and ZSCustomOverworld test suites test_manager.RegisterTestSuite(std::make_unique()); - test_manager.RegisterTestSuite(std::make_unique()); + test_manager.RegisterTestSuite( + std::make_unique()); #endif - + // Register Google Test suite if available #ifdef YAZE_ENABLE_GTEST test_manager.RegisterTestSuite(std::make_unique()); #endif - + // Update resource monitoring to track Arena state test_manager.UpdateResourceStats(); } -constexpr const char *kOverworldEditorName = ICON_MD_LAYERS " Overworld Editor"; -constexpr const char *kGraphicsEditorName = ICON_MD_PHOTO " Graphics Editor"; -constexpr const char *kPaletteEditorName = ICON_MD_PALETTE " Palette Editor"; -constexpr const char *kScreenEditorName = ICON_MD_SCREENSHOT " Screen Editor"; -constexpr const char *kSpriteEditorName = ICON_MD_SMART_TOY " Sprite Editor"; -constexpr const char *kMessageEditorName = ICON_MD_MESSAGE " Message Editor"; -constexpr const char *kSettingsEditorName = ICON_MD_SETTINGS " Settings Editor"; -constexpr const char *kAssemblyEditorName = ICON_MD_CODE " Assembly Editor"; -constexpr const char *kDungeonEditorName = ICON_MD_CASTLE " Dungeon Editor"; -constexpr const char *kMusicEditorName = ICON_MD_MUSIC_NOTE " Music Editor"; +constexpr const char* kOverworldEditorName = ICON_MD_LAYERS " Overworld Editor"; +constexpr const char* kGraphicsEditorName = ICON_MD_PHOTO " Graphics Editor"; +constexpr const char* kPaletteEditorName = ICON_MD_PALETTE " Palette Editor"; +constexpr const char* kScreenEditorName = ICON_MD_SCREENSHOT " Screen Editor"; +constexpr const char* kSpriteEditorName = ICON_MD_SMART_TOY " Sprite Editor"; +constexpr const char* kMessageEditorName = ICON_MD_MESSAGE " Message Editor"; +constexpr const char* kSettingsEditorName = ICON_MD_SETTINGS " Settings Editor"; +constexpr const char* kAssemblyEditorName = ICON_MD_CODE " Assembly Editor"; +constexpr const char* kDungeonEditorName = ICON_MD_CASTLE " Dungeon Editor"; +constexpr const char* kMusicEditorName = ICON_MD_MUSIC_NOTE " Music Editor"; -void EditorManager::Initialize(const std::string &filename) { +void EditorManager::Initialize(const std::string& filename) { // Point to a blank editor set when no ROM is loaded current_editor_set_ = &blank_editor_set_; @@ -207,15 +220,15 @@ void EditorManager::Initialize(const std::string &filename) { // Load critical user settings first LoadUserSettings(); - + // Defer workspace presets loading to avoid initialization crashes // This will be called lazily when workspace features are accessed - + // Initialize testing system only when tests are enabled #ifdef YAZE_ENABLE_TESTING InitializeTestSuites(); #endif - + // TestManager will be updated when ROMs are loaded via SetCurrentRom calls context_.shortcut_manager.RegisterShortcut( @@ -224,29 +237,42 @@ void EditorManager::Initialize(const std::string &filename) { "Save", {ImGuiKey_S, ImGuiMod_Ctrl}, [this]() { status_ = SaveRom(); }); context_.shortcut_manager.RegisterShortcut( "Close", {ImGuiKey_W, ImGuiMod_Ctrl}, [this]() { - if (current_rom_) current_rom_->Close(); + if (current_rom_) + current_rom_->Close(); }); context_.shortcut_manager.RegisterShortcut( "Quit", {ImGuiKey_Q, ImGuiMod_Ctrl}, [this]() { quit_ = true; }); context_.shortcut_manager.RegisterShortcut( - "Undo", {ImGuiKey_Z, ImGuiMod_Ctrl}, - [this]() { if (current_editor_) status_ = current_editor_->Undo(); }); + "Undo", {ImGuiKey_Z, ImGuiMod_Ctrl}, [this]() { + if (current_editor_) + status_ = current_editor_->Undo(); + }); context_.shortcut_manager.RegisterShortcut( - "Redo", {ImGuiKey_Y, ImGuiMod_Ctrl}, - [this]() { if (current_editor_) status_ = current_editor_->Redo(); }); + "Redo", {ImGuiKey_Y, ImGuiMod_Ctrl}, [this]() { + if (current_editor_) + status_ = current_editor_->Redo(); + }); context_.shortcut_manager.RegisterShortcut( - "Cut", {ImGuiKey_X, ImGuiMod_Ctrl}, - [this]() { if (current_editor_) status_ = current_editor_->Cut(); }); + "Cut", {ImGuiKey_X, ImGuiMod_Ctrl}, [this]() { + if (current_editor_) + status_ = current_editor_->Cut(); + }); context_.shortcut_manager.RegisterShortcut( - "Copy", {ImGuiKey_C, ImGuiMod_Ctrl}, - [this]() { if (current_editor_) status_ = current_editor_->Copy(); }); + "Copy", {ImGuiKey_C, ImGuiMod_Ctrl}, [this]() { + if (current_editor_) + status_ = current_editor_->Copy(); + }); context_.shortcut_manager.RegisterShortcut( - "Paste", {ImGuiKey_V, ImGuiMod_Ctrl}, - [this]() { if (current_editor_) status_ = current_editor_->Paste(); }); + "Paste", {ImGuiKey_V, ImGuiMod_Ctrl}, [this]() { + if (current_editor_) + status_ = current_editor_->Paste(); + }); context_.shortcut_manager.RegisterShortcut( - "Find", {ImGuiKey_F, ImGuiMod_Ctrl}, - [this]() { if (current_editor_) status_ = current_editor_->Find(); }); + "Find", {ImGuiKey_F, ImGuiMod_Ctrl}, [this]() { + if (current_editor_) + status_ = current_editor_->Find(); + }); // Command Palette and Global Search context_.shortcut_manager.RegisterShortcut( @@ -268,33 +294,36 @@ void EditorManager::Initialize(const std::string &filename) { context_.shortcut_manager.RegisterShortcut( "F1", ImGuiKey_F1, [this]() { popup_manager_->Show("About"); }); - + // Testing shortcuts (only when tests are enabled) #ifdef YAZE_ENABLE_TESTING context_.shortcut_manager.RegisterShortcut( - "Test Dashboard", {ImGuiKey_T, ImGuiMod_Ctrl}, + "Test Dashboard", {ImGuiKey_T, ImGuiMod_Ctrl}, [this]() { show_test_dashboard_ = true; }); #endif - + // Workspace shortcuts context_.shortcut_manager.RegisterShortcut( - "New Session", std::vector{ImGuiKey_N, ImGuiMod_Ctrl, ImGuiMod_Shift}, + "New Session", + std::vector{ImGuiKey_N, ImGuiMod_Ctrl, ImGuiMod_Shift}, [this]() { CreateNewSession(); }); context_.shortcut_manager.RegisterShortcut( - "Close Session", std::vector{ImGuiKey_W, ImGuiMod_Ctrl, ImGuiMod_Shift}, + "Close Session", + std::vector{ImGuiKey_W, ImGuiMod_Ctrl, ImGuiMod_Shift}, [this]() { CloseCurrentSession(); }); context_.shortcut_manager.RegisterShortcut( - "Session Switcher", std::vector{ImGuiKey_Tab, ImGuiMod_Ctrl}, + "Session Switcher", std::vector{ImGuiKey_Tab, ImGuiMod_Ctrl}, [this]() { show_session_switcher_ = true; }); context_.shortcut_manager.RegisterShortcut( - "Save Layout", std::vector{ImGuiKey_S, ImGuiMod_Ctrl, ImGuiMod_Shift}, + "Save Layout", + std::vector{ImGuiKey_S, ImGuiMod_Ctrl, ImGuiMod_Shift}, [this]() { SaveWorkspaceLayout(); }); context_.shortcut_manager.RegisterShortcut( - "Load Layout", std::vector{ImGuiKey_O, ImGuiMod_Ctrl, ImGuiMod_Shift}, + "Load Layout", + std::vector{ImGuiKey_O, ImGuiMod_Ctrl, ImGuiMod_Shift}, [this]() { LoadWorkspaceLayout(); }); context_.shortcut_manager.RegisterShortcut( - "Maximize Window", ImGuiKey_F11, - [this]() { MaximizeCurrentWindow(); }); + "Maximize Window", ImGuiKey_F11, [this]() { MaximizeCurrentWindow(); }); // Initialize menu items std::vector recent_files; @@ -303,7 +332,7 @@ void EditorManager::Initialize(const std::string &filename) { if (manager.GetRecentFiles().empty()) { recent_files.emplace_back("No Recent Files", "", nullptr); } else { - for (const auto &filePath : manager.GetRecentFiles()) { + for (const auto& filePath : manager.GetRecentFiles()) { recent_files.emplace_back(filePath, "", [filePath, this]() { status_ = OpenRomOrProject(filePath); }); @@ -318,19 +347,32 @@ void EditorManager::Initialize(const std::string &filename) { "Save New Auto", "", [this]() { save_new_auto_ = !save_new_auto_; }, [this]() { return save_new_auto_; }); options_subitems.emplace_back( - "Autosave", "", [this]() { + "Autosave", "", + [this]() { autosave_enabled_ = !autosave_enabled_; - toast_manager_.Show(autosave_enabled_ ? "Autosave enabled" - : "Autosave disabled", - editor::ToastType::kInfo); + toast_manager_.Show( + autosave_enabled_ ? "Autosave enabled" : "Autosave disabled", + editor::ToastType::kInfo); }, [this]() { return autosave_enabled_; }); options_subitems.emplace_back( "Autosave Interval", "", [this]() {}, []() { return true; }, std::vector{ - {"1 min", "", [this]() { autosave_interval_secs_ = 60.0f; SaveUserSettings(); }}, - {"2 min", "", [this]() { autosave_interval_secs_ = 120.0f; SaveUserSettings(); }}, - {"5 min", "", [this]() { autosave_interval_secs_ = 300.0f; SaveUserSettings(); }}, + {"1 min", "", + [this]() { + autosave_interval_secs_ = 60.0f; + SaveUserSettings(); + }}, + {"2 min", "", + [this]() { + autosave_interval_secs_ = 120.0f; + SaveUserSettings(); + }}, + {"5 min", "", + [this]() { + autosave_interval_secs_ = 300.0f; + SaveUserSettings(); + }}, }); std::vector project_menu_subitems; @@ -340,23 +382,27 @@ void EditorManager::Initialize(const std::string &filename) { [this]() { status_ = OpenProject(); }); project_menu_subitems.emplace_back( "Save Project", "", [this]() { status_ = SaveProject(); }, - [this]() { return current_project_.project_opened(); }); - project_menu_subitems.emplace_back( - "Save Workspace Layout", "", [this]() { - ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); - ImGui::SaveIniSettingsToDisk("yaze_workspace.ini"); - toast_manager_.Show("Workspace layout saved", editor::ToastType::kSuccess); - }); - project_menu_subitems.emplace_back( - "Load Workspace Layout", "", [this]() { - ImGui::LoadIniSettingsFromDisk("yaze_workspace.ini"); - toast_manager_.Show("Workspace layout loaded", editor::ToastType::kSuccess); - }); + [this]() { return current_project_.project_opened(); }); + project_menu_subitems.emplace_back("Save Workspace Layout", "", [this]() { + ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); + ImGui::SaveIniSettingsToDisk("yaze_workspace.ini"); + toast_manager_.Show("Workspace layout saved", editor::ToastType::kSuccess); + }); + project_menu_subitems.emplace_back("Load Workspace Layout", "", [this]() { + ImGui::LoadIniSettingsFromDisk("yaze_workspace.ini"); + toast_manager_.Show("Workspace layout loaded", editor::ToastType::kSuccess); + }); project_menu_subitems.emplace_back( "Workspace Presets", "", []() {}, []() { return true; }, std::vector{ - {"Save Preset", "", [this]() { show_save_workspace_preset_ = true; }}, - {"Load Preset", "", [this]() { show_load_workspace_preset_ = true; }}, + {"Save Preset", "", + [this]() { + show_save_workspace_preset_ = true; + }}, + {"Load Preset", "", + [this]() { + show_load_workspace_preset_ = true; + }}, }); gui::kMainMenu = { @@ -721,27 +767,29 @@ absl::Status EditorManager::Update() { popup_manager_->DrawPopups(); ExecuteShortcuts(context_.shortcut_manager); toast_manager_.Draw(); - + // Draw background grid effects for the entire viewport if (ImGui::GetCurrentContext()) { ImDrawList* bg_draw_list = ImGui::GetBackgroundDrawList(); const ImGuiViewport* viewport = ImGui::GetMainViewport(); - + auto& theme_manager = gui::ThemeManager::Get(); auto current_theme = theme_manager.GetCurrentTheme(); auto& bg_renderer = gui::BackgroundRenderer::Get(); - + // Draw grid covering the entire main viewport ImVec2 grid_pos = viewport->WorkPos; ImVec2 grid_size = viewport->WorkSize; - bg_renderer.RenderDockingBackground(bg_draw_list, grid_pos, grid_size, current_theme.primary); + bg_renderer.RenderDockingBackground(bg_draw_list, grid_pos, grid_size, + current_theme.primary); } - + // Ensure TestManager always has the current ROM static Rom* last_test_rom = nullptr; if (last_test_rom != current_rom_) { - util::logf("EditorManager::Update - ROM changed, updating TestManager: %p -> %p", - (void*)last_test_rom, (void*)current_rom_); + util::logf( + "EditorManager::Update - ROM changed, updating TestManager: %p -> %p", + (void*)last_test_rom, (void*)current_rom_); test::TestManager::Get().SetCurrentRom(current_rom_); last_test_rom = current_rom_; } @@ -758,14 +806,14 @@ absl::Status EditorManager::Update() { if (st.ok()) { toast_manager_.Show("Autosave completed", editor::ToastType::kSuccess); } else { - toast_manager_.Show(std::string(st.message()), editor::ToastType::kError, 5.0f); + toast_manager_.Show(std::string(st.message()), + editor::ToastType::kError, 5.0f); } } } else { autosave_timer_ = 0.0f; } - // Check if ROM is loaded before allowing editor updates if (!current_editor_set_) { // Show welcome screen when no session is active, but only if not manually closed @@ -775,7 +823,7 @@ absl::Status EditorManager::Update() { // Don't auto-show here, let the manual control handle it return absl::OkStatus(); } - + // Check if current ROM is valid if (!current_rom_) { // Only show welcome screen for truly empty state, not when ROM is loaded but current_rom_ is null @@ -784,56 +832,68 @@ absl::Status EditorManager::Update() { } return absl::OkStatus(); } - + // ROM is loaded and valid - don't auto-show welcome screen // Welcome screen should only be shown manually at this point - + // Iterate through ALL sessions to support multi-session docking for (size_t session_idx = 0; session_idx < sessions_.size(); ++session_idx) { auto& session = sessions_[session_idx]; - if (!session.rom.is_loaded()) continue; // Skip sessions with invalid ROMs - + if (!session.rom.is_loaded()) + continue; // Skip sessions with invalid ROMs + for (auto editor : session.editors.active_editors_) { if (*editor->active()) { if (editor->type() == EditorType::kOverworld) { - auto &overworld_editor = static_cast(*editor); + auto& overworld_editor = static_cast(*editor); if (overworld_editor.jump_to_tab() != -1) { session.editors.dungeon_editor_.set_active(true); // Set the dungeon editor to the jump to tab - session.editors.dungeon_editor_.add_room(overworld_editor.jump_to_tab()); + session.editors.dungeon_editor_.add_room( + overworld_editor.jump_to_tab()); overworld_editor.jump_to_tab_ = -1; } } // Generate unique window titles for multi-session support - std::string window_title = GenerateUniqueEditorTitle(editor->type(), session_idx); - + std::string window_title = + GenerateUniqueEditorTitle(editor->type(), session_idx); + if (ImGui::Begin(window_title.c_str(), editor->active())) { // Temporarily switch context for this editor's update Rom* prev_rom = current_rom_; EditorSet* prev_editor_set = current_editor_set_; - + current_rom_ = &session.rom; current_editor_set_ = &session.editors; current_editor_ = editor; - + status_ = editor->Update(); - + // Route editor errors to toast manager if (!status_.ok()) { - std::string editor_name = "Editor"; // Get actual editor name if available - if (editor == &session.editors.overworld_editor_) editor_name = "Overworld Editor"; - else if (editor == &session.editors.dungeon_editor_) editor_name = "Dungeon Editor"; - else if (editor == &session.editors.sprite_editor_) editor_name = "Sprite Editor"; - else if (editor == &session.editors.graphics_editor_) editor_name = "Graphics Editor"; - else if (editor == &session.editors.music_editor_) editor_name = "Music Editor"; - else if (editor == &session.editors.palette_editor_) editor_name = "Palette Editor"; - else if (editor == &session.editors.screen_editor_) editor_name = "Screen Editor"; - - toast_manager_.Show(absl::StrFormat("%s Error: %s", editor_name, status_.message()), - editor::ToastType::kError, 8.0f); + std::string editor_name = + "Editor"; // Get actual editor name if available + if (editor == &session.editors.overworld_editor_) + editor_name = "Overworld Editor"; + else if (editor == &session.editors.dungeon_editor_) + editor_name = "Dungeon Editor"; + else if (editor == &session.editors.sprite_editor_) + editor_name = "Sprite Editor"; + else if (editor == &session.editors.graphics_editor_) + editor_name = "Graphics Editor"; + else if (editor == &session.editors.music_editor_) + editor_name = "Music Editor"; + else if (editor == &session.editors.palette_editor_) + editor_name = "Palette Editor"; + else if (editor == &session.editors.screen_editor_) + editor_name = "Screen Editor"; + + toast_manager_.Show( + absl::StrFormat("%s Error: %s", editor_name, status_.message()), + editor::ToastType::kError, 8.0f); } - + // Restore context current_rom_ = prev_rom; current_editor_set_ = prev_editor_set; @@ -884,136 +944,155 @@ void EditorManager::DrawMenuBar() { std::string version_text = absl::StrFormat("v%s", version_.c_str()); float version_width = CalcTextSize(version_text.c_str()).x; float settings_width = CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x + 16; - float total_right_width = version_width + settings_width + 40; // Extra padding - - // Position for ROM status and sessions - float session_rom_area_width = 250.0f; // Reduced width + float total_right_width = + version_width + settings_width + 40; // Extra padding + + // Position for ROM status and sessions + float session_rom_area_width = 250.0f; // Reduced width SameLine(GetWindowWidth() - total_right_width - session_rom_area_width); - + // Multi-session indicator if (sessions_.size() > 1) { - if (SmallButton(absl::StrFormat("%s %zu", ICON_MD_TAB, sessions_.size()).c_str())) { + if (SmallButton(absl::StrFormat("%s %zu", ICON_MD_TAB, sessions_.size()) + .c_str())) { show_session_switcher_ = true; } if (IsItemHovered()) { - SetTooltip("Sessions: %zu active\nClick to switch between sessions", sessions_.size()); + SetTooltip("Sessions: %zu active\nClick to switch between sessions", + sessions_.size()); } SameLine(); ImGui::Separator(); SameLine(); } - + // Enhanced ROM status with metadata popup if (current_rom_ && current_rom_->is_loaded()) { std::string rom_display = current_rom_->title(); - - ImVec4 status_color = current_rom_->dirty() ? - ImVec4(1.0f, 0.5f, 0.0f, 1.0f) : // Orange for modified - ImVec4(0.0f, 0.8f, 0.0f, 1.0f); // Green for clean - + + ImVec4 status_color = + current_rom_->dirty() ? ImVec4(1.0f, 0.5f, 0.0f, 1.0f) + : // Orange for modified + ImVec4(0.0f, 0.8f, 0.0f, 1.0f); // Green for clean + // Make ROM status clickable for detailed popup - if (SmallButton(absl::StrFormat("%s %s%s", - ICON_MD_STORAGE, - rom_display.c_str(), - current_rom_->dirty() ? "*" : "").c_str())) { + if (SmallButton(absl::StrFormat("%s %s%s", ICON_MD_STORAGE, + rom_display.c_str(), + current_rom_->dirty() ? "*" : "") + .c_str())) { ImGui::OpenPopup("ROM Details"); } - + // Enhanced tooltip on hover if (IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text("%s ROM Information", ICON_MD_INFO); ImGui::Separator(); - ImGui::Text("%s Title: %s", ICON_MD_TITLE, current_rom_->title().c_str()); - ImGui::Text("%s File: %s", ICON_MD_FOLDER_OPEN, current_rom_->filename().c_str()); - ImGui::Text("%s Size: %.1f MB (%zu bytes)", ICON_MD_STORAGE, - current_rom_->size() / 1048576.0f, current_rom_->size()); - ImGui::Text("%s Status: %s", current_rom_->dirty() ? ICON_MD_EDIT : ICON_MD_CHECK_CIRCLE, - current_rom_->dirty() ? "Modified" : "Clean"); + ImGui::Text("%s Title: %s", ICON_MD_TITLE, + current_rom_->title().c_str()); + ImGui::Text("%s File: %s", ICON_MD_FOLDER_OPEN, + current_rom_->filename().c_str()); + ImGui::Text("%s Size: %.1f MB (%zu bytes)", ICON_MD_STORAGE, + current_rom_->size() / 1048576.0f, current_rom_->size()); + ImGui::Text("%s Status: %s", + current_rom_->dirty() ? ICON_MD_EDIT : ICON_MD_CHECK_CIRCLE, + current_rom_->dirty() ? "Modified" : "Clean"); ImGui::Text("%s Click for detailed view", ICON_MD_LAUNCH); ImGui::EndTooltip(); } - + // Detailed ROM popup if (ImGui::BeginPopup("ROM Details")) { ImGui::Text("%s ROM Detailed Information", ICON_MD_INFO); ImGui::Separator(); ImGui::Spacing(); - + // Basic info with icons - if (ImGui::BeginTable("ROMDetailsTable", 2, ImGuiTableFlags_SizingFixedFit)) { - ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 120); + if (ImGui::BeginTable("ROMDetailsTable", 2, + ImGuiTableFlags_SizingFixedFit)) { + ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, + 120); ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); - + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s Title", ICON_MD_TITLE); ImGui::TableNextColumn(); ImGui::Text("%s", current_rom_->title().c_str()); - + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s File", ICON_MD_FOLDER_OPEN); ImGui::TableNextColumn(); ImGui::Text("%s", current_rom_->filename().c_str()); - + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s Size", ICON_MD_STORAGE); ImGui::TableNextColumn(); - ImGui::Text("%.1f MB (%zu bytes)", current_rom_->size() / 1048576.0f, current_rom_->size()); - + ImGui::Text("%.1f MB (%zu bytes)", current_rom_->size() / 1048576.0f, + current_rom_->size()); + ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("%s Status", current_rom_->dirty() ? ICON_MD_EDIT : ICON_MD_CHECK_CIRCLE); + ImGui::Text("%s Status", current_rom_->dirty() + ? ICON_MD_EDIT + : ICON_MD_CHECK_CIRCLE); ImGui::TableNextColumn(); - ImGui::TextColored(status_color, "%s", current_rom_->dirty() ? "Modified" : "Clean"); - + ImGui::TextColored(status_color, "%s", + current_rom_->dirty() ? "Modified" : "Clean"); + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s Session", ICON_MD_TAB); ImGui::TableNextColumn(); size_t current_session_idx = GetCurrentSessionIndex(); - ImGui::Text("Session %zu of %zu", current_session_idx + 1, sessions_.size()); - + ImGui::Text("Session %zu of %zu", current_session_idx + 1, + sessions_.size()); + ImGui::EndTable(); } - + ImGui::Spacing(); ImGui::Separator(); - + // Quick actions ImGui::Text("%s Quick Actions", ICON_MD_FLASH_ON); - if (ImGui::Button(absl::StrFormat("%s Save ROM", ICON_MD_SAVE).c_str(), ImVec2(120, 0))) { + if (ImGui::Button(absl::StrFormat("%s Save ROM", ICON_MD_SAVE).c_str(), + ImVec2(120, 0))) { status_ = SaveRom(); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button(absl::StrFormat("%s Switch Session", ICON_MD_SWITCH_ACCOUNT).c_str(), ImVec2(120, 0))) { + if (ImGui::Button( + absl::StrFormat("%s Switch Session", ICON_MD_SWITCH_ACCOUNT) + .c_str(), + ImVec2(120, 0))) { show_session_switcher_ = true; ImGui::CloseCurrentPopup(); } - + ImGui::EndPopup(); } - + SameLine(); } else { - TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "%s No ROM", ICON_MD_HELP_OUTLINE); + TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "%s No ROM", + ICON_MD_HELP_OUTLINE); SameLine(); } - + // Settings and version (using pre-calculated positioning) SameLine(GetWindowWidth() - total_right_width); ImGui::Separator(); SameLine(); - + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); if (Button(ICON_MD_DISPLAY_SETTINGS)) { show_display_settings = !show_display_settings; } PopStyleColor(); - + SameLine(); Text("%s", version_text.c_str()); EndMenuBar(); @@ -1022,27 +1101,29 @@ void EditorManager::DrawMenuBar() { if (show_display_settings) { // Use the popup manager instead of a separate window popup_manager_->Show("Display Settings"); - show_display_settings = false; // Close the old-style window + show_display_settings = false; // Close the old-style window } - if (show_imgui_demo_) ShowDemoWindow(&show_imgui_demo_); - if (show_imgui_metrics_) ShowMetricsWindow(&show_imgui_metrics_); + if (show_imgui_demo_) + ShowDemoWindow(&show_imgui_demo_); + if (show_imgui_metrics_) + ShowMetricsWindow(&show_imgui_metrics_); if (show_memory_editor_ && current_editor_set_) { current_editor_set_->memory_editor_.Update(show_memory_editor_); } if (show_asm_editor_ && current_editor_set_) { current_editor_set_->assembly_editor_.Update(show_asm_editor_); } - + // Testing interface (only when tests are enabled) #ifdef YAZE_ENABLE_TESTING if (show_test_dashboard_) { auto& test_manager = test::TestManager::Get(); - test_manager.UpdateResourceStats(); // Update monitoring data + test_manager.UpdateResourceStats(); // Update monitoring data test_manager.DrawTestDashboard(&show_test_dashboard_); } #endif - + // Welcome screen (accessible from View menu) if (show_welcome_screen_) { DrawWelcomeScreen(); @@ -1056,62 +1137,71 @@ void EditorManager::DrawMenuBar() { // Enhanced Command Palette UI if (show_command_palette_) { - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), + ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(700, 500), ImGuiCond_FirstUseEver); - - if (Begin(absl::StrFormat("%s Command Palette", ICON_MD_TERMINAL).c_str(), &show_command_palette_, - ImGuiWindowFlags_NoCollapse)) { - + + if (Begin(absl::StrFormat("%s Command Palette", ICON_MD_TERMINAL).c_str(), + &show_command_palette_, ImGuiWindowFlags_NoCollapse)) { + // Search input with focus management static char query[256] = {}; ImGui::SetNextItemWidth(-100); if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } - - bool input_changed = InputTextWithHint("##cmd_query", - absl::StrFormat("%s Type a command or search...", ICON_MD_SEARCH).c_str(), - query, IM_ARRAYSIZE(query)); - + + bool input_changed = InputTextWithHint( + "##cmd_query", + absl::StrFormat("%s Type a command or search...", ICON_MD_SEARCH) + .c_str(), + query, IM_ARRAYSIZE(query)); + ImGui::SameLine(); if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) { query[0] = '\0'; input_changed = true; } - + Separator(); - + // Filter and categorize commands std::vector> filtered_commands; - for (const auto &entry : context_.shortcut_manager.GetShortcuts()) { - const auto &name = entry.first; - const auto &shortcut = entry.second; - + for (const auto& entry : context_.shortcut_manager.GetShortcuts()) { + const auto& name = entry.first; + const auto& shortcut = entry.second; + if (query[0] == '\0' || name.find(query) != std::string::npos) { - std::string shortcut_text = shortcut.keys.empty() ? "" : - absl::StrFormat("(%s)", PrintShortcut(shortcut.keys).c_str()); + std::string shortcut_text = + shortcut.keys.empty() + ? "" + : absl::StrFormat("(%s)", + PrintShortcut(shortcut.keys).c_str()); filtered_commands.emplace_back(name, shortcut_text); } } - + // Display results in a table for better organization - if (ImGui::BeginTable("CommandPaletteTable", 2, - ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | - ImGuiTableFlags_SizingStretchProp, - ImVec2(0, -30))) { // Reserve space for status bar - - ImGui::TableSetupColumn("Command", ImGuiTableColumnFlags_WidthStretch, 0.7f); - ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthStretch, 0.3f); + if (ImGui::BeginTable("CommandPaletteTable", 2, + ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingStretchProp, + ImVec2(0, -30))) { // Reserve space for status bar + + ImGui::TableSetupColumn("Command", ImGuiTableColumnFlags_WidthStretch, + 0.7f); + ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthStretch, + 0.3f); ImGui::TableHeadersRow(); - + for (size_t i = 0; i < filtered_commands.size(); ++i) { const auto& [command_name, shortcut_text] = filtered_commands[i]; - + ImGui::TableNextRow(); ImGui::TableNextColumn(); - + ImGui::PushID(static_cast(i)); - if (Selectable(command_name.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { + if (Selectable(command_name.c_str(), false, + ImGuiSelectableFlags_SpanAllColumns)) { // Execute the command const auto& shortcuts = context_.shortcut_manager.GetShortcuts(); auto it = shortcuts.find(command_name); @@ -1121,17 +1211,18 @@ void EditorManager::DrawMenuBar() { } } ImGui::PopID(); - + ImGui::TableNextColumn(); ImGui::TextDisabled("%s", shortcut_text.c_str()); } - + ImGui::EndTable(); } - + // Status bar ImGui::Separator(); - ImGui::Text("%s %zu commands found", ICON_MD_INFO, filtered_commands.size()); + ImGui::Text("%s %zu commands found", ICON_MD_INFO, + filtered_commands.size()); ImGui::SameLine(); ImGui::TextDisabled("| Press Enter to execute selected command"); } @@ -1140,66 +1231,77 @@ void EditorManager::DrawMenuBar() { // Enhanced Global Search UI if (show_global_search_) { - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), + ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); - - if (Begin(absl::StrFormat("%s Global Search", ICON_MD_MANAGE_SEARCH).c_str(), &show_global_search_, - ImGuiWindowFlags_NoCollapse)) { - + + if (Begin( + absl::StrFormat("%s Global Search", ICON_MD_MANAGE_SEARCH).c_str(), + &show_global_search_, ImGuiWindowFlags_NoCollapse)) { + // Enhanced search input with focus management static char query[256] = {}; ImGui::SetNextItemWidth(-100); if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } - - bool input_changed = InputTextWithHint("##global_query", - absl::StrFormat("%s Search everything...", ICON_MD_SEARCH).c_str(), - query, IM_ARRAYSIZE(query)); - + + bool input_changed = InputTextWithHint( + "##global_query", + absl::StrFormat("%s Search everything...", ICON_MD_SEARCH).c_str(), + query, IM_ARRAYSIZE(query)); + ImGui::SameLine(); if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) { query[0] = '\0'; input_changed = true; } - + Separator(); - + // Tabbed search results for better organization if (ImGui::BeginTabBar("SearchResultTabs")) { - + // Recent Files Tab - if (ImGui::BeginTabItem(absl::StrFormat("%s Recent Files", ICON_MD_HISTORY).c_str())) { + if (ImGui::BeginTabItem( + absl::StrFormat("%s Recent Files", ICON_MD_HISTORY).c_str())) { static core::RecentFilesManager manager("recent_files.txt"); manager.Load(); auto recent_files = manager.GetRecentFiles(); - - if (ImGui::BeginTable("RecentFilesTable", 3, - ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | - ImGuiTableFlags_SizingStretchProp)) { - - ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 0.6f); - ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 80.0f); - ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed, 100.0f); + + if (ImGui::BeginTable("RecentFilesTable", 3, + ImGuiTableFlags_ScrollY | + ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingStretchProp)) { + + ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, + 0.6f); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, + 80.0f); + ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed, + 100.0f); ImGui::TableHeadersRow(); - - for (const auto &file : recent_files) { - if (query[0] != '\0' && file.find(query) == std::string::npos) continue; - + + for (const auto& file : recent_files) { + if (query[0] != '\0' && file.find(query) == std::string::npos) + continue; + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s", core::GetFileName(file).c_str()); - + ImGui::TableNextColumn(); std::string ext = core::GetFileExtension(file); if (ext == "sfc" || ext == "smc") { - ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s ROM", ICON_MD_VIDEOGAME_ASSET); + ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s ROM", + ICON_MD_VIDEOGAME_ASSET); } else if (ext == "yaze") { - ImGui::TextColored(ImVec4(0.2f, 0.6f, 0.8f, 1.0f), "%s Project", ICON_MD_FOLDER); + ImGui::TextColored(ImVec4(0.2f, 0.6f, 0.8f, 1.0f), "%s Project", + ICON_MD_FOLDER); } else { ImGui::Text("%s File", ICON_MD_DESCRIPTION); } - + ImGui::TableNextColumn(); ImGui::PushID(file.c_str()); if (ImGui::Button("Open")) { @@ -1208,79 +1310,91 @@ void EditorManager::DrawMenuBar() { } ImGui::PopID(); } - + ImGui::EndTable(); } ImGui::EndTabItem(); } - + // Labels Tab (only if ROM is loaded) if (current_rom_ && current_rom_->resource_label()) { - if (ImGui::BeginTabItem(absl::StrFormat("%s Labels", ICON_MD_LABEL).c_str())) { - auto &labels = current_rom_->resource_label()->labels_; - - if (ImGui::BeginTable("LabelsTable", 3, - ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | - ImGuiTableFlags_SizingStretchProp)) { - - ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 100.0f); - ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthStretch, 0.4f); - ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 0.6f); + if (ImGui::BeginTabItem( + absl::StrFormat("%s Labels", ICON_MD_LABEL).c_str())) { + auto& labels = current_rom_->resource_label()->labels_; + + if (ImGui::BeginTable("LabelsTable", 3, + ImGuiTableFlags_ScrollY | + ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingStretchProp)) { + + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, + 100.0f); + ImGui::TableSetupColumn("Label", + ImGuiTableColumnFlags_WidthStretch, 0.4f); + ImGui::TableSetupColumn("Value", + ImGuiTableColumnFlags_WidthStretch, 0.6f); ImGui::TableHeadersRow(); - - for (const auto &type_pair : labels) { - for (const auto &kv : type_pair.second) { - if (query[0] != '\0' && - kv.first.find(query) == std::string::npos && - kv.second.find(query) == std::string::npos) continue; - + + for (const auto& type_pair : labels) { + for (const auto& kv : type_pair.second) { + if (query[0] != '\0' && + kv.first.find(query) == std::string::npos && + kv.second.find(query) == std::string::npos) + continue; + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("%s", type_pair.first.c_str()); - + ImGui::TableNextColumn(); - if (Selectable(kv.first.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { + if (Selectable(kv.first.c_str(), false, + ImGuiSelectableFlags_SpanAllColumns)) { // Future: navigate to related editor/location } - + ImGui::TableNextColumn(); ImGui::TextDisabled("%s", kv.second.c_str()); } } - + ImGui::EndTable(); } ImGui::EndTabItem(); } } - + // Sessions Tab if (GetActiveSessionCount() > 1) { - if (ImGui::BeginTabItem(absl::StrFormat("%s Sessions", ICON_MD_TAB).c_str())) { + if (ImGui::BeginTabItem( + absl::StrFormat("%s Sessions", ICON_MD_TAB).c_str())) { ImGui::Text("Search and switch between active sessions:"); - + for (size_t i = 0; i < sessions_.size(); ++i) { auto& session = sessions_[i]; - if (session.custom_name == "[CLOSED SESSION]") continue; - + if (session.custom_name == "[CLOSED SESSION]") + continue; + std::string session_info = session.GetDisplayName(); - if (query[0] != '\0' && session_info.find(query) == std::string::npos) continue; - + if (query[0] != '\0' && + session_info.find(query) == std::string::npos) + continue; + bool is_current = (&session.rom == current_rom_); if (is_current) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2f, 0.8f, 0.2f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, + ImVec4(0.2f, 0.8f, 0.2f, 1.0f)); } - - if (Selectable(absl::StrFormat("%s %s %s", - ICON_MD_TAB, - session_info.c_str(), - is_current ? "(Current)" : "").c_str())) { + + if (Selectable(absl::StrFormat("%s %s %s", ICON_MD_TAB, + session_info.c_str(), + is_current ? "(Current)" : "") + .c_str())) { if (!is_current) { SwitchToSession(i); show_global_search_ = false; } } - + if (is_current) { ImGui::PopStyleColor(); } @@ -1288,10 +1402,10 @@ void EditorManager::DrawMenuBar() { ImGui::EndTabItem(); } } - + ImGui::EndTabBar(); } - + // Status bar ImGui::Separator(); ImGui::Text("%s Global search across all YAZE data", ICON_MD_INFO); @@ -1302,13 +1416,14 @@ void EditorManager::DrawMenuBar() { if (show_palette_editor_ && current_editor_set_) { Begin("Palette Editor", &show_palette_editor_); status_ = current_editor_set_->palette_editor_.Update(); - + // Route palette editor errors to toast manager if (!status_.ok()) { - toast_manager_.Show(absl::StrFormat("Palette Editor Error: %s", status_.message()), - editor::ToastType::kError, 8.0f); + toast_manager_.Show( + absl::StrFormat("Palette Editor Error: %s", status_.message()), + editor::ToastType::kError, 8.0f); } - + End(); } @@ -1323,51 +1438,57 @@ void EditorManager::DrawMenuBar() { if (save_as_menu) { Begin("Save ROM As", &save_as_menu, ImGuiWindowFlags_AlwaysAutoResize); - + ImGui::Text("%s Save ROM to new location", ICON_MD_SAVE_AS); ImGui::Separator(); - + static std::string save_as_filename = ""; if (current_rom_ && save_as_filename.empty()) { save_as_filename = current_rom_->title(); } - + ImGui::InputText("Filename", &save_as_filename); - + ImGui::Separator(); - - if (Button(absl::StrFormat("%s Browse...", ICON_MD_FOLDER_OPEN).c_str(), gui::kDefaultModalSize)) { + + if (Button(absl::StrFormat("%s Browse...", ICON_MD_FOLDER_OPEN).c_str(), + gui::kDefaultModalSize)) { // Use save file dialog for ROM files - auto file_path = core::FileDialogWrapper::ShowSaveFileDialog(save_as_filename, "sfc"); + auto file_path = + core::FileDialogWrapper::ShowSaveFileDialog(save_as_filename, "sfc"); if (!file_path.empty()) { save_as_filename = file_path; } } - + ImGui::SameLine(); - if (Button(absl::StrFormat("%s Save", ICON_MD_SAVE).c_str(), gui::kDefaultModalSize)) { + if (Button(absl::StrFormat("%s Save", ICON_MD_SAVE).c_str(), + gui::kDefaultModalSize)) { if (!save_as_filename.empty()) { // Ensure proper file extension std::string final_filename = save_as_filename; - if (final_filename.find(".sfc") == std::string::npos && + if (final_filename.find(".sfc") == std::string::npos && final_filename.find(".smc") == std::string::npos) { final_filename += ".sfc"; } - + status_ = SaveRomAs(final_filename); if (status_.ok()) { save_as_menu = false; - toast_manager_.Show(absl::StrFormat("ROM saved as: %s", final_filename), - editor::ToastType::kSuccess); + toast_manager_.Show( + absl::StrFormat("ROM saved as: %s", final_filename), + editor::ToastType::kSuccess); } else { - toast_manager_.Show(absl::StrFormat("Failed to save ROM: %s", status_.message()), - editor::ToastType::kError); + toast_manager_.Show( + absl::StrFormat("Failed to save ROM: %s", status_.message()), + editor::ToastType::kError); } } } - + ImGui::SameLine(); - if (Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(), gui::kDefaultModalSize)) { + if (Button(absl::StrFormat("%s Cancel", ICON_MD_CANCEL).c_str(), + gui::kDefaultModalSize)) { save_as_menu = false; } End(); @@ -1377,43 +1498,51 @@ void EditorManager::DrawMenuBar() { Begin("New Project", &new_project_menu, ImGuiWindowFlags_AlwaysAutoResize); static std::string save_as_filename = ""; InputText("Project Name", &save_as_filename); - if (Button(absl::StrFormat("%s Destination Folder", ICON_MD_FOLDER).c_str(), gui::kDefaultModalSize)) { + if (Button(absl::StrFormat("%s Destination Folder", ICON_MD_FOLDER).c_str(), + gui::kDefaultModalSize)) { current_project_.filepath = FileDialogWrapper::ShowOpenFolderDialog(); } SameLine(); Text("%s", current_project_.filepath.c_str()); - - if (Button(absl::StrFormat("%s ROM File", ICON_MD_VIDEOGAME_ASSET).c_str(), gui::kDefaultModalSize)) { + + if (Button(absl::StrFormat("%s ROM File", ICON_MD_VIDEOGAME_ASSET).c_str(), + gui::kDefaultModalSize)) { current_project_.rom_filename = FileDialogWrapper::ShowOpenFileDialog(); } SameLine(); Text("%s", current_project_.rom_filename.c_str()); - - if (Button(absl::StrFormat("%s Labels File", ICON_MD_LABEL).c_str(), gui::kDefaultModalSize)) { - current_project_.labels_filename = FileDialogWrapper::ShowOpenFileDialog(); + + if (Button(absl::StrFormat("%s Labels File", ICON_MD_LABEL).c_str(), + gui::kDefaultModalSize)) { + current_project_.labels_filename = + FileDialogWrapper::ShowOpenFileDialog(); } SameLine(); Text("%s", current_project_.labels_filename.c_str()); - - if (Button(absl::StrFormat("%s Code Folder", ICON_MD_CODE).c_str(), gui::kDefaultModalSize)) { + + if (Button(absl::StrFormat("%s Code Folder", ICON_MD_CODE).c_str(), + gui::kDefaultModalSize)) { current_project_.code_folder = FileDialogWrapper::ShowOpenFolderDialog(); } SameLine(); Text("%s", current_project_.code_folder.c_str()); Separator(); - - if (Button(absl::StrFormat("%s Choose Project File Location", ICON_MD_SAVE).c_str(), gui::kDefaultModalSize)) { - auto project_file_path = core::FileDialogWrapper::ShowSaveFileDialog(save_as_filename, "yaze"); + + if (Button(absl::StrFormat("%s Choose Project File Location", ICON_MD_SAVE) + .c_str(), + gui::kDefaultModalSize)) { + auto project_file_path = + core::FileDialogWrapper::ShowSaveFileDialog(save_as_filename, "yaze"); if (!project_file_path.empty()) { // Ensure .yaze extension if (project_file_path.find(".yaze") == std::string::npos) { project_file_path += ".yaze"; } - + // Update project filepath to the chosen location current_project_.filepath = project_file_path; - + // Also set the project directory to the parent directory size_t last_slash = project_file_path.find_last_of("/\\"); if (last_slash != std::string::npos) { @@ -1422,16 +1551,19 @@ void EditorManager::DrawMenuBar() { } } } - - if (Button(absl::StrFormat("%s Create Project", ICON_MD_ADD).c_str(), gui::kDefaultModalSize)) { + + if (Button(absl::StrFormat("%s Create Project", ICON_MD_ADD).c_str(), + gui::kDefaultModalSize)) { if (!current_project_.filepath.empty()) { new_project_menu = false; - status_ = current_project_.Create(save_as_filename, current_project_.filepath); + status_ = current_project_.Create(save_as_filename, + current_project_.filepath); if (status_.ok()) { status_ = current_project_.Save(); } } else { - toast_manager_.Show("Please choose a project file location first", editor::ToastType::kWarning); + toast_manager_.Show("Please choose a project file location first", + editor::ToastType::kWarning); } } SameLine(); @@ -1443,7 +1575,8 @@ void EditorManager::DrawMenuBar() { // Workspace preset dialogs if (show_save_workspace_preset_) { - Begin("Save Workspace Preset", &show_save_workspace_preset_, ImGuiWindowFlags_AlwaysAutoResize); + Begin("Save Workspace Preset", &show_save_workspace_preset_, + ImGuiWindowFlags_AlwaysAutoResize); static std::string preset_name = ""; InputText("Name", &preset_name); if (Button("Save", gui::kDefaultModalSize)) { @@ -1452,29 +1585,33 @@ void EditorManager::DrawMenuBar() { show_save_workspace_preset_ = false; } SameLine(); - if (Button("Cancel", gui::kDefaultModalSize)) { show_save_workspace_preset_ = false; } + if (Button("Cancel", gui::kDefaultModalSize)) { + show_save_workspace_preset_ = false; + } End(); } if (show_load_workspace_preset_) { - Begin("Load Workspace Preset", &show_load_workspace_preset_, ImGuiWindowFlags_AlwaysAutoResize); - + Begin("Load Workspace Preset", &show_load_workspace_preset_, + ImGuiWindowFlags_AlwaysAutoResize); + // Lazy load workspace presets when UI is accessed if (!workspace_presets_loaded_) { RefreshWorkspacePresets(); } - - for (const auto &name : workspace_presets_) { + + for (const auto& name : workspace_presets_) { if (Selectable(name.c_str())) { LoadWorkspacePreset(name); toast_manager_.Show("Preset loaded", editor::ToastType::kSuccess); show_load_workspace_preset_ = false; } } - if (workspace_presets_.empty()) Text("No presets found"); + if (workspace_presets_.empty()) + Text("No presets found"); End(); } - + // Draw new workspace UI elements DrawSessionSwitcher(); DrawSessionManager(); @@ -1487,13 +1624,14 @@ absl::Status EditorManager::LoadRom() { if (file_name.empty()) { return absl::OkStatus(); } - + // Check for duplicate sessions if (HasDuplicateSession(file_name)) { - toast_manager_.Show("ROM already open in another session", editor::ToastType::kWarning); + toast_manager_.Show("ROM already open in another session", + editor::ToastType::kWarning); return absl::OkStatus(); } - + Rom temp_rom; RETURN_IF_ERROR(temp_rom.LoadFromFile(file_name)); @@ -1502,11 +1640,12 @@ absl::Status EditorManager::LoadRom() { for (auto& session : sessions_) { if (!session.rom.is_loaded()) { target_session = &session; - util::logf("Found empty session to populate with ROM: %s", file_name.c_str()); + util::logf("Found empty session to populate with ROM: %s", + file_name.c_str()); break; } } - + if (target_session) { // Populate existing empty session target_session->rom = std::move(temp_rom); @@ -1516,21 +1655,22 @@ absl::Status EditorManager::LoadRom() { } else { // Create new session only if no empty ones exist sessions_.emplace_back(std::move(temp_rom)); - RomSession &session = sessions_.back(); - session.filepath = file_name; // Store filepath for duplicate detection - + RomSession& session = sessions_.back(); + session.filepath = file_name; // Store filepath for duplicate detection + // Wire editor contexts - for (auto *editor : session.editors.active_editors_) { + for (auto* editor : session.editors.active_editors_) { editor->set_context(&context_); } current_rom_ = &session.rom; current_editor_set_ = &session.editors; } - + // Update test manager with current ROM for ROM-dependent tests (only when tests are enabled) #ifdef YAZE_ENABLE_TESTING - util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", - (void*)current_rom_, current_rom_ ? current_rom_->title().c_str() : "null"); + util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", + (void*)current_rom_, + current_rom_ ? current_rom_->title().c_str() : "null"); test::TestManager::Get().SetCurrentRom(current_rom_); #endif @@ -1550,9 +1690,9 @@ absl::Status EditorManager::LoadAssets() { if (!current_rom_ || !current_editor_set_) { return absl::FailedPreconditionError("No ROM or editor set loaded"); } - + auto start_time = std::chrono::steady_clock::now(); - + current_editor_set_->overworld_editor_.Initialize(); current_editor_set_->message_editor_.Initialize(); ASSIGN_OR_RETURN(*gfx::Arena::Get().mutable_gfx_sheets(), @@ -1565,11 +1705,14 @@ absl::Status EditorManager::LoadAssets() { RETURN_IF_ERROR(current_editor_set_->message_editor_.Load()); RETURN_IF_ERROR(current_editor_set_->music_editor_.Load()); RETURN_IF_ERROR(current_editor_set_->palette_editor_.Load()); - + + core::PerformanceMonitor::Get().PrintSummary(); + auto end_time = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast(end_time - start_time); + auto duration = std::chrono::duration_cast( + end_time - start_time); util::logf("ROM assets loaded in %lld ms", duration.count()); - + return absl::OkStatus(); } @@ -1619,9 +1762,9 @@ absl::Status EditorManager::SaveRomAs(const std::string& filename) { // Create save settings with custom filename Rom::SaveSettings settings; settings.backup = backup_rom_; - settings.save_new = false; // Don't auto-generate name, use provided filename + settings.save_new = false; // Don't auto-generate name, use provided filename settings.filename = filename; - + auto save_status = current_rom_->SaveToFile(settings); if (save_status.ok()) { // Update current ROM filepath to the new location @@ -1629,21 +1772,21 @@ absl::Status EditorManager::SaveRomAs(const std::string& filename) { if (current_session_idx < sessions_.size()) { sessions_[current_session_idx].filepath = filename; } - + // Add to recent files static core::RecentFilesManager manager("recent_files.txt"); manager.Load(); manager.AddFile(filename); manager.Save(); - - toast_manager_.Show(absl::StrFormat("ROM saved as: %s", filename), - editor::ToastType::kSuccess); + + toast_manager_.Show(absl::StrFormat("ROM saved as: %s", filename), + editor::ToastType::kSuccess); } - + return save_status; } -absl::Status EditorManager::OpenRomOrProject(const std::string &filename) { +absl::Status EditorManager::OpenRomOrProject(const std::string& filename) { if (filename.empty()) { return absl::OkStatus(); } @@ -1654,14 +1797,14 @@ absl::Status EditorManager::OpenRomOrProject(const std::string &filename) { Rom temp_rom; RETURN_IF_ERROR(temp_rom.LoadFromFile(filename)); sessions_.emplace_back(std::move(temp_rom)); - RomSession &session = sessions_.back(); - for (auto *editor : session.editors.active_editors_) { + RomSession& session = sessions_.back(); + for (auto* editor : session.editors.active_editors_) { editor->set_context(&context_); } current_rom_ = &session.rom; current_editor_set_ = &session.editors; RETURN_IF_ERROR(LoadAssets()); - + // Reset welcome screen state when ROM is loaded welcome_screen_manually_closed_ = false; } @@ -1671,9 +1814,9 @@ absl::Status EditorManager::OpenRomOrProject(const std::string &filename) { absl::Status EditorManager::CreateNewProject(const std::string& template_name) { auto dialog_path = core::FileDialogWrapper::ShowOpenFolderDialog(); if (dialog_path.empty()) { - return absl::OkStatus(); // User cancelled + return absl::OkStatus(); // User cancelled } - + // Show project creation dialog popup_manager_->Show("Create New Project"); return absl::OkStatus(); @@ -1684,76 +1827,80 @@ absl::Status EditorManager::OpenProject() { if (file_path.empty()) { return absl::OkStatus(); } - + core::YazeProject new_project; RETURN_IF_ERROR(new_project.Open(file_path)); - + // Validate project auto validation_status = new_project.Validate(); if (!validation_status.ok()) { - toast_manager_.Show(absl::StrFormat("Project validation failed: %s", - validation_status.message()), - editor::ToastType::kWarning, 5.0f); - + toast_manager_.Show(absl::StrFormat("Project validation failed: %s", + validation_status.message()), + editor::ToastType::kWarning, 5.0f); + // Ask user if they want to repair popup_manager_->Show("Project Repair"); } - + current_project_ = std::move(new_project); - + // Load ROM if specified in project if (!current_project_.rom_filename.empty()) { Rom temp_rom; RETURN_IF_ERROR(temp_rom.LoadFromFile(current_project_.rom_filename)); if (!current_project_.labels_filename.empty()) { - if (!temp_rom.resource_label()->LoadLabels(current_project_.labels_filename)) { - toast_manager_.Show("Could not load labels file from project", - editor::ToastType::kWarning); + if (!temp_rom.resource_label()->LoadLabels( + current_project_.labels_filename)) { + toast_manager_.Show("Could not load labels file from project", + editor::ToastType::kWarning); } } sessions_.emplace_back(std::move(temp_rom)); - RomSession &session = sessions_.back(); - for (auto *editor : session.editors.active_editors_) { + RomSession& session = sessions_.back(); + for (auto* editor : session.editors.active_editors_) { editor->set_context(&context_); } current_rom_ = &session.rom; current_editor_set_ = &session.editors; - + // Apply project feature flags to the session session.feature_flags = current_project_.feature_flags; - + // Update test manager with current ROM for ROM-dependent tests (only when tests are enabled) #ifdef YAZE_ENABLE_TESTING - util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", - (void*)current_rom_, current_rom_ ? current_rom_->title().c_str() : "null"); + util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", + (void*)current_rom_, + current_rom_ ? current_rom_->title().c_str() : "null"); test::TestManager::Get().SetCurrentRom(current_rom_); #endif if (current_editor_set_ && !current_project_.code_folder.empty()) { - current_editor_set_->assembly_editor_.OpenFolder(current_project_.code_folder); + current_editor_set_->assembly_editor_.OpenFolder( + current_project_.code_folder); } - + RETURN_IF_ERROR(LoadAssets()); } - + // Apply workspace settings font_global_scale_ = current_project_.workspace_settings.font_global_scale; autosave_enabled_ = current_project_.workspace_settings.autosave_enabled; - autosave_interval_secs_ = current_project_.workspace_settings.autosave_interval_secs; + autosave_interval_secs_ = + current_project_.workspace_settings.autosave_interval_secs; ImGui::GetIO().FontGlobalScale = font_global_scale_; - + // Add to recent files static core::RecentFilesManager manager("recent_files.txt"); manager.Load(); manager.AddFile(current_project_.filepath); manager.Save(); - - toast_manager_.Show(absl::StrFormat("Project '%s' loaded successfully", - current_project_.GetDisplayName()), - editor::ToastType::kSuccess); - + + toast_manager_.Show(absl::StrFormat("Project '%s' loaded successfully", + current_project_.GetDisplayName()), + editor::ToastType::kSuccess); + return absl::OkStatus(); } @@ -1761,18 +1908,19 @@ absl::Status EditorManager::SaveProject() { if (!current_project_.project_opened()) { return CreateNewProject(); } - + // Update project with current settings if (current_rom_ && current_editor_set_) { size_t session_idx = GetCurrentSessionIndex(); if (session_idx < sessions_.size()) { current_project_.feature_flags = sessions_[session_idx].feature_flags; } - + current_project_.workspace_settings.font_global_scale = font_global_scale_; current_project_.workspace_settings.autosave_enabled = autosave_enabled_; - current_project_.workspace_settings.autosave_interval_secs = autosave_interval_secs_; - + current_project_.workspace_settings.autosave_interval_secs = + autosave_interval_secs_; + // Save recent files static core::RecentFilesManager manager("recent_files.txt"); manager.Load(); @@ -1781,30 +1929,31 @@ absl::Status EditorManager::SaveProject() { current_project_.workspace_settings.recent_files.push_back(file); } } - + return current_project_.Save(); } absl::Status EditorManager::SaveProjectAs() { // Get current project name for default filename - std::string default_name = current_project_.project_opened() ? - current_project_.GetDisplayName() : - "untitled_project"; - - auto file_path = core::FileDialogWrapper::ShowSaveFileDialog(default_name, "yaze"); + std::string default_name = current_project_.project_opened() + ? current_project_.GetDisplayName() + : "untitled_project"; + + auto file_path = + core::FileDialogWrapper::ShowSaveFileDialog(default_name, "yaze"); if (file_path.empty()) { return absl::OkStatus(); } - + // Ensure .yaze extension if (file_path.find(".yaze") == std::string::npos) { file_path += ".yaze"; } - + // Update project filepath and save std::string old_filepath = current_project_.filepath; current_project_.filepath = file_path; - + auto save_status = current_project_.Save(); if (save_status.ok()) { // Add to recent files @@ -1812,30 +1961,33 @@ absl::Status EditorManager::SaveProjectAs() { manager.Load(); manager.AddFile(file_path); manager.Save(); - - toast_manager_.Show(absl::StrFormat("Project saved as: %s", file_path), - editor::ToastType::kSuccess); + + toast_manager_.Show(absl::StrFormat("Project saved as: %s", file_path), + editor::ToastType::kSuccess); } else { // Restore old filepath on failure current_project_.filepath = old_filepath; - toast_manager_.Show(absl::StrFormat("Failed to save project: %s", save_status.message()), - editor::ToastType::kError); + toast_manager_.Show( + absl::StrFormat("Failed to save project: %s", save_status.message()), + editor::ToastType::kError); } - + return save_status; } absl::Status EditorManager::ImportProject(const std::string& project_path) { core::YazeProject imported_project; - + if (project_path.ends_with(".zsproj")) { RETURN_IF_ERROR(imported_project.ImportZScreamProject(project_path)); - toast_manager_.Show("ZScream project imported successfully. Please configure ROM and folders.", - editor::ToastType::kInfo, 5.0f); + toast_manager_.Show( + "ZScream project imported successfully. Please configure ROM and " + "folders.", + editor::ToastType::kInfo, 5.0f); } else { RETURN_IF_ERROR(imported_project.Open(project_path)); } - + current_project_ = std::move(imported_project); return absl::OkStatus(); } @@ -1844,10 +1996,11 @@ absl::Status EditorManager::RepairCurrentProject() { if (!current_project_.project_opened()) { return absl::FailedPreconditionError("No project is currently open"); } - + RETURN_IF_ERROR(current_project_.RepairProject()); - toast_manager_.Show("Project repaired successfully", editor::ToastType::kSuccess); - + toast_manager_.Show("Project repaired successfully", + editor::ToastType::kSuccess); + return absl::OkStatus(); } @@ -1855,19 +2008,19 @@ void EditorManager::ShowProjectHelp() { popup_manager_->Show("Project Help"); } -absl::Status EditorManager::SetCurrentRom(Rom *rom) { +absl::Status EditorManager::SetCurrentRom(Rom* rom) { if (!rom) { return absl::InvalidArgumentError("Invalid ROM pointer"); } - for (auto &session : sessions_) { + for (auto& session : sessions_) { if (&session.rom == rom) { current_rom_ = &session.rom; current_editor_set_ = &session.editors; - + // Update test manager with current ROM for ROM-dependent tests test::TestManager::Get().SetCurrentRom(current_rom_); - + return absl::OkStatus(); } } @@ -1882,56 +2035,61 @@ void EditorManager::CreateNewSession() { popup_manager_->Show("Session Limit Warning"); return; } - + // Create a blank session sessions_.emplace_back(); RomSession& session = sessions_.back(); - + // Wire editor contexts for new session for (auto* editor : session.editors.active_editors_) { editor->set_context(&context_); } - + // Don't switch to the new session automatically - toast_manager_.Show(absl::StrFormat("New session created (Session %zu)", sessions_.size()), - editor::ToastType::kSuccess); - + toast_manager_.Show( + absl::StrFormat("New session created (Session %zu)", sessions_.size()), + editor::ToastType::kSuccess); + // Show session manager if user has multiple sessions now if (sessions_.size() > 2) { - toast_manager_.Show("Tip: Use Workspace → Sessions → Session Switcher for quick navigation", - editor::ToastType::kInfo, 5.0f); + toast_manager_.Show( + "Tip: Use Workspace → Sessions → Session Switcher for quick navigation", + editor::ToastType::kInfo, 5.0f); } } void EditorManager::DuplicateCurrentSession() { if (!current_rom_) { - toast_manager_.Show("No current ROM to duplicate", editor::ToastType::kWarning); + toast_manager_.Show("No current ROM to duplicate", + editor::ToastType::kWarning); return; } - + // Create a copy of the current ROM Rom rom_copy = *current_rom_; sessions_.emplace_back(std::move(rom_copy)); RomSession& session = sessions_.back(); - + // Wire editor contexts for (auto* editor : session.editors.active_editors_) { editor->set_context(&context_); } - - toast_manager_.Show(absl::StrFormat("Session duplicated (Session %zu)", sessions_.size()), - editor::ToastType::kSuccess); + + toast_manager_.Show( + absl::StrFormat("Session duplicated (Session %zu)", sessions_.size()), + editor::ToastType::kSuccess); } void EditorManager::CloseCurrentSession() { if (GetActiveSessionCount() <= 1) { - toast_manager_.Show("Cannot close the last active session", editor::ToastType::kWarning); + toast_manager_.Show("Cannot close the last active session", + editor::ToastType::kWarning); return; } - + // Find current session index size_t current_index = GetCurrentSessionIndex(); - + // Switch to another active session before removing current one size_t next_index = 0; for (size_t i = 0; i < sessions_.size(); ++i) { @@ -1940,41 +2098,46 @@ void EditorManager::CloseCurrentSession() { break; } } - + current_rom_ = &sessions_[next_index].rom; current_editor_set_ = &sessions_[next_index].editors; test::TestManager::Get().SetCurrentRom(current_rom_); - + // Now remove the current session RemoveSession(current_index); - - toast_manager_.Show("Session closed successfully", editor::ToastType::kSuccess); + + toast_manager_.Show("Session closed successfully", + editor::ToastType::kSuccess); } void EditorManager::RemoveSession(size_t index) { if (index >= sessions_.size()) { - toast_manager_.Show("Invalid session index for removal", editor::ToastType::kError); + toast_manager_.Show("Invalid session index for removal", + editor::ToastType::kError); return; } - + if (GetActiveSessionCount() <= 1) { - toast_manager_.Show("Cannot remove the last active session", editor::ToastType::kWarning); + toast_manager_.Show("Cannot remove the last active session", + editor::ToastType::kWarning); return; } - + // Get session info for logging std::string session_name = sessions_[index].GetDisplayName(); - + // For now, mark the session as invalid instead of removing it from the deque // This is a safer approach until RomSession becomes fully movable - sessions_[index].rom.Close(); // Close the ROM to mark as invalid + sessions_[index].rom.Close(); // Close the ROM to mark as invalid sessions_[index].custom_name = "[CLOSED SESSION]"; sessions_[index].filepath = ""; - - util::logf("Marked session as closed: %s (index %zu)", session_name.c_str(), index); - toast_manager_.Show(absl::StrFormat("Session marked as closed: %s", session_name), - editor::ToastType::kInfo); - + + util::logf("Marked session as closed: %s (index %zu)", session_name.c_str(), + index); + toast_manager_.Show( + absl::StrFormat("Session marked as closed: %s", session_name), + editor::ToastType::kInfo); + // TODO: Implement proper session removal when EditorSet becomes movable // The current workaround marks sessions as closed instead of removing them } @@ -1984,28 +2147,30 @@ void EditorManager::SwitchToSession(size_t index) { toast_manager_.Show("Invalid session index", editor::ToastType::kError); return; } - + auto& session = sessions_[index]; current_rom_ = &session.rom; current_editor_set_ = &session.editors; - + // Update test manager with current ROM for ROM-dependent tests - util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", - (void*)current_rom_, current_rom_ ? current_rom_->title().c_str() : "null"); + util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", + (void*)current_rom_, + current_rom_ ? current_rom_->title().c_str() : "null"); test::TestManager::Get().SetCurrentRom(current_rom_); - + std::string session_name = session.GetDisplayName(); - toast_manager_.Show(absl::StrFormat("Switched to %s", session_name), - editor::ToastType::kInfo); + toast_manager_.Show(absl::StrFormat("Switched to %s", session_name), + editor::ToastType::kInfo); } size_t EditorManager::GetCurrentSessionIndex() const { for (size_t i = 0; i < sessions_.size(); ++i) { - if (&sessions_[i].rom == current_rom_ && sessions_[i].custom_name != "[CLOSED SESSION]") { + if (&sessions_[i].rom == current_rom_ && + sessions_[i].custom_name != "[CLOSED SESSION]") { return i; } } - return 0; // Default to first session if not found + return 0; // Default to first session if not found } size_t EditorManager::GetActiveSessionCount() const { @@ -2018,24 +2183,26 @@ size_t EditorManager::GetActiveSessionCount() const { return count; } -std::string EditorManager::GenerateUniqueEditorTitle(EditorType type, size_t session_index) const { +std::string EditorManager::GenerateUniqueEditorTitle( + EditorType type, size_t session_index) const { const char* base_name = kEditorNames[static_cast(type)]; - + if (sessions_.size() <= 1) { // Single session - use simple name return std::string(base_name); } - + // Multi-session - include session identifier const auto& session = sessions_[session_index]; std::string session_name = session.GetDisplayName(); - + // Truncate long session names if (session_name.length() > 20) { session_name = session_name.substr(0, 17) + "..."; } - - return absl::StrFormat("%s - %s##session_%zu", base_name, session_name, session_index); + + return absl::StrFormat("%s - %s##session_%zu", base_name, session_name, + session_index); } void EditorManager::ResetWorkspaceLayout() { @@ -2054,8 +2221,9 @@ void EditorManager::LoadWorkspaceLayout() { } void EditorManager::ShowAllWindows() { - if (!current_editor_set_) return; - + if (!current_editor_set_) + return; + for (auto* editor : current_editor_set_->active_editors_) { editor->set_active(true); } @@ -2064,13 +2232,14 @@ void EditorManager::ShowAllWindows() { #ifdef YAZE_ENABLE_TESTING show_test_dashboard_ = true; #endif - + toast_manager_.Show("All windows shown", editor::ToastType::kInfo); } void EditorManager::HideAllWindows() { - if (!current_editor_set_) return; - + if (!current_editor_set_) + return; + for (auto* editor : current_editor_set_->active_editors_) { editor->set_active(false); } @@ -2079,7 +2248,7 @@ void EditorManager::HideAllWindows() { #ifdef YAZE_ENABLE_TESTING show_test_dashboard_ = false; #endif - + toast_manager_.Show("All windows hidden", editor::ToastType::kInfo); } @@ -2100,45 +2269,48 @@ void EditorManager::CloseAllFloatingWindows() { } void EditorManager::LoadDeveloperLayout() { - if (!current_editor_set_) return; - + if (!current_editor_set_) + return; + // Developer layout: Code editor, assembly editor, test dashboard current_editor_set_->assembly_editor_.set_active(true); #ifdef YAZE_ENABLE_TESTING show_test_dashboard_ = true; #endif show_imgui_metrics_ = true; - + // Hide non-dev windows current_editor_set_->graphics_editor_.set_active(false); current_editor_set_->music_editor_.set_active(false); current_editor_set_->sprite_editor_.set_active(false); - + toast_manager_.Show("Developer layout loaded", editor::ToastType::kSuccess); } void EditorManager::LoadDesignerLayout() { - if (!current_editor_set_) return; - + if (!current_editor_set_) + return; + // Designer layout: Graphics, palette, sprite editors current_editor_set_->graphics_editor_.set_active(true); current_editor_set_->palette_editor_.set_active(true); current_editor_set_->sprite_editor_.set_active(true); current_editor_set_->overworld_editor_.set_active(true); - + // Hide non-design windows current_editor_set_->assembly_editor_.set_active(false); #ifdef YAZE_ENABLE_TESTING show_test_dashboard_ = false; #endif show_imgui_metrics_ = false; - + toast_manager_.Show("Designer layout loaded", editor::ToastType::kSuccess); } void EditorManager::LoadModderLayout() { - if (!current_editor_set_) return; - + if (!current_editor_set_) + return; + // Modder layout: All editors except technical ones current_editor_set_->overworld_editor_.set_active(true); current_editor_set_->dungeon_editor_.set_active(true); @@ -2147,69 +2319,82 @@ void EditorManager::LoadModderLayout() { current_editor_set_->sprite_editor_.set_active(true); current_editor_set_->message_editor_.set_active(true); current_editor_set_->music_editor_.set_active(true); - + // Hide technical windows current_editor_set_->assembly_editor_.set_active(false); show_imgui_metrics_ = false; - + toast_manager_.Show("Modder layout loaded", editor::ToastType::kSuccess); } void EditorManager::DrawSessionSwitcher() { - if (!show_session_switcher_) return; - - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + if (!show_session_switcher_) + return; + + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), + ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(700, 450), ImGuiCond_Appearing); - - if (ImGui::Begin(absl::StrFormat("%s Session Switcher", ICON_MD_SWITCH_ACCOUNT).c_str(), - &show_session_switcher_, ImGuiWindowFlags_NoCollapse)) { - + + if (ImGui::Begin( + absl::StrFormat("%s Session Switcher", ICON_MD_SWITCH_ACCOUNT) + .c_str(), + &show_session_switcher_, ImGuiWindowFlags_NoCollapse)) { + // Header with enhanced info ImGui::Text("%s %zu Sessions Available", ICON_MD_TAB, sessions_.size()); ImGui::SameLine(ImGui::GetWindowWidth() - 120); - if (ImGui::Button(absl::StrFormat("%s New", ICON_MD_ADD).c_str(), ImVec2(50, 0))) { + if (ImGui::Button(absl::StrFormat("%s New", ICON_MD_ADD).c_str(), + ImVec2(50, 0))) { CreateNewSession(); } ImGui::SameLine(); - if (ImGui::Button(absl::StrFormat("%s Manager", ICON_MD_SETTINGS).c_str(), ImVec2(60, 0))) { + if (ImGui::Button(absl::StrFormat("%s Manager", ICON_MD_SETTINGS).c_str(), + ImVec2(60, 0))) { show_session_manager_ = true; } - + ImGui::Separator(); - + // Enhanced session list using table for better layout - const float TABLE_HEIGHT = ImGui::GetContentRegionAvail().y - 50; // Reserve space for close button - - if (ImGui::BeginTable("SessionSwitcherTable", 4, - ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | - ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_ScrollY | - ImGuiTableFlags_Resizable, - ImVec2(0, TABLE_HEIGHT))) { - + const float TABLE_HEIGHT = ImGui::GetContentRegionAvail().y - + 50; // Reserve space for close button + + if (ImGui::BeginTable("SessionSwitcherTable", 4, + ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingStretchProp | + ImGuiTableFlags_ScrollY | + ImGuiTableFlags_Resizable, + ImVec2(0, TABLE_HEIGHT))) { + // Setup columns with proper sizing weights - ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch, 0.3f); - ImGui::TableSetupColumn("ROM Info", ImGuiTableColumnFlags_WidthStretch, 0.4f); - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 90.0f); - ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 140.0f); + ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch, + 0.3f); + ImGui::TableSetupColumn("ROM Info", ImGuiTableColumnFlags_WidthStretch, + 0.4f); + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, + 90.0f); + ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, + 140.0f); ImGui::TableHeadersRow(); - + for (size_t i = 0; i < sessions_.size(); ++i) { auto& session = sessions_[i]; - + // Skip closed sessions if (session.custom_name == "[CLOSED SESSION]") { continue; } - + bool is_current = (&session.rom == current_rom_); - + ImGui::PushID(static_cast(i)); - ImGui::TableNextRow(ImGuiTableRowFlags_None, 55.0f); // Consistent row height - + ImGui::TableNextRow(ImGuiTableRowFlags_None, + 55.0f); // Consistent row height + // Session name column with better styling ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); - + if (is_current) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2f, 0.8f, 0.2f, 1.0f)); ImGui::Text("%s %s", ICON_MD_STAR, session.GetDisplayName().c_str()); @@ -2217,40 +2402,44 @@ void EditorManager::DrawSessionSwitcher() { } else { ImGui::Text("%s %s", ICON_MD_TAB, session.GetDisplayName().c_str()); } - + // ROM info column with better information layout ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); - + if (session.rom.is_loaded()) { - ImGui::Text("%s %s", ICON_MD_VIDEOGAME_ASSET, session.rom.title().c_str()); - ImGui::Text("%.1f MB | %s", - session.rom.size() / 1048576.0f, - session.rom.dirty() ? "Modified" : "Clean"); + ImGui::Text("%s %s", ICON_MD_VIDEOGAME_ASSET, + session.rom.title().c_str()); + ImGui::Text("%.1f MB | %s", session.rom.size() / 1048576.0f, + session.rom.dirty() ? "Modified" : "Clean"); } else { - ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s No ROM loaded", ICON_MD_WARNING); + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s No ROM loaded", + ICON_MD_WARNING); } - + // Status column with better visual indicators ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); - + if (session.rom.is_loaded()) { if (session.rom.dirty()) { - ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "%s", ICON_MD_EDIT); + ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "%s", + ICON_MD_EDIT); } else { - ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", ICON_MD_CHECK_CIRCLE); + ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", + ICON_MD_CHECK_CIRCLE); } } else { - ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s", ICON_MD_RADIO_BUTTON_UNCHECKED); + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s", + ICON_MD_RADIO_BUTTON_UNCHECKED); } - + // Actions column with improved button layout ImGui::TableNextColumn(); - + // Create button group for better alignment ImGui::BeginGroup(); - + if (!is_current) { if (ImGui::Button("Switch")) { SwitchToSession(i); @@ -2261,50 +2450,54 @@ void EditorManager::DrawSessionSwitcher() { ImGui::Button("Current"); ImGui::EndDisabled(); } - + ImGui::SameLine(); if (ImGui::Button("Rename")) { session_to_rename_ = i; // Safe string copy with bounds checking const std::string& name = session.GetDisplayName(); - size_t copy_len = std::min(name.length(), sizeof(session_rename_buffer_) - 1); + size_t copy_len = + std::min(name.length(), sizeof(session_rename_buffer_) - 1); std::memcpy(session_rename_buffer_, name.c_str(), copy_len); session_rename_buffer_[copy_len] = '\0'; show_session_rename_dialog_ = true; } - + ImGui::SameLine(); - + // Close button logic bool can_close = GetActiveSessionCount() > 1; if (!can_close) { ImGui::BeginDisabled(); } - + if (ImGui::Button("Close")) { if (is_current) { CloseCurrentSession(); } else { // Remove non-current session directly RemoveSession(i); - show_session_switcher_ = false; // Close switcher since indices changed + show_session_switcher_ = + false; // Close switcher since indices changed } } - + if (!can_close) { ImGui::EndDisabled(); } - + ImGui::EndGroup(); - + ImGui::PopID(); } - + ImGui::EndTable(); } - + ImGui::Separator(); - if (ImGui::Button(absl::StrFormat("%s Close Switcher", ICON_MD_CLOSE).c_str(), ImVec2(-1, 0))) { + if (ImGui::Button( + absl::StrFormat("%s Close Switcher", ICON_MD_CLOSE).c_str(), + ImVec2(-1, 0))) { show_session_switcher_ = false; } } @@ -2312,78 +2505,92 @@ void EditorManager::DrawSessionSwitcher() { } void EditorManager::DrawSessionManager() { - if (!show_session_manager_) return; - - if (ImGui::Begin(absl::StrCat(ICON_MD_VIEW_LIST, " Session Manager").c_str(), + if (!show_session_manager_) + return; + + if (ImGui::Begin(absl::StrCat(ICON_MD_VIEW_LIST, " Session Manager").c_str(), &show_session_manager_)) { - + ImGui::Text("%s Session Management", ICON_MD_MANAGE_ACCOUNTS); - + if (ImGui::Button(absl::StrCat(ICON_MD_ADD, " New Session").c_str())) { CreateNewSession(); } ImGui::SameLine(); - if (ImGui::Button(absl::StrCat(ICON_MD_CONTENT_COPY, " Duplicate Current").c_str()) && current_rom_) { + if (ImGui::Button( + absl::StrCat(ICON_MD_CONTENT_COPY, " Duplicate Current").c_str()) && + current_rom_) { DuplicateCurrentSession(); } - + ImGui::Separator(); - ImGui::Text("%s Active Sessions (%zu)", ICON_MD_TAB, GetActiveSessionCount()); - + ImGui::Text("%s Active Sessions (%zu)", ICON_MD_TAB, + GetActiveSessionCount()); + // Enhanced session management table with proper sizing const float AVAILABLE_HEIGHT = ImGui::GetContentRegionAvail().y; - - if (ImGui::BeginTable("SessionTable", 6, - ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | - ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | - ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_ContextMenuInBody, - ImVec2(0, AVAILABLE_HEIGHT))) { - + + if (ImGui::BeginTable("SessionTable", 6, + ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | + ImGuiTableFlags_Resizable | + ImGuiTableFlags_ScrollY | + ImGuiTableFlags_SizingStretchProp | + ImGuiTableFlags_ContextMenuInBody, + ImVec2(0, AVAILABLE_HEIGHT))) { + // Setup columns with explicit sizing for better control - ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch, 0.15f); - ImGui::TableSetupColumn("ROM Title", ImGuiTableColumnFlags_WidthStretch, 0.3f); + ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch, + 0.15f); + ImGui::TableSetupColumn("ROM Title", ImGuiTableColumnFlags_WidthStretch, + 0.3f); ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, 70.0f); - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 80.0f); - ImGui::TableSetupColumn("Custom OW", ImGuiTableColumnFlags_WidthFixed, 80.0f); - ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthStretch, 0.25f); + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, + 80.0f); + ImGui::TableSetupColumn("Custom OW", ImGuiTableColumnFlags_WidthFixed, + 80.0f); + ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthStretch, + 0.25f); ImGui::TableHeadersRow(); - + for (size_t i = 0; i < sessions_.size(); ++i) { auto& session = sessions_[i]; - + // Skip closed sessions in session manager too if (session.custom_name == "[CLOSED SESSION]") { continue; } - + bool is_current = (&session.rom == current_rom_); - - ImGui::TableNextRow(ImGuiTableRowFlags_None, 50.0f); // Consistent row height + + ImGui::TableNextRow(ImGuiTableRowFlags_None, + 50.0f); // Consistent row height ImGui::PushID(static_cast(i)); - + // Session name column ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); if (is_current) { - ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), - "%s Session %zu", ICON_MD_STAR, i + 1); + ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s Session %zu", + ICON_MD_STAR, i + 1); } else { ImGui::Text("%s Session %zu", ICON_MD_TAB, i + 1); } - + // ROM title column ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); std::string display_name = session.GetDisplayName(); if (!session.custom_name.empty()) { - ImGui::TextColored(ImVec4(0.7f, 0.9f, 1.0f, 1.0f), "%s %s", ICON_MD_EDIT, display_name.c_str()); + ImGui::TextColored(ImVec4(0.7f, 0.9f, 1.0f, 1.0f), "%s %s", + ICON_MD_EDIT, display_name.c_str()); } else { // Use TextWrapped for long ROM titles - ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetColumnWidth()); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + + ImGui::GetColumnWidth()); ImGui::Text("%s", display_name.c_str()); ImGui::PopTextWrapPos(); } - + // File size column ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); @@ -2392,46 +2599,55 @@ void EditorManager::DrawSessionManager() { } else { ImGui::TextDisabled("N/A"); } - + // Status column ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); if (session.rom.is_loaded()) { if (session.rom.dirty()) { - ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "%s", ICON_MD_EDIT); + ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "%s", + ICON_MD_EDIT); } else { - ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", ICON_MD_CHECK_CIRCLE); + ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", + ICON_MD_CHECK_CIRCLE); } } else { - ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s", ICON_MD_RADIO_BUTTON_UNCHECKED); + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s", + ICON_MD_RADIO_BUTTON_UNCHECKED); } - + // Custom Overworld checkbox column ImGui::TableNextColumn(); - + // Center the checkbox vertically - float checkbox_offset = (ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) * 0.5f; + float checkbox_offset = + (ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) * 0.5f; ImGui::SetCursorPosY(ImGui::GetCursorPosY() + checkbox_offset); - - ImGui::PushID(static_cast(i + 100)); // Different ID to avoid conflicts - bool custom_ow_enabled = session.feature_flags.overworld.kLoadCustomOverworld; + + ImGui::PushID( + static_cast(i + 100)); // Different ID to avoid conflicts + bool custom_ow_enabled = + session.feature_flags.overworld.kLoadCustomOverworld; if (ImGui::Checkbox("##CustomOW", &custom_ow_enabled)) { - session.feature_flags.overworld.kLoadCustomOverworld = custom_ow_enabled; + session.feature_flags.overworld.kLoadCustomOverworld = + custom_ow_enabled; if (is_current) { - core::FeatureFlags::get().overworld.kLoadCustomOverworld = custom_ow_enabled; + core::FeatureFlags::get().overworld.kLoadCustomOverworld = + custom_ow_enabled; } - toast_manager_.Show(absl::StrFormat("Session %zu: Custom Overworld %s", - i + 1, custom_ow_enabled ? "Enabled" : "Disabled"), - editor::ToastType::kInfo); + toast_manager_.Show( + absl::StrFormat("Session %zu: Custom Overworld %s", i + 1, + custom_ow_enabled ? "Enabled" : "Disabled"), + editor::ToastType::kInfo); } ImGui::PopID(); - + // Actions column with better button layout ImGui::TableNextColumn(); - + // Create button group for better alignment ImGui::BeginGroup(); - + if (!is_current) { if (ImGui::Button("Switch")) { SwitchToSession(i); @@ -2441,46 +2657,47 @@ void EditorManager::DrawSessionManager() { ImGui::Button("Current"); ImGui::EndDisabled(); } - + ImGui::SameLine(); if (ImGui::Button("Rename")) { session_to_rename_ = i; // Safe string copy with bounds checking const std::string& name = session.GetDisplayName(); - size_t copy_len = std::min(name.length(), sizeof(session_rename_buffer_) - 1); + size_t copy_len = + std::min(name.length(), sizeof(session_rename_buffer_) - 1); std::memcpy(session_rename_buffer_, name.c_str(), copy_len); session_rename_buffer_[copy_len] = '\0'; show_session_rename_dialog_ = true; } - + ImGui::SameLine(); - + // Close button logic bool can_close = GetActiveSessionCount() > 1; if (!can_close || is_current) { ImGui::BeginDisabled(); } - + if (ImGui::Button("Close")) { if (is_current) { CloseCurrentSession(); - break; // Exit loop since current session was closed + break; // Exit loop since current session was closed } else { // Remove non-current session directly RemoveSession(i); - break; // Exit loop since session indices changed + break; // Exit loop since session indices changed } } - + if (!can_close || is_current) { ImGui::EndDisabled(); } - + ImGui::EndGroup(); - + ImGui::PopID(); } - + ImGui::EndTable(); } } @@ -2488,54 +2705,66 @@ void EditorManager::DrawSessionManager() { } void EditorManager::DrawLayoutPresets() { - if (!show_layout_presets_) return; - - if (ImGui::Begin(absl::StrCat(ICON_MD_BOOKMARK, " Layout Presets").c_str(), + if (!show_layout_presets_) + return; + + if (ImGui::Begin(absl::StrCat(ICON_MD_BOOKMARK, " Layout Presets").c_str(), &show_layout_presets_)) { - + ImGui::Text("%s Predefined Layouts", ICON_MD_DASHBOARD); - + // Predefined layouts - if (ImGui::Button(absl::StrCat(ICON_MD_DEVELOPER_MODE, " Developer Layout").c_str(), ImVec2(-1, 40))) { + if (ImGui::Button( + absl::StrCat(ICON_MD_DEVELOPER_MODE, " Developer Layout").c_str(), + ImVec2(-1, 40))) { LoadDeveloperLayout(); } ImGui::SameLine(); ImGui::Text("Code editing, debugging, testing"); - - if (ImGui::Button(absl::StrCat(ICON_MD_DESIGN_SERVICES, " Designer Layout").c_str(), ImVec2(-1, 40))) { + + if (ImGui::Button( + absl::StrCat(ICON_MD_DESIGN_SERVICES, " Designer Layout").c_str(), + ImVec2(-1, 40))) { LoadDesignerLayout(); } ImGui::SameLine(); ImGui::Text("Graphics, palettes, sprites"); - - if (ImGui::Button(absl::StrCat(ICON_MD_GAMEPAD, " Modder Layout").c_str(), ImVec2(-1, 40))) { + + if (ImGui::Button(absl::StrCat(ICON_MD_GAMEPAD, " Modder Layout").c_str(), + ImVec2(-1, 40))) { LoadModderLayout(); } ImGui::SameLine(); ImGui::Text("All gameplay editors"); - + ImGui::Separator(); ImGui::Text("%s Custom Presets", ICON_MD_BOOKMARK); - + // Lazy load workspace presets when UI is accessed if (!workspace_presets_loaded_) { RefreshWorkspacePresets(); } - + for (const auto& preset : workspace_presets_) { - if (ImGui::Button(absl::StrFormat("%s %s", ICON_MD_BOOKMARK, preset.c_str()).c_str(), ImVec2(-1, 0))) { + if (ImGui::Button( + absl::StrFormat("%s %s", ICON_MD_BOOKMARK, preset.c_str()) + .c_str(), + ImVec2(-1, 0))) { LoadWorkspacePreset(preset); - toast_manager_.Show(absl::StrFormat("Loaded preset: %s", preset.c_str()), - editor::ToastType::kSuccess); + toast_manager_.Show( + absl::StrFormat("Loaded preset: %s", preset.c_str()), + editor::ToastType::kSuccess); } } - + if (workspace_presets_.empty()) { - ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "No custom presets saved"); + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), + "No custom presets saved"); } - + ImGui::Separator(); - if (ImGui::Button(absl::StrCat(ICON_MD_ADD, " Save Current Layout").c_str())) { + if (ImGui::Button( + absl::StrCat(ICON_MD_ADD, " Save Current Layout").c_str())) { show_save_workspace_preset_ = true; } } @@ -2554,46 +2783,52 @@ bool EditorManager::HasDuplicateSession(const std::string& filepath) { void EditorManager::RenameSession(size_t index, const std::string& new_name) { if (index < sessions_.size()) { sessions_[index].custom_name = new_name; - toast_manager_.Show(absl::StrFormat("Session renamed to: %s", new_name.c_str()), - editor::ToastType::kSuccess); + toast_manager_.Show( + absl::StrFormat("Session renamed to: %s", new_name.c_str()), + editor::ToastType::kSuccess); } } -std::string EditorManager::GenerateUniqueEditorTitle(EditorType type, size_t session_index) { +std::string EditorManager::GenerateUniqueEditorTitle(EditorType type, + size_t session_index) { std::string base_name = GetEditorName(type); - + if (sessions_.size() <= 1) { - return base_name; // No need for session identifier with single session + return base_name; // No need for session identifier with single session } - + // Add session identifier const auto& session = sessions_[session_index]; std::string session_name = session.GetDisplayName(); - + // Truncate long session names if (session_name.length() > 15) { session_name = session_name.substr(0, 12) + "..."; } - + return absl::StrFormat("%s (%s)", base_name.c_str(), session_name.c_str()); } void EditorManager::DrawSessionRenameDialog() { - if (!show_session_rename_dialog_) return; - - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + if (!show_session_rename_dialog_) + return; + + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), + ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(400, 150), ImGuiCond_Appearing); - - if (ImGui::Begin("Rename Session", &show_session_rename_dialog_, ImGuiWindowFlags_NoResize)) { + + if (ImGui::Begin("Rename Session", &show_session_rename_dialog_, + ImGuiWindowFlags_NoResize)) { if (session_to_rename_ < sessions_.size()) { const auto& session = sessions_[session_to_rename_]; - + ImGui::Text("Rename Session:"); ImGui::Text("Current: %s", session.GetDisplayName().c_str()); ImGui::Separator(); - - ImGui::InputText("New Name", session_rename_buffer_, sizeof(session_rename_buffer_)); - + + ImGui::InputText("New Name", session_rename_buffer_, + sizeof(session_rename_buffer_)); + ImGui::Separator(); if (ImGui::Button("Rename", ImVec2(120, 0))) { std::string new_name(session_rename_buffer_); @@ -2602,7 +2837,7 @@ void EditorManager::DrawSessionRenameDialog() { } show_session_rename_dialog_ = false; } - + ImGui::SameLine(); if (ImGui::Button("Cancel", ImVec2(120, 0))) { show_session_rename_dialog_ = false; @@ -2614,149 +2849,186 @@ void EditorManager::DrawSessionRenameDialog() { void EditorManager::DrawWelcomeScreen() { // Make welcome screen moveable but with a good default position - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), + ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); - + // Create a subtle animated background effect static float animation_time = 0.0f; animation_time += ImGui::GetIO().DeltaTime; - + // Make it moveable and resizable but keep the custom styling - ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground; - + ImGuiWindowFlags flags = + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground; + // Use a unique window name to prevent stacking static int welcome_window_id = 0; - std::string window_name = absl::StrFormat("Welcome to YAZE##welcome_%d", welcome_window_id); - + std::string window_name = + absl::StrFormat("Welcome to YAZE##welcome_%d", welcome_window_id); + bool welcome_was_open = show_welcome_screen_; if (ImGui::Begin(window_name.c_str(), &show_welcome_screen_, flags)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImVec2 window_pos = ImGui::GetWindowPos(); ImVec2 window_size = ImGui::GetWindowSize(); - + // Get theme colors for welcome screen auto& theme_manager = gui::ThemeManager::Get(); auto bg_color = theme_manager.GetWelcomeScreenBackground(); - auto border_color = theme_manager.GetWelcomeScreenBorder(); + auto border_color = theme_manager.GetWelcomeScreenBorder(); auto accent_color = theme_manager.GetWelcomeScreenAccent(); - + // Draw themed gradient background - ImU32 bg_top = ImGui::ColorConvertFloat4ToU32(ImVec4(bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha)); - ImU32 bg_bottom = ImGui::ColorConvertFloat4ToU32(ImVec4(bg_color.red * 0.8f, bg_color.green * 0.8f, bg_color.blue * 0.8f, bg_color.alpha)); + ImU32 bg_top = ImGui::ColorConvertFloat4ToU32( + ImVec4(bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha)); + ImU32 bg_bottom = ImGui::ColorConvertFloat4ToU32( + ImVec4(bg_color.red * 0.8f, bg_color.green * 0.8f, bg_color.blue * 0.8f, + bg_color.alpha)); draw_list->AddRectFilledMultiColor( - window_pos, + window_pos, ImVec2(window_pos.x + window_size.x, window_pos.y + window_size.y), bg_top, bg_top, bg_bottom, bg_bottom); - + // Themed animated border float border_thickness = 3.0f; float pulse = 0.8f + 0.2f * sinf(animation_time * 2.0f); - ImU32 themed_border = ImGui::ColorConvertFloat4ToU32(ImVec4( - border_color.red, border_color.green, border_color.blue, pulse * border_color.alpha)); - draw_list->AddRect(window_pos, - ImVec2(window_pos.x + window_size.x, window_pos.y + window_size.y), - themed_border, 12.0f, 0, border_thickness); - + ImU32 themed_border = ImGui::ColorConvertFloat4ToU32( + ImVec4(border_color.red, border_color.green, border_color.blue, + pulse * border_color.alpha)); + draw_list->AddRect( + window_pos, + ImVec2(window_pos.x + window_size.x, window_pos.y + window_size.y), + themed_border, 12.0f, 0, border_thickness); + // Enhanced floating particles effect with multiple layers for (int layer = 0; layer < 2; ++layer) { int particle_count = layer == 0 ? 12 : 8; float layer_speed = layer == 0 ? 1.0f : 0.6f; float layer_alpha = layer == 0 ? 0.4f : 0.2f; - + for (int i = 0; i < particle_count; ++i) { float time_offset = layer * 3.14159f + i * 0.8f; - float offset_x = sinf(animation_time * 0.5f * layer_speed + time_offset) * (30.0f + layer * 10.0f); - float offset_y = cosf(animation_time * 0.3f * layer_speed + time_offset) * (20.0f + layer * 8.0f); - + float offset_x = + sinf(animation_time * 0.5f * layer_speed + time_offset) * + (30.0f + layer * 10.0f); + float offset_y = + cosf(animation_time * 0.3f * layer_speed + time_offset) * + (20.0f + layer * 8.0f); + // Distribute particles across the window float base_x = window_pos.x + (window_size.x / particle_count) * i + 40; float base_y = window_pos.y + 80 + layer * 30; - + ImVec2 particle_pos = ImVec2(base_x + offset_x, base_y + offset_y); - + // Pulsing alpha effect - float alpha = layer_alpha + 0.3f * sinf(animation_time * 1.5f + time_offset); + float alpha = + layer_alpha + 0.3f * sinf(animation_time * 1.5f + time_offset); ImU32 particle_color = ImGui::ColorConvertFloat4ToU32(ImVec4( accent_color.red, accent_color.green, accent_color.blue, alpha)); - + // Varying particle sizes - float radius = 1.5f + layer * 0.5f + sinf(animation_time * 2.0f + time_offset) * 0.8f; + float radius = 1.5f + layer * 0.5f + + sinf(animation_time * 2.0f + time_offset) * 0.8f; draw_list->AddCircleFilled(particle_pos, radius, particle_color); - + // Add subtle glow effect for layer 0 if (layer == 0) { - ImU32 glow_color = ImGui::ColorConvertFloat4ToU32(ImVec4( - accent_color.red, accent_color.green, accent_color.blue, alpha * 0.3f)); + ImU32 glow_color = ImGui::ColorConvertFloat4ToU32( + ImVec4(accent_color.red, accent_color.green, accent_color.blue, + alpha * 0.3f)); draw_list->AddCircleFilled(particle_pos, radius + 1.0f, glow_color); } } } - + // Header with themed styling ImGui::Spacing(); - ImGui::SetCursorPosX((window_size.x - ImGui::CalcTextSize("Welcome to Yet Another Zelda3 Editor").x) * 0.5f); + ImGui::SetCursorPosX( + (window_size.x - + ImGui::CalcTextSize("Welcome to Yet Another Zelda3 Editor").x) * + 0.5f); auto text_color = theme_manager.GetCurrentTheme().text_primary; - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(text_color.red, text_color.green, text_color.blue, text_color.alpha)); + ImGui::PushStyleColor( + ImGuiCol_Text, ImVec4(text_color.red, text_color.green, text_color.blue, + text_color.alpha)); ImGui::Text("Welcome to Yet Another Zelda3 Editor"); ImGui::PopStyleColor(); - - ImGui::SetCursorPosX((window_size.x - ImGui::CalcTextSize("The Legend of Zelda: A Link to the Past").x) * 0.5f); + + ImGui::SetCursorPosX( + (window_size.x - + ImGui::CalcTextSize("The Legend of Zelda: A Link to the Past").x) * + 0.5f); auto subtitle_color = theme_manager.GetCurrentTheme().text_secondary; - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(subtitle_color.red, subtitle_color.green, subtitle_color.blue, subtitle_color.alpha * 0.9f)); + ImGui::PushStyleColor( + ImGuiCol_Text, + ImVec4(subtitle_color.red, subtitle_color.green, subtitle_color.blue, + subtitle_color.alpha * 0.9f)); ImGui::Text("The Legend of Zelda: A Link to the Past"); ImGui::PopStyleColor(); - + ImGui::Spacing(); - + // Themed decorative line with glow effect (positioned closer to header) - float line_y = window_pos.y + 30; // Move even higher for tighter header integration - float line_margin = 80; // Maintain good horizontal balance + float line_y = + window_pos.y + 30; // Move even higher for tighter header integration + float line_margin = 80; // Maintain good horizontal balance ImVec2 line_start = ImVec2(window_pos.x + line_margin, line_y); - ImVec2 line_end = ImVec2(window_pos.x + window_size.x - line_margin, line_y); - + ImVec2 line_end = + ImVec2(window_pos.x + window_size.x - line_margin, line_y); + // Enhanced glow effect with multiple line layers for depth float glow_alpha = 0.6f + 0.4f * sinf(animation_time * 1.5f); ImU32 line_color = ImGui::ColorConvertFloat4ToU32(ImVec4( accent_color.red, accent_color.green, accent_color.blue, glow_alpha)); - + // Draw main line with glow effect - draw_list->AddLine(line_start, line_end, - ImGui::ColorConvertFloat4ToU32(ImVec4(accent_color.red, accent_color.green, accent_color.blue, 0.3f)), - 4.0f); // Glow layer - draw_list->AddLine(line_start, line_end, line_color, 2.0f); // Main line - + draw_list->AddLine( + line_start, line_end, + ImGui::ColorConvertFloat4ToU32(ImVec4( + accent_color.red, accent_color.green, accent_color.blue, 0.3f)), + 4.0f); // Glow layer + draw_list->AddLine(line_start, line_end, line_color, 2.0f); // Main line + ImGui::Spacing(); ImGui::Spacing(); - + // Show different messages based on state if (!sessions_.empty() && !current_rom_) { ImGui::Separator(); ImGui::Spacing(); - ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.0f, 1.0f), ICON_MD_WARNING " ROM Loading Required"); - TextWrapped("A session exists but no ROM is loaded. Please load a ROM file to continue editing."); + ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.0f, 1.0f), + ICON_MD_WARNING " ROM Loading Required"); + TextWrapped( + "A session exists but no ROM is loaded. Please load a ROM file to " + "continue editing."); ImGui::Text("Active Sessions: %zu", GetActiveSessionCount()); } else { ImGui::Separator(); ImGui::Spacing(); TextWrapped("No ROM loaded."); } - + ImGui::Spacing(); - + // Enhanced primary actions with glowing buttons ImGui::Text("Get Started:"); ImGui::Spacing(); - + // Themed primary buttons with enhanced effects auto current_theme = theme_manager.GetCurrentTheme(); - ImGui::PushStyleColor(ImGuiCol_Button, ConvertColorToImVec4(current_theme.primary)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ConvertColorToImVec4(current_theme.accent)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ConvertColorToImVec4(current_theme.secondary)); - + ImGui::PushStyleColor(ImGuiCol_Button, + ConvertColorToImVec4(current_theme.primary)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, + ConvertColorToImVec4(current_theme.accent)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, + ConvertColorToImVec4(current_theme.secondary)); + if (ImGui::Button(ICON_MD_FILE_OPEN " Open ROM File", ImVec2(200, 40))) { status_ = LoadRom(); if (!status_.ok()) { - toast_manager_.Show(std::string(status_.message()), editor::ToastType::kError); + toast_manager_.Show(std::string(status_.message()), + editor::ToastType::kError); } } ImGui::SameLine(); @@ -2765,41 +3037,44 @@ void EditorManager::DrawWelcomeScreen() { if (!file_name.empty()) { status_ = OpenRomOrProject(file_name); if (!status_.ok()) { - toast_manager_.Show(std::string(status_.message()), editor::ToastType::kError); + toast_manager_.Show(std::string(status_.message()), + editor::ToastType::kError); } } } - + ImGui::PopStyleColor(3); - + ImGui::Spacing(); - + // Feature flags section (per-session) ImGui::Text("Options:"); auto* flags = GetCurrentFeatureFlags(); - Checkbox("Load custom overworld features", &flags->overworld.kLoadCustomOverworld); - + Checkbox("Load custom overworld features", + &flags->overworld.kLoadCustomOverworld); + ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); - + // Recent files section (reuse homepage logic) ImGui::Text("Recent Files:"); ImGui::BeginChild("RecentFiles", ImVec2(0, 100), true); static core::RecentFilesManager manager("recent_files.txt"); manager.Load(); - for (const auto &file : manager.GetRecentFiles()) { + for (const auto& file : manager.GetRecentFiles()) { if (gui::ClickableText(file.c_str())) { status_ = OpenRomOrProject(file); if (!status_.ok()) { - toast_manager_.Show(std::string(status_.message()), editor::ToastType::kError); + toast_manager_.Show(std::string(status_.message()), + editor::ToastType::kError); } } } ImGui::EndChild(); - + ImGui::Spacing(); - + // Show editor access buttons for loaded sessions bool has_loaded_sessions = false; for (const auto& session : sessions_) { @@ -2808,121 +3083,159 @@ void EditorManager::DrawWelcomeScreen() { break; } } - + if (has_loaded_sessions) { ImGui::Spacing(); ImGui::Separator(); ImGui::Text("Available Editors:"); - ImGui::Text("Click to open editor windows that can be docked side by side"); + ImGui::Text( + "Click to open editor windows that can be docked side by side"); ImGui::Spacing(); - + // Show sessions and their editors - for (size_t session_idx = 0; session_idx < sessions_.size(); ++session_idx) { + for (size_t session_idx = 0; session_idx < sessions_.size(); + ++session_idx) { const auto& session = sessions_[session_idx]; - if (!session.rom.is_loaded()) continue; - + if (!session.rom.is_loaded()) + continue; + ImGui::Text("Session: %s", session.GetDisplayName().c_str()); - + // Editor buttons in a grid layout for this session - if (ImGui::BeginTable(absl::StrFormat("EditorsTable##%zu", session_idx).c_str(), 4, - ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX)) { - + if (ImGui::BeginTable( + absl::StrFormat("EditorsTable##%zu", session_idx).c_str(), 4, + ImGuiTableFlags_SizingFixedFit | + ImGuiTableFlags_NoHostExtendX)) { + // Row 1: Primary editors ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_MAP " Overworld##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_MAP " Overworld##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.overworld_editor_.set_active(true); } ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_DOMAIN " Dungeon##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_DOMAIN " Dungeon##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.dungeon_editor_.set_active(true); } ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_IMAGE " Graphics##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_IMAGE " Graphics##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.graphics_editor_.set_active(true); } ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_PALETTE " Palette##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_PALETTE " Palette##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.palette_editor_.set_active(true); } - + // Row 2: Secondary editors ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_MESSAGE " Message##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_MESSAGE " Message##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.message_editor_.set_active(true); } ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_PERSON " Sprite##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_PERSON " Sprite##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.sprite_editor_.set_active(true); } ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_MUSIC_NOTE " Music##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_MUSIC_NOTE " Music##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.music_editor_.set_active(true); } ImGui::TableNextColumn(); - if (ImGui::Button(absl::StrFormat(ICON_MD_MONITOR " Screen##%zu", session_idx).c_str(), ImVec2(120, 30))) { + if (ImGui::Button( + absl::StrFormat(ICON_MD_MONITOR " Screen##%zu", session_idx) + .c_str(), + ImVec2(120, 30))) { sessions_[session_idx].editors.screen_editor_.set_active(true); } - + ImGui::EndTable(); } - + if (session_idx < sessions_.size() - 1) { ImGui::Spacing(); } } } - + // Links section ImGui::Spacing(); ImGui::Separator(); ImGui::Text("Help & Support:"); if (gui::ClickableText(ICON_MD_HELP " Getting Started Guide")) { - gui::OpenUrl("https://github.com/scawful/yaze/blob/master/docs/01-getting-started.md"); + gui::OpenUrl( + "https://github.com/scawful/yaze/blob/master/docs/" + "01-getting-started.md"); } if (gui::ClickableText(ICON_MD_BUG_REPORT " Report Issues")) { gui::OpenUrl("https://github.com/scawful/yaze/issues"); } - + // Show tip about drag and drop ImGui::Spacing(); - ImGui::TextColored(ImVec4(0.6f, 0.8f, 1.0f, 1.0f), ICON_MD_TIPS_AND_UPDATES " Tip: Drag and drop ROM files onto the window"); - + ImGui::TextColored(ImVec4(0.6f, 0.8f, 1.0f, 1.0f), ICON_MD_TIPS_AND_UPDATES + " Tip: Drag and drop ROM files onto the window"); + // Add settings and customization section (accessible before ROM loading) ImGui::Spacing(); ImGui::Separator(); ImGui::Text("%s Customization & Settings", ICON_MD_SETTINGS); - + // Theme and display settings buttons (always accessible) static bool show_welcome_theme_selector = false; - if (ImGui::Button(absl::StrFormat("%s Theme Settings", ICON_MD_PALETTE).c_str(), ImVec2(180, 35))) { + if (ImGui::Button( + absl::StrFormat("%s Theme Settings", ICON_MD_PALETTE).c_str(), + ImVec2(180, 35))) { show_welcome_theme_selector = true; } - + // Show theme selector if requested if (show_welcome_theme_selector) { auto& theme_manager = gui::ThemeManager::Get(); theme_manager.ShowThemeSelector(&show_welcome_theme_selector); } - + ImGui::SameLine(); - if (ImGui::Button(absl::StrFormat("%s Display Settings", ICON_MD_DISPLAY_SETTINGS).c_str(), ImVec2(180, 35))) { + if (ImGui::Button( + absl::StrFormat("%s Display Settings", ICON_MD_DISPLAY_SETTINGS) + .c_str(), + ImVec2(180, 35))) { // Open display settings popup (make it accessible without ROM) popup_manager_->Show("Display Settings"); } - + ImGui::SameLine(); - if (ImGui::Button(absl::StrFormat("%s Command Palette", ICON_MD_TERMINAL).c_str(), ImVec2(180, 35))) { + if (ImGui::Button( + absl::StrFormat("%s Command Palette", ICON_MD_TERMINAL).c_str(), + ImVec2(180, 35))) { show_command_palette_ = true; } } ImGui::End(); - + // Check if the welcome screen was manually closed via the close button if (welcome_was_open && !show_welcome_screen_) { welcome_screen_manually_closed_ = true; } } - } // namespace editor } // namespace yaze diff --git a/src/app/editor/graphics/palette_editor.cc b/src/app/editor/graphics/palette_editor.cc index 68671c12..0488c953 100644 --- a/src/app/editor/graphics/palette_editor.cc +++ b/src/app/editor/graphics/palette_editor.cc @@ -2,6 +2,7 @@ #include "absl/status/status.h" #include "absl/strings/str_cat.h" +#include "app/core/performance_monitor.h" #include "app/gfx/snes_palette.h" #include "app/gui/color.h" #include "imgui/imgui.h" @@ -171,6 +172,8 @@ absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded) { void PaletteEditor::Initialize() {} absl::Status PaletteEditor::Load() { + core::ScopedTimer timer("PaletteEditor::Load"); + if (rom()->is_loaded()) { // Initialize the labels for (int i = 0; i < kNumPalettes; i++) { diff --git a/src/app/editor/graphics/screen_editor.cc b/src/app/editor/graphics/screen_editor.cc index e66b8338..e613027d 100644 --- a/src/app/editor/graphics/screen_editor.cc +++ b/src/app/editor/graphics/screen_editor.cc @@ -6,6 +6,7 @@ #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "app/core/performance_monitor.h" #include "app/core/platform/file_dialog.h" #include "app/core/window.h" #include "app/gfx/arena.h" @@ -29,6 +30,8 @@ constexpr uint32_t kRedPen = 0xFF0000FF; void ScreenEditor::Initialize() {} absl::Status ScreenEditor::Load() { + core::ScopedTimer timer("ScreenEditor::Load"); + ASSIGN_OR_RETURN(dungeon_maps_, zelda3::LoadDungeonMaps(*rom(), dungeon_map_labels_)); RETURN_IF_ERROR(zelda3::LoadDungeonMapTile16( diff --git a/src/app/editor/message/message_editor.cc b/src/app/editor/message/message_editor.cc index d1611508..a4f7c192 100644 --- a/src/app/editor/message/message_editor.cc +++ b/src/app/editor/message/message_editor.cc @@ -6,6 +6,7 @@ #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" +#include "app/core/performance_monitor.h" #include "app/core/platform/file_dialog.h" #include "app/core/window.h" #include "app/gfx/bitmap.h" @@ -91,7 +92,10 @@ void MessageEditor::Initialize() { DrawMessagePreview(); } -absl::Status MessageEditor::Load() { return absl::OkStatus(); } +absl::Status MessageEditor::Load() { + core::ScopedTimer timer("MessageEditor::Load"); + return absl::OkStatus(); +} absl::Status MessageEditor::Update() { if (BeginTable("##MessageEditor", 4, kMessageTableFlags)) { diff --git a/src/app/editor/music/music_editor.cc b/src/app/editor/music/music_editor.cc index be04ba9e..9bf78a59 100644 --- a/src/app/editor/music/music_editor.cc +++ b/src/app/editor/music/music_editor.cc @@ -1,6 +1,7 @@ #include "music_editor.h" #include "absl/strings/str_format.h" +#include "app/core/performance_monitor.h" #include "app/editor/code/assembly_editor.h" #include "app/gui/icons.h" #include "app/gui/input.h" @@ -12,6 +13,7 @@ namespace editor { void MusicEditor::Initialize() {} absl::Status MusicEditor::Load() { + core::ScopedTimer timer("MusicEditor::Load"); return absl::OkStatus(); } diff --git a/src/app/editor/sprite/sprite_editor.cc b/src/app/editor/sprite/sprite_editor.cc index 52590624..530debb5 100644 --- a/src/app/editor/sprite/sprite_editor.cc +++ b/src/app/editor/sprite/sprite_editor.cc @@ -1,5 +1,6 @@ #include "sprite_editor.h" +#include "app/core/performance_monitor.h" #include "app/core/platform/file_dialog.h" #include "app/editor/sprite/zsprite.h" #include "app/gfx/arena.h" @@ -24,7 +25,10 @@ using ImGui::Text; void SpriteEditor::Initialize() {} -absl::Status SpriteEditor::Load() { return absl::OkStatus(); } +absl::Status SpriteEditor::Load() { + core::ScopedTimer timer("SpriteEditor::Load"); + return absl::OkStatus(); +} absl::Status SpriteEditor::Update() { if (rom()->is_loaded() && !sheets_loaded_) { diff --git a/src/app/editor/system/settings_editor.cc b/src/app/editor/system/settings_editor.cc index 2291b4a4..5c18119c 100644 --- a/src/app/editor/system/settings_editor.cc +++ b/src/app/editor/system/settings_editor.cc @@ -3,6 +3,7 @@ #include "absl/status/status.h" #include "app/core/features.h" +#include "app/core/performance_monitor.h" #include "app/gui/style.h" #include "imgui/imgui.h" @@ -23,7 +24,10 @@ using ImGui::TableSetupColumn; void SettingsEditor::Initialize() {} -absl::Status SettingsEditor::Load() { return absl::OkStatus(); } +absl::Status SettingsEditor::Load() { + core::ScopedTimer timer("SettingsEditor::Load"); + return absl::OkStatus(); +} absl::Status SettingsEditor::Update() { if (BeginTabBar("Settings", ImGuiTabBarFlags_None)) { diff --git a/src/app/zelda3/sprite/sprite.cc b/src/app/zelda3/sprite/sprite.cc index 2d1e83c8..bbdf5bc2 100644 --- a/src/app/zelda3/sprite/sprite.cc +++ b/src/app/zelda3/sprite/sprite.cc @@ -869,7 +869,6 @@ void Sprite::DrawSpriteTile(int x, int y, int srcx, int srcy, int pal, bool mirror_x, bool mirror_y, int sizex, int sizey) { if (current_gfx_.empty()) { - std::cout << "No gfx loaded" << std::endl; return; }