editor manager refactor
This commit is contained in:
@@ -9,9 +9,6 @@
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/system/command_manager.h"
|
||||
#include "app/editor/system/extension_manager.h"
|
||||
#include "app/editor/system/history_manager.h"
|
||||
#include "app/editor/system/popup_manager.h"
|
||||
#include "app/editor/system/shortcut_manager.h"
|
||||
|
||||
@@ -65,36 +62,11 @@ class UserSettings;
|
||||
* ```
|
||||
*/
|
||||
struct EditorDependencies {
|
||||
Rom* rom = nullptr;
|
||||
EditorCardRegistry* card_registry = nullptr;
|
||||
ToastManager* toast_manager = nullptr;
|
||||
PopupManager* popup_manager = nullptr;
|
||||
ShortcutManager* shortcut_manager = nullptr;
|
||||
UserSettings* user_settings = nullptr;
|
||||
size_t session_id = 0;
|
||||
|
||||
gfx::IRenderer* renderer = nullptr;
|
||||
void* custom_data = nullptr;
|
||||
};
|
||||
|
||||
struct EditorContext {
|
||||
CommandManager command_manager;
|
||||
ExtensionManager extension_manager;
|
||||
HistoryManager history_manager;
|
||||
PopupManager* popup_manager = nullptr;
|
||||
ShortcutManager shortcut_manager;
|
||||
|
||||
// Session identification for multi-session support
|
||||
// Used by child panels to create unique ImGui IDs
|
||||
size_t session_id = 0;
|
||||
|
||||
// Cross-session shared clipboard for editor data transfers
|
||||
struct SharedClipboard {
|
||||
// Overworld tile16 selection payload
|
||||
bool has_overworld_tile16 = false;
|
||||
std::vector<int> overworld_tile16_ids;
|
||||
int overworld_width = 0; // in tile16 units
|
||||
int overworld_height = 0; // in tile16 units
|
||||
int overworld_width = 0;
|
||||
int overworld_height = 0;
|
||||
|
||||
void Clear() {
|
||||
has_overworld_tile16 = false;
|
||||
@@ -102,7 +74,20 @@ struct EditorContext {
|
||||
overworld_width = 0;
|
||||
overworld_height = 0;
|
||||
}
|
||||
} shared_clipboard;
|
||||
};
|
||||
|
||||
Rom* rom = nullptr;
|
||||
EditorCardRegistry* card_registry = nullptr;
|
||||
ToastManager* toast_manager = nullptr;
|
||||
PopupManager* popup_manager = nullptr;
|
||||
ShortcutManager* shortcut_manager = nullptr;
|
||||
SharedClipboard* shared_clipboard = nullptr;
|
||||
UserSettings* user_settings = nullptr;
|
||||
size_t session_id = 0;
|
||||
|
||||
gfx::IRenderer* renderer = nullptr;
|
||||
|
||||
void* custom_data = nullptr;
|
||||
};
|
||||
|
||||
enum class EditorType {
|
||||
@@ -139,6 +124,8 @@ class Editor {
|
||||
Editor() = default;
|
||||
virtual ~Editor() = default;
|
||||
|
||||
void SetDependencies(const EditorDependencies& deps) { dependencies_ = deps; }
|
||||
|
||||
// Initialization of the editor, no ROM assets.
|
||||
virtual void Initialize() = 0;
|
||||
|
||||
@@ -164,8 +151,6 @@ class Editor {
|
||||
|
||||
EditorType type() const { return type_; }
|
||||
|
||||
void set_context(EditorContext* context) { context_ = context; }
|
||||
|
||||
bool* active() { return &active_; }
|
||||
void set_active(bool active) { active_ = active; }
|
||||
void toggle_active() { active_ = !active_; }
|
||||
@@ -177,20 +162,20 @@ class Editor {
|
||||
protected:
|
||||
bool active_ = false;
|
||||
EditorType type_;
|
||||
EditorContext* context_ = nullptr;
|
||||
EditorDependencies dependencies_;
|
||||
|
||||
// Helper method to create session-aware card titles for multi-session support
|
||||
std::string MakeCardTitle(const std::string& base_title) const {
|
||||
if (context_ && context_->session_id > 0) {
|
||||
return absl::StrFormat("%s [S%zu]", base_title, context_->session_id);
|
||||
if (dependencies_.session_id > 0) {
|
||||
return absl::StrFormat("%s [S%zu]", base_title, dependencies_.session_id);
|
||||
}
|
||||
return base_title;
|
||||
}
|
||||
|
||||
// Helper method to create session-aware card IDs for multi-session support
|
||||
std::string MakeCardId(const std::string& base_id) const {
|
||||
if (context_ && context_->session_id > 0) {
|
||||
return absl::StrFormat("s%zu.%s", context_->session_id, base_id);
|
||||
if (dependencies_.session_id > 0) {
|
||||
return absl::StrFormat("s%zu.%s", dependencies_.session_id, base_id);
|
||||
}
|
||||
return base_id;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ set(
|
||||
app/editor/system/session_coordinator.cc
|
||||
app/editor/system/user_settings.cc
|
||||
app/editor/system/window_delegate.cc
|
||||
app/editor/system/shortcut_configurator.cc
|
||||
app/editor/ui/editor_selection_dialog.cc
|
||||
app/editor/ui/menu_builder.cc
|
||||
app/editor/ui/ui_coordinator.cc
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,54 +3,55 @@
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/system/user_settings.h"
|
||||
#include "app/editor/ui/workspace_manager.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#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/ui/menu_builder.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/palette/palette_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/popup_manager.h"
|
||||
#include "app/editor/system/proposal_drawer.h"
|
||||
#include "app/editor/agent/agent_chat_history_popup.h"
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
#include "app/editor/agent/agent_editor.h"
|
||||
#include "app/editor/agent/automation_bridge.h"
|
||||
#endif
|
||||
#include "app/editor/system/settings_editor.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/editor/system/editor_card_registry.h"
|
||||
#include "app/editor/system/editor_registry.h"
|
||||
#include "app/editor/system/menu_orchestrator.h"
|
||||
#include "app/editor/system/popup_manager.h"
|
||||
#include "app/editor/system/project_manager.h"
|
||||
#include "app/editor/system/proposal_drawer.h"
|
||||
#include "app/editor/system/rom_file_manager.h"
|
||||
#include "app/editor/system/editor_card_registry.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"
|
||||
#include "app/editor/ui/menu_builder.h"
|
||||
#include "app/editor/ui/ui_coordinator.h"
|
||||
#include "app/editor/ui/welcome_screen.h"
|
||||
#include "app/emu/emulator.h"
|
||||
#include "app/gfx/debug/performance/performance_dashboard.h"
|
||||
#include "zelda3/overworld/overworld.h"
|
||||
#include "app/rom.h"
|
||||
#include "yaze_config.h"
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
#include "app/editor/agent/agent_editor.h"
|
||||
#include "app/editor/agent/automation_bridge.h"
|
||||
|
||||
// Forward declarations for gRPC-dependent types
|
||||
namespace yaze::agent {
|
||||
class AgentControlServer;
|
||||
@@ -66,7 +67,8 @@ namespace editor {
|
||||
*/
|
||||
class EditorSet {
|
||||
public:
|
||||
explicit EditorSet(Rom* rom = nullptr, UserSettings* user_settings = nullptr, size_t session_id = 0)
|
||||
explicit EditorSet(Rom* rom = nullptr, UserSettings* user_settings = nullptr,
|
||||
size_t session_id = 0)
|
||||
: session_id_(session_id),
|
||||
assembly_editor_(rom),
|
||||
dungeon_editor_(rom),
|
||||
@@ -84,11 +86,13 @@ class EditorSet {
|
||||
&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_;
|
||||
@@ -104,7 +108,7 @@ class EditorSet {
|
||||
MemoryEditorWithDiffChecker memory_editor_;
|
||||
|
||||
std::vector<Editor*> active_editors_;
|
||||
|
||||
|
||||
private:
|
||||
size_t session_id_ = 0;
|
||||
};
|
||||
@@ -130,28 +134,29 @@ class EditorManager {
|
||||
|
||||
// Processes startup flags to open a specific editor and cards.
|
||||
void OpenEditorAndCardsFromFlags(const std::string& editor_name,
|
||||
const std::string& cards_str);
|
||||
const std::string& cards_str);
|
||||
absl::Status Update();
|
||||
void DrawMenuBar();
|
||||
|
||||
auto emulator() -> emu::Emulator& { return emulator_; }
|
||||
auto quit() const { return quit_; }
|
||||
auto version() const { return version_; }
|
||||
void DrawMenuBarExtras();
|
||||
|
||||
MenuBuilder& menu_builder() { return menu_builder_; }
|
||||
void ShowSessionSwitcher();
|
||||
void ShowEditorSelection();
|
||||
void ShowDisplaySettings();
|
||||
|
||||
absl::Status SetCurrentRom(Rom* rom);
|
||||
auto GetCurrentRom() -> Rom* { return current_rom_; }
|
||||
auto GetCurrentEditorSet() -> EditorSet* { return current_editor_set_; }
|
||||
auto GetCurrentEditor() -> Editor* { return current_editor_; }
|
||||
auto overworld() -> yaze::zelda3::Overworld* { return ¤t_editor_set_->overworld_editor_.overworld(); }
|
||||
size_t GetCurrentSessionId() const { return current_session_id_; }
|
||||
UICoordinator* ui_coordinator() { return ui_coordinator_.get(); }
|
||||
auto overworld() -> yaze::zelda3::Overworld* {
|
||||
return ¤t_editor_set_->overworld_editor_.overworld();
|
||||
}
|
||||
|
||||
// Session management helpers
|
||||
size_t GetCurrentSessionIndex() const;
|
||||
|
||||
|
||||
// Get current session's feature flags (falls back to global if no session)
|
||||
core::FeatureFlags::Flags* GetCurrentFeatureFlags() {
|
||||
size_t current_index = GetCurrentSessionIndex();
|
||||
@@ -164,41 +169,41 @@ class EditorManager {
|
||||
void SetFontGlobalScale(float scale) {
|
||||
user_settings_.prefs().font_global_scale = scale;
|
||||
ImGui::GetIO().FontGlobalScale = scale;
|
||||
SaveUserSettings();
|
||||
auto status = user_settings_.Save();
|
||||
if (!status.ok()) {
|
||||
LOG_WARN("EditorManager", "Failed to save user settings: %s",
|
||||
status.ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void BuildModernMenu();
|
||||
|
||||
// User settings helpers
|
||||
void LoadUserSettings();
|
||||
void SaveUserSettings();
|
||||
|
||||
|
||||
// Workspace management (delegates to WorkspaceManager)
|
||||
void RefreshWorkspacePresets() { workspace_manager_.RefreshPresets(); }
|
||||
void SaveWorkspacePreset(const std::string& name) { workspace_manager_.SaveWorkspacePreset(name); }
|
||||
void LoadWorkspacePreset(const std::string& name) { workspace_manager_.LoadWorkspacePreset(name); }
|
||||
|
||||
void SaveWorkspacePreset(const std::string& name) {
|
||||
workspace_manager_.SaveWorkspacePreset(name);
|
||||
}
|
||||
void LoadWorkspacePreset(const std::string& name) {
|
||||
workspace_manager_.LoadWorkspacePreset(name);
|
||||
}
|
||||
|
||||
// Jump-to functionality for cross-editor navigation
|
||||
void JumpToDungeonRoom(int room_id);
|
||||
void JumpToOverworldMap(int map_id);
|
||||
void SwitchToEditor(EditorType editor_type);
|
||||
|
||||
|
||||
// Card-based editor registry
|
||||
static bool IsCardBasedEditor(EditorType type);
|
||||
static std::string GetEditorCategory(EditorType type);
|
||||
static EditorType GetEditorTypeFromCategory(const std::string& category);
|
||||
bool IsSidebarVisible() const {
|
||||
return ui_coordinator_ ? ui_coordinator_->IsCardSidebarVisible() : false;
|
||||
bool IsSidebarVisible() const {
|
||||
return ui_coordinator_ ? ui_coordinator_->IsCardSidebarVisible() : false;
|
||||
}
|
||||
void SetSidebarVisible(bool visible) {
|
||||
void SetSidebarVisible(bool visible) {
|
||||
if (ui_coordinator_) {
|
||||
ui_coordinator_->SetCardSidebarVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clean up cards when switching editors
|
||||
void HideCurrentEditorCards();
|
||||
|
||||
|
||||
// Session management
|
||||
void CreateNewSession();
|
||||
void DuplicateCurrentSession();
|
||||
@@ -206,44 +211,72 @@ class EditorManager {
|
||||
void RemoveSession(size_t index);
|
||||
void SwitchToSession(size_t index);
|
||||
size_t GetActiveSessionCount() const;
|
||||
|
||||
|
||||
// Workspace layout management
|
||||
// Window management - inline delegation (reduces EditorManager bloat)
|
||||
void SaveWorkspaceLayout() { window_delegate_.SaveWorkspaceLayout(); }
|
||||
void LoadWorkspaceLayout() { window_delegate_.LoadWorkspaceLayout(); }
|
||||
void ResetWorkspaceLayout() { window_delegate_.ResetWorkspaceLayout(); }
|
||||
void ShowAllWindows() { if (ui_coordinator_) ui_coordinator_->ShowAllWindows(); }
|
||||
void HideAllWindows() { if (ui_coordinator_) ui_coordinator_->HideAllWindows(); }
|
||||
|
||||
void ShowAllWindows() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->ShowAllWindows();
|
||||
}
|
||||
void HideAllWindows() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->HideAllWindows();
|
||||
}
|
||||
|
||||
// Layout presets (inline delegation)
|
||||
void LoadDeveloperLayout() { window_delegate_.LoadDeveloperLayout(); }
|
||||
void LoadDesignerLayout() { window_delegate_.LoadDesignerLayout(); }
|
||||
void LoadModderLayout() { window_delegate_.LoadModderLayout(); }
|
||||
|
||||
|
||||
// Helper methods
|
||||
std::string GenerateUniqueEditorTitle(EditorType type, size_t session_index) const;
|
||||
std::string GenerateUniqueEditorTitle(EditorType type,
|
||||
size_t session_index) const;
|
||||
bool HasDuplicateSession(const std::string& filepath);
|
||||
void RenameSession(size_t index, const std::string& new_name);
|
||||
void Quit() { quit_ = true; }
|
||||
|
||||
|
||||
// UI visibility controls (public for MenuOrchestrator)
|
||||
// UI visibility controls - inline for performance (single-line wrappers delegating to UICoordinator)
|
||||
void ShowGlobalSearch() { if (ui_coordinator_) ui_coordinator_->ShowGlobalSearch(); }
|
||||
void ShowCommandPalette() { if (ui_coordinator_) ui_coordinator_->ShowCommandPalette(); }
|
||||
void ShowPerformanceDashboard() { if (ui_coordinator_) ui_coordinator_->SetPerformanceDashboardVisible(true); }
|
||||
void ShowImGuiDemo() { if (ui_coordinator_) ui_coordinator_->SetImGuiDemoVisible(true); }
|
||||
void ShowImGuiMetrics() { if (ui_coordinator_) ui_coordinator_->SetImGuiMetricsVisible(true); }
|
||||
void ShowGlobalSearch() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->ShowGlobalSearch();
|
||||
}
|
||||
void ShowCommandPalette() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->ShowCommandPalette();
|
||||
}
|
||||
void ShowPerformanceDashboard() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->SetPerformanceDashboardVisible(true);
|
||||
}
|
||||
void ShowImGuiDemo() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->SetImGuiDemoVisible(true);
|
||||
}
|
||||
void ShowImGuiMetrics() {
|
||||
if (ui_coordinator_)
|
||||
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 ShowCardBrowser() { if (ui_coordinator_) ui_coordinator_->ShowCardBrowser(); }
|
||||
void ShowWelcomeScreen() { if (ui_coordinator_) ui_coordinator_->SetWelcomeScreenVisible(true); }
|
||||
|
||||
void ShowCardBrowser() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->ShowCardBrowser();
|
||||
}
|
||||
void ShowWelcomeScreen() {
|
||||
if (ui_coordinator_)
|
||||
ui_coordinator_->SetWelcomeScreenVisible(true);
|
||||
}
|
||||
|
||||
#ifdef YAZE_ENABLE_TESTING
|
||||
void ShowTestDashboard() { show_test_dashboard_ = true; }
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
void ShowAIAgent();
|
||||
void ShowChatHistory();
|
||||
@@ -255,23 +288,18 @@ class EditorManager {
|
||||
absl::Status SaveRom();
|
||||
absl::Status SaveRomAs(const std::string& filename);
|
||||
absl::Status OpenRomOrProject(const std::string& filename);
|
||||
absl::Status CreateNewProject(const std::string& template_name = "Basic ROM Hack");
|
||||
absl::Status CreateNewProject(
|
||||
const std::string& template_name = "Basic ROM Hack");
|
||||
absl::Status OpenProject();
|
||||
absl::Status SaveProject();
|
||||
absl::Status SaveProjectAs();
|
||||
absl::Status ImportProject(const std::string& project_path);
|
||||
absl::Status RepairCurrentProject();
|
||||
void ShowProjectHelp();
|
||||
|
||||
private:
|
||||
void DrawWelcomeScreen();
|
||||
absl::Status DrawRomSelector();
|
||||
void DrawContextSensitiveCardControl(); // Card control for current editor
|
||||
void DrawSessionSwitcher();
|
||||
void DrawSessionManager();
|
||||
void DrawLayoutPresets();
|
||||
void DrawSessionRenameDialog();
|
||||
|
||||
|
||||
absl::Status LoadAssets();
|
||||
|
||||
// Testing system
|
||||
@@ -311,7 +339,7 @@ class EditorManager {
|
||||
|
||||
// Project file editor
|
||||
ProjectFileEditor project_file_editor_;
|
||||
|
||||
|
||||
// Note: Editor selection dialog and welcome screen are now managed by UICoordinator
|
||||
// Kept here for backward compatibility during transition
|
||||
EditorSelectionDialog editor_selection_dialog_;
|
||||
@@ -336,7 +364,8 @@ class EditorManager {
|
||||
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
|
||||
|
||||
RomSession() = default;
|
||||
explicit RomSession(Rom&& r, UserSettings* user_settings = nullptr, size_t session_id = 0)
|
||||
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
|
||||
@@ -353,23 +382,26 @@ class EditorManager {
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
core::YazeProject current_project_;
|
||||
EditorContext context_;
|
||||
EditorDependencies::SharedClipboard shared_clipboard_;
|
||||
std::unique_ptr<PopupManager> popup_manager_;
|
||||
ToastManager toast_manager_;
|
||||
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
|
||||
EditorRegistry editor_registry_;
|
||||
@@ -379,21 +411,24 @@ class EditorManager {
|
||||
std::unique_ptr<UICoordinator> ui_coordinator_;
|
||||
WindowDelegate window_delegate_;
|
||||
std::unique_ptr<SessionCoordinator> session_coordinator_;
|
||||
|
||||
|
||||
float autosave_timer_ = 0.0f;
|
||||
|
||||
|
||||
// RAII helper for clean session context switching
|
||||
class SessionScope {
|
||||
public:
|
||||
SessionScope(EditorManager* manager, size_t session_id);
|
||||
~SessionScope();
|
||||
|
||||
|
||||
private:
|
||||
EditorManager* manager_;
|
||||
Rom* prev_rom_;
|
||||
EditorSet* prev_editor_set_;
|
||||
size_t prev_session_id_;
|
||||
};
|
||||
|
||||
void ConfigureEditorDependencies(EditorSet* editor_set, Rom* rom,
|
||||
size_t session_id);
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
||||
@@ -315,7 +315,9 @@ void MessageEditor::DrawExpandedMessageSettings() {
|
||||
expanded_messages_,
|
||||
message_preview_.all_dictionaries_)
|
||||
.ok()) {
|
||||
context_->popup_manager->Show("Error");
|
||||
if (auto* popup_manager = dependencies_.popup_manager) {
|
||||
popup_manager->Show("Error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ class MessageEditor : public Editor {
|
||||
type_ = EditorType::kMessage;
|
||||
}
|
||||
|
||||
explicit MessageEditor(Rom* rom, const EditorDependencies& deps)
|
||||
: MessageEditor(rom) {
|
||||
dependencies_ = deps;
|
||||
}
|
||||
|
||||
void Initialize() override;
|
||||
absl::Status Load() override;
|
||||
absl::Status Update() override;
|
||||
|
||||
@@ -1032,8 +1032,9 @@ void OverworldEditor::CheckForSelectRectangle() {
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::Copy() {
|
||||
if (!context_)
|
||||
return absl::FailedPreconditionError("No editor context");
|
||||
if (!dependencies_.shared_clipboard) {
|
||||
return absl::FailedPreconditionError("Clipboard unavailable");
|
||||
}
|
||||
// If a rectangle selection exists, copy its tile16 IDs into shared clipboard
|
||||
if (ow_map_canvas_.select_rect_active() &&
|
||||
!ow_map_canvas_.selected_points().empty()) {
|
||||
@@ -1059,27 +1060,28 @@ absl::Status OverworldEditor::Copy() {
|
||||
}
|
||||
}
|
||||
|
||||
context_->shared_clipboard.overworld_tile16_ids = std::move(ids);
|
||||
context_->shared_clipboard.overworld_width = width;
|
||||
context_->shared_clipboard.overworld_height = height;
|
||||
context_->shared_clipboard.has_overworld_tile16 = true;
|
||||
dependencies_.shared_clipboard->overworld_tile16_ids = std::move(ids);
|
||||
dependencies_.shared_clipboard->overworld_width = width;
|
||||
dependencies_.shared_clipboard->overworld_height = height;
|
||||
dependencies_.shared_clipboard->has_overworld_tile16 = true;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
// Single tile copy fallback
|
||||
if (current_tile16_ >= 0) {
|
||||
context_->shared_clipboard.overworld_tile16_ids = {current_tile16_};
|
||||
context_->shared_clipboard.overworld_width = 1;
|
||||
context_->shared_clipboard.overworld_height = 1;
|
||||
context_->shared_clipboard.has_overworld_tile16 = true;
|
||||
dependencies_.shared_clipboard->overworld_tile16_ids = {current_tile16_};
|
||||
dependencies_.shared_clipboard->overworld_width = 1;
|
||||
dependencies_.shared_clipboard->overworld_height = 1;
|
||||
dependencies_.shared_clipboard->has_overworld_tile16 = true;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
return absl::FailedPreconditionError("Nothing selected to copy");
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::Paste() {
|
||||
if (!context_)
|
||||
return absl::FailedPreconditionError("No editor context");
|
||||
if (!context_->shared_clipboard.has_overworld_tile16) {
|
||||
if (!dependencies_.shared_clipboard) {
|
||||
return absl::FailedPreconditionError("Clipboard unavailable");
|
||||
}
|
||||
if (!dependencies_.shared_clipboard->has_overworld_tile16) {
|
||||
return absl::FailedPreconditionError("Clipboard empty");
|
||||
}
|
||||
if (ow_map_canvas_.points().empty() &&
|
||||
@@ -1105,9 +1107,9 @@ absl::Status OverworldEditor::Paste() {
|
||||
const int superX = current_map_ % 8;
|
||||
const int tiles_per_local_map = 512 / kTile16Size;
|
||||
|
||||
const int width = context_->shared_clipboard.overworld_width;
|
||||
const int height = context_->shared_clipboard.overworld_height;
|
||||
const auto& ids = context_->shared_clipboard.overworld_tile16_ids;
|
||||
const int width = dependencies_.shared_clipboard->overworld_width;
|
||||
const int height = dependencies_.shared_clipboard->overworld_height;
|
||||
const auto& ids = dependencies_.shared_clipboard->overworld_tile16_ids;
|
||||
|
||||
// Guard
|
||||
if (width * height != static_cast<int>(ids.size())) {
|
||||
|
||||
@@ -69,6 +69,11 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
// MapPropertiesSystem will be initialized after maps_bmp_ and canvas are ready
|
||||
}
|
||||
|
||||
explicit OverworldEditor(Rom* rom, const EditorDependencies& deps)
|
||||
: OverworldEditor(rom) {
|
||||
dependencies_ = deps;
|
||||
}
|
||||
|
||||
void Initialize(gfx::IRenderer* renderer, Rom* rom);
|
||||
void Initialize() override;
|
||||
absl::Status Load() override;
|
||||
@@ -104,6 +109,8 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
return absl::StrFormat("ROM loaded: %s", rom_->title());
|
||||
}
|
||||
|
||||
Rom* rom() const { return rom_; }
|
||||
|
||||
// Jump-to functionality
|
||||
void set_current_map(int map_id) {
|
||||
if (map_id >= 0 && map_id < zelda3::kNumOverworldMaps) {
|
||||
|
||||
@@ -96,23 +96,24 @@ absl::Status OverworldEditor::DrawScratchSpace() {
|
||||
scratch_spaces_[current_scratch_slot_].tile_data[tile_x][tile_y]);
|
||||
}
|
||||
}
|
||||
if (!scratch_tile_ids.empty() && context_) {
|
||||
if (!scratch_tile_ids.empty() && dependencies_.shared_clipboard) {
|
||||
const auto& points = scratch_canvas_.selected_points();
|
||||
int width =
|
||||
std::abs(static_cast<int>((points[1].x - points[0].x) / 32)) + 1;
|
||||
int height =
|
||||
std::abs(static_cast<int>((points[1].y - points[0].y) / 32)) + 1;
|
||||
context_->shared_clipboard.overworld_tile16_ids =
|
||||
dependencies_.shared_clipboard->overworld_tile16_ids =
|
||||
std::move(scratch_tile_ids);
|
||||
context_->shared_clipboard.overworld_width = width;
|
||||
context_->shared_clipboard.overworld_height = height;
|
||||
context_->shared_clipboard.has_overworld_tile16 = true;
|
||||
dependencies_.shared_clipboard->overworld_width = width;
|
||||
dependencies_.shared_clipboard->overworld_height = height;
|
||||
dependencies_.shared_clipboard->has_overworld_tile16 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
HOVER_HINT("Copy scratch selection to clipboard for pasting in overworld");
|
||||
|
||||
if (context_ && context_->shared_clipboard.has_overworld_tile16) {
|
||||
if (dependencies_.shared_clipboard &&
|
||||
dependencies_.shared_clipboard->has_overworld_tile16) {
|
||||
Text(ICON_MD_CONTENT_PASTE
|
||||
" Pattern ready! Use Shift+Click to stamp, or paste in overworld");
|
||||
}
|
||||
@@ -223,13 +224,15 @@ void OverworldEditor::DrawScratchSpacePattern() {
|
||||
int start_tile_y = static_cast<int>(mouse_position.y) / 32;
|
||||
|
||||
// Get the selected tiles from overworld via clipboard
|
||||
if (!context_ || !context_->shared_clipboard.has_overworld_tile16) {
|
||||
if (!dependencies_.shared_clipboard ||
|
||||
!dependencies_.shared_clipboard->has_overworld_tile16) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& tile_ids = context_->shared_clipboard.overworld_tile16_ids;
|
||||
int pattern_width = context_->shared_clipboard.overworld_width;
|
||||
int pattern_height = context_->shared_clipboard.overworld_height;
|
||||
const auto& tile_ids =
|
||||
dependencies_.shared_clipboard->overworld_tile16_ids;
|
||||
int pattern_width = dependencies_.shared_clipboard->overworld_width;
|
||||
int pattern_height = dependencies_.shared_clipboard->overworld_height;
|
||||
|
||||
if (tile_ids.empty())
|
||||
return;
|
||||
|
||||
@@ -549,15 +549,21 @@ void MenuOrchestrator::OnSwitchToEditor(EditorType editor_type) {
|
||||
|
||||
void MenuOrchestrator::OnShowEditorSelection() {
|
||||
// Delegate to EditorManager
|
||||
// TODO: Draw editor selection via UICoordinator
|
||||
if (editor_manager_) {
|
||||
editor_manager_->ShowEditorSelection();
|
||||
if (auto* ui = editor_manager_->ui_coordinator()) {
|
||||
ui->ShowEditorSelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuOrchestrator::OnShowDisplaySettings() {
|
||||
// Delegate to EditorManager
|
||||
// TODO: Draw display settings via UICoordinator
|
||||
if (editor_manager_) {
|
||||
editor_manager_->ShowDisplaySettings();
|
||||
if (auto* ui = editor_manager_->ui_coordinator()) {
|
||||
ui->ShowDisplaySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,8 +630,11 @@ void MenuOrchestrator::OnSwitchToSession(size_t session_index) {
|
||||
}
|
||||
|
||||
void MenuOrchestrator::OnShowSessionSwitcher() {
|
||||
// TODO: Draw session switcher via UICoordinator
|
||||
if (editor_manager_) {
|
||||
editor_manager_->ShowSessionSwitcher();
|
||||
if (auto* ui = editor_manager_->ui_coordinator()) {
|
||||
ui->ShowSessionSwitcher();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -879,7 +888,8 @@ void MenuOrchestrator::OnQuit() {
|
||||
|
||||
// Menu item validation helpers
|
||||
bool MenuOrchestrator::CanSaveRom() const {
|
||||
return rom_manager_.IsRomLoaded();
|
||||
auto* rom = editor_manager_->GetCurrentRom();
|
||||
return rom ? rom_manager_.IsRomLoaded(rom) : false;
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::CanSaveProject() const {
|
||||
@@ -887,7 +897,8 @@ bool MenuOrchestrator::CanSaveProject() const {
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::HasActiveRom() const {
|
||||
return rom_manager_.IsRomLoaded();
|
||||
auto* rom = editor_manager_->GetCurrentRom();
|
||||
return rom ? rom_manager_.IsRomLoaded(rom) : false;
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::HasActiveProject() const {
|
||||
@@ -904,7 +915,8 @@ bool MenuOrchestrator::HasMultipleSessions() const {
|
||||
|
||||
// Menu item text generation
|
||||
std::string MenuOrchestrator::GetRomFilename() const {
|
||||
return rom_manager_.GetRomFilename();
|
||||
auto* rom = editor_manager_->GetCurrentRom();
|
||||
return rom ? rom_manager_.GetRomFilename(rom) : "";
|
||||
}
|
||||
|
||||
std::string MenuOrchestrator::GetProjectName() const {
|
||||
|
||||
@@ -2,37 +2,162 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/rom.h"
|
||||
#include "util/file_util.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
namespace yaze::editor {
|
||||
|
||||
RomFileManager::RomFileManager(ToastManager* toast_manager)
|
||||
: toast_manager_(toast_manager) {
|
||||
}
|
||||
: toast_manager_(toast_manager) {}
|
||||
|
||||
absl::Status RomFileManager::LoadRom(const std::string& filename) {
|
||||
absl::Status RomFileManager::LoadRom(Rom* rom, const std::string& filename) {
|
||||
if (!rom) {
|
||||
return absl::InvalidArgumentError("ROM pointer cannot be null");
|
||||
}
|
||||
if (filename.empty()) {
|
||||
// TODO: Show file dialog
|
||||
return absl::InvalidArgumentError("No filename provided");
|
||||
}
|
||||
|
||||
return LoadRomFromFile(filename);
|
||||
return LoadRomFromFile(rom, filename);
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::LoadRomFromFile(const std::string& filename) {
|
||||
absl::Status RomFileManager::SaveRom(Rom* rom) {
|
||||
if (!IsRomLoaded(rom)) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to save");
|
||||
}
|
||||
|
||||
Rom::SaveSettings settings;
|
||||
settings.backup = true;
|
||||
settings.save_new = false;
|
||||
settings.z3_save = true;
|
||||
|
||||
auto status = rom->SaveToFile(settings);
|
||||
if (!status.ok() && toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to save ROM: %s", status.message()),
|
||||
ToastType::kError);
|
||||
} else if (toast_manager_) {
|
||||
toast_manager_->Show("ROM saved successfully", ToastType::kSuccess);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::SaveRomAs(Rom* rom, const std::string& filename) {
|
||||
if (!IsRomLoaded(rom)) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to save");
|
||||
}
|
||||
if (filename.empty()) {
|
||||
return absl::InvalidArgumentError(
|
||||
"No filename provided for save as");
|
||||
}
|
||||
|
||||
Rom::SaveSettings settings;
|
||||
settings.backup = false;
|
||||
settings.save_new = true;
|
||||
settings.filename = filename;
|
||||
settings.z3_save = true;
|
||||
|
||||
auto status = rom->SaveToFile(settings);
|
||||
if (!status.ok() && toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to save ROM as: %s", status.message()),
|
||||
ToastType::kError);
|
||||
} else if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("ROM saved as: %s", filename),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::OpenRomOrProject(Rom* rom,
|
||||
const std::string& filename) {
|
||||
if (!rom) {
|
||||
return absl::InvalidArgumentError("ROM pointer cannot be null");
|
||||
}
|
||||
if (filename.empty()) {
|
||||
return absl::InvalidArgumentError("No filename provided");
|
||||
}
|
||||
|
||||
std::string extension =
|
||||
std::filesystem::path(filename).extension().string();
|
||||
|
||||
if (extension == ".yaze" || extension == ".json") {
|
||||
return absl::UnimplementedError(
|
||||
"Project file loading not yet implemented");
|
||||
}
|
||||
|
||||
return LoadRom(rom, filename);
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::CreateBackup(Rom* rom) {
|
||||
if (!IsRomLoaded(rom)) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to backup");
|
||||
}
|
||||
|
||||
std::string backup_filename = GenerateBackupFilename(rom->filename());
|
||||
|
||||
Rom::SaveSettings settings;
|
||||
settings.backup = true;
|
||||
settings.filename = backup_filename;
|
||||
settings.z3_save = true;
|
||||
|
||||
auto status = rom->SaveToFile(settings);
|
||||
if (!status.ok() && toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to create backup: %s", status.message()),
|
||||
ToastType::kError);
|
||||
} else if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Backup created: %s", backup_filename),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::ValidateRom(Rom* rom) {
|
||||
if (!IsRomLoaded(rom)) {
|
||||
return absl::FailedPreconditionError("No valid ROM to validate");
|
||||
}
|
||||
|
||||
if (rom->size() < 512 * 1024 || rom->size() > 8 * 1024 * 1024) {
|
||||
return absl::InvalidArgumentError("ROM size is outside expected range");
|
||||
}
|
||||
if (rom->title().empty()) {
|
||||
return absl::InvalidArgumentError("ROM title is empty or invalid");
|
||||
}
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("ROM validation passed", ToastType::kSuccess);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
bool RomFileManager::IsRomLoaded(Rom* rom) const {
|
||||
return rom && rom->is_loaded();
|
||||
}
|
||||
|
||||
std::string RomFileManager::GetRomFilename(Rom* rom) const {
|
||||
if (!IsRomLoaded(rom)) {
|
||||
return "";
|
||||
}
|
||||
return rom->filename();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::LoadRomFromFile(
|
||||
Rom* rom, const std::string& filename) {
|
||||
if (!rom) {
|
||||
return absl::InvalidArgumentError("ROM pointer cannot be null");
|
||||
}
|
||||
if (!IsValidRomFile(filename)) {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrFormat("Invalid ROM file: %s", filename));
|
||||
}
|
||||
|
||||
// Create new ROM instance
|
||||
Rom new_rom;
|
||||
auto status = new_rom.LoadFromFile(filename);
|
||||
|
||||
auto status = rom->LoadFromFile(filename);
|
||||
if (!status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
@@ -41,204 +166,23 @@ absl::Status RomFileManager::LoadRomFromFile(const std::string& filename) {
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Set as current ROM
|
||||
current_rom_ = &new_rom;
|
||||
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("ROM loaded: %s", new_rom.title()),
|
||||
ToastType::kSuccess);
|
||||
toast_manager_->Show(absl::StrFormat("ROM loaded: %s", rom->title()),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::SaveRom() {
|
||||
if (!IsRomLoaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to save");
|
||||
}
|
||||
|
||||
Rom::SaveSettings settings;
|
||||
settings.backup = true;
|
||||
settings.save_new = false;
|
||||
settings.z3_save = true;
|
||||
|
||||
auto status = current_rom_->SaveToFile(settings);
|
||||
if (!status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to save ROM: %s", status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("ROM saved successfully", ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::SaveRomAs(const std::string& filename) {
|
||||
if (!IsRomLoaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to save");
|
||||
}
|
||||
|
||||
if (filename.empty()) {
|
||||
return absl::InvalidArgumentError("No filename provided for save as");
|
||||
}
|
||||
|
||||
Rom::SaveSettings settings;
|
||||
settings.backup = false;
|
||||
settings.save_new = true;
|
||||
settings.filename = filename;
|
||||
settings.z3_save = true;
|
||||
|
||||
auto status = current_rom_->SaveToFile(settings);
|
||||
if (!status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to save ROM as: %s", status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("ROM saved as: %s", filename),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::OpenRomOrProject(const std::string& filename) {
|
||||
if (filename.empty()) {
|
||||
return absl::InvalidArgumentError("No filename provided");
|
||||
}
|
||||
|
||||
// Check if it's a project file or ROM file
|
||||
std::string extension = std::filesystem::path(filename).extension().string();
|
||||
|
||||
if (extension == ".yaze" || extension == ".json") {
|
||||
// TODO: Handle project files
|
||||
return absl::UnimplementedError("Project file loading not yet implemented");
|
||||
} else {
|
||||
// Assume it's a ROM file
|
||||
return LoadRom(filename);
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::LoadAssets() {
|
||||
if (!IsRomLoaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to load assets from");
|
||||
}
|
||||
|
||||
// TODO: Implement asset loading logic
|
||||
// This would typically load graphics, music, etc. from the ROM
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("Assets loaded", ToastType::kInfo);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::SetCurrentRom(Rom* rom) {
|
||||
if (!rom) {
|
||||
return absl::InvalidArgumentError("ROM pointer cannot be null");
|
||||
}
|
||||
|
||||
current_rom_ = rom;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::string RomFileManager::GetRomFilename() const {
|
||||
if (!IsRomLoaded()) {
|
||||
return "";
|
||||
}
|
||||
return current_rom_->filename();
|
||||
}
|
||||
|
||||
std::string RomFileManager::GetRomTitle() const {
|
||||
if (!IsRomLoaded()) {
|
||||
return "";
|
||||
}
|
||||
return current_rom_->title();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::ValidateRom() {
|
||||
return ValidateRom(current_rom_);
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::ValidateRom(Rom* rom) {
|
||||
if (!rom || !rom->is_loaded()) {
|
||||
return absl::FailedPreconditionError("No valid ROM to validate");
|
||||
}
|
||||
|
||||
// TODO: Implement ROM validation logic
|
||||
// This would check ROM integrity, checksums, expected data structures, etc.
|
||||
|
||||
// Basic validation: check if ROM size is reasonable
|
||||
if (rom->size() < 512 * 1024 || rom->size() > 8 * 1024 * 1024) {
|
||||
return absl::InvalidArgumentError("ROM size is outside expected range");
|
||||
}
|
||||
|
||||
// Check if ROM title is readable
|
||||
if (rom->title().empty()) {
|
||||
return absl::InvalidArgumentError("ROM title is empty or invalid");
|
||||
}
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("ROM validation passed", ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::CreateBackup() {
|
||||
if (!IsRomLoaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to backup");
|
||||
}
|
||||
|
||||
std::string backup_filename = GenerateBackupFilename(GetRomFilename());
|
||||
|
||||
Rom::SaveSettings settings;
|
||||
settings.backup = true;
|
||||
settings.filename = backup_filename;
|
||||
settings.z3_save = true;
|
||||
|
||||
auto status = current_rom_->SaveToFile(settings);
|
||||
if (!status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to create backup: %s", status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Backup created: %s", backup_filename),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::string RomFileManager::GenerateBackupFilename(const std::string& original_filename) const {
|
||||
std::string RomFileManager::GenerateBackupFilename(
|
||||
const std::string& original_filename) const {
|
||||
std::filesystem::path path(original_filename);
|
||||
std::string stem = path.stem().string();
|
||||
std::string extension = path.extension().string();
|
||||
|
||||
// Add timestamp to make it unique
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time_t = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
|
||||
return absl::StrFormat("%s_backup_%ld%s", stem, time_t, extension);
|
||||
}
|
||||
|
||||
@@ -246,21 +190,17 @@ bool RomFileManager::IsValidRomFile(const std::string& filename) const {
|
||||
if (filename.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check file size (SNES ROMs are typically 2MB, 3MB, 4MB, 6MB, etc.)
|
||||
|
||||
auto file_size = std::filesystem::file_size(filename);
|
||||
if (file_size < 1024 * 1024 || file_size > 8 * 1024 * 1024) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Add more ROM validation (header checks, etc.)
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
} // namespace yaze::editor
|
||||
|
||||
@@ -27,34 +27,21 @@ class RomFileManager {
|
||||
~RomFileManager() = default;
|
||||
|
||||
// ROM file operations
|
||||
absl::Status LoadRom(const std::string& filename = "");
|
||||
absl::Status SaveRom();
|
||||
absl::Status SaveRomAs(const std::string& filename);
|
||||
absl::Status OpenRomOrProject(const std::string& filename);
|
||||
|
||||
// Asset operations
|
||||
absl::Status LoadAssets();
|
||||
|
||||
// ROM state management
|
||||
absl::Status SetCurrentRom(Rom* rom);
|
||||
Rom* GetCurrentRom() const { return current_rom_; }
|
||||
|
||||
// ROM information
|
||||
bool IsRomLoaded() const { return current_rom_ && current_rom_->is_loaded(); }
|
||||
std::string GetRomFilename() const;
|
||||
std::string GetRomTitle() const;
|
||||
|
||||
// Validation and backup
|
||||
absl::Status ValidateRom();
|
||||
absl::Status ValidateRom(Rom* rom); // Validate a specific ROM
|
||||
absl::Status CreateBackup();
|
||||
absl::Status LoadRom(Rom* rom, const std::string& filename);
|
||||
absl::Status SaveRom(Rom* rom);
|
||||
absl::Status SaveRomAs(Rom* rom, const std::string& filename);
|
||||
absl::Status OpenRomOrProject(Rom* rom, const std::string& filename);
|
||||
absl::Status CreateBackup(Rom* rom);
|
||||
absl::Status ValidateRom(Rom* rom);
|
||||
|
||||
// Utility helpers
|
||||
bool IsRomLoaded(Rom* rom) const;
|
||||
std::string GetRomFilename(Rom* rom) const;
|
||||
|
||||
private:
|
||||
Rom* current_rom_ = nullptr;
|
||||
ToastManager* toast_manager_ = nullptr;
|
||||
|
||||
// Helper methods
|
||||
absl::Status LoadRomFromFile(const std::string& filename);
|
||||
|
||||
absl::Status LoadRomFromFile(Rom* rom, const std::string& filename);
|
||||
std::string GenerateBackupFilename(const std::string& original_filename) const;
|
||||
bool IsValidRomFile(const std::string& filename) const;
|
||||
};
|
||||
|
||||
350
src/app/editor/system/shortcut_configurator.cc
Normal file
350
src/app/editor/system/shortcut_configurator.cc
Normal file
@@ -0,0 +1,350 @@
|
||||
#include "app/editor/system/shortcut_configurator.h"
|
||||
|
||||
#include "absl/functional/bind_front.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/editor_manager.h"
|
||||
#include "app/editor/system/editor_card_registry.h"
|
||||
#include "app/editor/system/menu_orchestrator.h"
|
||||
#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/toast_manager.h"
|
||||
#include "app/editor/ui/ui_coordinator.h"
|
||||
#include "app/editor/ui/workspace_manager.h"
|
||||
#include "app/editor/system/popup_manager.h"
|
||||
#include "app/core/project.h"
|
||||
|
||||
namespace yaze::editor {
|
||||
|
||||
namespace {
|
||||
|
||||
void RegisterIfValid(ShortcutManager* shortcut_manager,
|
||||
const std::string& name,
|
||||
const std::vector<ImGuiKey>& keys,
|
||||
std::function<void()> callback) {
|
||||
if (!shortcut_manager || !callback) {
|
||||
return;
|
||||
}
|
||||
shortcut_manager->RegisterShortcut(name, keys, std::move(callback));
|
||||
}
|
||||
|
||||
void RegisterIfValid(ShortcutManager* shortcut_manager,
|
||||
const std::string& name,
|
||||
ImGuiKey key,
|
||||
std::function<void()> callback) {
|
||||
if (!shortcut_manager || !callback) {
|
||||
return;
|
||||
}
|
||||
shortcut_manager->RegisterShortcut(name, key, std::move(callback));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ConfigureEditorShortcuts(const ShortcutDependencies& deps,
|
||||
ShortcutManager* shortcut_manager) {
|
||||
if (!shortcut_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* editor_manager = deps.editor_manager;
|
||||
auto* ui_coordinator = deps.ui_coordinator;
|
||||
auto* popup_manager = deps.popup_manager;
|
||||
auto* card_registry = deps.card_registry;
|
||||
|
||||
RegisterIfValid(
|
||||
shortcut_manager, "global.toggle_sidebar",
|
||||
{ImGuiKey_LeftCtrl, ImGuiKey_B},
|
||||
[ui_coordinator]() {
|
||||
if (ui_coordinator) {
|
||||
ui_coordinator->ToggleCardSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Open", {ImGuiMod_Ctrl, ImGuiKey_O},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->LoadRom();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Save", {ImGuiMod_Ctrl, ImGuiKey_S},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->SaveRom();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Save As",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_S},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
// Use project-aware default filename when possible
|
||||
std::string filename = editor_manager->GetCurrentRom()
|
||||
? editor_manager->GetCurrentRom()->filename()
|
||||
: "";
|
||||
editor_manager->SaveRomAs(filename);
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Close ROM", {ImGuiMod_Ctrl, ImGuiKey_W},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentRom()) {
|
||||
editor_manager->GetCurrentRom()->Close();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Quit", {ImGuiMod_Ctrl, ImGuiKey_Q},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->Quit();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Undo", {ImGuiMod_Ctrl, ImGuiKey_Z},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentEditor()) {
|
||||
editor_manager->GetCurrentEditor()->Undo();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Redo",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_Z},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentEditor()) {
|
||||
editor_manager->GetCurrentEditor()->Redo();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Cut", {ImGuiMod_Ctrl, ImGuiKey_X},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentEditor()) {
|
||||
editor_manager->GetCurrentEditor()->Cut();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Copy", {ImGuiMod_Ctrl, ImGuiKey_C},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentEditor()) {
|
||||
editor_manager->GetCurrentEditor()->Copy();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Paste", {ImGuiMod_Ctrl, ImGuiKey_V},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentEditor()) {
|
||||
editor_manager->GetCurrentEditor()->Paste();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Find", {ImGuiMod_Ctrl, ImGuiKey_F},
|
||||
[editor_manager]() {
|
||||
if (editor_manager && editor_manager->GetCurrentEditor()) {
|
||||
editor_manager->GetCurrentEditor()->Find();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(
|
||||
shortcut_manager, "Command Palette",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_P},
|
||||
[ui_coordinator]() {
|
||||
if (ui_coordinator) {
|
||||
ui_coordinator->ShowCommandPalette();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(
|
||||
shortcut_manager, "Global Search",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_K},
|
||||
[ui_coordinator]() {
|
||||
if (ui_coordinator) {
|
||||
ui_coordinator->ShowGlobalSearch();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Load Last ROM",
|
||||
{ImGuiMod_Ctrl, ImGuiKey_R},
|
||||
[editor_manager]() {
|
||||
auto& recent = core::RecentFilesManager::GetInstance();
|
||||
if (!recent.GetRecentFiles().empty() && editor_manager) {
|
||||
editor_manager->OpenRomOrProject(
|
||||
recent.GetRecentFiles().front());
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Show About", ImGuiKey_F1,
|
||||
[popup_manager]() {
|
||||
if (popup_manager) {
|
||||
popup_manager->Show("About");
|
||||
}
|
||||
});
|
||||
|
||||
auto register_editor_shortcut = [&](EditorType type, ImGuiKey key) {
|
||||
RegisterIfValid(shortcut_manager,
|
||||
absl::StrFormat("switch.%d", static_cast<int>(type)),
|
||||
{ImGuiMod_Ctrl, key},
|
||||
[editor_manager, type]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->SwitchToEditor(type);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
register_editor_shortcut(EditorType::kOverworld, ImGuiKey_1);
|
||||
register_editor_shortcut(EditorType::kDungeon, ImGuiKey_2);
|
||||
register_editor_shortcut(EditorType::kGraphics, ImGuiKey_3);
|
||||
register_editor_shortcut(EditorType::kSprite, ImGuiKey_4);
|
||||
register_editor_shortcut(EditorType::kMessage, ImGuiKey_5);
|
||||
register_editor_shortcut(EditorType::kMusic, ImGuiKey_6);
|
||||
register_editor_shortcut(EditorType::kPalette, ImGuiKey_7);
|
||||
register_editor_shortcut(EditorType::kScreen, ImGuiKey_8);
|
||||
register_editor_shortcut(EditorType::kAssembly, ImGuiKey_9);
|
||||
register_editor_shortcut(EditorType::kSettings, ImGuiKey_0);
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Editor Selection",
|
||||
{ImGuiMod_Ctrl, ImGuiKey_E},
|
||||
[ui_coordinator]() {
|
||||
if (ui_coordinator) {
|
||||
ui_coordinator->ShowEditorSelection();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(
|
||||
shortcut_manager, "Card Browser",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_B},
|
||||
[ui_coordinator]() {
|
||||
if (ui_coordinator) {
|
||||
ui_coordinator->ShowCardBrowser();
|
||||
}
|
||||
});
|
||||
|
||||
if (card_registry) {
|
||||
RegisterIfValid(shortcut_manager, "Show Dungeon Cards",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_D},
|
||||
[card_registry]() {
|
||||
card_registry->ShowAllCardsInCategory("Dungeon");
|
||||
});
|
||||
RegisterIfValid(shortcut_manager, "Show Graphics Cards",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_G},
|
||||
[card_registry]() {
|
||||
card_registry->ShowAllCardsInCategory("Graphics");
|
||||
});
|
||||
RegisterIfValid(shortcut_manager, "Show Screen Cards",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_S},
|
||||
[card_registry]() {
|
||||
card_registry->ShowAllCardsInCategory("Screen");
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
RegisterIfValid(shortcut_manager, "Agent Editor",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_A},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->ShowAIAgent();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Agent Chat History",
|
||||
{ImGuiMod_Ctrl, ImGuiKey_H},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->ShowChatHistory();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Proposal Drawer",
|
||||
{ImGuiMod_Ctrl, ImGuiKey_P},
|
||||
[editor_manager]() {
|
||||
if (editor_manager) {
|
||||
editor_manager->ShowProposalDrawer();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConfigureMenuShortcuts(const ShortcutDependencies& deps,
|
||||
ShortcutManager* shortcut_manager) {
|
||||
if (!shortcut_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* menu_orchestrator = deps.menu_orchestrator;
|
||||
auto* session_coordinator = deps.session_coordinator;
|
||||
auto* workspace_manager = deps.workspace_manager;
|
||||
|
||||
RegisterIfValid(shortcut_manager, "New Session",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_N},
|
||||
[session_coordinator]() {
|
||||
if (session_coordinator) {
|
||||
session_coordinator->CreateNewSession();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Duplicate Session",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_D},
|
||||
[session_coordinator]() {
|
||||
if (session_coordinator) {
|
||||
session_coordinator->DuplicateCurrentSession();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Close Session",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_W},
|
||||
[session_coordinator]() {
|
||||
if (session_coordinator) {
|
||||
session_coordinator->CloseCurrentSession();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Session Switcher",
|
||||
{ImGuiMod_Ctrl, ImGuiKey_Tab},
|
||||
[session_coordinator]() {
|
||||
if (session_coordinator) {
|
||||
session_coordinator->ShowSessionSwitcher();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Save Layout",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_L},
|
||||
[workspace_manager]() {
|
||||
if (workspace_manager) {
|
||||
workspace_manager->SaveWorkspaceLayout();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Load Layout",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_O},
|
||||
[workspace_manager]() {
|
||||
if (workspace_manager) {
|
||||
workspace_manager->LoadWorkspaceLayout();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Reset Layout",
|
||||
{ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiKey_R},
|
||||
[workspace_manager]() {
|
||||
if (workspace_manager) {
|
||||
workspace_manager->ResetWorkspaceLayout();
|
||||
}
|
||||
});
|
||||
|
||||
RegisterIfValid(shortcut_manager, "Maximize Window", ImGuiKey_F11,
|
||||
[workspace_manager]() {
|
||||
if (workspace_manager) {
|
||||
workspace_manager->MaximizeCurrentWindow();
|
||||
}
|
||||
});
|
||||
|
||||
#ifdef YAZE_ENABLE_TESTING
|
||||
RegisterIfValid(shortcut_manager, "Test Dashboard",
|
||||
{ImGuiMod_Ctrl, ImGuiKey_T},
|
||||
[menu_orchestrator]() {
|
||||
if (menu_orchestrator) {
|
||||
menu_orchestrator->OnShowTestDashboard();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace yaze::editor
|
||||
|
||||
48
src/app/editor/system/shortcut_configurator.h
Normal file
48
src/app/editor/system/shortcut_configurator.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_SHORTCUT_CONFIGURATOR_H_
|
||||
#define YAZE_APP_EDITOR_SYSTEM_SHORTCUT_CONFIGURATOR_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/system/shortcut_manager.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
class EditorManager;
|
||||
class EditorRegistry;
|
||||
class MenuOrchestrator;
|
||||
class RomFileManager;
|
||||
class ProjectManager;
|
||||
class SessionCoordinator;
|
||||
class UICoordinator;
|
||||
class WorkspaceManager;
|
||||
class PopupManager;
|
||||
class ToastManager;
|
||||
class EditorCardRegistry;
|
||||
|
||||
struct ShortcutDependencies {
|
||||
EditorManager* editor_manager = nullptr;
|
||||
EditorRegistry* editor_registry = nullptr;
|
||||
MenuOrchestrator* menu_orchestrator = nullptr;
|
||||
RomFileManager* rom_file_manager = nullptr;
|
||||
ProjectManager* project_manager = nullptr;
|
||||
SessionCoordinator* session_coordinator = nullptr;
|
||||
UICoordinator* ui_coordinator = nullptr;
|
||||
WorkspaceManager* workspace_manager = nullptr;
|
||||
PopupManager* popup_manager = nullptr;
|
||||
ToastManager* toast_manager = nullptr;
|
||||
EditorCardRegistry* card_registry = nullptr;
|
||||
};
|
||||
|
||||
void ConfigureEditorShortcuts(const ShortcutDependencies& deps,
|
||||
ShortcutManager* shortcut_manager);
|
||||
|
||||
void ConfigureMenuShortcuts(const ShortcutDependencies& deps,
|
||||
ShortcutManager* shortcut_manager);
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_SHORTCUT_CONFIGURATOR_H_
|
||||
|
||||
@@ -111,7 +111,8 @@ void UICoordinator::DrawAllUI() {
|
||||
}
|
||||
|
||||
void UICoordinator::DrawMenuBarExtras() {
|
||||
auto* current_rom = rom_manager_.GetCurrentRom();
|
||||
// Get current ROM from EditorManager (RomFileManager doesn't track "current")
|
||||
auto* current_rom = editor_manager_->GetCurrentRom();
|
||||
std::string version_text = absl::StrFormat("v%s", editor_manager_->version().c_str());
|
||||
float version_width = ImGui::CalcTextSize(version_text.c_str()).x;
|
||||
float session_rom_area_width = 280.0f;
|
||||
|
||||
Reference in New Issue
Block a user