feat: add "Add component" button

This commit is contained in:
2026-08-12 01:18:47 +02:00
parent 8c7302de49
commit c3c1d5ae28
5 changed files with 146 additions and 59 deletions
@@ -1,18 +1,6 @@
// destrum/Serialization/ComponentRegistry.cpp
#include <destrum/Serialization/ComponentRegistry.h>
#include <destrum/Serialization/ComponentFactory.h>
#include <destrum/Components/MeshRendererComponent.h>
#include <destrum/Components/Rotator.h>
#include <destrum/Components/Spinner.h>
#include <destrum/Components/OrbitAndSpin.h>
#include <destrum/Components/Animator.h>
#include <destrum/Components/Physics/Rigidbody.h>
#include <destrum/Components/Physics/BoxCollider.h>
#include <destrum/Components/Physics/CapsuleCollider.h>
#include <destrum/Components/Physics/SphereCollider.h>
#include <destrum/Serialization/EngineComponentList.h>
void RegisterEngineComponents()
{
@@ -23,47 +11,8 @@ void RegisterEngineComponents()
registered = true;
ComponentFactory::Register("MeshRendererComponent", [](GameObject& owner) {
return owner.AddComponent<MeshRendererComponent>();
});
// Keep the old serialized spelling readable while writing the canonical
// component name returned by MeshRendererComponent.
ComponentFactory::Register("MeshRenderer", [](GameObject& owner) {
return owner.AddComponent<MeshRendererComponent>();
});
ComponentFactory::Register("Rotator", [](GameObject& owner) {
return owner.AddComponent<Rotator>();
});
ComponentFactory::Register("Spinner", [](GameObject& owner) {
return owner.AddComponent<Spinner>();
});
ComponentFactory::Register("OrbitAndSpin", [](GameObject& owner) {
return owner.AddComponent<OrbitAndSpin>();
});
ComponentFactory::Register("Animator", [](GameObject& owner) {
return owner.AddComponent<Animator>();
});
ComponentFactory::Register("Rigidbody", [](GameObject& owner) {
return owner.AddComponent<Rigidbody>();
});
ComponentFactory::Register("RigidBody", [](GameObject& owner) {
return owner.AddComponent<Rigidbody>();
});
ComponentFactory::Register("BoxCollider", [](GameObject& owner) {
return owner.AddComponent<BoxCollider>();
});
ComponentFactory::Register("SphereCollider", [](GameObject& owner) {
return owner.AddComponent<SphereCollider>();
});
ComponentFactory::Register("CapsuleCollider", [](GameObject& owner) {
return owner.AddComponent<CapsuleCollider>();
});
#define DESTRUM_REGISTER_COMPONENT(ComponentType) \
ComponentFactory::Register<ComponentType>(#ComponentType);
DESTRUM_ENGINE_COMPONENTS(DESTRUM_REGISTER_COMPONENT)
#undef DESTRUM_REGISTER_COMPONENT
}
+68 -3
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include <cfloat>
#include <exception>
#include <string>
#include <unordered_set>
#include <vector>
@@ -14,6 +15,8 @@
#include <destrum/ObjectModel/Component.h>
#include <destrum/ObjectModel/GameObject.h>
#include <destrum/ObjectModel/Transform.h>
#include <destrum/Serialization/ComponentFactory.h>
#include <destrum/Serialization/ComponentRegistry.h>
namespace {
[[nodiscard]] bool IsInspectableObject(const GameObject* object) {
@@ -121,6 +124,8 @@ namespace ImGuiUtils {
const std::vector<std::shared_ptr<GameObject>>& objectsSource,
const std::vector<std::shared_ptr<GameObject>>& pendingAdditions,
ObjectId& selectedObjectId) {
RegisterEngineComponents();
std::vector<GameObject*> objects;
objects.reserve(objectsSource.size() + pendingAdditions.size());
@@ -268,9 +273,69 @@ namespace ImGuiUtils {
worldPosition.z);
}
if (ImGui::CollapsingHeader(
"Components",
ImGuiTreeNodeFlags_DefaultOpen)) {
const bool componentsOpen = ImGui::CollapsingHeader(
"Components",
ImGuiTreeNodeFlags_DefaultOpen);
if (componentsOpen) {
if (ImGui::Button("+ Add Component")) {
ImGui::OpenPopup("AddComponentPopup");
}
std::string addComponentError;
if (ImGui::BeginPopup("AddComponentPopup")) {
std::vector<std::string> componentTypes =
ComponentFactory::GetRegisteredTypeNames();
std::sort(componentTypes.begin(), componentTypes.end());
bool hasAvailableComponent = false;
for (const std::string& componentType : componentTypes) {
const bool alreadyAdded = std::any_of(
selectedObject->GetComponents().begin(),
selectedObject->GetComponents().end(),
[&componentType](const auto& component) {
return component != nullptr &&
!component->IsBeingDestroyed() &&
component->GetTypeName() == componentType;
});
if (alreadyAdded) {
const std::string label =
componentType + " (already added)";
ImGui::BeginDisabled();
ImGui::MenuItem(label.c_str());
ImGui::EndDisabled();
continue;
}
hasAvailableComponent = true;
if (ImGui::MenuItem(componentType.c_str())) {
try {
if (ComponentFactory::Create(
componentType,
*selectedObject) == nullptr) {
addComponentError =
"Component type is not registered: " +
componentType;
} else {
ImGui::CloseCurrentPopup();
}
} catch (const std::exception& exception) {
addComponentError = exception.what();
}
}
}
if (!hasAvailableComponent) {
ImGui::TextDisabled("All components are already added.");
}
if (!addComponentError.empty()) {
ImGui::TextWrapped("Failed to add component: %s",
addComponentError.c_str());
}
ImGui::EndPopup();
}
bool hasComponents = false;
for (const auto& component : selectedObject->GetComponents()) {
if (component == nullptr || component->IsBeingDestroyed()) {