diff --git a/src/translations/Dyt_zh_CN.ts b/src/translations/Dyt_zh_CN.ts index 10c08122..021ac0f5 100644 --- a/src/translations/Dyt_zh_CN.ts +++ b/src/translations/Dyt_zh_CN.ts @@ -573,22 +573,22 @@ AddParamSetting - + ParamSetting - + param - + input param descript - + input value @@ -641,17 +641,17 @@ - + 添加 - + 删除 - + 应用 @@ -1589,135 +1589,25 @@ - + model elements - + + preset models + + + + attribte - + Main View - - - Wave Curve - - - - - Speed Curve - - - - - 3D Curve - - - - - Target number - - - - - Signal-to-noise ratio - - - - - Azimuth line of sight - - - - - Pitch gaze angle - - - - - azimuth - - - - - Pitch angle - - - - - attribute - - - - - Doppler - - - - - course - - - - - Speed - - - - - longitude - - - - - latitude - - - - - distance - - - - - velocity - - - - - Radial dimensions - - - - - Target RCS - - - - - Report Table - - - - - Signal Indicator Lamp - - - - - ParamSetting - - - - - bat File - - ModelTreeWidget @@ -1785,12 +1675,12 @@ OsgWidget - + warning - + open dyt file failed @@ -1884,6 +1774,29 @@ + + PresetModelPanel + + + Ships + + + + + Satellites + + + + + Missiles + + + + + Jammers + + + PropertyBrowser @@ -2850,25 +2763,32 @@ SimuRunMenu - + no workspace - + no commands - + Commands - + unnamed + + + + + MatlabParam + + SimuRunMenuClass diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index c53cb78e..3f9e0526 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -5,6 +5,7 @@ #include "PropertyBrowser.h" #include "ModelBrowser.h" +#include "PresetModelPanel.h" #include "DockWidget.h" #include "viewer/QtOsgViewWidget.h" @@ -65,6 +66,14 @@ void MainWindow::InitUI() { modelBrowser_->AttachDock(model); m_mapDockWidget.insert("ModelBrowser", model); + // 创建预制模型面板 + DockWidget* presetModel = new DockWidget(tr("preset models"), 0); + presetModel->SetDockWidgetTitleBar(new DockTitleBar(presetModel)); + presetModel->setObjectName("Dock.PresetModelPanel"); + presetModelPanel_ = new PresetModelPanel(0); + presetModelPanel_->AttachDock(presetModel); + m_mapDockWidget.insert("PresetModelPanel", presetModel); + DockWidget* attribte = new DockWidget(tr("attribte"), 0); attribte->SetDockWidgetTitleBar(new DockTitleBar(attribte)); attribte->setObjectName("Dock.PropertyBrowser"); @@ -88,7 +97,11 @@ void MainWindow::InitUI() { m_mapDockWidget.insert("MainView", viewDock); addDockWidget(Qt::LeftDockWidgetArea, model); + addDockWidget(Qt::LeftDockWidgetArea, presetModel); splitDockWidget(model, viewDock, Qt::Horizontal); + + // 将预制模型面板与模型浏览器标签化 + tabifyDockWidget(model, presetModel); QString wavePath ="", speedPath = "", rdPath = "", matlabParam=""; if (WorkSpaceManager::Get().GetCurrent()) diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index 2c1e54f4..7e6e29e3 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -25,6 +25,9 @@ public: class ModelBrowser* GetModelBrowser() const { return modelBrowser_; } + class PresetModelPanel* GetPresetModelPanel() const { + return presetModelPanel_; + } class OsgWidget* GetViewWidget() const { return qtOsgViewWidget_; } @@ -58,6 +61,7 @@ private: Ui::MainWindow* ui; class ModelBrowser* modelBrowser_{ nullptr }; + class PresetModelPanel* presetModelPanel_{ nullptr }; class PropertyBrowser* propertyBrowser_{ nullptr }; class QWebEngineView* webEngineView_{ nullptr }; class OsgWidget* qtOsgViewWidget_{ nullptr }; diff --git a/src/ui/PresetModelPanel.cpp b/src/ui/PresetModelPanel.cpp new file mode 100644 index 00000000..da4ffb61 --- /dev/null +++ b/src/ui/PresetModelPanel.cpp @@ -0,0 +1,238 @@ +#include "PresetModelPanel.h" +#include "DockTitleBar.h" +#include "DockWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PresetModelPanel::PresetModelPanel(QWidget *parent) + : QWidget(parent) + , toolBox_(nullptr) + , mainLayout_(nullptr) + , shipList_(nullptr) + , satelliteList_(nullptr) + , missileList_(nullptr) + , jammerList_(nullptr) +{ + InitUI(); +} + +PresetModelPanel::~PresetModelPanel() +{ +} + +void PresetModelPanel::AttachDock(DockWidget* dockWidget) +{ + if (nullptr == dockWidget) { + qDebug() << __FUNCTION__ << "dockwidget is nullptr"; + return; + } + + dockWidget->SetDockWidgetTitleBar(nullptr); + dockWidget->setWidget(this); + + DockTitleBar* dockTitleBar = new DockTitleBar; + dockWidget->SetDockWidgetTitleBar(dockTitleBar); +} + +void PresetModelPanel::InitUI() +{ + mainLayout_ = new QVBoxLayout(this); + mainLayout_->setContentsMargins(5, 5, 5, 5); + mainLayout_->setSpacing(5); + + toolBox_ = new QToolBox(this); + toolBox_->setObjectName("PresetModelToolBox"); + + toolBox_->addItem(CreateShipPage(), QIcon(), tr("Ships")); + toolBox_->addItem(CreateSatellitePage(), QIcon(), tr("Satellites")); + toolBox_->addItem(CreateMissilePage(), QIcon(), tr("Missiles")); + toolBox_->addItem(CreateJammerPage(), QIcon(), tr("Jammers")); + + mainLayout_->addWidget(toolBox_); + + setLayout(mainLayout_); +} + +QWidget* PresetModelPanel::CreateShipPage() +{ + QWidget* page = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(page); + + QStringList shipModels = { + "Destroyer", + "Aircraft Carrier", + "Frigate", + "Submarine" + }; + + shipList_ = CreateModelList(page, "Ship", shipModels); + layout->addWidget(shipList_); + + return page; +} + +QWidget* PresetModelPanel::CreateSatellitePage() +{ + QWidget* page = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(page); + + QStringList satelliteModels = { + "Geostationary Satellite", + "Communication Satellite", + "Weather Satellite", + "Navigation Satellite" + }; + + satelliteList_ = CreateModelList(page, "Satellite", satelliteModels); + layout->addWidget(satelliteList_); + + return page; +} + +QWidget* PresetModelPanel::CreateMissilePage() +{ + QWidget* page = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(page); + + QStringList missileModels = { + "Hypersonic Missile", + "Cruise Missile", + "Ballistic Missile", + "Anti-Ship Missile" + }; + + missileList_ = CreateModelList(page, "Missile", missileModels); + layout->addWidget(missileList_); + + return page; +} + +QWidget* PresetModelPanel::CreateJammerPage() +{ + QWidget* page = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(page); + + QStringList jammerModels = { + "Passive Jammer", + "Active Jammer", + "Electronic Warfare Pod", + "Decoy System" + }; + + jammerList_ = CreateModelList(page, "Jammer", jammerModels); + layout->addWidget(jammerList_); + + return page; +} + +QListWidget* PresetModelPanel::CreateModelList(QWidget* parent, const QString& modelType, const QStringList& models) +{ + DraggableListWidget* listWidget = new DraggableListWidget(modelType, parent); + + listWidget->setDragDropMode(QAbstractItemView::DragOnly); + listWidget->setDefaultDropAction(Qt::CopyAction); + + for (const QString& model : models) { + QListWidgetItem* item = new QListWidgetItem(model); + item->setFlags(item->flags() | Qt::ItemIsDragEnabled); + + if (modelType == "Ship") { + item->setIcon(QIcon(":/icons/ship.png")); + } else if (modelType == "Satellite") { + item->setIcon(QIcon(":/icons/satellite.png")); + } else if (modelType == "Missile") { + item->setIcon(QIcon(":/icons/missile.png")); + } else if (modelType == "Jammer") { + item->setIcon(QIcon(":/icons/jammer.png")); + } + + listWidget->addItem(item); + } + + connect(listWidget, &QListWidget::itemDoubleClicked, this, &PresetModelPanel::OnModelItemDoubleClicked); + + return listWidget; +} + +void PresetModelPanel::SetupDragAndDrop(QListWidget* listWidget) +{ + listWidget->setDragDropMode(QAbstractItemView::DragOnly); + listWidget->setDefaultDropAction(Qt::CopyAction); +} + +void PresetModelPanel::OnModelItemDoubleClicked(QListWidgetItem* item) +{ + if (!item) return; + + QListWidget* listWidget = item->listWidget(); + if (!listWidget) return; + + QString modelType = listWidget->property("modelType").toString(); + QString modelName = item->text(); + + emit ModelDropped(modelType, modelName); +} + +// DraggableListWidget implementation +DraggableListWidget::DraggableListWidget(const QString& modelType, QWidget* parent) + : QListWidget(parent), modelType_(modelType) +{ + setProperty("modelType", modelType); +} + +void DraggableListWidget::mousePressEvent(QMouseEvent* event) +{ + if (event->button() == Qt::LeftButton) { + dragStartPosition_ = event->pos(); + } + QListWidget::mousePressEvent(event); +} + +void DraggableListWidget::mouseMoveEvent(QMouseEvent* event) { + if (!(event->buttons() & Qt::LeftButton)) { + return; + } + + if ((event->pos() - dragStartPosition_).manhattanLength() < QApplication::startDragDistance()) { + return; + } + + QListWidgetItem* item = itemAt(dragStartPosition_); + if (!item) { + return; + } + + QDrag* drag = new QDrag(this); + QMimeData* mimeData = new QMimeData; + + QString modelType = this->property("modelType").toString(); + QString modelName = item->text(); + QString dragData = QString("%1|%2").arg(modelType, modelName); + + mimeData->setData("application/x-preset-model", dragData.toUtf8()); + drag->setMimeData(mimeData); + + QPixmap pixmap(item->icon().pixmap(32, 32)); + if (pixmap.isNull()) { + pixmap = QPixmap(100, 30); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + painter.setPen(Qt::black); + painter.drawText(pixmap.rect(), Qt::AlignCenter, modelName); + } + drag->setPixmap(pixmap); + + Qt::DropAction dropAction = drag->exec(Qt::CopyAction); + Q_UNUSED(dropAction); +} \ No newline at end of file diff --git a/src/ui/PresetModelPanel.h b/src/ui/PresetModelPanel.h new file mode 100644 index 00000000..9e9c25ed --- /dev/null +++ b/src/ui/PresetModelPanel.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + */ +class PresetModelPanel : public QWidget { + Q_OBJECT + +public: + explicit PresetModelPanel(QWidget *parent = nullptr); + ~PresetModelPanel() override; + + /** + * @brief Attach to dock widget + * @param dockWidget Dock widget pointer + */ + void AttachDock(DockWidget* dockWidget); + +Q_SIGNALS: + /** + * @brief Signal emitted when model is dragged to scene + * @param modelType Model type + * @param modelName Model name + * @param position Scene position (optional) + */ + void ModelDropped(const QString& modelType, const QString& modelName, const QPointF& position = QPointF()); + +private slots: + /** + * @brief Handle model item double click event + * @param item Clicked item + */ + void OnModelItemDoubleClicked(QListWidgetItem* item); + +private: + /** + * @brief Initialize user interface + */ + void InitUI(); + + /** + * @brief Create ship category page + * @return Ship page widget + */ + QWidget* CreateShipPage(); + + /** + * @brief Create satellite category page + * @return Satellite page widget + */ + QWidget* CreateSatellitePage(); + + /** + * @brief Create missile category page + * @return Missile page widget + */ + QWidget* CreateMissilePage(); + + /** + * @brief Create jammer category page + * @return Jammer page widget + */ + QWidget* CreateJammerPage(); + + /** + * @brief Create model list items + * @param parent Parent widget + * @param modelType Model type + * @param models Model name list + * @return Configured QListWidget + */ + QListWidget* CreateModelList(QWidget* parent, const QString& modelType, const QStringList& models); + + /** + * @brief Setup drag and drop functionality + * @param listWidget List widget to setup drag and drop + */ + void SetupDragAndDrop(QListWidget* listWidget); + +private: + QToolBox* toolBox_; + QVBoxLayout* mainLayout_; + + QListWidget* shipList_; + QListWidget* satelliteList_; + QListWidget* missileList_; + QListWidget* jammerList_; +}; + +/** + * @brief Custom list widget with drag and drop support + */ +class DraggableListWidget : public QListWidget { + Q_OBJECT + +public: + explicit DraggableListWidget(const QString& modelType, QWidget* parent = nullptr); + +Q_SIGNALS: + void ItemDragged(const QString& modelType, const QString& modelName); + +protected: + void mousePressEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + +private: + QString modelType_; + QPoint dragStartPosition_; +}; \ No newline at end of file diff --git a/src/viewer/OsgWidget.cpp b/src/viewer/OsgWidget.cpp index 2e484e25..9d90214a 100644 --- a/src/viewer/OsgWidget.cpp +++ b/src/viewer/OsgWidget.cpp @@ -5,6 +5,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -44,6 +48,9 @@ OsgWidget::OsgWidget(QWidget* parent, Qt::WindowFlags f) setMouseTracking(true); setKeyEventSetsDone(0); + // 启用拖拽接收 + setAcceptDrops(true); + connect( &timer_, SIGNAL(timeout()), this, SLOT(update()) ); timer_.start( 10 ); @@ -183,3 +190,59 @@ void OsgWidget::paintEvent(QPaintEvent*) { frame(); } +void OsgWidget::dragEnterEvent(QDragEnterEvent* event) { + // 检查是否是预制模型拖拽 + if (event->mimeData()->hasFormat("application/x-preset-model")) { + event->acceptProposedAction(); + } else { + event->ignore(); + } +} + +void OsgWidget::dragMoveEvent(QDragMoveEvent* event) { + // 检查是否是预制模型拖拽 + if (event->mimeData()->hasFormat("application/x-preset-model")) { + event->acceptProposedAction(); + } else { + event->ignore(); + } +} + +void OsgWidget::dropEvent(QDropEvent* event) { + // 检查是否是预制模型拖拽 + if (event->mimeData()->hasFormat("application/x-preset-model")) { + QByteArray data = event->mimeData()->data("application/x-preset-model"); + QString modelInfo = QString::fromUtf8(data); + + // 解析模型信息 (格式: "modelType|modelName") + QStringList parts = modelInfo.split("|"); + if (parts.size() == 2) { + QString modelType = parts[0]; + QString modelName = parts[1]; + + // 获取拖拽位置 + QPointF position = event->posF(); + + // 处理预制模型拖拽 + OnPresetModelDropped(modelType, modelName, position); + + event->acceptProposedAction(); + } else { + event->ignore(); + } + } else { + event->ignore(); + } +} + +void OsgWidget::OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position) { + // TODO: 实现预制模型拖拽处理逻辑 + // 1. 将屏幕坐标转换为世界坐标 + // 2. 创建对应的Entity和MeshComponent + // 3. 添加到场景中 + + qDebug() << "预制模型拖拽:" << modelType << modelName << "位置:" << position; + + // 这里暂时只是输出调试信息,后续需要集成实体系统 +} + diff --git a/src/viewer/OsgWidget.h b/src/viewer/OsgWidget.h index ff64a146..b8664ac4 100644 --- a/src/viewer/OsgWidget.h +++ b/src/viewer/OsgWidget.h @@ -29,6 +29,20 @@ protected: void resizeEvent(QResizeEvent* event) override; void paintEvent( QPaintEvent* /*event*/ ) override; + // 拖拽事件处理 + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; + +public slots: + /** + * @brief 处理预制模型拖拽 + * @param modelType 模型类型 + * @param modelName 模型名称 + * @param position 屏幕位置(可选) + */ + void OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position = QPointF()); + private: QTimer timer_;