diff --git a/src/entities/EntitiesManager.cpp b/src/entities/EntitiesManager.cpp index e8271843..c13abace 100644 --- a/src/entities/EntitiesManager.cpp +++ b/src/entities/EntitiesManager.cpp @@ -180,7 +180,7 @@ Entity* EntitiesManager::CreateEntity(const QString& type, WorkSpace* workspace) return entity; } -Entity* EntitiesManager::CreateEntityWithComponents(const QString& type, WorkSpace* workspace) { +Entity* EntitiesManager::CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace) { if (!initialized_) { Initialize(); } @@ -189,7 +189,7 @@ Entity* EntitiesManager::CreateEntityWithComponents(const QString& type, WorkSpa workspace = WorkSpaceManager::Get().GetCurrent(); } - Entity* entity = EntityFactory::Get().CreateEntityWithComponents(type, workspace); + Entity* entity = EntityFactory::Get().CreateEntityWithComponents(type, mesh, useLabel, workspace); if (entity) { AddEntity(entity); if (workspace) { diff --git a/src/entities/EntitiesManager.h b/src/entities/EntitiesManager.h index ad2b43d5..5d223127 100644 --- a/src/entities/EntitiesManager.h +++ b/src/entities/EntitiesManager.h @@ -32,7 +32,7 @@ public: // New factory methods Entity* CreateEntity(const QString& type, WorkSpace* workspace = nullptr); - Entity* CreateEntityWithComponents(const QString& type, WorkSpace* workspace = nullptr); + Entity* CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace = nullptr); // Get supported entity types QStringList GetSupportedEntityTypes() const; diff --git a/src/entities/EntityFactory.cpp b/src/entities/EntityFactory.cpp index 3107dfd4..9a46e28a 100644 --- a/src/entities/EntityFactory.cpp +++ b/src/entities/EntityFactory.cpp @@ -23,7 +23,7 @@ Entity* EntityFactory::CreateEntity(const QString& type, WorkSpace* workspace) { return entity; } -Entity* EntityFactory::CreateEntityWithComponents(const QString& type, WorkSpace* workspace) { +Entity* EntityFactory::CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace) { Entity* entity = CreateEntity(type, workspace); if (!entity) { return nullptr; @@ -36,15 +36,36 @@ Entity* EntityFactory::CreateEntityWithComponents(const QString& type, WorkSpace // Get default mesh QString defaultMesh = it->second->GetDefaultMesh(); + if (!mesh.isEmpty()) { + defaultMesh = mesh; + } if (!defaultMesh.isEmpty()) { SceneComponent* meshComponent = ComponentFactory::Create("MeshComponent", nullptr); if (meshComponent) { - meshComponent->SetAttribute("mesh", defaultMesh.toStdString().c_str()); + meshComponent->SetAttribute("mesh", defaultMesh.toLocal8Bit()); meshComponent->AttachEntity(entity); LOG_INFO("EntityFactory::CreateEntityWithComponents - Added MeshComponent with mesh: {}", defaultMesh.toStdString()); } } + if (useLabel) { + SceneComponent* rootComponent = entity->GetRootComponent(); + if (nullptr == rootComponent) { + SceneComponent* meshComponent = ComponentFactory::Create("LabelComponent", nullptr); + if (meshComponent) { + meshComponent->AttachEntity(entity); + LOG_INFO("EntityFactory::CreateEntityWithComponents - Added LabelComponent with mesh: {}", defaultMesh.toStdString()); + } + } + else { + SceneComponent* LabelComponent = ComponentFactory::Create("LabelComponent", rootComponent); + if (LabelComponent) { + LabelComponent->AttachTo(rootComponent); + LOG_INFO("EntityFactory::CreateEntityWithComponents - Added LabelComponent with mesh: {}", defaultMesh.toStdString()); + } + } + } + // Add required components QStringList requiredComponents = it->second->GetRequiredComponents(); SceneComponent* rootComponent = entity->GetRootComponent(); diff --git a/src/entities/EntityFactory.h b/src/entities/EntityFactory.h index 7a40e94f..33e02898 100644 --- a/src/entities/EntityFactory.h +++ b/src/entities/EntityFactory.h @@ -66,7 +66,7 @@ public: Entity* CreateEntity(const QString& type, WorkSpace* workspace); - Entity* CreateEntityWithComponents(const QString& type, WorkSpace* workspace); + Entity* CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace); QStringList GetRegisteredTypes() const; diff --git a/src/translations/Dyt_zh_CN.ts b/src/translations/Dyt_zh_CN.ts index 9a5fbf47..bb0a14dd 100644 --- a/src/translations/Dyt_zh_CN.ts +++ b/src/translations/Dyt_zh_CN.ts @@ -2082,12 +2082,12 @@ OsgWidget - + warning - + open dyt file failed @@ -2188,26 +2188,6 @@ Preset Models - - - Ships - - - - - Satellites - - - - - Missiles - - - - - Jammers - - PropertyBrowser diff --git a/src/ui/ModelBrowser/PresetModelListWidget.cpp b/src/ui/ModelBrowser/PresetModelListWidget.cpp index c0cabf0b..c79632ca 100644 --- a/src/ui/ModelBrowser/PresetModelListWidget.cpp +++ b/src/ui/ModelBrowser/PresetModelListWidget.cpp @@ -131,6 +131,8 @@ void PresetModelListWidget::setModelList(const QVector& models) { painter.drawText(pixmap.rect(), Qt::AlignCenter, "?"); item->setIcon(QIcon(pixmap)); } + + item->setToolTip(modelInfo.description.isEmpty() ? modelInfo.name : modelInfo.description); // Store model name as simple string item->setData(Qt::UserRole, modelInfo.name); diff --git a/src/ui/ModelBrowser/PresetModelListWidget.h b/src/ui/ModelBrowser/PresetModelListWidget.h index 65c46e78..96d30d32 100644 --- a/src/ui/ModelBrowser/PresetModelListWidget.h +++ b/src/ui/ModelBrowser/PresetModelListWidget.h @@ -1,3 +1,5 @@ +#pragma once + #include #include diff --git a/src/ui/ModelBrowser/PresetModelPanel.cpp b/src/ui/ModelBrowser/PresetModelPanel.cpp index c9f7cccf..2fd26676 100644 --- a/src/ui/ModelBrowser/PresetModelPanel.cpp +++ b/src/ui/ModelBrowser/PresetModelPanel.cpp @@ -14,11 +14,13 @@ #include #include #include +#include #include "common/RecourceHelper.h" #include "common/SpdLogger.h" #include "ui/DockTitleBar.h" #include "ui/DockWidget.h" +#include "workspace/PresetModelConfigParser.h" #include "ui_PresetModelPanel.h" @@ -34,6 +36,7 @@ PresetModelPanel::PresetModelPanel(QWidget *parent) PresetModelPanel::~PresetModelPanel() { + ClearDynamicUI(); delete ui; } @@ -57,80 +60,97 @@ void PresetModelPanel::InitUI() QString presetsPath = QString("%1/presets").arg(RecourceHelper::Get().GetResourcesPath()); if (PresetModelConfigParser::Get().LoadAllConfigs(presetsPath)) { // Successfully loaded from configuration files + CreateDynamicUI(); LoadModelsFromConfig(); } else { // Failed to load configuration files, use hardcoded defaults as fallback LOG_WARN("Failed to load preset models from config files, using hardcoded defaults. Error: {}", PresetModelConfigParser::Get().GetLastError().toStdString()); - LoadDefaultModels(); + } +} + +void PresetModelPanel::CreateDynamicUI() +{ + // Clear any existing dynamic UI + ClearDynamicUI(); + + // Get all category names from configuration + QStringList categoryNames = PresetModelConfigParser::Get().GetCategoryNames(); + + if (categoryNames.isEmpty()) { + LOG_WARN("No categories found in configuration"); + return; + } + + // Create UI for each category + for (const QString& categoryName : categoryNames) { + ModelCategory category = PresetModelConfigParser::Get().GetCategory(categoryName); + + // Create page widget + QWidget* page = new QWidget(); + page->setObjectName(QString("%1Page").arg(categoryName.toLower())); + + // Create layout for the page + QVBoxLayout* layout = new QVBoxLayout(page); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + + // Create list widget + PresetModelListWidget* listWidget = new PresetModelListWidget(page); + listWidget->setObjectName(QString("%1List").arg(categoryName.toLower())); + listWidget->setDragDropMode(QAbstractItemView::DragOnly); + listWidget->setDefaultDropAction(Qt::CopyAction); + + // Add list widget to layout + layout->addWidget(listWidget); + + // Add page to toolbox with display name + QString displayName = category.displayName.isEmpty() ? categoryName : category.displayName; + ui->PresetModelToolBox->addItem(page, displayName); + + // Store references for later use + categoryWidgets_[categoryName] = listWidget; + categoryPages_[categoryName] = page; + + LOG_INFO("Created dynamic UI for category: {}", categoryName.toStdString()); + } + + // Set first page as current if available + if (ui->PresetModelToolBox->count() > 0) { + ui->PresetModelToolBox->setCurrentIndex(0); } } void PresetModelPanel::LoadModelsFromConfig() { - // Load ship models - ModelCategory shipCategory = PresetModelConfigParser::Get().GetCategory("Ship"); - if (!shipCategory.models.isEmpty()) { - ui->shipList->setModelType("Ship"); - ui->shipList->setModelList(shipCategory.models); - } + // Load models for each dynamically created category + QStringList categoryNames = PresetModelConfigParser::Get().GetCategoryNames(); - // Load satellite models - ModelCategory satelliteCategory = PresetModelConfigParser::Get().GetCategory("Satellite"); - if (!satelliteCategory.models.isEmpty()) { - ui->satelliteList->setModelType("Satellite"); - ui->satelliteList->setModelList(satelliteCategory.models); - } - - // Load missile models - ModelCategory missileCategory = PresetModelConfigParser::Get().GetCategory("Missile"); - if (!missileCategory.models.isEmpty()) { - ui->missileList->setModelType("Missile"); - ui->missileList->setModelList(missileCategory.models); - } - - // Load jammer models - ModelCategory jammerCategory = PresetModelConfigParser::Get().GetCategory("Jammer"); - if (!jammerCategory.models.isEmpty()) { - ui->jammerList->setModelType("Jammer"); - ui->jammerList->setModelList(jammerCategory.models); + for (const QString& categoryName : categoryNames) { + ModelCategory category = PresetModelConfigParser::Get().GetCategory(categoryName); + + if (!category.models.isEmpty() && categoryWidgets_.contains(categoryName)) { + PresetModelListWidget* listWidget = categoryWidgets_[categoryName]; + listWidget->setModelType(categoryName); + listWidget->setModelList(category.models); + + LOG_INFO("Loaded {} models for category: {}", + category.models.size(), categoryName.toStdString()); + } } } -void PresetModelPanel::LoadDefaultModels() { - // Use hardcoded default models as fallback mechanism - QVector shipModels = { - {"destroyer", "Destroyer", "Naval destroyer vessel", "", ":/icons/ship.png", true}, - {"aircraft_carrier", "Aircraft Carrier", "Large naval vessel", "", ":/icons/ship.png", true}, - {"frigate", "Frigate", "Fast naval vessel", "", ":/icons/ship.png", true}, - {"submarine", "Submarine", "Underwater vessel", "", ":/icons/ship.png", true} - }; - ui->shipList->setModelType("Ship"); - ui->shipList->setModelList(shipModels); +void PresetModelPanel::ClearDynamicUI() +{ + // Clear all dynamic UI elements + categoryWidgets_.clear(); + categoryPages_.clear(); - QVector satelliteModels = { - {"comm_satellite", "Communication Satellite", "Communication satellite", "", ":/icons/satellite.png", true}, - {"weather_satellite", "Weather Satellite", "Weather monitoring satellite", "", ":/icons/satellite.png", true}, - {"gps_satellite", "GPS Satellite", "GPS navigation satellite", "", ":/icons/satellite.png", true}, - {"spy_satellite", "Spy Satellite", "Reconnaissance satellite", "", ":/icons/satellite.png", true} - }; - ui->satelliteList->setModelType("Satellite"); - ui->satelliteList->setModelList(satelliteModels); - - QVector missileModels = { - {"cruise_missile", "Cruise Missile", "Long-range cruise missile", "", ":/icons/missile.png", true}, - {"ballistic_missile", "Ballistic Missile", "Ballistic missile", "", ":/icons/missile.png", true}, - {"anti_ship_missile", "Anti-Ship Missile", "Anti-ship missile", "", ":/icons/missile.png", true}, - {"sam_missile", "Surface-to-Air Missile", "Surface-to-air missile", "", ":/icons/missile.png", true} - }; - ui->missileList->setModelType("Missile"); - ui->missileList->setModelList(missileModels); - - QVector jammerModels = { - {"electronic_jammer", "Electronic Jammer", "Electronic warfare jammer", "", ":/icons/jammer.png", true}, - {"comm_jammer", "Communication Jammer", "Communication jammer", "", ":/icons/jammer.png", true}, - {"radar_jammer", "Radar Jammer", "Radar jamming device", "", ":/icons/jammer.png", true}, - {"gps_jammer", "GPS Jammer", "GPS jamming device", "", ":/icons/jammer.png", true} - }; - ui->jammerList->setModelType("Jammer"); - ui->jammerList->setModelList(jammerModels); + // Remove all pages from toolbox + while (ui->PresetModelToolBox->count() > 0) { + QWidget* widget = ui->PresetModelToolBox->widget(0); + ui->PresetModelToolBox->removeItem(0); + if (widget) { + widget->deleteLater(); + } + } } diff --git a/src/ui/ModelBrowser/PresetModelPanel.h b/src/ui/ModelBrowser/PresetModelPanel.h index 6d220217..bd0e24d5 100644 --- a/src/ui/ModelBrowser/PresetModelPanel.h +++ b/src/ui/ModelBrowser/PresetModelPanel.h @@ -14,9 +14,10 @@ #include #include #include +#include #include "workspace/ModelInfo.h" -#include "workspace/PresetModelConfigParser.h" +#include "ui/ModelBrowser/PresetModelListWidget.h" namespace Ui { class PresetModelPanel; } @@ -26,11 +27,8 @@ class DockWidget; /** * @brief Preset model panel class * - * Provides preset 3D models for users to drag into the 3D scene, including: - * - Ships: Destroyer, Aircraft Carrier - * - Satellites: Geostationary Satellites - * - Missiles: Hypersonic Missiles - * - Jammers: Passive Jammers, Active Jammers + * Provides preset 3D models for users to drag into the 3D scene. + * Dynamically creates UI based on configuration files, supporting any number of categories. */ class PresetModelPanel : public QWidget { Q_OBJECT @@ -51,19 +49,28 @@ private: */ void InitUI(); + /** + * @brief Create dynamic UI based on configuration + */ + void CreateDynamicUI(); + /** * @brief Load models from configuration file */ void LoadModelsFromConfig(); /** - * @brief Load default models when config is unavailable + * @brief Clear all dynamic UI elements */ - void LoadDefaultModels(); + void ClearDynamicUI(); private: Ui::PresetModelPanel *ui; + // Dynamic UI management + QMap categoryWidgets_; + QMap categoryPages_; + // Drag and drop support QPoint dragStartPosition_; QListWidget* dragSourceWidget_; diff --git a/src/ui/ModelBrowser/PresetModelPanel.ui b/src/ui/ModelBrowser/PresetModelPanel.ui index 60d64214..8206ddf1 100644 --- a/src/ui/ModelBrowser/PresetModelPanel.ui +++ b/src/ui/ModelBrowser/PresetModelPanel.ui @@ -32,168 +32,8 @@ - 0 + -1 - - - - 0 - 0 - 290 - 470 - - - - Ships - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::DragOnly - - - Qt::CopyAction - - - - - - - - - 0 - 0 - 290 - 470 - - - - Satellites - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::DragOnly - - - Qt::CopyAction - - - - - - - - - 0 - 0 - 98 - 73 - - - - Missiles - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::DragOnly - - - Qt::CopyAction - - - - - - - - - 0 - 0 - 98 - 73 - - - - Jammers - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::DragOnly - - - Qt::CopyAction - - - - - diff --git a/src/viewer/OsgWidget.cpp b/src/viewer/OsgWidget.cpp index 0a28707a..43f540c5 100644 --- a/src/viewer/OsgWidget.cpp +++ b/src/viewer/OsgWidget.cpp @@ -28,6 +28,7 @@ #include "workspace/PresetModelConfigParser.h" #include "entities/EntitiesManager.h" +#include "entities/EntityFactory.h" #include "entities/ComponentFactory.h" #include "entities/Entity.h" #include "entities/Component.h" @@ -271,7 +272,14 @@ void OsgWidget::OnPresetModelDropped(const QString& modelType, const QString& mo height = 0.0; } - Entity* entity = EntitiesManager::Get().CreateEntityWithComponents(modelType, currentWorkSpace); + bool success = false; + ModelInfo modelInfo = PresetModelConfigParser::Get().GetModelInfo(modelType, modelName, &success); + if (!success) { + LOG_ERROR("OsgWidget::OnPresetModelDropped - Failed to get model info of type:{} name:{}", modelType.toStdString(), modelName.toStdString()); + return; + } + + Entity* entity = EntitiesManager::Get().CreateEntityWithComponents(modelType, modelInfo.meshFile, modelInfo.useLabel, currentWorkSpace); if (nullptr == entity) { LOG_ERROR("OsgWidget::OnPresetModelDropped - Failed to create entity of type: {}", modelType.toStdString()); return; diff --git a/src/viewer/OsgWidget.h b/src/viewer/OsgWidget.h index e8cfc972..bb973ae4 100644 --- a/src/viewer/OsgWidget.h +++ b/src/viewer/OsgWidget.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include diff --git a/src/workspace/ModelInfo.h b/src/workspace/ModelInfo.h index e6582e44..bf8ea4b8 100644 --- a/src/workspace/ModelInfo.h +++ b/src/workspace/ModelInfo.h @@ -7,7 +7,7 @@ * @brief Model information structure * * Contains all information for a single preset model, including name, display name, - * description, mesh file path, icon path, and enabled status. + * description, mesh file path, icon path, enabled status, and entity registration info. */ struct ModelInfo { QString name; ///< Model name (unique identifier) @@ -15,21 +15,24 @@ struct ModelInfo { QString description; ///< Model description QString meshFile; ///< 3D mesh file path QString icon; ///< Icon file path + bool useLabel; bool enabled; ///< Whether this model is enabled /** * @brief Default constructor * Model is enabled by default */ - ModelInfo() : enabled(true) {} + ModelInfo() : useLabel(true), enabled(true) {} /** * @brief Constructor with parameters */ ModelInfo(const QString& name, const QString& displayName, const QString& description, - const QString& meshFile, const QString& icon, bool enabled = true) + const QString& meshFile, const QString& icon, bool enabled = true, + const QString& entityType = "", const QString& entityClass = "", + const QStringList& requiredComponents = QStringList()) : name(name), displayName(displayName), description(description), - meshFile(meshFile), icon(icon), enabled(enabled) {} + meshFile(meshFile), icon(icon), useLabel(true), enabled(enabled) {} }; /** diff --git a/src/workspace/PresetModelConfigParser.cpp b/src/workspace/PresetModelConfigParser.cpp index c0fd4428..67f27ac0 100644 --- a/src/workspace/PresetModelConfigParser.cpp +++ b/src/workspace/PresetModelConfigParser.cpp @@ -105,8 +105,14 @@ bool PresetModelConfigParser::ParseXmlFile(const QString& filePath) const char* description = modelElement->Attribute("description"); const char* meshFile = modelElement->Attribute("meshFile"); const char* modelIcon = modelElement->Attribute("icon"); + const char* label = modelElement->Attribute("label"); const char* enabled = modelElement->Attribute("enabled"); + // Entity registration attributes + const char* entityType = modelElement->Attribute("entityType"); + const char* entityClass = modelElement->Attribute("entityClass"); + const char* requiredComponents = modelElement->Attribute("requiredComponents"); + if (!modelName) { LOG_WARN("Model element missing name attribute in file: {}", filePath.toStdString()); modelElement = modelElement->NextSiblingElement("model"); @@ -118,6 +124,7 @@ bool PresetModelConfigParser::ParseXmlFile(const QString& filePath) model.description = description ? QString::fromUtf8(description) : ""; model.meshFile = meshFile ? QString::fromUtf8(meshFile) : ""; model.icon = modelIcon ? QString::fromUtf8(modelIcon) : ""; + model.useLabel = label ? (strcmp(label, "true") == 0) : true; model.enabled = enabled ? (strcmp(enabled, "true") == 0) : true; category.models.append(model); diff --git a/workspace/presets/jammers.xml b/workspace/presets/jammers.xml index 9941ef0c..1e3ca715 100644 --- a/workspace/presets/jammers.xml +++ b/workspace/presets/jammers.xml @@ -9,5 +9,5 @@ description="Multi-frequency signal jamming equipment" meshFile="models/signal_jammer.ive" icon="icons/signal_jammer_icon.png" - enabled="true" /> + enabled="true"/> \ No newline at end of file diff --git a/workspace/presets/ships.xml b/workspace/presets/ships.xml index 8979bbbb..7acee27e 100644 --- a/workspace/presets/ships.xml +++ b/workspace/presets/ships.xml @@ -4,10 +4,10 @@ description="High-speed combat vessel with powerful anti-submarine and air defense capabilities" meshFile="models/destroyer.ive" icon="icons/destroyer_icon.png" - enabled="true" /> + enabled="true"/> + enabled="true"/> \ No newline at end of file