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>
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -332,6 +332,7 @@ void NodeInstanceServer::createScene(const CreateSceneCommand &command)
|
||||
registerFonts(command.resourceUrl);
|
||||
setTranslationLanguage(command.language);
|
||||
|
||||
if (!ViewConfig::isParticleViewMode())
|
||||
Internal::QmlPrivateGate::stopUnifiedTimer();
|
||||
|
||||
setupScene(command);
|
||||
@@ -783,6 +784,15 @@ QList<QQmlContext *> NodeInstanceServer::allSubContextsForObject(QObject *object
|
||||
return contextList;
|
||||
}
|
||||
|
||||
QList<QObject *> NodeInstanceServer::allSubObjectsForObject(QObject *object)
|
||||
{
|
||||
QList<QObject *> subChildren;
|
||||
if (object)
|
||||
subChildren = object->findChildren<QObject *>();
|
||||
|
||||
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<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
|
||||
|
||||
@@ -43,6 +43,20 @@
|
||||
#include <nodeinstanceserverinterface.h>
|
||||
#include "servernodeinstance.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 {
|
||||
template <class T>
|
||||
@@ -217,6 +231,9 @@ public:
|
||||
virtual QImage grabItem(QQuickItem *item) = 0;
|
||||
|
||||
virtual bool isInformationServer() const;
|
||||
void addAnimation(QQuickAbstractAnimation *animation);
|
||||
QVector<QQuickAbstractAnimation *> animations() const;
|
||||
QVariant animationDefaultValue(int index) const;
|
||||
|
||||
public slots:
|
||||
void refreshLocalFileProperty(const QString &path);
|
||||
@@ -292,6 +309,7 @@ protected:
|
||||
QList<ServerNodeInstance> setupInstances(const CreateSceneCommand &command);
|
||||
|
||||
QList<QQmlContext*> allSubContextsForObject(QObject *object);
|
||||
static QList<QObject*> allSubObjectsForObject(QObject *object);
|
||||
|
||||
virtual void resizeCanvasToRootItem() = 0;
|
||||
void setupState(qint32 stateInstanceId);
|
||||
@@ -322,6 +340,8 @@ private:
|
||||
std::unique_ptr<MultiLanguage::Link> multilanguageLink;
|
||||
int m_needsExtraRenderCount = 0;
|
||||
int m_extraRenderCurrentPass = 0;
|
||||
QVector<QQuickAbstractAnimation *> m_animations;
|
||||
QVector<QVariant> m_defaultValues;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
#include <QQmlEngine>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QtQuick/private/qquickrendercontrol_p.h>
|
||||
@@ -103,10 +104,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef QUICK3D_PARTICLES_MODULE
|
||||
#include <QtQuick3DParticles/private/qquick3dparticlesystem_p.h>
|
||||
#endif
|
||||
|
||||
#ifdef IMPORT_QUICK3D_ASSETS
|
||||
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
|
||||
#endif
|
||||
@@ -216,7 +213,7 @@ void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
|
||||
|
||||
void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &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<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.
|
||||
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
|
||||
{
|
||||
#ifdef QUICK3D_PARTICLES_MODULE
|
||||
resetParticleSystem();
|
||||
#endif
|
||||
QList<ServerNodeInstance> instanceList;
|
||||
const QVariantList varObjs = objs.value<QVariantList>();
|
||||
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<ServerNodeInstance> 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<QQuick3DParticleSystem *>(instance.internalObject());
|
||||
if (particlesystem)
|
||||
handleParticleSystemSelected(particlesystem);
|
||||
else
|
||||
handleParticleSystemDeselected();
|
||||
#endif
|
||||
auto isSelectableAsRoot = [&]() -> bool {
|
||||
#ifdef QUICK3D_MODULE
|
||||
if (qobject_cast<QQuick3DModel *>(object)
|
||||
|| qobject_cast<QQuick3DCamera *>(object)
|
||||
#ifdef QUICK3D_PARTICLES_MODULE
|
||||
|| qobject_cast<QQuick3DParticleSystem *>(object)
|
||||
#endif
|
||||
|| qobject_cast<QQuick3DAbstractLight *>(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<const View3DSeekActionCommand &>(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;
|
||||
|
||||
@@ -32,8 +32,14 @@
|
||||
#include "requestmodelnodepreviewimagecommand.h"
|
||||
#include "propertybindingcontainer.h"
|
||||
#include "propertyabstractcontainer.h"
|
||||
#include "animationdriver.h"
|
||||
|
||||
#ifdef QUICK3D_PARTICLES_MODULE
|
||||
#include <QtQuick3DParticles/private/qquick3dparticlesystem_p.h>
|
||||
#endif
|
||||
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QVariant>
|
||||
#include <QPointer>
|
||||
#include <QImage>
|
||||
@@ -140,6 +146,11 @@ private:
|
||||
void removeRotationBlocks(const QVector<qint32> &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<PropertyName> m_changedProperties;
|
||||
ChangeSelectionCommand m_lastSelectionChangeCommand;
|
||||
|
||||
@@ -82,6 +82,7 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
|
||||
setNodeInstanceServer(std::make_unique<Qt5PreviewNodeInstanceServer>(this));
|
||||
initializeSocket();
|
||||
} else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) {
|
||||
ViewConfig::enableParticleView(true);
|
||||
setNodeInstanceServer(std::make_unique<Qt5InformationNodeInstanceServer>(this));
|
||||
initializeSocket();
|
||||
} else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) {
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace QmlDesigner {
|
||||
Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient)
|
||||
: NodeInstanceServer(nodeInstanceClient)
|
||||
{
|
||||
if (!ViewConfig::isParticleViewMode())
|
||||
DesignerSupport::activateDesignerMode();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QQuickItem>
|
||||
#include <QQmlComponent>
|
||||
#include <QFileInfo>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include <private/qabstractfileengine_p.h>
|
||||
#include <private/qfsfileengine_p.h>
|
||||
@@ -47,6 +48,19 @@
|
||||
#include <private/qqmldata_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 Internal {
|
||||
@@ -382,8 +396,15 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
|
||||
static_cast<QQmlParserStatus *>(item)->componentComplete();
|
||||
} else {
|
||||
QQmlParserStatus *qmlParserStatus = dynamic_cast<QQmlParserStatus *>(object);
|
||||
if (qmlParserStatus)
|
||||
if (qmlParserStatus) {
|
||||
qmlParserStatus->componentComplete();
|
||||
auto *anim = dynamic_cast<QQuickAbstractAnimation *>(object);
|
||||
if (anim && ViewConfig::isParticleViewMode()) {
|
||||
nodeInstanceServer->addAnimation(anim);
|
||||
anim->setEnableUserControl();
|
||||
anim->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,5 +47,17 @@ QDebug operator<<(QDebug debug, const DiagnosticContainer &container)
|
||||
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
|
||||
|
||||
|
||||
@@ -123,5 +123,8 @@ public:
|
||||
};
|
||||
|
||||
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const DiagnosticContainer &container);
|
||||
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector<DiagnosticContainer> &container);
|
||||
|
||||
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -39,5 +39,17 @@ QDebug operator<<(QDebug debug, const FixItContainer &container)
|
||||
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
|
||||
|
||||
|
||||
@@ -69,5 +69,6 @@ public:
|
||||
};
|
||||
|
||||
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FixItContainer &container);
|
||||
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector<FixItContainer> &container);
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -39,4 +39,16 @@ QDebug operator<<(QDebug debug, const SourceRangeContainer &container)
|
||||
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
|
||||
|
||||
@@ -85,5 +85,6 @@ public:
|
||||
};
|
||||
|
||||
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const SourceRangeContainer &container);
|
||||
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const QVector<SourceRangeContainer> &container);
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,5 +34,15 @@
|
||||
<file>images/select_item@2x.png</file>
|
||||
<file>images/orthographic_camera.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>
|
||||
</RCC>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "view3dactioncommand.h"
|
||||
#include "seekerslider.h"
|
||||
|
||||
#include <abstractview.h>
|
||||
#include <QtGui/qevent.h>
|
||||
@@ -68,6 +69,7 @@ public:
|
||||
void createEdit3DActions();
|
||||
QVector<Edit3DAction *> leftActions() const;
|
||||
QVector<Edit3DAction *> 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
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "qmldesignerplugin.h"
|
||||
#include "qmlvisualnode.h"
|
||||
#include "viewmanager.h"
|
||||
#include <seekerslider.h>
|
||||
#include <nodeinstanceview.h>
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
@@ -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);
|
||||
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 =
|
||||
|
||||
|
After Width: | Height: | Size: 226 B |
|
After Width: | Height: | Size: 395 B |
|
After Width: | Height: | Size: 299 B |
|
After Width: | Height: | Size: 375 B |
|
After Width: | Height: | Size: 116 B |
|
After Width: | Height: | Size: 105 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 203 B |
|
After Width: | Height: | Size: 214 B |
|
After Width: | Height: | Size: 375 B |
BIN
src/plugins/qmldesigner/components/edit3d/images/playpause.png
Normal file
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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
|
||||
|
||||
@@ -8,5 +8,11 @@
|
||||
<file>snapping_and_anchoring@2x.png</file>
|
||||
<file>annotationsIcon.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>
|
||||
</RCC>
|
||||
|
||||
@@ -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);
|
||||
|
||||
BIN
src/plugins/qmldesigner/components/formeditor/scrubbg.png
Normal file
|
After Width: | Height: | Size: 152 B |
BIN
src/plugins/qmldesigner/components/formeditor/scrubbg@2x.png
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
src/plugins/qmldesigner/components/formeditor/scrubhandle-24.png
Normal file
|
After Width: | Height: | Size: 362 B |
BIN
src/plugins/qmldesigner/components/formeditor/scrubhandle-48.png
Normal file
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 438 B |
|
After Width: | Height: | Size: 829 B |
138
src/plugins/qmldesigner/components/formeditor/seekerslider.cpp
Normal 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
|
||||
73
src/plugins/qmldesigner/components/formeditor/seekerslider.h
Normal 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
|
||||
@@ -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<QAction*> ToolBox::actions() const
|
||||
return m_leftToolBar->actions() + m_rightToolBar->actions();
|
||||
}
|
||||
|
||||
SeekerSlider *ToolBox::seeker() const
|
||||
{
|
||||
return m_seeker;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utils/styledbar.h>
|
||||
#include <seekerslider.h>
|
||||
|
||||
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<QAction*> &actions);
|
||||
void setRightSideActions(const QList<QAction*> &actions);
|
||||
void addLeftSideAction(QAction *action);
|
||||
void addRightSideAction(QAction *action);
|
||||
QList<QAction*> actions() const;
|
||||
SeekerSlider *seeker() const;
|
||||
|
||||
private:
|
||||
QToolBar *m_leftToolBar;
|
||||
QToolBar *m_rightToolBar;
|
||||
SeekerSlider *m_seeker;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -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");
|
||||
|
||||
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();
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||