重构ui_editor:向引擎核心类型对齐
- 删除UI::Event,使用XCEngine::Core::Event替代 - GameObject.h重构,Component添加friend class Entity - LogEntry使用XCEngine::Debug::LogLevel - SceneManager/SelectionManager使用XCEngine::Core::Event - LogSystem使用XCEngine::Debug::LogLevel - CMakeLists.txt添加engine/include路径
This commit is contained in:
@@ -50,6 +50,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${imgui_SOURCE_DIR}
|
||||
${imgui_SOURCE_DIR}/backends
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../engine/include
|
||||
)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE UNICODE _UNICODE)
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace UI {
|
||||
|
||||
template<typename... Args>
|
||||
class Event {
|
||||
public:
|
||||
using HandlerID = size_t;
|
||||
using Handler = std::function<void(Args...)>;
|
||||
|
||||
HandlerID Subscribe(Handler handler) {
|
||||
HandlerID id = m_nextId++;
|
||||
m_handlers.emplace_back(id, std::move(handler));
|
||||
return id;
|
||||
}
|
||||
|
||||
void Unsubscribe(HandlerID id) {
|
||||
m_handlers.erase(
|
||||
std::remove_if(m_handlers.begin(), m_handlers.end(),
|
||||
[id](const auto& pair) { return pair.first == id; }),
|
||||
m_handlers.end()
|
||||
);
|
||||
}
|
||||
|
||||
void Invoke(Args... args) {
|
||||
for (const auto& pair : m_handlers) {
|
||||
pair.second(args...);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(Args... args) {
|
||||
Invoke(args...);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
m_handlers.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
HandlerID m_nextId = 0;
|
||||
std::vector<std::pair<HandlerID, Handler>> m_handlers;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -7,15 +7,32 @@
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
using EntityID = uint64_t;
|
||||
constexpr EntityID INVALID_ENTITY = 0;
|
||||
constexpr EntityID INVALID_ENTITY_ID = 0;
|
||||
|
||||
class Component {
|
||||
public:
|
||||
virtual ~Component() = default;
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
virtual void Awake() {}
|
||||
virtual void Start() {}
|
||||
virtual void Update(float deltaTime) {}
|
||||
virtual void OnDestroy() {}
|
||||
|
||||
class Entity* GetEntity() const { return m_entity; }
|
||||
bool IsEnabled() const { return m_enabled; }
|
||||
void SetEnabled(bool enabled) { m_enabled = enabled; }
|
||||
|
||||
protected:
|
||||
class Entity* m_entity = nullptr;
|
||||
bool m_enabled = true;
|
||||
|
||||
friend class Entity;
|
||||
};
|
||||
|
||||
class TransformComponent : public Component {
|
||||
@@ -35,10 +52,11 @@ public:
|
||||
std::string GetName() const override { return "Mesh Renderer"; }
|
||||
};
|
||||
|
||||
struct Entity {
|
||||
EntityID id = INVALID_ENTITY;
|
||||
class Entity {
|
||||
public:
|
||||
EntityID id = INVALID_ENTITY_ID;
|
||||
std::string name;
|
||||
EntityID parent = INVALID_ENTITY;
|
||||
EntityID parent = INVALID_ENTITY_ID;
|
||||
std::vector<EntityID> children;
|
||||
std::vector<std::unique_ptr<Component>> components;
|
||||
bool selected = false;
|
||||
@@ -46,6 +64,7 @@ struct Entity {
|
||||
template<typename T, typename... Args>
|
||||
T* AddComponent(Args&&... args) {
|
||||
auto comp = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
comp->m_entity = this;
|
||||
T* ptr = comp.get();
|
||||
components.push_back(std::move(comp));
|
||||
return ptr;
|
||||
@@ -60,6 +79,17 @@ struct Entity {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T*> GetComponents() {
|
||||
std::vector<T*> result;
|
||||
for (auto& comp : components) {
|
||||
if (auto casted = dynamic_cast<T*>(comp.get())) {
|
||||
result.push_back(casted);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
using ComponentInspectorFn = std::function<void(Component*)>;
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <XCEngine/Debug/LogLevel.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
struct LogEntry {
|
||||
enum class Level { Info, Warning, Error };
|
||||
Level level;
|
||||
XCEngine::Debug::LogLevel level;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ LogSystem& LogSystem::Get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
void LogSystem::AddLog(LogEntry::Level level, const std::string& message) {
|
||||
void LogSystem::AddLog(XCEngine::Debug::LogLevel level, const std::string& message) {
|
||||
m_logs.push_back({level, message});
|
||||
if (m_callback) m_callback();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class LogSystem {
|
||||
public:
|
||||
static LogSystem& Get();
|
||||
|
||||
void AddLog(LogEntry::Level level, const std::string& message);
|
||||
void AddLog(XCEngine::Debug::LogLevel level, const std::string& message);
|
||||
void Clear();
|
||||
const std::vector<LogEntry>& GetLogs() const { return m_logs; }
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "SceneManager.h"
|
||||
#include "SelectionManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace UI {
|
||||
@@ -11,7 +12,7 @@ EntityID SceneManager::CreateEntity(const std::string& name, EntityID parent) {
|
||||
entity.parent = parent;
|
||||
m_entities[id] = std::move(entity);
|
||||
|
||||
if (parent != INVALID_ENTITY) {
|
||||
if (parent != INVALID_ENTITY_ID) {
|
||||
m_entities[parent].children.push_back(id);
|
||||
} else {
|
||||
m_rootEntities.push_back(id);
|
||||
@@ -32,7 +33,7 @@ void SceneManager::DeleteEntity(EntityID id) {
|
||||
DeleteEntity(childId);
|
||||
}
|
||||
|
||||
if (entity.parent != INVALID_ENTITY) {
|
||||
if (entity.parent != INVALID_ENTITY_ID) {
|
||||
auto* parent = GetEntity(entity.parent);
|
||||
if (parent) {
|
||||
auto& siblings = parent->children;
|
||||
@@ -118,14 +119,14 @@ EntityID SceneManager::PasteEntityRecursive(const ClipboardData& data, EntityID
|
||||
}
|
||||
|
||||
EntityID SceneManager::PasteEntity(EntityID parent) {
|
||||
if (!m_clipboard) return INVALID_ENTITY;
|
||||
if (!m_clipboard) return INVALID_ENTITY_ID;
|
||||
return PasteEntityRecursive(*m_clipboard, parent);
|
||||
}
|
||||
|
||||
EntityID SceneManager::DuplicateEntity(EntityID id) {
|
||||
CopyEntity(id);
|
||||
const Entity* entity = GetEntity(id);
|
||||
if (!entity) return INVALID_ENTITY;
|
||||
if (!entity) return INVALID_ENTITY_ID;
|
||||
return PasteEntity(entity->parent);
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@ void SceneManager::MoveEntity(EntityID id, EntityID newParent) {
|
||||
Entity* entity = GetEntity(id);
|
||||
if (!entity || id == newParent) return;
|
||||
|
||||
if (entity->parent != INVALID_ENTITY) {
|
||||
if (entity->parent != INVALID_ENTITY_ID) {
|
||||
Entity* oldParent = GetEntity(entity->parent);
|
||||
if (oldParent) {
|
||||
auto& siblings = oldParent->children;
|
||||
@@ -145,7 +146,7 @@ void SceneManager::MoveEntity(EntityID id, EntityID newParent) {
|
||||
|
||||
entity->parent = newParent;
|
||||
|
||||
if (newParent != INVALID_ENTITY) {
|
||||
if (newParent != INVALID_ENTITY_ID) {
|
||||
Entity* newParentEntity = GetEntity(newParent);
|
||||
if (newParentEntity) {
|
||||
newParentEntity->children.push_back(id);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/GameObject.h"
|
||||
#include "SelectionManager.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
struct ClipboardData {
|
||||
@@ -22,7 +23,7 @@ public:
|
||||
return instance;
|
||||
}
|
||||
|
||||
EntityID CreateEntity(const std::string& name, EntityID parent = INVALID_ENTITY);
|
||||
EntityID CreateEntity(const std::string& name, EntityID parent = INVALID_ENTITY_ID);
|
||||
|
||||
Entity* GetEntity(EntityID id) {
|
||||
auto it = m_entities.find(id);
|
||||
@@ -56,7 +57,7 @@ public:
|
||||
|
||||
void CopyEntity(EntityID id);
|
||||
|
||||
EntityID PasteEntity(EntityID parent = INVALID_ENTITY);
|
||||
EntityID PasteEntity(EntityID parent = INVALID_ENTITY_ID);
|
||||
|
||||
EntityID DuplicateEntity(EntityID id);
|
||||
|
||||
@@ -66,10 +67,10 @@ public:
|
||||
|
||||
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
||||
|
||||
Event<EntityID> OnEntityCreated;
|
||||
Event<EntityID> OnEntityDeleted;
|
||||
Event<EntityID> OnEntityChanged;
|
||||
Event<> OnSceneChanged;
|
||||
XCEngine::Core::Event<EntityID> OnEntityCreated;
|
||||
XCEngine::Core::Event<EntityID> OnEntityDeleted;
|
||||
XCEngine::Core::Event<EntityID> OnEntityChanged;
|
||||
XCEngine::Core::Event<> OnSceneChanged;
|
||||
|
||||
private:
|
||||
SceneManager() = default;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/GameObject.h"
|
||||
#include "Core/Event.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
class SelectionManager {
|
||||
@@ -21,18 +22,18 @@ public:
|
||||
}
|
||||
|
||||
void ClearSelection() {
|
||||
SetSelectedEntity(INVALID_ENTITY);
|
||||
SetSelectedEntity(INVALID_ENTITY_ID);
|
||||
}
|
||||
|
||||
bool IsSelected(EntityID id) const {
|
||||
return m_selectedEntity == id;
|
||||
}
|
||||
|
||||
Event<EntityID> OnSelectionChanged;
|
||||
XCEngine::Core::Event<EntityID> OnSelectionChanged;
|
||||
|
||||
private:
|
||||
SelectionManager() = default;
|
||||
EntityID m_selectedEntity = INVALID_ENTITY;
|
||||
EntityID m_selectedEntity = INVALID_ENTITY_ID;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,11 +6,11 @@
|
||||
namespace UI {
|
||||
|
||||
ConsolePanel::ConsolePanel() : Panel("Console") {
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Engine initialized successfully");
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Loading default scene...");
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Warning, "Missing material on object 'Cube'");
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Error, "Failed to load texture: 'Assets/Textures/missing.png'");
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Scene loaded successfully");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Info, "Engine initialized successfully");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Info, "Loading default scene...");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Warning, "Missing material on object 'Cube'");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Error, "Failed to load texture: 'Assets/Textures/missing.png'");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Info, "Scene loaded successfully");
|
||||
}
|
||||
|
||||
void ConsolePanel::Render() {
|
||||
@@ -21,15 +21,15 @@ void ConsolePanel::Render() {
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Info")) {
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Info, "Test info message");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Info, "Test info message");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Warn")) {
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Warning, "Test warning message");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Warning, "Test warning message");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Error")) {
|
||||
LogSystem::Get().AddLog(LogEntry::Level::Error, "Test error message");
|
||||
LogSystem::Get().AddLog(XCEngine::Debug::LogLevel::Error, "Test error message");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -41,15 +41,15 @@ void ConsolePanel::Render() {
|
||||
const char* prefix;
|
||||
|
||||
switch (log.level) {
|
||||
case LogEntry::Level::Info:
|
||||
case XCEngine::Debug::LogLevel::Info:
|
||||
color = ImVec4(0.7f, 0.7f, 0.7f, 1.0f);
|
||||
prefix = "[Info] ";
|
||||
break;
|
||||
case LogEntry::Level::Warning:
|
||||
case XCEngine::Debug::LogLevel::Warning:
|
||||
color = ImVec4(1.0f, 0.8f, 0.0f, 1.0f);
|
||||
prefix = "[Warn] ";
|
||||
break;
|
||||
case LogEntry::Level::Error:
|
||||
case XCEngine::Debug::LogLevel::Error:
|
||||
color = ImVec4(1.0f, 0.3f, 0.3f, 1.0f);
|
||||
prefix = "[Error]";
|
||||
break;
|
||||
|
||||
@@ -41,7 +41,7 @@ void HierarchyPanel::Render() {
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
||||
RenderCreateMenu(INVALID_ENTITY);
|
||||
RenderCreateMenu(INVALID_ENTITY_ID);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ void HierarchyPanel::Render() {
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_ID")) {
|
||||
EntityID sourceId = *(const EntityID*)payload->Data;
|
||||
if (sourceId != INVALID_ENTITY) {
|
||||
if (sourceId != INVALID_ENTITY_ID) {
|
||||
const Entity* sourceEntity = SceneManager::Get().GetEntity(sourceId);
|
||||
if (sourceEntity && sourceEntity->parent != INVALID_ENTITY) {
|
||||
SceneManager::Get().MoveEntity(sourceId, INVALID_ENTITY);
|
||||
if (sourceEntity && sourceEntity->parent != INVALID_ENTITY_ID) {
|
||||
SceneManager::Get().MoveEntity(sourceId, INVALID_ENTITY_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,7 @@ void HierarchyPanel::RenderEntity(EntityID id, const std::string& filter) {
|
||||
sceneManager.RenameEntity(id, m_renameBuffer);
|
||||
}
|
||||
m_renaming = false;
|
||||
m_renamingEntity = INVALID_ENTITY;
|
||||
m_renamingEntity = INVALID_ENTITY_ID;
|
||||
}
|
||||
|
||||
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) {
|
||||
@@ -110,7 +110,7 @@ void HierarchyPanel::RenderEntity(EntityID id, const std::string& filter) {
|
||||
sceneManager.RenameEntity(id, m_renameBuffer);
|
||||
}
|
||||
m_renaming = false;
|
||||
m_renamingEntity = INVALID_ENTITY;
|
||||
m_renamingEntity = INVALID_ENTITY_ID;
|
||||
}
|
||||
} else {
|
||||
bool isOpen = ImGui::TreeNodeEx(entity->name.c_str(), flags);
|
||||
@@ -181,7 +181,7 @@ void HierarchyPanel::RenderContextMenu(EntityID id) {
|
||||
|
||||
if (ImGui::MenuItem("Duplicate", "Ctrl+D")) {
|
||||
EntityID newId = sceneManager.DuplicateEntity(id);
|
||||
if (newId != INVALID_ENTITY) {
|
||||
if (newId != INVALID_ENTITY_ID) {
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
}
|
||||
@@ -249,19 +249,19 @@ void HierarchyPanel::HandleDragDrop(EntityID id) {
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_ID")) {
|
||||
EntityID sourceId = *(const EntityID*)payload->Data;
|
||||
if (sourceId != id && sourceId != INVALID_ENTITY) {
|
||||
if (sourceId != id && sourceId != INVALID_ENTITY_ID) {
|
||||
const Entity* targetEntity = sceneManager.GetEntity(id);
|
||||
const Entity* sourceEntity = sceneManager.GetEntity(sourceId);
|
||||
|
||||
bool isValidMove = true;
|
||||
EntityID checkParent = targetEntity ? targetEntity->parent : INVALID_ENTITY;
|
||||
while (checkParent != INVALID_ENTITY) {
|
||||
EntityID checkParent = targetEntity ? targetEntity->parent : INVALID_ENTITY_ID;
|
||||
while (checkParent != INVALID_ENTITY_ID) {
|
||||
if (checkParent == sourceId) {
|
||||
isValidMove = false;
|
||||
break;
|
||||
}
|
||||
const Entity* parentEntity = sceneManager.GetEntity(checkParent);
|
||||
checkParent = parentEntity ? parentEntity->parent : INVALID_ENTITY;
|
||||
checkParent = parentEntity ? parentEntity->parent : INVALID_ENTITY_ID;
|
||||
}
|
||||
|
||||
if (isValidMove && sourceEntity && sourceEntity->parent != id) {
|
||||
@@ -281,13 +281,13 @@ void HierarchyPanel::HandleKeyboardShortcuts() {
|
||||
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Delete)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
if (selectedId != INVALID_ENTITY_ID) {
|
||||
sceneManager.DeleteEntity(selectedId);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F2)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
if (selectedId != INVALID_ENTITY_ID) {
|
||||
const Entity* entity = sceneManager.GetEntity(selectedId);
|
||||
if (entity) {
|
||||
m_renaming = true;
|
||||
@@ -301,7 +301,7 @@ void HierarchyPanel::HandleKeyboardShortcuts() {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.KeyCtrl) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
if (selectedId != INVALID_ENTITY_ID) {
|
||||
sceneManager.CopyEntity(selectedId);
|
||||
}
|
||||
}
|
||||
@@ -313,9 +313,9 @@ void HierarchyPanel::HandleKeyboardShortcuts() {
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
if (selectedId != INVALID_ENTITY_ID) {
|
||||
EntityID newId = sceneManager.DuplicateEntity(selectedId);
|
||||
if (newId != INVALID_ENTITY) {
|
||||
if (newId != INVALID_ENTITY_ID) {
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Core/Event.h"
|
||||
#include "Core/GameObject.h"
|
||||
|
||||
namespace UI {
|
||||
@@ -22,14 +21,14 @@ private:
|
||||
void HandleKeyboardShortcuts();
|
||||
bool PassesFilter(EntityID id, const std::string& filter);
|
||||
|
||||
Event<EntityID>::HandlerID m_selectionHandlerId = 0;
|
||||
uint64_t m_selectionHandlerId = 0;
|
||||
|
||||
char m_searchBuffer[256] = "";
|
||||
bool m_renaming = false;
|
||||
EntityID m_renamingEntity = INVALID_ENTITY;
|
||||
EntityID m_renamingEntity = INVALID_ENTITY_ID;
|
||||
char m_renameBuffer[256] = "";
|
||||
bool m_renameJustStarted = false;
|
||||
EntityID m_dragSource = INVALID_ENTITY;
|
||||
EntityID m_dragSource = INVALID_ENTITY_ID;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Core/Event.h"
|
||||
#include "Core/GameObject.h"
|
||||
|
||||
namespace UI {
|
||||
@@ -17,7 +16,7 @@ private:
|
||||
void RenderEntity(Entity* entity);
|
||||
void RenderComponent(Component* component);
|
||||
|
||||
Event<EntityID>::HandlerID m_selectionHandlerId = 0;
|
||||
uint64_t m_selectionHandlerId = 0;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user