diff options
author | Mahmoud Badri <mahmoud.badri@qt.io> | 2022-08-19 13:04:26 +0300 |
---|---|---|
committer | Mahmoud Badri <mahmoud.badri@qt.io> | 2022-08-22 13:26:18 +0000 |
commit | fc4ebb0cab19eb9e4a87262ea079c5ad74d9bf2b (patch) | |
tree | 2cf25654fc4bb1e8b106e05a762882bb38e4a4a7 | |
parent | 86d1526564b2aad91ac84039af9e97e69f072ae7 (diff) | |
download | qt-creator-fc4ebb0cab19eb9e4a87262ea079c5ad74d9bf2b.tar.gz |
QmlDesigner: Create a context menu for the 3D Editor
For now only 1 action is implemented (edit material), more actions are
coming next.
Task-number: QDS-7414
Task-number: QDS-7398
Change-Id: Id8e36c23d9a4d35ee94d55d3d6b15df78241a05d
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
9 files changed, 111 insertions, 35 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index dae4f975b4..b94fa31fc6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -291,6 +291,10 @@ void Qt5InformationNodeInstanceServer::handleInputEvents() // data stored internally in QMutableEventPoint to potentially be updated by system // before the event is delivered. QGuiApplication::sendEvent(m_editView3DData.window, me); + + // Context menu requested + if (command.button() == Qt::RightButton && command.modifiers() == Qt::NoModifier) + getModelAtPos(command.pos()); } } @@ -405,6 +409,29 @@ void Qt5InformationNodeInstanceServer::removeRotationBlocks(const QVector<qint32 #endif } +void Qt5InformationNodeInstanceServer::getModelAtPos(const QPointF &pos) +{ +#ifdef QUICK3D_MODULE + // pick a Quick3DModel at view position + auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper); + if (!helper) + return; + + QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context()); + QObject *obj = qvariant_cast<QObject *>(editViewProp.read()); + QQuick3DViewport *editView = qobject_cast<QQuick3DViewport *>(obj); + + QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); + + // filter out picks of models created dynamically or inside components + QQuick3DModel *resolvedPick = qobject_cast<QQuick3DModel *>(helper->resolvePick(hitModel)); + + QVariant instance = resolvedPick ? instanceForObject(resolvedPick).instanceId() : -1; + nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ModelAtPos, instance}); + return; +#endif +} + void Qt5InformationNodeInstanceServer::createEditView3D() { #ifdef QUICK3D_MODULE @@ -2399,26 +2426,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c #endif #ifdef QUICK3D_MODULE case View3DActionCommand::GetModelAtPos: { - // pick a Quick3DModel at view position - auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper); - if (!helper) - return; - - QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context()); - QObject *obj = qvariant_cast<QObject *>(editViewProp.read()); - QQuick3DViewport *editView = qobject_cast<QQuick3DViewport *>(obj); - - QPointF pos = command.value().toPointF(); - QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); - - // filter out picks of models created dynamically or inside components - QQuick3DModel *resolvedPick = qobject_cast<QQuick3DModel *>(helper->resolvePick(hitModel)); - - if (resolvedPick) { - ServerNodeInstance instance = instanceForObject(resolvedPick); - nodeInstanceClient()->handlePuppetToCreatorCommand( - {PuppetToCreatorCommand::ModelAtPos, QVariant(instance.instanceId())}); - } + getModelAtPos(command.value().toPointF()); return; } #endif diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index ea104442a6..87c1d53d54 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -148,6 +148,7 @@ private: void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges); void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges); void removeRotationBlocks(const QVector<qint32> &instanceIds); + void getModelAtPos(const QPointF &pos); void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); #ifdef QUICK3D_PARTICLES_MODULE diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 068e9cf2fd..8df917be69 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -796,7 +796,11 @@ void addNewSignalHandler(const SelectionContext &selectionState) // Open a model's material in the material editor void editMaterial(const SelectionContext &selectionContext) { - ModelNode modelNode = selectionContext.currentSingleSelectedNode(); + ModelNode modelNode = selectionContext.targetNode(); + + if (!modelNode.isValid()) + modelNode = selectionContext.currentSingleSelectedNode(); + QTC_ASSERT(modelNode.isValid(), return); BindingProperty prop = modelNode.bindingProperty("materials"); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index 02d798c1f6..98c052dc18 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -102,6 +102,9 @@ QWidget *Edit3DCanvas::busyIndicator() const void Edit3DCanvas::mousePressEvent(QMouseEvent *e) { + if (e->button() == Qt::RightButton && e->modifiers() == Qt::NoModifier) + m_parent->view()->startContextMenu(e->pos()); + m_parent->view()->sendInputEvent(e); QWidget::mousePressEvent(e); } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index f848b58b3f..fb844b1c85 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -239,14 +239,25 @@ void Edit3DView::customNotification(const AbstractView *view, const QString &ide resetPuppet(); } +/** + * @brief get model at position from puppet process + * + * Response from puppet process for the model at requested position + * + * @param modelNode 3D model picked at the requested position, invalid node if no model exists + */ void Edit3DView::modelAtPosReady(const ModelNode &modelNode) { - if (!m_droppedMaterial.isValid() || !modelNode.isValid()) - return; - - executeInTransaction(__FUNCTION__, [&] { - assignMaterialTo3dModel(modelNode, m_droppedMaterial); - }); + if (m_modelAtPosReqType == ModelAtPosReqType::ContextMenu) { + m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode); + } else if (m_modelAtPosReqType == ModelAtPosReqType::MaterialDrop) { + if (m_droppedMaterial.isValid() && modelNode.isValid()) { + executeInTransaction(__FUNCTION__, [&] { + assignMaterialTo3dModel(modelNode, m_droppedMaterial); + }); + } + } + m_modelAtPosReqType = ModelAtPosReqType::None; } void Edit3DView::sendInputEvent(QInputEvent *e) const @@ -631,8 +642,17 @@ void Edit3DView::addQuick3DImport() tr("Could not add QtQuick3D import to project.")); } +// This method is called upon right-clicking the view to prepare for context-menu creation. The actual +// context menu is created when modelAtPosReady() is received from puppet +void Edit3DView::startContextMenu(const QPoint &pos) +{ + m_contextMenuPos = pos; + m_modelAtPosReqType = ModelAtPosReqType::ContextMenu; +} + void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos) { + m_modelAtPosReqType = ModelAtPosReqType::MaterialDrop; m_droppedMaterial = matNode; QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos}); } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 8b242058ef..0d3e9ff16f 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -79,9 +79,16 @@ public: void setSeeker(SeekerSlider *slider); void addQuick3DImport(); + void startContextMenu(const QPoint &pos); void dropMaterial(const ModelNode &matNode, const QPointF &pos); private: + enum class ModelAtPosReqType { + MaterialDrop, + ContextMenu, + None + }; + void createEdit3DWidget(); void checkImports(); @@ -120,6 +127,8 @@ private: int particlemode; ModelCache<QImage> m_canvasCache; ModelNode m_droppedMaterial; + ModelAtPosReqType m_modelAtPosReqType; + QPoint m_contextMenuPos; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index a6672b9f16..8643bc091b 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -30,6 +30,7 @@ #include "edit3dwidget.h" #include "edit3dvisibilitytogglesmenu.h" #include "metainfo.h" +#include "modelnodeoperations.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include "qmlvisualnode.h" @@ -49,8 +50,8 @@ namespace QmlDesigner { -Edit3DWidget::Edit3DWidget(Edit3DView *view) : - m_view(view) +Edit3DWidget::Edit3DWidget(Edit3DView *view) + : m_view(view) { setAcceptDrops(true); @@ -146,6 +147,8 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : handleActions(view->backgroundColorActions(), m_backgroundColorMenu, false); + createContextMenu(); + view->setSeeker(seeker); seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); @@ -173,6 +176,18 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : showCanvas(false); } +void Edit3DWidget::createContextMenu() +{ + m_contextMenu = new QMenu(this); + m_editMaterialAction = m_contextMenu->addAction(tr("Edit Material"), [&] { + SelectionContext selCtx(m_view); + selCtx.setTargetNode(m_contextMenuTarget); + ModelNodeOperations::editMaterial(selCtx); + }); + + // TODO: add more actions: delete, create, etc +} + void Edit3DWidget::contextHelp(const Core::IContext::HelpCallback &callback) const { if (m_view) @@ -221,6 +236,15 @@ void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos) m_backgroundColorMenu->close(); } +void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode) +{ + m_contextMenuTarget = modelNode; + + m_editMaterialAction->setEnabled(modelNode.isValid()); + + m_contextMenu->popup(mapToGlobal(pos)); +} + void Edit3DWidget::linkActivated(const QString &link) { Q_UNUSED(link) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index 7d40fd5471..6b3e773fdc 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -24,11 +24,13 @@ ****************************************************************************/ #pragma once -#include <QtWidgets/qwidget.h> -#include <QtWidgets/qlabel.h> -#include <QtWidgets/qmenu.h> -#include <QtCore/qpointer.h> +#include <QLabel> +#include <QMenu> +#include <QPointer> +#include <QWidget> + #include <coreplugin/icontext.h> +#include <modelnode.h> namespace QmlDesigner { @@ -54,12 +56,15 @@ public: QMenu *backgroundColorMenu() const; void showBackgroundColorMenu(bool show, const QPoint &pos); + void showContextMenu(const QPoint &pos, const ModelNode &modelNode); + protected: void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; void dropEvent(QDropEvent *dropEvent) override; private: void linkActivated(const QString &link); + void createContextMenu(); QPointer<Edit3DView> m_edit3DView; QPointer<Edit3DView> m_view; @@ -69,6 +74,9 @@ private: Core::IContext *m_context = nullptr; QPointer<QMenu> m_visibilityTogglesMenu; QPointer<QMenu> m_backgroundColorMenu; + QPointer<QMenu> m_contextMenu; + QPointer<QAction> m_editMaterialAction; + ModelNode m_contextMenuTarget; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 1a703463cc..d723a21792 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1707,8 +1707,7 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand emitImport3DSupportChanged(supportMap); } else if (command.type() == PuppetToCreatorCommand::ModelAtPos) { ModelNode modelNode = modelNodeForInternalId(command.data().toUInt()); - if (modelNode.isValid()) - emitModelAtPosResult(modelNode); + emitModelAtPosResult(modelNode); } } |