#include "Actions/InspectorActionRouter.h" #include "Actions/ActionRouting.h" #include "Actions/EditorActions.h" #include "InspectorPanel.h" #include "Core/IEditorContext.h" #include "Core/ISceneManager.h" #include "Core/ISelectionManager.h" #include "Core/EventBus.h" #include "Core/EditorEvents.h" #include "ComponentEditors/ComponentEditorRegistry.h" #include "ComponentEditors/IComponentEditor.h" #include "UI/UI.h" #include #include namespace XCEngine { namespace Editor { InspectorPanel::InspectorPanel() : Panel("Inspector") {} InspectorPanel::~InspectorPanel() { } void InspectorPanel::OnAttach() { if (!m_context || m_selectionHandlerId) { return; } m_selectionHandlerId = m_context->GetEventBus().Subscribe( [this](const SelectionChangedEvent& event) { OnSelectionChanged(event); } ); m_selectedEntityId = m_context->GetSelectionManager().GetSelectedEntity(); } void InspectorPanel::OnDetach() { if (!m_context || !m_selectionHandlerId) { return; } m_context->GetEventBus().Unsubscribe(m_selectionHandlerId); m_selectionHandlerId = 0; } void InspectorPanel::OnSelectionChanged(const SelectionChangedEvent& event) { Actions::HandleInspectorSelectionChanged(*m_context, event, m_selectedEntityId, m_addComponentPopup); } void InspectorPanel::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::ObserveInactiveActionRoute(*m_context); if (m_selectedEntityId) { auto& sceneManager = m_context->GetSceneManager(); auto* gameObject = sceneManager.GetEntity(m_selectedEntityId); if (gameObject) { RenderGameObject(gameObject); } else { RenderEmptyState("Object not found"); } } else { UI::PanelContentScope content( "InspectorEmpty", UI::InspectorPanelContentPadding(), ImGuiChildFlags_None); } } ImGui::PopStyleColor(2); } void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameObject) { ImGuiStyle& style = ImGui::GetStyle(); UI::PanelContentScope content( "InspectorContent", UI::InspectorPanelContentPadding(), ImGuiChildFlags_None, ImGuiWindowFlags_None, true, ImVec2(style.ItemSpacing.x, 0.0f)); if (!content.IsOpen()) { return; } auto components = gameObject->GetComponents<::XCEngine::Components::Component>(); for (auto* component : components) { RenderComponent(component, gameObject); } Actions::DrawInspectorAddComponentButton(m_addComponentPopup, gameObject != nullptr); Actions::DrawInspectorAddComponentPopup(*m_context, m_addComponentPopup, gameObject); Actions::FinalizeInspectorInteractiveChangeIfIdle(*m_context); } void InspectorPanel::RenderEmptyState(const char* title, const char* subtitle) { UI::PanelContentScope content( "InspectorEmptyState", UI::InspectorPanelContentPadding(), ImGuiChildFlags_None); if (!content.IsOpen()) { return; } UI::DrawEmptyState(title, subtitle); } void InspectorPanel::RenderComponent(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject) { if (!component) return; IComponentEditor* editor = ComponentEditorRegistry::Get().FindEditor(component); const std::string name = component->GetName(); bool removed = false; const UI::ComponentSectionResult section = UI::BeginComponentSection( (void*)typeid(*component).hash_code(), name.c_str(), [&]() { removed = Actions::DrawInspectorComponentMenu(*m_context, component, gameObject, editor); }); if (removed) { return; } if (section.open) { ImGui::Indent(section.contentIndent); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, UI::InspectorComponentControlSpacing()); if (editor) { if (editor->Render(component, &m_context->GetUndoManager())) { m_context->GetSceneManager().MarkSceneDirty(); } } else { UI::DrawHintText("No registered editor for this component"); } ImGui::PopStyleVar(); UI::EndComponentSection(section); } } } }