2026-03-27 00:08:46 +08:00
|
|
|
#include "Actions/InspectorActionRouter.h"
|
2026-03-26 22:31:22 +08:00
|
|
|
#include "Actions/ActionRouting.h"
|
2026-03-26 21:18:33 +08:00
|
|
|
#include "Actions/EditorActions.h"
|
2026-03-20 17:08:06 +08:00
|
|
|
#include "InspectorPanel.h"
|
2026-03-26 01:26:26 +08:00
|
|
|
#include "Core/IEditorContext.h"
|
2026-03-25 16:39:15 +08:00
|
|
|
#include "Core/ISceneManager.h"
|
2026-03-26 01:26:26 +08:00
|
|
|
#include "Core/ISelectionManager.h"
|
|
|
|
|
#include "Core/EventBus.h"
|
|
|
|
|
#include "Core/EditorEvents.h"
|
2026-03-26 02:24:11 +08:00
|
|
|
#include "ComponentEditors/ComponentEditorRegistry.h"
|
2026-03-26 01:26:26 +08:00
|
|
|
#include "ComponentEditors/IComponentEditor.h"
|
2026-03-26 21:18:33 +08:00
|
|
|
#include "UI/UI.h"
|
2026-03-20 17:08:06 +08:00
|
|
|
#include <imgui.h>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
2026-03-24 20:02:38 +08:00
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Editor {
|
2026-03-20 17:08:06 +08:00
|
|
|
|
2026-03-26 02:24:11 +08:00
|
|
|
InspectorPanel::InspectorPanel() : Panel("Inspector") {}
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
InspectorPanel::~InspectorPanel() {
|
2026-03-27 00:08:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InspectorPanel::OnAttach() {
|
|
|
|
|
if (!m_context || m_selectionHandlerId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_selectionHandlerId = m_context->GetEventBus().Subscribe<SelectionChangedEvent>(
|
|
|
|
|
[this](const SelectionChangedEvent& event) {
|
|
|
|
|
OnSelectionChanged(event);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
m_selectedEntityId = m_context->GetSelectionManager().GetSelectedEntity();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InspectorPanel::OnDetach() {
|
|
|
|
|
if (!m_context || !m_selectionHandlerId) {
|
|
|
|
|
return;
|
2026-03-25 15:54:22 +08:00
|
|
|
}
|
2026-03-27 00:08:46 +08:00
|
|
|
|
|
|
|
|
m_context->GetEventBus().Unsubscribe<SelectionChangedEvent>(m_selectionHandlerId);
|
|
|
|
|
m_selectionHandlerId = 0;
|
2026-03-25 15:54:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InspectorPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
|
2026-03-27 12:06:24 +08:00
|
|
|
Actions::HandleInspectorSelectionChanged(*m_context, event, m_selectedEntityId, m_addComponentPopup);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InspectorPanel::Render() {
|
2026-03-26 16:43:06 +08:00
|
|
|
UI::PanelWindowScope panel(m_name.c_str());
|
|
|
|
|
if (!panel.IsOpen()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-03-26 22:31:22 +08:00
|
|
|
|
|
|
|
|
Actions::ObserveInactiveActionRoute(*m_context);
|
2026-03-27 00:08:46 +08:00
|
|
|
|
2026-03-25 15:54:22 +08:00
|
|
|
if (m_selectedEntityId) {
|
2026-03-25 16:39:15 +08:00
|
|
|
auto& sceneManager = m_context->GetSceneManager();
|
|
|
|
|
auto* gameObject = sceneManager.GetEntity(m_selectedEntityId);
|
2026-03-25 15:54:22 +08:00
|
|
|
if (gameObject) {
|
|
|
|
|
RenderGameObject(gameObject);
|
|
|
|
|
} else {
|
2026-03-26 21:18:33 +08:00
|
|
|
RenderEmptyState("Object not found");
|
2026-03-25 15:54:22 +08:00
|
|
|
}
|
2026-03-20 17:08:06 +08:00
|
|
|
} else {
|
2026-03-26 21:18:33 +08:00
|
|
|
RenderEmptyState("No Selection", "Select an object in Hierarchy");
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameObject) {
|
2026-03-26 15:26:46 +08:00
|
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
2026-03-26 16:43:06 +08:00
|
|
|
UI::PanelContentScope content(
|
|
|
|
|
"InspectorContent",
|
|
|
|
|
UI::InspectorPanelContentPadding(),
|
|
|
|
|
ImGuiWindowFlags_None,
|
|
|
|
|
true,
|
|
|
|
|
ImVec2(style.ItemSpacing.x, 0.0f));
|
|
|
|
|
if (!content.IsOpen()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-03-26 15:26:46 +08:00
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
auto components = gameObject->GetComponents<::XCEngine::Components::Component>();
|
2026-03-24 20:02:38 +08:00
|
|
|
for (auto* component : components) {
|
2026-03-25 01:23:08 +08:00
|
|
|
RenderComponent(component, gameObject);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
2026-03-26 01:59:14 +08:00
|
|
|
|
2026-03-27 12:06:24 +08:00
|
|
|
Actions::DrawInspectorAddComponentButton(m_addComponentPopup, gameObject != nullptr);
|
|
|
|
|
Actions::DrawInspectorAddComponentPopup(*m_context, m_addComponentPopup, gameObject);
|
2026-03-26 15:26:46 +08:00
|
|
|
|
2026-03-27 12:06:24 +08:00
|
|
|
Actions::FinalizeInspectorInteractiveChangeIfIdle(*m_context);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void InspectorPanel::RenderEmptyState(const char* title, const char* subtitle) {
|
|
|
|
|
UI::PanelContentScope content("InspectorEmptyState", UI::InspectorPanelContentPadding());
|
|
|
|
|
if (!content.IsOpen()) {
|
2026-03-25 01:23:08 +08:00
|
|
|
return;
|
|
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
UI::DrawEmptyState(title, subtitle);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
void InspectorPanel::RenderComponent(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject) {
|
2026-03-20 17:08:06 +08:00
|
|
|
if (!component) return;
|
|
|
|
|
|
2026-03-26 02:24:11 +08:00
|
|
|
IComponentEditor* editor = ComponentEditorRegistry::Get().FindEditor(component);
|
2026-03-26 15:26:46 +08:00
|
|
|
const std::string name = component->GetName();
|
2026-03-26 21:18:33 +08:00
|
|
|
|
2026-03-27 00:08:46 +08:00
|
|
|
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);
|
|
|
|
|
});
|
2026-03-26 21:18:33 +08:00
|
|
|
|
2026-03-27 00:08:46 +08:00
|
|
|
if (removed) {
|
2026-03-25 01:23:08 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
if (section.open) {
|
2026-03-26 01:26:26 +08:00
|
|
|
if (editor) {
|
2026-03-26 01:59:14 +08:00
|
|
|
if (editor->Render(component, &m_context->GetUndoManager())) {
|
2026-03-26 01:26:26 +08:00
|
|
|
m_context->GetSceneManager().MarkSceneDirty();
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
} else {
|
2026-03-26 21:18:33 +08:00
|
|
|
UI::DrawHintText("No registered editor for this component");
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
UI::EndComponentSection();
|
2026-03-25 01:23:08 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 18:38:01 +08:00
|
|
|
}
|
2026-03-24 20:02:38 +08:00
|
|
|
}
|