diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml index e522a60cf48..a108190ff7a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml @@ -46,8 +46,8 @@ IconGizmo { frustum.targetNode = targetNode; frustum.targetNode = Qt.binding(function() {return targetNode;}); - frustum.visible = visible; - frustum.visible = Qt.binding(function() {return visible;}); + frustum.visible = visible || (targetNode && selected && activeScene === scene); + frustum.visible = Qt.binding(function() {return visible || (targetNode && selected && activeScene === scene);}); } onActiveSceneChanged: { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 2842d70637c..002ed7bc04e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -263,11 +263,16 @@ Item { function handleObjectClicked(object, multi) { - var theObject = object; + var clickedObject; + + // Click on locked object is treated same as click on empty space + if (!_generalHelper.isLocked(object)) + clickedObject = object; + if (selectionMode === EditView3D.SelectionMode.Group) { - while (theObject && theObject !== activeScene - && (activeScene instanceof Model || theObject.parent !== activeScene)) { - theObject = theObject.parent; + while (clickedObject && clickedObject !== activeScene + && (activeScene instanceof Model || clickedObject.parent !== activeScene)) { + clickedObject = clickedObject.parent; } } // Object selection logic: @@ -276,20 +281,20 @@ Item { // One or more objects selected: Multiselect // Null object always clears entire selection var newSelection = []; - if (object !== null) { + if (clickedObject) { if (multi && selectedNodes.length > 0) { var deselect = false; for (var i = 0; i < selectedNodes.length; ++i) { // Multiselecting already selected object clears that object from selection - if (selectedNodes[i] !== object) + if (selectedNodes[i] !== clickedObject) newSelection[newSelection.length] = selectedNodes[i]; else deselect = true; } if (!deselect) - newSelection[newSelection.length] = object; + newSelection[newSelection.length] = clickedObject; } else { - newSelection[0] = theObject; + newSelection[0] = clickedObject; } } selectObjects(newSelection); @@ -312,16 +317,22 @@ Item { if (slotFound !== -1) { lightIconGizmos[slotFound].scene = scene; lightIconGizmos[slotFound].targetNode = obj; + lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj); + lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj); + _generalHelper.registerGizmoTarget(obj); return; } // No free gizmos available, create a new one var gizmoComponent = Qt.createComponent("LightIconGizmo.qml"); if (gizmoComponent.status === Component.Ready) { + _generalHelper.registerGizmoTarget(obj); var gizmo = gizmoComponent.createObject(overlayView, {"view3D": overlayView, "targetNode": obj, "selectedNodes": selectedNodes, "scene": scene, - "activeScene": activeScene}); + "activeScene": activeScene, + "locked": _generalHelper.isLocked(obj), + "hidden": _generalHelper.isHidden(obj)}); lightIconGizmos[lightIconGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;}); @@ -345,6 +356,9 @@ Item { if (slotFound !== -1) { cameraGizmos[slotFound].scene = scene; cameraGizmos[slotFound].targetNode = obj; + cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj); + cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj); + _generalHelper.registerGizmoTarget(obj); return; } @@ -352,6 +366,7 @@ Item { var gizmoComponent = Qt.createComponent("CameraGizmo.qml"); var frustumComponent = Qt.createComponent("CameraFrustum.qml"); if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) { + _generalHelper.registerGizmoTarget(obj); var geometryName = _generalHelper.generateUniqueName("CameraGeometry"); var frustum = frustumComponent.createObject( overlayScene, @@ -359,7 +374,8 @@ Item { var gizmo = gizmoComponent.createObject( overlayView, {"view3D": overlayView, "targetNode": obj, - "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene}); + "selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene, + "locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj)}); cameraGizmos[cameraGizmos.length] = gizmo; gizmo.clicked.connect(handleObjectClicked); @@ -376,6 +392,7 @@ Item { if (lightIconGizmos[i].targetNode === obj) { lightIconGizmos[i].scene = null; lightIconGizmos[i].targetNode = null; + _generalHelper.unregisterGizmoTarget(obj); return; } } @@ -387,6 +404,7 @@ Item { if (cameraGizmos[i].targetNode === obj) { cameraGizmos[i].scene = null; cameraGizmos[i].targetNode = null; + _generalHelper.unregisterGizmoTarget(obj); return; } } @@ -423,6 +441,40 @@ Item { onWidthChanged: _generalHelper.requestOverlayUpdate() onHeightChanged: _generalHelper.requestOverlayUpdate() + Connections { + target: _generalHelper + function onLockedStateChanged(node) + { + for (var i = 0; i < cameraGizmos.length; ++i) { + if (cameraGizmos[i].targetNode === node) { + cameraGizmos[i].locked = _generalHelper.isLocked(node); + return; + } + } + for (var i = 0; i < lightIconGizmos.length; ++i) { + if (lightIconGizmos[i].targetNode === node) { + lightIconGizmos[i].locked = _generalHelper.isLocked(node); + return; + } + } + } + function onHiddenStateChanged(node) + { + for (var i = 0; i < cameraGizmos.length; ++i) { + if (cameraGizmos[i].targetNode === node) { + cameraGizmos[i].hidden = _generalHelper.isHidden(node); + return; + } + } + for (var i = 0; i < lightIconGizmos.length; ++i) { + if (lightIconGizmos[i].targetNode === node) { + lightIconGizmos[i].hidden = _generalHelper.isHidden(node); + return; + } + } + } + } + Node { id: overlayScene diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml index 10de1f224cd..78f4190621a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml @@ -43,6 +43,8 @@ Item { return false; } property bool hasMouse: false + property bool hidden: false + property bool locked: false property alias iconSource: iconImage.source @@ -53,7 +55,7 @@ Item { hasMouse = false; } - visible: activeScene === scene && (targetNode ? targetNode.visible : false) + visible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false) Overlay2D { id: iconOverlay @@ -70,7 +72,7 @@ Item { y: -height / 2 color: "transparent" border.color: "#7777ff" - border.width: iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0 + border.width: !iconGizmo.locked && iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0 radius: 5 opacity: iconGizmo.selected ? 0.2 : 1 Image { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 6222c84ce71..133035de20c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -244,6 +244,40 @@ QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode) return pickNode; } +void GeneralHelper::registerGizmoTarget(QQuick3DNode *node) +{ + if (!m_gizmoTargets.contains(node)) { + m_gizmoTargets.insert(node); + node->installEventFilter(this); + } +} + +void GeneralHelper::unregisterGizmoTarget(QQuick3DNode *node) +{ + if (m_gizmoTargets.contains(node)) { + m_gizmoTargets.remove(node); + node->removeEventFilter(this); + } +} + +bool GeneralHelper::isLocked(QQuick3DNode *node) +{ + if (node) { + QVariant lockValue = node->property("_edit3dLocked"); + return lockValue.isValid() && lockValue.toBool(); + } + return false; +} + +bool GeneralHelper::isHidden(QQuick3DNode *node) +{ + if (node) { + QVariant hideValue = node->property("_edit3dHidden"); + return hideValue.isValid() && hideValue.toBool(); + } + return false; +} + void GeneralHelper::storeToolState(const QString &sceneId, const QString &tool, const QVariant &state, int delay) { @@ -322,6 +356,21 @@ bool GeneralHelper::isMacOS() const #endif } +bool GeneralHelper::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::DynamicPropertyChange) { + auto node = qobject_cast(obj); + if (m_gizmoTargets.contains(node)) { + auto de = static_cast(event); + if (de->propertyName() == "_edit3dLocked") + emit lockedStateChanged(node); + else if (de->propertyName() == "_edit3dHidden") + emit hiddenStateChanged(node); + } + } + return QObject::eventFilter(obj, event); +} + void GeneralHelper::handlePendingToolStateUpdate() { m_toolStateUpdateTimer.stop(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index f162eb0d30c..f40e8a45696 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -74,6 +74,12 @@ public: Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property, const QVariant& value); Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode); + + Q_INVOKABLE void registerGizmoTarget(QQuick3DNode *node); + Q_INVOKABLE void unregisterGizmoTarget(QQuick3DNode *node); + Q_INVOKABLE bool isLocked(QQuick3DNode *node); + Q_INVOKABLE bool isHidden(QQuick3DNode *node); + Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool, const QVariant &state, int delayEmit = 0); void initToolStates(const QString &sceneId, const QVariantMap &toolStates); @@ -90,6 +96,11 @@ public: signals: void overlayUpdateNeeded(); void toolStateChanged(const QString &sceneId, const QString &tool, const QVariant &toolState); + void hiddenStateChanged(QQuick3DNode *node); + void lockedStateChanged(QQuick3DNode *node); + +protected: + bool eventFilter(QObject *obj, QEvent *event); private: void handlePendingToolStateUpdate(); @@ -98,6 +109,7 @@ private: QTimer m_toolStateUpdateTimer; QHash m_toolStates; QHash m_toolStatesPending; + QSet m_gizmoTargets; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index ece608fdc98..39add144fb3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -998,9 +998,17 @@ void NodeInstanceServer::setInstanceAuxiliaryData(const PropertyValueContainer & if (hasInstanceForId(auxiliaryContainer.instanceId())) { ServerNodeInstance instance = instanceForId(auxiliaryContainer.instanceId()); if (!auxiliaryContainer.value().isNull()) - instance.setHideInEditor(auxiliaryContainer.value().toBool()); + instance.setHiddenInEditor(auxiliaryContainer.value().toBool()); else - instance.setHideInEditor(false); + instance.setHiddenInEditor(false); + } + } else if (auxiliaryContainer.name() == "locked") { + if (hasInstanceForId(auxiliaryContainer.instanceId())) { + ServerNodeInstance instance = instanceForId(auxiliaryContainer.instanceId()); + if (!auxiliaryContainer.value().isNull()) + instance.setLockedInEditor(auxiliaryContainer.value().toBool()); + else + instance.setLockedInEditor(false); } } } @@ -1480,4 +1488,14 @@ void NodeInstanceServer::initializeAuxiliaryViews() { } +void NodeInstanceServer::handleInstanceLocked(const ServerNodeInstance &/*instance*/, bool /*enable*/, + bool /*checkAncestors*/) +{ +} + +void NodeInstanceServer::handleInstanceHidden(const ServerNodeInstance &/*instance*/, bool /*enable*/, + bool /*checkAncestors*/) +{ +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 78e35d98a92..1d1533884db 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -208,6 +208,9 @@ public: virtual void collectItemChangesAndSendChangeCommands() = 0; + virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors); + virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors); + public slots: void refreshLocalFileProperty(const QString &path); void refreshDummyData(const QString &path); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index d69846d400a..d7fba0a8e75 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -392,8 +392,24 @@ PropertyNameList ObjectNodeInstance::ignoredProperties() const return PropertyNameList(); } -void ObjectNodeInstance::setHideInEditor(bool) +void ObjectNodeInstance::setHiddenInEditor(bool b) { + m_isHiddenInEditor = b; +} + +bool ObjectNodeInstance::isHiddenInEditor() const +{ + return m_isHiddenInEditor; +} + +void ObjectNodeInstance::setLockedInEditor(bool b) +{ + m_isLockedInEditor = b; +} + +bool ObjectNodeInstance::isLockedInEditor() const +{ + return m_isLockedInEditor; } void ObjectNodeInstance::setModifiedFlag(bool b) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index 29e7dc640b0..01cb1c46fc1 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -196,7 +196,11 @@ public: virtual PropertyNameList ignoredProperties() const; - void virtual setHideInEditor(bool b); + virtual void setHiddenInEditor(bool b); + bool isHiddenInEditor() const; + + virtual void setLockedInEditor(bool b); + bool isLockedInEditor() const; void setModifiedFlag(bool b); @@ -213,6 +217,7 @@ protected: void initializePropertyWatcher(const ObjectNodeInstance::Pointer &objectNodeInstance); void ensureVector3DDotProperties(PropertyNameList &list) const; + private: QString m_id; @@ -227,6 +232,8 @@ private: bool m_deleteHeldInstance; bool m_isInLayoutable; bool m_isModified = false; + bool m_isLockedInEditor = false; + bool m_isHiddenInEditor = false; static QHash m_enumationValueHash; }; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 94702ed6099..db97dadffa1 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -129,6 +129,12 @@ static bool imageHasContent(const QImage &image) return false; } +static bool isQuick3DMode() +{ + static bool mode3D = qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE"); + return mode3D; +} + QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url, QQuickItem *&rootItem) { @@ -154,6 +160,23 @@ QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUr return view; } +void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet &instances) +{ + if (!isQuick3DMode()) + return; + + // We only want to update the topmost parents in the set + for (const auto &instance : instances) { + if (instance.isValid()) { + const auto parentInst = instance.parent(); + if (!parentInst.isValid() || !instances.contains(parentInst)) { + handleInstanceHidden(instance, instance.internalInstance()->isHiddenInEditor(), true); + handleInstanceLocked(instance, instance.internalInstance()->isLockedInEditor(), true); + } + } + } +} + void Qt5InformationNodeInstanceServer::createEditView3D() { #ifdef QUICK3D_MODULE @@ -860,7 +883,7 @@ QList Qt5InformationNodeInstanceServer::createInstances( void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews() { #ifdef QUICK3D_MODULE - if (qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE")) { + if (isQuick3DMode()) { createEditView3D(); m_ModelNode3DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"), m_ModelNode3DImageViewRootItem); @@ -1243,6 +1266,7 @@ void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands() if (!m_parentChangedSet.isEmpty()) { sendChildrenChangedCommand(QtHelpers::toList(m_parentChangedSet)); + updateLockedAndHiddenStates(m_parentChangedSet); m_parentChangedSet.clear(); } @@ -1307,7 +1331,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com sendChildrenChangedCommand(instanceList); nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList)); - if (qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE")) + if (isQuick3DMode()) setup3DEditView(instanceList, command.edit3dToolStates()); QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout, @@ -1621,6 +1645,110 @@ void Qt5InformationNodeInstanceServer::removeProperties(const RemovePropertiesCo render3DEditView(); } +void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInstance &instance, + bool enable, bool checkAncestors) +{ +#ifdef QUICK3D_MODULE + if (!isQuick3DMode()) + return; + + bool edit3dLocked = enable; + if (!edit3dLocked || checkAncestors) { + auto parentInst = instance.parent(); + while (!edit3dLocked && parentInst.isValid()) { + edit3dLocked = parentInst.internalInstance()->isLockedInEditor(); + parentInst = parentInst.parent(); + } + } + + QObject *obj = instance.internalObject(); + auto node = qobject_cast(obj); + if (node) + node->setProperty("_edit3dLocked", edit3dLocked); + const auto children = obj->children(); + for (auto child : children) { + if (hasInstanceForObject(child)) { + const ServerNodeInstance childInstance = instanceForObject(child); + if (childInstance.isValid()) { + auto objInstance = childInstance.internalInstance(); + // Don't override explicit lock on children + handleInstanceLocked(childInstance, edit3dLocked || objInstance->isLockedInEditor(), false); + } + } + } +#endif +} + +void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInstance &instance, + bool enable, bool checkAncestors) +{ +#ifdef QUICK3D_MODULE + if (!isQuick3DMode()) + return; + + bool edit3dHidden = enable; + if (!edit3dHidden || checkAncestors) { + // We do not care about hidden status of non-3D ancestor nodes, as the 3D scene + // can be considered a separate visual entity in the whole scene. + auto parentInst = instance.parent(); + while (!edit3dHidden && parentInst.isValid() && qobject_cast(parentInst.internalObject())) { + edit3dHidden = parentInst.internalInstance()->isHiddenInEditor(); + parentInst = parentInst.parent(); + } + } + + auto node = qobject_cast(instance.internalObject()); + if (node) { + bool isInstanceHidden = false; + auto getQuick3DInstanceAndHidden = [this, &isInstanceHidden](QQuick3DObject *obj) -> ServerNodeInstance { + if (hasInstanceForObject(obj)) { + const ServerNodeInstance instance = instanceForObject(obj); + if (instance.isValid() && qobject_cast(instance.internalObject())) { + auto objInstance = instance.internalInstance(); + isInstanceHidden = objInstance->isHiddenInEditor(); + return instance; + } + } + return {}; + }; + // Always make sure the hide status is correct on the node tree from this point on, + // as changes in the node tree (reparenting, adding new nodes) can make the previously set + // hide status based on ancestor unreliable. + node->setProperty("_edit3dHidden", edit3dHidden); + if (auto model = qobject_cast(node)) + model->setPickable(!edit3dHidden); // allow 3D objects to receive mouse clicks + const auto childItems = node->childItems(); + for (auto childItem : childItems) { + const ServerNodeInstance quick3dInstance = getQuick3DInstanceAndHidden(childItem); + if (quick3dInstance.isValid()) { + // Don't override explicit hide in children + handleInstanceHidden(quick3dInstance, edit3dHidden || isInstanceHidden, false); + } else { + // Children of components do not have instances, but will still need to be pickable + std::function checkChildren; + checkChildren = [&](QQuick3DNode *checkNode) { + const auto childItems = checkNode->childItems(); + for (auto child : childItems) { + if (auto childNode = qobject_cast(child)) + checkChildren(childNode); + } + if (auto checkModel = qobject_cast(checkNode)) { + QVariant value; + if (!edit3dHidden) + value = QVariant::fromValue(node); + // Specify the actual pick target with dynamic property + checkModel->setProperty("_pickTarget", value); + checkModel->setPickable(!edit3dHidden); + } + }; + if (auto childNode = qobject_cast(childItem)) + checkChildren(childNode); + } + } + } +#endif +} + // update 3D view size when it changes in creator side void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewStateCommand &command) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 8f3af1ccdb4..f703e9fcb89 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -70,6 +70,9 @@ public: void changeState(const ChangeStateCommand &command) override; void removeProperties(const RemovePropertiesCommand &command) override; + void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override; + void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override; + private slots: void handleSelectionChanged(const QVariant &objs); void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName); @@ -127,6 +130,7 @@ private: void doRenderModelNode3DImageView(); void doRenderModelNode2DImageView(); QQuickView *createAuxiliaryQuickView(const QUrl &url, QQuickItem *&rootItem); + void updateLockedAndHiddenStates(const QSet &instances); QPointer m_editView3D; QQuickItem *m_editView3DRootItem = nullptr; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 907896cdd46..c8bbc46ddb8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -57,7 +57,6 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo InstanceContainer::NodeFlags flags) { ObjectNodeInstance::initialize(objectNodeInstance, flags); - setPickable(true, true, false); } Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const @@ -74,71 +73,6 @@ QQuick3DNode *Quick3DNodeInstance::quick3DNode() const #endif } -void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildInstances) -{ -#ifdef QUICK3D_MODULE - auto node = quick3DNode(); - if (node) { - bool parentHidden = false; - if (checkParent) { - // First check if any parent node is already hidden. Never set pickable on that case. - auto parentNode = node->parentNode(); - while (parentNode && !parentHidden) { - parentHidden = QQuick3DNodePrivate::get(parentNode)->m_isHiddenInEditor; - parentNode = parentNode->parentNode(); - } - - } - if (!parentHidden) { - auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * { - if (nodeInstanceServer()->hasInstanceForObject(obj)) { - ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj); - if (instance.isValid() && qobject_cast(instance.internalObject())) - return static_cast(instance.internalInstance().data()); - } - return nullptr; - }; - const auto childItems = node->childItems(); - for (auto childItem : childItems) { - if (auto quick3dInstance = getQuick3DInstance(childItem)) { - if (applyToChildInstances) { - // Don't override explicit block in children - if (!QQuick3DNodePrivate::get(quick3dInstance->quick3DNode())->m_isHiddenInEditor) - quick3dInstance->setPickable(enable, false, true); - } - } else { - // Children of components do not have instances, but will still need to be - // pickable. These need to be set even if applyToChildInstances is false. - std::function checkChildren; - checkChildren = [&](QQuick3DNode *checkNode) { - const auto childItems = checkNode->childItems(); - for (auto child : childItems) { - if (auto childNode = qobject_cast(child)) - checkChildren(childNode); - } - if (auto checkModel = qobject_cast(checkNode)) { - QVariant value; - if (enable) - value = QVariant::fromValue(node); - // Specify the actual pick target with dynamic property - checkModel->setProperty("_pickTarget", value); - checkModel->setPickable(enable); - } - }; - checkChildren(node); - } - } - if (qobject_cast(node)) - setPropertyVariant("pickable", enable); // allow 3D objects to receive mouse clicks - } - } -#else - Q_UNUSED(enable) - Q_UNUSED(checkParent) - Q_UNUSED(applyToChildInstances) -#endif -} - Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object) { Pointer instance(new Quick3DNodeInstance(object)); @@ -146,18 +80,13 @@ Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object) return instance; } -void Quick3DNodeInstance::setHideInEditor(bool b) +void Quick3DNodeInstance::setHiddenInEditor(bool b) { + ObjectNodeInstance::setHiddenInEditor(b); #ifdef QUICK3D_MODULE QQuick3DNodePrivate *privateNode = QQuick3DNodePrivate::get(quick3DNode()); - if (privateNode) { + if (privateNode) privateNode->setIsHiddenInEditor(b); - - // Hidden objects should not be pickable - setPickable(!b, true, true); - } -#else - Q_UNUSED(b) #endif } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h index 7b48ea9193f..892946ee1f6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -43,7 +43,7 @@ public: ~Quick3DNodeInstance() override; static Pointer create(QObject *objectToBeWrapped); - void setHideInEditor(bool b) override; + void setHiddenInEditor(bool b) override; void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, InstanceContainer::NodeFlags flags) override; @@ -53,7 +53,6 @@ protected: private: Qt5NodeInstanceServer *qt5NodeInstanceServer() const; QQuick3DNode *quick3DNode() const; - void setPickable(bool enable, bool checkParent, bool applyToChildInstances); }; } // namespace Internal diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 511a89b62b2..f53e31b49f2 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -270,6 +270,9 @@ ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceSe instance.internalInstance()->initialize(instance.m_nodeInstance, instanceContainer.metaFlags()); + // Handle hidden state to initialize pickable state + nodeInstanceServer->handleInstanceHidden(instance, false, false); + return instance; } @@ -346,9 +349,16 @@ void ServerNodeInstance::setPropertyBinding(const PropertyName &name, const QStr m_nodeInstance->setPropertyBinding(name, expression); } -void ServerNodeInstance::setHideInEditor(bool b) +void ServerNodeInstance::setHiddenInEditor(bool b) { - m_nodeInstance->setHideInEditor(b); + m_nodeInstance->setHiddenInEditor(b); + m_nodeInstance->nodeInstanceServer()->handleInstanceHidden(*this, b, true); +} + +void ServerNodeInstance::setLockedInEditor(bool b) +{ + m_nodeInstance->setLockedInEditor(b); + m_nodeInstance->nodeInstanceServer()->handleInstanceLocked(*this, b, true); } void ServerNodeInstance::resetProperty(const PropertyName &name) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 9150b2bd4ec..786a09fd476 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -185,7 +185,8 @@ private: // functions void setPropertyBinding(const PropertyName &name, const QString &expression); - void setHideInEditor(bool b); + void setHiddenInEditor(bool b); + void setLockedInEditor(bool b); void resetProperty(const PropertyName &name); void refreshProperty(const PropertyName &name); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index de3757e68c7..cf93c81c121 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -102,14 +102,21 @@ void Edit3DCanvas::resizeEvent(QResizeEvent *e) void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e) { - QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); - if (!data.isEmpty()) { - QDataStream stream(data); - stream >> m_itemLibraryEntry; - bool canDrop = NodeHints::fromItemLibraryEntry(m_itemLibraryEntry).canBeDroppedInView3D(); + // Block all drags if scene root node is locked + ModelNode node; + if (m_parent->view()->hasModelNodeForInternalId(m_activeScene)) + node = m_parent->view()->modelNodeForInternalId(m_activeScene); - if (canDrop) - e->accept(); + // Allow drop when there is no valid active scene, as the drop goes under the root node of + // the document in that case. + if (!node.isValid() || !ModelNode::isThisOrAncestorLocked(node)) { + QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); + if (!data.isEmpty()) { + QDataStream stream(data); + stream >> m_itemLibraryEntry; + if (NodeHints::fromItemLibraryEntry(m_itemLibraryEntry).canBeDroppedInView3D()) + e->accept(); + } } }