From fc4ebb0cab19eb9e4a87262ea079c5ad74d9bf2b Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 19 Aug 2022 13:04:26 +0300 Subject: 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: Reviewed-by: Miikka Heikkinen --- .../instances/qt5informationnodeinstanceserver.cpp | 48 +++++++++++++--------- .../instances/qt5informationnodeinstanceserver.h | 1 + .../componentcore/modelnodeoperations.cpp | 6 ++- .../qmldesigner/components/edit3d/edit3dcanvas.cpp | 3 ++ .../qmldesigner/components/edit3d/edit3dview.cpp | 32 ++++++++++++--- .../qmldesigner/components/edit3d/edit3dview.h | 9 ++++ .../qmldesigner/components/edit3d/edit3dwidget.cpp | 28 ++++++++++++- .../qmldesigner/components/edit3d/edit3dwidget.h | 16 ++++++-- .../designercore/instances/nodeinstanceview.cpp | 3 +- 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 dae4f975b40..b94fa31fc63 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(m_3dHelper); + if (!helper) + return; + + QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context()); + QObject *obj = qvariant_cast(editViewProp.read()); + QQuick3DViewport *editView = qobject_cast(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(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(m_3dHelper); - if (!helper) - return; - - QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context()); - QObject *obj = qvariant_cast(editViewProp.read()); - QQuick3DViewport *editView = qobject_cast(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(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 ea104442a6e..87c1d53d547 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 &valueChanges); void updateRotationBlocks(const QVector &valueChanges); void removeRotationBlocks(const QVector &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 068e9cf2fd8..8df917be694 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 02d798c1f6b..98c052dc188 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 f848b58b3f0..fb844b1c858 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 8b242058efb..0d3e9ff16fd 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 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 a6672b9f164..8643bc091b1 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 7d40fd54715..6b3e773fdc4 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -24,11 +24,13 @@ ****************************************************************************/ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include + #include +#include 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 m_edit3DView; QPointer m_view; @@ -69,6 +74,9 @@ private: Core::IContext *m_context = nullptr; QPointer m_visibilityTogglesMenu; QPointer m_backgroundColorMenu; + QPointer m_contextMenu; + QPointer 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 1a703463ccf..d723a217924 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); } } -- cgit v1.2.3