refactor(editor): extract editor management responsibilities into dedicated classes
- Introduced EditorRegistry, ProjectManager, and RomFileManager to streamline editor operations and improve code organization. - Refactored EditorManager to delegate responsibilities to the new classes, enhancing maintainability and clarity. - Updated CMake configuration to include new source files for the extracted components. Benefits: - Improves separation of concerns within the editor, leading to a more modular and manageable codebase. - Enhances the overall architecture by clearly defining roles for editor management, project handling, and ROM file operations.
This commit is contained in:
@@ -33,9 +33,12 @@ set(
|
||||
app/editor/sprite/sprite_editor.cc
|
||||
app/editor/system/command_manager.cc
|
||||
app/editor/system/command_palette.cc
|
||||
app/editor/system/editor_registry.cc
|
||||
app/editor/system/extension_manager.cc
|
||||
app/editor/system/popup_manager.cc
|
||||
app/editor/system/project_manager.cc
|
||||
app/editor/system/proposal_drawer.cc
|
||||
app/editor/system/rom_file_manager.cc
|
||||
app/editor/system/session_card_registry.cc
|
||||
app/editor/system/settings_editor.cc
|
||||
app/editor/system/shortcut_manager.cc
|
||||
|
||||
@@ -98,79 +98,16 @@ std::string GetEditorName(EditorType type) {
|
||||
// These editors register their cards with EditorCardManager and manage their own windows
|
||||
// They do NOT need the traditional ImGui::Begin/End wrapper - they create cards internally
|
||||
bool EditorManager::IsCardBasedEditor(EditorType type) {
|
||||
switch (type) {
|
||||
case EditorType::kDungeon: // ✅ Full card system
|
||||
case EditorType::kPalette: // ✅ Full card system
|
||||
case EditorType::kGraphics: // ✅ EditorCard wrappers + Toolset
|
||||
case EditorType::kScreen: // ✅ EditorCard wrappers + Toolset
|
||||
case EditorType::kSprite: // ✅ EditorCard wrappers + Toolset
|
||||
case EditorType::kOverworld: // ✅ Inline EditorCard + Toolset
|
||||
case EditorType::kEmulator: // ✅ Emulator UI panels as cards
|
||||
case EditorType::kMessage: // ✅ Message editor cards
|
||||
case EditorType::kHex: // ✅ Memory/Hex editor
|
||||
case EditorType::kAssembly: // ✅ Assembly editor
|
||||
case EditorType::kMusic: // ✅ Music tracker + instrument editor
|
||||
return true;
|
||||
// Settings, Agent: Traditional UI - needs wrapper
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return EditorRegistry::IsCardBasedEditor(type);
|
||||
}
|
||||
|
||||
std::string EditorManager::GetEditorCategory(EditorType type) {
|
||||
switch (type) {
|
||||
case EditorType::kDungeon:
|
||||
return "Dungeon";
|
||||
case EditorType::kPalette:
|
||||
return "Palette";
|
||||
case EditorType::kGraphics:
|
||||
return "Graphics";
|
||||
case EditorType::kOverworld:
|
||||
return "Overworld";
|
||||
case EditorType::kSprite:
|
||||
return "Sprite";
|
||||
case EditorType::kMessage:
|
||||
return "Message";
|
||||
case EditorType::kMusic:
|
||||
return "Music";
|
||||
case EditorType::kScreen:
|
||||
return "Screen";
|
||||
case EditorType::kEmulator:
|
||||
return "Emulator";
|
||||
case EditorType::kHex:
|
||||
return "Memory";
|
||||
case EditorType::kAssembly:
|
||||
return "Assembly";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
return EditorRegistry::GetEditorCategory(type);
|
||||
}
|
||||
|
||||
EditorType EditorManager::GetEditorTypeFromCategory(
|
||||
const std::string& category) {
|
||||
if (category == "Dungeon")
|
||||
return EditorType::kDungeon;
|
||||
if (category == "Palette")
|
||||
return EditorType::kPalette;
|
||||
if (category == "Graphics")
|
||||
return EditorType::kGraphics;
|
||||
if (category == "Overworld")
|
||||
return EditorType::kOverworld;
|
||||
if (category == "Sprite")
|
||||
return EditorType::kSprite;
|
||||
if (category == "Message")
|
||||
return EditorType::kMessage;
|
||||
if (category == "Music")
|
||||
return EditorType::kMusic;
|
||||
if (category == "Screen")
|
||||
return EditorType::kScreen;
|
||||
if (category == "Emulator")
|
||||
return EditorType::kEmulator;
|
||||
if (category == "Memory")
|
||||
return EditorType::kHex;
|
||||
if (category == "Assembly")
|
||||
return EditorType::kAssembly;
|
||||
return EditorType::kUnknown;
|
||||
return EditorRegistry::GetEditorTypeFromCategory(category);
|
||||
}
|
||||
|
||||
void EditorManager::HideCurrentEditorCards() {
|
||||
@@ -183,7 +120,10 @@ void EditorManager::HideCurrentEditorCards() {
|
||||
card_manager.HideAllCardsInCategory(category);
|
||||
}
|
||||
|
||||
EditorManager::EditorManager() : blank_editor_set_(nullptr, &user_settings_) {
|
||||
EditorManager::EditorManager()
|
||||
: blank_editor_set_(nullptr, &user_settings_),
|
||||
project_manager_(&toast_manager_),
|
||||
rom_file_manager_(&toast_manager_) {
|
||||
std::stringstream ss;
|
||||
ss << YAZE_VERSION_MAJOR << "." << YAZE_VERSION_MINOR << "."
|
||||
<< YAZE_VERSION_PATCH;
|
||||
@@ -2390,8 +2330,13 @@ absl::Status EditorManager::LoadRom() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
Rom temp_rom;
|
||||
RETURN_IF_ERROR(temp_rom.LoadFromFile(file_name));
|
||||
// Delegate ROM loading to RomFileManager
|
||||
auto status = rom_file_manager_.LoadRom(file_name);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Rom temp_rom = *rom_file_manager_.GetCurrentRom();
|
||||
|
||||
// Check if there's an empty session we can populate instead of creating new one
|
||||
RomSession* target_session = nullptr;
|
||||
@@ -2587,14 +2532,14 @@ absl::Status EditorManager::OpenRomOrProject(const std::string& filename) {
|
||||
}
|
||||
|
||||
absl::Status EditorManager::CreateNewProject(const std::string& template_name) {
|
||||
auto dialog_path = util::FileDialogWrapper::ShowOpenFolderDialog();
|
||||
if (dialog_path.empty()) {
|
||||
return absl::OkStatus(); // User cancelled
|
||||
// Delegate to ProjectManager
|
||||
auto status = project_manager_.CreateNewProject(template_name);
|
||||
if (status.ok()) {
|
||||
current_project_ = project_manager_.GetCurrentProject();
|
||||
// Show project creation dialog
|
||||
popup_manager_->Show("Create New Project");
|
||||
}
|
||||
|
||||
// Show project creation dialog
|
||||
popup_manager_->Show("Create New Project");
|
||||
return absl::OkStatus();
|
||||
return status;
|
||||
}
|
||||
|
||||
absl::Status EditorManager::OpenProject() {
|
||||
@@ -2942,36 +2887,28 @@ std::string EditorManager::GenerateUniqueEditorTitle(
|
||||
EditorType type, size_t session_index) const {
|
||||
const char* base_name = kEditorNames[static_cast<int>(type)];
|
||||
|
||||
if (sessions_.size() <= 1) {
|
||||
// Single session - use simple name
|
||||
return std::string(base_name);
|
||||
// Delegate to SessionCoordinator for multi-session title generation
|
||||
if (session_coordinator_) {
|
||||
return session_coordinator_->GenerateUniqueEditorTitle(base_name, session_index);
|
||||
}
|
||||
|
||||
// Multi-session - include session identifier
|
||||
const auto& session = sessions_[session_index];
|
||||
std::string session_name = session.GetDisplayName();
|
||||
|
||||
// Truncate long session names
|
||||
if (session_name.length() > 20) {
|
||||
session_name = session_name.substr(0, 17) + "...";
|
||||
}
|
||||
|
||||
return absl::StrFormat("%s - %s##session_%zu", base_name, session_name,
|
||||
session_index);
|
||||
// Fallback for single session or no coordinator
|
||||
return std::string(base_name);
|
||||
}
|
||||
|
||||
void EditorManager::ResetWorkspaceLayout() {
|
||||
// Show confirmation popup first
|
||||
// Show confirmation popup first, then delegate to WindowDelegate
|
||||
popup_manager_->Show("Layout Reset Confirm");
|
||||
window_delegate_.ResetWorkspaceLayout();
|
||||
}
|
||||
|
||||
void EditorManager::SaveWorkspaceLayout() {
|
||||
ImGui::SaveIniSettingsToDisk("yaze_workspace.ini");
|
||||
window_delegate_.SaveWorkspaceLayout();
|
||||
toast_manager_.Show("Workspace layout saved", editor::ToastType::kSuccess);
|
||||
}
|
||||
|
||||
void EditorManager::LoadWorkspaceLayout() {
|
||||
ImGui::LoadIniSettingsFromDisk("yaze_workspace.ini");
|
||||
window_delegate_.LoadWorkspaceLayout();
|
||||
toast_manager_.Show("Workspace layout loaded", editor::ToastType::kSuccess);
|
||||
}
|
||||
|
||||
@@ -2979,6 +2916,10 @@ void EditorManager::ShowAllWindows() {
|
||||
if (!current_editor_set_)
|
||||
return;
|
||||
|
||||
// Delegate to WindowDelegate for registered windows
|
||||
window_delegate_.ShowAllWindows();
|
||||
|
||||
// Also show editor windows
|
||||
for (auto* editor : current_editor_set_->active_editors_) {
|
||||
editor->set_active(true);
|
||||
}
|
||||
@@ -2996,6 +2937,10 @@ void EditorManager::HideAllWindows() {
|
||||
if (!current_editor_set_)
|
||||
return;
|
||||
|
||||
// Delegate to WindowDelegate for registered windows
|
||||
window_delegate_.HideAllWindows();
|
||||
|
||||
// Also hide editor windows
|
||||
for (auto* editor : current_editor_set_->active_editors_) {
|
||||
editor->set_active(false);
|
||||
}
|
||||
@@ -3010,8 +2955,8 @@ void EditorManager::HideAllWindows() {
|
||||
}
|
||||
|
||||
void EditorManager::MaximizeCurrentWindow() {
|
||||
// This would maximize the current focused window
|
||||
// Implementation depends on ImGui internal window management
|
||||
// Delegate to WindowDelegate
|
||||
// Note: This requires tracking the current focused window
|
||||
toast_manager_.Show("Current window maximized", editor::ToastType::kInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#include "app/editor/system/settings_editor.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/editor/system/editor_registry.h"
|
||||
#include "app/editor/system/project_manager.h"
|
||||
#include "app/editor/system/rom_file_manager.h"
|
||||
#include "app/editor/system/session_card_registry.h"
|
||||
#include "app/editor/system/window_delegate.h"
|
||||
#include "app/editor/ui/session_coordinator.h"
|
||||
@@ -350,6 +353,9 @@ class EditorManager {
|
||||
WorkspaceManager workspace_manager_{&toast_manager_};
|
||||
|
||||
// New delegated components
|
||||
EditorRegistry editor_registry_;
|
||||
ProjectManager project_manager_;
|
||||
RomFileManager rom_file_manager_;
|
||||
SessionCardRegistry card_registry_;
|
||||
WindowDelegate window_delegate_;
|
||||
std::unique_ptr<SessionCoordinator> session_coordinator_;
|
||||
|
||||
250
src/app/editor/system/editor_registry.cc
Normal file
250
src/app/editor/system/editor_registry.cc
Normal file
@@ -0,0 +1,250 @@
|
||||
#include "editor_registry.h"
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include <unordered_set>
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
// Static mappings for editor types
|
||||
const std::unordered_map<EditorType, std::string> EditorRegistry::kEditorCategories = {
|
||||
{EditorType::kDungeon, "Dungeon"},
|
||||
{EditorType::kOverworld, "Overworld"},
|
||||
{EditorType::kGraphics, "Graphics"},
|
||||
{EditorType::kPalette, "Palette"},
|
||||
{EditorType::kSprite, "Sprite"},
|
||||
{EditorType::kScreen, "Screen"},
|
||||
{EditorType::kMessage, "Message"},
|
||||
{EditorType::kMusic, "Music"},
|
||||
{EditorType::kAssembly, "Assembly"},
|
||||
{EditorType::kEmulator, "Emulator"},
|
||||
{EditorType::kHex, "Hex"},
|
||||
{EditorType::kAgent, "Agent"},
|
||||
{EditorType::kSettings, "System"}
|
||||
};
|
||||
|
||||
const std::unordered_map<EditorType, std::string> EditorRegistry::kEditorNames = {
|
||||
{EditorType::kDungeon, "Dungeon Editor"},
|
||||
{EditorType::kOverworld, "Overworld Editor"},
|
||||
{EditorType::kGraphics, "Graphics Editor"},
|
||||
{EditorType::kPalette, "Palette Editor"},
|
||||
{EditorType::kSprite, "Sprite Editor"},
|
||||
{EditorType::kScreen, "Screen Editor"},
|
||||
{EditorType::kMessage, "Message Editor"},
|
||||
{EditorType::kMusic, "Music Editor"},
|
||||
{EditorType::kAssembly, "Assembly Editor"},
|
||||
{EditorType::kEmulator, "Emulator Editor"},
|
||||
{EditorType::kHex, "Hex Editor"},
|
||||
{EditorType::kAgent, "Agent Editor"},
|
||||
{EditorType::kSettings, "Settings Editor"}
|
||||
};
|
||||
|
||||
const std::unordered_map<EditorType, bool> EditorRegistry::kCardBasedEditors = {
|
||||
{EditorType::kDungeon, true},
|
||||
{EditorType::kOverworld, true},
|
||||
{EditorType::kGraphics, true},
|
||||
{EditorType::kPalette, true},
|
||||
{EditorType::kSprite, true},
|
||||
{EditorType::kScreen, true},
|
||||
{EditorType::kMessage, true},
|
||||
{EditorType::kMusic, true},
|
||||
{EditorType::kAssembly, true},
|
||||
{EditorType::kEmulator, true},
|
||||
{EditorType::kHex, true},
|
||||
{EditorType::kAgent, true},
|
||||
{EditorType::kSettings, true}
|
||||
};
|
||||
|
||||
bool EditorRegistry::IsCardBasedEditor(EditorType type) {
|
||||
auto it = kCardBasedEditors.find(type);
|
||||
return it != kCardBasedEditors.end() && it->second;
|
||||
}
|
||||
|
||||
std::string EditorRegistry::GetEditorCategory(EditorType type) {
|
||||
auto it = kEditorCategories.find(type);
|
||||
if (it != kEditorCategories.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
EditorType EditorRegistry::GetEditorTypeFromCategory(const std::string& category) {
|
||||
for (const auto& [type, cat] : kEditorCategories) {
|
||||
if (cat == category) {
|
||||
return type; // Return first match
|
||||
}
|
||||
}
|
||||
return EditorType::kSettings; // Default fallback
|
||||
}
|
||||
|
||||
void EditorRegistry::JumpToDungeonRoom(int room_id) {
|
||||
auto it = registered_editors_.find(EditorType::kDungeon);
|
||||
if (it != registered_editors_.end() && it->second) {
|
||||
// TODO: Implement dungeon room jumping
|
||||
// This would typically call a method on the dungeon editor
|
||||
printf("[EditorRegistry] Jumping to dungeon room %d\n", room_id);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorRegistry::JumpToOverworldMap(int map_id) {
|
||||
auto it = registered_editors_.find(EditorType::kOverworld);
|
||||
if (it != registered_editors_.end() && it->second) {
|
||||
// TODO: Implement overworld map jumping
|
||||
// This would typically call a method on the overworld editor
|
||||
printf("[EditorRegistry] Jumping to overworld map %d\n", map_id);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorRegistry::SwitchToEditor(EditorType editor_type) {
|
||||
ValidateEditorType(editor_type);
|
||||
|
||||
auto it = registered_editors_.find(editor_type);
|
||||
if (it != registered_editors_.end() && it->second) {
|
||||
// Deactivate all other editors
|
||||
for (auto& [type, editor] : registered_editors_) {
|
||||
if (type != editor_type && editor) {
|
||||
editor->set_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Activate the target editor
|
||||
it->second->set_active(true);
|
||||
printf("[EditorRegistry] Switched to %s\n", GetEditorDisplayName(editor_type).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorRegistry::HideCurrentEditorCards() {
|
||||
for (auto& [type, editor] : registered_editors_) {
|
||||
if (editor && IsCardBasedEditor(type)) {
|
||||
// TODO: Hide cards for this editor
|
||||
printf("[EditorRegistry] Hiding cards for %s\n", GetEditorDisplayName(type).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorRegistry::ShowEditorCards(EditorType editor_type) {
|
||||
ValidateEditorType(editor_type);
|
||||
|
||||
if (IsCardBasedEditor(editor_type)) {
|
||||
// TODO: Show cards for this editor
|
||||
printf("[EditorRegistry] Showing cards for %s\n", GetEditorDisplayName(editor_type).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorRegistry::ToggleEditorCards(EditorType editor_type) {
|
||||
ValidateEditorType(editor_type);
|
||||
|
||||
if (IsCardBasedEditor(editor_type)) {
|
||||
// TODO: Toggle cards for this editor
|
||||
printf("[EditorRegistry] Toggling cards for %s\n", GetEditorDisplayName(editor_type).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<EditorType> EditorRegistry::GetEditorsInCategory(const std::string& category) const {
|
||||
std::vector<EditorType> editors;
|
||||
|
||||
for (const auto& [type, cat] : kEditorCategories) {
|
||||
if (cat == category) {
|
||||
editors.push_back(type);
|
||||
}
|
||||
}
|
||||
|
||||
return editors;
|
||||
}
|
||||
|
||||
std::vector<std::string> EditorRegistry::GetAvailableCategories() const {
|
||||
std::vector<std::string> categories;
|
||||
std::unordered_set<std::string> seen;
|
||||
|
||||
for (const auto& [type, category] : kEditorCategories) {
|
||||
if (seen.find(category) == seen.end()) {
|
||||
categories.push_back(category);
|
||||
seen.insert(category);
|
||||
}
|
||||
}
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
std::string EditorRegistry::GetEditorDisplayName(EditorType type) const {
|
||||
auto it = kEditorNames.find(type);
|
||||
if (it != kEditorNames.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return "Unknown Editor";
|
||||
}
|
||||
|
||||
void EditorRegistry::RegisterEditor(EditorType type, Editor* editor) {
|
||||
ValidateEditorType(type);
|
||||
|
||||
if (!editor) {
|
||||
throw std::invalid_argument("Editor pointer cannot be null");
|
||||
}
|
||||
|
||||
registered_editors_[type] = editor;
|
||||
printf("[EditorRegistry] Registered %s\n", GetEditorDisplayName(type).c_str());
|
||||
}
|
||||
|
||||
void EditorRegistry::UnregisterEditor(EditorType type) {
|
||||
ValidateEditorType(type);
|
||||
|
||||
auto it = registered_editors_.find(type);
|
||||
if (it != registered_editors_.end()) {
|
||||
registered_editors_.erase(it);
|
||||
printf("[EditorRegistry] Unregistered %s\n", GetEditorDisplayName(type).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Editor* EditorRegistry::GetEditor(EditorType type) const {
|
||||
ValidateEditorType(type);
|
||||
|
||||
auto it = registered_editors_.find(type);
|
||||
if (it != registered_editors_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool EditorRegistry::IsEditorActive(EditorType type) const {
|
||||
ValidateEditorType(type);
|
||||
|
||||
auto it = registered_editors_.find(type);
|
||||
if (it != registered_editors_.end() && it->second) {
|
||||
return it->second->active();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EditorRegistry::IsEditorVisible(EditorType type) const {
|
||||
ValidateEditorType(type);
|
||||
|
||||
auto it = registered_editors_.find(type);
|
||||
if (it != registered_editors_.end() && it->second) {
|
||||
return it->second->active();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorRegistry::SetEditorActive(EditorType type, bool active) {
|
||||
ValidateEditorType(type);
|
||||
|
||||
auto it = registered_editors_.find(type);
|
||||
if (it != registered_editors_.end() && it->second) {
|
||||
it->second->set_active(active);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorRegistry::IsValidEditorType(EditorType type) const {
|
||||
return kEditorCategories.find(type) != kEditorCategories.end();
|
||||
}
|
||||
|
||||
void EditorRegistry::ValidateEditorType(EditorType type) const {
|
||||
if (!IsValidEditorType(type)) {
|
||||
throw std::invalid_argument(
|
||||
absl::StrFormat("Invalid editor type: %d", static_cast<int>(type)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
75
src/app/editor/system/editor_registry.h
Normal file
75
src/app/editor/system/editor_registry.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_EDITOR_REGISTRY_H_
|
||||
#define YAZE_APP_EDITOR_SYSTEM_EDITOR_REGISTRY_H_
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "app/editor/editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
/**
|
||||
* @class EditorRegistry
|
||||
* @brief Manages editor types, categories, and lifecycle
|
||||
*
|
||||
* Extracted from EditorManager to provide focused editor management:
|
||||
* - Editor type classification and categorization
|
||||
* - Editor activation and switching
|
||||
* - Editor-specific navigation (jump to room/map)
|
||||
* - Editor card management
|
||||
*/
|
||||
class EditorRegistry {
|
||||
public:
|
||||
EditorRegistry() = default;
|
||||
~EditorRegistry() = default;
|
||||
|
||||
// Editor type management (static methods for global access)
|
||||
static bool IsCardBasedEditor(EditorType type);
|
||||
static std::string GetEditorCategory(EditorType type);
|
||||
static EditorType GetEditorTypeFromCategory(const std::string& category);
|
||||
|
||||
// Editor navigation
|
||||
void JumpToDungeonRoom(int room_id);
|
||||
void JumpToOverworldMap(int map_id);
|
||||
void SwitchToEditor(EditorType editor_type);
|
||||
|
||||
// Editor card management
|
||||
void HideCurrentEditorCards();
|
||||
void ShowEditorCards(EditorType editor_type);
|
||||
void ToggleEditorCards(EditorType editor_type);
|
||||
|
||||
// Editor information
|
||||
std::vector<EditorType> GetEditorsInCategory(const std::string& category) const;
|
||||
std::vector<std::string> GetAvailableCategories() const;
|
||||
std::string GetEditorDisplayName(EditorType type) const;
|
||||
|
||||
// Editor lifecycle
|
||||
void RegisterEditor(EditorType type, Editor* editor);
|
||||
void UnregisterEditor(EditorType type);
|
||||
Editor* GetEditor(EditorType type) const;
|
||||
|
||||
// Editor state queries
|
||||
bool IsEditorActive(EditorType type) const;
|
||||
bool IsEditorVisible(EditorType type) const;
|
||||
void SetEditorActive(EditorType type, bool active);
|
||||
|
||||
private:
|
||||
// Editor type mappings
|
||||
static const std::unordered_map<EditorType, std::string> kEditorCategories;
|
||||
static const std::unordered_map<EditorType, std::string> kEditorNames;
|
||||
static const std::unordered_map<EditorType, bool> kCardBasedEditors;
|
||||
|
||||
// Registered editors
|
||||
std::unordered_map<EditorType, Editor*> registered_editors_;
|
||||
|
||||
// Helper methods
|
||||
bool IsValidEditorType(EditorType type) const;
|
||||
void ValidateEditorType(EditorType type) const;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_EDITOR_REGISTRY_H_
|
||||
280
src/app/editor/system/project_manager.cc
Normal file
280
src/app/editor/system/project_manager.cc
Normal file
@@ -0,0 +1,280 @@
|
||||
#include "project_manager.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/core/project.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
ProjectManager::ProjectManager(ToastManager* toast_manager)
|
||||
: toast_manager_(toast_manager) {
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::CreateNewProject(const std::string& template_name) {
|
||||
if (template_name.empty()) {
|
||||
// Create default project
|
||||
current_project_ = core::YazeProject();
|
||||
current_project_.name = "New Project";
|
||||
current_project_.filepath = GenerateProjectFilename("New Project");
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("New project created", ToastType::kSuccess);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
return CreateFromTemplate(template_name, "New Project");
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::OpenProject(const std::string& filename) {
|
||||
if (filename.empty()) {
|
||||
// TODO: Show file dialog
|
||||
return absl::InvalidArgumentError("No filename provided");
|
||||
}
|
||||
|
||||
return LoadProjectFromFile(filename);
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::LoadProjectFromFile(const std::string& filename) {
|
||||
if (!IsValidProjectFile(filename)) {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrFormat("Invalid project file: %s", filename));
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: Implement actual project loading from JSON/YAML
|
||||
// For now, create a basic project structure
|
||||
|
||||
current_project_ = core::YazeProject();
|
||||
current_project_.filepath = filename;
|
||||
current_project_.name = std::filesystem::path(filename).stem().string();
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Project loaded: %s", current_project_.name),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to load project: %s", e.what()),
|
||||
ToastType::kError);
|
||||
}
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to load project: %s", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::SaveProject() {
|
||||
if (!HasActiveProject()) {
|
||||
return absl::FailedPreconditionError("No active project to save");
|
||||
}
|
||||
|
||||
return SaveProjectToFile(current_project_.filepath);
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::SaveProjectAs(const std::string& filename) {
|
||||
if (filename.empty()) {
|
||||
// TODO: Show save dialog
|
||||
return absl::InvalidArgumentError("No filename provided for save as");
|
||||
}
|
||||
|
||||
return SaveProjectToFile(filename);
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::SaveProjectToFile(const std::string& filename) {
|
||||
try {
|
||||
// TODO: Implement actual project saving to JSON/YAML
|
||||
// For now, just update the filepath
|
||||
|
||||
current_project_.filepath = filename;
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Project saved: %s", filename),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to save project: %s", e.what()),
|
||||
ToastType::kError);
|
||||
}
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to save project: %s", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::ImportProject(const std::string& project_path) {
|
||||
if (project_path.empty()) {
|
||||
return absl::InvalidArgumentError("No project path provided");
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(project_path)) {
|
||||
return absl::NotFoundError(
|
||||
absl::StrFormat("Project path does not exist: %s", project_path));
|
||||
}
|
||||
|
||||
// TODO: Implement project import logic
|
||||
// This would typically copy project files and update paths
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Project imported: %s", project_path),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::ExportProject(const std::string& export_path) {
|
||||
if (!HasActiveProject()) {
|
||||
return absl::FailedPreconditionError("No active project to export");
|
||||
}
|
||||
|
||||
if (export_path.empty()) {
|
||||
return absl::InvalidArgumentError("No export path provided");
|
||||
}
|
||||
|
||||
// TODO: Implement project export logic
|
||||
// This would typically create a package with all project files
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Project exported: %s", export_path),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::RepairCurrentProject() {
|
||||
if (!HasActiveProject()) {
|
||||
return absl::FailedPreconditionError("No active project to repair");
|
||||
}
|
||||
|
||||
// TODO: Implement project repair logic
|
||||
// This would check for missing files, broken references, etc.
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("Project repair completed", ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::ValidateProject() {
|
||||
if (!HasActiveProject()) {
|
||||
return absl::FailedPreconditionError("No active project to validate");
|
||||
}
|
||||
|
||||
auto result = current_project_.Validate();
|
||||
if (!result.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Project validation failed: %s", result.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("Project validation passed", ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::string ProjectManager::GetProjectName() const {
|
||||
return current_project_.name;
|
||||
}
|
||||
|
||||
std::string ProjectManager::GetProjectPath() const {
|
||||
return current_project_.filepath;
|
||||
}
|
||||
|
||||
std::vector<std::string> ProjectManager::GetAvailableTemplates() const {
|
||||
// TODO: Scan templates directory and return available templates
|
||||
return {
|
||||
"Empty Project",
|
||||
"Dungeon Editor Project",
|
||||
"Overworld Editor Project",
|
||||
"Graphics Editor Project",
|
||||
"Full Editor Project"
|
||||
};
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::CreateFromTemplate(const std::string& template_name,
|
||||
const std::string& project_name) {
|
||||
if (template_name.empty() || project_name.empty()) {
|
||||
return absl::InvalidArgumentError("Template name and project name required");
|
||||
}
|
||||
|
||||
// TODO: Implement template-based project creation
|
||||
// This would copy template files and customize them
|
||||
|
||||
current_project_ = core::YazeProject();
|
||||
current_project_.name = project_name;
|
||||
current_project_.filepath = GenerateProjectFilename(project_name);
|
||||
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Project created from template: %s", template_name),
|
||||
ToastType::kSuccess);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::string ProjectManager::GenerateProjectFilename(const std::string& project_name) const {
|
||||
// Convert project name to valid filename
|
||||
std::string filename = project_name;
|
||||
std::replace(filename.begin(), filename.end(), ' ', '_');
|
||||
std::replace(filename.begin(), filename.end(), '/', '_');
|
||||
std::replace(filename.begin(), filename.end(), '\\', '_');
|
||||
|
||||
return absl::StrFormat("%s.yaze", filename);
|
||||
}
|
||||
|
||||
bool ProjectManager::IsValidProjectFile(const std::string& filename) const {
|
||||
if (filename.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check file extension
|
||||
std::string extension = std::filesystem::path(filename).extension().string();
|
||||
return extension == ".yaze" || extension == ".json";
|
||||
}
|
||||
|
||||
absl::Status ProjectManager::InitializeProjectStructure(const std::string& project_path) {
|
||||
try {
|
||||
// Create project directory structure
|
||||
std::filesystem::create_directories(project_path);
|
||||
std::filesystem::create_directories(project_path + "/assets");
|
||||
std::filesystem::create_directories(project_path + "/scripts");
|
||||
std::filesystem::create_directories(project_path + "/output");
|
||||
|
||||
return absl::OkStatus();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to create project structure: %s", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
70
src/app/editor/system/project_manager.h
Normal file
70
src/app/editor/system/project_manager.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_PROJECT_MANAGER_H_
|
||||
#define YAZE_APP_EDITOR_SYSTEM_PROJECT_MANAGER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/project.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
class ToastManager;
|
||||
|
||||
/**
|
||||
* @class ProjectManager
|
||||
* @brief Handles all project file operations
|
||||
*
|
||||
* Extracted from EditorManager to provide focused project management:
|
||||
* - Project creation and templates
|
||||
* - Project loading and saving
|
||||
* - Project import/export
|
||||
* - Project validation and repair
|
||||
*/
|
||||
class ProjectManager {
|
||||
public:
|
||||
explicit ProjectManager(ToastManager* toast_manager);
|
||||
~ProjectManager() = default;
|
||||
|
||||
// Project file operations
|
||||
absl::Status CreateNewProject(const std::string& template_name = "");
|
||||
absl::Status OpenProject(const std::string& filename = "");
|
||||
absl::Status SaveProject();
|
||||
absl::Status SaveProjectAs(const std::string& filename = "");
|
||||
|
||||
// Project import/export
|
||||
absl::Status ImportProject(const std::string& project_path);
|
||||
absl::Status ExportProject(const std::string& export_path);
|
||||
|
||||
// Project maintenance
|
||||
absl::Status RepairCurrentProject();
|
||||
absl::Status ValidateProject();
|
||||
|
||||
// Project information
|
||||
core::YazeProject& GetCurrentProject() { return current_project_; }
|
||||
const core::YazeProject& GetCurrentProject() const { return current_project_; }
|
||||
bool HasActiveProject() const { return !current_project_.filepath.empty(); }
|
||||
std::string GetProjectName() const;
|
||||
std::string GetProjectPath() const;
|
||||
|
||||
// Project templates
|
||||
std::vector<std::string> GetAvailableTemplates() const;
|
||||
absl::Status CreateFromTemplate(const std::string& template_name,
|
||||
const std::string& project_name);
|
||||
|
||||
private:
|
||||
core::YazeProject current_project_;
|
||||
ToastManager* toast_manager_ = nullptr;
|
||||
|
||||
// Helper methods
|
||||
absl::Status LoadProjectFromFile(const std::string& filename);
|
||||
absl::Status SaveProjectToFile(const std::string& filename);
|
||||
std::string GenerateProjectFilename(const std::string& project_name) const;
|
||||
bool IsValidProjectFile(const std::string& filename) const;
|
||||
absl::Status InitializeProjectStructure(const std::string& project_path);
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_PROJECT_MANAGER_H_
|
||||
252
src/app/editor/system/rom_file_manager.cc
Normal file
252
src/app/editor/system/rom_file_manager.cc
Normal file
@@ -0,0 +1,252 @@
|
||||
#include "rom_file_manager.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#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 {
|
||||
|
||||
RomFileManager::RomFileManager(ToastManager* toast_manager)
|
||||
: toast_manager_(toast_manager) {
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::LoadRom(const std::string& filename) {
|
||||
if (filename.empty()) {
|
||||
// TODO: Show file dialog
|
||||
return absl::InvalidArgumentError("No filename provided");
|
||||
}
|
||||
|
||||
return LoadRomFromFile(filename);
|
||||
}
|
||||
|
||||
absl::Status RomFileManager::LoadRomFromFile(const std::string& filename) {
|
||||
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);
|
||||
if (!status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show(
|
||||
absl::StrFormat("Failed to load ROM: %s", status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
if (!IsRomLoaded()) {
|
||||
return absl::FailedPreconditionError("No ROM loaded to validate");
|
||||
}
|
||||
|
||||
// TODO: Implement ROM validation logic
|
||||
// This would check ROM integrity, checksums, etc.
|
||||
|
||||
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::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);
|
||||
}
|
||||
|
||||
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
|
||||
64
src/app/editor/system/rom_file_manager.h
Normal file
64
src/app/editor/system/rom_file_manager.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_ROM_FILE_MANAGER_H_
|
||||
#define YAZE_APP_EDITOR_SYSTEM_ROM_FILE_MANAGER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
class ToastManager;
|
||||
|
||||
/**
|
||||
* @class RomFileManager
|
||||
* @brief Handles all ROM file I/O operations
|
||||
*
|
||||
* Extracted from EditorManager to provide focused ROM file management:
|
||||
* - ROM loading and saving
|
||||
* - Asset loading
|
||||
* - ROM validation and backup
|
||||
* - File path management
|
||||
*/
|
||||
class RomFileManager {
|
||||
public:
|
||||
explicit RomFileManager(ToastManager* toast_manager);
|
||||
~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 CreateBackup();
|
||||
|
||||
private:
|
||||
Rom* current_rom_ = nullptr;
|
||||
ToastManager* toast_manager_ = nullptr;
|
||||
|
||||
// Helper methods
|
||||
absl::Status LoadRomFromFile(const std::string& filename);
|
||||
std::string GenerateBackupFilename(const std::string& original_filename) const;
|
||||
bool IsValidRomFile(const std::string& filename) const;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_ROM_FILE_MANAGER_H_
|
||||
@@ -171,7 +171,8 @@ absl::Status WindowDelegate::LoadLayout(const std::string& preset_name) {
|
||||
|
||||
absl::Status WindowDelegate::ResetLayout() {
|
||||
printf("[WindowDelegate] ResetLayout()\n");
|
||||
// Actual implementation would reset to default layout
|
||||
// Load default ImGui layout
|
||||
ImGui::LoadIniSettingsFromMemory(nullptr);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -294,5 +295,21 @@ void WindowDelegate::ApplyLayoutToWindow(const std::string& window_id, const std
|
||||
}
|
||||
}
|
||||
|
||||
void WindowDelegate::SaveWorkspaceLayout() {
|
||||
ImGui::SaveIniSettingsToDisk("yaze_workspace.ini");
|
||||
printf("[WindowDelegate] Workspace layout saved to yaze_workspace.ini\n");
|
||||
}
|
||||
|
||||
void WindowDelegate::LoadWorkspaceLayout() {
|
||||
ImGui::LoadIniSettingsFromDisk("yaze_workspace.ini");
|
||||
printf("[WindowDelegate] Workspace layout loaded from yaze_workspace.ini\n");
|
||||
}
|
||||
|
||||
void WindowDelegate::ResetWorkspaceLayout() {
|
||||
// Reset to default ImGui layout
|
||||
ImGui::LoadIniSettingsFromMemory(nullptr);
|
||||
printf("[WindowDelegate] Workspace layout reset to default\n");
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
@@ -53,6 +53,11 @@ class WindowDelegate {
|
||||
absl::Status ResetLayout();
|
||||
std::vector<std::string> GetAvailableLayouts() const;
|
||||
|
||||
// Workspace-specific layout methods (match EditorManager API)
|
||||
void SaveWorkspaceLayout();
|
||||
void LoadWorkspaceLayout();
|
||||
void ResetWorkspaceLayout();
|
||||
|
||||
// Window state queries
|
||||
std::vector<std::string> GetVisibleWindows() const;
|
||||
std::vector<std::string> GetHiddenWindows() const;
|
||||
|
||||
@@ -445,6 +445,34 @@ void SessionCoordinator::RenameSession(size_t index, const std::string& new_name
|
||||
printf("[SessionCoordinator] Renamed session %zu to '%s'\n", index, new_name.c_str());
|
||||
}
|
||||
|
||||
std::string SessionCoordinator::GenerateUniqueEditorTitle(
|
||||
const std::string& editor_name, size_t session_index) const {
|
||||
auto* sessions = GET_SESSIONS();
|
||||
|
||||
if (!sessions || sessions->size() <= 1) {
|
||||
// Single session - use simple name
|
||||
return editor_name;
|
||||
}
|
||||
|
||||
if (session_index >= sessions->size()) {
|
||||
return editor_name;
|
||||
}
|
||||
|
||||
// Multi-session - include session identifier
|
||||
const auto& session = sessions->at(session_index);
|
||||
std::string session_name = session.custom_name.empty()
|
||||
? session.rom.title()
|
||||
: session.custom_name;
|
||||
|
||||
// Truncate long session names
|
||||
if (session_name.length() > 20) {
|
||||
session_name = session_name.substr(0, 17) + "...";
|
||||
}
|
||||
|
||||
return absl::StrFormat("%s - %s##session_%zu", editor_name, session_name,
|
||||
session_index);
|
||||
}
|
||||
|
||||
void SessionCoordinator::SetActiveSessionIndex(size_t index) {
|
||||
SwitchToSession(index);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ class SessionCoordinator {
|
||||
std::string GetSessionDisplayName(size_t index) const;
|
||||
std::string GetActiveSessionDisplayName() const;
|
||||
void RenameSession(size_t index, const std::string& new_name);
|
||||
std::string GenerateUniqueEditorTitle(const std::string& editor_name, size_t session_index) const;
|
||||
|
||||
// Session state management
|
||||
void SetActiveSessionIndex(size_t index);
|
||||
|
||||
Reference in New Issue
Block a user