From 6b17cd91a6501394e34512898089d935fc804470 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 25 Oct 2019 16:37:33 +0200 Subject: [PATCH] QmlDesigner: Use transactions in 3D Edit View We send a ValuesModifiedCommand 'immediately' when the item is moved. This means the 2D form editor and property editor update while moving nodes in the 3D edit view. The updates are 'compressed' by 100ms. This is to avoid performance issues. The timer could be reduced to 50ms or even 10ms, but 100ms feel acceptable at least for me. The code was a bit refactored. Qt5InformationNodeInstanceServer::modifyVariantValue() can be used later to update other Vector3D based properties like rotation and scale. There is one issue left. MouseArea3D emits 'onReleased' only after the mouse is moved again. This delays the 'commit' of the transaction which is annoying and can triggers bugs. Change-Id: I834a1e2658278ff8dd39678f39e51735dee91b65 Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../qml/qmlpuppet/mockfiles/Arrow.qml | 2 + .../qml/qmlpuppet/mockfiles/EditView3D.qml | 3 + .../qml/qmlpuppet/mockfiles/MoveGizmo.qml | 4 ++ .../qt5informationnodeinstanceserver.cpp | 56 ++++++++++++++++--- .../qt5informationnodeinstanceserver.h | 11 ++++ 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml index dc2fee64543..e8a45b8e058 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -43,6 +43,7 @@ Model { property var _targetStartPos signal positionCommit() + signal positionMove() materials: DefaultMaterial { id: material @@ -85,6 +86,7 @@ Model { return; targetNode.position = posInParent(mouseArea, pointerPosition); + arrow.positionMove(); } function handleReleased(mouseArea, pointerPosition) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index a0a9c0e5998..dc031d2820d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -46,6 +46,7 @@ Window { signal objectClicked(var object) signal commitObjectPosition(var object) + signal moveObjectPosition(var object) function selectObject(object) { selectedNode = object; @@ -70,6 +71,7 @@ Window { targetNode: viewWindow.selectedNode position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) + rotation: globalControl.checked || !viewWindow.selectedNode ? Qt.vector3d(0, 0, 0) : viewWindow.selectedNode.sceneRotation @@ -78,6 +80,7 @@ Window { view3D: overlayView onPositionCommit: viewWindow.commitObjectPosition(selectedNode) + onPositionMove: viewWindow.moveObjectPosition(selectedNode) } AutoScaleHelper { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml index 73b80018a92..d6e7e918497 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml @@ -41,6 +41,7 @@ Node { property alias arrowZ: arrowZ signal positionCommit() + signal positionMove() Arrow { id: arrowX @@ -52,6 +53,7 @@ Node { view3D: arrows.view3D onPositionCommit: arrows.positionCommit() + onPositionMove: arrows.positionMove() } Arrow { @@ -64,6 +66,7 @@ Node { view3D: arrows.view3D onPositionCommit: arrows.positionCommit() + onPositionMove: arrows.positionMove() } Arrow { @@ -76,5 +79,6 @@ Node { view3D: arrows.view3D onPositionCommit: arrows.positionCommit() + onPositionMove: arrows.positionMove() } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index b1fa8be60d5..a2dc7c541ae 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -98,6 +98,10 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant))); QObject::connect(window, SIGNAL(commitObjectPosition(QVariant)), this, SLOT(handleObjectPositionCommit(QVariant))); + QObject::connect(window, SIGNAL(moveObjectPosition(QVariant)), + this, SLOT(handleObjectPositionMove(QVariant))); + QObject::connect(&m_moveTimer, &QTimer::timeout, + this, &Qt5InformationNodeInstanceServer::handleObjectPositionMoveTimeout); //For macOS we have to use the 4.1 core profile QSurfaceFormat surfaceFormat = window->requestedFormat(); @@ -149,21 +153,54 @@ Qt5InformationNodeInstanceServer::vectorToPropertyValue( return result; } +void Qt5InformationNodeInstanceServer::modifyVariantValue( + const QVariant &node, + const PropertyName &propertyName, + ValuesModifiedCommand::TransactionOption option) +{ + PropertyName targetPopertyName; + + // Position is a special case, because the position can be 'position.x 'or simply 'x'. + // We prefer 'x'. + if (propertyName != "position") + targetPopertyName = propertyName; + + auto *obj = node.value(); + if (obj) { + // We do have to split position into position.x, position.y, position.z + ValuesModifiedCommand command = createValuesModifiedCommand(vectorToPropertyValue( + instanceForObject(obj), + targetPopertyName, + obj->property(propertyName))); + + command.transactionOption = option; + + nodeInstanceClient()->valuesModified(command); + } +} + void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object) { - auto *obj = object.value(); - if (obj) { - /* We do have to split position into position.x, position.y, position.z */ - nodeInstanceClient()->valuesModified(createValuesModifiedCommand(vectorToPropertyValue( - instanceForObject(obj), - "position", - obj->property("position")))); + modifyVariantValue(object, "position", ValuesModifiedCommand::TransactionOption::End); + m_movedNode = {}; + m_moveTimer.stop(); +} + +void Qt5InformationNodeInstanceServer::handleObjectPositionMove(const QVariant &object) +{ + if (m_movedNode.isNull()) { + modifyVariantValue(object, "position", ValuesModifiedCommand::TransactionOption::Start); + } else { + if (!m_moveTimer.isActive()) + m_moveTimer.start(); } + m_movedNode = object; } Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : Qt5NodeInstanceServer(nodeInstanceClient) { + m_moveTimer.setInterval(100); } void Qt5InformationNodeInstanceServer::sendTokenBack() @@ -236,6 +273,11 @@ void Qt5InformationNodeInstanceServer::modifyProperties( nodeInstanceClient()->valuesModified(createValuesModifiedCommand(properties)); } +void Qt5InformationNodeInstanceServer::handleObjectPositionMoveTimeout() +{ + modifyVariantValue(m_movedNode, "position", ValuesModifiedCommand::TransactionOption::None); +} + QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( const QList &instanceList) const { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index c574a6ed11d..c8dfceed2f9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -27,6 +27,10 @@ #include "qt5nodeinstanceserver.h" #include "tokencommand.h" +#include "valueschangedcommand.h" + +#include +#include namespace QmlDesigner { @@ -47,6 +51,7 @@ public: private slots: void objectClicked(const QVariant &object); void handleObjectPositionCommit(const QVariant &object); + void handleObjectPositionMove(const QVariant &object); protected: void collectItemChangesAndSendChangeCommands() override; @@ -58,17 +63,23 @@ protected: void modifyProperties(const QVector &properties); private: + void handleObjectPositionMoveTimeout(); QObject *createEditView3D(QQmlEngine *engine); void setup3DEditView(const QList &instanceList); QObject *findRootNodeOf3DViewport(const QList &instanceList) const; QVector vectorToPropertyValue(const ServerNodeInstance &instance, const PropertyName &propertyName, const QVariant &variant); + void modifyVariantValue(const QVariant &node, + const PropertyName &propertyName, + ValuesModifiedCommand::TransactionOption option); QObject *m_editView3D = nullptr; QSet m_parentChangedSet; QList m_completedComponentList; QList m_tokenList; + QTimer m_moveTimer; + QVariant m_movedNode; }; } // namespace QmlDesigner