QmlDesigner: Enable 3D Edit View in Qt Quick Designer

If we find a QQuick3DViewport or the root node is a QQuick3DNode,
we create an 3D Edit View QQuickView for 3D editing in the 'editmode'.

This requires to not use the DesignerWindowManager for the 'editmode'.

The current implementation for the 3D Edit View is done in EditView3D.qml,
but can be replaced by a custom EditView class later. At this point in time
there is no hard dependency on QtQuick3D. Once we start to implement
more advanceded editing features, EditView3D.qml has to be replaced by a
custom C++ class with a hard dependency on QtQuick3D.

Currently the scene can be rotated around the 'y' axis, it is possible
to move the camera on the 'z' axis and the custom light can be turned
on and off. This is simply a proof of concept that the 3D Edit View
already allows some user interaction.

Change-Id: I96400e72b0853dde7939c693d1d7300f9c2ab142
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Thomas Hartmann
2019-09-27 18:52:06 +02:00
parent 3451f4c048
commit 1900276c17
7 changed files with 176 additions and 3 deletions

View File

@@ -0,0 +1,101 @@
/****************************************************************************
**
** Copyright (C) 2019 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.
**
****************************************************************************/
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick3D 1.0
import QtQuick.Controls 2.0
Window {
width: 1024
height: 768
visible: true
title: "3D"
flags: Qt.WindowStaysOnTopHint | Qt.Window | Qt.WindowTitleHint | Qt.WindowCloseButtonHint
Rectangle {
color: "black"
anchors.fill: parent
}
Column {
y: 32
Slider {
id: slider
value: -600
from: -1200
to: 600
}
Slider {
id: slider2
value: 0
from: -360
to: 360
}
CheckBox {
id: checkBox
text: "Light"
Rectangle {
anchors.fill: parent
z: -1
}
}
}
Binding {
target: view.scene
property: "rotation.y"
value: slider2.value
}
property alias scene: view.scene
property alias showLight: checkBox.checked
id: viewWindow
View3D {
id: view
anchors.fill: parent
enableWireframeMode: true
camera: camera01
Light {
id: directionalLight
visible: checkBox.checked
}
Camera {
id: camera01
z: slider.value
}
Component.onCompleted: {
directionalLight.setParentItem(view.scene)
camera01.setParentItem(view.scene)
}
}
}

View File

@@ -60,8 +60,23 @@
#include <designersupportdelegate.h> #include <designersupportdelegate.h>
#include <QQmlProperty>
#include <QOpenGLContext>
#include <QQuickView>
namespace QmlDesigner { namespace QmlDesigner {
static QVariant objectToVariant(QObject *object)
{
return QVariant::fromValue(object);
}
static QObject *createEditView3D(QQmlEngine *engine)
{
QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"));
return component.create();
}
Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
Qt5NodeInstanceServer(nodeInstanceClient) Qt5NodeInstanceServer(nodeInstanceClient)
{ {
@@ -122,6 +137,40 @@ bool Qt5InformationNodeInstanceServer::isDirtyRecursiveForParentInstances(QQuick
return false; return false;
} }
void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeInstance> &instanceList)
{
ServerNodeInstance root = rootNodeInstance();
QObject *node = nullptr;
bool showCustomLight = false;
if (root.isSubclassOf("QQuick3DNode")) {
node = root.internalObject();
showCustomLight = true; // Pure node scene we should add a custom light
} else { // Look for QQuick3DView
for (const ServerNodeInstance &instance : instanceList) {
if (instance.isSubclassOf("QQuick3DViewport")) {
for (const ServerNodeInstance &child : instanceList) { /* Look for scene node */
if (child.isSubclassOf("QQuick3DNode") && child.parent() == instance)
node = child.internalObject();
}
}
}
}
if (node) { // If we found a scene we create the edit view
QObject *view = createEditView3D(engine());
QQmlProperty sceneProperty(view, "scene", context());
node->setParent(view);
sceneProperty.write(objectToVariant(node));
QQmlProperty parentProperty(node, "parent", context());
parentProperty.write(objectToVariant(view));
QQmlProperty completeSceneProperty(view, "showLight", context());
completeSceneProperty.write(showCustomLight);
}
}
void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands() void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{ {
static bool inFunction = false; static bool inFunction = false;
@@ -232,6 +281,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
sendChildrenChangedCommand(instanceList); sendChildrenChangedCommand(instanceList);
nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList)); nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList));
setup3DEditView(instanceList);
} }
void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList<ServerNodeInstance> &childList) void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList<ServerNodeInstance> &childList)

View File

@@ -51,6 +51,8 @@ protected:
bool isDirtyRecursiveForParentInstances(QQuickItem *item) const; bool isDirtyRecursiveForParentInstances(QQuickItem *item) const;
private: private:
void setup3DEditView(const QList<ServerNodeInstance> &instanceList);
QSet<ServerNodeInstance> m_parentChangedSet; QSet<ServerNodeInstance> m_parentChangedSet;
QList<ServerNodeInstance> m_completedComponentList; QList<ServerNodeInstance> m_completedComponentList;
QList<TokenCommand> m_tokenList; QList<TokenCommand> m_tokenList;

View File

@@ -54,7 +54,6 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
NodeInstanceClientProxy(parent) NodeInstanceClientProxy(parent)
{ {
prioritizeDown(); prioritizeDown();
DesignerSupport::activateDesignerWindowManager();
if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) { if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) {
qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1"); qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1");
setNodeInstanceServer(new Qt5TestNodeInstanceServer(this)); setNodeInstanceServer(new Qt5TestNodeInstanceServer(this));
@@ -62,12 +61,18 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
readDataStream(); readDataStream();
QCoreApplication::exit(); QCoreApplication::exit();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("previewmode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("previewmode")) {
DesignerSupport::activateDesignerWindowManager();
setNodeInstanceServer(new Qt5PreviewNodeInstanceServer(this)); setNodeInstanceServer(new Qt5PreviewNodeInstanceServer(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) {
/* The editormode does not use the DesignerWindowManager,
* because we want to be able to show the 3D Edit View
* as a normal QQuickView.
* The DesignerWindowManager prevents any window from actually being shown. */
setNodeInstanceServer(new Qt5InformationNodeInstanceServer(this)); setNodeInstanceServer(new Qt5InformationNodeInstanceServer(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) {
DesignerSupport::activateDesignerWindowManager();
setNodeInstanceServer(new Qt5RenderNodeInstanceServer(this)); setNodeInstanceServer(new Qt5RenderNodeInstanceServer(this));
initializeSocket(); initializeSocket();
} }

View File

@@ -37,6 +37,9 @@
#include <createscenecommand.h> #include <createscenecommand.h>
#include <reparentinstancescommand.h> #include <reparentinstancescommand.h>
#include <QDebug>
#include <QOpenGLContext>
namespace QmlDesigner { namespace QmlDesigner {
Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient)
@@ -68,6 +71,16 @@ void Qt5NodeInstanceServer::initializeView()
DesignerSupport::createOpenGLContext(m_quickView.data()); DesignerSupport::createOpenGLContext(m_quickView.data());
if (QCoreApplication::arguments().at(2) == "editormode") {
/* In 'editormode' we do not use the DesignerWindowManager
* and since we do not show the QQuickView we have to manually create the OpenGL context */
auto context = new QOpenGLContext(m_quickView);
context->setFormat(surfaceFormat);
context->create();
if (!context->makeCurrent(m_quickView))
qWarning("QOpenGLContext: makeCurrent() failed...");
}
if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) { if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) {
QQmlFileSelector *fileSelector = new QQmlFileSelector(engine(), engine()); QQmlFileSelector *fileSelector = new QQmlFileSelector(engine(), engine());
QStringList customSelectors = QString::fromUtf8(qgetenv("QML_FILE_SELECTORS")).split(","); QStringList customSelectors = QString::fromUtf8(qgetenv("QML_FILE_SELECTORS")).split(",");

View File

@@ -67,6 +67,7 @@ class ServerNodeInstance
friend class NodeInstanceServer; friend class NodeInstanceServer;
friend class Qt4NodeInstanceServer; friend class Qt4NodeInstanceServer;
friend class Qt4PreviewNodeInstanceServer; friend class Qt4PreviewNodeInstanceServer;
friend class Qt5InformationNodeInstanceServer;
friend class Qt5NodeInstanceServer; friend class Qt5NodeInstanceServer;
friend class Qt5PreviewNodeInstanceServer; friend class Qt5PreviewNodeInstanceServer;
friend class Qt5TestNodeInstanceServer; friend class Qt5TestNodeInstanceServer;
@@ -162,6 +163,8 @@ public:
QList<ServerNodeInstance> stateInstances() const; QList<ServerNodeInstance> stateInstances() const;
static bool isSubclassOf(QObject *object, const QByteArray &superTypeName);
private: // functions private: // functions
ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance); ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance);
@@ -192,8 +195,6 @@ private: // functions
void paintUpdate(); void paintUpdate();
static bool isSubclassOf(QObject *object, const QByteArray &superTypeName);
void setNodeSource(const QString &source); void setNodeSource(const QString &source);
bool holdsGraphical() const; bool holdsGraphical() const;

View File

@@ -7,5 +7,6 @@
<file>mockfiles/SwipeView.qml</file> <file>mockfiles/SwipeView.qml</file>
<file>mockfiles/GenericBackend.qml</file> <file>mockfiles/GenericBackend.qml</file>
<file>mockfiles/Dialog.qml</file> <file>mockfiles/Dialog.qml</file>
<file>mockfiles/EditView3D.qml</file>
</qresource> </qresource>
</RCC> </RCC>