添加ui_editor编辑器模块初始代码
This commit is contained in:
345
ui_editor/src/panels/HierarchyPanel.cpp
Normal file
345
ui_editor/src/panels/HierarchyPanel.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
#include "HierarchyPanel.h"
|
||||
#include "Managers/SceneManager.h"
|
||||
#include "Managers/SelectionManager.h"
|
||||
#include <imgui.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace UI {
|
||||
|
||||
HierarchyPanel::HierarchyPanel() : Panel("Hierarchy") {
|
||||
SceneManager::Get().CreateDemoScene();
|
||||
|
||||
m_selectionHandlerId = SelectionManager::Get().OnSelectionChanged.Subscribe([this](EntityID) {
|
||||
});
|
||||
}
|
||||
|
||||
HierarchyPanel::~HierarchyPanel() {
|
||||
SelectionManager::Get().OnSelectionChanged.Unsubscribe(m_selectionHandlerId);
|
||||
}
|
||||
|
||||
void HierarchyPanel::Render() {
|
||||
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
||||
|
||||
RenderSearchBar();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
HandleKeyboardShortcuts();
|
||||
|
||||
std::string filter = m_searchBuffer;
|
||||
|
||||
ImGui::BeginChild("EntityList");
|
||||
|
||||
for (EntityID id : SceneManager::Get().GetRootEntities()) {
|
||||
RenderEntity(id, filter);
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(0) && !ImGui::IsAnyItemHovered()) {
|
||||
if (!m_renaming) {
|
||||
SelectionManager::Get().ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
||||
RenderCreateMenu(INVALID_ENTITY);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::InvisibleButton("##DragTarget", ImVec2(-1, -1));
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_ID")) {
|
||||
EntityID sourceId = *(const EntityID*)payload->Data;
|
||||
if (sourceId != INVALID_ENTITY) {
|
||||
const Entity* sourceEntity = SceneManager::Get().GetEntity(sourceId);
|
||||
if (sourceEntity && sourceEntity->parent != INVALID_ENTITY) {
|
||||
SceneManager::Get().MoveEntity(sourceId, INVALID_ENTITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderSearchBar() {
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
ImGui::InputTextWithHint("##Search", "Search...", m_searchBuffer, sizeof(m_searchBuffer));
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderEntity(EntityID id, const std::string& filter) {
|
||||
auto& sceneManager = SceneManager::Get();
|
||||
Entity* entity = sceneManager.GetEntity(id);
|
||||
if (!entity) return;
|
||||
|
||||
if (!filter.empty() && !PassesFilter(id, filter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::PushID(static_cast<int>(id));
|
||||
|
||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
|
||||
|
||||
if (entity->children.empty()) {
|
||||
flags |= ImGuiTreeNodeFlags_Leaf;
|
||||
}
|
||||
|
||||
if (SelectionManager::Get().IsSelected(id)) {
|
||||
flags |= ImGuiTreeNodeFlags_Selected;
|
||||
}
|
||||
|
||||
if (m_renaming && m_renamingEntity == id) {
|
||||
if (m_renameJustStarted) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
m_renameJustStarted = false;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::InputText("##Rename", m_renameBuffer, sizeof(m_renameBuffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
if (strlen(m_renameBuffer) > 0) {
|
||||
sceneManager.RenameEntity(id, m_renameBuffer);
|
||||
}
|
||||
m_renaming = false;
|
||||
m_renamingEntity = INVALID_ENTITY;
|
||||
}
|
||||
|
||||
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) {
|
||||
if (strlen(m_renameBuffer) > 0) {
|
||||
sceneManager.RenameEntity(id, m_renameBuffer);
|
||||
}
|
||||
m_renaming = false;
|
||||
m_renamingEntity = INVALID_ENTITY;
|
||||
}
|
||||
} else {
|
||||
bool isOpen = ImGui::TreeNodeEx(entity->name.c_str(), flags);
|
||||
|
||||
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
|
||||
SelectionManager::Get().SetSelectedEntity(id);
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
||||
m_renaming = true;
|
||||
m_renamingEntity = id;
|
||||
strcpy_s(m_renameBuffer, entity->name.c_str());
|
||||
m_renameJustStarted = true;
|
||||
}
|
||||
|
||||
HandleDragDrop(id);
|
||||
|
||||
if (ImGui::BeginPopupContextItem("EntityContextMenu")) {
|
||||
RenderContextMenu(id);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
for (EntityID childId : entity->children) {
|
||||
RenderEntity(childId, filter);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderContextMenu(EntityID id) {
|
||||
auto& sceneManager = SceneManager::Get();
|
||||
auto& selectionManager = SelectionManager::Get();
|
||||
|
||||
if (ImGui::BeginMenu("Create")) {
|
||||
RenderCreateMenu(id);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Rename", "F2")) {
|
||||
const Entity* entity = sceneManager.GetEntity(id);
|
||||
if (entity) {
|
||||
m_renaming = true;
|
||||
m_renamingEntity = id;
|
||||
strcpy_s(m_renameBuffer, entity->name.c_str());
|
||||
m_renameJustStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Delete", "Delete")) {
|
||||
sceneManager.DeleteEntity(id);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Copy", "Ctrl+C")) {
|
||||
sceneManager.CopyEntity(id);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Paste", "Ctrl+V", false, sceneManager.HasClipboardData())) {
|
||||
sceneManager.PasteEntity(id);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Duplicate", "Ctrl+D")) {
|
||||
EntityID newId = sceneManager.DuplicateEntity(id);
|
||||
if (newId != INVALID_ENTITY) {
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderCreateMenu(EntityID parent) {
|
||||
auto& sceneManager = SceneManager::Get();
|
||||
auto& selectionManager = SelectionManager::Get();
|
||||
|
||||
if (ImGui::MenuItem("Empty Object")) {
|
||||
EntityID newId = sceneManager.CreateEntity("GameObject", parent);
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Camera")) {
|
||||
EntityID newId = sceneManager.CreateEntity("Camera", parent);
|
||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Light")) {
|
||||
EntityID newId = sceneManager.CreateEntity("Light", parent);
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Cube")) {
|
||||
EntityID newId = sceneManager.CreateEntity("Cube", parent);
|
||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
||||
sceneManager.GetEntity(newId)->AddComponent<MeshRendererComponent>()->meshName = "Cube";
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Sphere")) {
|
||||
EntityID newId = sceneManager.CreateEntity("Sphere", parent);
|
||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
||||
sceneManager.GetEntity(newId)->AddComponent<MeshRendererComponent>()->meshName = "Sphere";
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Plane")) {
|
||||
EntityID newId = sceneManager.CreateEntity("Plane", parent);
|
||||
sceneManager.GetEntity(newId)->AddComponent<TransformComponent>();
|
||||
sceneManager.GetEntity(newId)->AddComponent<MeshRendererComponent>()->meshName = "Plane";
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::HandleDragDrop(EntityID id) {
|
||||
auto& sceneManager = SceneManager::Get();
|
||||
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
m_dragSource = id;
|
||||
ImGui::SetDragDropPayload("ENTITY_ID", &id, sizeof(EntityID));
|
||||
const Entity* entity = sceneManager.GetEntity(id);
|
||||
if (entity) {
|
||||
ImGui::Text("%s", entity->name.c_str());
|
||||
}
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_ID")) {
|
||||
EntityID sourceId = *(const EntityID*)payload->Data;
|
||||
if (sourceId != id && sourceId != INVALID_ENTITY) {
|
||||
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) {
|
||||
if (checkParent == sourceId) {
|
||||
isValidMove = false;
|
||||
break;
|
||||
}
|
||||
const Entity* parentEntity = sceneManager.GetEntity(checkParent);
|
||||
checkParent = parentEntity ? parentEntity->parent : INVALID_ENTITY;
|
||||
}
|
||||
|
||||
if (isValidMove && sourceEntity && sourceEntity->parent != id) {
|
||||
sceneManager.MoveEntity(sourceId, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::HandleKeyboardShortcuts() {
|
||||
auto& sceneManager = SceneManager::Get();
|
||||
auto& selectionManager = SelectionManager::Get();
|
||||
|
||||
EntityID selectedId = selectionManager.GetSelectedEntity();
|
||||
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Delete)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
sceneManager.DeleteEntity(selectedId);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F2)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
const Entity* entity = sceneManager.GetEntity(selectedId);
|
||||
if (entity) {
|
||||
m_renaming = true;
|
||||
m_renamingEntity = selectedId;
|
||||
strcpy_s(m_renameBuffer, entity->name.c_str());
|
||||
m_renameJustStarted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.KeyCtrl) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
sceneManager.CopyEntity(selectedId);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_V)) {
|
||||
if (sceneManager.HasClipboardData()) {
|
||||
sceneManager.PasteEntity(selectedId);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
|
||||
if (selectedId != INVALID_ENTITY) {
|
||||
EntityID newId = sceneManager.DuplicateEntity(selectedId);
|
||||
if (newId != INVALID_ENTITY) {
|
||||
selectionManager.SetSelectedEntity(newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HierarchyPanel::PassesFilter(EntityID id, const std::string& filter) {
|
||||
auto& sceneManager = SceneManager::Get();
|
||||
const Entity* entity = sceneManager.GetEntity(id);
|
||||
if (!entity) return false;
|
||||
|
||||
if (entity->name.find(filter) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (EntityID childId : entity->children) {
|
||||
if (PassesFilter(childId, filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user