From 4908055937697e9ba4ea681246dd62de2829d040 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 11 Feb 2020 11:33:25 +0200 Subject: [PATCH] Integrate Edit3D view into Creator Edit3D view is now a tab alongside Form Editor. Buttons were moved to a Creator side task bar on Edit 3D view. Change-Id: Ia06107e4f855ba512ffea3e628a61558894e800e Fixes: QDS-1570 Reviewed-by: Thomas Hartmann --- .../qml/qmlpuppet/commands/commands.pri | 6 +- .../qmlpuppet/commands/inputeventcommand.cpp | 96 ++++ .../qmlpuppet/commands/inputeventcommand.h | 68 +++ .../commands/puppettocreatorcommand.h | 2 +- .../commands/update3dviewstatecommand.cpp | 17 +- .../commands/update3dviewstatecommand.h | 6 +- ...iewcommand.cpp => view3dactioncommand.cpp} | 41 +- .../qmlpuppet/commands/view3dactioncommand.h | 67 +++ .../instances/nodeinstanceclientproxy.cpp | 29 +- .../instances/nodeinstanceclientproxy.h | 6 +- .../nodeinstanceserverinterface.cpp | 12 +- .../interfaces/nodeinstanceserverinterface.h | 6 +- .../qml/qmlpuppet/mockfiles/EditView3D.qml | 528 +++++++++--------- .../qml/qmlpuppet/mockfiles/EditWindow3D.qml | 50 ++ .../qml/qmlpuppet/mockfiles/IconGizmo.qml | 20 +- .../qml/qmlpuppet/mockfiles/LightGizmo.qml | 3 +- .../qml2puppet/editor3d/generalhelper.cpp | 53 +- .../qml2puppet/editor3d/generalhelper.h | 10 +- .../instances/nodeinstanceserver.cpp | 16 +- .../qml2puppet/instances/nodeinstanceserver.h | 3 +- .../qt5informationnodeinstanceserver.cpp | 303 +++++++--- .../qt5informationnodeinstanceserver.h | 16 +- .../instances/qt5nodeinstanceclientproxy.cpp | 4 +- .../instances/qt5nodeinstanceserver.cpp | 1 + .../instances/servernodeinstance.cpp | 12 +- share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc | 1 + src/plugins/qmldesigner/CMakeLists.txt | 13 +- .../componentcore/actioninterface.h | 3 +- .../qmldesigner/components/edit3d/edit3d.pri | 12 + .../qmldesigner/components/edit3d/edit3d.qrc | 34 ++ .../components/edit3d/edit3dactions.cpp | 97 ++++ .../components/edit3d/edit3dactions.h | 84 +++ .../components/edit3d/edit3dcanvas.cpp | 125 +++++ .../components/edit3d/edit3dcanvas.h | 66 +++ .../components/edit3d/edit3dview.cpp | 247 ++++++++ .../components/edit3d/edit3dview.h | 87 +++ .../components/edit3d/edit3dwidget.cpp | 106 ++++ .../components/edit3d/edit3dwidget.h | 33 +- .../edit3d/images/edit_light_off.png | Bin 0 -> 1189 bytes .../edit3d/images/edit_light_off@2x.png | Bin 0 -> 1430 bytes .../edit3d/images/edit_light_on.png | Bin 0 -> 1355 bytes .../edit3d/images/edit_light_on@2x.png | Bin 0 -> 1766 bytes .../components/edit3d/images/fit_active.png | Bin 0 -> 266 bytes .../edit3d/images/fit_active@2x.png | Bin 0 -> 386 bytes .../components/edit3d/images/global.png | Bin 0 -> 433 bytes .../components/edit3d/images/global@2x.png | Bin 0 -> 561 bytes .../images/group_selection_selected.png | Bin 0 -> 438 bytes .../images/group_selection_selected@2x.png | Bin 0 -> 904 bytes .../edit3d/images/item_selection_selected.png | Bin 0 -> 355 bytes .../images/item_selection_selected@2x.png | Bin 0 -> 661 bytes .../components/edit3d/images/local.png | Bin 0 -> 1309 bytes .../components/edit3d/images/local@2x.png | Bin 0 -> 1960 bytes .../components/edit3d/images/move_active.png | Bin 0 -> 294 bytes .../edit3d/images/move_active@2x.png | Bin 0 -> 303 bytes .../edit3d/images/move_selected.png | Bin 0 -> 191 bytes .../edit3d/images/move_selected@2x.png | Bin 0 -> 272 bytes .../components/edit3d/images/ortho.png | Bin 0 -> 1310 bytes .../components/edit3d/images/ortho@2x.png | Bin 0 -> 1727 bytes .../components/edit3d/images/persp.png | Bin 0 -> 1391 bytes .../components/edit3d/images/persp@2x.png | Bin 0 -> 1971 bytes .../edit3d/images/rotate_active.png | Bin 0 -> 451 bytes .../edit3d/images/rotate_active@2x.png | Bin 0 -> 869 bytes .../edit3d/images/rotate_selected.png | Bin 0 -> 478 bytes .../edit3d/images/rotate_selected@2x.png | Bin 0 -> 906 bytes .../components/edit3d/images/scale_active.png | Bin 0 -> 242 bytes .../edit3d/images/scale_active@2x.png | Bin 0 -> 338 bytes .../edit3d/images/scale_selected.png | Bin 0 -> 277 bytes .../edit3d/images/scale_selected@2x.png | Bin 0 -> 364 bytes .../components/formeditor/formeditorview.cpp | 3 - .../formeditor/formeditorwidget.cpp | 11 +- .../components/resources/centerwidget.css | 4 + .../componentsplugin/componentsplugin.qbs | 1 + .../designercore/include/abstractview.h | 6 + .../designercore/include/nodehints.h | 1 + .../designercore/include/nodeinstanceview.h | 6 +- .../designercore/include/viewmanager.h | 1 + .../instances/nodeinstanceserverproxy.cpp | 20 +- .../instances/nodeinstanceserverproxy.h | 3 +- .../instances/nodeinstanceview.cpp | 26 +- .../designercore/metainfo/nodehints.cpp | 5 + .../designercore/model/abstractview.cpp | 20 + .../qmldesigner/designercore/model/model.cpp | 16 + .../qmldesigner/designercore/model/model_p.h | 3 + .../designercore/model/viewmanager.cpp | 14 +- src/plugins/qmldesigner/designmodewidget.cpp | 1 + .../qmldesigner/qmldesigner_dependencies.pri | 1 + src/plugins/qmldesigner/qmldesignericons.h | 31 + src/plugins/qmldesigner/qmldesignerplugin.pro | 1 + src/plugins/qmldesigner/qmldesignerplugin.qbs | 17 +- .../qmldesigner/switchsplittabwidget.cpp | 50 +- .../qmldesigner/switchsplittabwidget.h | 13 +- src/tools/qml2puppet/CMakeLists.txt | 3 +- src/tools/qml2puppet/qml2puppet.qbs | 6 +- 93 files changed, 2037 insertions(+), 509 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/commands/inputeventcommand.h rename share/qtcreator/qml/qmlpuppet/commands/{enable3dviewcommand.cpp => view3dactioncommand.cpp} (58%) create mode 100644 share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/EditWindow3D.qml create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3d.pri create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3d.qrc create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dactions.h create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dview.cpp create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dview.h create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp rename share/qtcreator/qml/qmlpuppet/commands/enable3dviewcommand.h => src/plugins/qmldesigner/components/edit3d/edit3dwidget.h (65%) create mode 100644 src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/fit_active.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/global.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/global@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/local.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/local@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/move_active.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/move_selected.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/ortho.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/persp.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/persp@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/rotate_active.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/scale_active.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/scale_selected.png create mode 100644 src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png 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 0000000000000000000000000000000000000000..73e6e92374b15f4b693ef5804309327c65a06253 GIT binary patch literal 1189 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoBuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztF!N`IM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTcwn`Gu2HtFf>sx zx70H)KM@pFf`UTFxEFT)-^P;GO)BVG*y5CB|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9ucqbpIn-onpfiKVyje1YYl>zP+vl9-pA3e%g3(Cds>ua$FA zYGO%#QAmD%4lMQpGV)9Ei!<^I6r7zE!ZY(y^2>`s;R+5kE0@%w%(B!Jx1#)91#rMv zWg=N_>0)GIZt7xcWM*k@Xlia@VPxoLY-wR`W?|s$Y+!7t1l5y*zXjWXkDm^&28sGc4pMq_I}YbleZpRcAi@Q*y#B{v+%Q1nW68zBR5&6%HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRu#Dg zxv3?I3Kh9IdBs*0wn|`gt@4VkK*IV;3ScEA*|tg$M@9GsC^+XAr7D=}nd&AR7@8=U zTk08_8k$%b>L?f)7#iyv80#Av>lzwa8CY5wnkqnnlAVH0QA(Oskc%7CuA-DQTcwPW zk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7Wta&rsl~}fnFS@8 z`FRQ;6BCp2OG|8(l%U2|bol2!OE0x2x;^|f-zPcF?(%`5SAu~n+bEznEJOtCUB zH#c=La5XhFFt#)_bak{eG_-WIa58kXG_y1{G&X_h^~@_SNz6-5h3U;i=rzHs*UGsl zHL)bWC?r2W2Nrt)8Tlpo#Toep3eL_7;hA|U`Q^o+a0LgNl}l<-W?5>ATTyF?VaXfv- zhRq)|`dd}rPq69MbnUpH^CU1V$jnU4OsplyEGOs94FO*@Gdb?0!x~~|E-bj>(~*+; zN#=j>{8`JaC(pcn#&Y|){dKjM=M+Di_y11u`JekF_a1+IF*7pIs@Gd;0^1VCOa~~{ z%9CY(AjeF5Z!Fs_2fiOnX4gb-)LPH-QQOB>GletEai!C3l^d*gA4DEey~3ZD@riqZ z%#x;(0PpezayE@(iPHo!17rhrc&Yv^Bob=~sETQK~Cju_ty} z#*>{bTpCtR64joDvzIsKcU{z4_xJGS1CmGo2pkg&-15<+z+t0#%f{L%X>SUR8}2sC z26!(Je!^g!QW=-4N@0JEmh0o{z6+UQI(99{wx2gI9%cVW@IP1GuuYcKfC|mf! zyfe9tdI3Don7(Wd_!Yo<&h@lg_yINvCQYulR~HESG%E*cZ`yBq_p$ojv{|A%muv|N zIrTldQP`#{PWXOM*W1-81q)jj{o_6IGqadG{EBwRQnuEFDcd~DZm9*_o+`$}(`?o1 z+?6{!Im+O{66apgFKePM1s{7EG`rI66vJip9hY4lJ}p1W5XHj(pw;jGh7$sA%sJMz stcDM4W5h3>w%@fB5=B>Dgf}oUJf4u1AFtuD6jV}ry85}Sb4q9e06~TX5dZ)H literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7660c285460512ed0025dd1d64014fb5b661adaf GIT binary patch literal 1355 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoBuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztF!N`IM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTcwn`Gu2HtFf>sx zx70H)KM@pFf`UTFxEFT)-^P;GO)BVG*y5CB|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9ucqbpIn-onpfiKVyjezP+vl9-pA3e%g3&})EKua$FA zYGO%#QAmD%4lMQpGV)9Ei!<^I6r7zE!ZY(y^2>`s;R+5kE0@%w%(B!Jx1#)91#rMv zWg=N_>0)GIZt7xcWM*k@Xlia@VPxoLY-wR`W?|s$Y+!7t1l5y*2l`<&6)ovDqo6U@tD!eqQcsZl(7} zQ);%Kdy&7(`2U~a%|)+Y->H6Q`FvjW`=9Ug`;R7V%Q0)$J$?2P)5C%r+{R%wMY?Js zxuxtoXX#8`C#ZKP@4Neq#g>j)+RdarXleunL_JyfB9e3YYD_l@o z#GZBHQ*4Q9hjfJN_DO{^g;q#EWDK|2ap$t~B4M_TAD4u>N>~Z{MSgK*+IE2RueGn? zoX5r9+nKi=-5>Gph3UKrh3tn5c)~BJ?^ov5@{c*>#O&Y|eq!@d@?^H@)Ml`7DRF6-PIr7h{d$P1 zXky+WgYuRg&gN6z71y#=bM6XUSv>XP=4XOACtj@dxN&n$)w+{crk|BRw_KF{_y1on e(=XMrN-#uRHRzxA|JX-R@#g93=d#Wzp$P!*$nT2) literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..836bd2a0d594e7a283a3f755ce6bb6817cad5562 GIT binary patch literal 1766 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?FHY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRu#Dg zxv3?I3Kh9IdBs*0wn|`gt@4VkK*IV;3ScEA*|tg$M@9GsC^+XAr7D=}nd&AR7@8=U zTk08_8k$%b>L?f)7#iyv80#Av>lzwa8CY5wnkqnnlAVH0QA(Oskc%7CuA-DQTcwPW zk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7Wta&rsl~}fnFS@8 z`FRQ;6BCp2OG|8(l%U2|bol2!OE0x2x;^|f-zPcF?(%`5SAu~n+bEznEJOtCUB zHZ*s1b96K`Ft#)_baiwzH8pf`HE?pYbTv0Ma5aJH^~@_SNz6-5h3U;i=(WVF*UGsl zHL)bWC?r2W2Nrt)8Tlpo#Toep3eL_7;hA|U`Q^o+a0LgNl}l<-W?5>ATTyS zSEjm5xai^9z3Ju6@)zQK(?7qtTYbOwyGoe`-$>3Y9-mbC8;K`HfJhh6WNT})1T*J>eUTD0u&tcCLv?QXCA z{lR|GWt%;FHsrpuxp^^X?b#-)XX|>e^?qyB`Mb`eFe(0p@1z&Rk^K*mC`dd4j4>!{NO)*EL=qHmQ)=vM4Sz zJ3LXC$8gJPqe8hi?bVKdwJsJf3zxp-LQ$%>Yt ze|QoOonDdtBF6bMx97&UMiE^#moL6bSo3O!!~vJDK|NP)-d}cNyGLMf%yP{IE5(D3 z-3Z+mmf};uww3LhV1rhUYO04fZ%E5s&AcGdugpu{u2ht$3-vm-&SCk-+uLSbXXdG4 z*eaSeGogE-+PjGhKLng|kDYRR4o|EZ^Beczx9_Uz>;+#dmx!0W=YZo7ja|%z;`Y1&@|pJ!sdw(%=dr7wO{4sm>X-NREcSn9 s9r60R*gDnWRKpZTP3Ao(;u+Z(QtxvvdltR#G^pnBboFyt=akR{0OLWj0{{R3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..056e9ec3c8b690fa708232ff38f26bd477ca91ae GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|7G?$p2BAoW(+ms@iUB?$t_%ze|M7zJim!h% zFfeeH1o;IsFmegVD|Aes_kFM4?BUDd zmXO#X6v5&Uq!g)e&d7a()wWQDbE{Yk)VU8uvQ2C#I1qH^*fF=c##4HGc@>rwuZgMG6~mKvvKSfy(?M7(iWEXms7Cf;x-jCEtW<&E4&0)C1Sve}{?n{61*6pFAH q3b`JbC!C{3i~y?LMUs zGOi@ZFPMRmTR>hxrLtrC<(t3GybI`HU|{&=>Eak-(R+6CM&3gP0t~sD3#RB@N@3#i z67w)iU`boxeu_!Y$ib|kZ651{6&o4fH`&+yek&ke^7GNxQ!oF_pMLg6(Bj6BUAvk? z6jmsBhHHE1GUZLZwBuI9Qh^?kmyJq{Q!Z5`SP89B;?xjYz|45r)!~@KQl>_aiJAeO z0*wn!Xnr`A$Ft4ye*eC{IISkl%>2Vq{&s3tca-z;PwW~VB8!|?PMhiZ#ATggiItV0iwT!t z%6XY;>)pjoP7f#N82#RtfA9A9r7 zNT%AW=>pHXhCSB(yY4+tuIes-ygMVg_|}bCZ!aGEw(BidP(GXDuSVtEobm(D-8q$h zHEc2~I}u!`>F6RJaO&2YS-M4j?Ot8&Gjh-UJsRlEm-J5dT-Z}q4J}PGXHg#J-?wg< ziPtbhu;(>iK2kh!NA=?`QkSlk98sOgxUEsxK~r;{@YQDxncu7Ud^9xm_D@j_T= zE8FCQ!c!U|RgdmnzGRDrpLzlBoyt?{yVvcy^5CnG%ak7$GWf@PVN@2h%!85kHCJYD@<);T3K0RZmQyXgP` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a2a857fb10cb935e127fe65d0263ed0fcb7ef423 GIT binary patch literal 561 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_<_GwMxH2#>?Ag0-&>~aQ zg-00}7)(ln{DK)6nV31b1Vlt7l~r|g^$kretZW^eeEkE1^9o9;8~P?pn?7^R+TBNw zoj8B(`mNiqzy19C@8g?KS_}+~yq+$OAs)xyPVo#r6qbfg%qJToP9PQ`M&n)esHw+6ZM9gTf4y}z{R)#Uvr9Be+N-)GQ2_cMXj;oqAX z?{zgUY|lH?BYShHcikEJmkX@zPkm>(HurUhsj1an|9nwa=bsAX{lh% ztxqbw$25D*XMESbcY2S>`DuqLTGns4W;fxs9g~CD-1MCMDT*1d?KRpqHiai2*v1*k zw86%(Wy@3XDL?14C%3MRUN_G>M0nCQ>qA*QxA!xYIa_k{xz+bO$Xc50&${huDF4)- Rmw|zS!PC{xWt~$(69AmUAF==d literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bfb848aa384d7aa0694c22c281eff34094c0aaaa GIT binary patch literal 438 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoYdu{YLp(a)UfJKz8z^z? zBY#+v%i_xxy&Pd%d9_-dRtip<8al^q(WNdo5seN3m06$pUvze~xG26TyWZcm{gUQ{ zjtwW??B%RJe`fE&DZhP}&G=q>uJY5r85>XS4}7#uNcz`{d$+WV64?5u+=xo8GKx6D zXA_>Z?9{iE4+7yIBRZ3(KC+`7WK~F#X^HSJi8$U&?)ZZ1GNG zB^UB0T=w5{aGiaUd;y35N1x8xt2@PR@z!n6 zJm2xr+;Z-rN}GVBbylW_ESe84xP9WK7~kVrLer;2TwfHGwyJB5$&6S*O~c-^8T&r< z?r7+q5tbC@H~-(U1V-zrGbUXwSLJ)8ckkip51C>Q?WPq7O?TISdGEE5?{7Q)dg*+_ ze(9oJahb<2*f!6pd+@b@Fa5%l`puVo6Jok~%vVZ26O@^7IcVt&hjLctSzLZ5ypu0? wYu#>k3_e&rXRVQ~)SPLTk85rA(tjY{cr!s&i*3U*1_lNOPgg&ebxsLQ0A8ERr~m)} literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f18895dc4400ab6fd4265573925cece156414df2 GIT binary patch literal 904 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?FS zPc~Sg8Kkml#*vg`&6?L;IzKf`Vi(c()|fd(T;*e$&5DIjg03|yeN(8bk6-0+ zUGzr>xjXBP_0|^ed;BKzY}z-w-*b!?|6P6gUiI4ixqJV;{=KjC=8`2#mV6QDv2ED+ zcUN?Jb*1V<69#dEvWOL~k{wD5L}xI?9KXS~ep@?70S~)g;v1p!i+EfF3)Bnl%UiT< zyluGc&}JRQLYoH`O4oA_aQ4VPh@9S`!KCxS^IbXf>jwD)Nt`Pu#&ru_C}oWL%k=Ja zux!*@)@O|Q4V?!}d*;5{s%;c#GaZLKt_t$o*gLvbw!N z`sZc`(E^F&*#_G#Wyi8S;#%=KVAa*=gnduil9daDl2`Ao_n46pykMj0f#k|nZmav} z-dMx(jj^`j_5r6YRj+QUx`goCFz-82yEfeWm~?xC<$>%4abfRf&Wnv?$@nU~L*4)J z-d}s}x+ZL@NHDn2v~jiVZkCQ$j7-LXI~vw-JYW0rfF`H<_Sw09Ry!Ya{MgQ3l<}1@ zg5}MWNna00_Q<}td2ERQ|CMUfxepKdt@b@o^g!A`d`Hv9$ES1?LYCN02+R9#!d=1H zBP>{Kv%BMn;0G7CO-dzdT+XXkA5eL~_TbP9nPX;c5#^mPn6~^9Jkh+aHSqX1{RYVc zg_Zy1dhYgbthK$ZCvcpZ<&efK_D@Q7%-)S}gEp~Q^lxmoyFdMg2U;(M|J->vX!eb5 zmH9l1>l)lYO|qNBZq8h~x*_w@!Jipl4`k0(_&6zI^|u2)Q}~sW+ZlX6ZCQL{?(&An z4nKbL4crnc3ok#}s=?&RaiZ$LjhmZd3)Z}yAbvOGK<>_KNjXzxl4RVUu89%i5}fec z$&l>^R}br*i$%@pkuF?<4}`YFE<3Fov`untT;;U8K@DNKN=ogwSIB;O)8(Tmr!e6} zUSX83`#CvPh3)B?ZmXl?aydPm4ix`95iK@}W1-uYUr(-r()XYL4Eq^F-(S-xlw^I+ Qz`(%Z>FVdQ&MBb@0IqweK>z>% literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2b685d3d00a8d06631fbe3678b9997f258c77d1a GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJowLD!MLp(a)PO@}b#-f0!6I!P2 z^K8yNW+%Y$zWT&r+n7T$9vavmui4i3*4Jy&C6+vc_$kZO9JwP{-x=n6MNd{pw|I+GqHmNMTKFnx;~~5R+)9ewN`B3tx=~*Xx_7rY+T67$I<2|AS8D zDXxO{pR-I@MYw}*O)7~zvF_tClUg2aj~R@52KI+)yl(XbvRGChFn#v<62s+5C6$v{ z_BDz>Fs|O$P`-dUhxzz_!6))rUs84-DNvfstPvl`V_$3jQqW@RPOej|nm=a=-4rt{ zNmeAmF@af9)W^OqGXBUo#gOswkinbs*=HNKDvj#N~% zzHqYg0o$V4y}^QZj3P6PwPXr)w_dgoy-?j?@r!kjK~?wN1IjMnrI)AFlr`uv3TVLxT?t7cb6vZNka9;gZjj(<`_OHQqZZGTvjf?|J2a$!)u! z?bP&%8v-M~aBevL;-Qb}d3PDzAL|4*F^gPrn>&Z$oq|=)93Cg;FIGW63NF}wIkt); z;0xat$->9ScN7Li?B6uUbN%*9*YmdTV>o>v{rg{0k6(YK4c^R1!)r2!U%EjLz z8@8|Bmd|WIAR2sqJ7d(A z+Zj78&u@vd)K<-J_~ubK(V{Br4wr_~0rrGL7R*8m9zOdK`S{9}D_8#fXV}lEFlVAl U^4&;v1_lNOPgg&ebxsLQ07c>=(f|Me literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0a608f6816e62e1942a668cbe66f2745db13e623 GIT binary patch literal 1309 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoBuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFe_$;M3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTcwn`Gu2HtFf>sx zx70H)KM@pFf`UTFxEFT)-^P;GO)BVG*y5CB|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9ucqbpIn-onpfiKVyjezP+vl9-pA3e%g3(Cds>ua$FA zYGO%#QAmD%4lMQpGV)9Ei!<^I6r7zEG{Q6UQu51-H9;W@4mK;7)S}F?)D*X({9FZa z&{$<+vEJ0k*wNI`%)-FU!W`suM{`FQL22%>BK2jvr}%8i$qcrm;Yg&!g^C9Xi<#UNvBh7lVXI#PAt`lxUn)aqDM_< z=@joG$@{_kS6*(pC;47y&M%Ynb927iyx(ctt1iKF?C7Q=$B*tfV&jlharoiI!WFZ6 zm|`9(PjZxgwYM)Vf$jd0hNhkSTuL>LZb-Y>>|@TnCGu;H&tpdC`diFXl`7W0f2MPP zrtTrhppT2btzeq5-T&b3Uq1p{mtU|;l3D$zzoc{4gUbuvYB+BE`kQl-L7R8&d$*-= zZ>}@EeBs>MwC1r?aM*nFFRSM@M4d@E;@RNNo3nm>E{JUY_+MAC`Q*DR?21d|eX?#G zu*tf^@gR8Bw%=11hE_lEGK<~zihG5d-nP3ZmMwd;n0xoGlt9t*`~Qc3R6W43TsinZ Tf0y}6P=V#?>gTe~DWM4fMkwDG literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a5c931e750fa19f3baaae1fd47679c4683d1ddd6 GIT binary patch literal 1960 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?FHY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRu#Dg zxv3?I3Kh9IdBs*0wn|`gt@4VkK*IV;3ScEA*|tg$M@9GsC^+XAr7D=}nd&AR7@8=U zTk08_8k$%b>L?f)7#iyv80#Av>lzwa8CY5wnkqnnlAVH0QA(Oskc%7CuA-DQTcwPW zk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7Wta&rsl~}fnFS@8 z`FRQ;6BCp2OG|8(l%U2|bol2!OE0x2x;^|f-zPcF?(%`5SAu~n+bEznEJOtCVx zFn2aIH*zvGFg7(bbaiwzHg$0_H8wYJHgIw=uyBIu^~@_SNz6-5h3U;i=yk-a*UGsl zHL)bWC?r2W2Nrt)8Tlpo#Toep3eL_78sV9FDf#8anxK#c2b+~kYEfocYKmJ?ey##I zXsj}^S#MhftcVV2}+)J3W#){nwMg$RHS5YSEA}C&cMJT>*?YcQgQ3etef5;g(An( z?{pnG<#pJr>7v*Q9qn5Sx7c40oRcUl+TohZ`<8^pbPVxFH z8+0z1ZN5|_o4)LQm&24>lfPK!+({qZ?fBOATZzK7D|osNYJa$V!tSFggXYYadVR~ALpCtl zur6I7wWZyO(=&4o%g4NP(uWm39W2~%dWG9}Gv*+rZd;r0+7-N6j>a2Utr<>UtJ&c2 ze8-DVaUXb18rXFfZqKQC%2@N@ep;OH28LrR)q2XbTrWzl{CasoUt>h*bJymW35{Y4599^dGj?*VkDZ8}Mu4}if-n*-()ZUdpzMh|U zP@j9IwdRNEpB8rBJXKh%pZP$}oZsivR+S0Tv(oG~G8**H^4J)Wwc_am0crD#NB5?v z%zyCW>u#}2#)W(4EDn>})F7O06u}g>vGVx`Yhh{IW1R+j4k{*cr!c7f%Mks}z4J_0 zYv1{xx#5T1&a*_$aZw8mxRh_-6STN0?OFfnQ&t>m4azYLN3A68lzwR86Em>(T=m;S z@}6ms-|I-FZ0qo+B}~i1BzGKR*cEy`q*zOn@lWF8Z*0m8+~sMRfBx{quuhMe;%qH` zbm^4{-8=Kx{%q}{!@MaF*%P9w| z52k&X$bBhf)d|K|RoNQ*W(uqBnrf}}^lyOB{5qNHrE@3y+VQvFn!PjaR6@G&i8ZfS zZ_brvogLz=U?yUeko@+0fSQG|=K8mHBA*t%)?BrzcW)AZ8ru}z#7_3-M}seP2JAl3 zu(&za>C_(k)t|39THo%T(VEg1mc7B-Lw9EC^Q}&wYwe9gPR0e^Z&A4f5R&!!DVYzo)sFBg$8V?9{I`#{#>SlkPfq+Jy{&C36^1vwws^FNr+z|3Iw Wi<>>uV)AcL-RbG-=d#Wzp$Py!UjHrt literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d21d290349ce216e263c91151198bb31c15e4e57 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJo-g>$?hIn+oonp(^fSUemd)ob!$x;$9)X;e$#QQ-d8`IXSZFLTXW30NK0vX!xpDA y;x<>hR@!~%Ke@Vd#v#M{;KTP$@{}+gked?W%m?%TPH zfq{XiB*-tAfl*D}!6RV7juYqa*d!kO#lXO@+SA1`#Nu>vg2bB!UB>p7D^4;(md7`A z8?UoeZMfTIoW3Disq`67nRn5-IS2DPJKejD%WmJ~mSCI8l5FI3h(|Ltwab~A#_k)v3g%fFGp=TNJ=2)+hVIN_q4w2DeUBzQnA70gWSVecIvc~+ YM~-u+nVXa`FfcH9y85}Sb4q9e02|zdS^xk5 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5c8ce42a7588ce13303070ea892765582c05b951 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|7G?$p2BAoW(+ms@iUB?$t_%ze4D%l1LGKf8 zyk}rw;4TUB3ua*S2*@jH-*@8tAFu4k{0s~XPM$7~Are!Q6BHN?G!+Uhq$XHIbx*K( zr|Kb-#(YTTA%j5sRRJBV)i-YF+`LhmdKI;Vst07ij69smFU literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fad362a3e6a5b51b12c94e97374f7e4bb1e1be2c GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-7G?$phNU`BwlFX-=mz+NxH2#>FwA>MBr<7B z$z)();42C83ua(cQ+MzPSg_;7`8%J#99t3ig@J*g#nZ(x#Nu>vg2bB!Q-*ey=PWWp zh5m&eXR137cWwW^A^OnIXEJ5pkM8X~oY&dq-Ys0_eS=$qZ7NH$k<%d`22Y#UoKA=G zXEHebk==B}dWX-o-PZc28W&Vqcf7IwohPZtImhkc7MbnE?3phf`SVyz=0C^MZru6E l=gN-FjOTiqjaT!^F)*m@b)6~t`d}8wYo4xtF6*2UngCeBY6AcO literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..35b36203fa20ad34b5b48264723aa966b33786e9 GIT binary patch literal 1310 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoBuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFe_$;M3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTcwn`Gu2HtFf>sx zx70H)KM@pFf`UTFxEFT)-^P;GO)BVG*y5CB|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9ucqbpIn-onpfiKVyjegWv9>zP+vl9-pA3e%g3&})oWua$FA zYGO%#QAmD%4lMQpGV)9Ei!<^I6r7zEG{Q6UQu51-H9;W@4mK;7)S}F?)D*X({9FZa z&{$<+vEJFp$jH&i$;80T(iG%$CqpAwH#ZXt0~a?Vb5~1OC8*vMEZ&CdHN~k{-%i0s z9~7@h@eC6Ra&ZGO!ATO7Jna+^={_|t#a5|E$=)t9*6J4n1LI^*7srr_TW_v~%`l6+{QK3Ic**cs1JZtJgoe4`@Rl+9aJTdf`#mjv@>9OF` ztut674X*#cW?m}({oEYMw1qWaqwf@_pZh-d{k-aRv6oGvRg_POJ^b;TbJ1D0?c46A z9sXRfP@X+ZI4m@*WlvLu%pw;5h=UVVivDeJt*khzUUadkMrQ%%^Baz(7M!OF+FYkd z9h-01m~_Q+_p}F&bF!M`R<03@W$gNJA}eVr$MUQu$C`zVhds9bxGUkew1Zb=wb~AM zTfK{I+-pwHus6Hd&XhS(drJBO{hz##KP{O3@aPnuJ#8jS9v=zVx$KLafSroOy7Jb2 zsp=PbcR$>BH|LWB=bA^dmo-c@PkfJdZ@nkg{-HfQ>`j2LK=W;d&K_MUCpNhdVU@&l zOGN*5e!W(A;;WHcK%ezhmbDd)(Pf_N6PMeZa`CIY{8h;)RanEmx%SE;j@2)Y7^Xet zIC*HQ%Bf?eJKFE^vOP(C<)Gv?Q8{-d=j-YO!Rke_nll1_PX7CUvAoVcRtbjJt|6yA SzI_%2l~|sxelF{r5}E)fYu0}N literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..443c73e444b195ca8aaf90f77707a87405bd379a GIT binary patch literal 1727 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?FHY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRu#Dg zxv3?I3Kh9IdBs*0wn|`gt@4VkK*IV;3ScEA*|tg$M@9GsC^+XAr7D=}nd&AR7@8=U zTk08_8k$%b>L?f)7#iyv80#Av>lzwa8CY5wnkqnnlAVH0QA(Oskc%7CuA-DQTcwPW zk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7Wta&rsl~}fnFS@8 z`FRQ;6BCp2OG|8(l%U2|VL96y)LtVuF(-D0$i`AkuwmUW%AQ z^ZOjD{l7})7r)y+wM&<7*-tOeT z_q2nxM)@O-7?$e}k`+v5P5b-=3;5SC`93g~U_RI2Rv>(4>*|J*4{T==l9xCAOJLq{ zzFLgYzJhmK^Taa24NblN>CEhn&;PvDnZY?p^O@=ihT{jhKTJ@*W*o<4)~u~Fy{U4+ z;>o{fX{3qFVD%FP*sm0t#xQ4DdVMy% z_SIU7aqofL4b9gteORRNYGR-zZ(HH5w-3K7AK*1`aF(?fF0l()c7XXp|2Zp37T*tx z{TH;q+VwmB`Z05(2)^pLH-gXCORCw%@?JV%eL-3!^5K!}&{X*w{Kq77YQ(}fnCPuv zta)rws7BFy?Qa+2KFlco$s)04^T)~uE7zzzFp}WgSNwlN$N{wp9DEI77uZFbzJKYL z;VqR-S$veQxhdiub6nlK#S?C7-Jfx;$k;tKL;b&g@LG%A2i{e@KO!2lJy=7_!(Hcz zl>WjaMFuP^2b?aji8UyfaXs5t5S3b>Yky308t=NM?FoF!Av2$Ee>3Mo$Kv-(Ha{=A z8G7T##s|@7glB22Z8p3V&Q|3(`L%yhmDkJST@7K&xiboOHI(h<^kAJS$XB2J-`21+;`&l8cm-4n|D|* zH}dNB)KS@6H}B_1mA12Ib6VyE{b88COJXXUYE530>&K})|6V;7J#)1oH$lNU%l_}8 zhNt}r-9mOrBGGGG&ig9=blDcj{wbr@d*$Pjs6LOdrmu69Vr2zb-bndfFV^y0@Bd`g z*Y5qMK_Lg$v`6lpc=giBS|9nP&*#tl${(JaZG%Q-e|yQz{EjrrIztFe_$;M3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTcwn`Gu2HtFf>sx zx70H)KM@pFf`UTFxEFT)-^P;GO)BVG*y5CB|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9IbD3=a&{Grv{~_DTCZpVC7ttnpl!w6q28x0}I7~jQo=P;*9(P z1!rdkjquF8l>G8yO|WubUn|eN;*!L?-46f0LFa}x_oXJZ35OH)Hb zS4T@jOLIqOV{>O`S3@^5V{@2Zm;B_?+|;}hnBEkGUK5;pK`8+g8dff;MVV!(DQ-pi zxe8z(TV>*Qiy=<)pn6kqyTu5nUVS?S8+}l`BE>UID9FVP!~`cvQ1Y}>K&1QBycAod zA|-pfImchkWnf@@;_2cTQgQ3eRd0`wK$+toXD;j&n3cq}GQq=W+XNxOC=NTbCh6!@ zmmPv4g$q}o@Lhc%Hd9T zJ~(`)_RP<@)$jh#;dE1)cp!A!gHne>4gA5EJKvo=RBYoYRri?VzCpYGkH`NO>{?~? z>u;O;@|PKhlb@_?Hr(T`=@rnIzN1q%=aInVA1_1$+Tui#W#(>h|MT>Y@yi;2M>Q_P zrjW0ayc`Qp{B+!D^*{SEd$psw-R1JGTHDN3hwkq%k8s#loU=GC`~*wfLx%ewrOF?* z+}OIiqTTjS5ATf9zU?ND*h-Xp*d?xNm~UtjySsnI`KUYnFSVrvZm%)Qnv*OY+HSRB zx^;hT-?)CMOWOq2hi0kjuQ+x$E%dWz^^~a}CdD6Ebv|bQ6|eQdo^7S~yuP%GrEI?M zC+U@R{O$$sx7WREyZ-O`7Ixd~P?7hto3CV#800HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRu#Dg zxv3?I3Kh9IdBs*0wn|`gt@4VkK*IV;3ScEA*|tg$M@9GsC^+XAr7D=}nd&AR7@8=U zTk08_8k$%b>L?f)7#iyv80#Av>lzwa8CY5wnkqnnlAVH0QA(Oskc%7CuA-DQTcwPW zk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7Wta&rsl~}fnFS@8 z`FRQ;6BCp2OG|8(l%U2|nxvQgrxrvdbvxSqTvk6SEOMY@`Zfaf$Om7N8uMVL96y)LtVuF(-D0$i`AkuwmUW%CXkZS{dRWhl#59&+XS}c z`@1@Qec-*i^{O-f+K_}05jT--`O_k&-7uONqB6tTB&~W{s^wq)Kl(CykME?uTXLx8 z!{g8Qs^881Y=63ZUvWu=joebbXxpWI(E$z+cs8o}wRzsHzi0Cjq&gV)JK9xnavfw3 z$o$s)_|dU2{R7Lq+?zQQCjGFLf4VQYLs+C?_MUYc?l9MdRIzAV%YM0Rvzx)M*-XS- zz@Io%lx-Tedivz1J}w6*3G%hy*Rg2sVgUmXFJ1NCK1u~jZfF? zIiy(W?BB5dl+5Dtq8VG*q7MiMaFrEz+)ON&5b?77*7~#|$(HeKt&RWkd?q0a#$XB6 zBR67s*EL*E5SK_Z6nbW`%F;3=+S7KyZlUQvD)gd$>8j7*sC7*+c780eVe)4upF^e( z^fZ_=6IL8NCBA9R55IW5l8HG>f|Qx;UQMy|w+}A1=T7VO<^u}F!e`{K= z+~qBOfu|XY9W*?c(ku51YwHJ1$PfA%cUJb#ak_mcf7+ZoIkcO@BKJAEzoRCfyZ^F^;F)}6j4dsFe3iaqNJ z&cvC|_F4V=>=3HJGUsB+=Fsj1*O%S-{KA-dtNOn~R|A*qIjkENr;;hV=SxEbPx^=V zmmBX~S$#O8&y_KeXQgNi{}#(|EAhPzoF^8{=bjZQAmH>r@D{uOQ@{0H+zAf-p)qG{ zoL{QXsri?D^7gwOM!b z-hd-p6PVYF8!huU{E(Nd8Nzj2qxSHplXFf#+P%`o^F(rvc=h$>1rr-xeOxx5ytGX9 zx;*2*oO9eeE=Hbzt@>u+jjU7U%fuIc;rJi-;QXSb>o;GNEj!9TBlDTpqLggU`Nvpu z<;@*U^&Diynk~18nAJN~-BeXXKxk?pstG zlkqL!W&MmBSMrnGX6HU{mp%CZ3Og$cD+}wD6@P^j7*3pj_UTl#RwAex^>p=fS?83{ F1OV(@6C(fs literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bdabaf30285f9a7468f9fb7f6c14e78359a42f1a GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoyF6VSLp(a)PBruhOB89F z@1x>kgPw#zRbN{JCuEoV8t0y1GeZXeG&BJ`Zar=Sd2dOT9 zypGB7EcM#{Q#V0)2bT@YvxdwB!5=&}OxLb%K6!_&)b(zlxOY%#OzoPy)yAFyO}iHS z3pp>Y^4D?ot7TTxPDp+1*tJwobrZwaCBOXk2Cx5N|6tj!g=T#FkC`w37vTT3_^)#u z!#uYm@2@On6x_&H!}{zt(<1d*y%NwTKlL6x2T8;!@+IvPNuPu!HHE(jIZYa57`u2fbfxXf<;m_jDGF#-{2b`YvS6J@VDhUqT>36>_{-#y;`dsN> zh93+z%w`S#f*WTa;nn!Zuk?u1fOQYsG;8THRnGoG6^43-t*7>wJZ(E9#K6G7;OXk; Jvd$@?2>{-k$P)kn literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8c81f409d326592bf944d13e7fea01ca58ef479a GIT binary patch literal 869 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_-2;3=Tp1V`K8^y4L*USc zGFt`)hMbZhzhDMNCT12^Hg+CfegP3taS0hYMI~hwH4QBTV>3%DYa2&r?|{&-@TmBN zl+?7$yn@1_vdY@J=9bpBt_c&TO`p49$eDv6flNYYvxOwZ& z-TM!oK6~-(AeR>f-00GcYhFdb&77p=^J^c-w5XV?{5rMgZHoHywDNZ@lUDuU-u0Y6c>a@18$TrU zwwBd5#ouY0BYNw0l7o@ayVrru54|6_nZD)Ub2u-4852_D7i3y(YMnC!1`GnvV z63w>L+a`xAD7}#Xk#v0F^5+ScHr)SuVCCT#2c>4}Dc4PXu6EemQfQ9Eg?BoK7x_Mu zxU@NOUCZSgPa=+=%xpSTSpMwu+9=0j_G$M|Vl0cF z$?HxRVQ0`>{&nLjhRbDQ<&5j~tgmq#*d+Vev&iUn&hdMbOg1K#G`byWvg+^E)@m|f zX%RTm!`ahxM&{RwH7vdo(GG_1Y^SOIvtS6^y?@P$kfZetkKBWFnfLtX+?k)x$Z+!{Uv#j2I@O}7`9?!v&B5e5hiVP~ ztb0`@u~NzStojG8-G!2mBijE~bZXC-^l8?rZSCJgm(*}QwbW{>o_gv9$;fYvI+eWlQpQvp^SosL?M2*XU!xDQugTilv2aeep`p!slT$199p|3& zRy0j|O8?f)TJsHm1|FUDLwS$ePq%V5Nt**LQ(iM$%=z?8{K$vm363{Ui(1&QH}BpN z<*I!ubmFIQ&HOc6{=4mb6ZB8#Df8#toAv8wzy75(?*ZGqq$r;ItM4#=`7eK@fH(W& mhT@;5!rNA#icW}opdVk9erb(qzY_xk1B0ilpUXO@geCy0@8To? literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b6cc48c053351c5ec94b98bcfd108b13af604cff GIT binary patch literal 906 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_V*-3aTp1V`80I}3MYITk z#zZ3y+qx!9oHl*t+y#r5u3EQo^VV(KckbG|Z~x&VM~|I2 zdExqvo40P?xqJV?!>7+)ynOra^SAFme*XIN_uuq{R5=C)#w<@4#}JR>Z>NR_A94_B z4L=}sv}>=nR>FH$?r--tCcAD-di?vpv7JG4;>lw!@wWNj-`LK)TkPHP<9L36@g~9A z$I9EpbIxv>@Xq>y^z*;#WdN)k}qegQXS2;`nthv`d9B!HWOt{Zu&k4V3?u*vh z=?yIcmU7a{tD4G|MlgAqNUxU^E;+m^&3ocbt@@@dJ-P~8-`P%6-DkkiT~;62{Ybw4 Zpm^W9xOb+qd4ix!<>~6@vd$@?2>|Cjq#*zR literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..cd63c1d03bca5b4993cf2c2e3e18a233c3b6aa4b GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuJoc6z!vhIn+ooxGR#kb!{P zc|lbJ*3=al677>%Z#1%LGN*`3G&FG?t31)geOp|{S&3y*eDeMNzjN(XgDSWmu)TS! z75nGoKJf<^rvKM$I5vOzr{*W0l^B?F8ifnCZG1grb(+7zZKVXxn3oo-+BPy|KX~Y3 zHm~6Gr&lrE4N^O-C%T4YUu9fBBUNz2rs=B>nRn>Ua-D2w(rkEaMT*ArB5tHl6!>JezSriPWON%h z9%M^Cz=G_v_RC?NAN%-K6j&((n_TSGN{> UfY6dV3=9kmp00i_>zopr0EsrR`Tzg` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4cca7726170335abb9f8e413eb4b6245e2da8c10 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8N@DA_^ab;j&V3_xiD(H%I z_cM?kB|(0{42-;d0`e+4y2cg>8KoV)6XxtcaOT3b>r)puvNA9*Bzn3yhG!CByd_ZC4WgT(?)Ju!crdU%>#~L!-=i2+ zMrH%f8G%A;bP^OA*9AARdL>J=>M3@3H;K6&{CiNB$2EkN;mQp*8-XAjeUSe=UHx3v IIVCg!0QH4pLI3~& literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..690cf5f924fc3dbb2146954f62f93b43fdc1bb67 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4rT@hhJ-tuTNxM_LIQk3Tp1V`80I~sE_(G; zse*xlLAoT!FPMRmSwLP#-`K*^!K0#~qj$pec}ox6ef073mmiiHIujTe7}j{YIEHu} ze>?Rw*C7J|*Y{hp9xIy}W?lXL|Nl#;31$=1lDO}F(PLvPN_Zw9l+bHcqQIH*ilN{f z<4h|CvGWJTn5LbQJ+dV{kU8m=btPNF;!~H_DW6=HQ1n?LpY{3C{qyE`mP|Wh{ARaX zuBVN2>)N>2tqXsdNqH~7SNZf@_r0YmlN)acnU~sY3fMEPSzKo%5P6FE{ rkJJ6j`e(bP0l+XkKa`l^( literal 0 HcmV?d00001 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",