feat(editor): integrate session management into EditorManager

- Added a new `session_types` module to encapsulate session-related structures and logic, including `EditorSet` and `RomSession`.
- Refactored `EditorManager` to utilize `SessionCoordinator` for session management, enhancing modularity and clarity.
- Updated various methods to replace direct references to current ROM and editor sets with calls to `SessionCoordinator`, improving session handling.
- Removed redundant session management logic from `EditorManager`, delegating responsibilities to `SessionCoordinator`.

Benefits:
- Streamlines session management, making it easier to handle multiple sessions and their associated editors.
- Enhances code maintainability by centralizing session-related logic and reducing coupling within the `EditorManager`.
- Improves overall architecture by promoting a clearer separation of concerns between session management and editor functionality.
This commit is contained in:
scawful
2025-10-15 18:44:27 -04:00
parent 60f0925984
commit 6f02852d3f
9 changed files with 665 additions and 718 deletions

View File

@@ -14,6 +14,7 @@ set(
app/editor/dungeon/dungeon_usage_tracker.cc
app/editor/dungeon/object_editor_card.cc
app/editor/editor_manager.cc
app/editor/session_types.cc
app/editor/graphics/gfx_group_editor.cc
app/editor/graphics/graphics_editor.cc
app/editor/graphics/screen_editor.cc

File diff suppressed because it is too large Load Diff

View File

@@ -6,28 +6,19 @@
#include "app/editor/editor.h"
#include "app/editor/system/user_settings.h"
#include "app/editor/ui/workspace_manager.h"
#include "app/editor/session_types.h"
#include "imgui/imgui.h"
#include <cstddef>
#include <deque>
#include <vector>
#include <memory>
#include <string>
#include "absl/status/status.h"
#include "app/core/features.h"
#include "app/core/project.h"
#include "app/editor/agent/agent_chat_history_popup.h"
#include "app/editor/code/assembly_editor.h"
#include "app/editor/code/memory_editor.h"
#include "app/editor/code/project_file_editor.h"
#include "app/editor/dungeon/dungeon_editor_v2.h"
#include "app/editor/graphics/graphics_editor.h"
#include "app/editor/graphics/screen_editor.h"
#include "app/editor/message/message_editor.h"
#include "app/editor/music/music_editor.h"
#include "app/editor/overworld/overworld_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/editor/sprite/sprite_editor.h"
#include "app/editor/system/editor_card_registry.h"
#include "app/editor/system/editor_registry.h"
#include "app/editor/system/menu_orchestrator.h"
@@ -36,7 +27,6 @@
#include "app/editor/system/proposal_drawer.h"
#include "app/editor/system/rom_file_manager.h"
#include "app/editor/system/session_coordinator.h"
#include "app/editor/system/settings_editor.h"
#include "app/editor/system/toast_manager.h"
#include "app/editor/system/window_delegate.h"
#include "app/editor/ui/editor_selection_dialog.h"
@@ -62,58 +52,6 @@ class AgentControlServer;
namespace yaze {
namespace editor {
/**
* @class EditorSet
* @brief Contains a complete set of editors for a single ROM instance
*/
class EditorSet {
public:
explicit EditorSet(Rom* rom = nullptr, UserSettings* user_settings = nullptr,
size_t session_id = 0)
: session_id_(session_id),
assembly_editor_(rom),
dungeon_editor_(rom),
graphics_editor_(rom),
music_editor_(rom),
overworld_editor_(rom),
palette_editor_(rom),
screen_editor_(rom),
sprite_editor_(rom),
settings_editor_(rom, user_settings),
message_editor_(rom),
memory_editor_(rom) {
active_editors_ = {&overworld_editor_, &dungeon_editor_, &graphics_editor_,
&palette_editor_, &sprite_editor_, &message_editor_,
&music_editor_, &screen_editor_, &settings_editor_,
&assembly_editor_};
}
void set_user_settings(UserSettings* settings) {
settings_editor_.set_user_settings(settings);
}
void ApplyDependencies(const EditorDependencies& dependencies);
size_t session_id() const { return session_id_; }
AssemblyEditor assembly_editor_;
DungeonEditorV2 dungeon_editor_;
GraphicsEditor graphics_editor_;
MusicEditor music_editor_;
OverworldEditor overworld_editor_;
PaletteEditor palette_editor_;
ScreenEditor screen_editor_;
SpriteEditor sprite_editor_;
SettingsEditor settings_editor_;
MessageEditor message_editor_;
MemoryEditorWithDiffChecker memory_editor_;
std::vector<Editor*> active_editors_;
private:
size_t session_id_ = 0;
};
/**
* @class EditorManager
* @brief The EditorManager controls the main editor window and manages the
@@ -144,15 +82,19 @@ class EditorManager {
auto version() const { return version_; }
MenuBuilder& menu_builder() { return menu_builder_; }
WorkspaceManager* workspace_manager() { return &workspace_manager_; }
absl::Status SetCurrentRom(Rom* rom);
auto GetCurrentRom() -> Rom* { return current_rom_; }
auto GetCurrentEditorSet() -> EditorSet* { return current_editor_set_; }
auto GetCurrentEditor() -> Editor* { return current_editor_; }
size_t GetCurrentSessionId() const { return current_session_id_; }
auto GetCurrentRom() const -> Rom* { return session_coordinator_ ? session_coordinator_->GetCurrentRom() : nullptr; }
auto GetCurrentEditorSet() const -> EditorSet* { return session_coordinator_ ? session_coordinator_->GetCurrentEditorSet() : nullptr; }
auto GetCurrentEditor() const -> Editor* { return current_editor_; }
size_t GetCurrentSessionId() const { return session_coordinator_ ? session_coordinator_->GetActiveSessionIndex() : 0; }
UICoordinator* ui_coordinator() { return ui_coordinator_.get(); }
auto overworld() -> yaze::zelda3::Overworld* {
return &current_editor_set_->overworld_editor_.overworld();
auto overworld() const -> yaze::zelda3::Overworld* {
if (auto* editor_set = GetCurrentEditorSet()) {
return &editor_set->overworld_editor_.overworld();
}
return nullptr;
}
// Session management helpers
@@ -262,9 +204,9 @@ class EditorManager {
ui_coordinator_->SetImGuiMetricsVisible(true);
}
void ShowHexEditor();
void ShowEmulator() { show_emulator_ = true; }
void ShowMemoryEditor() { show_memory_editor_ = true; }
void ShowResourceLabelManager() { show_resource_label_manager = true; }
void ShowEmulator() { if (ui_coordinator_) ui_coordinator_->SetEmulatorVisible(true); }
void ShowMemoryEditor() { if (ui_coordinator_) ui_coordinator_->SetMemoryEditorVisible(true); }
void ShowResourceLabelManager() { if (ui_coordinator_) ui_coordinator_->SetResourceLabelManagerVisible(true); }
void ShowCardBrowser() {
if (ui_coordinator_)
ui_coordinator_->ShowCardBrowser();
@@ -298,7 +240,7 @@ class EditorManager {
absl::Status RepairCurrentProject();
private:
absl::Status DrawRomSelector();
absl::Status DrawRomSelector() = delete; // Moved to UICoordinator
void DrawContextSensitiveCardControl(); // Card control for current editor
absl::Status LoadAssets();
@@ -308,16 +250,11 @@ class EditorManager {
bool quit_ = false;
bool show_emulator_ = false;
bool show_memory_editor_ = false;
bool show_asm_editor_ = false;
bool show_palette_editor_ = false;
bool show_resource_label_manager = false;
// Note: show_imgui_demo_ and show_imgui_metrics_ moved to UICoordinator
// Note: All show_* flags are being moved to UICoordinator
// Access via ui_coordinator_->IsXxxVisible() or SetXxxVisible()
// Workspace dialog flags (managed by EditorManager, not UI)
bool show_workspace_layout = false;
bool show_save_workspace_preset_ = false;
bool show_load_workspace_preset_ = false;
size_t session_to_rename_ = 0;
char session_rename_buffer_[256] = {};
@@ -355,40 +292,13 @@ class EditorManager {
emu::Emulator emulator_;
public:
struct RomSession {
Rom rom;
EditorSet editors;
std::string custom_name; // User-defined session name
std::string filepath; // ROM filepath for duplicate detection
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
RomSession() = default;
explicit RomSession(Rom&& r, UserSettings* user_settings = nullptr,
size_t session_id = 0)
: rom(std::move(r)), editors(&rom, user_settings, session_id) {
filepath = rom.filename();
// Initialize with default feature flags
feature_flags = core::FeatureFlags::Flags{};
}
// Get display name (custom name or ROM title)
std::string GetDisplayName() const {
if (!custom_name.empty()) {
return custom_name;
}
return rom.title().empty() ? "Untitled Session" : rom.title();
}
};
private:
std::deque<RomSession> sessions_;
Rom* current_rom_ = nullptr;
EditorSet* current_editor_set_ = nullptr;
Editor* current_editor_ = nullptr;
EditorSet blank_editor_set_{};
// Tracks which session is currently active so delegators (menus, popups,
// shortcuts) stay in sync without relying on per-editor context.
size_t current_session_id_ = 0;
gfx::IRenderer* renderer_ = nullptr;
@@ -399,7 +309,6 @@ class EditorManager {
MenuBuilder menu_builder_;
ShortcutManager shortcut_manager_;
UserSettings user_settings_;
WorkspaceManager workspace_manager_{&toast_manager_};
// New delegated components (dependency injection architecture)
EditorCardRegistry card_registry_; // Card management with session awareness
@@ -411,6 +320,7 @@ class EditorManager {
WindowDelegate window_delegate_;
std::unique_ptr<SessionCoordinator> session_coordinator_;
std::unique_ptr<LayoutManager> layout_manager_; // DockBuilder layout management
WorkspaceManager workspace_manager_{&toast_manager_};
float autosave_timer_ = 0.0f;

View File

@@ -0,0 +1,51 @@
#include "app/editor/session_types.h"
#include "app/editor/editor.h" // For EditorDependencies, needed by ApplyDependencies
#include "app/editor/system/user_settings.h" // For UserSettings forward decl in header
namespace yaze::editor {
EditorSet::EditorSet(Rom* rom, UserSettings* user_settings, size_t session_id)
: session_id_(session_id),
assembly_editor_(rom),
dungeon_editor_(rom),
graphics_editor_(rom),
music_editor_(rom),
overworld_editor_(rom),
palette_editor_(rom),
screen_editor_(rom),
sprite_editor_(rom),
settings_editor_(rom, user_settings),
message_editor_(rom),
memory_editor_(rom) {
active_editors_ = {&overworld_editor_, &dungeon_editor_, &graphics_editor_,
&palette_editor_, &sprite_editor_, &message_editor_,
&music_editor_, &screen_editor_, &settings_editor_,
&assembly_editor_};
}
void EditorSet::set_user_settings(UserSettings* settings) {
settings_editor_.set_user_settings(settings);
}
void EditorSet::ApplyDependencies(const EditorDependencies& dependencies) {
for (auto* editor : active_editors_) {
editor->SetDependencies(dependencies);
}
memory_editor_.set_rom(dependencies.rom);
}
RomSession::RomSession(Rom&& r, UserSettings* user_settings, size_t session_id)
: rom(std::move(r)), editors(&rom, user_settings, session_id) {
filepath = rom.filename();
feature_flags = core::FeatureFlags::Flags{};
}
std::string RomSession::GetDisplayName() const {
if (!custom_name.empty()) {
return custom_name;
}
return rom.title().empty() ? "Untitled Session" : rom.title();
}
} // namespace yaze::editor

View File

@@ -0,0 +1,79 @@
#ifndef YAZE_APP_EDITOR_SESSION_TYPES_H_
#define YAZE_APP_EDITOR_SESSION_TYPES_H_
#include "app/core/features.h"
#include "app/editor/code/assembly_editor.h"
#include "app/editor/code/memory_editor.h"
#include "app/editor/dungeon/dungeon_editor_v2.h"
#include "app/editor/graphics/graphics_editor.h"
#include "app/editor/graphics/screen_editor.h"
#include "app/editor/message/message_editor.h"
#include "app/editor/music/music_editor.h"
#include "app/editor/overworld/overworld_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/editor/sprite/sprite_editor.h"
#include "app/editor/system/settings_editor.h"
#include "app/rom.h"
#include <string>
#include <vector>
namespace yaze::editor {
class EditorDependencies;
/**
* @class EditorSet
* @brief Contains a complete set of editors for a single ROM instance
*/
class EditorSet {
public:
explicit EditorSet(Rom* rom = nullptr, UserSettings* user_settings = nullptr,
size_t session_id = 0);
void set_user_settings(UserSettings* settings);
void ApplyDependencies(const EditorDependencies& dependencies);
size_t session_id() const { return session_id_; }
AssemblyEditor assembly_editor_;
DungeonEditorV2 dungeon_editor_;
GraphicsEditor graphics_editor_;
MusicEditor music_editor_;
OverworldEditor overworld_editor_;
PaletteEditor palette_editor_;
ScreenEditor screen_editor_;
SpriteEditor sprite_editor_;
SettingsEditor settings_editor_;
MessageEditor message_editor_;
MemoryEditorWithDiffChecker memory_editor_;
std::vector<Editor*> active_editors_;
private:
size_t session_id_ = 0;
};
/**
* @struct RomSession
* @brief Represents a single session, containing a ROM and its associated editors.
*/
struct RomSession {
Rom rom;
EditorSet editors;
std::string custom_name; // User-defined session name
std::string filepath; // ROM filepath for duplicate detection
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
RomSession() = default;
explicit RomSession(Rom&& r, UserSettings* user_settings = nullptr,
size_t session_id = 0);
// Get display name (custom name or ROM title)
std::string GetDisplayName() const;
};
} // namespace yaze::editor
#endif // YAZE_APP_EDITOR_SESSION_TYPES_H_

View File

@@ -14,11 +14,13 @@ namespace editor {
SessionCoordinator::SessionCoordinator(void* sessions_ptr,
EditorCardRegistry* card_registry,
ToastManager* toast_manager)
ToastManager* toast_manager,
UserSettings* user_settings)
: sessions_ptr_(sessions_ptr),
card_registry_(card_registry),
toast_manager_(toast_manager) {
auto* sessions = static_cast<std::deque<EditorManager::RomSession>*>(sessions_ptr_);
toast_manager_(toast_manager),
user_settings_(user_settings) {
auto* sessions = static_cast<std::deque<RomSession>*>(sessions_ptr_);
if (sessions && !sessions->empty()) {
active_session_index_ = 0;
session_count_ = sessions->size();
@@ -26,7 +28,7 @@ SessionCoordinator::SessionCoordinator(void* sessions_ptr,
}
// Helper macro to get sessions pointer
#define GET_SESSIONS() static_cast<std::deque<EditorManager::RomSession>*>(sessions_ptr_)
#define GET_SESSIONS() static_cast<std::deque<RomSession>*>(sessions_ptr_)
void SessionCoordinator::CreateNewSession() {
auto* sessions = GET_SESSIONS();
@@ -137,7 +139,7 @@ size_t SessionCoordinator::GetActiveSessionIndex() const {
return active_session_index_;
}
void* SessionCoordinator::GetActiveSession() {
void* SessionCoordinator::GetActiveSession() const {
auto* sessions = GET_SESSIONS();
if (!sessions || !IsValidSessionIndex(active_session_index_)) {
return nullptr;
@@ -145,7 +147,21 @@ void* SessionCoordinator::GetActiveSession() {
return &sessions->at(active_session_index_);
}
void* SessionCoordinator::GetSession(size_t index) {
RomSession* SessionCoordinator::GetActiveRomSession() const {
return static_cast<RomSession*>(GetActiveSession());
}
Rom* SessionCoordinator::GetCurrentRom() const {
auto* session = GetActiveRomSession();
return session ? &session->rom : nullptr;
}
EditorSet* SessionCoordinator::GetCurrentEditorSet() const {
auto* session = GetActiveRomSession();
return session ? &session->editors : nullptr;
}
void* SessionCoordinator::GetSession(size_t index) const {
auto* sessions = GET_SESSIONS();
if (!sessions || !IsValidSessionIndex(index)) {
return nullptr;
@@ -588,6 +604,21 @@ absl::Status SessionCoordinator::SaveSessionAs(size_t session_index, const std::
return absl::OkStatus();
}
absl::StatusOr<RomSession*> SessionCoordinator::CreateSessionFromRom(Rom&& rom, const std::string& filepath) {
auto* sessions = GET_SESSIONS();
if (!sessions) return absl::InternalError("Sessions not initialized");
size_t new_session_id = sessions->size();
sessions->emplace_back(std::move(rom), user_settings_, new_session_id);
RomSession& session = sessions->back();
session.filepath = filepath;
UpdateSessionCount();
SwitchToSession(new_session_id);
return &session;
}
void SessionCoordinator::CleanupClosedSessions() {
auto* sessions = GET_SESSIONS();
if (!sessions) return;

View File

@@ -6,14 +6,17 @@
#include <vector>
#include "absl/status/status.h"
#include "app/editor/session_types.h"
#include "app/editor/system/toast_manager.h"
#include "app/rom.h"
#include "imgui/imgui.h"
// Forward declarations
namespace yaze {
class Rom;
namespace editor {
class EditorManager;
class EditorSet;
class EditorCardRegistry;
}
}
@@ -38,9 +41,12 @@ class SessionCoordinator {
public:
explicit SessionCoordinator(void* sessions_ptr,
EditorCardRegistry* card_registry,
ToastManager* toast_manager);
ToastManager* toast_manager,
UserSettings* user_settings);
~SessionCoordinator() = default;
void SetEditorManager(EditorManager* manager) { editor_manager_ = manager; }
// Session lifecycle management
void CreateNewSession();
void DuplicateCurrentSession();
@@ -52,8 +58,11 @@ class SessionCoordinator {
// Session activation and queries
void ActivateSession(size_t index);
size_t GetActiveSessionIndex() const;
void* GetActiveSession();
void* GetSession(size_t index);
void* GetActiveSession() const;
RomSession* GetActiveRomSession() const;
Rom* GetCurrentRom() const;
EditorSet* GetCurrentEditorSet() const;
void* GetSession(size_t index) const;
bool HasMultipleSessions() const;
size_t GetActiveSessionCount() const;
bool HasDuplicateSession(const std::string& filepath) const;
@@ -95,6 +104,7 @@ class SessionCoordinator {
absl::Status LoadRomIntoSession(const std::string& filename, size_t session_index = SIZE_MAX);
absl::Status SaveActiveSession(const std::string& filename = "");
absl::Status SaveSessionAs(size_t session_index, const std::string& filename);
absl::StatusOr<RomSession*> CreateSessionFromRom(Rom&& rom, const std::string& filepath);
// Session cleanup
void CleanupClosedSessions();
@@ -117,27 +127,6 @@ class SessionCoordinator {
void ToggleSessionManager() { show_session_manager_ = !show_session_manager_; }
bool IsSessionManagerVisible() const { return show_session_manager_; }
private:
// Core dependencies
void* sessions_ptr_; // std::deque<EditorManager::RomSession>*
EditorCardRegistry* card_registry_;
ToastManager* toast_manager_;
// Session state
size_t active_session_index_ = 0;
size_t session_count_ = 0;
// UI state
bool show_session_switcher_ = false;
bool show_session_manager_ = false;
bool show_session_rename_dialog_ = false;
size_t session_to_rename_ = 0;
char session_rename_buffer_[256] = {};
// Session limits
static constexpr size_t kMaxSessions = 8;
static constexpr size_t kMinSessions = 1;
// Helper methods
void UpdateActiveSession();
void ValidateSessionIndex(size_t index) const;
@@ -156,6 +145,28 @@ class SessionCoordinator {
bool IsSessionEmpty(size_t index) const;
bool IsSessionClosed(size_t index) const;
bool IsSessionModified(size_t index) const;
private:
// Core dependencies
EditorManager* editor_manager_ = nullptr;
void* sessions_ptr_; // std::deque<EditorManager::RomSession>*
EditorCardRegistry* card_registry_;
ToastManager* toast_manager_;
UserSettings* user_settings_;
// Session state
size_t active_session_index_ = 0;
size_t session_count_ = 0;
// UI state
bool show_session_switcher_ = false;
bool show_session_manager_ = false;
bool show_session_rename_dialog_ = false;
size_t session_to_rename_ = 0;
char session_rename_buffer_[256] = {};
// Session limits
static constexpr size_t kMaxSessions = 8;
static constexpr size_t kMinSessions = 1;
};
} // namespace editor

View File

@@ -108,12 +108,47 @@ void UICoordinator::DrawAllUI() {
// Session dialogs are drawn by SessionCoordinator separately to avoid duplication
DrawCommandPalette(); // Ctrl+Shift+P
DrawGlobalSearch(); // Ctrl+Shift+K
DrawWorkspacePresetDialogs(); // Save/Load workspace dialogs
DrawLayoutPresets(); // Layout preset dialogs
DrawWelcomeScreen(); // Welcome screen
DrawProjectHelp(); // Project help
DrawWindowManagementUI(); // Window management
}
void UICoordinator::DrawRomSelector() {
auto* current_rom = editor_manager_->GetCurrentRom();
ImGui::SameLine((ImGui::GetWindowWidth() / 2) - 100);
if (current_rom && current_rom->is_loaded()) {
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() / 6);
if (ImGui::BeginCombo("##ROMSelector", current_rom->short_name().c_str())) {
for (size_t i = 0; i < session_coordinator_.GetTotalSessionCount(); ++i) {
if (session_coordinator_.IsSessionClosed(i)) continue;
auto* session = static_cast<RomSession*>(session_coordinator_.GetSession(i));
if (!session) continue;
Rom* rom = &session->rom;
ImGui::PushID(static_cast<int>(i));
bool selected = (rom == current_rom);
if (ImGui::Selectable(rom->short_name().c_str(), selected)) {
editor_manager_->SwitchToSession(i);
}
ImGui::PopID();
}
ImGui::EndCombo();
}
// Inline status next to ROM selector
ImGui::SameLine();
ImGui::Text("Size: %.1f MB", current_rom->size() / 1048576.0f);
// Context-sensitive card control (right after ROM info)
ImGui::SameLine();
DrawContextSensitiveCardControl();
} else {
ImGui::Text("No ROM loaded");
}
}
void UICoordinator::DrawMenuBarExtras() {
// Get current ROM from EditorManager (RomFileManager doesn't track "current")
auto* current_rom = editor_manager_->GetCurrentRom();
@@ -312,6 +347,50 @@ void UICoordinator::DrawProjectHelp() {
// Show context-sensitive help based on current editor and ROM state
}
void UICoordinator::DrawWorkspacePresetDialogs() {
if (show_save_workspace_preset_) {
ImGui::Begin("Save Workspace Preset", &show_save_workspace_preset_,
ImGuiWindowFlags_AlwaysAutoResize);
static char preset_name[128] = "";
ImGui::InputText("Name", preset_name, IM_ARRAYSIZE(preset_name));
if (ImGui::Button("Save", gui::kDefaultModalSize)) {
if (strlen(preset_name) > 0) {
editor_manager_->SaveWorkspacePreset(preset_name);
toast_manager_.Show("Preset saved", editor::ToastType::kSuccess);
show_save_workspace_preset_ = false;
preset_name[0] = '\0';
}
}
ImGui::SameLine();
if (ImGui::Button("Cancel", gui::kDefaultModalSize)) {
show_save_workspace_preset_ = false;
preset_name[0] = '\0';
}
ImGui::End();
}
if (show_load_workspace_preset_) {
ImGui::Begin("Load Workspace Preset", &show_load_workspace_preset_,
ImGuiWindowFlags_AlwaysAutoResize);
// Lazy load workspace presets when UI is accessed
editor_manager_->RefreshWorkspacePresets();
if (auto* workspace_manager = editor_manager_->workspace_manager()) {
for (const auto& name : workspace_manager->workspace_presets()) {
if (ImGui::Selectable(name.c_str())) {
editor_manager_->LoadWorkspacePreset(name);
toast_manager_.Show("Preset loaded", editor::ToastType::kSuccess);
show_load_workspace_preset_ = false;
}
}
if (workspace_manager->workspace_presets().empty())
ImGui::Text("No presets found");
}
ImGui::End();
}
}
void UICoordinator::DrawWindowManagementUI() {
// TODO: [EditorManagerRefactor] Implement window management dialog
// Provide UI for toggling window visibility, managing docking, etc.
@@ -370,8 +449,9 @@ void UICoordinator::DrawSessionBadges() {
}
// Material Design component helpers
void UICoordinator::DrawMaterialButton(const std::string& text, const std::string& icon,
std::function<void()> callback, bool enabled) {
void UICoordinator::DrawMaterialButton(const std::string& text, const std::string& icon,
const ImVec4& color, std::function<void()> callback,
bool enabled) {
if (!enabled) {
ImGui::PushStyleColor(ImGuiCol_Button, gui::GetSurfaceContainerHighestVec4());
ImGui::PushStyleColor(ImGuiCol_Text, gui::GetOnSurfaceVariantVec4());
@@ -592,147 +672,192 @@ void UICoordinator::DrawCommandPalette() {
void UICoordinator::DrawGlobalSearch() {
if (!show_global_search_) return;
using namespace ImGui;
auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
SetNextWindowPos(GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
bool show_search = true;
if (Begin(absl::StrFormat("%s Global Search", ICON_MD_SEARCH).c_str(),
if (ImGui::Begin(
absl::StrFormat("%s Global Search", ICON_MD_MANAGE_SEARCH).c_str(),
&show_search, ImGuiWindowFlags_NoCollapse)) {
// Search input with focus management
SetNextItemWidth(-100);
if (IsWindowAppearing()) {
SetKeyboardFocusHere();
// Enhanced search input with focus management
ImGui::SetNextItemWidth(-100);
if (ImGui::IsWindowAppearing()) {
ImGui::SetKeyboardFocusHere();
}
bool input_changed = InputTextWithHint(
"##global_search_query",
absl::StrFormat("%s Search ROM data, cards, editors, resources...", ICON_MD_SEARCH).c_str(),
bool input_changed = ImGui::InputTextWithHint(
"##global_query",
absl::StrFormat("%s Search everything...", ICON_MD_SEARCH).c_str(),
global_search_query_, IM_ARRAYSIZE(global_search_query_));
SameLine();
if (Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
ImGui::SameLine();
if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
global_search_query_[0] = '\0';
input_changed = true;
}
Separator();
// Search results organized by category
if (BeginTabBar("SearchCategories")) {
// TODO: [EditorManagerRefactor] Implement actual ROM data searching
// This should search through:
// - Editor cards (all registered cards across all editors)
// - ROM resources (palettes, graphics, sprites, etc.)
// - Text strings (messages, dialogue)
// - Map names, room names, sprite names
// - Memory addresses and labels
if (BeginTabItem(absl::StrFormat("%s All Results", ICON_MD_LIST).c_str())) {
if (global_search_query_[0] != '\0') {
// Search through editor cards
TextColored(gui::ConvertColorToImVec4(theme.info),
"%s Editor Cards", ICON_MD_DASHBOARD);
Separator();
// Get current session ID from editor manager
size_t current_session_id = 0;
if (editor_manager_) {
current_session_id = editor_manager_->GetCurrentSessionId();
ImGui::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())) {
auto& manager = core::RecentFilesManager::GetInstance();
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);
ImGui::TableHeadersRow();
for (const auto& file : recent_files) {
if (global_search_query_[0] != '\0' && file.find(global_search_query_) == std::string::npos)
continue;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", util::GetFileName(file).c_str());
ImGui::TableNextColumn();
std::string ext = util::GetFileExtension(file);
if (ext == "sfc" || ext == "smc") {
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);
} else {
ImGui::Text("%s File", ICON_MD_DESCRIPTION);
}
ImGui::TableNextColumn();
ImGui::PushID(file.c_str());
if (ImGui::Button("Open")) {
auto status = editor_manager_->OpenRomOrProject(file);
if (!status.ok()) {
toast_manager_.Show(absl::StrCat("Failed to open: ", status.message()), ToastType::kError);
}
SetGlobalSearchVisible(false);
}
ImGui::PopID();
}
// Get all cards in current session
auto card_ids = card_registry_.GetCardsInSession(current_session_id);
bool found_cards = false;
for (const auto& card_id : card_ids) {
const auto* card_info = card_registry_.GetCardInfo(current_session_id, card_id);
if (!card_info) continue;
std::string search_lower = global_search_query_;
std::string card_lower = card_info->display_name;
std::transform(search_lower.begin(), search_lower.end(),
search_lower.begin(), ::tolower);
std::transform(card_lower.begin(), card_lower.end(),
card_lower.begin(), ::tolower);
if (card_lower.find(search_lower) != std::string::npos) {
if (Selectable(absl::StrFormat("%s %s - %s",
card_info->icon.c_str(),
card_info->display_name.c_str(),
card_info->category.c_str()).c_str())) {
// Show the card when selected
card_registry_.ShowCard(current_session_id, card_id);
show_global_search_ = false;
ImGui::EndTable();
}
ImGui::EndTabItem();
}
// Labels Tab (only if ROM is loaded)
auto* current_rom = editor_manager_->GetCurrentRom();
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);
ImGui::TableHeadersRow();
for (const auto& type_pair : labels) {
for (const auto& kv : type_pair.second) {
if (global_search_query_[0] != '\0' &&
kv.first.find(global_search_query_) == std::string::npos &&
kv.second.find(global_search_query_) == std::string::npos)
continue;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", type_pair.first.c_str());
ImGui::TableNextColumn();
if (ImGui::Selectable(kv.first.c_str(), false,
ImGuiSelectableFlags_SpanAllColumns)) {
// Future: navigate to related editor/location
}
ImGui::TableNextColumn();
ImGui::TextDisabled("%s", kv.second.c_str());
}
if (IsItemHovered()) {
BeginTooltip();
Text("Category: %s", card_info->category.c_str());
Text("Shortcut: %s", card_info->shortcut_hint.c_str());
Text("Click to open");
EndTooltip();
}
ImGui::EndTable();
}
ImGui::EndTabItem();
}
}
// Sessions Tab
if (session_coordinator_.GetActiveSessionCount() > 1) {
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 < session_coordinator_.GetTotalSessionCount(); ++i) {
std::string session_info = session_coordinator_.GetSessionDisplayName(i);
if (session_info == "[CLOSED SESSION]")
continue;
if (global_search_query_[0] != '\0' &&
session_info.find(global_search_query_) == std::string::npos)
continue;
bool is_current = (i == session_coordinator_.GetActiveSessionIndex());
if (is_current) {
ImGui::PushStyleColor(ImGuiCol_Text,
ImVec4(0.2f, 0.8f, 0.2f, 1.0f));
}
if (ImGui::Selectable(absl::StrFormat("%s %s %s", ICON_MD_TAB,
session_info.c_str(),
is_current ? "(Current)" : "")
.c_str())) {
if (!is_current) {
editor_manager_->SwitchToSession(i);
SetGlobalSearchVisible(false);
}
found_cards = true;
}
if (is_current) {
ImGui::PopStyleColor();
}
}
if (!found_cards) {
PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
Text("No cards found matching '%s'", global_search_query_);
PopStyleColor();
}
Spacing();
Spacing();
// TODO: [EditorManagerRefactor] Add more search categories:
// - ROM Resources (palettes, graphics, sprites)
// - Text/Messages
// - Map/Room names
// - Memory addresses
} else {
PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
Text("%s Enter search query to find ROM data, cards, and resources",
ICON_MD_INFO);
PopStyleColor();
ImGui::EndTabItem();
}
EndTabItem();
}
if (BeginTabItem(absl::StrFormat("%s Cards", ICON_MD_DASHBOARD).c_str())) {
Text("Card-specific search coming soon...");
EndTabItem();
}
if (BeginTabItem(absl::StrFormat("%s ROM Data", ICON_MD_STORAGE).c_str())) {
Text("ROM data search coming soon...");
EndTabItem();
}
if (BeginTabItem(absl::StrFormat("%s Text", ICON_MD_TEXT_FIELDS).c_str())) {
Text("Text search coming soon...");
EndTabItem();
}
EndTabBar();
ImGui::EndTabBar();
}
// Status bar
Separator();
Text("%s Global Search", ICON_MD_INFO);
SameLine();
PushStyleColor(ImGuiCol_Text, gui::ConvertColorToImVec4(theme.text_disabled));
Text("| Currently searches: Editor Cards | More categories coming soon");
PopStyleColor();
ImGui::Separator();
ImGui::Text("%s Global search across all YAZE data", ICON_MD_INFO);
}
End();
ImGui::End();
// Update visibility state
if (!show_search) {
show_global_search_ = false;
SetGlobalSearchVisible(false);
}
}

View File

@@ -65,6 +65,7 @@ class UICoordinator {
// Core UI components (actual ImGui rendering moved from EditorManager)
void DrawCommandPalette();
void DrawGlobalSearch();
void DrawWorkspacePresetDialogs();
// Session UI components
void DrawSessionSwitcher();
@@ -78,6 +79,7 @@ class UICoordinator {
// Window management UI
void DrawWindowManagementUI();
void DrawRomSelector();
// Popup and dialog management
void DrawAllPopups();
@@ -87,6 +89,8 @@ class UICoordinator {
// UI state management
void ShowEditorSelection() { show_editor_selection_ = true; }
void ShowDisplaySettings();
void ShowSaveWorkspacePresetDialog() { show_save_workspace_preset_ = true; }
void ShowLoadWorkspacePresetDialog() { show_load_workspace_preset_ = true; }
// Session switcher is now managed by SessionCoordinator
void ShowSessionSwitcher();
void HideCurrentEditorCards();
@@ -113,6 +117,11 @@ class UICoordinator {
bool IsCardSidebarVisible() const { return show_card_sidebar_; }
bool IsImGuiDemoVisible() const { return show_imgui_demo_; }
bool IsImGuiMetricsVisible() const { return show_imgui_metrics_; }
bool IsEmulatorVisible() const { return show_emulator_; }
bool IsMemoryEditorVisible() const { return show_memory_editor_; }
bool IsAsmEditorVisible() const { return show_asm_editor_; }
bool IsPaletteEditorVisible() const { return show_palette_editor_; }
bool IsResourceLabelManagerVisible() const { return show_resource_label_manager_; }
// UI state setters (for programmatic control)
void SetEditorSelectionVisible(bool visible) { show_editor_selection_ = visible; }
@@ -128,6 +137,11 @@ class UICoordinator {
void SetCardSidebarVisible(bool visible) { show_card_sidebar_ = visible; }
void SetImGuiDemoVisible(bool visible) { show_imgui_demo_ = visible; }
void SetImGuiMetricsVisible(bool visible) { show_imgui_metrics_ = visible; }
void SetEmulatorVisible(bool visible) { show_emulator_ = visible; }
void SetMemoryEditorVisible(bool visible) { show_memory_editor_ = visible; }
void SetAsmEditorVisible(bool visible) { show_asm_editor_ = visible; }
void SetPaletteEditorVisible(bool visible) { show_palette_editor_ = visible; }
void SetResourceLabelManagerVisible(bool visible) { show_resource_label_manager_ = visible; }
// Note: Theme styling is handled by ThemeManager, not UICoordinator
@@ -162,6 +176,8 @@ class UICoordinator {
bool show_asm_editor_ = false;
bool show_palette_editor_ = false;
bool show_resource_label_manager_ = false;
bool show_save_workspace_preset_ = false;
bool show_load_workspace_preset_ = false;
bool show_card_sidebar_ = true; // Show sidebar by default
// Command Palette state
@@ -180,8 +196,9 @@ class UICoordinator {
void DrawSessionBadges();
// Material Design component helpers
void DrawMaterialButton(const std::string& text, const std::string& icon,
std::function<void()> callback, bool enabled = true);
void DrawMaterialButton(const std::string& text, const std::string& icon,
const ImVec4& color, std::function<void()> callback,
bool enabled = true);
// Layout and positioning helpers
void CenterWindow(const std::string& window_name);