#include "Actions/HierarchyActionRouter.h" #include "Actions/ActionRouting.h" #include "Commands/EntityCommands.h" #include "HierarchyPanel.h" #include "Core/IEditorContext.h" #include "Core/ISceneManager.h" #include "Core/ISelectionManager.h" #include "Core/EditorEvents.h" #include "Core/EventBus.h" #include "UI/UI.h" #include namespace XCEngine { namespace Editor { HierarchyPanel::HierarchyPanel() : Panel("Hierarchy") { } void HierarchyPanel::OnAttach() { if (!m_context || m_selectionHandlerId || m_renameRequestHandlerId) { return; } m_selectionHandlerId = m_context->GetEventBus().Subscribe( [this](const SelectionChangedEvent& event) { OnSelectionChanged(event); } ); m_renameRequestHandlerId = m_context->GetEventBus().Subscribe( [this](const EntityRenameRequestedEvent& event) { OnRenameRequested(event); } ); } void HierarchyPanel::OnDetach() { if (!m_context) { return; } if (m_selectionHandlerId) { m_context->GetEventBus().Unsubscribe(m_selectionHandlerId); m_selectionHandlerId = 0; } if (m_renameRequestHandlerId) { m_context->GetEventBus().Unsubscribe(m_renameRequestHandlerId); m_renameRequestHandlerId = 0; } } void HierarchyPanel::OnSelectionChanged(const SelectionChangedEvent& event) { if (m_renameState.IsActive() && event.primarySelection != m_renameState.Item()) { CancelRename(); } } void HierarchyPanel::OnRenameRequested(const EntityRenameRequestedEvent& event) { if (!m_context || event.entityId == 0) { return; } if (auto* gameObject = m_context->GetSceneManager().GetEntity(event.entityId)) { BeginRename(gameObject); } } void HierarchyPanel::Render() { ImGui::PushStyleColor(ImGuiCol_WindowBg, UI::HierarchyInspectorPanelBackgroundColor()); ImGui::PushStyleColor(ImGuiCol_ChildBg, UI::HierarchyInspectorPanelBackgroundColor()); { UI::PanelWindowScope panel(m_name.c_str()); if (!panel.IsOpen()) { ImGui::PopStyleColor(2); return; } Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Hierarchy); UI::PanelContentScope content("EntityList"); if (!content.IsOpen()) { ImGui::PopStyleColor(2); return; } auto& sceneManager = m_context->GetSceneManager(); auto rootEntities = sceneManager.GetRootEntities(); for (auto* gameObject : rootEntities) { RenderEntity(gameObject); } Actions::HandleHierarchyBackgroundPrimaryClick(*m_context, m_renameState); Actions::DrawHierarchyBackgroundContextPopup(*m_context); Actions::DrawHierarchyRootDropTarget(*m_context); } ImGui::PopStyleColor(2); } void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject) { if (!gameObject) return; ImGui::PushID(static_cast(gameObject->GetID())); if (m_renameState.IsEditing(gameObject->GetID())) { if (m_renameState.ConsumeFocusRequest()) { ImGui::SetKeyboardFocusHere(); } ImGui::SetNextItemWidth(-1); if (ImGui::InputText( "##Rename", m_renameState.Buffer(), m_renameState.BufferSize(), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) { CommitRename(); } if (ImGui::IsItemActive() && ImGui::IsKeyPressed(ImGuiKey_Escape)) { CancelRename(); } else if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) { CommitRename(); } } else { UI::TreeNodeOptions nodeOptions; nodeOptions.selected = m_context->GetSelectionManager().IsSelected(gameObject->GetID()); nodeOptions.leaf = gameObject->GetChildCount() == 0; const UI::TreeNodeResult node = UI::DrawTreeNode( (void*)gameObject->GetUUID(), gameObject->GetName().c_str(), nodeOptions); if (node.clicked) { Actions::HandleHierarchySelectionClick(*m_context, gameObject->GetID(), ImGui::GetIO().KeyCtrl); } if (node.doubleClicked) { BeginRename(gameObject); } Actions::BeginHierarchyEntityDrag(gameObject); Actions::AcceptHierarchyEntityDrop(*m_context, gameObject); Actions::DrawHierarchyEntityContextPopup(*m_context, gameObject); if (node.open) { for (size_t i = 0; i < gameObject->GetChildCount(); i++) { RenderEntity(gameObject->GetChild(i)); } UI::EndTreeNode(); } } ImGui::PopID(); } void HierarchyPanel::BeginRename(::XCEngine::Components::GameObject* gameObject) { if (!gameObject) { CancelRename(); return; } m_renameState.Begin(gameObject->GetID(), gameObject->GetName().c_str()); } void HierarchyPanel::CommitRename() { if (!m_renameState.IsActive()) { return; } const uint64_t entityId = m_renameState.Item(); Actions::CommitEntityRename(*m_context, entityId, m_renameState.Buffer()); CancelRename(); } void HierarchyPanel::CancelRename() { m_renameState.Cancel(); } } }