diff --git a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h index 95ca0d3ce25..9fbaf671765 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h @@ -40,7 +40,7 @@ public: ActiveSceneChanged, RenderModelNodePreviewImage, Import3DSupport, - ModelAtPos, + NodeAtPos, None }; PuppetToCreatorCommand(Type type, const QVariant &data); diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index 4373a1c9ddd..e187ba94c8c 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -60,7 +60,7 @@ public: SelectGridColor, ResetBackgroundColor, SyncBackgroundColor, - GetModelAtPos + GetNodeAtPos }; View3DActionCommand(Type type, const QVariant &value); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 34090031897..f18c330fedf 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -547,6 +547,19 @@ Item { } } + function gizmoAt(x, y) + { + for (var i = 0; i < lightIconGizmos.length; ++i) { + if (lightIconGizmos[i].visible && lightIconGizmos[i].hasPoint(x, y)) + return lightIconGizmos[i].targetNode; + } + for (var i = 0; i < cameraGizmos.length; ++i) { + if (cameraGizmos[i].visible && cameraGizmos[i].hasPoint(x, y)) + return cameraGizmos[i].targetNode; + } + return null; + } + Component.onCompleted: { createEditView(); selectObjects([]); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml index 3ee4776aa52..a49570be82f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/IconGizmo.qml @@ -52,6 +52,17 @@ Item { signal clicked(Node node, bool multi) + function hasPoint(x, y) + { + if (!view3D || !targetNode) + return false; + + var point = view3D.mapToItem(iconMouseArea, x, y); + + return point.x >= iconMouseArea.x && (point.x <= iconMouseArea.x + iconMouseArea.width) + && point.y >= iconMouseArea.y && (point.y <= iconMouseArea.y + iconMouseArea.height); + } + onSelectedChanged: { if (selected) hasMouse = false; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 5fa269a916d..a7202fb7fd7 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -670,6 +670,23 @@ Item { } } + function gizmoAt(x, y) + { + for (var i = 0; i < lightIconGizmos.length; ++i) { + if (lightIconGizmos[i].visible && lightIconGizmos[i].hasPoint(x, y)) + return lightIconGizmos[i].targetNode; + } + for (var i = 0; i < cameraGizmos.length; ++i) { + if (cameraGizmos[i].visible && cameraGizmos[i].hasPoint(x, y)) + return cameraGizmos[i].targetNode; + } + for (var i = 0; i < particleSystemIconGizmos.length; ++i) { + if (particleSystemIconGizmos[i].visible && particleSystemIconGizmos[i].hasPoint(x, y)) + return particleSystemIconGizmos[i].targetNode; + } + return null; + } + Component.onCompleted: { createEditView(); selectObjects([]); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml index 2b78dd04aac..315bb79c80d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml @@ -53,6 +53,17 @@ Item { signal clicked(Node node, bool multi) + function hasPoint(x, y) + { + if (!view3D || !targetNode) + return false; + + var point = view3D.mapToItem(iconMouseArea, x, y); + + return point.x >= iconMouseArea.x && (point.x <= iconMouseArea.x + iconMouseArea.width) + && point.y >= iconMouseArea.y && (point.y <= iconMouseArea.y + iconMouseArea.height); + } + onSelectedChanged: { if (selected) hasMouse = false; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 852572ebf13..24dad5961dc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -294,7 +294,7 @@ void Qt5InformationNodeInstanceServer::handleInputEvents() // Context menu requested if (command.button() == Qt::RightButton && command.modifiers() == Qt::NoModifier) - getModelAtPos(command.pos()); + getNodeAtPos(command.pos()); } } @@ -409,7 +409,7 @@ void Qt5InformationNodeInstanceServer::removeRotationBlocks(const QVector(editViewProp.read()); QQuick3DViewport *editView = qobject_cast(obj); - QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); + // Non-model nodes with icon gizmos are also valid results + QVariant gizmoVar; + QMetaObject::invokeMethod(m_editView3DData.rootItem, "gizmoAt", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, gizmoVar), + Q_ARG(QVariant, pos.x()), + Q_ARG(QVariant, pos.y())); + QObject *gizmoObj = qvariant_cast(gizmoVar); + QVariant instance = -1; - // filter out picks of models created dynamically or inside components - QQuick3DModel *resolvedPick = qobject_cast(helper->resolvePick(hitModel)); + if (gizmoObj && hasInstanceForObject(gizmoObj)) { + instance = instanceForObject(gizmoObj).instanceId(); + } else { + QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); + QObject *resolvedPick = helper->resolvePick(hitModel); + if (hasInstanceForObject(resolvedPick)) + instance = instanceForObject(resolvedPick).instanceId(); + } - QVariant instance = resolvedPick ? instanceForObject(resolvedPick).instanceId() : -1; - nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ModelAtPos, instance}); + nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::NodeAtPos, instance}); #else Q_UNUSED(pos) #endif @@ -2426,8 +2438,8 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c break; #endif #ifdef QUICK3D_MODULE - case View3DActionCommand::GetModelAtPos: { - getModelAtPos(command.value().toPointF()); + case View3DActionCommand::GetNodeAtPos: { + getNodeAtPos(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 87c1d53d547..57586755841 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -148,7 +148,7 @@ private: void updateMaterialPreviewData(const QVector &valueChanges); void updateRotationBlocks(const QVector &valueChanges); void removeRotationBlocks(const QVector &instanceIds); - void getModelAtPos(const QPointF &pos); + void getNodeAtPos(const QPointF &pos); void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); #ifdef QUICK3D_PARTICLES_MODULE diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index d3b576f5cf0..41a82bf6963 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -290,28 +290,29 @@ void Edit3DView::customNotification(const AbstractView *view, const QString &ide } /** - * @brief get model at position from puppet process + * @brief Get node 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 + * @param modelNode Node picked at the requested position or invalid node if nothing could be picked */ -void Edit3DView::modelAtPosReady(const ModelNode &modelNode) +void Edit3DView::nodeAtPosReady(const ModelNode &modelNode) { - if (m_modelAtPosReqType == ModelAtPosReqType::ContextMenu) { + if (m_nodeAtPosReqType == NodeAtPosReqType::ContextMenu) { // Make sure right-clicked item is selected. Due to a bug in puppet side right-clicking an item // while the context-menu is shown doesn't select the item. if (modelNode.isValid() && !modelNode.isSelected()) setSelectedModelNode(modelNode); m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode); - } else if (m_modelAtPosReqType == ModelAtPosReqType::MaterialDrop) { - if (m_droppedMaterial.isValid() && modelNode.isValid()) { + } else if (m_nodeAtPosReqType == NodeAtPosReqType::MaterialDrop) { + if (m_droppedMaterial.isValid() && modelNode.isValid() + && modelNode.isSubclassOf("QtQuick3D.Model")) { executeInTransaction(__FUNCTION__, [&] { assignMaterialTo3dModel(modelNode, m_droppedMaterial); }); } } - m_modelAtPosReqType = ModelAtPosReqType::None; + m_nodeAtPosReqType = NodeAtPosReqType::None; } void Edit3DView::sendInputEvent(QInputEvent *e) const @@ -697,18 +698,18 @@ void Edit3DView::addQuick3DImport() } // 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 +// context menu is created when nodeAtPosReady() is received from puppet void Edit3DView::startContextMenu(const QPoint &pos) { m_contextMenuPos = pos; - m_modelAtPosReqType = ModelAtPosReqType::ContextMenu; + m_nodeAtPosReqType = NodeAtPosReqType::ContextMenu; } void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos) { - m_modelAtPosReqType = ModelAtPosReqType::MaterialDrop; + m_nodeAtPosReqType = NodeAtPosReqType::MaterialDrop; m_droppedMaterial = matNode; - QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos}); + QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetNodeAtPos, pos}); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 57a967b2f01..635bbaf574b 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -63,7 +63,7 @@ public: void modelAboutToBeDetached(Model *model) override; void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; - void modelAtPosReady(const ModelNode &modelNode) override; + void nodeAtPosReady(const ModelNode &modelNode) override; void sendInputEvent(QInputEvent *e) const; void edit3DViewResized(const QSize &size) const; @@ -85,7 +85,7 @@ private slots: void onEntriesChanged(); private: - enum class ModelAtPosReqType { + enum class NodeAtPosReqType { MaterialDrop, ContextMenu, None @@ -130,7 +130,7 @@ private: int particlemode; ModelCache m_canvasCache; ModelNode m_droppedMaterial; - ModelAtPosReqType m_modelAtPosReqType; + NodeAtPosReqType m_nodeAtPosReqType; QPoint m_contextMenuPos; QTimer m_compressionTimer; }; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 26f2ce6cf0c..60d6d7ed633 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -300,8 +300,10 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode { m_contextMenuTarget = modelNode; - m_editMaterialAction->setEnabled(modelNode.isValid()); - m_deleteAction->setEnabled(modelNode.isValid()); + const bool isValid = modelNode.isValid(); + const bool isModel = isValid && modelNode.isSubclassOf("QtQuick3D.Model"); + m_editMaterialAction->setEnabled(isModel); + m_deleteAction->setEnabled(isValid && !modelNode.isRootNode()); m_contextMenu->popup(mapToGlobal(pos)); } diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 994caaa7ec4..065e3382157 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -166,7 +166,7 @@ public: void emitUpdateActiveScene3D(const QVariantMap &sceneState); void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void emitImport3DSupportChanged(const QVariantMap &supportMap); - void emitModelAtPosResult(const ModelNode &modelNode); + void emitNodeAtPosResult(const ModelNode &modelNode); void sendTokenToInstances(const QString &token, int number, const QVector &nodeVector); @@ -232,7 +232,7 @@ public: virtual void renderImage3DChanged(const QImage &image); virtual void updateActiveScene3D(const QVariantMap &sceneState); virtual void updateImport3DSupport(const QVariantMap &supportMap); - virtual void modelAtPosReady(const ModelNode &modelNode); + virtual void nodeAtPosReady(const ModelNode &modelNode); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); virtual void dragStarted(QMimeData *mimeData); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 8fce87eb326..222a5fa079e 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1705,9 +1705,9 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand } else if (command.type() == PuppetToCreatorCommand::Import3DSupport) { const QVariantMap supportMap = qvariant_cast(command.data()); emitImport3DSupportChanged(supportMap); - } else if (command.type() == PuppetToCreatorCommand::ModelAtPos) { + } else if (command.type() == PuppetToCreatorCommand::NodeAtPos) { ModelNode modelNode = modelNodeForInternalId(command.data().toUInt()); - emitModelAtPosResult(modelNode); + emitNodeAtPosResult(modelNode); } } diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 8bf0e4347f2..6ec1cbc7f0e 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -409,7 +409,7 @@ void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/) } // a Quick3DModel that is picked at the requested position in the 3D Editor -void AbstractView::modelAtPosReady(const ModelNode & /*modelNode*/) {} +void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/) {} void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/) { @@ -802,10 +802,10 @@ void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap) model()->d->notifyImport3DSupportChanged(supportMap); } -void AbstractView::emitModelAtPosResult(const ModelNode &modelNode) +void AbstractView::emitNodeAtPosResult(const ModelNode &modelNode) { if (model()) - model()->d->notifyModelAtPosResult(modelNode); + model()->d->notifyNodeAtPosResult(modelNode); } void AbstractView::emitRewriterEndTransaction() diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index d98cb944509..e1344a50957 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -598,9 +598,9 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap) notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); }); } -void ModelPrivate::notifyModelAtPosResult(const ModelNode &modelNode) +void ModelPrivate::notifyNodeAtPosResult(const ModelNode &modelNode) { - notifyInstanceChanges([&](AbstractView *view) { view->modelAtPosReady(modelNode); }); + notifyInstanceChanges([&](AbstractView *view) { view->nodeAtPosReady(modelNode); }); } void ModelPrivate::notifyDragStarted(QMimeData *mimeData) diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 98be8a135fc..f2c31a1730a 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -186,7 +186,7 @@ public: void notifyUpdateActiveScene3D(const QVariantMap &sceneState); void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyImport3DSupportChanged(const QVariantMap &supportMap); - void notifyModelAtPosResult(const ModelNode &modelNode); + void notifyNodeAtPosResult(const ModelNode &modelNode); void notifyDragStarted(QMimeData *mimeData); void notifyDragEnded();