diff --git a/share/qtcreator/qml/qmlpuppet/commands/commands.pri b/share/qtcreator/qml/qmlpuppet/commands/commands.pri index 7bc595154b3..deee4c34e1c 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/commands.pri +++ b/share/qtcreator/qml/qmlpuppet/commands/commands.pri @@ -29,9 +29,10 @@ HEADERS += $$PWD/puppetalivecommand.h HEADERS += $$PWD/changeselectioncommand.h HEADERS += $$PWD/drop3dlibraryitemcommand.h HEADERS += $$PWD/update3dviewstatecommand.h -HEADERS += $$PWD/enable3dviewcommand.h HEADERS += $$PWD/view3dclosedcommand.h HEADERS += $$PWD/puppettocreatorcommand.h +HEADERS += $$PWD/inputeventcommand.h +HEADERS += $$PWD/view3dactioncommand.h SOURCES += $$PWD/synchronizecommand.cpp SOURCES += $$PWD/debugoutputcommand.cpp @@ -62,6 +63,7 @@ SOURCES += $$PWD/puppetalivecommand.cpp SOURCES += $$PWD/changeselectioncommand.cpp SOURCES += $$PWD/drop3dlibraryitemcommand.cpp SOURCES += $$PWD/update3dviewstatecommand.cpp -SOURCES += $$PWD/enable3dviewcommand.cpp SOURCES += $$PWD/view3dclosedcommand.cpp SOURCES += $$PWD/puppettocreatorcommand.cpp +SOURCES += $$PWD/inputeventcommand.cpp +SOURCES += $$PWD/view3dactioncommand.cpp diff --git a/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp new file mode 100644 index 00000000000..73a68b06207 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "inputeventcommand.h" + +#include +#include + +namespace QmlDesigner { + +InputEventCommand::InputEventCommand() = default; + +InputEventCommand::InputEventCommand(QInputEvent *e) + : m_type(e->type()), + m_modifiers(e->modifiers()) +{ + if (m_type == QEvent::Wheel) { + auto we = static_cast(e); +#if QT_VERSION <= QT_VERSION_CHECK(5, 15, 0) + m_pos = we->pos(); +#else + m_pos = we->position().toPoint(); +#endif + m_buttons = we->buttons(); + m_angleDelta = we->angleDelta().y(); + } else { + auto me = static_cast(e); + m_pos = me->pos(); + m_button = me->button(); + m_buttons = me->buttons(); + } +} + +QDataStream &operator<<(QDataStream &out, const InputEventCommand &command) +{ + out << command.type(); + out << command.pos(); + out << command.button(); + out << command.buttons(); + out << command.modifiers(); + out << command.angleDelta(); + + return out; +} + +QDataStream &operator>>(QDataStream &in, InputEventCommand &command) +{ + int type; + int button; + in >> type; + command.m_type = (QEvent::Type)type; + in >> command.m_pos; + in >> button; + command.m_button = (Qt::MouseButton)button; + in >> command.m_buttons; + in >> command.m_modifiers; + in >> command.m_angleDelta; + + return in; +} + +QDebug operator <<(QDebug debug, const InputEventCommand &command) +{ + return debug.nospace() << "InputEventCommand(" + << "type: " << command.type() << ", " + << "pos: " << command.pos() << ", " + << "button: " << command.button() << ", " + << "buttons: " << command.buttons() << ", " + << "modifiers: " << command.modifiers() << ", " + << "angleDelta: " << command.angleDelta() << ")"; + +} + +} // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.h b/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.h new file mode 100644 index 00000000000..2d77cab6dd5 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +#include "instancecontainer.h" + +namespace QmlDesigner { + +class InputEventCommand +{ + friend QDataStream &operator>>(QDataStream &in, InputEventCommand &command); + friend QDebug operator <<(QDebug debug, const InputEventCommand &command); + +public: + InputEventCommand(); + explicit InputEventCommand(QInputEvent *e); + + QEvent::Type type() const { return m_type; } + QPoint pos() const { return m_pos; } + Qt::MouseButton button() const { return m_button; } + Qt::MouseButtons buttons() const { return m_buttons; } + Qt::KeyboardModifiers modifiers() const { return m_modifiers; } + int angleDelta() const { return m_angleDelta; } + +private: + QEvent::Type m_type; + QPoint m_pos; + Qt::MouseButton m_button = Qt::NoButton; + Qt::MouseButtons m_buttons = Qt::NoButton; + Qt::KeyboardModifiers m_modifiers = Qt::NoModifier; + int m_angleDelta = 0; +}; + +QDataStream &operator<<(QDataStream &out, const InputEventCommand &command); +QDataStream &operator>>(QDataStream &in, InputEventCommand &command); + +QDebug operator <<(QDebug debug, const InputEventCommand &command); + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::InputEventCommand) diff --git a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h index 3ac17ee0c5b..91c2877f4b3 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/puppettocreatorcommand.h @@ -34,7 +34,7 @@ namespace QmlDesigner { class PuppetToCreatorCommand { public: - enum Type { KeyPressed, Edit3DToolState, None }; + enum Type { KeyPressed, Edit3DToolState, Render3DView, ActiveSceneChanged, None }; PuppetToCreatorCommand(Type type, const QVariant &data); PuppetToCreatorCommand() = default; diff --git a/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.cpp index b387cf09f3d..584e041c7ab 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.cpp @@ -45,6 +45,12 @@ Update3dViewStateCommand::Update3dViewStateCommand(bool active, bool hasPopup) { } +Update3dViewStateCommand::Update3dViewStateCommand(const QSize &size) + : m_size(size) + , m_type(Update3dViewStateCommand::SizeChange) +{ +} + Qt::WindowStates Update3dViewStateCommand::previousStates() const { return m_previousStates; @@ -65,6 +71,11 @@ bool Update3dViewStateCommand::hasPopup() const return m_hasPopup; } +QSize Update3dViewStateCommand::size() const +{ + return m_size; +} + Update3dViewStateCommand::Type Update3dViewStateCommand::type() const { return m_type; @@ -77,6 +88,7 @@ QDataStream &operator<<(QDataStream &out, const Update3dViewStateCommand &comman out << qint32(command.isActive()); out << qint32(command.hasPopup()); out << qint32(command.type()); + out << command.size(); return out; } @@ -94,13 +106,16 @@ QDataStream &operator>>(QDataStream &in, Update3dViewStateCommand &command) command.m_active = active; command.m_hasPopup = hasPopup; command.m_type = Update3dViewStateCommand::Type(type); + in >> command.m_size; return in; } QDebug operator<<(QDebug debug, const Update3dViewStateCommand &command) { - return debug.nospace() << "Update3dViewStateCommand(type: " << command.m_type << ")"; + return debug.nospace() << "Update3dViewStateCommand(type: " + << command.m_type << "," + << command.m_size << ")"; } } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.h b/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.h index de8511255d5..a38ca4bb543 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/update3dviewstatecommand.h @@ -26,6 +26,7 @@ #pragma once #include +#include namespace QmlDesigner { @@ -35,10 +36,11 @@ class Update3dViewStateCommand friend QDebug operator<<(QDebug debug, const Update3dViewStateCommand &command); public: - enum Type { StateChange, ActiveChange, Empty }; + enum Type { StateChange, ActiveChange, SizeChange, Empty }; explicit Update3dViewStateCommand(Qt::WindowStates previousStates, Qt::WindowStates currentStates); explicit Update3dViewStateCommand(bool active, bool hasPopup); + explicit Update3dViewStateCommand(const QSize &size); Update3dViewStateCommand() = default; Qt::WindowStates previousStates() const; @@ -46,6 +48,7 @@ public: bool isActive() const; bool hasPopup() const; + QSize size() const; Type type() const; @@ -55,6 +58,7 @@ private: bool m_active = false; bool m_hasPopup = false; + QSize m_size; Type m_type = Empty; }; diff --git a/share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp similarity index 58% rename from share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.cpp rename to share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp index 7fd3b3f350a..ae94ed79812 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -23,43 +23,54 @@ ** ****************************************************************************/ -#include "enable3dviewcommand.h" +#include "view3dactioncommand.h" #include #include namespace QmlDesigner { -// open / close edit view 3D command -Enable3DViewCommand::Enable3DViewCommand(bool enable) - : m_enable(enable) +View3DActionCommand::View3DActionCommand(Type type, bool enable) + : m_type(type) + , m_enabled(enable) { } -bool Enable3DViewCommand::isEnable() const +bool View3DActionCommand::isEnabled() const { - return m_enable; + return m_enabled; } -QDataStream &operator<<(QDataStream &out, const Enable3DViewCommand &command) +View3DActionCommand::Type View3DActionCommand::type() const { - out << qint32(command.isEnable()); + return m_type; +} + +QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command) +{ + out << qint32(command.isEnabled()); + out << qint32(command.type()); return out; } -QDataStream &operator>>(QDataStream &in, Enable3DViewCommand &command) +QDataStream &operator>>(QDataStream &in, View3DActionCommand &command) { - qint32 enable; - in >> enable; - command.m_enable = enable; + qint32 enabled; + qint32 type; + in >> enabled; + in >> type; + command.m_enabled = bool(enabled); + command.m_type = View3DActionCommand::Type(type); return in; } -QDebug operator<<(QDebug debug, const Enable3DViewCommand &command) +QDebug operator<<(QDebug debug, const View3DActionCommand &command) { - return debug.nospace() << "Enable3DViewCommand(enable: " << command.m_enable << ")"; + return debug.nospace() << "View3DActionCommand(type: " + << command.m_type << "," + << command.m_enabled << ")"; } } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h new file mode 100644 index 00000000000..9f25e2abb4b --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 + +namespace QmlDesigner { + +class View3DActionCommand +{ + friend QDataStream &operator>>(QDataStream &in, View3DActionCommand &command); + friend QDebug operator<<(QDebug debug, const View3DActionCommand &command); + +public: + enum Type { Empty, + MoveTool, + ScaleTool, + RotateTool, + FitToView, + SelectionModeToggle, + CameraToggle, + OrientationToggle, + EditLightToggle + }; + + explicit View3DActionCommand(Type type, bool enable); + View3DActionCommand() = default; + + bool isEnabled() const; + Type type() const; + +private: + Type m_type = Empty; + bool m_enabled = false; +}; + +QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command); +QDataStream &operator>>(QDataStream &in, View3DActionCommand &command); + +QDebug operator<<(QDebug debug, const View3DActionCommand &command); + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::View3DActionCommand) diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp index b6b17f1bfab..e42c8bb3a2a 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp @@ -42,7 +42,6 @@ #include "createinstancescommand.h" #include "createscenecommand.h" #include "update3dviewstatecommand.h" -#include "enable3dviewcommand.h" #include "changevaluescommand.h" #include "changebindingscommand.h" #include "changeauxiliarycommand.h" @@ -57,6 +56,8 @@ #include "synchronizecommand.h" #include "removesharedmemorycommand.h" #include "tokencommand.h" +#include "inputeventcommand.h" +#include "view3dactioncommand.h" #include "informationchangedcommand.h" #include "pixmapchangedcommand.h" @@ -328,6 +329,16 @@ QVariant NodeInstanceClientProxy::readCommandFromIOStream(QIODevice *ioDevice, q return command; } +void NodeInstanceClientProxy::inputEvent(const InputEventCommand &command) +{ + nodeInstanceServer()->inputEvent(command); +} + +void NodeInstanceClientProxy::view3DAction(const View3DActionCommand &command) +{ + nodeInstanceServer()->view3DAction(command); +} + void NodeInstanceClientProxy::readDataStream() { QList commandList; @@ -386,11 +397,6 @@ void NodeInstanceClientProxy::update3DViewState(const Update3dViewStateCommand & nodeInstanceServer()->update3DViewState(command); } -void NodeInstanceClientProxy::enable3DView(const Enable3DViewCommand &command) -{ - nodeInstanceServer()->enable3DView(command); -} - void NodeInstanceClientProxy::clearScene(const ClearSceneCommand &command) { nodeInstanceServer()->clearScene(command); @@ -479,7 +485,6 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command) { static const int createInstancesCommandType = QMetaType::type("CreateInstancesCommand"); static const int update3dViewStateCommand = QMetaType::type("Update3dViewStateCommand"); - static const int enable3DViewCommandType = QMetaType::type("Enable3DViewCommand"); static const int changeFileUrlCommandType = QMetaType::type("ChangeFileUrlCommand"); static const int createSceneCommandType = QMetaType::type("CreateSceneCommand"); static const int clearSceneCommandType = QMetaType::type("ClearSceneCommand"); @@ -498,15 +503,17 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command) static const int tokenCommandType = QMetaType::type("TokenCommand"); static const int endPuppetCommandType = QMetaType::type("EndPuppetCommand"); static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand"); + static const int inputEventCommandType = QMetaType::type("InputEventCommand"); + static const int view3DActionCommandType = QMetaType::type("View3DActionCommand"); const int commandType = command.userType(); - if (commandType == createInstancesCommandType) + if (commandType == inputEventCommandType) + inputEvent(command.value()); + else if (commandType == createInstancesCommandType) createInstances(command.value()); else if (commandType == update3dViewStateCommand) update3DViewState(command.value()); - else if (commandType == enable3DViewCommandType) - enable3DView(command.value()); else if (commandType == changeFileUrlCommandType) changeFileUrl(command.value()); else if (commandType == createSceneCommandType) @@ -539,6 +546,8 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command) redirectToken(command.value()); else if (commandType == endPuppetCommandType) redirectToken(command.value()); + else if (commandType == view3DActionCommandType) + view3DAction(command.value()); else if (commandType == synchronizeCommandType) { SynchronizeCommand synchronizeCommand = command.value(); m_synchronizeId = synchronizeCommand.synchronizeId(); diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h index 6a114bbe3e1..6cafd282af4 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h @@ -46,7 +46,6 @@ class CreateInstancesCommand; class ClearSceneCommand; class ReparentInstancesCommand; class Update3dViewStateCommand; -class Enable3DViewCommand; class ChangeFileUrlCommand; class ChangeValuesCommand; class ChangeAuxiliaryCommand; @@ -62,6 +61,8 @@ class ChangeSelectionCommand; class Drop3DLibraryItemCommand; class PuppetToCreatorCommand; class View3DClosedCommand; +class InputEventCommand; +class View3DActionCommand; class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface { @@ -102,7 +103,6 @@ protected: void createScene(const CreateSceneCommand &command); void clearScene(const ClearSceneCommand &command); void update3DViewState(const Update3dViewStateCommand &command); - void enable3DView(const Enable3DViewCommand &command); void removeInstances(const RemoveInstancesCommand &command); void removeProperties(const RemovePropertiesCommand &command); void changePropertyBindings(const ChangeBindingsCommand &command); @@ -118,6 +118,8 @@ protected: void redirectToken(const EndPuppetCommand &command); void changeSelection(const ChangeSelectionCommand &command); static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize); + void inputEvent(const InputEventCommand &command); + void view3DAction(const View3DActionCommand &command); protected slots: void readDataStream(); diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp index 5c7c9d2953a..b2703f7f320 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp @@ -33,7 +33,6 @@ #include "createinstancescommand.h" #include "createscenecommand.h" #include "update3dviewstatecommand.h" -#include "enable3dviewcommand.h" #include "changevaluescommand.h" #include "changebindingscommand.h" #include "changeauxiliarycommand.h" @@ -49,6 +48,8 @@ #include "changenodesourcecommand.h" #include "changeselectioncommand.h" #include "drop3dlibraryitemcommand.h" +#include "inputeventcommand.h" +#include "view3dactioncommand.h" #include "informationchangedcommand.h" #include "pixmapchangedcommand.h" @@ -97,9 +98,6 @@ void NodeInstanceServerInterface::registerCommands() qRegisterMetaType("Update3dViewStateCommand"); qRegisterMetaTypeStreamOperators("Update3dViewStateCommand"); - qRegisterMetaType("Enable3DViewCommand"); - qRegisterMetaTypeStreamOperators("Enable3DViewCommand"); - qRegisterMetaType("ChangeBindingsCommand"); qRegisterMetaTypeStreamOperators("ChangeBindingsCommand"); @@ -214,6 +212,12 @@ void NodeInstanceServerInterface::registerCommands() qRegisterMetaType("PuppetToCreatorCommand"); qRegisterMetaTypeStreamOperators("PuppetToCreatorCommand"); + qRegisterMetaType("InputEventCommand"); + qRegisterMetaTypeStreamOperators("InputEventCommand"); + + qRegisterMetaType("View3DActionCommand"); + qRegisterMetaTypeStreamOperators("View3DActionCommand"); + qRegisterMetaType>("QPairIntInt"); qRegisterMetaTypeStreamOperators>("QPairIntInt"); } diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h index e60d99b1e19..0c6009e4778 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h @@ -34,7 +34,6 @@ class PropertyBindingContainer; class PropertyValueContainer; class Update3dViewStateCommand; -class Enable3DViewCommand; class ChangeFileUrlCommand; class ChangeValuesCommand; class ChangeBindingsCommand; @@ -52,6 +51,8 @@ class ChangeNodeSourceCommand; class TokenCommand; class RemoveSharedMemoryCommand; class ChangeSelectionCommand; +class InputEventCommand; +class View3DActionCommand; class NodeInstanceServerInterface : public QObject { @@ -69,7 +70,6 @@ public: virtual void createScene(const CreateSceneCommand &command) = 0; virtual void clearScene(const ClearSceneCommand &command) = 0; virtual void update3DViewState(const Update3dViewStateCommand &command) = 0; - virtual void enable3DView(const Enable3DViewCommand &command) = 0; virtual void removeInstances(const RemoveInstancesCommand &command) = 0; virtual void removeProperties(const RemovePropertiesCommand &command) = 0; virtual void changePropertyBindings(const ChangeBindingsCommand &command) = 0; @@ -83,6 +83,8 @@ public: virtual void token(const TokenCommand &command) = 0; virtual void removeSharedMemory(const RemoveSharedMemoryCommand &command) = 0; virtual void changeSelection(const ChangeSelectionCommand &command) = 0; + virtual void inputEvent(const InputEventCommand &command) = 0; + virtual void view3DAction(const View3DActionCommand &command) = 0; virtual void benchmark(const QString &) {} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 4b90659e6e6..9ee23e48a4e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -30,16 +30,11 @@ import QtQuick.Controls 2.0 import QtGraphicalEffects 1.0 import MouseArea3D 1.0 -Window { - id: viewWindow +Item { + id: viewRoot width: 1024 height: 768 - minimumHeight: 200 - minimumWidth: 200 visible: true - title: qsTr("3D Edit View [") + sceneId + qsTr("]") - // need all those flags otherwise the title bar disappears after setting WindowStaysOnTopHint flag later - flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint property Node activeScene: null property View3D editView: null @@ -48,6 +43,7 @@ Window { property alias showEditLight: btnEditViewLight.toggled property alias usePerspective: btnPerspective.toggled property alias globalOrientation: btnLocalGlobal.toggled + property alias contentItem: contentItem property Node selectedNode: null // This is non-null only in single selection case property var selectedNodes: [] // All selected nodes @@ -57,6 +53,8 @@ Window { property var selectionBoxes: [] property rect viewPortRect: Qt.rect(0, 0, 1000, 1000) + property bool showButtons: false + signal selectionChanged(var selectedNodes) signal commitObjectProperty(var object, var propName) signal changeObjectProperty(var object, var propName) @@ -86,7 +84,7 @@ Window { editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; - updateToolStates(); + updateToolStates(_generalHelper.getToolStates(sceneId), true); } } } @@ -99,54 +97,62 @@ Window { _generalHelper.enableItemUpdate(editView, (scene && scene === activeScene)); } - - function restoreWindowState() + function fitToView() { - // It is expected that tool states have been initialized before calling this - _generalHelper.restoreWindowState(viewWindow); + if (editView) { + var targetNode = selectedNodes.length > 0 + ? selectionBoxes[0].model : null; + cameraControl.focusObject(targetNode, editView.camera.rotation, true); + } } - function updateToolStates() + // If resetToDefault is true, tool states not specifically set to anything will be reset to + // their default state. + function updateToolStates(toolStates, resetToDefault) { - var toolStates = _generalHelper.getToolStates(sceneId); if ("showEditLight" in toolStates) showEditLight = toolStates.showEditLight; - else + else if (resetToDefault) showEditLight = false; if ("usePerspective" in toolStates) usePerspective = toolStates.usePerspective; - else + else if (resetToDefault) usePerspective = false; if ("globalOrientation" in toolStates) globalOrientation = toolStates.globalOrientation; - else + else if (resetToDefault) globalOrientation = false; var groupIndex; var group; var i; - btnSelectItem.selected = false; - btnSelectGroup.selected = true; + if ("groupSelect" in toolStates) { groupIndex = toolStates.groupSelect; group = toolbarButtons.buttonGroups["groupSelect"]; for (i = 0; i < group.length; ++i) group[i].selected = (i === groupIndex); + _generalHelper.storeToolState(sceneId, "groupSelect", groupIndex) + } else if (resetToDefault) { + btnSelectItem.selected = true; + btnSelectGroup.selected = false; } - btnRotate.selected = false; - btnScale.selected = false; - btnMove.selected = true; if ("groupTransform" in toolStates) { groupIndex = toolStates.groupTransform; group = toolbarButtons.buttonGroups["groupTransform"]; for (i = 0; i < group.length; ++i) group[i].selected = (i === groupIndex); + _generalHelper.storeToolState(sceneId, "groupTransform", groupIndex) + } else if (resetToDefault) { + btnRotate.selected = false; + btnScale.selected = false; + btnMove.selected = true; } if ("editCamState" in toolStates) cameraControl.restoreCameraState(toolStates.editCamState); - else + else if (resetToDefault) cameraControl.restoreDefaultState(); } @@ -324,37 +330,27 @@ Window { _generalHelper.requestOverlayUpdate(); } - onWidthChanged: { - _generalHelper.requestOverlayUpdate(); - _generalHelper.storeWindowState(viewWindow); - } - onHeightChanged: { - _generalHelper.requestOverlayUpdate(); - _generalHelper.storeWindowState(viewWindow); - - } - onXChanged: _generalHelper.storeWindowState(viewWindow); - onYChanged: _generalHelper.storeWindowState(viewWindow); - onWindowStateChanged: _generalHelper.storeWindowState(viewWindow); + onWidthChanged: _generalHelper.requestOverlayUpdate() + onHeightChanged: _generalHelper.requestOverlayUpdate() Node { id: overlayScene PerspectiveCamera { id: overlayPerspectiveCamera - clipFar: viewWindow.editView ? viewWindow.editView.perpectiveCamera.clipFar : 1000 - clipNear: viewWindow.editView ? viewWindow.editView.perpectiveCamera.clipNear : 1 - position: viewWindow.editView ? viewWindow.editView.perpectiveCamera.position : Qt.vector3d(0, 0, 0) - rotation: viewWindow.editView ? viewWindow.editView.perpectiveCamera.rotation : Qt.vector3d(0, 0, 0) + clipFar: viewRoot.editView ? viewRoot.editView.perpectiveCamera.clipFar : 1000 + clipNear: viewRoot.editView ? viewRoot.editView.perpectiveCamera.clipNear : 1 + position: viewRoot.editView ? viewRoot.editView.perpectiveCamera.position : Qt.vector3d(0, 0, 0) + rotation: viewRoot.editView ? viewRoot.editView.perpectiveCamera.rotation : Qt.vector3d(0, 0, 0) } OrthographicCamera { id: overlayOrthoCamera - clipFar: viewWindow.editView ? viewWindow.editView.orthoCamera.clipFar : 1000 - clipNear: viewWindow.editView ? viewWindow.editView.orthoCamera.clipNear : 1 - position: viewWindow.editView ? viewWindow.editView.orthoCamera.position : Qt.vector3d(0, 0, 0) - rotation: viewWindow.editView ? viewWindow.editView.orthoCamera.rotation : Qt.vector3d(0, 0, 0) - scale: viewWindow.editView ? viewWindow.editView.orthoCamera.scale : Qt.vector3d(0, 0, 0) + clipFar: viewRoot.editView ? viewRoot.editView.orthoCamera.clipFar : 1000 + clipNear: viewRoot.editView ? viewRoot.editView.orthoCamera.clipNear : 1 + position: viewRoot.editView ? viewRoot.editView.orthoCamera.position : Qt.vector3d(0, 0, 0) + rotation: viewRoot.editView ? viewRoot.editView.orthoCamera.rotation : Qt.vector3d(0, 0, 0) + scale: viewRoot.editView ? viewRoot.editView.orthoCamera.scale : Qt.vector3d(0, 0, 0) } MouseArea3D { @@ -366,41 +362,41 @@ Window { id: moveGizmo scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) highlightOnHover: true - targetNode: viewWindow.selectedNode - globalOrientation: viewWindow.globalOrientation - visible: viewWindow.selectedNode && btnMove.selected + targetNode: viewRoot.selectedNode + globalOrientation: viewRoot.globalOrientation + visible: viewRoot.selectedNode && btnMove.selected view3D: overlayView dragHelper: gizmoDragHelper - onPositionCommit: viewWindow.commitObjectProperty(viewWindow.selectedNode, "position") - onPositionMove: viewWindow.changeObjectProperty(viewWindow.selectedNode, "position") + onPositionCommit: viewRoot.commitObjectProperty(viewRoot.selectedNode, "position") + onPositionMove: viewRoot.changeObjectProperty(viewRoot.selectedNode, "position") } ScaleGizmo { id: scaleGizmo scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) highlightOnHover: true - targetNode: viewWindow.selectedNode - visible: viewWindow.selectedNode && btnScale.selected + targetNode: viewRoot.selectedNode + visible: viewRoot.selectedNode && btnScale.selected view3D: overlayView dragHelper: gizmoDragHelper - onScaleCommit: viewWindow.commitObjectProperty(viewWindow.selectedNode, "scale") - onScaleChange: viewWindow.changeObjectProperty(viewWindow.selectedNode, "scale") + onScaleCommit: viewRoot.commitObjectProperty(viewRoot.selectedNode, "scale") + onScaleChange: viewRoot.changeObjectProperty(viewRoot.selectedNode, "scale") } RotateGizmo { id: rotateGizmo scale: autoScale.getScale(Qt.vector3d(7, 7, 7)) highlightOnHover: true - targetNode: viewWindow.selectedNode - globalOrientation: viewWindow.globalOrientation - visible: viewWindow.selectedNode && btnRotate.selected + targetNode: viewRoot.selectedNode + globalOrientation: viewRoot.globalOrientation + visible: viewRoot.selectedNode && btnRotate.selected view3D: overlayView dragHelper: gizmoDragHelper - onRotateCommit: viewWindow.commitObjectProperty(viewWindow.selectedNode, "rotation") - onRotateChange: viewWindow.changeObjectProperty(viewWindow.selectedNode, "rotation") + onRotateCommit: viewRoot.commitObjectProperty(viewRoot.selectedNode, "rotation") + onRotateChange: viewRoot.changeObjectProperty(viewRoot.selectedNode, "rotation") } AutoScaleHelper { @@ -412,31 +408,31 @@ Window { Line3D { id: pivotLine - visible: viewWindow.selectedNode + visible: viewRoot.selectedNode name: "3D Edit View Pivot Line" color: "#ddd600" function flipIfNeeded(vec) { - if (!viewWindow.selectedNode || viewWindow.selectedNode.orientation === Node.LeftHanded) + if (!viewRoot.selectedNode || viewRoot.selectedNode.orientation === Node.LeftHanded) return vec; else return Qt.vector3d(vec.x, vec.y, -vec.z); } - startPos: viewWindow.selectedNode ? flipIfNeeded(viewWindow.selectedNode.scenePosition) + startPos: viewRoot.selectedNode ? flipIfNeeded(viewRoot.selectedNode.scenePosition) : Qt.vector3d(0, 0, 0) Connections { - target: viewWindow + target: viewRoot onSelectedNodeChanged: { pivotLine.endPos = pivotLine.flipIfNeeded(gizmoDragHelper.pivotScenePosition( - viewWindow.selectedNode)); + viewRoot.selectedNode)); } } Connections { - target: viewWindow.selectedNode + target: viewRoot.selectedNode onSceneTransformChanged: { pivotLine.endPos = pivotLine.flipIfNeeded(gizmoDragHelper.pivotScenePosition( - viewWindow.selectedNode)); + viewRoot.selectedNode)); } } @@ -457,243 +453,235 @@ Window { } } - Rectangle { - id: viewRect + Item { + id: contentItem anchors.fill: parent - focus: true - gradient: Gradient { - GradientStop { position: 1.0; color: "#222222" } - GradientStop { position: 0.0; color: "#999999" } - } - - MouseArea { + Rectangle { + id: viewRect anchors.fill: parent - acceptedButtons: Qt.LeftButton - onClicked: { - if (viewWindow.editView) { - var pickResult = viewWindow.editView.pick(mouse.x, mouse.y); - handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit), - mouse.modifiers & Qt.ControlModifier); - if (!pickResult.objectHit) - mouse.accepted = false; + focus: true + + gradient: Gradient { + GradientStop { position: 1.0; color: "#222222" } + GradientStop { position: 0.0; color: "#999999" } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + onClicked: { + if (viewRoot.editView) { + var pickResult = viewRoot.editView.pick(mouse.x, mouse.y); + handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit), + mouse.modifiers & Qt.ControlModifier); + if (!pickResult.objectHit) + mouse.accepted = false; + } } } - } - DropArea { - anchors.fill: parent - } + DropArea { + anchors.fill: parent + } - View3D { - id: overlayView - anchors.fill: parent - camera: usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera - importScene: overlayScene - z: 2 - } + View3D { + id: overlayView + anchors.fill: parent + camera: usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera + importScene: overlayScene + z: 2 + } - Overlay2D { - id: gizmoLabel - targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo - targetView: overlayView - visible: targetNode.dragging - z: 3 + Overlay2D { + id: gizmoLabel + targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo + targetView: overlayView + visible: targetNode.dragging + z: 3 - Rectangle { - color: "white" - x: -width / 2 - y: -height - 8 - width: gizmoLabelText.width + 4 - height: gizmoLabelText.height + 4 - border.width: 1 - Text { - id: gizmoLabelText - text: { - var l = Qt.locale(); - var targetProperty; - if (viewWindow.selectedNode) { - if (gizmoLabel.targetNode === moveGizmo) - targetProperty = viewWindow.selectedNode.position; - else - targetProperty = viewWindow.selectedNode.scale; - return qsTr("x:") + Number(targetProperty.x).toLocaleString(l, 'f', 1) - + qsTr(" y:") + Number(targetProperty.y).toLocaleString(l, 'f', 1) - + qsTr(" z:") + Number(targetProperty.z).toLocaleString(l, 'f', 1); - } else { - return ""; + Rectangle { + color: "white" + x: -width / 2 + y: -height - 8 + width: gizmoLabelText.width + 4 + height: gizmoLabelText.height + 4 + border.width: 1 + Text { + id: gizmoLabelText + text: { + var l = Qt.locale(); + var targetProperty; + if (viewRoot.selectedNode) { + if (gizmoLabel.targetNode === moveGizmo) + targetProperty = viewRoot.selectedNode.position; + else + targetProperty = viewRoot.selectedNode.scale; + return qsTr("x:") + Number(targetProperty.x).toLocaleString(l, 'f', 1) + + qsTr(" y:") + Number(targetProperty.y).toLocaleString(l, 'f', 1) + + qsTr(" z:") + Number(targetProperty.z).toLocaleString(l, 'f', 1); + } else { + return ""; + } } + anchors.centerIn: parent } - anchors.centerIn: parent } } + + EditCameraController { + id: cameraControl + camera: viewRoot.editView ? viewRoot.editView.camera : null + anchors.fill: parent + view3d: viewRoot.editView + sceneId: viewRoot.sceneId + } } - EditCameraController { - id: cameraControl - camera: viewWindow.editView ? viewWindow.editView.camera : null - anchors.fill: parent - view3d: viewWindow.editView - sceneId: viewWindow.sceneId - } - } + Rectangle { // toolbar + id: toolbar + color: "#9F000000" + width: 35 + height: toolbarButtons.height + visible: viewRoot.showButtons - Rectangle { // toolbar - id: toolbar - color: "#9F000000" - width: 35 - height: toolbarButtons.height - - Column { - id: toolbarButtons - anchors.horizontalCenter: parent.horizontalCenter - spacing: 5 - padding: 5 - - // Button groups must be defined in parent object of buttons - property var buttonGroups: { - "groupSelect": [btnSelectGroup, btnSelectItem], - "groupTransform": [btnMove, btnRotate, btnScale] - } - - ToolBarButton { - id: btnSelectItem - selected: true - tooltip: qsTr("Select Item") - shortcut: "Q" - currentShortcut: selected ? "" : shortcut - tool: "item_selection" - buttonGroup: "groupSelect" - sceneId: viewWindow.sceneId - } - - ToolBarButton { - id: btnSelectGroup - tooltip: qsTr("Select Group") - shortcut: "Q" - currentShortcut: btnSelectItem.currentShortcut === shortcut ? "" : shortcut - tool: "group_selection" - buttonGroup: "groupSelect" - sceneId: viewWindow.sceneId - } - - Rectangle { // separator - width: 25 - height: 1 - color: "#f1f1f1" + Column { + id: toolbarButtons anchors.horizontalCenter: parent.horizontalCenter - } + spacing: 5 + padding: 5 - ToolBarButton { - id: btnMove - selected: true - tooltip: qsTr("Move current selection") - shortcut: "W" - currentShortcut: shortcut - tool: "move" - buttonGroup: "groupTransform" - sceneId: viewWindow.sceneId - } + // Button groups must be defined in parent object of buttons + property var buttonGroups: { + "groupSelect": [btnSelectGroup, btnSelectItem], + "groupTransform": [btnMove, btnRotate, btnScale] + } - ToolBarButton { - id: btnRotate - tooltip: qsTr("Rotate current selection") - shortcut: "E" - currentShortcut: shortcut - tool: "rotate" - buttonGroup: "groupTransform" - sceneId: viewWindow.sceneId - } + ToolBarButton { + id: btnSelectItem + selected: true + tooltip: qsTr("Select Item") + shortcut: "Q" + currentShortcut: selected ? "" : shortcut + tool: "item_selection" + buttonGroup: "groupSelect" + sceneId: viewRoot.sceneId + } - ToolBarButton { - id: btnScale - tooltip: qsTr("Scale current selection") - shortcut: "R" - currentShortcut: shortcut - tool: "scale" - buttonGroup: "groupTransform" - sceneId: viewWindow.sceneId - } + ToolBarButton { + id: btnSelectGroup + tooltip: qsTr("Select Group") + shortcut: "Q" + currentShortcut: btnSelectItem.currentShortcut === shortcut ? "" : shortcut + tool: "group_selection" + buttonGroup: "groupSelect" + sceneId: viewRoot.sceneId + } - Rectangle { // separator - width: 25 - height: 1 - color: "#f1f1f1" - anchors.horizontalCenter: parent.horizontalCenter - } + Rectangle { // separator + width: 25 + height: 1 + color: "#f1f1f1" + anchors.horizontalCenter: parent.horizontalCenter + } - ToolBarButton { - id: btnFit - tooltip: qsTr("Fit camera to current selection") - shortcut: "F" - currentShortcut: shortcut - tool: "fit" - togglable: false + ToolBarButton { + id: btnMove + selected: true + tooltip: qsTr("Move current selection") + shortcut: "W" + currentShortcut: shortcut + tool: "move" + buttonGroup: "groupTransform" + sceneId: viewRoot.sceneId + } - onSelectedChanged: { - if (viewWindow.editView && selected) { - var targetNode = viewWindow.selectedNodes.length > 0 - ? selectionBoxes[0].model : null; - cameraControl.focusObject(targetNode, viewWindow.editView.camera.rotation, true); + ToolBarButton { + id: btnRotate + tooltip: qsTr("Rotate current selection") + shortcut: "E" + currentShortcut: shortcut + tool: "rotate" + buttonGroup: "groupTransform" + sceneId: viewRoot.sceneId + } + + ToolBarButton { + id: btnScale + tooltip: qsTr("Scale current selection") + shortcut: "R" + currentShortcut: shortcut + tool: "scale" + buttonGroup: "groupTransform" + sceneId: viewRoot.sceneId + } + + Rectangle { // separator + width: 25 + height: 1 + color: "#f1f1f1" + anchors.horizontalCenter: parent.horizontalCenter + } + + ToolBarButton { + id: btnFit + tooltip: qsTr("Fit camera to current selection") + shortcut: "F" + currentShortcut: shortcut + tool: "fit" + togglable: false + + onSelectedChanged: { + if (selected) + viewRoot.fitToView(); } } } } - } - AxisHelper { - anchors.right: parent.right - anchors.top: parent.top - width: 100 - height: width - editCameraCtrl: cameraControl - selectedNode : viewWindow.selectedNodes.length ? selectionBoxes[0].model : null - } - - Rectangle { // top controls bar - color: "#aa000000" - width: 290 - height: btnPerspective.height + 10 - anchors.top: parent.top - anchors.right: parent.right - anchors.rightMargin: 100 - - Row { - padding: 5 - anchors.fill: parent - ToggleButton { - id: btnPerspective - width: 105 - tooltip: qsTr("Toggle Perspective / Orthographic Projection") - states: [{iconId: "ortho", text: qsTr("Orthographic")}, {iconId: "persp", text: qsTr("Perspective")}] - } - - ToggleButton { - id: btnLocalGlobal - width: 65 - tooltip: qsTr("Toggle Global / Local Orientation") - states: [{iconId: "local", text: qsTr("Local")}, {iconId: "global", text: qsTr("Global")}] - } - - ToggleButton { - id: btnEditViewLight - width: 110 - toggleBackground: true - tooltip: qsTr("Toggle Edit Light") - states: [{iconId: "edit_light_off", text: qsTr("Edit Light Off")}, {iconId: "edit_light_on", text: qsTr("Edit Light On")}] - } + AxisHelper { + anchors.right: parent.right + anchors.top: parent.top + width: 100 + height: width + editCameraCtrl: cameraControl + selectedNode : viewRoot.selectedNodes.length ? selectionBoxes[0].model : null } - } + Rectangle { // top controls bar + color: "#aa000000" + width: 290 + height: btnPerspective.height + 10 + anchors.top: parent.top + anchors.right: parent.right + anchors.rightMargin: 100 + visible: viewRoot.showButtons - Text { - id: helpText + Row { + padding: 5 + anchors.fill: parent + ToggleButton { + id: btnPerspective + width: 105 + tooltip: qsTr("Toggle Perspective / Orthographic Projection") + states: [{iconId: "ortho", text: qsTr("Orthographic")}, {iconId: "persp", text: qsTr("Perspective")}] + } - property string modKey: _generalHelper.isMacOS ? qsTr("Option") : qsTr("Alt") + ToggleButton { + id: btnLocalGlobal + width: 65 + tooltip: qsTr("Toggle Global / Local Orientation") + states: [{iconId: "local", text: qsTr("Local")}, {iconId: "global", text: qsTr("Global")}] + } - color: "white" - text: qsTr("Camera controls: ") + modKey - + qsTr(" + mouse press and drag. Left: Rotate, Middle: Pan, Right/Wheel: Zoom.") - anchors.bottom: parent.bottom + ToggleButton { + id: btnEditViewLight + width: 110 + toggleBackground: true + tooltip: qsTr("Toggle Edit Light") + states: [{iconId: "edit_light_off", text: qsTr("Edit Light Off")}, {iconId: "edit_light_on", text: qsTr("Edit Light On")}] + } + } + } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditWindow3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditWindow3D.qml new file mode 100644 index 00000000000..4ec92e63c35 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditWindow3D.qml @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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.12 +import QtQuick.Window 2.12 + +Window { + id: viewWindow + width: 1024 + height: 768 + visible: true + title: qsTr("3D Edit View [") + sceneId + qsTr("]") + // need all those flags otherwise the title bar disappears after setting WindowStaysOnTopHint flag later + flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint + + property alias editViewRoot: windowContentItem + + onWidthChanged: _generalHelper.storeWindowState(); + onHeightChanged: _generalHelper.storeWindowState(); + onXChanged: _generalHelper.storeWindowState(); + onYChanged: _generalHelper.storeWindowState(); + onWindowStateChanged: _generalHelper.storeWindowState(); + + EditView3D { + id: windowContentItem + anchors.fill: parent + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml index a198cae04bc..77f3a54a055 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml @@ -45,7 +45,7 @@ Node { } property alias iconSource: iconImage.source - property alias overlayColor: colorOverlay.color + //property alias overlayColor: colorOverlay.color signal positionCommit() signal clicked(Node node, bool multi) @@ -94,15 +94,15 @@ Node { acceptedButtons: Qt.LeftButton } } - ColorOverlay { - id: colorOverlay - anchors.fill: parent - cached: true - source: iconImage - color: "transparent" - opacity: 0.6 - } - +// ColorOverlay doesn't work correctly with hidden windows so commenting it out for now +// ColorOverlay { +// id: colorOverlay +// anchors.fill: parent +// cached: true +// source: iconImage +// color: "#00000000" +// opacity: 0.6 +// } } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml index 6e321f8398a..7c9953e9bb5 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml @@ -37,5 +37,6 @@ IconGizmo { : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" - overlayColor: targetNode ? targetNode.color : "transparent" + // ColorOverlay doesn't work correctly with hidden windows so commenting it out for now + //overlayColor: targetNode ? targetNode.color : "transparent" } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 7c33ab2b8e4..c123a68d47d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -48,7 +48,7 @@ namespace QmlDesigner { namespace Internal { -const QString globalStateId = QStringLiteral("@GTS"); // global tool state +const QString _globalStateId = QStringLiteral("@GTS"); // global tool state GeneralHelper::GeneralHelper() : QObject() @@ -260,37 +260,42 @@ void GeneralHelper::initToolStates(const QString &sceneId, const QVariantMap &to m_toolStates[sceneId] = toolStates; } -void GeneralHelper::storeWindowState(QQuickWindow *w) +void GeneralHelper::storeWindowState() { + if (!m_edit3DWindow) + return; + QVariantMap windowState; - const QRect geometry = w->geometry(); - const bool maximized = w->windowState() == Qt::WindowMaximized; + const QRect geometry = m_edit3DWindow->geometry(); + const bool maximized = m_edit3DWindow->windowState() == Qt::WindowMaximized; windowState.insert("maximized", maximized); windowState.insert("geometry", geometry); - storeToolState(globalStateId, "windowState", windowState, 500); + storeToolState(globalStateId(), "windowState", windowState, 500); } -void GeneralHelper::restoreWindowState(QQuickWindow *w) +void GeneralHelper::restoreWindowState() { - if (m_toolStates.contains(globalStateId)) { - const QVariantMap &globalStateMap = m_toolStates[globalStateId]; + if (!m_edit3DWindow) + return; + + if (m_toolStates.contains(globalStateId())) { + const QVariantMap &globalStateMap = m_toolStates[globalStateId()]; const QString stateKey = QStringLiteral("windowState"); if (globalStateMap.contains(stateKey)) { QVariantMap windowState = globalStateMap[stateKey].value(); - doRestoreWindowState(w, windowState); + doRestoreWindowState(windowState); // If the mouse cursor at puppet launch time is in a different screen than the one where the // view geometry was saved on, the initial position and size can be incorrect, but if // we reset the geometry again asynchronously, it should end up with correct geometry. - QTimer::singleShot(0, [this, w, windowState]() { - doRestoreWindowState(w, windowState); - - QTimer::singleShot(0, [w]() { + QTimer::singleShot(0, [this, windowState]() { + doRestoreWindowState(windowState); + QTimer::singleShot(0, [this]() { // Make sure that the window is at least partially visible on the screen - QRect geo = w->geometry(); - QRect sRect = w->screen()->geometry(); + QRect geo = m_edit3DWindow->geometry(); + QRect sRect = m_edit3DWindow->screen()->geometry(); if (geo.left() > sRect.right() - 150) geo.moveRight(sRect.right()); if (geo.right() < sRect.left() + 150) @@ -303,7 +308,7 @@ void GeneralHelper::restoreWindowState(QQuickWindow *w) geo.setWidth(sRect.width()); if (geo.height() > sRect.height()) geo.setHeight(sRect.height()); - w->setGeometry(geo); + m_edit3DWindow->setGeometry(geo); }); }); } @@ -324,7 +329,17 @@ QVariantMap GeneralHelper::getToolStates(const QString &sceneId) return {}; } -void GeneralHelper::doRestoreWindowState(QQuickWindow *w, const QVariantMap &windowState) +void GeneralHelper::setEdit3DWindow(QQuickWindow *w) +{ + m_edit3DWindow = w; +} + +QString GeneralHelper::globalStateId() const +{ + return _globalStateId; +} + +void GeneralHelper::doRestoreWindowState(const QVariantMap &windowState) { const QString geoKey = QStringLiteral("geometry"); if (windowState.contains(geoKey)) { @@ -335,9 +350,9 @@ void GeneralHelper::doRestoreWindowState(QQuickWindow *w, const QVariantMap &win QRect rect = windowState[geoKey].value(); - w->setGeometry(rect); + m_edit3DWindow->setGeometry(rect); if (maximized) - w->showMaximized(); + m_edit3DWindow->showMaximized(); } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index a6b66907488..f36e7458173 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -74,10 +75,12 @@ public: Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool, const QVariant &state, int delayEmit = 0); void initToolStates(const QString &sceneId, const QVariantMap &toolStates); - Q_INVOKABLE void storeWindowState(QQuickWindow *w); - void restoreWindowState(QQuickWindow *w); + Q_INVOKABLE void storeWindowState(); + void restoreWindowState(); Q_INVOKABLE void enableItemUpdate(QQuickItem *item, bool enable); Q_INVOKABLE QVariantMap getToolStates(const QString &sceneId); + void setEdit3DWindow(QQuickWindow *w); + QString globalStateId() const; bool isMacOS() const; @@ -86,7 +89,7 @@ signals: void toolStateChanged(const QString &sceneId, const QString &tool, const QVariant &toolState); private slots: - void doRestoreWindowState(QQuickWindow *w, const QVariantMap &windowState); + void doRestoreWindowState(const QVariantMap &windowState); private: void handlePendingToolStateUpdate(); @@ -95,6 +98,7 @@ private: QTimer m_toolStateUpdateTimer; QHash m_toolStates; QHash m_toolStatesPending; + QPointer m_edit3DWindow; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index d772844b3c6..2b5f805f174 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -68,6 +68,8 @@ #include #include #include +#include +#include #include #include @@ -336,10 +338,6 @@ void NodeInstanceServer::update3DViewState(const Update3dViewStateCommand &/*com { } -void NodeInstanceServer::enable3DView(const Enable3DViewCommand &/*command*/) -{ -} - void NodeInstanceServer::changeSelection(const ChangeSelectionCommand & /*command*/) { } @@ -1395,6 +1393,16 @@ QStringList NodeInstanceServer::dummyDataDirectories(const QString& directoryPat } } +void NodeInstanceServer::inputEvent(const InputEventCommand &command) +{ + Q_UNUSED(command) +} + +void NodeInstanceServer::view3DAction(const View3DActionCommand &command) +{ + Q_UNUSED(command) +} + } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index 1c3ee59791c..e2a5528bcf1 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -102,7 +102,6 @@ public: void createScene(const CreateSceneCommand &command) override; void clearScene(const ClearSceneCommand &command) override; void update3DViewState(const Update3dViewStateCommand &command) override; - void enable3DView(const Enable3DViewCommand &command) override; void removeInstances(const RemoveInstancesCommand &command) override; void removeProperties(const RemovePropertiesCommand &command) override; void reparentInstances(const ReparentInstancesCommand &command) override; @@ -112,6 +111,8 @@ public: void token(const TokenCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void changeSelection(const ChangeSelectionCommand &command) override; + void inputEvent(const InputEventCommand &command) override; + void view3DAction(const View3DActionCommand &command) override; ServerNodeInstance instanceForId(qint32 id) const; bool hasInstanceForId(qint32 id) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index a30f972025e..a82859a36c4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -41,7 +41,6 @@ #include "clearscenecommand.h" #include "reparentinstancescommand.h" #include "update3dviewstatecommand.h" -#include "enable3dviewcommand.h" #include "changevaluescommand.h" #include "changebindingscommand.h" #include "changeidscommand.h" @@ -63,6 +62,8 @@ #include "drop3dlibraryitemcommand.h" #include "puppettocreatorcommand.h" #include "view3dclosedcommand.h" +#include "inputeventcommand.h" +#include "view3dactioncommand.h" #include "dummycontextobject.h" #include "../editor3d/generalhelper.h" @@ -73,6 +74,7 @@ #include "../editor3d/linegeometry.h" #include +#include #include #include @@ -80,6 +82,8 @@ #include #include #include +#include +#include #ifdef QUICK3D_MODULE #include @@ -165,53 +169,72 @@ bool Qt5InformationNodeInstanceServer::dropAcceptable(QDragMoveEvent *event) con return canBeDropped == "true" || canBeDropped == "True"; } -QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) +void Qt5InformationNodeInstanceServer::createEditView3D() { #ifdef QUICK3D_MODULE - auto helper = new QmlDesigner::Internal::GeneralHelper(); - QObject::connect(helper, &QmlDesigner::Internal::GeneralHelper::toolStateChanged, - this, &Qt5InformationNodeInstanceServer::handleToolStateChanged); - engine->rootContext()->setContextProperty("_generalHelper", helper); - m_3dHelper = helper; + static bool showEditView = qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_SHOW_EDIT_WINDOW"); + qmlRegisterType("MouseArea3D", 1, 0, "MouseArea3D"); qmlRegisterType("CameraGeometry", 1, 0, "CameraGeometry"); qmlRegisterType("GridGeometry", 1, 0, "GridGeometry"); qmlRegisterType("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry"); qmlRegisterType("LineGeometry", 1, 0, "LineGeometry"); -#endif - QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); + auto helper = new QmlDesigner::Internal::GeneralHelper(); + QObject::connect(helper, &QmlDesigner::Internal::GeneralHelper::toolStateChanged, + this, &Qt5InformationNodeInstanceServer::handleToolStateChanged); + engine()->rootContext()->setContextProperty("_generalHelper", helper); + m_3dHelper = helper; - QWindow *window = qobject_cast(component.create()); + QQmlComponent component(engine()); + if (showEditView) { + component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/EditWindow3D.qml")); + m_editWindow3D = qobject_cast(component.create()); + m_editView3DRootItem = QQmlProperty::read(m_editWindow3D, "editViewRoot").value(); - if (!window) { - qWarning() << "Could not create edit view 3D: " << component.errors(); - return nullptr; + //For macOS we have to use the 4.1 core profile + QSurfaceFormat surfaceFormat = m_editWindow3D->requestedFormat(); + surfaceFormat.setVersion(4, 1); + surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); + m_editWindow3D->setFormat(surfaceFormat); + } else { + m_editView3D = new QQuickView(quickView()->engine(), quickView()); + m_editView3D->setFormat(quickView()->format()); + DesignerSupport::createOpenGLContext(m_editView3D.data()); + component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); + m_editView3DRootItem = qobject_cast(component.create()); } - window->installEventFilter(this); - QObject::connect(window, SIGNAL(selectionChanged(QVariant)), + if (!m_editView3DRootItem) { + qWarning() << "Could not create edit view 3D: " << component.errors(); + return; + } + + if (!showEditView) { + DesignerSupport::setRootItem(m_editView3D, m_editView3DRootItem); + } else { + m_editView3DRootItem->installEventFilter(this); + QQmlProperty showButtonsProperty(m_editView3DRootItem, "showButtons", context()); + showButtonsProperty.write(QVariant(true)); + } + + QObject::connect(m_editView3DRootItem, SIGNAL(selectionChanged(QVariant)), this, SLOT(handleSelectionChanged(QVariant))); - QObject::connect(window, SIGNAL(commitObjectProperty(QVariant, QVariant)), + QObject::connect(m_editView3DRootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)), this, SLOT(handleObjectPropertyCommit(QVariant, QVariant))); - QObject::connect(window, SIGNAL(changeObjectProperty(QVariant, QVariant)), + QObject::connect(m_editView3DRootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)), this, SLOT(handleObjectPropertyChange(QVariant, QVariant))); QObject::connect(&m_propertyChangeTimer, &QTimer::timeout, this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout); QObject::connect(&m_selectionChangeTimer, &QTimer::timeout, this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout); + QObject::connect(&m_renderTimer, &QTimer::timeout, + this, &Qt5InformationNodeInstanceServer::doRender3DEditView); - //For macOS we have to use the 4.1 core profile - QSurfaceFormat surfaceFormat = window->requestedFormat(); - surfaceFormat.setVersion(4, 1); - surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); - window->setFormat(surfaceFormat); - -#ifdef QUICK3D_MODULE - helper->setParent(window); + helper->setParent(m_editView3DRootItem); + if (showEditView) + helper->setEdit3DWindow(m_editWindow3D); #endif - - return window; } // The selection has changed in the edit view 3D. Empty list indicates selection is cleared. @@ -357,10 +380,10 @@ void Qt5InformationNodeInstanceServer::handleNode3DDestroyed(QObject *obj) { #ifdef QUICK3D_MODULE if (qobject_cast(obj)) { - QMetaObject::invokeMethod(m_editView3D, "releaseCameraGizmo", + QMetaObject::invokeMethod(m_editView3DRootItem, "releaseCameraGizmo", Q_ARG(QVariant, objectToVariant(obj))); } else if (qobject_cast(obj)) { - QMetaObject::invokeMethod(m_editView3D, "releaseLightGizmo", + QMetaObject::invokeMethod(m_editView3DRootItem, "releaseLightGizmo", Q_ARG(QVariant, objectToVariant(obj))); } removeNode3D(obj); @@ -376,29 +399,41 @@ void Qt5InformationNodeInstanceServer::updateView3DRect(QObject *view3D) viewPortrect = QRectF(0., 0., view3D->property("width").toDouble(), view3D->property("height").toDouble()); } - QQmlProperty viewPortProperty(m_editView3D, "viewPortRect", context()); + QQmlProperty viewPortProperty(m_editView3DRootItem, "viewPortRect", context()); viewPortProperty.write(viewPortrect); } void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D() { +#ifdef QUICK3D_MODULE // Active scene change handling on qml side is async, so a deleted importScene would crash // editView when it updates next. Disable/enable edit view update synchronously to avoid this. QVariant activeSceneVar = objectToVariant(m_active3DScene); - QMetaObject::invokeMethod(m_editView3D, "enableEditViewUpdate", + QMetaObject::invokeMethod(m_editView3DRootItem, "enableEditViewUpdate", Q_ARG(QVariant, activeSceneVar)); ServerNodeInstance sceneInstance = active3DSceneInstance(); - QVariant sceneInstanceVar; - QQmlProperty sceneIdProperty(m_editView3D, "sceneId", context()); + QVariant sceneIdVar; + QQmlProperty sceneIdProperty(m_editView3DRootItem, "sceneId", context()); + const QString sceneId = sceneInstance.id(); if (sceneInstance.isValid()) - sceneInstanceVar = QVariant::fromValue(sceneInstance.id()); - sceneIdProperty.write(sceneInstanceVar); + sceneIdVar = QVariant::fromValue(sceneId); + sceneIdProperty.write(sceneIdVar); - QQmlProperty sceneProperty(m_editView3D, "activeScene", context()); + QQmlProperty sceneProperty(m_editView3DRootItem, "activeScene", context()); sceneProperty.write(activeSceneVar); + auto helper = qobject_cast(m_3dHelper); + QVariantMap toolStates; + if (helper) + toolStates = helper->getToolStates(sceneId); + toolStates.insert("sceneInstanceId", QVariant::fromValue(sceneInstance.instanceId())); + + nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ActiveSceneChanged, + toolStates}); + updateView3DRect(m_active3DView); +#endif } void Qt5InformationNodeInstanceServer::removeNode3D(QObject *node) @@ -439,11 +474,11 @@ void Qt5InformationNodeInstanceServer::resolveSceneRoots() if (newRoot != oldRoot) { if (qobject_cast(node)) { - QMetaObject::invokeMethod(m_editView3D, "updateCameraGizmoScene", + QMetaObject::invokeMethod(m_editView3DRootItem, "updateCameraGizmoScene", Q_ARG(QVariant, objectToVariant(newRoot)), Q_ARG(QVariant, objectToVariant(node))); } else if (qobject_cast(node)) { - QMetaObject::invokeMethod(m_editView3D, "updateLightGizmoScene", + QMetaObject::invokeMethod(m_editView3DRootItem, "updateLightGizmoScene", Q_ARG(QVariant, objectToVariant(newRoot)), Q_ARG(QVariant, objectToVariant(node))); } @@ -467,11 +502,65 @@ ServerNodeInstance Qt5InformationNodeInstanceServer::active3DSceneInstance() con return sceneInstance; } +void Qt5InformationNodeInstanceServer::render3DEditView() +{ + m_needRender = true; + if (!m_renderTimer.isActive()) + m_renderTimer.start(0); +} + +// render the 3D edit view and send the result to creator process +void Qt5InformationNodeInstanceServer::doRender3DEditView() +{ + static bool showEditView = qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_SHOW_EDIT_WINDOW"); + if (m_editView3DRootItem && !showEditView) { + auto t = std::chrono::steady_clock::now(); + if (!m_editView3DContentItem) { + m_editView3DContentItem = QQmlProperty::read(m_editView3DRootItem, "contentItem").value(); + if (m_editView3DContentItem) { + designerSupport()->refFromEffectItem(m_editView3DContentItem, false); + QmlDesigner::Internal::QmlPrivateGate::disableNativeTextRendering(m_editView3DContentItem); + } + } + + std::function updateNodesRecursive; + updateNodesRecursive = [&updateNodesRecursive](QQuickItem *item) { + for (QQuickItem *childItem : item->childItems()) + updateNodesRecursive(childItem); + DesignerSupport::updateDirtyNode(item); + }; + updateNodesRecursive(m_editView3DContentItem); + + QSizeF size = qobject_cast(m_editView3DContentItem)->size(); + QRectF renderRect(QPointF(0., 0.), size); + QImage renderImage = designerSupport()->renderImageForItem(m_editView3DContentItem, + renderRect, size.toSize()); + + // There's no instance related to image, so instance id is -1. + // Key number is selected so that it is unlikely to conflict other ImageContainer use. + const qint32 edit3DKey = 2100000000; + auto imgContainer = ImageContainer(-1, renderImage, edit3DKey); + + // send the rendered image to creator process + nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::Render3DView, + QVariant::fromValue(imgContainer)}); + qDebug() << "\x1b[42m \x1b[1m" << __FUNCTION__ + << ", t=" << std::chrono::duration_cast(std::chrono::steady_clock::now()-t).count() + << "\x1b[m"; + + if (m_needRender) { + m_renderTimer.start(0); + m_needRender = false; + } + } +} + Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : Qt5NodeInstanceServer(nodeInstanceClient) { m_propertyChangeTimer.setInterval(100); m_selectionChangeTimer.setSingleShot(true); + m_renderTimer.setSingleShot(true); } void Qt5InformationNodeInstanceServer::sendTokenBack() @@ -523,7 +612,6 @@ bool Qt5InformationNodeInstanceServer::isDirtyRecursiveForParentInstances(QQuick return false; return isDirtyRecursiveForParentInstances(parentItem); - } return false; @@ -549,12 +637,14 @@ QList Qt5InformationNodeInstanceServer::createInstances( { const auto createdInstances = NodeInstanceServer::createInstances(container); - if (m_editView3D) { + if (m_editView3DRootItem) { add3DViewPorts(createdInstances); add3DScenes(createdInstances); createCameraAndLightGizmos(createdInstances); } + render3DEditView(); + return createdInstances; } @@ -586,7 +676,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos( while (cameraIt != cameras.constEnd()) { const auto cameraObjs = cameraIt.value(); for (auto &obj : cameraObjs) { - QMetaObject::invokeMethod(m_editView3D, "addCameraGizmo", + QMetaObject::invokeMethod(m_editView3DRootItem, "addCameraGizmo", Q_ARG(QVariant, objectToVariant(cameraIt.key())), Q_ARG(QVariant, objectToVariant(obj))); } @@ -596,7 +686,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos( while (lightIt != lights.constEnd()) { const auto lightObjs = lightIt.value(); for (auto &obj : lightObjs) { - QMetaObject::invokeMethod(m_editView3D, "addLightGizmo", + QMetaObject::invokeMethod(m_editView3DRootItem, "addLightGizmo", Q_ARG(QVariant, objectToVariant(lightIt.key())), Q_ARG(QVariant, objectToVariant(obj))); } @@ -791,8 +881,8 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QListinitToolStates(it.key(), it.value()); ++it; } - helper->restoreWindowState(qobject_cast(m_editView3D)); + helper->restoreWindowState(); + if (toolStates.contains(helper->globalStateId()) + && toolStates[helper->globalStateId()].contains("rootSize")) { + m_editView3DRootItem->setSize(toolStates[helper->globalStateId()]["rootSize"].value()); + } } updateActiveSceneToEditView3D(); @@ -900,7 +994,7 @@ void Qt5InformationNodeInstanceServer::reparentInstances(const ReparentInstances Qt5NodeInstanceServer::reparentInstances(command); - if (m_editView3D) + if (m_editView3DRootItem) resolveSceneRoots(); } @@ -991,7 +1085,7 @@ void QmlDesigner::Qt5InformationNodeInstanceServer::removeSharedMemory(const Qml void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionCommand &command) { - if (!m_editView3D) + if (!m_editView3DRootItem) return; if (m_selectionChangeTimer.isActive()) { @@ -1033,16 +1127,18 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm // Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the // case when the first selection processed is a multiselection, we wait a bit as // using the new boxes immediately leads to visual glitches. - int boxCount = m_editView3D->property("selectionBoxes").value().size(); + int boxCount = m_editView3DRootItem->property("selectionBoxes").value().size(); if (boxCount < selectedObjs.size()) { - QMetaObject::invokeMethod(m_editView3D, "ensureSelectionBoxes", + QMetaObject::invokeMethod(m_editView3DRootItem, "ensureSelectionBoxes", Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size()))); m_pendingSelectionChangeCommand = command; m_selectionChangeTimer.start(100); } else { - QMetaObject::invokeMethod(m_editView3D, "selectObjects", + QMetaObject::invokeMethod(m_editView3DRootItem, "selectObjects", Q_ARG(QVariant, QVariant::fromValue(selectedObjs))); } + + render3DEditView(); } void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command) @@ -1060,6 +1156,8 @@ void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCo refreshBindings(); startRenderTimer(); + + render3DEditView(); } void Qt5InformationNodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) @@ -1074,45 +1172,110 @@ void Qt5InformationNodeInstanceServer::removeInstances(const RemoveInstancesComm resolveSceneRoots(); } - if (m_editView3D && (!m_active3DScene || !m_active3DView)) { + if (m_editView3DRootItem && (!m_active3DScene || !m_active3DView)) { if (!m_active3DScene && !m_3DSceneMap.isEmpty()) m_active3DScene = m_3DSceneMap.begin().key(); m_active3DView = findView3DForSceneRoot(m_active3DScene); updateActiveSceneToEditView3D(); } + render3DEditView(); +} + +void Qt5InformationNodeInstanceServer::inputEvent(const InputEventCommand &command) +{ + if (m_editView3D) { + if (command.type() == QEvent::Wheel) { + auto we = new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()}, + command.buttons(), command.modifiers(), Qt::NoScrollPhase, + false); + QGuiApplication::postEvent(m_editView3D, we); + } else { + auto me = new QMouseEvent(command.type(), command.pos(), command.button(), + command.buttons(), command.modifiers()); + QGuiApplication::postEvent(m_editView3D, me); + } + + render3DEditView(); + } +} + +void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &command) +{ + QVariantMap updatedState; + + switch (command.type()) { + case View3DActionCommand::MoveTool: + updatedState.insert("groupTransform", 0); + break; + case View3DActionCommand::RotateTool: + updatedState.insert("groupTransform", 1); + break; + case View3DActionCommand::ScaleTool: + updatedState.insert("groupTransform", 2); + break; + case View3DActionCommand::FitToView: + QMetaObject::invokeMethod(m_editView3DRootItem, "fitToView"); + break; + case View3DActionCommand::SelectionModeToggle: + updatedState.insert("groupSelect", command.isEnabled() ? 0 : 1); + break; + case View3DActionCommand::CameraToggle: + updatedState.insert("usePerspective", command.isEnabled()); + break; + case View3DActionCommand::OrientationToggle: + updatedState.insert("globalOrientation", command.isEnabled()); + break; + case View3DActionCommand::EditLightToggle: + updatedState.insert("showEditLight", command.isEnabled()); + break; + default: + break; + } + + if (!updatedState.isEmpty()) { + QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates", + Q_ARG(QVariant, updatedState), + Q_ARG(QVariant, QVariant::fromValue(false))); + } + + render3DEditView(); +} + +void Qt5InformationNodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &command) +{ + Qt5NodeInstanceServer::changeAuxiliaryValues(command); + render3DEditView(); } // update 3D view window state when the main app window state change void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewStateCommand &command) { - auto window = qobject_cast(m_editView3D); - if (window) { +#ifdef QUICK3D_MODULE + if (command.type() == Update3dViewStateCommand::SizeChange) { + if (m_editView3DRootItem) { + m_editView3DRootItem->setSize(command.size()); + auto helper = qobject_cast(m_3dHelper); + if (helper) + helper->storeToolState(helper->globalStateId(), "rootSize", QVariant(command.size()), 0); + render3DEditView(); + } + } else if (m_editWindow3D) { if (command.type() == Update3dViewStateCommand::StateChange) { if (command.previousStates() & Qt::WindowMinimized) // main window expanded from minimize state - window->show(); + m_editWindow3D->show(); else if (command.currentStates() & Qt::WindowMinimized) // main window minimized - window->hide(); + m_editWindow3D->hide(); } else if (command.type() == Update3dViewStateCommand::ActiveChange) { - window->setFlag(Qt::WindowStaysOnTopHint, command.isActive()); + m_editWindow3D->setFlag(Qt::WindowStaysOnTopHint, command.isActive()); // main window has a popup open, lower the edit view 3D so that the pop up is visible if (command.hasPopup()) - window->lower(); + m_editWindow3D->lower(); } } -} - -void Qt5InformationNodeInstanceServer::enable3DView(const Enable3DViewCommand &command) -{ - // TODO: this method is not currently in use as the 3D view is currently enabled by resetting the puppet. - // It should however be implemented here. - - auto window = qobject_cast(m_editView3D); - if (window && !command.isEnable()) { - // TODO: remove the 3D view - } else if (!window && command.isEnable()) { - // TODO: create the 3D view - } +#else + Q_UNUSED(command) +#endif } } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 12b2f12821a..1e4d70577b0 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -32,6 +32,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QDragMoveEvent; @@ -49,7 +50,6 @@ public: void reparentInstances(const ReparentInstancesCommand &command) override; void clearScene(const ClearSceneCommand &command) override; void update3DViewState(const Update3dViewStateCommand &command) override; - void enable3DView(const Enable3DViewCommand &command) override; void createScene(const CreateSceneCommand &command) override; void completeComponent(const CompleteComponentCommand &command) override; void token(const TokenCommand &command) override; @@ -57,6 +57,9 @@ public: void changeSelection(const ChangeSelectionCommand &command) override; void changePropertyValues(const ChangeValuesCommand &command) override; void removeInstances(const RemoveInstancesCommand &command) override; + void inputEvent(const InputEventCommand &command) override; + void view3DAction(const View3DActionCommand &command) override; + void changeAuxiliaryValues(const ChangeAuxiliaryCommand &command) override; private slots: void handleSelectionChanged(const QVariant &objs); @@ -82,7 +85,7 @@ protected: private: void handleObjectPropertyChangeTimeout(); void handleSelectionChangeTimeout(); - QObject *createEditView3D(QQmlEngine *engine); + void createEditView3D(); void setup3DEditView(const QList &instanceList, const QHash &toolStates); void createCameraAndLightGizmos(const QList &instanceList) const; @@ -104,8 +107,13 @@ private: void removeNode3D(QObject *node); void resolveSceneRoots(); ServerNodeInstance active3DSceneInstance() const; + void render3DEditView(); + void doRender3DEditView(); - QObject *m_editView3D = nullptr; + QPointer m_editView3D; + QPointer m_editWindow3D; + QQuickItem *m_editView3DRootItem = nullptr; + QQuickItem *m_editView3DContentItem = nullptr; QSet m_view3Ds; QMultiHash m_3DSceneMap; // key: scene root, value: node QObject *m_active3DView; @@ -115,10 +123,12 @@ private: QList m_tokenList; QTimer m_propertyChangeTimer; QTimer m_selectionChangeTimer; + QTimer m_renderTimer; QVariant m_changedNode; PropertyName m_changedProperty; ChangeSelectionCommand m_pendingSelectionChangeCommand; QObject *m_3dHelper = nullptr; + bool m_needRender = false; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp index dbee5969be4..be54efd2c54 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp @@ -70,8 +70,10 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) : * 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. */ - if (!qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE")) + if (!qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE") + || !qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_SHOW_EDIT_WINDOW")) { DesignerSupport::activateDesignerWindowManager(); + } setNodeInstanceServer(new Qt5InformationNodeInstanceServer(this)); initializeSocket(); } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 39653af4129..b503afb655c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -72,6 +72,7 @@ void Qt5NodeInstanceServer::initializeView() DesignerSupport::createOpenGLContext(m_quickView.data()); if (qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE") + && qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_SHOW_EDIT_WINDOW") && QCoreApplication::arguments().at(2) == "editormode") { /* In '3d editormode' we do not use the DesignerWindowManager * and since we do not show the QQuickView we have to manually create the OpenGL context */ diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index b128161aeee..395b56e2416 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -627,16 +627,18 @@ QList ServerNodeInstance::allItemsRecursive() const QString ServerNodeInstance::id() const { - return m_nodeInstance->id(); + if (isValid()) + return m_nodeInstance->id(); + + return {}; } qint32 ServerNodeInstance::instanceId() const { - if (isValid()) { + if (isValid()) return m_nodeInstance->instanceId(); - } else { - return -1; - } + + return -1; } QList ServerNodeInstance::stateInstances() const diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index 79ffb4934f2..749517125f5 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -8,6 +8,7 @@ mockfiles/GenericBackend.qml mockfiles/Dialog.qml mockfiles/EditView3D.qml + mockfiles/EditWindow3D.qml mockfiles/EditCameraController.qml mockfiles/Arrow.qml mockfiles/AutoScaleHelper.qml diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 7689c8e83e8..82c26c43adc 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -141,9 +141,10 @@ extend_qtc_plugin(QmlDesigner changeselectioncommand.cpp changeselectioncommand.h drop3dlibraryitemcommand.cpp drop3dlibraryitemcommand.h update3dviewstatecommand.cpp update3dviewstatecommand.h - enable3dviewcommand.cpp enable3dviewcommand.h view3dclosedcommand.cpp view3dclosedcommand.h puppettocreatorcommand.cpp puppettocreatorcommand.h + inputeventcommand.cpp inputeventcommand.h + view3dactioncommand.cpp view3dactioncommand.h ) extend_qtc_plugin(QmlDesigner @@ -194,6 +195,16 @@ extend_qtc_plugin(QmlDesigner debugviewwidget.cpp debugviewwidget.h debugviewwidget.ui ) +extend_qtc_plugin(QmlDesigner + SOURCES_PREFIX components/edit3d + SOURCES + edit3dview.cpp edit3dview.h + edit3dwidget.cpp edit3dwidget.h + edit3dcanvas.cpp edit3dcanvas.h + edit3dactions.cpp edit3dactions.h + edit3d.qrc +) + extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/formeditor SOURCES diff --git a/src/plugins/qmldesigner/components/componentcore/actioninterface.h b/src/plugins/qmldesigner/components/componentcore/actioninterface.h index ee120131f79..026bb707a9d 100644 --- a/src/plugins/qmldesigner/components/componentcore/actioninterface.h +++ b/src/plugins/qmldesigner/components/componentcore/actioninterface.h @@ -42,7 +42,8 @@ public: ContextMenuAction, ToolBarAction, Action, - FormEditorAction + FormEditorAction, + Edit3DAction }; enum Priorities { diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.pri b/src/plugins/qmldesigner/components/edit3d/edit3d.pri new file mode 100644 index 00000000000..fbef3175286 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.pri @@ -0,0 +1,12 @@ +VPATH += $$PWD +SOURCES += edit3dwidget.cpp \ + edit3dview.cpp \ + edit3dcanvas.cpp \ + edit3dactions.cpp + +HEADERS += edit3dwidget.h \ + edit3dview.h \ + edit3dcanvas.h \ + edit3dactions.h + +RESOURCES += edit3d.qrc diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc new file mode 100644 index 00000000000..1719b8ed63a --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc @@ -0,0 +1,34 @@ + + + images/edit_light_off.png + images/edit_light_off@2x.png + images/edit_light_on.png + images/edit_light_on@2x.png + images/fit_active.png + images/fit_active@2x.png + images/global.png + images/global@2x.png + images/group_selection_selected.png + images/group_selection_selected@2x.png + images/item_selection_selected.png + images/item_selection_selected@2x.png + images/local.png + images/local@2x.png + images/move_active.png + images/move_active@2x.png + images/move_selected.png + images/move_selected@2x.png + images/ortho.png + images/ortho@2x.png + images/persp.png + images/persp@2x.png + images/rotate_active.png + images/rotate_active@2x.png + images/rotate_selected.png + images/rotate_selected@2x.png + images/scale_active.png + images/scale_active@2x.png + images/scale_selected.png + images/scale_selected@2x.png + + diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp new file mode 100644 index 00000000000..a249f78a126 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "edit3dactions.h" +#include "edit3dview.h" +#include "edit3dwidget.h" + +#include +#include +#include + +#include + +namespace QmlDesigner { + +Edit3DActionTemplate::Edit3DActionTemplate(const QString &description, + SelectionContextOperation action, + View3DActionCommand::Type type) + : DefaultAction(description), + m_action(action), + m_type(type) +{ } + +void Edit3DActionTemplate::actionTriggered(bool b) +{ + if (m_type != View3DActionCommand::Empty) { + QmlDesignerPlugin::instance()->viewManager().nodeInstanceView() + ->view3DAction(View3DActionCommand(m_type, b)); + } + + if (m_action) + m_action(m_selectionContext); +} + +Edit3DAction::Edit3DAction(const QByteArray &menuId, View3DActionCommand::Type type, + const QString &description, const QKeySequence &key, bool checkable, + bool checked, const QIcon &iconOff, const QIcon &iconOn, + SelectionContextOperation selectionAction) + : AbstractAction(new Edit3DActionTemplate(description, selectionAction, type)) + , m_menuId(menuId) +{ + action()->setShortcut(key); + action()->setShortcutContext(Qt::WidgetWithChildrenShortcut); + action()->setCheckable(checkable); + action()->setChecked(checked); + if (checkable) { + QIcon onOffIcon; + const auto onAvail = iconOn.availableSizes(); // Assume both icons have same sizes available + for (const auto &size : onAvail) { + onOffIcon.addPixmap(iconOn.pixmap(size), QIcon::Normal, QIcon::On); + onOffIcon.addPixmap(iconOff.pixmap(size), QIcon::Normal, QIcon::Off); + } + action()->setIcon(onOffIcon); + } else { + action()->setIcon(iconOff); + } +} + +QByteArray Edit3DAction::category() const +{ + return QByteArray(); +} + +bool Edit3DAction::isVisible(const SelectionContext &selectionContext) const +{ + return true; +} + +bool Edit3DAction::isEnabled(const SelectionContext &selectionContext) const +{ + return isVisible(selectionContext); +} + +} + diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h new file mode 100644 index 00000000000..1973e22491d --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "view3dactioncommand.h" + +#include + +#include +#include + +namespace QmlDesigner { + +using SelectionContextOperation = std::function; + +class Edit3DActionTemplate : public DefaultAction +{ + +public: + Edit3DActionTemplate(const QString &description, SelectionContextOperation action, + View3DActionCommand::Type type); + + void actionTriggered(bool b) override; + + SelectionContextOperation m_action; + View3DActionCommand::Type m_type; +}; + +class Edit3DAction : public AbstractAction +{ +public: + Edit3DAction(const QByteArray &menuId, View3DActionCommand::Type type, + const QString &description, const QKeySequence &key, bool checkable, bool checked, + const QIcon &iconOff, const QIcon &iconOn, + SelectionContextOperation selectionAction = nullptr); + + QByteArray category() const override; + + int priority() const override + { + return CustomActionsPriority; + } + + Type type() const override + { + return ActionInterface::Edit3DAction; + } + + QByteArray menuId() const override + { + return m_menuId; + } + +protected: + bool isVisible(const SelectionContext &selectionContext) const override; + bool isEnabled(const SelectionContext &selectionContext) const override; + +private: + QByteArray m_menuId; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp new file mode 100644 index 00000000000..8a1c049907b --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "edit3dcanvas.h" +#include "edit3dview.h" +#include "edit3dwidget.h" + +#include "nodehints.h" +#include "qmlvisualnode.h" + +#include +#include + +namespace QmlDesigner { + +Edit3DCanvas::Edit3DCanvas(Edit3DWidget *parent) + : QWidget(parent), + m_parent(parent) +{ + setMouseTracking(true); + setAcceptDrops(true); +} + +void Edit3DCanvas::updateRenderImage(const QImage &img) +{ + m_image = img; + update(); +} + +void Edit3DCanvas::updateActiveScene(qint32 activeScene) +{ + m_activeScene = activeScene; +} + +void Edit3DCanvas::mousePressEvent(QMouseEvent *e) +{ + m_parent->view()->sendInputEvent(e); + QWidget::mousePressEvent(e); +} + +void Edit3DCanvas::mouseReleaseEvent(QMouseEvent *e) +{ + m_parent->view()->sendInputEvent(e); + QWidget::mouseReleaseEvent(e); +} + +void Edit3DCanvas::mouseDoubleClickEvent(QMouseEvent *e) +{ + m_parent->view()->sendInputEvent(e); + QWidget::mouseDoubleClickEvent(e); +} + +void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e) +{ + m_parent->view()->sendInputEvent(e); + QWidget::mouseMoveEvent(e); +} + +void Edit3DCanvas::wheelEvent(QWheelEvent *e) +{ + m_parent->view()->sendInputEvent(e); + QWidget::wheelEvent(e); +} + +void Edit3DCanvas::paintEvent(QPaintEvent *e) +{ + Q_UNUSED(e) + + QWidget::paintEvent(e); + + QPainter painter(this); + + painter.drawImage(rect(), m_image, rect()); +} + +void Edit3DCanvas::resizeEvent(QResizeEvent *e) +{ + m_parent->view()->edit3DViewResized(e->size()); +} + +void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e) +{ + QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); + if (!data.isEmpty()) { + QDataStream stream(data); + stream >> m_itemLibraryEntry; + bool canDrop = NodeHints::fromItemLibraryEntry(m_itemLibraryEntry).canBeDroppedInView3D(); + + if (canDrop) + e->accept(); + } +} + +void Edit3DCanvas::dropEvent(QDropEvent *e) +{ + Q_UNUSED(e) + + QmlVisualNode::createQmlVisualNode(m_parent->view(), m_itemLibraryEntry, m_activeScene, {}); +} + +} + + diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h new file mode 100644 index 00000000000..48b05789476 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "itemlibraryinfo.h" + +#include +#include +#include +#include + +namespace QmlDesigner { + +class Edit3DWidget; + +class Edit3DCanvas : public QWidget +{ + Q_OBJECT + +public: + Edit3DCanvas(Edit3DWidget *parent); + + void updateRenderImage(const QImage &img); + void updateActiveScene(qint32 activeScene); + +protected: + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void mouseDoubleClickEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void wheelEvent(QWheelEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void dragEnterEvent(QDragEnterEvent *e) override; + void dropEvent(QDropEvent *e) override; + +private: + QPointer m_parent; + QImage m_image; + qint32 m_activeScene; + ItemLibraryEntry m_itemLibraryEntry; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp new file mode 100644 index 00000000000..8aefce79403 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "edit3dview.h" +#include "edit3dwidget.h" +#include "edit3dcanvas.h" +#include "edit3dactions.h" +#include "designmodewidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace QmlDesigner { + +Edit3DView::Edit3DView(QObject *parent) + : AbstractView(parent) +{ +} + +Edit3DView::~Edit3DView() +{ +} + +void Edit3DView::createEdit3DWidget() +{ + createEdit3DActions(); + m_edit3DWidget = new Edit3DWidget(this); +} + +WidgetInfo Edit3DView::widgetInfo() +{ + if (!m_edit3DWidget) + createEdit3DWidget(); + + return createWidgetInfo(m_edit3DWidget.data(), nullptr, "Editor3D", WidgetInfo::CentralPane, 0, tr("3D Editor"), DesignerWidgetFlags::IgnoreErrors); +} + +Edit3DWidget *Edit3DView::edit3DWidget() const +{ + return m_edit3DWidget.data(); +} + +void Edit3DView::renderImage3DChanged(const QImage &img) +{ + edit3DWidget()->canvas()->updateRenderImage(img); +} + +void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) +{ + const QString sceneKey = QStringLiteral("sceneInstanceId"); + const QString selectKey = QStringLiteral("groupSelect"); + const QString transformKey = QStringLiteral("groupTransform"); + const QString perspectiveKey = QStringLiteral("usePerspective"); + const QString orientationKey = QStringLiteral("globalOrientation"); + const QString editLightKey = QStringLiteral("showEditLight"); + + if (sceneState.contains(sceneKey)) + edit3DWidget()->canvas()->updateActiveScene(sceneState[sceneKey].value()); + + if (sceneState.contains(selectKey)) + m_selectionModeAction->action()->setChecked(sceneState[selectKey].toInt() == 0); + else + m_selectionModeAction->action()->setChecked(false); + + if (sceneState.contains(transformKey)) { + const int tool = sceneState[transformKey].toInt(); + if (tool == 0) + m_moveToolAction->action()->setChecked(true); + else if (tool == 1) + m_rotateToolAction->action()->setChecked(true); + else + m_scaleToolAction->action()->setChecked(true); + } else { + m_moveToolAction->action()->setChecked(true); + } + + if (sceneState.contains(perspectiveKey)) + m_cameraModeAction->action()->setChecked(sceneState[perspectiveKey].toBool()); + else + m_cameraModeAction->action()->setChecked(false); + if (sceneState.contains(orientationKey)) + m_orientationModeAction->action()->setChecked(sceneState[orientationKey].toBool()); + else + m_orientationModeAction->action()->setChecked(false); + if (sceneState.contains(editLightKey)) + m_editLightAction->action()->setChecked(sceneState[editLightKey].toBool()); + else + m_editLightAction->action()->setChecked(false); +} + +void Edit3DView::sendInputEvent(QInputEvent *e) const +{ + nodeInstanceView()->sendInputEvent(e); +} + +void Edit3DView::edit3DViewResized(const QSize &size) const +{ + nodeInstanceView()->edit3DViewResized(size); +} + +QSize Edit3DView::canvasSize() const +{ + if (!m_edit3DWidget.isNull() && m_edit3DWidget->canvas()) + return m_edit3DWidget->canvas()->size(); + + return {}; +} + +void Edit3DView::createEdit3DActions() +{ + m_selectionModeAction + = new Edit3DAction( + "Edit3DSelectionModeToggle", View3DActionCommand::SelectionModeToggle, + QCoreApplication::translate("SelectionModeToggleAction", "Toggle Group / Single Selection Mode"), + QKeySequence(Qt::Key_Q), true, false, Icons::EDIT3D_SELECTION_MODE_OFF.icon(), + Icons::EDIT3D_SELECTION_MODE_ON.icon()); + + m_moveToolAction + = new Edit3DAction( + "Edit3DMoveTool", View3DActionCommand::MoveTool, + QCoreApplication::translate("MoveToolAction", "Activate Move Tool"), + QKeySequence(Qt::Key_W), true, true, Icons::EDIT3D_MOVE_TOOL_OFF.icon(), + Icons::EDIT3D_MOVE_TOOL_ON.icon()); + + m_rotateToolAction + = new Edit3DAction( + "Edit3DRotateTool", View3DActionCommand::RotateTool, + QCoreApplication::translate("RotateToolAction", "Activate Rotate Tool"), + QKeySequence(Qt::Key_E), true, false, Icons::EDIT3D_ROTATE_TOOL_OFF.icon(), + Icons::EDIT3D_ROTATE_TOOL_ON.icon()); + + m_scaleToolAction + = new Edit3DAction( + "Edit3DScaleTool", View3DActionCommand::ScaleTool, + QCoreApplication::translate("ScaleToolAction", "Activate Scale Tool"), + QKeySequence(Qt::Key_R), true, false, Icons::EDIT3D_SCALE_TOOL_OFF.icon(), + Icons::EDIT3D_SCALE_TOOL_ON.icon()); + + m_fitAction = new Edit3DAction( + "Edit3DFitToView", View3DActionCommand::FitToView, + QCoreApplication::translate("FitToViewAction", "Fit Selected Object To View"), + QKeySequence(Qt::Key_F), false, false, Icons::EDIT3D_FIT_SELECTED_OFF.icon(), {}); + + m_cameraModeAction + = new Edit3DAction( + "Edit3DCameraToggle", View3DActionCommand::CameraToggle, + QCoreApplication::translate("CameraToggleAction", "Toggle Perspective / Orthographic Edit Camera"), + QKeySequence(Qt::Key_T), true, false, Icons::EDIT3D_EDIT_CAMERA_OFF.icon(), + Icons::EDIT3D_EDIT_CAMERA_ON.icon()); + + m_orientationModeAction + = new Edit3DAction( + "Edit3DOrientationToggle", View3DActionCommand::OrientationToggle, + QCoreApplication::translate("OrientationToggleAction", "Toggle Global / Local Orientation"), + QKeySequence(Qt::Key_Y), true, false, Icons::EDIT3D_ORIENTATION_OFF.icon(), + Icons::EDIT3D_ORIENTATION_ON.icon()); + + m_editLightAction + = new Edit3DAction( + "Edit3DEditLightToggle", View3DActionCommand::EditLightToggle, + QCoreApplication::translate("EditLightToggleAction", "Toggle Edit Light On / Off"), + QKeySequence(Qt::Key_U), true, false, Icons::EDIT3D_LIGHT_OFF.icon(), + Icons::EDIT3D_LIGHT_ON.icon()); + + SelectionContextOperation resetTrigger = [this](const SelectionContext &) { + setCurrentStateNode(rootModelNode()); + resetPuppet(); + }; + m_resetAction + = new Edit3DAction( + "Edit3DResetView", View3DActionCommand::Empty, + QCoreApplication::translate("ResetView", "Reset View"), + QKeySequence(Qt::Key_P), false, false, Utils::Icons::RESET_TOOLBAR.icon(), {}, + resetTrigger); + + m_leftActions << m_selectionModeAction; + m_leftActions << nullptr; // Null indicates separator + m_leftActions << nullptr; // Second null after separator indicates an exclusive group + m_leftActions << m_moveToolAction; + m_leftActions << m_rotateToolAction; + m_leftActions << m_scaleToolAction; + m_leftActions << nullptr; + m_leftActions << m_fitAction; + m_leftActions << nullptr; + m_leftActions << m_cameraModeAction; + m_leftActions << m_orientationModeAction; + m_leftActions << m_editLightAction; + + m_rightActions << m_resetAction; + + // TODO: Registering actions to action manager causes conflicting shortcuts in form editor. + // Registration commented out until UX defines non-conflicting shortcuts. + // Also, actions creation needs to be somehow triggered before action manager registers + // actions to creator. +// DesignerActionManager &actionManager = QmlDesignerPlugin::instance()->designerActionManager(); +// for (auto action : qAsConst(m_leftActions)) { +// if (action) +// actionManager.addDesignerAction(action); +// } +// for (auto action : qAsConst(m_rightActions)) { +// if (action) +// actionManager.addDesignerAction(action); +// } +} + +QVector Edit3DView::leftActions() const +{ + return m_leftActions; +} + +QVector Edit3DView::rightActions() const +{ + return m_rightActions; +} + +} + diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h new file mode 100644 index 00000000000..64ffedb1540 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "view3dactioncommand.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +QT_END_NAMESPACE + +namespace QmlDesigner { + +class Edit3DWidget; +class Edit3DAction; + +class QMLDESIGNERCORE_EXPORT Edit3DView : public AbstractView +{ + Q_OBJECT + +public: + Edit3DView(QObject *parent = nullptr); + ~Edit3DView() override; + + WidgetInfo widgetInfo() override; + + Edit3DWidget *edit3DWidget() const; + + void renderImage3DChanged(const QImage &img) override; + void updateActiveScene3D(const QVariantMap &sceneState) override; + + void sendInputEvent(QInputEvent *e) const; + void edit3DViewResized(const QSize &size) const; + + QSize canvasSize() const; + + void createEdit3DActions(); + QVector leftActions() const; + QVector rightActions() const; + +protected: + +private: + void createEdit3DWidget(); + + QPointer m_edit3DWidget; + QVector m_leftActions; + QVector m_rightActions; + Edit3DAction *m_selectionModeAction; + Edit3DAction *m_moveToolAction; + Edit3DAction *m_rotateToolAction; + Edit3DAction *m_scaleToolAction; + Edit3DAction *m_fitAction; + Edit3DAction *m_cameraModeAction; + Edit3DAction *m_orientationModeAction; + Edit3DAction *m_editLightAction; + Edit3DAction *m_resetAction; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp new file mode 100644 index 00000000000..b21bb3d46ec --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "edit3dwidget.h" +#include "edit3dview.h" +#include "edit3dcanvas.h" +#include "edit3dactions.h" + +#include "qmldesignerplugin.h" +#include "designersettings.h" +#include "qmldesignerconstants.h" +#include "viewmanager.h" + +#include +#include +#include + +namespace QmlDesigner { + +Edit3DWidget::Edit3DWidget(Edit3DView *view) : + m_view(view) +{ + setMouseTracking(true); + setFocusPolicy(Qt::WheelFocus); + + auto fillLayout = new QVBoxLayout(this); + fillLayout->setContentsMargins(0, 0, 0, 0); + fillLayout->setSpacing(0); + setLayout(fillLayout); + + // Initialize toolbar + m_toolBox = new ToolBox(this); + fillLayout->addWidget(m_toolBox.data()); + + // Iterate through view actions. A null action indicates a separator and a second null action + // after separator indicates an exclusive group. + auto addActionsToToolBox = [this](const QVector &actions, bool left) { + bool previousWasSeparator = true; + QActionGroup *group = nullptr; + for (auto action : actions) { + if (action) { + if (group) + group->addAction(action->action()); + addAction(action->action()); + if (left) + m_toolBox->addLeftSideAction(action->action()); + else + m_toolBox->addRightSideAction(action->action()); + previousWasSeparator = false; + } else { + if (previousWasSeparator) { + group = new QActionGroup(this); + previousWasSeparator = false; + } else { + group = nullptr; + auto separator = new QAction(this); + separator->setSeparator(true); + addAction(separator); + m_toolBox->addLeftSideAction(separator); + previousWasSeparator = true; + } + } + } + + }; + addActionsToToolBox(view->leftActions(), true); + addActionsToToolBox(view->rightActions(), false); + + // Canvas is used to render the actual edit 3d view + m_canvas = new Edit3DCanvas(this); + fillLayout->addWidget(m_canvas.data()); +} + +Edit3DCanvas *Edit3DWidget::canvas() const +{ + return m_canvas.data(); +} + +Edit3DView *Edit3DWidget::view() const +{ + return m_view.data(); +} + +} diff --git a/share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h similarity index 65% rename from share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.h rename to src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index cd9529fbb5a..967713930e4 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -22,33 +22,32 @@ ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ - #pragma once -#include +#include +#include namespace QmlDesigner { -class Enable3DViewCommand +class Edit3DView; +class Edit3DCanvas; +class ToolBox; + +class Edit3DWidget : public QWidget { - friend QDataStream &operator>>(QDataStream &in, Enable3DViewCommand &command); - friend QDebug operator<<(QDebug debug, const Enable3DViewCommand &command); + Q_OBJECT public: - explicit Enable3DViewCommand(bool enable); - Enable3DViewCommand() = default; + Edit3DWidget(Edit3DView *view); - bool isEnable() const; + Edit3DCanvas *canvas() const; + Edit3DView *view() const; private: - bool m_enable = true; + QPointer m_edit3DView; + QPointer m_view; + QPointer m_canvas; + QPointer m_toolBox; }; -QDataStream &operator<<(QDataStream &out, const Enable3DViewCommand &command); -QDataStream &operator>>(QDataStream &in, Enable3DViewCommand &command); - -QDebug operator<<(QDebug debug, const Enable3DViewCommand &command); - } // namespace QmlDesigner - -Q_DECLARE_METATYPE(QmlDesigner::Enable3DViewCommand) diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png new file mode 100644 index 00000000000..73e6e92374b Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png new file mode 100644 index 00000000000..5166264e16d Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png new file mode 100644 index 00000000000..7660c285460 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png new file mode 100644 index 00000000000..836bd2a0d59 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/fit_active.png b/src/plugins/qmldesigner/components/edit3d/images/fit_active.png new file mode 100644 index 00000000000..056e9ec3c8b Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/fit_active.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png new file mode 100644 index 00000000000..4b05f83d460 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/global.png b/src/plugins/qmldesigner/components/edit3d/images/global.png new file mode 100644 index 00000000000..1bd09c680ac Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/global.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/global@2x.png b/src/plugins/qmldesigner/components/edit3d/images/global@2x.png new file mode 100644 index 00000000000..a2a857fb10c Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/global@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png b/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png new file mode 100644 index 00000000000..bfb848aa384 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png new file mode 100644 index 00000000000..f18895dc440 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png b/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png new file mode 100644 index 00000000000..2b685d3d00a Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png new file mode 100644 index 00000000000..eb0051a606e Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/local.png b/src/plugins/qmldesigner/components/edit3d/images/local.png new file mode 100644 index 00000000000..0a608f6816e Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/local.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/local@2x.png b/src/plugins/qmldesigner/components/edit3d/images/local@2x.png new file mode 100644 index 00000000000..a5c931e750f Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/local@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_active.png b/src/plugins/qmldesigner/components/edit3d/images/move_active.png new file mode 100644 index 00000000000..d21d290349c Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/move_active.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png new file mode 100644 index 00000000000..bd0827f918c Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_selected.png b/src/plugins/qmldesigner/components/edit3d/images/move_selected.png new file mode 100644 index 00000000000..5c8ce42a758 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/move_selected.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png new file mode 100644 index 00000000000..fad362a3e6a Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/ortho.png b/src/plugins/qmldesigner/components/edit3d/images/ortho.png new file mode 100644 index 00000000000..35b36203fa2 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/ortho.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png b/src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png new file mode 100644 index 00000000000..443c73e444b Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/persp.png b/src/plugins/qmldesigner/components/edit3d/images/persp.png new file mode 100644 index 00000000000..9a48e763996 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/persp.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/persp@2x.png b/src/plugins/qmldesigner/components/edit3d/images/persp@2x.png new file mode 100644 index 00000000000..88a4eab9c6a Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/persp@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_active.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_active.png new file mode 100644 index 00000000000..bdabaf30285 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/rotate_active.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png new file mode 100644 index 00000000000..8c81f409d32 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png new file mode 100644 index 00000000000..42dc2763ce4 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png new file mode 100644 index 00000000000..b6cc48c0533 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_active.png b/src/plugins/qmldesigner/components/edit3d/images/scale_active.png new file mode 100644 index 00000000000..cd63c1d03bc Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/scale_active.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png new file mode 100644 index 00000000000..0d95e8e8913 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_selected.png b/src/plugins/qmldesigner/components/edit3d/images/scale_selected.png new file mode 100644 index 00000000000..4cca7726170 Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/scale_selected.png differ diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png new file mode 100644 index 00000000000..690cf5f924f Binary files /dev/null and b/src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png differ diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index fee7147648d..37c0efc9d7f 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -676,9 +676,6 @@ void FormEditorView::toggle3DViewEnabled(bool enabled) rootModelNode().removeAuxiliaryData("3d-view"); resetNodeInstanceView(); - - // TODO: the line below is not in use. It should replace the resetNodeInstanceView(); to have a clean API -// nodeInstanceView()->enable3DView(enabled); } QmlItemNode findRecursiveQmlItemNode(const QmlObjectNode &firstQmlObjectNode) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index 5cab6523710..ec7e1d782d8 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -72,7 +72,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : layoutActionGroup->setExclusive(true); m_noSnappingAction = layoutActionGroup->addAction(tr("No snapping (T).")); - m_noSnappingAction->setShortcut(Qt::Key_W); + m_noSnappingAction->setShortcut(Qt::Key_T); m_noSnappingAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_noSnappingAction->setCheckable(true); m_noSnappingAction->setChecked(true); @@ -133,7 +133,6 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : m_toolBox = new ToolBox(this); fillLayout->addWidget(m_toolBox.data()); - m_toolBox->setLeftSideActions(upperActions); m_backgroundAction = new BackgroundAction(m_toolActionGroup.data()); @@ -143,9 +142,11 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : m_toolBox->addRightSideAction(m_backgroundAction.data()); m_option3DAction = new Option3DAction(m_toolActionGroup.data()); - addAction(m_option3DAction.data()); - upperActions.append(m_option3DAction.data()); - m_toolBox->addRightSideAction(m_option3DAction.data()); + if (qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_SHOW_EDIT_WINDOW")) { + addAction(m_option3DAction.data()); + upperActions.append(m_option3DAction.data()); + m_toolBox->addRightSideAction(m_option3DAction.data()); + } m_zoomAction = new ZoomAction(m_toolActionGroup.data()); connect(m_zoomAction.data(), &ZoomAction::zoomLevelChanged, diff --git a/src/plugins/qmldesigner/components/resources/centerwidget.css b/src/plugins/qmldesigner/components/resources/centerwidget.css index 41855e5d770..ba659f61c4d 100644 --- a/src/plugins/qmldesigner/components/resources/centerwidget.css +++ b/src/plugins/qmldesigner/components/resources/centerwidget.css @@ -28,6 +28,10 @@ QTabBar#centralTabBar::tab:selected { color: creatorTheme.QmlDesigner_TabDark; } +QTabBar#centralTabBar::tab:disabled { + color: creatorTheme.QmlDesigner_ScrollBarHandleColor; +} + QToolButton#centralTabBar { background-color: creatorTheme.QmlDesigner_BackgroundColorDarkAlternate; width: 08px; diff --git a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs index 51d8ccbd636..a49c475f800 100644 --- a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs +++ b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs @@ -16,6 +16,7 @@ QtcProduct { "..", "../components/componentcore", "../components/debugview", + "../components/edit3d", "../components/formeditor", "../components/importmanager", "../components/integration", diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 2e549b52b1e..08e5d954749 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE class QStyle; class QToolButton; +class QImage; QT_END_NAMESPACE namespace QmlDesigner { @@ -182,6 +183,8 @@ public: void emitRewriterBeginTransaction(); void emitRewriterEndTransaction(); void emitInstanceToken(const QString &token, int number, const QVector &nodeVector); + void emitRenderImage3DChanged(const QImage &image); + void emitUpdateActiveScene3D(const QVariantMap &sceneState); void sendTokenToInstances(const QString &token, int number, const QVector &nodeVector); @@ -237,6 +240,9 @@ public: virtual void currentTimelineChanged(const ModelNode &node); + virtual void renderImage3DChanged(const QImage &image); + virtual void updateActiveScene3D(const QVariantMap &sceneState); + void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); NodeInstanceView *nodeInstanceView() const; diff --git a/src/plugins/qmldesigner/designercore/include/nodehints.h b/src/plugins/qmldesigner/designercore/include/nodehints.h index 7fed390ee0a..9b9f52721ac 100644 --- a/src/plugins/qmldesigner/designercore/include/nodehints.h +++ b/src/plugins/qmldesigner/designercore/include/nodehints.h @@ -59,6 +59,7 @@ public: bool doesLayoutChildren() const; bool canBeDroppedInFormEditor() const; bool canBeDroppedInNavigator() const; + bool canBeDroppedInView3D() const; bool isMovable() const; bool isResizable() const; bool isStackedContainer() const; diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 33c436aa100..6087997332c 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -39,6 +39,7 @@ #include #include #include +#include namespace ProjectExplorer { class Target; @@ -94,7 +95,6 @@ public: void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; void nodeSourceChanged(const ModelNode &modelNode, const QString &newNodeSource) override; - void currentStateChanged(const ModelNode &node) override; QList instances() const; @@ -136,7 +136,9 @@ public: void mainWindowStateChanged(Qt::WindowStates previousStates, Qt::WindowStates currentStates); void mainWindowActiveChanged(bool active, bool hasPopup); - void enable3DView(bool enable); + void sendInputEvent(QInputEvent *e) const; + void view3DAction(const View3DActionCommand &command); + void edit3DViewResized(const QSize &size) const; void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) override; diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index 8f1ccbfe083..3491a7c33a3 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -42,6 +42,7 @@ class AbstractCustomTool; class DesignerActionManager; class NodeInstanceView; class RewriterView; +class Edit3DView; namespace Internal { class DesignModeWidget; } diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index 706d62b2cfc..480f1e4472a 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,8 @@ #include #include #include +#include +#include #include #include @@ -665,11 +666,6 @@ void NodeInstanceServerProxy::update3DViewState(const Update3dViewStateCommand & writeCommand(QVariant::fromValue(command)); } -void NodeInstanceServerProxy::enable3DView(const Enable3DViewCommand &command) -{ - writeCommand(QVariant::fromValue(command)); -} - void NodeInstanceServerProxy::removeInstances(const RemoveInstancesCommand &command) { writeCommand(QVariant::fromValue(command)); @@ -732,7 +728,7 @@ void NodeInstanceServerProxy::token(const TokenCommand &command) void NodeInstanceServerProxy::removeSharedMemory(const RemoveSharedMemoryCommand &command) { - writeCommand(QVariant::fromValue(command)); + writeCommand(QVariant::fromValue(command)); } void NodeInstanceServerProxy::benchmark(const QString &message) @@ -740,4 +736,14 @@ void NodeInstanceServerProxy::benchmark(const QString &message) qCInfo(instanceViewBenchmark) << message << m_benchmarkTimer.elapsed(); } +void NodeInstanceServerProxy::inputEvent(const InputEventCommand &command) +{ + writeCommand(QVariant::fromValue(command)); +} + +void NodeInstanceServerProxy::view3DAction(const View3DActionCommand &command) +{ + writeCommand(QVariant::fromValue(command)); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h index 5affc3fe448..77a86199a60 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h @@ -68,7 +68,6 @@ public: void changeFileUrl(const ChangeFileUrlCommand &command) override; void createScene(const CreateSceneCommand &command) override; void update3DViewState(const Update3dViewStateCommand &command) override; - void enable3DView(const Enable3DViewCommand &command) override; void clearScene(const ClearSceneCommand &command) override; void removeInstances(const RemoveInstancesCommand &command) override; void changeSelection(const ChangeSelectionCommand &command) override; @@ -84,6 +83,8 @@ public: void token(const TokenCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void benchmark(const QString &message) override; + void inputEvent(const InputEventCommand &command) override; + void view3DAction(const View3DActionCommand &command) override; protected: void writeCommand(const QVariant &command); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index a7cf6a64e14..c3aa57f2d1d 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -48,7 +48,6 @@ #include "changefileurlcommand.h" #include "reparentinstancescommand.h" #include "update3dviewstatecommand.h" -#include "enable3dviewcommand.h" #include "changevaluescommand.h" #include "changeauxiliarycommand.h" #include "changebindingscommand.h" @@ -71,6 +70,9 @@ #include "debugoutputcommand.h" #include "nodeinstanceserverproxy.h" #include "puppettocreatorcommand.h" +#include "inputeventcommand.h" +#include "view3dactioncommand.h" +#include "edit3dview.h" #ifndef QMLDESIGNER_TEST #include @@ -1470,6 +1472,13 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand m_edit3DToolStates[qmlId].insert(data[1].toString(), data[2]); } } + } else if (command.type() == PuppetToCreatorCommand::Render3DView) { + ImageContainer container = qvariant_cast(command.data()); + if (!container.image().isNull()) + emitRenderImage3DChanged(container.image()); + } else if (command.type() == PuppetToCreatorCommand::ActiveSceneChanged) { + const auto sceneState = qvariant_cast(command.data()); + emitUpdateActiveScene3D(sceneState); } } @@ -1526,10 +1535,19 @@ void NodeInstanceView::mainWindowActiveChanged(bool active, bool hasPopup) nodeInstanceServer()->update3DViewState(Update3dViewStateCommand(active, hasPopup)); } -// enable / disable 3D edit View -void NodeInstanceView::enable3DView(bool enable) +void NodeInstanceView::sendInputEvent(QInputEvent *e) const { - nodeInstanceServer()->enable3DView(Enable3DViewCommand(enable)); + nodeInstanceServer()->inputEvent(InputEventCommand(e)); +} + +void NodeInstanceView::view3DAction(const View3DActionCommand &command) +{ + nodeInstanceServer()->view3DAction(command); +} + +void NodeInstanceView::edit3DViewResized(const QSize &size) const +{ + nodeInstanceServer()->update3DViewState(Update3dViewStateCommand(size)); } void NodeInstanceView::timerEvent(QTimerEvent *event) diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp index 4862b59c048..1e34e197bbe 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp @@ -165,6 +165,11 @@ bool NodeHints::canBeDroppedInNavigator() const return evaluateBooleanExpression("canBeDroppedInNavigator", true); } +bool NodeHints::canBeDroppedInView3D() const +{ + return evaluateBooleanExpression("canBeDroppedInView3D", false); +} + bool NodeHints::isMovable() const { if (!isValid()) diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index f5e07d9f834..c7b1203124a 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -42,6 +42,7 @@ #include #include +#include namespace QmlDesigner { @@ -362,7 +363,14 @@ void AbstractView::documentMessagesChanged(const QList &/*error void AbstractView::currentTimelineChanged(const ModelNode & /*node*/) { +} +void AbstractView::renderImage3DChanged(const QImage &image) +{ +} + +void AbstractView::updateActiveScene3D(const QVariantMap &sceneState) +{ } QList AbstractView::toModelNodeList(const QList &nodeList) const @@ -729,6 +737,18 @@ void AbstractView::emitInstanceToken(const QString &token, int number, const QVe model()->d->notifyInstanceToken(token, number, nodeVector); } +void AbstractView::emitRenderImage3DChanged(const QImage &image) +{ + if (model()) + model()->d->notifyRenderImage3DChanged(image); +} + +void AbstractView::emitUpdateActiveScene3D(const QVariantMap &sceneState) +{ + if (model()) + model()->d->notifyUpdateActiveScene3D(sceneState); +} + void AbstractView::emitRewriterEndTransaction() { if (model()) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 45d6f872eda..871c04aeb17 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -668,6 +668,22 @@ void ModelPrivate::notifyCurrentTimelineChanged(const ModelNode &node) resetModelByRewriter(description); } +void ModelPrivate::notifyRenderImage3DChanged(const QImage &image) +{ + for (const QPointer &view : qAsConst(m_viewList)) { + Q_ASSERT(view != nullptr); + view->renderImage3DChanged(image); + } +} + +void ModelPrivate::notifyUpdateActiveScene3D(const QVariantMap &sceneState) +{ + for (const QPointer &view : qAsConst(m_viewList)) { + Q_ASSERT(view != nullptr); + view->updateActiveScene3D(sceneState); + } +} + void ModelPrivate::notifyRewriterBeginTransaction() { bool resetModel = false; diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index dd29d25e510..6990610b374 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -158,6 +158,9 @@ public: void notifyCurrentStateChanged(const ModelNode &node); void notifyCurrentTimelineChanged(const ModelNode &node); + void notifyRenderImage3DChanged(const QImage &image); + void notifyUpdateActiveScene3D(const QVariantMap &sceneState); + void setDocumentMessages(const QList &errors, const QList &warnings); void notifyRewriterBeginTransaction(); diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 65d76164844..b2873816af7 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ public: DesignerActionManagerView designerActionManagerView; NodeInstanceView nodeInstanceView; ComponentView componentView; + Edit3DView edit3DView; FormEditorView formEditorView; TextEditorView textEditorView; ItemLibraryView itemLibraryView; @@ -73,7 +75,6 @@ public: QList > additionalViews; }; - static CrumbleBar *crumbleBar() { return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar(); } @@ -165,6 +166,7 @@ QList > ViewManager::views() const { auto list = d->additionalViews; list.append({ + &d->edit3DView, &d->formEditorView, &d->textEditorView, &d->itemLibraryView, @@ -195,6 +197,7 @@ void ViewManager::detachViewsExceptRewriterAndComponetView() switchStateEditorViewToBaseState(); detachAdditionalViews(); currentModel()->detachView(&d->designerActionManagerView); + currentModel()->detachView(&d->edit3DView); currentModel()->detachView(&d->formEditorView); currentModel()->detachView(&d->textEditorView); currentModel()->detachView(&d->navigatorView); @@ -264,9 +267,15 @@ void ViewManager::attachViewsExceptRewriterAndComponetView() int last = time.elapsed(); qCInfo(viewBenchmark) << "ActionManagerView:" << last << time.elapsed(); - currentModel()->attachView(&d->formEditorView); + currentModel()->attachView(&d->edit3DView); int currentTime = time.elapsed(); + qCInfo(viewBenchmark) << "Edit3DView:" << currentTime - last; + last = currentTime; + + currentModel()->attachView(&d->formEditorView); + + currentTime = time.elapsed(); qCInfo(viewBenchmark) << "FormEditorView:" << currentTime - last; last = currentTime; @@ -337,6 +346,7 @@ QList ViewManager::widgetInfos() const { QList widgetInfoList; + widgetInfoList.append(d->edit3DView.widgetInfo()); widgetInfoList.append(d->formEditorView.widgetInfo()); widgetInfoList.append(d->textEditorView.widgetInfo()); widgetInfoList.append(d->itemLibraryView.widgetInfo()); diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index b17ed5941c3..091f1d5e459 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -31,6 +31,7 @@ #include "qmldesignerplugin.h" #include "crumblebar.h" #include "documentwarningwidget.h" +#include "edit3dview.h" #include #include diff --git a/src/plugins/qmldesigner/qmldesigner_dependencies.pri b/src/plugins/qmldesigner/qmldesigner_dependencies.pri index 47c23f57f57..cba0186ce73 100644 --- a/src/plugins/qmldesigner/qmldesigner_dependencies.pri +++ b/src/plugins/qmldesigner/qmldesigner_dependencies.pri @@ -23,6 +23,7 @@ INCLUDEPATH *= \ $$PWD/components/componentcore \ $$PWD/components/importmanager \ $$PWD/components/itemlibrary \ + $$PWD/components/edit3d \ $$PWD/components/formeditor \ $$PWD/components/navigator \ $$PWD/components/stateseditor \ diff --git a/src/plugins/qmldesigner/qmldesignericons.h b/src/plugins/qmldesigner/qmldesignericons.h index 9a16ce2b0c0..840f1ea97c7 100644 --- a/src/plugins/qmldesigner/qmldesignericons.h +++ b/src/plugins/qmldesigner/qmldesignericons.h @@ -47,5 +47,36 @@ const Utils::Icon NO_SNAPPING({ const Utils::Icon NO_SNAPPING_AND_ANCHORING({ {QLatin1String(":/icon/layout/snapping_and_anchoring.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_LIGHT_ON({ + {QLatin1String(":/edit3d/images/edit_light_on.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_LIGHT_OFF({ + {QLatin1String(":/edit3d/images/edit_light_off.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_SELECTION_MODE_ON({ + {QLatin1String(":/edit3d/images/group_selection_selected.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_SELECTION_MODE_OFF({ + {QLatin1String(":/edit3d/images/item_selection_selected.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_MOVE_TOOL_ON({ + {QLatin1String(":/edit3d/images/move_selected.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_MOVE_TOOL_OFF({ + {QLatin1String(":/edit3d/images/move_active.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_ROTATE_TOOL_ON({ + {QLatin1String(":/edit3d/images/rotate_selected.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_ROTATE_TOOL_OFF({ + {QLatin1String(":/edit3d/images/rotate_active.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_SCALE_TOOL_ON({ + {QLatin1String(":/edit3d/images/scale_selected.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_SCALE_TOOL_OFF({ + {QLatin1String(":/edit3d/images/scale_active.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_FIT_SELECTED_OFF({ + {QLatin1String(":/edit3d/images/fit_active.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_EDIT_CAMERA_ON({ + {QLatin1String(":/edit3d/images/persp.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_EDIT_CAMERA_OFF({ + {QLatin1String(":/edit3d/images/ortho.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_ORIENTATION_ON({ + {QLatin1String(":/edit3d/images/global.png"), Utils::Theme::IconsBaseColor}}); +const Utils::Icon EDIT3D_ORIENTATION_OFF({ + {QLatin1String(":/edit3d/images/local.png"), Utils::Theme::IconsBaseColor}}); + } // Icons } // QmlDesigner diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pro b/src/plugins/qmldesigner/qmldesignerplugin.pro index 30c34209377..ea017e3ceff 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.pro +++ b/src/plugins/qmldesigner/qmldesignerplugin.pro @@ -13,6 +13,7 @@ include(designercore/designercore-lib.pri) include(components/componentcore/componentcore.pri) include(components/integration/integration.pri) include(components/propertyeditor/propertyeditor.pri) +include(components/edit3d/edit3d.pri) include(components/formeditor/formeditor.pri) include(components/texteditor/texteditor.pri) include(components/itemlibrary/itemlibrary.pri) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 3daa46281b9..4bad2b32bed 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -51,6 +51,7 @@ Project { "components/importmanager", "components/integration", "components/propertyeditor", + "components/edit3d", "components/formeditor", "components/itemlibrary", "components/navigator", @@ -70,6 +71,7 @@ Project { cpp.includePaths: base.concat([ product.sourceDirectory, product.sourceDirectory + "/components/componentcore", + product.sourceDirectory + "/components/edit3d", product.sourceDirectory + "/components/formeditor", product.sourceDirectory + "/components/integration", product.sourceDirectory + "/designercore", @@ -175,12 +177,14 @@ Project { "commands/drop3dlibraryitemcommand.h", "commands/update3dviewstatecommand.cpp", "commands/update3dviewstatecommand.h", - "commands/enable3dviewcommand.cpp", - "commands/enable3dviewcommand.h", "commands/view3dclosedcommand.cpp", "commands/view3dclosedcommand.h", "commands/puppettocreatorcommand.cpp", "commands/puppettocreatorcommand.h", + "commands/inputeventcommand.cpp", + "commands/inputeventcommand.h", + "commands/view3dactioncommand.cpp", + "commands/view3dactioncommand.h", "container/addimportcontainer.cpp", "container/addimportcontainer.h", "container/idcontainer.cpp", @@ -444,6 +448,15 @@ Project { "debugview/debugviewwidget.cpp", "debugview/debugviewwidget.h", "debugview/debugviewwidget.ui", + "edit3d/edit3dview.cpp", + "edit3d/edit3dview.h", + "edit3d/edit3dwidget.cpp", + "edit3d/edit3dwidget.h", + "edit3d/edit3dcanvas.cpp", + "edit3d/edit3dcanvas.h", + "edit3d/edit3dactions.cpp", + "edit3d/edit3dactions.h", + "edit3d/edit3d.qrc", "formeditor/abstractcustomtool.cpp", "formeditor/abstractcustomtool.h", "formeditor/abstractformeditortool.cpp", diff --git a/src/plugins/qmldesigner/switchsplittabwidget.cpp b/src/plugins/qmldesigner/switchsplittabwidget.cpp index 7dea80f164f..e30f4180cfe 100644 --- a/src/plugins/qmldesigner/switchsplittabwidget.cpp +++ b/src/plugins/qmldesigner/switchsplittabwidget.cpp @@ -121,25 +121,32 @@ QWidget *SwitchSplitTabWidget::currentWidget() const void SwitchSplitTabWidget::updateSplitterSizes(int index) { - if (isHidden()) { - // we cannot get the sizes if the splitter is hidden - m_splittSizesAreDirty = true; - return; - } - QVector splitterSizes = m_splitter->sizes().toVector(); + QVector splitterSizes(m_splitter->count()); int splitterFullSize = 0; - for (int size : splitterSizes) - splitterFullSize += size; + bool isHorizontal = m_splitter->orientation() == Qt::Horizontal; + for (int i = 0; i < m_splitter->count(); ++i) { + auto widget = m_splitter->widget(i); + splitterFullSize += isHorizontal ? widget->width() : widget->height(); + } + if (index > -1) { - // collapse all but not the one at index + // collapse all but the one at index splitterSizes.fill(0); splitterSizes.replace(index, splitterFullSize); } else { - // distribute full size - splitterSizes.fill(splitterFullSize / splitterSizes.count()); + // distribute full size among enabled tabs + int divisor = splitterSizes.count(); + for (int i = 0; i < m_splitter->count(); ++i) { + if (!m_tabBar->isTabEnabled(i + fakeTab)) + --divisor; + } + + int splitSize = splitterFullSize / divisor; + for (int i = 0; i < m_splitter->count(); ++i) + splitterSizes.replace(i, m_tabBar->isTabEnabled(i + fakeTab) ? splitSize : 0); } + m_splitter->setSizes(splitterSizes.toList()); - m_splittSizesAreDirty = false; } int SwitchSplitTabWidget::addTab(QWidget *w, const QString &label) @@ -178,20 +185,10 @@ void SwitchSplitTabWidget::switchTo(QWidget *widget) updateSplitterSizes(widgetIndex); m_tabBar->setCurrentIndex(widgetIndex + fakeTab); } + widget->setFocus(); } -bool SwitchSplitTabWidget::event(QEvent *event) -{ - if (event->type() == QEvent::Show && m_splittSizesAreDirty) { - bool returnValue = QWidget::event(event); - updateSplitterSizes(m_tabBar->currentIndex() - fakeTab); - return returnValue; - } - - return QWidget::event(event); -} - void SwitchSplitTabWidget::updateSplitButtons() { const bool isTabBarNecessary = count() > 1; @@ -203,14 +200,13 @@ void SwitchSplitTabWidget::selectFakeTab() m_tabBar->setCurrentIndex(0); } -SwitchSplitTabWidget::Mode SwitchSplitTabWidget::mode() +SwitchSplitTabWidget::Mode SwitchSplitTabWidget::mode() const { const bool isTabBarNecessary = count() > 1; const int fakeTabPosition = 0; const int hasSelectedTab = m_tabBar->currentIndex() > fakeTabPosition; - if (isTabBarNecessary && !hasSelectedTab) - return SplitMode; - return TabMode; + // Note: When splitting the view by dragging from the side of the view, SplitMode is not detected + return (isTabBarNecessary && !hasSelectedTab) ? SplitMode : TabMode; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/switchsplittabwidget.h b/src/plugins/qmldesigner/switchsplittabwidget.h index 3bd19f393e9..72c5cc3e5e8 100644 --- a/src/plugins/qmldesigner/switchsplittabwidget.h +++ b/src/plugins/qmldesigner/switchsplittabwidget.h @@ -37,10 +37,9 @@ namespace QmlDesigner { class SwitchSplitTabWidget : public QWidget { Q_OBJECT - enum Mode { - SplitMode, - TabMode - }; + + enum Mode { SplitMode, TabMode }; + public: explicit SwitchSplitTabWidget(QWidget *parent = nullptr); int count() const; @@ -50,19 +49,15 @@ public: QWidget *takeTabWidget(const int index); void switchTo(QWidget *widget); -protected: - bool event(QEvent* event) override; - private: void updateSplitterSizes(int index = -1); void updateSplitButtons(); void selectFakeTab(); - Mode mode(); + Mode mode() const; QSplitter *m_splitter = nullptr; QTabBar *m_tabBar = nullptr; QWidget *m_tabBarBackground = nullptr; const int fakeTab = 1; - bool m_splittSizesAreDirty = true; }; } // namespace QmlDesigner diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index c3c53cfd813..941951f4982 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -47,9 +47,10 @@ extend_qtc_executable(qml2puppet changeselectioncommand.cpp changeselectioncommand.h drop3dlibraryitemcommand.cpp drop3dlibraryitemcommand.h update3dviewstatecommand.cpp update3dviewstatecommand.h - enable3dviewcommand.cpp enable3dviewcommand.h view3dclosedcommand.cpp view3dclosedcommand.h puppettocreatorcommand.cpp puppettocreatorcommand.h + inputeventcommand.cpp inputeventcommand.h + view3dactioncommand.cpp view3dactioncommand.h valueschangedcommand.cpp ) diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 8cdbbb84d83..bf494c8a7bd 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -99,12 +99,14 @@ QtcTool { "commands/drop3dlibraryitemcommand.h", "commands/update3dviewstatecommand.cpp", "commands/update3dviewstatecommand.h", - "commands/enable3dviewcommand.cpp", - "commands/enable3dviewcommand.h", "commands/view3dclosedcommand.cpp", "commands/view3dclosedcommand.h", "commands/puppettocreatorcommand.cpp", "commands/puppettocreatorcommand.h", + "commands/inputeventcommand.cpp", + "commands/inputeventcommand.h", + "commands/view3dactioncommand.cpp", + "commands/view3dactioncommand.h", "container/addimportcontainer.cpp", "container/addimportcontainer.h", "container/idcontainer.cpp",