Files
XCEngine/editor/src/panels/InspectorPanel.cpp

171 lines
5.2 KiB
C++
Raw Normal View History

2026-03-26 21:18:33 +08:00
#include "Actions/EditorActions.h"
#include "Commands/ComponentCommands.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"
2026-03-26 21:18:33 +08:00
#include "UI/UI.h"
#include <imgui.h>
#include <string>
namespace XCEngine {
namespace Editor {
InspectorPanel::InspectorPanel() : Panel("Inspector") {}
InspectorPanel::~InspectorPanel() {
if (m_context) {
m_context->GetEventBus().Unsubscribe<SelectionChangedEvent>(m_selectionHandlerId);
}
}
void InspectorPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
if (m_context && m_context->GetUndoManager().HasPendingInteractiveChange()) {
m_context->GetUndoManager().FinalizeInteractiveChange();
}
m_selectedEntityId = event.primarySelection;
2026-03-26 21:30:46 +08:00
m_addComponentPopup.Clear();
}
void InspectorPanel::Render() {
UI::PanelWindowScope panel(m_name.c_str());
if (!panel.IsOpen()) {
return;
}
if (!m_selectionHandlerId && m_context) {
m_selectionHandlerId = m_context->GetEventBus().Subscribe<SelectionChangedEvent>(
[this](const SelectionChangedEvent& event) {
OnSelectionChanged(event);
}
);
}
m_selectedEntityId = m_context->GetSelectionManager().GetSelectedEntity();
if (m_selectedEntityId) {
auto& sceneManager = m_context->GetSceneManager();
auto* gameObject = sceneManager.GetEntity(m_selectedEntityId);
if (gameObject) {
RenderGameObject(gameObject);
} else {
2026-03-26 21:18:33 +08:00
RenderEmptyState("Object not found");
}
} else {
2026-03-26 21:18:33 +08:00
RenderEmptyState("No Selection", "Select an object in Hierarchy");
}
}
void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameObject) {
ImGuiStyle& style = ImGui::GetStyle();
UI::PanelContentScope content(
"InspectorContent",
UI::InspectorPanelContentPadding(),
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);
}
2026-03-26 21:18:33 +08:00
if (Actions::DrawInspectorAction(Actions::MakeAddComponentButtonAction(gameObject != nullptr))) {
2026-03-26 21:30:46 +08:00
m_addComponentPopup.RequestOpen();
}
RenderAddComponentPopup(gameObject);
if (m_context->GetUndoManager().HasPendingInteractiveChange() && !ImGui::IsAnyItemActive()) {
m_context->GetUndoManager().FinalizeInteractiveChange();
}
}
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()) {
return;
}
2026-03-26 21:18:33 +08:00
UI::DrawEmptyState(title, subtitle);
}
void InspectorPanel::RenderAddComponentPopup(::XCEngine::Components::GameObject* gameObject) {
2026-03-26 21:30:46 +08:00
m_addComponentPopup.ConsumeOpenRequest("AddComponent");
2026-03-26 21:18:33 +08:00
if (!UI::BeginTitledPopup("AddComponent", "Components")) {
return;
}
bool drewAnyEntry = false;
for (const auto& editor : ComponentEditorRegistry::Get().GetEditors()) {
if (!editor || !editor->ShowInAddComponentMenu()) {
continue;
}
drewAnyEntry = true;
2026-03-26 21:18:33 +08:00
const bool canAdd = Commands::CanAddComponent(*editor, gameObject);
std::string label = editor->GetDisplayName();
if (!canAdd) {
const char* reason = editor->GetAddDisabledReason(gameObject);
if (reason && reason[0] != '\0') {
label += " (";
label += reason;
label += ")";
}
}
2026-03-26 21:18:33 +08:00
Actions::DrawMenuAction(Actions::MakeAddComponentMenuAction(label, canAdd), [&]() {
if (Commands::AddComponent(*m_context, *editor, gameObject)) {
ImGui::CloseCurrentPopup();
}
2026-03-26 21:18:33 +08:00
});
}
if (!drewAnyEntry) {
2026-03-26 21:18:33 +08:00
UI::DrawHintText("No registered component editors");
}
2026-03-26 21:18:33 +08:00
UI::EndTitledPopup();
}
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();
2026-03-26 21:18:33 +08:00
const UI::ComponentSectionResult section =
UI::BeginComponentSection(
(void*)typeid(*component).hash_code(),
name.c_str(),
Commands::CanRemoveComponent(component, editor));
if (section.removeRequested) {
Commands::RemoveComponent(*m_context, component, gameObject, editor);
return;
}
2026-03-26 21:18:33 +08:00
if (section.open) {
if (editor) {
if (editor->Render(component, &m_context->GetUndoManager())) {
m_context->GetSceneManager().MarkSceneDirty();
}
} else {
2026-03-26 21:18:33 +08:00
UI::DrawHintText("No registered editor for this component");
}
2026-03-26 21:18:33 +08:00
UI::EndComponentSection();
}
}
}
}