Add particle editor support

Add a way to edit and view particles visually, as editing
only the properties in property editor does not help visualize
how the particle effect is going to look. Support toggling the
effects on/off, pausing, resuming, and scrubbing the time back
and forth. Only the selected particle system is animated to allow
concentrating on that particular system without being confused
by other possible particle systems.

Fixes: QDS-4623
Change-Id: I2677c56a73279d451d77df1d131bd7294e6b23bb
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Tomi Korpipaa
2021-10-19 10:04:15 +03:00
committed by Tomi Korpipää
parent b6c8871dbd
commit 69c8be67ae
56 changed files with 932 additions and 30 deletions

View File

@@ -33,9 +33,18 @@ namespace QmlDesigner {
View3DActionCommand::View3DActionCommand(Type type, bool enable) View3DActionCommand::View3DActionCommand(Type type, bool enable)
: m_type(type) : m_type(type)
, m_enabled(enable) , m_enabled(enable)
, m_position(0)
{ {
} }
View3DActionCommand::View3DActionCommand(int pos)
: m_type(ParticlesSeek)
, m_enabled(true)
, m_position(pos)
{
}
bool View3DActionCommand::isEnabled() const bool View3DActionCommand::isEnabled() const
{ {
return m_enabled; return m_enabled;
@@ -46,10 +55,16 @@ View3DActionCommand::Type View3DActionCommand::type() const
return m_type; return m_type;
} }
int View3DActionCommand::position() const
{
return m_position;
}
QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command) QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command)
{ {
out << qint32(command.isEnabled()); out << qint32(command.isEnabled());
out << qint32(command.type()); out << qint32(command.type());
out << qint32(command.position());
return out; return out;
} }
@@ -58,10 +73,13 @@ QDataStream &operator>>(QDataStream &in, View3DActionCommand &command)
{ {
qint32 enabled; qint32 enabled;
qint32 type; qint32 type;
qint32 pos;
in >> enabled; in >> enabled;
in >> type; in >> type;
in >> pos;
command.m_enabled = bool(enabled); command.m_enabled = bool(enabled);
command.m_type = View3DActionCommand::Type(type); command.m_type = View3DActionCommand::Type(type);
command.m_position = pos;
return in; return in;
} }

View File

@@ -44,18 +44,34 @@ public:
CameraToggle, CameraToggle,
OrientationToggle, OrientationToggle,
EditLightToggle, EditLightToggle,
ShowGrid ShowGrid,
Edit3DParticleModeToggle,
ParticlesPlay,
ParticlesRestart,
ParticlesSeek,
}; };
explicit View3DActionCommand(Type type, bool enable); explicit View3DActionCommand(Type type, bool enable);
View3DActionCommand() = default; View3DActionCommand() = default;
bool isEnabled() const; bool isEnabled() const;
Type type() const; Type type() const;
int position() const;
private: private:
Type m_type = Empty; Type m_type = Empty;
bool m_enabled = false; 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); QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command);

View File

@@ -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;
}

View File

@@ -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 <qabstractanimation.h>
#include <QtCore/qbasictimer.h>
#include <QtCore/qmath.h>
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;
};

View File

@@ -44,6 +44,8 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \
$$PWD/qt3dpresentationnodeinstance.h \ $$PWD/qt3dpresentationnodeinstance.h \
$$PWD/quick3dnodeinstance.h \ $$PWD/quick3dnodeinstance.h \
$$PWD/quick3dtexturenodeinstance.h \ $$PWD/quick3dtexturenodeinstance.h \
$$PWD/viewconfig.h \
$$PWD/animationdriver.h
SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \
@@ -74,4 +76,6 @@ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \
$$PWD/layoutnodeinstance.cpp \ $$PWD/layoutnodeinstance.cpp \
$$PWD/qt3dpresentationnodeinstance.cpp \ $$PWD/qt3dpresentationnodeinstance.cpp \
$$PWD/quick3dnodeinstance.cpp \ $$PWD/quick3dnodeinstance.cpp \
$$PWD/quick3dtexturenodeinstance.cpp $$PWD/quick3dtexturenodeinstance.cpp \
$$PWD/viewconfig.cpp \
$$PWD/animationdriver.cpp

View File

@@ -332,6 +332,7 @@ void NodeInstanceServer::createScene(const CreateSceneCommand &command)
registerFonts(command.resourceUrl); registerFonts(command.resourceUrl);
setTranslationLanguage(command.language); setTranslationLanguage(command.language);
if (!ViewConfig::isParticleViewMode())
Internal::QmlPrivateGate::stopUnifiedTimer(); Internal::QmlPrivateGate::stopUnifiedTimer();
setupScene(command); setupScene(command);
@@ -783,6 +784,15 @@ QList<QQmlContext *> NodeInstanceServer::allSubContextsForObject(QObject *object
return contextList; return contextList;
} }
QList<QObject *> NodeInstanceServer::allSubObjectsForObject(QObject *object)
{
QList<QObject *> subChildren;
if (object)
subChildren = object->findChildren<QObject *>();
return subChildren;
}
void NodeInstanceServer::removeAllInstanceRelationships() void NodeInstanceServer::removeAllInstanceRelationships()
{ {
for (ServerNodeInstance &instance : m_objectInstanceHash) { for (ServerNodeInstance &instance : m_objectInstanceHash) {
@@ -1563,4 +1573,39 @@ bool NodeInstanceServer::isInformationServer() const
return false; 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<QQuickPropertyAnimation *>(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<QQuickAbstractAnimation *> NodeInstanceServer::animations() const
{
return m_animations;
}
QVariant NodeInstanceServer::animationDefaultValue(int index) const
{
return m_defaultValues.at(index);
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -43,6 +43,20 @@
#include <nodeinstanceserverinterface.h> #include <nodeinstanceserverinterface.h>
#include "servernodeinstance.h" #include "servernodeinstance.h"
#include "debugoutputcommand.h" #include "debugoutputcommand.h"
#include "viewconfig.h"
#include <private/qabstractanimation_p.h>
#include <private/qobject_p.h>
#include <private/qquickbehavior_p.h>
#include <private/qquicktext_p.h>
#include <private/qquicktextinput_p.h>
#include <private/qquicktextedit_p.h>
#include <private/qquicktransition_p.h>
#include <private/qquickloader_p.h>
#include <private/qquickanimation_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmltimer_p.h>
namespace QtHelpers { namespace QtHelpers {
template <class T> template <class T>
@@ -217,6 +231,9 @@ public:
virtual QImage grabItem(QQuickItem *item) = 0; virtual QImage grabItem(QQuickItem *item) = 0;
virtual bool isInformationServer() const; virtual bool isInformationServer() const;
void addAnimation(QQuickAbstractAnimation *animation);
QVector<QQuickAbstractAnimation *> animations() const;
QVariant animationDefaultValue(int index) const;
public slots: public slots:
void refreshLocalFileProperty(const QString &path); void refreshLocalFileProperty(const QString &path);
@@ -292,6 +309,7 @@ protected:
QList<ServerNodeInstance> setupInstances(const CreateSceneCommand &command); QList<ServerNodeInstance> setupInstances(const CreateSceneCommand &command);
QList<QQmlContext*> allSubContextsForObject(QObject *object); QList<QQmlContext*> allSubContextsForObject(QObject *object);
static QList<QObject*> allSubObjectsForObject(QObject *object);
virtual void resizeCanvasToRootItem() = 0; virtual void resizeCanvasToRootItem() = 0;
void setupState(qint32 stateInstanceId); void setupState(qint32 stateInstanceId);
@@ -322,6 +340,8 @@ private:
std::unique_ptr<MultiLanguage::Link> multilanguageLink; std::unique_ptr<MultiLanguage::Link> multilanguageLink;
int m_needsExtraRenderCount = 0; int m_needsExtraRenderCount = 0;
int m_extraRenderCurrentPass = 0; int m_extraRenderCurrentPass = 0;
QVector<QQuickAbstractAnimation *> m_animations;
QVector<QVariant> m_defaultValues;
}; };
} }

View File

@@ -87,6 +87,7 @@
#include <QQmlEngine> #include <QQmlEngine>
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#include <QProcessEnvironment>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtQuick/private/qquickrendercontrol_p.h> #include <QtQuick/private/qquickrendercontrol_p.h>
@@ -103,10 +104,6 @@
#endif #endif
#endif #endif
#ifdef QUICK3D_PARTICLES_MODULE
#include <QtQuick3DParticles/private/qquick3dparticlesystem_p.h>
#endif
#ifdef IMPORT_QUICK3D_ASSETS #ifdef IMPORT_QUICK3D_ASSETS
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h> #include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
#endif #endif
@@ -216,7 +213,7 @@ void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances) void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances)
{ {
if (!isQuick3DMode()) if (!ViewConfig::isQuick3DMode())
return; return;
// We only want to update the topmost parents in the set // We only want to update the topmost parents in the set
@@ -406,9 +403,83 @@ void Qt5InformationNodeInstanceServer::createEditView3D()
#endif #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<QQuickPropertyAnimation *>(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. // The selection has changed in the edit view 3D. Empty list indicates selection is cleared.
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs) void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
{ {
#ifdef QUICK3D_PARTICLES_MODULE
resetParticleSystem();
#endif
QList<ServerNodeInstance> instanceList; QList<ServerNodeInstance> instanceList;
const QVariantList varObjs = objs.value<QVariantList>(); const QVariantList varObjs = objs.value<QVariantList>();
for (const auto &object : varObjs) { for (const auto &object : varObjs) {
@@ -829,6 +900,12 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView()
m_render3DEditViewTimer.start(0); m_render3DEditViewTimer.start(0);
--m_need3DEditViewRender; --m_need3DEditViewRender;
} }
#ifdef QUICK3D_PARTICLES_MODULE
if (ViewConfig::isParticleViewMode()
&& m_particleAnimationDriver && m_particleAnimationDriver->isAnimating()) {
m_need3DEditViewRender++;
}
#endif
#ifdef FPS_COUNTER #ifdef FPS_COUNTER
// Force constant rendering for accurate fps count // Force constant rendering for accurate fps count
if (!m_render3DEditViewTimer.isActive()) if (!m_render3DEditViewTimer.isActive())
@@ -1084,6 +1161,12 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC
_fpsTimer->start(); _fpsTimer->start();
} }
#endif #endif
#ifdef QUICK3D_PARTICLES_MODULE
if (ViewConfig::isParticleViewMode()) {
m_particleAnimationDriver = new AnimationDriver(this);
m_particleAnimationDriver->setInterval(17);
}
#endif
} }
Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
@@ -1205,7 +1288,7 @@ QList<ServerNodeInstance> Qt5InformationNodeInstanceServer::createInstances(
void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews() void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews()
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (isQuick3DMode()) if (ViewConfig::isQuick3DMode())
createEditView3D(); createEditView3D();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"), createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"),
@@ -1665,7 +1748,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
sendChildrenChangedCommand(instanceList); sendChildrenChangedCommand(instanceList);
nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList)); nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList));
if (isQuick3DMode()) { if (ViewConfig::isQuick3DMode()) {
setup3DEditView(instanceList, command.edit3dToolStates); setup3DEditView(instanceList, command.edit3dToolStates);
updateRotationBlocks(command.auxiliaryChanges); updateRotationBlocks(command.auxiliaryChanges);
} }
@@ -1735,7 +1818,9 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
{ {
if (!m_editView3DSetupDone) if (!m_editView3DSetupDone)
return; return;
#ifdef QUICK3D_PARTICLES_MODULE
resetParticleSystem();
#endif
m_lastSelectionChangeCommand = command; m_lastSelectionChangeCommand = command;
if (m_selectionChangeTimer.isActive()) { if (m_selectionChangeTimer.isActive()) {
// If selection was recently changed by puppet, hold updating the selection for a bit to // 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")) if (firstSceneRoot && sceneRoot == firstSceneRoot && instance.isSubclassOf("QQuick3DNode"))
object = instance.internalObject(); object = instance.internalObject();
#ifdef QUICK3D_PARTICLES_MODULE
auto particlesystem = qobject_cast<QQuick3DParticleSystem *>(instance.internalObject());
if (particlesystem)
handleParticleSystemSelected(particlesystem);
else
handleParticleSystemDeselected();
#endif
auto isSelectableAsRoot = [&]() -> bool { auto isSelectableAsRoot = [&]() -> bool {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (qobject_cast<QQuick3DModel *>(object) if (qobject_cast<QQuick3DModel *>(object)
|| qobject_cast<QQuick3DCamera *>(object) || qobject_cast<QQuick3DCamera *>(object)
#ifdef QUICK3D_PARTICLES_MODULE
|| qobject_cast<QQuick3DParticleSystem *>(object)
#endif
|| qobject_cast<QQuick3DAbstractLight *>(object)) { || qobject_cast<QQuick3DAbstractLight *>(object)) {
return true; return true;
} }
@@ -1900,6 +1989,33 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
case View3DActionCommand::ShowGrid: case View3DActionCommand::ShowGrid:
updatedState.insert("showGrid", command.isEnabled()); updatedState.insert("showGrid", command.isEnabled());
break; 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<const View3DSeekActionCommand &>(command).position());
break;
#endif
default: default:
break; break;
} }
@@ -1977,7 +2093,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst
bool enable, bool checkAncestors) bool enable, bool checkAncestors)
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (!isQuick3DMode()) if (!ViewConfig::isQuick3DMode())
return; return;
bool edit3dLocked = enable; bool edit3dLocked = enable;
@@ -2015,7 +2131,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst
bool enable, bool checkAncestors) bool enable, bool checkAncestors)
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (!isQuick3DMode()) if (!ViewConfig::isQuick3DMode())
return; return;
bool edit3dHidden = enable; bool edit3dHidden = enable;

View File

@@ -32,8 +32,14 @@
#include "requestmodelnodepreviewimagecommand.h" #include "requestmodelnodepreviewimagecommand.h"
#include "propertybindingcontainer.h" #include "propertybindingcontainer.h"
#include "propertyabstractcontainer.h" #include "propertyabstractcontainer.h"
#include "animationdriver.h"
#ifdef QUICK3D_PARTICLES_MODULE
#include <QtQuick3DParticles/private/qquick3dparticlesystem_p.h>
#endif
#include <QTimer> #include <QTimer>
#include <QElapsedTimer>
#include <QVariant> #include <QVariant>
#include <QPointer> #include <QPointer>
#include <QImage> #include <QImage>
@@ -140,6 +146,11 @@ private:
void removeRotationBlocks(const QVector<qint32> &instanceIds); void removeRotationBlocks(const QVector<qint32> &instanceIds);
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); 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_editView3DData;
RenderViewData m_modelNode3DImageViewData; RenderViewData m_modelNode3DImageViewData;
@@ -161,6 +172,12 @@ private:
QTimer m_render3DEditViewTimer; QTimer m_render3DEditViewTimer;
QTimer m_renderModelNodeImageViewTimer; QTimer m_renderModelNodeImageViewTimer;
QTimer m_inputEventTimer; 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; QObjectList m_changedNodes;
QList<PropertyName> m_changedProperties; QList<PropertyName> m_changedProperties;
ChangeSelectionCommand m_lastSelectionChangeCommand; ChangeSelectionCommand m_lastSelectionChangeCommand;

View File

@@ -82,6 +82,7 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
setNodeInstanceServer(std::make_unique<Qt5PreviewNodeInstanceServer>(this)); setNodeInstanceServer(std::make_unique<Qt5PreviewNodeInstanceServer>(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) {
ViewConfig::enableParticleView(true);
setNodeInstanceServer(std::make_unique<Qt5InformationNodeInstanceServer>(this)); setNodeInstanceServer(std::make_unique<Qt5InformationNodeInstanceServer>(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) {

View File

@@ -60,6 +60,7 @@ namespace QmlDesigner {
Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient)
: NodeInstanceServer(nodeInstanceClient) : NodeInstanceServer(nodeInstanceClient)
{ {
if (!ViewConfig::isParticleViewMode())
DesignerSupport::activateDesignerMode(); DesignerSupport::activateDesignerMode();
} }

View File

@@ -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 <QtGlobal>
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;
}

View File

@@ -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();
};

View File

@@ -34,6 +34,7 @@
#include <QQuickItem> #include <QQuickItem>
#include <QQmlComponent> #include <QQmlComponent>
#include <QFileInfo> #include <QFileInfo>
#include <QProcessEnvironment>
#include <private/qabstractfileengine_p.h> #include <private/qabstractfileengine_p.h>
#include <private/qfsfileengine_p.h> #include <private/qfsfileengine_p.h>
@@ -47,6 +48,19 @@
#include <private/qqmldata_p.h> #include <private/qqmldata_p.h>
#include <private/qqmlcomponentattached_p.h> #include <private/qqmlcomponentattached_p.h>
#include <private/qabstractanimation_p.h>
#include <private/qobject_p.h>
#include <private/qquickbehavior_p.h>
#include <private/qquicktext_p.h>
#include <private/qquicktextinput_p.h>
#include <private/qquicktextedit_p.h>
#include <private/qquicktransition_p.h>
#include <private/qquickloader_p.h>
#include <private/qquickanimation_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmltimer_p.h>
namespace QmlDesigner { namespace QmlDesigner {
namespace Internal { namespace Internal {
@@ -382,8 +396,15 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
static_cast<QQmlParserStatus *>(item)->componentComplete(); static_cast<QQmlParserStatus *>(item)->componentComplete();
} else { } else {
QQmlParserStatus *qmlParserStatus = dynamic_cast<QQmlParserStatus *>(object); QQmlParserStatus *qmlParserStatus = dynamic_cast<QQmlParserStatus *>(object);
if (qmlParserStatus) if (qmlParserStatus) {
qmlParserStatus->componentComplete(); qmlParserStatus->componentComplete();
auto *anim = dynamic_cast<QQuickAbstractAnimation *>(object);
if (anim && ViewConfig::isParticleViewMode()) {
nodeInstanceServer->addAnimation(anim);
anim->setEnableUserControl();
anim->stop();
}
}
} }
} }
} }

View File

@@ -47,5 +47,17 @@ QDebug operator<<(QDebug debug, const DiagnosticContainer &container)
return debug; return debug;
} }
QDebug operator<<(QDebug debug, const QVector<DiagnosticContainer> &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 } // namespace ClangBackEnd

View File

@@ -123,5 +123,8 @@ public:
}; };
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const DiagnosticContainer &container); CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const DiagnosticContainer &container);
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector<DiagnosticContainer> &container);
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -39,5 +39,17 @@ QDebug operator<<(QDebug debug, const FixItContainer &container)
return debug; return debug;
} }
QDebug operator<<(QDebug debug, const QVector<FixItContainer> &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 } // namespace ClangBackEnd

View File

@@ -69,5 +69,6 @@ public:
}; };
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FixItContainer &container); CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FixItContainer &container);
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector<FixItContainer> &container);
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -39,4 +39,16 @@ QDebug operator<<(QDebug debug, const SourceRangeContainer &container)
return debug; return debug;
} }
QDebug operator<<(QDebug debug, const QVector<SourceRangeContainer> &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 } // namespace ClangBackEnd

View File

@@ -85,5 +85,6 @@ public:
}; };
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const SourceRangeContainer &container); CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const SourceRangeContainer &container);
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector<SourceRangeContainer> &container);
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -202,6 +202,7 @@ extend_qtc_plugin(QmlDesigner
rubberbandselectionmanipulator.cpp rubberbandselectionmanipulator.h rubberbandselectionmanipulator.cpp rubberbandselectionmanipulator.h
scaleitem.cpp scaleitem.h scaleitem.cpp scaleitem.h
scalemanipulator.cpp scalemanipulator.h scalemanipulator.cpp scalemanipulator.h
seekerslider.cpp seekerslider.h
selectionindicator.cpp selectionindicator.h selectionindicator.cpp selectionindicator.h
selectionrectangle.cpp selectionrectangle.h selectionrectangle.cpp selectionrectangle.h
selectiontool.cpp selectiontool.h selectiontool.cpp selectiontool.h

View File

@@ -34,5 +34,15 @@
<file>images/select_item@2x.png</file> <file>images/select_item@2x.png</file>
<file>images/orthographic_camera.png</file> <file>images/orthographic_camera.png</file>
<file>images/orthographic_camera@2x.png</file> <file>images/orthographic_camera@2x.png</file>
<file>images/particles_off.png</file>
<file>images/particles_off@2x.png</file>
<file>images/particles_on.png</file>
<file>images/particles_on@2x.png</file>
<file>images/particles_play.png</file>
<file>images/particles_play@2x.png</file>
<file>images/particles_pause.png</file>
<file>images/particles_pause@2x.png</file>
<file>images/particles_restart.png</file>
<file>images/particles_restart@2x.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -209,6 +209,11 @@ QSize Edit3DView::canvasSize() const
return {}; return {};
} }
void Edit3DView::setSeeker(SeekerSlider *slider)
{
m_seeker = slider;
}
void Edit3DView::createEdit3DActions() void Edit3DView::createEdit3DActions()
{ {
m_selectionModeAction m_selectionModeAction
@@ -272,9 +277,59 @@ void Edit3DView::createEdit3DActions()
Icons::EDIT3D_GRID_ON.icon()); Icons::EDIT3D_GRID_ON.icon());
SelectionContextOperation resetTrigger = [this](const SelectionContext &) { 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()); setCurrentStateNode(rootModelNode());
resetPuppet(); 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 m_resetAction
= new Edit3DAction( = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_RESET_VIEW, View3DActionCommand::Empty, QmlDesigner::Constants::EDIT3D_RESET_VIEW, View3DActionCommand::Empty,
@@ -296,6 +351,10 @@ void Edit3DView::createEdit3DActions()
m_leftActions << m_editLightAction; m_leftActions << m_editLightAction;
m_leftActions << m_showGridAction; m_leftActions << m_showGridAction;
m_rightActions << m_particleViewModeAction;
m_rightActions << m_particlesPlayAction;
m_rightActions << m_particlesRestartAction;
m_rightActions << nullptr;
m_rightActions << m_resetAction; m_rightActions << m_resetAction;
} }

View File

@@ -25,6 +25,7 @@
#pragma once #pragma once
#include "view3dactioncommand.h" #include "view3dactioncommand.h"
#include "seekerslider.h"
#include <abstractview.h> #include <abstractview.h>
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
@@ -68,6 +69,7 @@ public:
void createEdit3DActions(); void createEdit3DActions();
QVector<Edit3DAction *> leftActions() const; QVector<Edit3DAction *> leftActions() const;
QVector<Edit3DAction *> rightActions() const; QVector<Edit3DAction *> rightActions() const;
void setSeeker(SeekerSlider *slider);
void addQuick3DImport(); void addQuick3DImport();
@@ -90,6 +92,11 @@ private:
Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_editLightAction = nullptr;
Edit3DAction *m_showGridAction = nullptr; Edit3DAction *m_showGridAction = nullptr;
Edit3DAction *m_resetAction = 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 } // namespace QmlDesigner

View File

@@ -33,6 +33,8 @@
#include "qmldesignerplugin.h" #include "qmldesignerplugin.h"
#include "qmlvisualnode.h" #include "qmlvisualnode.h"
#include "viewmanager.h" #include "viewmanager.h"
#include <seekerslider.h>
#include <nodeinstanceview.h>
#include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h> #include <coreplugin/actionmanager/command.h>
@@ -64,8 +66,11 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
fillLayout->setSpacing(0); fillLayout->setSpacing(0);
setLayout(fillLayout); setLayout(fillLayout);
SeekerSlider *seeker = new SeekerSlider(this);
seeker->setEnabled(false);
// Initialize toolbar // Initialize toolbar
m_toolBox = new ToolBox(this); m_toolBox = new ToolBox(seeker, this);
fillLayout->addWidget(m_toolBox.data()); fillLayout->addWidget(m_toolBox.data());
// Iterate through view actions. A null action indicates a separator and a second null action // 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); auto separator = new QAction(this);
separator->setSeparator(true); separator->setSeparator(true);
addAction(separator); addAction(separator);
if (left)
m_toolBox->addLeftSideAction(separator); m_toolBox->addLeftSideAction(separator);
else
m_toolBox->addRightSideAction(separator);
previousWasSeparator = true; previousWasSeparator = true;
} }
} }
@@ -109,6 +117,14 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
addActionsToToolBox(view->leftActions(), true); addActionsToToolBox(view->leftActions(), true);
addActionsToToolBox(view->rightActions(), false); 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 // Onboarding label contains instructions for new users how to get 3D content into the project
m_onboardingLabel = new QLabel(this); m_onboardingLabel = new QLabel(this);
QString labelText = QString labelText =

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -42,7 +42,8 @@ SOURCES += formeditoritem.cpp \
backgroundaction.cpp \ backgroundaction.cpp \
formeditortoolbutton.cpp \ formeditortoolbutton.cpp \
formeditorannotationicon.cpp \ formeditorannotationicon.cpp \
transitiontool.cpp transitiontool.cpp \
seekerslider.cpp
HEADERS += formeditorscene.h \ HEADERS += formeditorscene.h \
formeditorwidget.h \ formeditorwidget.h \
@@ -87,6 +88,7 @@ HEADERS += formeditorscene.h \
backgroundaction.h \ backgroundaction.h \
formeditortoolbutton.h \ formeditortoolbutton.h \
formeditorannotationicon.h \ formeditorannotationicon.h \
transitiontool.h transitiontool.h \
seekerslider.h
RESOURCES += formeditor.qrc RESOURCES += formeditor.qrc

View File

@@ -8,5 +8,11 @@
<file>snapping_and_anchoring@2x.png</file> <file>snapping_and_anchoring@2x.png</file>
<file>annotationsIcon.png</file> <file>annotationsIcon.png</file>
<file>annotationsIconActive.png</file> <file>annotationsIconActive.png</file>
<file>scrubbg.png</file>
<file>scrubbg@2x.png</file>
<file>scrubhandle-24.png</file>
<file>scrubhandle-48.png</file>
<file>scrubhandle-disabled-24.png</file>
<file>scrubhandle-disabled-48.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -139,7 +139,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view)
addAction(m_rootHeightAction.data()); addAction(m_rootHeightAction.data());
upperActions.append(m_rootHeightAction.data()); upperActions.append(m_rootHeightAction.data());
m_toolBox = new ToolBox(this); m_toolBox = new ToolBox(nullptr, this);
fillLayout->addWidget(m_toolBox.data()); fillLayout->addWidget(m_toolBox.data());
m_toolBox->setLeftSideActions(upperActions); m_toolBox->setLeftSideActions(upperActions);

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

View File

@@ -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 <utils/icon.h>
#include <QStyleOption>
#include <QSlider>
#include <QDebug>
#include <QPainter>
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

View File

@@ -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 <QWidget>
#include <QMouseEvent>
#include <QIcon>
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

View File

@@ -33,10 +33,11 @@
namespace QmlDesigner { namespace QmlDesigner {
ToolBox::ToolBox(QWidget *parentWidget) ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget)
: Utils::StyledBar(parentWidget), : Utils::StyledBar(parentWidget),
m_leftToolBar(new QToolBar(QLatin1String("LeftSidebar"), this)), 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->setFloatable(true);
m_leftToolBar->setMovable(true); m_leftToolBar->setMovable(true);
@@ -62,6 +63,8 @@ ToolBox::ToolBox(QWidget *parentWidget)
m_rightToolBar->setOrientation(Qt::Horizontal); m_rightToolBar->setOrientation(Qt::Horizontal);
horizontalLayout->addWidget(m_leftToolBar); horizontalLayout->addWidget(m_leftToolBar);
horizontalLayout->addWidget(stretchToolbar); horizontalLayout->addWidget(stretchToolbar);
if (seeker)
horizontalLayout->addWidget(m_seeker);
horizontalLayout->addWidget(m_rightToolBar); horizontalLayout->addWidget(m_rightToolBar);
} }
@@ -94,4 +97,9 @@ QList<QAction*> ToolBox::actions() const
return m_leftToolBar->actions() + m_rightToolBar->actions(); return m_leftToolBar->actions() + m_rightToolBar->actions();
} }
SeekerSlider *ToolBox::seeker() const
{
return m_seeker;
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -25,6 +25,7 @@
#pragma once #pragma once
#include <utils/styledbar.h> #include <utils/styledbar.h>
#include <seekerslider.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QToolBar; class QToolBar;
@@ -37,16 +38,18 @@ namespace QmlDesigner {
class ToolBox : public Utils::StyledBar class ToolBox : public Utils::StyledBar
{ {
public: public:
ToolBox(QWidget *parentWidget); ToolBox(SeekerSlider *seeker, QWidget *parentWidget);
void setLeftSideActions(const QList<QAction*> &actions); void setLeftSideActions(const QList<QAction*> &actions);
void setRightSideActions(const QList<QAction*> &actions); void setRightSideActions(const QList<QAction*> &actions);
void addLeftSideAction(QAction *action); void addLeftSideAction(QAction *action);
void addRightSideAction(QAction *action); void addRightSideAction(QAction *action);
QList<QAction*> actions() const; QList<QAction*> actions() const;
SeekerSlider *seeker() const;
private: private:
QToolBar *m_leftToolBar; QToolBar *m_leftToolBar;
QToolBar *m_rightToolBar; QToolBar *m_rightToolBar;
SeekerSlider *m_seeker;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -533,10 +533,20 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0"); QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0");
if (m_model->hasImport(import, true, true)) if (m_model->hasImport(import, true, true))
environment.set("QMLDESIGNER_QUICK3D_MODE", "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"); import = QmlDesigner::Import::createLibraryImport("QtCharts", "2.0");
if (m_model->hasImport(import, true, true)) if (m_model->hasImport(import, true, true))
environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true"); environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true");
bool particlemode = QmlDesigner::DesignerSettings::getValue("particleMode").toBool();
if (!particlemode)
environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1"); environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1");
else
environment.set("QT_QUICK3D_EDITOR_PARTICLE_SYSTEMS", "1");
#endif #endif
QStringList importPaths = m_model->importPaths(); QStringList importPaths = m_model->importPaths();

View File

@@ -64,6 +64,10 @@ const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle";
const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle";
const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid";
const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView"; 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 QML_DESIGNER_SUBFOLDER[] = "/designer/";
const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets"; const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";

View File

@@ -51,6 +51,16 @@ const Utils::Icon EDIT3D_LIGHT_ON({
{":/edit3d/images/edit_light_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); {":/edit3d/images/edit_light_on.png", Utils::Theme::QmlDesigner_HighlightColor}});
const Utils::Icon EDIT3D_LIGHT_OFF({ const Utils::Icon EDIT3D_LIGHT_OFF({
{":/edit3d/images/edit_light_off.png", Utils::Theme::IconsBaseColor}}); {":/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({ const Utils::Icon EDIT3D_GRID_ON({
{":/edit3d/images/grid_on.png", Utils::Theme::QmlDesigner_HighlightColor}}); {":/edit3d/images/grid_on.png", Utils::Theme::QmlDesigner_HighlightColor}});
const Utils::Icon EDIT3D_GRID_OFF({ const Utils::Icon EDIT3D_GRID_OFF({

View File

@@ -577,6 +577,8 @@ Project {
"formeditor/scaleitem.h", "formeditor/scaleitem.h",
"formeditor/scalemanipulator.cpp", "formeditor/scalemanipulator.cpp",
"formeditor/scalemanipulator.h", "formeditor/scalemanipulator.h",
"formeditor/seekerslider.cpp",
"formeditor/seekerslider.h",
"formeditor/selectionindicator.cpp", "formeditor/selectionindicator.cpp",
"formeditor/selectionindicator.h", "formeditor/selectionindicator.h",
"formeditor/selectionrectangle.cpp", "formeditor/selectionrectangle.cpp",

View File

@@ -221,6 +221,8 @@ extend_qtc_executable(qml2puppet
nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h
capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h
qt5captureimagenodeinstanceserver.cpp qt5captureimagenodeinstanceserver.h qt5captureimagenodeinstanceserver.cpp qt5captureimagenodeinstanceserver.h
viewconfig.cpp viewconfig.h
animationdriver.cpp animationdriver.h
) )
extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet

View File

@@ -16,7 +16,6 @@ QtcTool {
] ]
} }
Depends { name: "Qt.quick3d-private"; required: false } 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 property bool useQuick3d: Utilities.versionCompare(Qt.core.version, "5.15") >= 0
&& Qt["quick3d-private"].present && Qt["quick3d-private"].present
property bool useParticle3d: Utilities.versionCompare(Qt.core.version, "6.2") >= 0 property bool useParticle3d: Utilities.versionCompare(Qt.core.version, "6.2") >= 0
@@ -249,6 +248,10 @@ QtcTool {
"instances/nodeinstanceserverdispatcher.h", "instances/nodeinstanceserverdispatcher.h",
"instances/capturenodeinstanceserverdispatcher.cpp", "instances/capturenodeinstanceserverdispatcher.cpp",
"instances/capturenodeinstanceserverdispatcher.h", "instances/capturenodeinstanceserverdispatcher.h",
"instances/viewconfig.cpp",
"instances/viewconfig.h",
"instances/animationdriver.cpp",
"instances/animationdriver.h",
"editor3d/generalhelper.cpp", "editor3d/generalhelper.cpp",
"editor3d/mousearea3d.cpp", "editor3d/mousearea3d.cpp",
"editor3d/geometrybase.cpp", "editor3d/geometrybase.cpp",