diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp index ae94ed79812..211fe6d54bd 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp @@ -33,9 +33,18 @@ namespace QmlDesigner { View3DActionCommand::View3DActionCommand(Type type, bool enable) : m_type(type) , m_enabled(enable) + , m_position(0) { } +View3DActionCommand::View3DActionCommand(int pos) + : m_type(ParticlesSeek) + , m_enabled(true) + , m_position(pos) +{ + +} + bool View3DActionCommand::isEnabled() const { return m_enabled; @@ -46,10 +55,16 @@ View3DActionCommand::Type View3DActionCommand::type() const return m_type; } +int View3DActionCommand::position() const +{ + return m_position; +} + QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command) { out << qint32(command.isEnabled()); out << qint32(command.type()); + out << qint32(command.position()); return out; } @@ -58,10 +73,13 @@ QDataStream &operator>>(QDataStream &in, View3DActionCommand &command) { qint32 enabled; qint32 type; + qint32 pos; in >> enabled; in >> type; + in >> pos; command.m_enabled = bool(enabled); command.m_type = View3DActionCommand::Type(type); + command.m_position = pos; return in; } diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index 332b6006c39..c564bb2ec59 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -44,18 +44,34 @@ public: CameraToggle, OrientationToggle, EditLightToggle, - ShowGrid + ShowGrid, + Edit3DParticleModeToggle, + ParticlesPlay, + ParticlesRestart, + ParticlesSeek, }; explicit View3DActionCommand(Type type, bool enable); + View3DActionCommand() = default; bool isEnabled() const; Type type() const; + int position() const; private: Type m_type = Empty; bool m_enabled = false; + int m_position = 0; + +protected: + View3DActionCommand(int pos); +}; + +class View3DSeekActionCommand : public View3DActionCommand +{ +public: + View3DSeekActionCommand(int pos) : View3DActionCommand(pos) {} }; QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.cpp new file mode 100644 index 00000000000..4f32513b7ec --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "animationdriver.h" +#include "private/qabstractanimation_p.h" + +AnimationDriver::AnimationDriver(QObject *parent) + : QAnimationDriver(parent) +{ + setProperty("allowNegativeDelta", true); + install(); + connect(this, SIGNAL(started()), this, SLOT(startTimer())); + connect(this, SIGNAL(stopped()), this, SLOT(stopTimer())); +} + +AnimationDriver::~AnimationDriver() +{ + +} + +void AnimationDriver::timerEvent(QTimerEvent *e) +{ + Q_ASSERT(e->timerId() == m_timer.timerId()); + Q_UNUSED(e); + + quint32 old = elapsed(); + // Provide same time for all users + if (m_seekerEnabled) { + m_seekerElapsed += (m_seekerPos * 100) / 30; + if (m_seekerElapsed + m_elapsed < -100) // -100 to allow small negative value + m_seekerElapsed = -m_elapsed - 100; + } else { + m_elapsed = QAnimationDriver::elapsed(); + } + m_delta = elapsed() - old; + advance(); + Q_EMIT advanced(); +} + +void AnimationDriver::startTimer() +{ + m_timer.start(m_interval, Qt::PreciseTimer, this); +} + +void AnimationDriver::stopTimer() +{ + m_timer.stop(); +} + +void AnimationDriver::setSeekerPosition(int position) +{ + if (!m_seekerEnabled) + return; + + if (!m_timer.isActive()) + restart(); + + m_seekerPos = position; +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.h new file mode 100644 index 00000000000..f4f50f0afcd --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/animationdriver.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +class AnimationDriver : public QAnimationDriver +{ + Q_OBJECT +public: + AnimationDriver(QObject *parent = nullptr); + ~AnimationDriver(); + void timerEvent(QTimerEvent *e) override; + void setInterval(int interval) + { + m_interval = qBound(1, interval, 60); + } + int interval() const + { + return m_interval; + } + void reset() + { + stop(); + stopTimer(); + } + void restart() + { + start(); + startTimer(); + } + qint64 elapsed() const override + { + return m_elapsed + m_seekerElapsed; + } + void setSeekerPosition(int position); + void setSeekerEnabled(bool enable) + { + m_seekerEnabled = enable; + } + bool isSeekerEnabled() const + { + return m_seekerEnabled; + } + bool isAnimating() const + { + return (!m_seekerEnabled && m_timer.isActive()) || (m_seekerEnabled && m_delta && m_seekerPos); + } +Q_SIGNALS: + void advanced(); + +private: + Q_SLOT void startTimer(); + Q_SLOT void stopTimer(); + + QBasicTimer m_timer; + int m_interval = 16; + int m_seekerPos = 0; + bool m_seekerEnabled = false; + qint64 m_elapsed = 0; + qint64 m_seekerElapsed = 0; + qint64 m_delta = 0; +}; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri index ff3ee9394b9..59ac62420c9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri @@ -44,6 +44,8 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \ $$PWD/qt3dpresentationnodeinstance.h \ $$PWD/quick3dnodeinstance.h \ $$PWD/quick3dtexturenodeinstance.h \ + $$PWD/viewconfig.h \ + $$PWD/animationdriver.h SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ @@ -74,4 +76,6 @@ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ $$PWD/layoutnodeinstance.cpp \ $$PWD/qt3dpresentationnodeinstance.cpp \ $$PWD/quick3dnodeinstance.cpp \ - $$PWD/quick3dtexturenodeinstance.cpp + $$PWD/quick3dtexturenodeinstance.cpp \ + $$PWD/viewconfig.cpp \ + $$PWD/animationdriver.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index bd3994400ba..c1c086c58d6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -332,7 +332,8 @@ void NodeInstanceServer::createScene(const CreateSceneCommand &command) registerFonts(command.resourceUrl); setTranslationLanguage(command.language); - Internal::QmlPrivateGate::stopUnifiedTimer(); + if (!ViewConfig::isParticleViewMode()) + Internal::QmlPrivateGate::stopUnifiedTimer(); setupScene(command); setupState(command.stateInstanceId); @@ -783,6 +784,15 @@ QList NodeInstanceServer::allSubContextsForObject(QObject *object return contextList; } +QList NodeInstanceServer::allSubObjectsForObject(QObject *object) +{ + QList subChildren; + if (object) + subChildren = object->findChildren(); + + return subChildren; +} + void NodeInstanceServer::removeAllInstanceRelationships() { for (ServerNodeInstance &instance : m_objectInstanceHash) { @@ -1563,4 +1573,39 @@ bool NodeInstanceServer::isInformationServer() const return false; } +static QString baseProperty(const QString &property) +{ + int index = property.indexOf('.'); + if (index > 0) + return property.left(index); + return property; +} + +void NodeInstanceServer::addAnimation(QQuickAbstractAnimation *animation) +{ + if (!m_animations.contains(animation)) { + m_animations.push_back(animation); + + QQuickPropertyAnimation *panim = qobject_cast(animation); + if (panim) { + QObject *target = panim->target(); + QString property = panim->property(); + QVariant value = target->property(qPrintable(baseProperty(property))); + m_defaultValues.push_back(value); + } else { + m_defaultValues.push_back({}); + } + } +} + +QVector NodeInstanceServer::animations() const +{ + return m_animations; +} + +QVariant NodeInstanceServer::animationDefaultValue(int index) const +{ + return m_defaultValues.at(index); +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 47dfd6c0b50..f2255bd891d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -43,6 +43,20 @@ #include #include "servernodeinstance.h" #include "debugoutputcommand.h" +#include "viewconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include namespace QtHelpers { template @@ -217,6 +231,9 @@ public: virtual QImage grabItem(QQuickItem *item) = 0; virtual bool isInformationServer() const; + void addAnimation(QQuickAbstractAnimation *animation); + QVector animations() const; + QVariant animationDefaultValue(int index) const; public slots: void refreshLocalFileProperty(const QString &path); @@ -291,7 +308,8 @@ protected: void setupDefaultDummyData(); QList setupInstances(const CreateSceneCommand &command); - QList allSubContextsForObject(QObject *object); + QList allSubContextsForObject(QObject *object); + static QList allSubObjectsForObject(QObject *object); virtual void resizeCanvasToRootItem() = 0; void setupState(qint32 stateInstanceId); @@ -322,6 +340,8 @@ private: std::unique_ptr multilanguageLink; int m_needsExtraRenderCount = 0; int m_extraRenderCurrentPass = 0; + QVector m_animations; + QVector m_defaultValues; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index ee20e5636c4..419e75cfa04 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -87,6 +87,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include @@ -103,10 +104,6 @@ #endif #endif -#ifdef QUICK3D_PARTICLES_MODULE -#include -#endif - #ifdef IMPORT_QUICK3D_ASSETS #include #endif @@ -216,7 +213,7 @@ void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url, void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet &instances) { - if (!isQuick3DMode()) + if (!ViewConfig::isQuick3DMode()) return; // We only want to update the topmost parents in the set @@ -406,9 +403,83 @@ void Qt5InformationNodeInstanceServer::createEditView3D() #endif } +#ifdef QUICK3D_PARTICLES_MODULE +void Qt5InformationNodeInstanceServer::resetParticleSystem() +{ + if (!m_targetParticleSystem) + return; + m_targetParticleSystem->reset(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2) + m_targetParticleSystem->setEditorTime(0); +#endif + if (m_particleAnimationDriver) + m_particleAnimationDriver->reset(); +} + +void Qt5InformationNodeInstanceServer::handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem) +{ + if (!m_particleAnimationDriver) + return; + + m_particleAnimationDriver->reset(); + // stop the previously selected from animating + resetParticleSystem(); + + m_targetParticleSystem = targetParticleSystem; + + resetParticleSystem(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2) + QObject::disconnect(m_particleAnimationConnection); + m_particleAnimationConnection = connect(m_particleAnimationDriver, &AnimationDriver::advanced, [this] () { + if (m_targetParticleSystem) + m_targetParticleSystem->setEditorTime(m_particleAnimationDriver->elapsed()); + }); +#endif + if (m_particleAnimationPlaying && m_targetParticleSystem->visible()) + m_particleAnimationDriver->restart(); + QObject::connect(m_targetParticleSystem, &QQuick3DNode::visibleChanged, [this] () { + if (m_particleAnimationPlaying && m_targetParticleSystem->visible()) { + m_particleAnimationDriver->restart(); + } else { + m_particleAnimationDriver->reset(); + resetParticleSystem(); + } + }); + + const auto anim = animations(); + for (auto a : anim) + a->restart(); +} + +static QString baseProperty(const QString &property) +{ + int index = property.indexOf('.'); + if (index > 0) + return property.left(index); + return property; +} + +void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected() +{ + m_targetParticleSystem = nullptr; + const auto anim = animations(); + int i = 0; + for (auto a : anim) { + a->stop(); + QQuickPropertyAnimation *panim = qobject_cast(a); + if (panim) + panim->target()->setProperty(qPrintable(baseProperty(panim->property())), animationDefaultValue(i)); + i++; + } +} +#endif + // The selection has changed in the edit view 3D. Empty list indicates selection is cleared. void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs) { +#ifdef QUICK3D_PARTICLES_MODULE + resetParticleSystem(); +#endif QList instanceList; const QVariantList varObjs = objs.value(); for (const auto &object : varObjs) { @@ -829,6 +900,12 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() m_render3DEditViewTimer.start(0); --m_need3DEditViewRender; } +#ifdef QUICK3D_PARTICLES_MODULE + if (ViewConfig::isParticleViewMode() + && m_particleAnimationDriver && m_particleAnimationDriver->isAnimating()) { + m_need3DEditViewRender++; + } +#endif #ifdef FPS_COUNTER // Force constant rendering for accurate fps count if (!m_render3DEditViewTimer.isActive()) @@ -1084,6 +1161,12 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC _fpsTimer->start(); } #endif +#ifdef QUICK3D_PARTICLES_MODULE + if (ViewConfig::isParticleViewMode()) { + m_particleAnimationDriver = new AnimationDriver(this); + m_particleAnimationDriver->setInterval(17); + } +#endif } Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() @@ -1205,7 +1288,7 @@ QList Qt5InformationNodeInstanceServer::createInstances( void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews() { #ifdef QUICK3D_MODULE - if (isQuick3DMode()) + if (ViewConfig::isQuick3DMode()) createEditView3D(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"), @@ -1665,7 +1748,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com sendChildrenChangedCommand(instanceList); nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList)); - if (isQuick3DMode()) { + if (ViewConfig::isQuick3DMode()) { setup3DEditView(instanceList, command.edit3dToolStates); updateRotationBlocks(command.auxiliaryChanges); } @@ -1735,7 +1818,9 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm { if (!m_editView3DSetupDone) return; - +#ifdef QUICK3D_PARTICLES_MODULE + resetParticleSystem(); +#endif m_lastSelectionChangeCommand = command; if (m_selectionChangeTimer.isActive()) { // If selection was recently changed by puppet, hold updating the selection for a bit to @@ -1762,13 +1847,17 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm if (firstSceneRoot && sceneRoot == firstSceneRoot && instance.isSubclassOf("QQuick3DNode")) object = instance.internalObject(); +#ifdef QUICK3D_PARTICLES_MODULE + auto particlesystem = qobject_cast(instance.internalObject()); + if (particlesystem) + handleParticleSystemSelected(particlesystem); + else + handleParticleSystemDeselected(); +#endif auto isSelectableAsRoot = [&]() -> bool { #ifdef QUICK3D_MODULE if (qobject_cast(object) || qobject_cast(object) -#ifdef QUICK3D_PARTICLES_MODULE - || qobject_cast(object) -#endif || qobject_cast(object)) { return true; } @@ -1900,6 +1989,33 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionCommand::ShowGrid: updatedState.insert("showGrid", command.isEnabled()); break; +#ifdef QUICK3D_PARTICLES_MODULE + case View3DActionCommand::Edit3DParticleModeToggle: + updatedState.insert("enableParticleViewMode", command.isEnabled()); + break; + case View3DActionCommand::ParticlesPlay: + m_particleAnimationPlaying = command.isEnabled(); + if (m_particleAnimationPlaying) { + m_particleAnimationDriver->reset(); + m_particleAnimationDriver->restart(); + m_particleAnimationDriver->setSeekerEnabled(false); + m_particleAnimationDriver->setSeekerPosition(0); + } else { + m_particleAnimationDriver->reset(); + m_particleAnimationDriver->setSeekerEnabled(true); + } + break; + case View3DActionCommand::ParticlesRestart: + resetParticleSystem(); + m_particleAnimationPlaying = true; + m_particleAnimationDriver->restart(); + m_particleAnimationDriver->setSeekerEnabled(false); + m_particleAnimationDriver->setSeekerPosition(0); + break; + case View3DActionCommand::ParticlesSeek: + m_particleAnimationDriver->setSeekerPosition(static_cast(command).position()); + break; +#endif default: break; } @@ -1977,7 +2093,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst bool enable, bool checkAncestors) { #ifdef QUICK3D_MODULE - if (!isQuick3DMode()) + if (!ViewConfig::isQuick3DMode()) return; bool edit3dLocked = enable; @@ -2015,7 +2131,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst bool enable, bool checkAncestors) { #ifdef QUICK3D_MODULE - if (!isQuick3DMode()) + if (!ViewConfig::isQuick3DMode()) return; bool edit3dHidden = enable; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index d827075c452..25a4b900ce8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -32,8 +32,14 @@ #include "requestmodelnodepreviewimagecommand.h" #include "propertybindingcontainer.h" #include "propertyabstractcontainer.h" +#include "animationdriver.h" + +#ifdef QUICK3D_PARTICLES_MODULE +#include +#endif #include +#include #include #include #include @@ -140,6 +146,11 @@ private: void removeRotationBlocks(const QVector &instanceIds); void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); +#ifdef QUICK3D_PARTICLES_MODULE + void handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem); + void resetParticleSystem(); + void handleParticleSystemDeselected(); +#endif RenderViewData m_editView3DData; RenderViewData m_modelNode3DImageViewData; @@ -161,6 +172,12 @@ private: QTimer m_render3DEditViewTimer; QTimer m_renderModelNodeImageViewTimer; QTimer m_inputEventTimer; +#ifdef QUICK3D_PARTICLES_MODULE + bool m_particleAnimationPlaying = true; + AnimationDriver *m_particleAnimationDriver = nullptr; + QMetaObject::Connection m_particleAnimationConnection; + QQuick3DParticleSystem* m_targetParticleSystem = nullptr; +#endif QObjectList m_changedNodes; QList m_changedProperties; ChangeSelectionCommand m_lastSelectionChangeCommand; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp index 44eaab88d22..8b1221a4f44 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp @@ -82,6 +82,7 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) : setNodeInstanceServer(std::make_unique(this)); initializeSocket(); } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) { + ViewConfig::enableParticleView(true); setNodeInstanceServer(std::make_unique(this)); initializeSocket(); } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 9f8f5caf528..dbffe2f4fbe 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -60,7 +60,8 @@ namespace QmlDesigner { Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : NodeInstanceServer(nodeInstanceClient) { - DesignerSupport::activateDesignerMode(); + if (!ViewConfig::isParticleViewMode()) + DesignerSupport::activateDesignerMode(); } Qt5NodeInstanceServer::~Qt5NodeInstanceServer() diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.cpp new file mode 100644 index 00000000000..4a20bfcc406 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "viewconfig.h" +#include + +bool ViewConfig::isQuick3DMode() +{ + static bool mode3D = qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE"); + return mode3D; +} + +static bool particleViewEnabled = false; +void ViewConfig::enableParticleView(bool enable) +{ + particleViewEnabled = enable; +} + +bool ViewConfig::isParticleViewMode() +{ + static bool particleviewmode = !qEnvironmentVariableIsSet("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS"); + return particleviewmode && particleViewEnabled; +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.h new file mode 100644 index 00000000000..dcb51551d74 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/viewconfig.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +class ViewConfig +{ +public: + static bool isQuick3DMode(); + static void enableParticleView(bool enable); + static bool isParticleViewMode(); +}; diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp index e920263e1bd..195fd805f47 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,19 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + namespace QmlDesigner { namespace Internal { @@ -382,8 +396,15 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta static_cast(item)->componentComplete(); } else { QQmlParserStatus *qmlParserStatus = dynamic_cast(object); - if (qmlParserStatus) + if (qmlParserStatus) { qmlParserStatus->componentComplete(); + auto *anim = dynamic_cast(object); + if (anim && ViewConfig::isParticleViewMode()) { + nodeInstanceServer->addAnimation(anim); + anim->setEnableUserControl(); + anim->stop(); + } + } } } } diff --git a/src/libs/clangsupport/diagnosticcontainer.cpp b/src/libs/clangsupport/diagnosticcontainer.cpp index 889e51d650c..1f7c013f0b5 100644 --- a/src/libs/clangsupport/diagnosticcontainer.cpp +++ b/src/libs/clangsupport/diagnosticcontainer.cpp @@ -47,5 +47,17 @@ QDebug operator<<(QDebug debug, const DiagnosticContainer &container) return debug; } +QDebug operator<<(QDebug debug, const QVector &containers) +{ + debug.nospace() << "{"; + for (int i = 0; i < containers.size(); i++) { + debug.nospace() << containers[i]; + if (i < containers.size() - 1) + debug.nospace() << ", "; + } + debug.nospace() << "}"; + return debug; +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/diagnosticcontainer.h b/src/libs/clangsupport/diagnosticcontainer.h index f8344ccf767..65306bf8a6b 100644 --- a/src/libs/clangsupport/diagnosticcontainer.h +++ b/src/libs/clangsupport/diagnosticcontainer.h @@ -123,5 +123,8 @@ public: }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const DiagnosticContainer &container); +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector &container); + + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/fixitcontainer.cpp b/src/libs/clangsupport/fixitcontainer.cpp index 29caaf71018..7b1404ac9ec 100644 --- a/src/libs/clangsupport/fixitcontainer.cpp +++ b/src/libs/clangsupport/fixitcontainer.cpp @@ -39,5 +39,17 @@ QDebug operator<<(QDebug debug, const FixItContainer &container) return debug; } +QDebug operator<<(QDebug debug, const QVector &containers) +{ + debug.nospace() << "{"; + for (int i = 0; i < containers.size(); i++) { + debug.nospace() << containers[i]; + if (i < containers.size() - 1) + debug.nospace() << ", "; + } + debug.nospace() << "}"; + return debug; +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/fixitcontainer.h b/src/libs/clangsupport/fixitcontainer.h index e13199712ef..81667fe76e0 100644 --- a/src/libs/clangsupport/fixitcontainer.h +++ b/src/libs/clangsupport/fixitcontainer.h @@ -69,5 +69,6 @@ public: }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FixItContainer &container); +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector &container); } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/sourcerangecontainer.cpp b/src/libs/clangsupport/sourcerangecontainer.cpp index 81348356285..d9146d0ff33 100644 --- a/src/libs/clangsupport/sourcerangecontainer.cpp +++ b/src/libs/clangsupport/sourcerangecontainer.cpp @@ -39,4 +39,16 @@ QDebug operator<<(QDebug debug, const SourceRangeContainer &container) return debug; } +QDebug operator<<(QDebug debug, const QVector &containers) +{ + debug.nospace() << "{"; + for (int i = 0; i < containers.size(); i++) { + debug.nospace() << containers[i]; + if (i < containers.size() - 1) + debug.nospace() << ", "; + } + debug.nospace() << "}"; + return debug; +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/sourcerangecontainer.h b/src/libs/clangsupport/sourcerangecontainer.h index 603143e210a..39a0e6cb210 100644 --- a/src/libs/clangsupport/sourcerangecontainer.h +++ b/src/libs/clangsupport/sourcerangecontainer.h @@ -85,5 +85,6 @@ public: }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const SourceRangeContainer &container); +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector &container); } // namespace ClangBackEnd diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 8af14b2550e..901a631a421 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -202,6 +202,7 @@ extend_qtc_plugin(QmlDesigner rubberbandselectionmanipulator.cpp rubberbandselectionmanipulator.h scaleitem.cpp scaleitem.h scalemanipulator.cpp scalemanipulator.h + seekerslider.cpp seekerslider.h selectionindicator.cpp selectionindicator.h selectionrectangle.cpp selectionrectangle.h selectiontool.cpp selectiontool.h diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc index 69e7113f023..13ac3b0a499 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc @@ -34,5 +34,15 @@ images/select_item@2x.png images/orthographic_camera.png images/orthographic_camera@2x.png - + images/particles_off.png + images/particles_off@2x.png + images/particles_on.png + images/particles_on@2x.png + images/particles_play.png + images/particles_play@2x.png + images/particles_pause.png + images/particles_pause@2x.png + images/particles_restart.png + images/particles_restart@2x.png + diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index e5a8c1747aa..3e08e0fc4e7 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -209,6 +209,11 @@ QSize Edit3DView::canvasSize() const return {}; } +void Edit3DView::setSeeker(SeekerSlider *slider) +{ + m_seeker = slider; +} + void Edit3DView::createEdit3DActions() { m_selectionModeAction @@ -272,9 +277,59 @@ void Edit3DView::createEdit3DActions() Icons::EDIT3D_GRID_ON.icon()); SelectionContextOperation resetTrigger = [this](const SelectionContext &) { + m_particlesPlayAction->action()->setEnabled(particlemode); + m_particlesRestartAction->action()->setEnabled(particlemode); + if (particlemode) + m_particlesPlayAction->action()->setChecked(true); + if (m_seeker) + m_seeker->setEnabled(false); setCurrentStateNode(rootModelNode()); resetPuppet(); }; + + SelectionContextOperation particlesTrigger = [this](const SelectionContext &) { + particlemode = !particlemode; + m_particlesPlayAction->action()->setEnabled(particlemode); + m_particlesRestartAction->action()->setEnabled(particlemode); + if (m_seeker) + m_seeker->setEnabled(false); + QmlDesigner::DesignerSettings::setValue("particleMode", particlemode); + setCurrentStateNode(rootModelNode()); + resetPuppet(); + }; + + SelectionContextOperation particlesRestartTrigger = [this](const SelectionContext &) { + m_particlesPlayAction->action()->setChecked(true); + if (m_seeker) + m_seeker->setEnabled(false); + }; + + SelectionContextOperation particlesPlayTrigger = [this](const SelectionContext &) { + if (m_seeker) + m_seeker->setEnabled(!m_particlesPlayAction->action()->isChecked()); + }; + + m_particleViewModeAction + = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_PARTICLE_MODE, View3DActionCommand::Edit3DParticleModeToggle, + QCoreApplication::translate("ParticleViewModeAction", "Toggle particle animation On/Off"), + QKeySequence(Qt::Key_V), true, false, Icons::EDIT3D_PARTICLE_OFF.icon(), + Icons::EDIT3D_PARTICLE_ON.icon(), particlesTrigger); + particlemode = false; + m_particlesPlayAction + = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_PARTICLES_PLAY, View3DActionCommand::ParticlesPlay, + QCoreApplication::translate("ParticlesPlayAction", "Play Particles"), + QKeySequence(Qt::Key_W), true, true, Icons::EDIT3D_PARTICLE_PLAY.icon(), + Icons::EDIT3D_PARTICLE_PAUSE.icon(), particlesPlayTrigger); + m_particlesRestartAction + = new Edit3DAction( + QmlDesigner::Constants::EDIT3D_PARTICLES_RESTART, View3DActionCommand::ParticlesRestart, + QCoreApplication::translate("ParticlesRestartAction", "Restart Particles"), + QKeySequence(Qt::Key_E), false, false, Icons::EDIT3D_PARTICLE_RESTART.icon(), + Icons::EDIT3D_PARTICLE_RESTART.icon(), particlesRestartTrigger); + m_particlesPlayAction->action()->setEnabled(particlemode); + m_particlesRestartAction->action()->setEnabled(particlemode); m_resetAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_RESET_VIEW, View3DActionCommand::Empty, @@ -296,6 +351,10 @@ void Edit3DView::createEdit3DActions() m_leftActions << m_editLightAction; m_leftActions << m_showGridAction; + m_rightActions << m_particleViewModeAction; + m_rightActions << m_particlesPlayAction; + m_rightActions << m_particlesRestartAction; + m_rightActions << nullptr; m_rightActions << m_resetAction; } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 6c3ae892a91..2001dbbcf4d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -25,6 +25,7 @@ #pragma once #include "view3dactioncommand.h" +#include "seekerslider.h" #include #include @@ -68,6 +69,7 @@ public: void createEdit3DActions(); QVector leftActions() const; QVector rightActions() const; + void setSeeker(SeekerSlider *slider); void addQuick3DImport(); @@ -90,6 +92,11 @@ private: Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; Edit3DAction *m_resetAction = nullptr; + Edit3DAction *m_particleViewModeAction = nullptr; + Edit3DAction *m_particlesPlayAction = nullptr; + Edit3DAction *m_particlesRestartAction = nullptr; + SeekerSlider *m_seeker = nullptr; + int particlemode; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 968cab58466..57a4877301d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -33,6 +33,8 @@ #include "qmldesignerplugin.h" #include "qmlvisualnode.h" #include "viewmanager.h" +#include +#include #include #include @@ -64,8 +66,11 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : fillLayout->setSpacing(0); setLayout(fillLayout); + SeekerSlider *seeker = new SeekerSlider(this); + seeker->setEnabled(false); + // Initialize toolbar - m_toolBox = new ToolBox(this); + m_toolBox = new ToolBox(seeker, this); fillLayout->addWidget(m_toolBox.data()); // Iterate through view actions. A null action indicates a separator and a second null action @@ -100,7 +105,10 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : auto separator = new QAction(this); separator->setSeparator(true); addAction(separator); - m_toolBox->addLeftSideAction(separator); + if (left) + m_toolBox->addLeftSideAction(separator); + else + m_toolBox->addRightSideAction(separator); previousWasSeparator = true; } } @@ -109,6 +117,14 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) : addActionsToToolBox(view->leftActions(), true); addActionsToToolBox(view->rightActions(), false); + view->setSeeker(seeker); + seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); + + QObject::connect(seeker, &SeekerSlider::positionChanged, [this, seeker](){ + QmlDesignerPlugin::instance()->viewManager().nodeInstanceView() + ->view3DAction(View3DSeekActionCommand(seeker->position())); + }); + // Onboarding label contains instructions for new users how to get 3D content into the project m_onboardingLabel = new QLabel(this); QString labelText = diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_off.png b/src/plugins/qmldesigner/components/edit3d/images/particles_off.png new file mode 100644 index 00000000000..8f5c8355414 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_off.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_off@2x.png new file mode 100644 index 00000000000..b77feeee014 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_off@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_on.png b/src/plugins/qmldesigner/components/edit3d/images/particles_on.png new file mode 100644 index 00000000000..c01b374040d Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_on.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_on@2x.png new file mode 100644 index 00000000000..9a0e06578d5 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_on@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_pause.png b/src/plugins/qmldesigner/components/edit3d/images/particles_pause.png new file mode 100644 index 00000000000..89d6fd8211c Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_pause.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_pause@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_pause@2x.png new file mode 100644 index 00000000000..94276bf81e6 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_pause@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_play.png b/src/plugins/qmldesigner/components/edit3d/images/particles_play.png new file mode 100644 index 00000000000..d0c2c58d2b8 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_play.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_play@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_play@2x.png new file mode 100644 index 00000000000..07dedc164ee Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_play@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_restart.png b/src/plugins/qmldesigner/components/edit3d/images/particles_restart.png new file mode 100644 index 00000000000..e427433e4e7 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_restart.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/particles_restart@2x.png b/src/plugins/qmldesigner/components/edit3d/images/particles_restart@2x.png new file mode 100644 index 00000000000..90981337b17 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/particles_restart@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/playpause.png b/src/plugins/qmldesigner/components/edit3d/images/playpause.png new file mode 100644 index 00000000000..c86b8068181 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/playpause.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/playpause@2x.png b/src/plugins/qmldesigner/components/edit3d/images/playpause@2x.png new file mode 100644 index 00000000000..4b92db41cca Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/playpause@2x.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.pri b/src/plugins/qmldesigner/components/formeditor/formeditor.pri index 833260dd1a0..df905d377db 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditor.pri +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.pri @@ -42,7 +42,8 @@ SOURCES += formeditoritem.cpp \ backgroundaction.cpp \ formeditortoolbutton.cpp \ formeditorannotationicon.cpp \ - transitiontool.cpp + transitiontool.cpp \ + seekerslider.cpp HEADERS += formeditorscene.h \ formeditorwidget.h \ @@ -87,6 +88,7 @@ HEADERS += formeditorscene.h \ backgroundaction.h \ formeditortoolbutton.h \ formeditorannotationicon.h \ - transitiontool.h + transitiontool.h \ + seekerslider.h RESOURCES += formeditor.qrc diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.qrc b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc index 45170bde01d..23a15d7effa 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditor.qrc +++ b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc @@ -8,5 +8,11 @@ snapping_and_anchoring@2x.png annotationsIcon.png annotationsIconActive.png + scrubbg.png + scrubbg@2x.png + scrubhandle-24.png + scrubhandle-48.png + scrubhandle-disabled-24.png + scrubhandle-disabled-48.png diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index a777d5df87b..31aa8a4de69 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -139,7 +139,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) addAction(m_rootHeightAction.data()); upperActions.append(m_rootHeightAction.data()); - m_toolBox = new ToolBox(this); + m_toolBox = new ToolBox(nullptr, this); fillLayout->addWidget(m_toolBox.data()); m_toolBox->setLeftSideActions(upperActions); diff --git a/src/plugins/qmldesigner/components/formeditor/scrubbg.png b/src/plugins/qmldesigner/components/formeditor/scrubbg.png new file mode 100644 index 00000000000..ca3237983ac Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubbg.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png b/src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png new file mode 100644 index 00000000000..c8ff06eb3cb Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png new file mode 100644 index 00000000000..60fef1546a6 Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png new file mode 100644 index 00000000000..1613f758ba5 Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-24.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-24.png new file mode 100644 index 00000000000..403e5d655a9 Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-24.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-48.png b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-48.png new file mode 100644 index 00000000000..1f9c10d733f Binary files /dev/null and b/src/plugins/qmldesigner/components/formeditor/scrubhandle-disabled-48.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp new file mode 100644 index 00000000000..c4659dcd651 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "seekerslider.h" +#include + +#include +#include +#include +#include + +namespace QmlDesigner { + +SeekerSlider::SeekerSlider(QWidget *parentWidget) + : QWidget(parentWidget), + m_bgIcon(QLatin1String(":/icon/layout/scrubbg.png")) +{ + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-24.png"), QSize(24, 24)); + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-48.png"), QSize(48, 48)); + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-24.png"), QSize(24, 24), QIcon::Disabled); + m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-48.png"), QSize(48, 48), QIcon::Disabled); + const Utils::Icon bg({{":/icon/layout/scrubbg.png", Utils::Theme::IconsBaseColor}}); + m_bgWidth = bg.pixmap().width(); + m_bgHeight = bg.pixmap().height(); + m_handleWidth = m_bgHeight; + m_handleHeight = m_bgHeight; + int width = m_bgWidth + m_handleWidth * 2; + m_sliderHalfWidth = m_bgWidth / 2; + setMinimumWidth(width); + setMaximumWidth(width); + setProperty("panelwidget", true); + setProperty("panelwidget_singlerow", true); +} + +void SeekerSlider::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + { + QStyleOptionToolBar option; + option.rect = rect(); + option.state = QStyle::State_Horizontal; + style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this); + } + + int x = rect().width() / 2; + int y = rect().height() / 2; + + const QPixmap bg = m_bgIcon.pixmap(QSize(m_bgWidth, m_bgHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On); + painter.drawPixmap(x - m_bgWidth / 2, y - m_bgHeight / 2, bg); + + if (m_moving) { + const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), QIcon::Active, QIcon::On); + painter.drawPixmap(x - m_handleWidth / 2 + m_sliderPos, y - m_handleHeight / 2, handle); + } else { + const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On); + painter.drawPixmap(x - m_handleWidth / 2, y - m_handleHeight / 2, handle); + } +} + +void SeekerSlider::mousePressEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton) { + QWidget::mousePressEvent(event); + return; + } + + int x = rect().width() / 2; + int y = rect().height() / 2; + auto pos = event->localPos(); + if (pos.x() >= x - m_handleWidth / 2 && pos.x() <= x + m_handleWidth / 2 + && pos.y() >= y - m_handleHeight / 2 && pos.y() <= y + m_handleHeight / 2) { + m_moving = true; + m_startPos = pos.x(); + } +} + +void SeekerSlider::mouseMoveEvent(QMouseEvent *event) +{ + if (!m_moving) { + QWidget::mouseMoveEvent(event); + return; + } + + auto pos = event->localPos(); + int delta = pos.x() - m_startPos; + m_sliderPos = qBound(-m_sliderHalfWidth, delta, m_sliderHalfWidth); + delta = m_maxPosition * m_sliderPos / m_sliderHalfWidth; + if (delta != m_position) { + m_position = delta; + Q_EMIT positionChanged(); + update(); + } +} + +void SeekerSlider::mouseReleaseEvent(QMouseEvent *event) +{ + if (!m_moving) { + QWidget::mouseReleaseEvent(event); + return; + } + + m_moving = false; + m_position = 0; + m_startPos = 0; + m_sliderPos = 0; + Q_EMIT positionChanged(); + update(); +} + +int SeekerSlider::position() const +{ + return m_position; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.h b/src/plugins/qmldesigner/components/formeditor/seekerslider.h new file mode 100644 index 00000000000..79b320d6507 --- /dev/null +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#pragma once + +#include +#include +#include + +namespace QmlDesigner { + +class SeekerSlider : public QWidget +{ + Q_OBJECT +public: + SeekerSlider(QWidget *parentWidget); + int position() const; + int maxPosition() const + { + return m_maxPosition; + } + + void setMaxPosition(int pos) + { + m_maxPosition = qMax(0, pos); + } + +Q_SIGNALS: + void positionChanged(); + +protected: + void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + int m_position = 0; + int m_startPos = 0; + int m_sliderPos = 0; + int m_sliderHalfWidth = 0; + int m_maxPosition = 30; + bool m_moving = false; + int m_bgWidth; + int m_bgHeight; + int m_handleWidth; + int m_handleHeight; + QIcon m_bgIcon; + QIcon m_handleIcon; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp index c72db4c37c2..433ddc661b7 100644 --- a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp @@ -33,10 +33,11 @@ namespace QmlDesigner { -ToolBox::ToolBox(QWidget *parentWidget) +ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget) : Utils::StyledBar(parentWidget), m_leftToolBar(new QToolBar(QLatin1String("LeftSidebar"), this)), - m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this)) + m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this)), + m_seeker(seeker) { m_leftToolBar->setFloatable(true); m_leftToolBar->setMovable(true); @@ -62,6 +63,8 @@ ToolBox::ToolBox(QWidget *parentWidget) m_rightToolBar->setOrientation(Qt::Horizontal); horizontalLayout->addWidget(m_leftToolBar); horizontalLayout->addWidget(stretchToolbar); + if (seeker) + horizontalLayout->addWidget(m_seeker); horizontalLayout->addWidget(m_rightToolBar); } @@ -94,4 +97,9 @@ QList ToolBox::actions() const return m_leftToolBar->actions() + m_rightToolBar->actions(); } +SeekerSlider *ToolBox::seeker() const +{ + return m_seeker; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.h b/src/plugins/qmldesigner/components/formeditor/toolbox.h index 72bd0ffb8b5..d1d5676f957 100644 --- a/src/plugins/qmldesigner/components/formeditor/toolbox.h +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.h @@ -25,6 +25,7 @@ #pragma once #include +#include QT_BEGIN_NAMESPACE class QToolBar; @@ -37,16 +38,18 @@ namespace QmlDesigner { class ToolBox : public Utils::StyledBar { public: - ToolBox(QWidget *parentWidget); + ToolBox(SeekerSlider *seeker, QWidget *parentWidget); void setLeftSideActions(const QList &actions); void setRightSideActions(const QList &actions); void addLeftSideAction(QAction *action); void addRightSideAction(QAction *action); QList actions() const; + SeekerSlider *seeker() const; private: QToolBar *m_leftToolBar; QToolBar *m_rightToolBar; + SeekerSlider *m_seeker; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 41563efd417..23014b7ce92 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -533,10 +533,20 @@ QProcessEnvironment PuppetCreator::processEnvironment() const QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0"); if (m_model->hasImport(import, true, true)) environment.set("QMLDESIGNER_QUICK3D_MODE", "true"); + + import = QmlDesigner::Import::createLibraryImport("QtQuick3D.Particles3D", "1.0"); + if (m_model->hasImport(import, true, true)) + environment.set("QMLDESIGNER_QUICK3D_PARTICLES3D_MODE", "true"); + import = QmlDesigner::Import::createLibraryImport("QtCharts", "2.0"); if (m_model->hasImport(import, true, true)) environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true"); - environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1"); + + bool particlemode = QmlDesigner::DesignerSettings::getValue("particleMode").toBool(); + if (!particlemode) + environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1"); + else + environment.set("QT_QUICK3D_EDITOR_PARTICLE_SYSTEMS", "1"); #endif QStringList importPaths = m_model->importPaths(); diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 937cfc8005f..2ed1daeb883 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -64,6 +64,10 @@ const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle"; const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView"; +const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeToggle"; +const char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay"; +const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart"; + const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets"; diff --git a/src/plugins/qmldesigner/qmldesignericons.h b/src/plugins/qmldesigner/qmldesignericons.h index b4a97d8fae8..50e4ea1dd03 100644 --- a/src/plugins/qmldesigner/qmldesignericons.h +++ b/src/plugins/qmldesigner/qmldesignericons.h @@ -51,6 +51,16 @@ const Utils::Icon EDIT3D_LIGHT_ON({ {":/edit3d/images/edit_light_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_LIGHT_OFF({ {":/edit3d/images/edit_light_off.png", Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_PARTICLE_ON({ + {":/edit3d/images/particles_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); +const Utils::Icon EDIT3D_PARTICLE_OFF({ + {":/edit3d/images/particles_off.png", Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_PARTICLE_PLAY({ + {":/edit3d/images/particles_play.png", Utils::Theme::QmlDesigner_HighlightColor}}); +const Utils::Icon EDIT3D_PARTICLE_PAUSE({ + {":/edit3d/images/particles_pause.png", Utils::Theme::QmlDesigner_HighlightColor}}); +const Utils::Icon EDIT3D_PARTICLE_RESTART({ + {":/edit3d/images/particles_restart.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_GRID_ON({ {":/edit3d/images/grid_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); const Utils::Icon EDIT3D_GRID_OFF({ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 6a3e76edac4..4e20e2b52ed 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -577,6 +577,8 @@ Project { "formeditor/scaleitem.h", "formeditor/scalemanipulator.cpp", "formeditor/scalemanipulator.h", + "formeditor/seekerslider.cpp", + "formeditor/seekerslider.h", "formeditor/selectionindicator.cpp", "formeditor/selectionindicator.h", "formeditor/selectionrectangle.cpp", diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 4606ee57082..60aaee4a528 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -221,6 +221,8 @@ extend_qtc_executable(qml2puppet nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h qt5captureimagenodeinstanceserver.cpp qt5captureimagenodeinstanceserver.h + viewconfig.cpp viewconfig.h + animationdriver.cpp animationdriver.h ) extend_qtc_executable(qml2puppet diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 83acc77ba36..626aed22255 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -16,7 +16,6 @@ QtcTool { ] } Depends { name: "Qt.quick3d-private"; required: false } - Depends { name: "Qt.quick3dparticles-private"; required: false } property bool useQuick3d: Utilities.versionCompare(Qt.core.version, "5.15") >= 0 && Qt["quick3d-private"].present property bool useParticle3d: Utilities.versionCompare(Qt.core.version, "6.2") >= 0 @@ -249,6 +248,10 @@ QtcTool { "instances/nodeinstanceserverdispatcher.h", "instances/capturenodeinstanceserverdispatcher.cpp", "instances/capturenodeinstanceserverdispatcher.h", + "instances/viewconfig.cpp", + "instances/viewconfig.h", + "instances/animationdriver.cpp", + "instances/animationdriver.h", "editor3d/generalhelper.cpp", "editor3d/mousearea3d.cpp", "editor3d/geometrybase.cpp",