refactor: rename ui_editor to editor for consistency
This commit is contained in:
19
editor/src/Managers/LogSystem.cpp
Normal file
19
editor/src/Managers/LogSystem.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "LogSystem.h"
|
||||
|
||||
namespace UI {
|
||||
|
||||
LogSystem& LogSystem::Get() {
|
||||
static LogSystem instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void LogSystem::AddLog(XCEngine::Debug::LogLevel level, const std::string& message) {
|
||||
m_logs.push_back({level, message});
|
||||
if (m_callback) m_callback();
|
||||
}
|
||||
|
||||
void LogSystem::Clear() {
|
||||
m_logs.clear();
|
||||
}
|
||||
|
||||
}
|
||||
26
editor/src/Managers/LogSystem.h
Normal file
26
editor/src/Managers/LogSystem.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/LogEntry.h"
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace UI {
|
||||
|
||||
class LogSystem {
|
||||
public:
|
||||
static LogSystem& Get();
|
||||
|
||||
void AddLog(XCEngine::Debug::LogLevel level, const std::string& message);
|
||||
void Clear();
|
||||
const std::vector<LogEntry>& GetLogs() const { return m_logs; }
|
||||
|
||||
void SetCallback(std::function<void()> callback) { m_callback = callback; }
|
||||
|
||||
private:
|
||||
LogSystem() = default;
|
||||
|
||||
std::vector<LogEntry> m_logs;
|
||||
std::function<void()> m_callback;
|
||||
};
|
||||
|
||||
}
|
||||
246
editor/src/Managers/ProjectManager.cpp
Normal file
246
editor/src/Managers/ProjectManager.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "ProjectManager.h"
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <windows.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace UI {
|
||||
|
||||
ProjectManager& ProjectManager::Get() {
|
||||
static ProjectManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::vector<AssetItemPtr>& ProjectManager::GetCurrentItems() {
|
||||
if (m_path.empty()) {
|
||||
static std::vector<AssetItemPtr> empty;
|
||||
return empty;
|
||||
}
|
||||
return m_path.back()->children;
|
||||
}
|
||||
|
||||
void ProjectManager::NavigateToFolder(const AssetItemPtr& folder) {
|
||||
m_path.push_back(folder);
|
||||
m_selectedIndex = -1;
|
||||
}
|
||||
|
||||
void ProjectManager::NavigateBack() {
|
||||
if (m_path.size() > 1) {
|
||||
m_path.pop_back();
|
||||
m_selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectManager::NavigateToIndex(size_t index) {
|
||||
if (index >= m_path.size()) return;
|
||||
while (m_path.size() > index + 1) {
|
||||
m_path.pop_back();
|
||||
}
|
||||
m_selectedIndex = -1;
|
||||
}
|
||||
|
||||
std::string ProjectManager::GetCurrentPath() const {
|
||||
if (m_path.empty()) return "Assets";
|
||||
std::string result = "Assets";
|
||||
for (size_t i = 1; i < m_path.size(); i++) {
|
||||
result += "/";
|
||||
result += m_path[i]->name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ProjectManager::GetPathName(size_t index) const {
|
||||
if (index >= m_path.size()) return "";
|
||||
return m_path[index]->name;
|
||||
}
|
||||
|
||||
static std::wstring Utf8ToWstring(const std::string& str) {
|
||||
if (str.empty()) return L"";
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
|
||||
if (len <= 0) return L"";
|
||||
std::wstring result(len - 1, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &result[0], len);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string WstringToUtf8(const std::wstring& wstr) {
|
||||
if (wstr.empty()) return "";
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (len <= 0) return "";
|
||||
std::string result(len - 1, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &result[0], len, nullptr, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProjectManager::Initialize(const std::string& projectPath) {
|
||||
m_projectPath = projectPath;
|
||||
|
||||
std::wstring projectPathW = Utf8ToWstring(projectPath);
|
||||
fs::path assetsPath = fs::path(projectPathW) / L"Assets";
|
||||
|
||||
try {
|
||||
if (!fs::exists(assetsPath)) {
|
||||
fs::create_directories(assetsPath);
|
||||
fs::create_directories(assetsPath / L"Textures");
|
||||
fs::create_directories(assetsPath / L"Models");
|
||||
fs::create_directories(assetsPath / L"Scripts");
|
||||
fs::create_directories(assetsPath / L"Materials");
|
||||
fs::create_directories(assetsPath / L"Scenes");
|
||||
|
||||
std::ofstream((assetsPath / L"Textures" / L"Grass.png").wstring());
|
||||
std::ofstream((assetsPath / L"Textures" / L"Stone.png").wstring());
|
||||
std::ofstream((assetsPath / L"Models" / L"Character.fbx").wstring());
|
||||
std::ofstream((assetsPath / L"Scripts" / L"PlayerController.cs").wstring());
|
||||
std::ofstream((assetsPath / L"Scenes" / L"Main.unity").wstring());
|
||||
}
|
||||
|
||||
m_rootFolder = ScanDirectory(assetsPath.wstring());
|
||||
m_rootFolder->name = "Assets";
|
||||
m_rootFolder->fullPath = WstringToUtf8(assetsPath.wstring());
|
||||
|
||||
m_path.clear();
|
||||
m_path.push_back(m_rootFolder);
|
||||
m_selectedIndex = -1;
|
||||
} catch (const std::exception& e) {
|
||||
m_rootFolder = std::make_shared<AssetItem>();
|
||||
m_rootFolder->name = "Assets";
|
||||
m_rootFolder->isFolder = true;
|
||||
m_rootFolder->type = "Folder";
|
||||
m_path.push_back(m_rootFolder);
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring ProjectManager::GetCurrentFullPathW() const {
|
||||
if (m_path.empty()) return Utf8ToWstring(m_projectPath);
|
||||
|
||||
std::wstring fullPath = Utf8ToWstring(m_projectPath);
|
||||
for (size_t i = 0; i < m_path.size(); i++) {
|
||||
fullPath += L"/" + Utf8ToWstring(m_path[i]->name);
|
||||
}
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
void ProjectManager::RefreshCurrentFolder() {
|
||||
if (m_path.empty()) return;
|
||||
|
||||
try {
|
||||
auto newFolder = ScanDirectory(GetCurrentFullPathW());
|
||||
m_path.back()->children = newFolder->children;
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectManager::CreateFolder(const std::string& name) {
|
||||
try {
|
||||
std::wstring fullPath = GetCurrentFullPathW();
|
||||
fs::path newFolderPath = fs::path(fullPath) / Utf8ToWstring(name);
|
||||
fs::create_directory(newFolderPath);
|
||||
RefreshCurrentFolder();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectManager::DeleteItem(int index) {
|
||||
if (m_path.empty()) return;
|
||||
auto& items = m_path.back()->children;
|
||||
if (index < 0 || index >= (int)items.size()) return;
|
||||
|
||||
try {
|
||||
std::wstring fullPath = GetCurrentFullPathW();
|
||||
fs::path itemPath = fs::path(fullPath) / Utf8ToWstring(items[index]->name);
|
||||
fs::remove_all(itemPath);
|
||||
m_selectedIndex = -1;
|
||||
RefreshCurrentFolder();
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ProjectManager::MoveItem(const std::string& sourceFullPath, const std::string& destFolderFullPath) {
|
||||
try {
|
||||
fs::path sourcePath = Utf8ToWstring(sourceFullPath);
|
||||
fs::path destPath = fs::path(Utf8ToWstring(destFolderFullPath)) / sourcePath.filename();
|
||||
|
||||
if (!fs::exists(sourcePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fs::exists(destPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::rename(sourcePath, destPath);
|
||||
RefreshCurrentFolder();
|
||||
return true;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AssetItemPtr ProjectManager::ScanDirectory(const std::wstring& path) {
|
||||
auto folder = std::make_shared<AssetItem>();
|
||||
folder->name = WstringToUtf8(fs::path(path).filename().wstring());
|
||||
folder->isFolder = true;
|
||||
folder->type = "Folder";
|
||||
|
||||
if (!fs::exists(path)) return folder;
|
||||
|
||||
std::vector<AssetItemPtr> items;
|
||||
|
||||
try {
|
||||
for (const auto& entry : fs::directory_iterator(path)) {
|
||||
std::wstring nameW = entry.path().filename().wstring();
|
||||
bool isFolder = entry.is_directory();
|
||||
items.push_back(CreateAssetItem(entry.path().wstring(), nameW, isFolder));
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
std::sort(items.begin(), items.end(), [](const AssetItemPtr& a, const AssetItemPtr& b) {
|
||||
if (a->isFolder != b->isFolder) return a->isFolder;
|
||||
return a->name < b->name;
|
||||
});
|
||||
|
||||
folder->children = items;
|
||||
return folder;
|
||||
}
|
||||
|
||||
AssetItemPtr ProjectManager::CreateAssetItem(const std::wstring& path, const std::wstring& nameW, bool isFolder) {
|
||||
auto item = std::make_shared<AssetItem>();
|
||||
item->name = WstringToUtf8(nameW);
|
||||
item->isFolder = isFolder;
|
||||
item->fullPath = WstringToUtf8(path);
|
||||
|
||||
if (isFolder) {
|
||||
item->type = "Folder";
|
||||
try {
|
||||
auto subFolder = ScanDirectory(path);
|
||||
item->children = subFolder->children;
|
||||
} catch (...) {
|
||||
}
|
||||
} else {
|
||||
std::wstring ext = fs::path(path).extension().wstring();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower);
|
||||
|
||||
if (ext == L".png" || ext == L".jpg" || ext == L".tga" || ext == L".bmp") {
|
||||
item->type = "Texture";
|
||||
} else if (ext == L".fbx" || ext == L".obj" || ext == L".gltf" || ext == L".glb") {
|
||||
item->type = "Model";
|
||||
} else if (ext == L".cs" || ext == L".cpp" || ext == L".h") {
|
||||
item->type = "Script";
|
||||
} else if (ext == L".mat") {
|
||||
item->type = "Material";
|
||||
} else if (ext == L".unity" || ext == L".scene") {
|
||||
item->type = "Scene";
|
||||
} else if (ext == L".prefab") {
|
||||
item->type = "Prefab";
|
||||
} else {
|
||||
item->type = "File";
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
||||
49
editor/src/Managers/ProjectManager.h
Normal file
49
editor/src/Managers/ProjectManager.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/AssetItem.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace UI {
|
||||
|
||||
class ProjectManager {
|
||||
public:
|
||||
static ProjectManager& Get();
|
||||
|
||||
std::vector<AssetItemPtr>& GetCurrentItems();
|
||||
int GetSelectedIndex() const { return m_selectedIndex; }
|
||||
void SetSelectedIndex(int index) { m_selectedIndex = index; }
|
||||
|
||||
void NavigateToFolder(const AssetItemPtr& folder);
|
||||
void NavigateBack();
|
||||
void NavigateToIndex(size_t index);
|
||||
bool CanNavigateBack() const { return m_path.size() > 1; }
|
||||
|
||||
std::string GetCurrentPath() const;
|
||||
size_t GetPathDepth() const { return m_path.size(); }
|
||||
std::string GetPathName(size_t index) const;
|
||||
|
||||
void Initialize(const std::string& projectPath);
|
||||
void RefreshCurrentFolder();
|
||||
|
||||
void CreateFolder(const std::string& name);
|
||||
void DeleteItem(int index);
|
||||
bool MoveItem(const std::string& sourceFullPath, const std::string& destFolderFullPath);
|
||||
|
||||
const std::string& GetProjectPath() const { return m_projectPath; }
|
||||
|
||||
private:
|
||||
ProjectManager() = default;
|
||||
|
||||
AssetItemPtr ScanDirectory(const std::wstring& path);
|
||||
AssetItemPtr CreateAssetItem(const std::wstring& path, const std::wstring& nameW, bool isFolder);
|
||||
std::wstring GetCurrentFullPathW() const;
|
||||
|
||||
AssetItemPtr m_rootFolder;
|
||||
std::vector<AssetItemPtr> m_path;
|
||||
int m_selectedIndex = -1;
|
||||
std::string m_projectPath;
|
||||
};
|
||||
|
||||
}
|
||||
186
editor/src/Managers/SceneManager.cpp
Normal file
186
editor/src/Managers/SceneManager.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include "SceneManager.h"
|
||||
#include "SelectionManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace UI {
|
||||
|
||||
EntityID SceneManager::CreateEntity(const std::string& name, EntityID parent) {
|
||||
EntityID id = m_nextEntityId++;
|
||||
GameObject entity;
|
||||
entity.id = id;
|
||||
entity.name = name;
|
||||
entity.parent = parent;
|
||||
m_entities[id] = std::move(entity);
|
||||
|
||||
if (parent != INVALID_ENTITY_ID) {
|
||||
m_entities[parent].children.push_back(id);
|
||||
} else {
|
||||
m_rootEntities.push_back(id);
|
||||
}
|
||||
|
||||
OnEntityCreated.Invoke(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
void SceneManager::DeleteEntity(EntityID id) {
|
||||
auto it = m_entities.find(id);
|
||||
if (it == m_entities.end()) return;
|
||||
|
||||
GameObject& entity = it->second;
|
||||
|
||||
std::vector<EntityID> childrenToDelete = entity.children;
|
||||
for (EntityID childId : childrenToDelete) {
|
||||
DeleteEntity(childId);
|
||||
}
|
||||
|
||||
if (entity.parent != INVALID_ENTITY_ID) {
|
||||
auto* parent = GetEntity(entity.parent);
|
||||
if (parent) {
|
||||
auto& siblings = parent->children;
|
||||
siblings.erase(std::remove(siblings.begin(), siblings.end(), id), siblings.end());
|
||||
}
|
||||
} else {
|
||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), id), m_rootEntities.end());
|
||||
}
|
||||
|
||||
if (SelectionManager::Get().GetSelectedEntity() == id) {
|
||||
SelectionManager::Get().ClearSelection();
|
||||
}
|
||||
|
||||
m_entities.erase(it);
|
||||
OnEntityDeleted.Invoke(id);
|
||||
}
|
||||
|
||||
ClipboardData SceneManager::CopyEntityRecursive(const GameObject* entity) {
|
||||
ClipboardData data;
|
||||
data.name = entity->name;
|
||||
|
||||
for (const auto& comp : entity->components) {
|
||||
if (auto* transform = dynamic_cast<const TransformComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<TransformComponent>();
|
||||
memcpy(newComp->position, transform->position, sizeof(transform->position));
|
||||
memcpy(newComp->rotation, transform->rotation, sizeof(transform->rotation));
|
||||
memcpy(newComp->scale, transform->scale, sizeof(transform->scale));
|
||||
data.components.push_back(std::move(newComp));
|
||||
}
|
||||
else if (auto* meshRenderer = dynamic_cast<const MeshRendererComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<MeshRendererComponent>();
|
||||
newComp->materialName = meshRenderer->materialName;
|
||||
newComp->meshName = meshRenderer->meshName;
|
||||
data.components.push_back(std::move(newComp));
|
||||
}
|
||||
}
|
||||
|
||||
for (EntityID childId : entity->children) {
|
||||
const GameObject* child = GetEntity(childId);
|
||||
if (child) {
|
||||
data.children.push_back(CopyEntityRecursive(child));
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void SceneManager::CopyEntity(EntityID id) {
|
||||
const GameObject* entity = GetEntity(id);
|
||||
if (!entity) return;
|
||||
|
||||
m_clipboard = CopyEntityRecursive(entity);
|
||||
}
|
||||
|
||||
EntityID SceneManager::PasteEntityRecursive(const ClipboardData& data, EntityID parent) {
|
||||
EntityID newId = CreateEntity(data.name, parent);
|
||||
GameObject* newEntity = GetEntity(newId);
|
||||
|
||||
if (newEntity) {
|
||||
newEntity->components.clear();
|
||||
for (const auto& comp : data.components) {
|
||||
if (auto* transform = dynamic_cast<const TransformComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<TransformComponent>();
|
||||
memcpy(newComp->position, transform->position, sizeof(transform->position));
|
||||
memcpy(newComp->rotation, transform->rotation, sizeof(transform->rotation));
|
||||
memcpy(newComp->scale, transform->scale, sizeof(transform->scale));
|
||||
newEntity->components.push_back(std::move(newComp));
|
||||
}
|
||||
else if (auto* meshRenderer = dynamic_cast<const MeshRendererComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<MeshRendererComponent>();
|
||||
newComp->materialName = meshRenderer->materialName;
|
||||
newComp->meshName = meshRenderer->meshName;
|
||||
newEntity->components.push_back(std::move(newComp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& childData : data.children) {
|
||||
PasteEntityRecursive(childData, newId);
|
||||
}
|
||||
|
||||
return newId;
|
||||
}
|
||||
|
||||
EntityID SceneManager::PasteEntity(EntityID parent) {
|
||||
if (!m_clipboard) return INVALID_ENTITY_ID;
|
||||
return PasteEntityRecursive(*m_clipboard, parent);
|
||||
}
|
||||
|
||||
EntityID SceneManager::DuplicateEntity(EntityID id) {
|
||||
CopyEntity(id);
|
||||
const GameObject* entity = GetEntity(id);
|
||||
if (!entity) return INVALID_ENTITY_ID;
|
||||
return PasteEntity(entity->parent);
|
||||
}
|
||||
|
||||
void SceneManager::MoveEntity(EntityID id, EntityID newParent) {
|
||||
GameObject* entity = GetEntity(id);
|
||||
if (!entity || id == newParent) return;
|
||||
|
||||
if (entity->parent != INVALID_ENTITY_ID) {
|
||||
GameObject* oldParent = GetEntity(entity->parent);
|
||||
if (oldParent) {
|
||||
auto& siblings = oldParent->children;
|
||||
siblings.erase(std::remove(siblings.begin(), siblings.end(), id), siblings.end());
|
||||
}
|
||||
} else {
|
||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), id), m_rootEntities.end());
|
||||
}
|
||||
|
||||
entity->parent = newParent;
|
||||
|
||||
if (newParent != INVALID_ENTITY_ID) {
|
||||
GameObject* newParentEntity = GetEntity(newParent);
|
||||
if (newParentEntity) {
|
||||
newParentEntity->children.push_back(id);
|
||||
}
|
||||
} else {
|
||||
m_rootEntities.push_back(id);
|
||||
}
|
||||
|
||||
OnEntityChanged.Invoke(id);
|
||||
}
|
||||
|
||||
void SceneManager::CreateDemoScene() {
|
||||
m_entities.clear();
|
||||
m_rootEntities.clear();
|
||||
m_nextEntityId = 1;
|
||||
m_clipboard.reset();
|
||||
|
||||
EntityID camera = CreateEntity("Main Camera");
|
||||
GetEntity(camera)->AddComponent<TransformComponent>();
|
||||
|
||||
EntityID light = CreateEntity("Directional Light");
|
||||
|
||||
EntityID cube = CreateEntity("Cube");
|
||||
GetEntity(cube)->AddComponent<TransformComponent>();
|
||||
GetEntity(cube)->AddComponent<MeshRendererComponent>()->meshName = "Cube Mesh";
|
||||
|
||||
EntityID sphere = CreateEntity("Sphere");
|
||||
GetEntity(sphere)->AddComponent<TransformComponent>();
|
||||
GetEntity(sphere)->AddComponent<MeshRendererComponent>()->meshName = "Sphere Mesh";
|
||||
|
||||
EntityID player = CreateEntity("Player");
|
||||
EntityID weapon = CreateEntity("Weapon", player);
|
||||
|
||||
OnSceneChanged.Invoke();
|
||||
}
|
||||
|
||||
}
|
||||
87
editor/src/Managers/SceneManager.h
Normal file
87
editor/src/Managers/SceneManager.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/GameObject.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
struct ClipboardData {
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<Component>> components;
|
||||
std::vector<ClipboardData> children;
|
||||
};
|
||||
|
||||
class SceneManager {
|
||||
public:
|
||||
static SceneManager& Get() {
|
||||
static SceneManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
EntityID CreateEntity(const std::string& name, EntityID parent = INVALID_ENTITY_ID);
|
||||
|
||||
GameObject* GetEntity(EntityID id) {
|
||||
auto it = m_entities.find(id);
|
||||
if (it != m_entities.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GameObject* GetEntity(EntityID id) const {
|
||||
auto it = m_entities.find(id);
|
||||
if (it != m_entities.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<EntityID>& GetRootEntities() const {
|
||||
return m_rootEntities;
|
||||
}
|
||||
|
||||
void DeleteEntity(EntityID id);
|
||||
|
||||
void RenameEntity(EntityID id, const std::string& newName) {
|
||||
auto* entity = GetEntity(id);
|
||||
if (entity) {
|
||||
entity->name = newName;
|
||||
OnEntityChanged.Invoke(id);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyEntity(EntityID id);
|
||||
|
||||
EntityID PasteEntity(EntityID parent = INVALID_ENTITY_ID);
|
||||
|
||||
EntityID DuplicateEntity(EntityID id);
|
||||
|
||||
void MoveEntity(EntityID id, EntityID newParent);
|
||||
|
||||
void CreateDemoScene();
|
||||
|
||||
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
||||
|
||||
XCEngine::Core::Event<EntityID> OnEntityCreated;
|
||||
XCEngine::Core::Event<EntityID> OnEntityDeleted;
|
||||
XCEngine::Core::Event<EntityID> OnEntityChanged;
|
||||
XCEngine::Core::Event<> OnSceneChanged;
|
||||
|
||||
private:
|
||||
SceneManager() = default;
|
||||
|
||||
ClipboardData CopyEntityRecursive(const GameObject* entity);
|
||||
EntityID PasteEntityRecursive(const ClipboardData& data, EntityID parent);
|
||||
|
||||
EntityID m_nextEntityId = 1;
|
||||
std::unordered_map<EntityID, GameObject> m_entities;
|
||||
std::vector<EntityID> m_rootEntities;
|
||||
std::optional<ClipboardData> m_clipboard;
|
||||
};
|
||||
|
||||
}
|
||||
39
editor/src/Managers/SelectionManager.h
Normal file
39
editor/src/Managers/SelectionManager.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/GameObject.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
class SelectionManager {
|
||||
public:
|
||||
static SelectionManager& Get() {
|
||||
static SelectionManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
EntityID GetSelectedEntity() const { return m_selectedEntity; }
|
||||
|
||||
void SetSelectedEntity(EntityID id) {
|
||||
m_selectedEntity = id;
|
||||
OnSelectionChanged.Invoke(id);
|
||||
}
|
||||
|
||||
void ClearSelection() {
|
||||
SetSelectedEntity(INVALID_ENTITY_ID);
|
||||
}
|
||||
|
||||
bool IsSelected(EntityID id) const {
|
||||
return m_selectedEntity == id;
|
||||
}
|
||||
|
||||
XCEngine::Core::Event<EntityID> OnSelectionChanged;
|
||||
|
||||
private:
|
||||
SelectionManager() = default;
|
||||
EntityID m_selectedEntity = INVALID_ENTITY_ID;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user