From 21879c27844bb1ad0f2fca857ede85134047a870 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Sun, 12 Apr 2026 04:04:40 +0300 Subject: [PATCH] Groups and components --- .../components/CellGridEditorsModule.cpp | 28 ++++---- .../components/ProceduralMaterialModule.cpp | 4 +- .../components/ProceduralTextureModule.cpp | 4 +- .../editScene/systems/EditorUISystem.cpp | 40 ++++++++--- .../editScene/ui/ComponentRegistration.hpp | 14 ++++ .../editScene/ui/ComponentRegistry.hpp | 72 +++++++++++++++++-- 6 files changed, 126 insertions(+), 36 deletions(-) diff --git a/src/features/editScene/components/CellGridEditorsModule.cpp b/src/features/editScene/components/CellGridEditorsModule.cpp index 41da562..ff1d684 100644 --- a/src/features/editScene/components/CellGridEditorsModule.cpp +++ b/src/features/editScene/components/CellGridEditorsModule.cpp @@ -9,10 +9,10 @@ #include "../ui/FurnitureTemplateEditor.hpp" // Register CellGrid component -REGISTER_COMPONENT("Cell Grid", CellGridComponent, CellGridEditor) +REGISTER_COMPONENT_GROUP("Cell Grid", "Cell Grid", CellGridComponent, CellGridEditor) { registry.registerComponent( - "Cell Grid", + "Cell Grid", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { @@ -28,10 +28,10 @@ REGISTER_COMPONENT("Cell Grid", CellGridComponent, CellGridEditor) } // Register Lot component -REGISTER_COMPONENT("Lot", LotComponent, LotEditor) +REGISTER_COMPONENT_GROUP("Lot", "Cell Grid", LotComponent, LotEditor) { registry.registerComponent( - "Lot", + "Lot", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { @@ -47,10 +47,10 @@ REGISTER_COMPONENT("Lot", LotComponent, LotEditor) } // Register District component -REGISTER_COMPONENT("District", DistrictComponent, DistrictEditor) +REGISTER_COMPONENT_GROUP("District", "Cell Grid", DistrictComponent, DistrictEditor) { registry.registerComponent( - "District", + "District", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { @@ -66,10 +66,10 @@ REGISTER_COMPONENT("District", DistrictComponent, DistrictEditor) } // Register Town component -REGISTER_COMPONENT("Town", TownComponent, TownEditor) +REGISTER_COMPONENT_GROUP("Town", "Cell Grid", TownComponent, TownEditor) { registry.registerComponent( - "Town", + "Town", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { @@ -85,10 +85,10 @@ REGISTER_COMPONENT("Town", TownComponent, TownEditor) } // Register Roof component -REGISTER_COMPONENT("Roof", RoofComponent, RoofEditor) +REGISTER_COMPONENT_GROUP("Roof", "Cell Grid", RoofComponent, RoofEditor) { registry.registerComponent( - "Roof", + "Roof", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { @@ -104,10 +104,10 @@ REGISTER_COMPONENT("Roof", RoofComponent, RoofEditor) } // Register Room component -REGISTER_COMPONENT("Room", RoomComponent, RoomEditor) +REGISTER_COMPONENT_GROUP("Room", "Cell Grid", RoomComponent, RoomEditor) { registry.registerComponent( - "Room", + "Room", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { @@ -123,10 +123,10 @@ REGISTER_COMPONENT("Room", RoomComponent, RoomEditor) } // Register FurnitureTemplate component -REGISTER_COMPONENT("Furniture Template", FurnitureTemplateComponent, FurnitureTemplateEditor) +REGISTER_COMPONENT_GROUP("Furniture Template", "Cell Grid", FurnitureTemplateComponent, FurnitureTemplateEditor) { registry.registerComponent( - "Furniture Template", + "Furniture Template", "Cell Grid", std::make_unique(), [sceneMgr](flecs::entity e) { if (!e.has()) { diff --git a/src/features/editScene/components/ProceduralMaterialModule.cpp b/src/features/editScene/components/ProceduralMaterialModule.cpp index 27dd746..3e594f2 100644 --- a/src/features/editScene/components/ProceduralMaterialModule.cpp +++ b/src/features/editScene/components/ProceduralMaterialModule.cpp @@ -4,10 +4,10 @@ #include // Register ProceduralMaterial component -REGISTER_COMPONENT("Procedural Material", ProceduralMaterialComponent, ProceduralMaterialEditor) +REGISTER_COMPONENT_GROUP("Procedural Material", "Material", ProceduralMaterialComponent, ProceduralMaterialEditor) { registry.registerComponent( - "Procedural Material", + "Procedural Material", "Material", std::make_unique(sceneMgr), // Adder [sceneMgr](flecs::entity e) { diff --git a/src/features/editScene/components/ProceduralTextureModule.cpp b/src/features/editScene/components/ProceduralTextureModule.cpp index c553161..5e5d564 100644 --- a/src/features/editScene/components/ProceduralTextureModule.cpp +++ b/src/features/editScene/components/ProceduralTextureModule.cpp @@ -3,10 +3,10 @@ #include "../ui/ProceduralTextureEditor.hpp" // Register ProceduralTexture component -REGISTER_COMPONENT("Procedural Texture", ProceduralTextureComponent, ProceduralTextureEditor) +REGISTER_COMPONENT_GROUP("Procedural Texture", "Material", ProceduralTextureComponent, ProceduralTextureEditor) { registry.registerComponent( - "Procedural Texture", + "Procedural Texture", "Material", std::make_unique(), // Adder [sceneMgr](flecs::entity e) { diff --git a/src/features/editScene/systems/EditorUISystem.cpp b/src/features/editScene/systems/EditorUISystem.cpp index 0b1c33a..244006b 100644 --- a/src/features/editScene/systems/EditorUISystem.cpp +++ b/src/features/editScene/systems/EditorUISystem.cpp @@ -78,7 +78,7 @@ void EditorUISystem::registerComponentEditors() // Register Transform component auto transformEditor = std::make_unique(); m_componentRegistry.registerComponent( - "Transform", std::move(transformEditor), + "Transform", "Transform", std::move(transformEditor), // Adder [this](flecs::entity e) { if (!e.has()) { @@ -109,7 +109,7 @@ void EditorUISystem::registerComponentEditors() // Register Renderable component auto renderableEditor = std::make_unique(m_sceneMgr); m_componentRegistry.registerComponent( - "Renderable", std::move(renderableEditor), + "Renderable", "Rendering", std::move(renderableEditor), // Adder [this](flecs::entity e) { if (!e.has()) { @@ -133,7 +133,7 @@ void EditorUISystem::registerComponentEditors() // Register RigidBody component auto rigidBodyEditor = std::make_unique(); m_componentRegistry.registerComponent( - "Rigid Body", std::move(rigidBodyEditor), + "Rigid Body", "Physics", std::move(rigidBodyEditor), // Adder [this](flecs::entity e) { if (!e.has()) { @@ -150,7 +150,7 @@ void EditorUISystem::registerComponentEditors() // Register PhysicsCollider component auto colliderEditor = std::make_unique(m_sceneMgr); m_componentRegistry.registerComponent( - "Physics Collider", std::move(colliderEditor), + "Physics Collider", "Physics", std::move(colliderEditor), // Adder [this](flecs::entity e) { if (!e.has()) { @@ -679,16 +679,34 @@ void EditorUISystem::renderAddComponentMenu(flecs::entity entity) ImGui::Text("Add Component:"); ImGui::Separator(); - // Dynamically list all registered components that the entity doesn't have + // Group components by their group name + auto groups = m_componentRegistry.getGroups(); bool hasAny = false; - m_componentRegistry.forEach([&](const std::type_index& type, const ComponentRegistry::ComponentInfo& info) { - if (!m_componentRegistry.entityHasComponent(entity, type)) { - hasAny = true; - if (ImGui::MenuItem(info.name)) { - m_componentRegistry.addComponentByType(entity, type); + + for (const auto& group : groups) { + // Count components in this group that the entity doesn't have + int availableCount = 0; + m_componentRegistry.forEachInGroup(group.c_str(), [&](const std::type_index& type, const ComponentRegistry::ComponentInfo& info) { + if (!m_componentRegistry.entityHasComponent(entity, type)) { + availableCount++; } + }); + + if (availableCount == 0) continue; + hasAny = true; + + // Create a submenu for each group + if (ImGui::BeginMenu(group.c_str())) { + m_componentRegistry.forEachInGroup(group.c_str(), [&](const std::type_index& type, const ComponentRegistry::ComponentInfo& info) { + if (!m_componentRegistry.entityHasComponent(entity, type)) { + if (ImGui::MenuItem(info.name)) { + m_componentRegistry.addComponentByType(entity, type); + } + } + }); + ImGui::EndMenu(); } - }); + } if (!hasAny) { ImGui::TextDisabled("All components added"); diff --git a/src/features/editScene/ui/ComponentRegistration.hpp b/src/features/editScene/ui/ComponentRegistration.hpp index 2dcd6f9..09c047c 100644 --- a/src/features/editScene/ui/ComponentRegistration.hpp +++ b/src/features/editScene/ui/ComponentRegistration.hpp @@ -50,8 +50,22 @@ private: * [](flecs::entity e) { ... }, * [](flecs::entity e) { ... }); * } + * + * Or with a group: + * REGISTER_COMPONENT_GROUP("My Component", "Group Name", MyComponent, MyComponentEditor) + * { + * registry.registerComponent( + * name, group, std::make_unique(...), + * [](flecs::entity e) { ... }, + * [](flecs::entity e) { ... }); + * } */ #define REGISTER_COMPONENT(nameStr, ComponentType, EditorType) \ + REGISTER_COMPONENT_GROUP(nameStr, "Miscellaneous", ComponentType, EditorType) + +#define REGISTER_COMPONENT_GROUP(nameStr, groupStr, ComponentType, EditorType) \ + static const char* ComponentType##_name = nameStr; \ + static const char* ComponentType##_group = groupStr; \ static void register_##ComponentType(ComponentRegistry& registry, \ Ogre::SceneManager* sceneMgr, \ EditorPhysicsSystem* physics); \ diff --git a/src/features/editScene/ui/ComponentRegistry.hpp b/src/features/editScene/ui/ComponentRegistry.hpp index a6692a2..36cbf2c 100644 --- a/src/features/editScene/ui/ComponentRegistry.hpp +++ b/src/features/editScene/ui/ComponentRegistry.hpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include "ComponentEditor.hpp" @@ -31,6 +33,7 @@ class ComponentRegistry { public: struct ComponentInfo { const char *name; + const char *group; // Group name for menu organization (nullptr = "Miscellaneous") std::unique_ptr editor; ComponentAdder adder; ComponentRemover remover; @@ -50,19 +53,36 @@ public: /** * Register a component type with its editor and add/remove functions + * @param name Display name for the component + * @param group Group name for menu organization (nullptr for "Miscellaneous") + * @param editor The editor for this component + * @param adder Function to add the component to an entity + * @param remover Function to remove the component from an entity + */ + template + void registerComponent(const char *name, const char *group, + std::unique_ptr> editor, + ComponentAdder adder, ComponentRemover remover) + { + ComponentInfo info; + info.name = name; + info.group = group ? group : "Miscellaneous"; + info.editor = std::move(editor); + info.adder = adder; + info.remover = remover; + info.checker = [](flecs::entity e) { return e.has(); }; + m_components[std::type_index(typeid(T))] = std::move(info); + } + + /** + * Backward-compatible overload (defaults to "Miscellaneous" group) */ template void registerComponent(const char *name, std::unique_ptr> editor, ComponentAdder adder, ComponentRemover remover) { - ComponentInfo info; - info.name = name; - info.editor = std::move(editor); - info.adder = adder; - info.remover = remover; - info.checker = [](flecs::entity e) { return e.has(); }; - m_components[std::type_index(typeid(T))] = std::move(info); + registerComponent(name, nullptr, std::move(editor), adder, remover); } /** @@ -185,6 +205,44 @@ public: * Get the number of registered components */ size_t getComponentCount() const { return m_components.size(); } + + /** + * Get all unique group names + */ + std::vector getGroups() const { + std::set groups; + for (const auto& pair : m_components) { + groups.insert(pair.second.group); + } + return std::vector(groups.begin(), groups.end()); + } + + /** + * Get all component types in a specific group + */ + std::vector getComponentsInGroup(const char* group) const { + std::vector types; + const char* groupName = group ? group : "Miscellaneous"; + for (const auto& pair : m_components) { + if (std::string(pair.second.group) == groupName) { + types.push_back(pair.first); + } + } + return types; + } + + /** + * Iterate over all registered components in a specific group + */ + template + void forEachInGroup(const char* group, Func&& func) const { + const char* groupName = group ? group : "Miscellaneous"; + for (const auto& pair : m_components) { + if (std::string(pair.second.group) == groupName) { + func(pair.first, pair.second); + } + } + } private: std::unordered_map m_components;