diff options
author | Ali Kianian <[email protected]> | 2024-08-02 18:19:21 +0300 |
---|---|---|
committer | Ali Kianian <[email protected]> | 2024-08-23 14:47:53 +0000 |
commit | ee78ccc7dc8fe4b8c7577f21d3232347f9c35b16 (patch) | |
tree | 917199be5de1f06b09823ac663bd7dd599f87f10 | |
parent | 133554186e4888f623588131bc77bea9cc640a3e (diff) |
QmlDesigner: Add a camera view to 3d editor view
Task-number: QDS-13275
Fixes: QDS-13352
Change-Id: I9b583a273a0aa7fc0d2c72b274fca243cc65546e
Reviewed-by: Miikka Heikkinen <[email protected]>
15 files changed, 503 insertions, 17 deletions
diff --git a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h index d5647a0740b..a05d9681f64 100644 --- a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h +++ b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h @@ -44,6 +44,7 @@ enum class View3DActionType { ShowSelectionBox, ShowIconGizmo, ShowCameraFrustum, + CameraViewMode, ShowParticleEmitter, Edit3DParticleModeToggle, ParticlesPlay, diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index a2e9fc943a7..7c2f81c10ab 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -652,6 +652,7 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/edit3d SOURCES + cameraviewwidgetaction.cpp cameraviewwidgetaction.h edit3dview.cpp edit3dview.h edit3dviewconfig.h edit3dwidget.cpp edit3dwidget.h diff --git a/src/plugins/qmldesigner/components/edit3d/cameraviewwidgetaction.cpp b/src/plugins/qmldesigner/components/edit3d/cameraviewwidgetaction.cpp new file mode 100644 index 00000000000..8f9e025dc0a --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/cameraviewwidgetaction.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 +#include "cameraviewwidgetaction.h" + +#include <utils/algorithm.h> +#include <utils/qtcassert.h> + +#include <QComboBox> + +namespace QmlDesigner { + +struct CameraActionsModel::DataItem +{ + QString name; + QString tooltip; + QString mode; +}; + +const QList<CameraActionsModel::DataItem> CameraActionsModel::m_data{ + {tr("Hide Camera View"), tr("Never show the camera view."), "CameraOff"}, + {tr("Show Selected Camera View"), + tr("Show the selected camera in the camera view."), + "ShowSelectedCamera"}, + {tr("Always Show Camera View"), + tr("Show the last selected camera in the camera view."), + "AlwaysShowCamera"}, +}; + +CameraViewWidgetAction::CameraViewWidgetAction(QObject *parent) + : QWidgetAction(parent) +{ + QComboBox *defaultComboBox = new QComboBox(); + CameraActionsModel *comboBoxModel = new CameraActionsModel(defaultComboBox); + + defaultComboBox->setModel(comboBoxModel); + setDefaultWidget(defaultComboBox); + connect(defaultComboBox, &QComboBox::currentIndexChanged, this, [this] { + emit currentModeChanged(currentMode()); + }); +} + +QString CameraViewWidgetAction::currentMode() const +{ + QComboBox *defaultComboBox = qobject_cast<QComboBox *>(defaultWidget()); + QTC_ASSERT(defaultComboBox, return "CameraOff"); + + return defaultComboBox->currentData(CameraActionsModel::ModeRole).toString(); +} + +void CameraViewWidgetAction::setMode(const QString &mode) +{ + QComboBox *defaultComboBox = qobject_cast<QComboBox *>(defaultWidget()); + QTC_ASSERT(defaultComboBox, return); + defaultComboBox->setCurrentIndex(CameraActionsModel::modeIndex(mode)); +} + +QWidget *CameraViewWidgetAction::createWidget(QWidget *parent) +{ + QComboBox *defaultComboBox = qobject_cast<QComboBox *>(defaultWidget()); + QTC_ASSERT(defaultComboBox, return nullptr); + + QComboBox *newComboBox = new QComboBox(parent); + newComboBox->setModel(defaultComboBox->model()); + connect(defaultComboBox, &QComboBox::currentIndexChanged, newComboBox, &QComboBox::setCurrentIndex); + connect(newComboBox, &QComboBox::currentIndexChanged, defaultComboBox, &QComboBox::setCurrentIndex); + newComboBox->setCurrentIndex(defaultComboBox->currentIndex()); + return newComboBox; +} + +CameraActionsModel::CameraActionsModel(QObject *parent) + : QAbstractListModel(parent) +{} + +CameraActionsModel::~CameraActionsModel() = default; + +int CameraActionsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const +{ + return m_data.size(); +} + +QVariant CameraActionsModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return {}; + + const DataItem &data = m_data.at(index.row()); + switch (role) { + case Qt::DisplayRole: + return data.name; + case Qt::ToolTipRole: + return data.tooltip; + case ExtendedDataRoles::ModeRole: + return data.mode; + default: + return {}; + } +} + +int CameraActionsModel::modeIndex(const QString &mode) +{ + int idx = Utils::indexOf(m_data, Utils::equal(&DataItem::mode, mode)); + return std::max(0, idx); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/cameraviewwidgetaction.h b/src/plugins/qmldesigner/components/edit3d/cameraviewwidgetaction.h new file mode 100644 index 00000000000..e368a41b032 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/cameraviewwidgetaction.h @@ -0,0 +1,46 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 +#pragma once + +#include <QAbstractListModel> +#include <QCoreApplication> +#include <QWidgetAction> + +namespace QmlDesigner { + +class CameraViewWidgetAction : public QWidgetAction +{ + Q_OBJECT + +public: + explicit CameraViewWidgetAction(QObject *parent = nullptr); + QString currentMode() const; + void setMode(const QString &mode); + +protected: + QWidget *createWidget(QWidget *parent) override; + +signals: + void currentModeChanged(QString); +}; + +class CameraActionsModel : public QAbstractListModel +{ + Q_DECLARE_TR_FUNCTIONS(CameraActionsModel) + +public: + enum ExtendedDataRoles { ModeRole = Qt::UserRole + 1 }; + + explicit CameraActionsModel(QObject *parent); + virtual ~CameraActionsModel(); + + int rowCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + static int modeIndex(const QString &mode); + +private: + struct DataItem; + static const QList<DataItem> m_data; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp index 83299a485d5..272b5994193 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -3,6 +3,7 @@ #include "edit3dactions.h" +#include "cameraviewwidgetaction.h" #include "edit3dview.h" #include "indicatoractionwidget.h" #include "qmldesignerconstants.h" @@ -11,6 +12,7 @@ #include <utils3d.h> #include <utils/algorithm.h> +#include <utils/qtcassert.h> namespace QmlDesigner { @@ -198,4 +200,27 @@ bool Edit3DIndicatorButtonAction::isEnabled(const SelectionContext &) const return m_buttonAction->isEnabled(); } +Edit3DCameraViewAction::Edit3DCameraViewAction(const QByteArray &menuId, + View3DActionType type, + Edit3DView *view) + : Edit3DAction(menuId, type, view, new Edit3DWidgetActionTemplate(new CameraViewWidgetAction(view))) +{ + CameraViewWidgetAction *widgetAction = qobject_cast<CameraViewWidgetAction *>(action()); + Q_ASSERT(widgetAction); + + QObject::connect(widgetAction, + &CameraViewWidgetAction::currentModeChanged, + view, + [this, edit3dview = std::move(view)](const QString &newState) { + edit3dview->emitView3DAction(actionType(), newState); + }); +} + +void Edit3DCameraViewAction::setMode(const QString &mode) +{ + CameraViewWidgetAction *widgetAction = qobject_cast<CameraViewWidgetAction *>(action()); + QTC_ASSERT(widgetAction, return); + widgetAction->setMode(mode); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h index 03aeb22902a..63c9d3b41e8 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h @@ -150,4 +150,12 @@ private: Edit3DView *m_view = nullptr; }; +class Edit3DCameraViewAction : public Edit3DAction +{ +public: + Edit3DCameraViewAction(const QByteArray &menuId, View3DActionType type, Edit3DView *view); + + void setMode(const QString &mode); +}; + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index b971d828c50..9d9e9848ff0 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -45,6 +45,11 @@ #include <utils/utilsicons.h> #include <QToolButton> +static const QByteArray operator""_actionId(const char *text, size_t size) +{ + return QString("QmlDesigner.Edit3D.%1").arg(QLatin1String(text, size)).toLatin1(); +} + namespace QmlDesigner { inline static QIcon contextIcon(const DesignerIcons::IconId &iconId) @@ -127,23 +132,24 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) m_activeSplit = 0; } - const QString sceneKey = QStringLiteral("sceneInstanceId"); - const QString selectKey = QStringLiteral("selectionMode"); - const QString transformKey = QStringLiteral("transformMode"); - const QString perspectiveKey = QStringLiteral("usePerspective"); - const QString orientationKey = QStringLiteral("globalOrientation"); - const QString editLightKey = QStringLiteral("showEditLight"); - const QString gridKey = QStringLiteral("showGrid"); - const QString showLookAtKey = QStringLiteral("showLookAt"); - const QString selectionBoxKey = QStringLiteral("showSelectionBox"); - const QString iconGizmoKey = QStringLiteral("showIconGizmo"); - const QString cameraFrustumKey = QStringLiteral("showCameraFrustum"); - const QString particleEmitterKey = QStringLiteral("showParticleEmitter"); - const QString particlesPlayKey = QStringLiteral("particlePlay"); - const QString syncEnvBgKey = QStringLiteral("syncEnvBackground"); - const QString splitViewKey = QStringLiteral("splitView"); - const QString matOverrideKey = QStringLiteral("matOverride"); - const QString showWireframeKey = QStringLiteral("showWireframe"); + const QString sceneKey = QStringLiteral("sceneInstanceId"); + const QString selectKey = QStringLiteral("selectionMode"); + const QString transformKey = QStringLiteral("transformMode"); + const QString perspectiveKey = QStringLiteral("usePerspective"); + const QString orientationKey = QStringLiteral("globalOrientation"); + const QString editLightKey = QStringLiteral("showEditLight"); + const QString gridKey = QStringLiteral("showGrid"); + const QString showLookAtKey = QStringLiteral("showLookAt"); + const QString selectionBoxKey = QStringLiteral("showSelectionBox"); + const QString iconGizmoKey = QStringLiteral("showIconGizmo"); + const QString cameraFrustumKey = QStringLiteral("showCameraFrustum"); + const QString cameraViewModeKey = QStringLiteral("cameraViewMode"); + const QString particleEmitterKey = QStringLiteral("showParticleEmitter"); + const QString particlesPlayKey = QStringLiteral("particlePlay"); + const QString syncEnvBgKey = QStringLiteral("syncEnvBackground"); + const QString splitViewKey = QStringLiteral("splitView"); + const QString matOverrideKey = QStringLiteral("matOverride"); + const QString showWireframeKey = QStringLiteral("showWireframe"); if (sceneState.contains(sceneKey)) { qint32 newActiveScene = sceneState[sceneKey].value<qint32>(); @@ -209,6 +215,11 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) else m_showCameraFrustumAction->action()->setChecked(false); + if (sceneState.contains(cameraViewModeKey)) + m_cameraViewAction->setMode(sceneState[cameraViewModeKey].toString()); + else + m_cameraViewAction->setMode(""); + if (sceneState.contains(particleEmitterKey)) m_showParticleEmitterAction->action()->setChecked(sceneState[particleEmitterKey].toBool()); else @@ -1100,6 +1111,10 @@ void Edit3DView::createEdit3DActions() "Toggle between always showing the camera frustum visualization and only showing it " "when the camera is selected.")); + m_cameraViewAction = std::make_unique<Edit3DCameraViewAction>("CamerView"_actionId, + View3DActionType::CameraViewMode, + this); + m_showParticleEmitterAction = std::make_unique<Edit3DAction>( QmlDesigner::Constants::EDIT3D_EDIT_SHOW_PARTICLE_EMITTER, View3DActionType::ShowParticleEmitter, @@ -1368,6 +1383,7 @@ void Edit3DView::createEdit3DActions() m_visibilityToggleActions << m_showSelectionBoxAction.get(); m_visibilityToggleActions << m_showIconGizmoAction.get(); m_visibilityToggleActions << m_showCameraFrustumAction.get(); + m_visibilityToggleActions << m_cameraViewAction.get(); m_visibilityToggleActions << m_showParticleEmitterAction.get(); createSyncEnvBackgroundAction(); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index f0ebc69dddb..8560fd6b45a 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -177,6 +177,7 @@ private: std::unique_ptr<Edit3DAction> m_showSelectionBoxAction; std::unique_ptr<Edit3DAction> m_showIconGizmoAction; std::unique_ptr<Edit3DAction> m_showCameraFrustumAction; + std::unique_ptr<Edit3DCameraViewAction> m_cameraViewAction; std::unique_ptr<Edit3DAction> m_showParticleEmitterAction; std::unique_ptr<Edit3DAction> m_particleViewModeAction; std::unique_ptr<Edit3DAction> m_particlesPlayAction; diff --git a/src/tools/qml2puppet/editor3d_qt6.qrc b/src/tools/qml2puppet/editor3d_qt6.qrc index 85df241f162..e1de7a0903d 100644 --- a/src/tools/qml2puppet/editor3d_qt6.qrc +++ b/src/tools/qml2puppet/editor3d_qt6.qrc @@ -26,6 +26,7 @@ <file>mockfiles/qt6/AutoScaleHelper.qml</file> <file>mockfiles/qt6/CameraFrustum.qml</file> <file>mockfiles/qt6/CameraGizmo.qml</file> + <file>mockfiles/qt6/CameraView.qml</file> <file>mockfiles/qt6/DirectionalDraggable.qml</file> <file>mockfiles/qt6/EditCameraController.qml</file> <file>mockfiles/qt6/EditView3D.qml</file> diff --git a/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml b/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml new file mode 100644 index 00000000000..3bc67468099 --- /dev/null +++ b/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml @@ -0,0 +1,164 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +import QtQuick +import QtQuick3D + +Item { + id: cameraView + + required property bool showCameraView + required property bool alwaysOn + property bool snapLeft: true + property Node targetNode + property size preferredSize + property size viewPortSize + property var activeScene + property var activeSceneEnvironment + property var preferredCamera + + width: loader.width + height: loader.height + anchors.bottom: parent.bottom + anchors.margins: 10 + visible: loader.active + + onTargetNodeChanged: loader.updateCamera() + onAlwaysOnChanged: loader.updateCamera() + onPreferredCameraChanged: loader.updateCamera() + onActiveSceneChanged: forceReload() + Component.onCompleted: loader.updateCamera() + + function forceReload() { + loader.forceDeactive = true + loader.oldCamera = null + loader.updateCamera() + loader.forceDeactive = false + } + + Loader { + id: loader + + property Camera camera + property Camera oldCamera + property bool forceDeactive: false + + active: !forceDeactive && (cameraView.alwaysOn || cameraView.showCameraView) && loader.camera + + function updateCamera() { + loader.camera = activeCamera() + } + + function activeCamera() { + if (cameraView.alwaysOn) { + if (_generalHelper.isCamera(cameraView.targetNode)) + return cameraView.targetNode + else if (loader.oldCamera) + return loader.oldCamera + else + return cameraView.preferredCamera + } else if (_generalHelper.isCamera(cameraView.targetNode)) { + return cameraView.targetNode + } + return null + } + + onCameraChanged: { + if (loader.camera) + loader.oldCamera = loader.camera + } + + sourceComponent: Rectangle { + id: cameraRect + + implicitWidth: view3D.dispSize.width + 2 + implicitHeight: view3D.dispSize.height + 2 + border.width: 1 + border.color: "lightslategray" + color: "black" + + View3D { + id: view3D + + readonly property bool isOrthographicCamera: _generalHelper.isOrthographicCamera(view3D.camera) + property size dispSize: calculateSize(cameraView.viewPortSize, cameraView.preferredSize) + readonly property real magnificationFactor: cameraView.viewPortSize.width === 0 + ? 1.0 + : (view3D.dispSize.width / cameraView.viewPortSize.width) + + transformOrigin: Item.Center + anchors.centerIn: parent + + camera: loader.camera + importScene: cameraView.activeScene + environment: cameraView.activeSceneEnvironment ?? defaultSceneEnvironment + + function calculateSize(viewPortSize: size, preferredSize : size){ + if (_generalHelper.fuzzyCompare(viewPortSize.width, 0) + || _generalHelper.fuzzyCompare(viewPortSize.height, 0)) + return Qt.size(0, 0) + + let aspectRatio = viewPortSize.height / viewPortSize.width + var calculatedHeight = preferredSize.width * aspectRatio + if (calculatedHeight <= preferredSize.height) + return Qt.size(preferredSize.width, calculatedHeight) + + var calculatedWidth = preferredSize.height / aspectRatio; + return Qt.size(calculatedWidth, preferredSize.height); + } + + states: [ + State { + name: "orthoCamera" + when: view3D.isOrthographicCamera + PropertyChanges { + target: view3D + + width: cameraView.viewPortSize.width + height: cameraView.viewPortSize.height + scale: view3D.magnificationFactor + } + }, + State { + name: "nonOrthoCamera" + when: !view3D.isOrthographicCamera + PropertyChanges { + target: view3D + + width: view3D.dispSize.width + height: view3D.dispSize.height + scale: 1.0 + } + } + ] + } + } + } + + SceneEnvironment { + id: defaultSceneEnvironment + + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } + + states: [ + State { + name: "default" + when: cameraView.snapLeft + AnchorChanges { + target: cameraView + anchors.left: parent.left + anchors.right: undefined + } + }, + State { + name: "snapRight" + when: !cameraView.snapLeft + AnchorChanges { + target: cameraView + anchors.left: undefined + anchors.right: parent.right + } + } + ] +} diff --git a/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml b/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml index 751d21c0e8a..e159b532c34 100644 --- a/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml +++ b/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml @@ -40,6 +40,7 @@ Item { property bool splitView: false property bool flyMode: false property bool showCameraSpeed: false + property string cameraViewMode enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -72,6 +73,7 @@ Item { onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox); onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo); onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum); + onCameraViewModeChanged: _generalHelper.storeToolState(sceneId, "cameraViewMode", cameraViewMode) onShowParticleEmitterChanged: _generalHelper.storeToolState(sceneId, "showParticleEmitter", showParticleEmitter); onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode); @@ -334,6 +336,11 @@ Item { else if (resetToDefault) showCameraFrustum = false; + if ("cameraViewMode" in toolStates) + cameraViewMode = toolStates.cameraViewMode + else if (resetToDefault) + cameraViewMode = "CameraOff" + if ("showParticleEmitter" in toolStates) showParticleEmitter = toolStates.showParticleEmitter; else if (resetToDefault) @@ -405,6 +412,7 @@ Item { _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox) _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo) _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum) + _generalHelper.storeToolState(sceneId, "cameraViewMode", cameraViewMode) _generalHelper.storeToolState(sceneId, "showParticleEmitter", showParticleEmitter) _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective) _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation) @@ -1083,6 +1091,35 @@ Item { anchors.centerIn: parent } } + + CameraView { + id: cameraView + + showCameraView: viewRoot.cameraViewMode === "ShowSelectedCamera" + alwaysOn: viewRoot.cameraViewMode === "AlwaysShowCamera" + targetNode: viewRoot.selectedNode + activeScene: viewRoot.activeScene + activeSceneEnvironment: viewRoot.activeEditView.sceneEnv + preferredCamera: _generalHelper.activeScenePreferredCamera + preferredSize: Qt.size(viewRoot.width * 0.3, viewRoot.height * 0.3) + viewPortSize: Qt.size(viewRoot.viewPortRect.width, viewRoot.viewPortRect.height) + + function updateSnapping() { + if (!viewRoot.splitView) + cameraView.snapLeft = true + else if (viewRoot.activeSplit === 2) + cameraView.snapLeft = false + else if (viewRoot.activeSplit === 3) + cameraView.snapLeft = true + } + + Connections { + target: viewRoot + + onSplitViewChanged: cameraView.updateSnapping() + onActiveSplitChanged: cameraView.updateSnapping() + } + } } Text { diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp index 3baf91c1464..e58192e54f8 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp @@ -682,6 +682,16 @@ bool GeneralHelper::isPickable(QQuick3DNode *node) const return true; } +bool GeneralHelper::isCamera(QQuick3DNode *node) const +{ + return node && qobject_cast<QQuick3DCamera *>(node); +} + +bool GeneralHelper::isOrthographicCamera(QQuick3DNode *node) const +{ + return node && qobject_cast<QQuick3DOrthographicCamera *>(node); +} + // Emitter gizmo model creation is done in C++ as creating dynamic properties and // assigning materials to dynamically created models is lot simpler in C++ QQuick3DNode *GeneralHelper::createParticleEmitterGizmoModel(QQuick3DNode *emitter, @@ -1546,6 +1556,28 @@ void GeneralHelper::requestTimerEvent(const QString &timerId, qint64 delay) } } +QQuick3DCamera *GeneralHelper::activeScenePreferredCamera() const +{ + return m_activeScenePreferredCamera.get(); +} + +void GeneralHelper::setActiveScenePreferredCamera(QQuick3DCamera *camera) +{ + if (m_activeScenePreferredCamera.get() != camera) { + if (m_activeScenePreferredCamera) + disconnect(m_activeScenePreferredCamera.get(), &QObject::destroyed, this, 0); + + m_activeScenePreferredCamera = camera; + + connect( + m_activeScenePreferredCamera.get(), + &QObject::destroyed, + this, + &GeneralHelper::requestActiveScenePreferredCamera); + + emit activeScenePreferredCameraChanged(); + } +} } } diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h index f1b57f4122f..4aa66bd7419 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h @@ -40,6 +40,11 @@ class GeneralHelper : public QObject Q_PROPERTY(double minGridStep READ minGridStep NOTIFY minGridStepChanged FINAL) Q_PROPERTY(double cameraSpeed READ cameraSpeed NOTIFY cameraSpeedChanged FINAL) + Q_PROPERTY( + QQuick3DCamera *activeScenePreferredCamera + READ activeScenePreferredCamera + NOTIFY activeScenePreferredCameraChanged FINAL) + public: GeneralHelper(); @@ -90,6 +95,8 @@ public: Q_INVOKABLE bool isLocked(QQuick3DNode *node) const; Q_INVOKABLE bool isHidden(QQuick3DNode *node) const; Q_INVOKABLE bool isPickable(QQuick3DNode *node) const; + Q_INVOKABLE bool isCamera(QQuick3DNode *node) const; + Q_INVOKABLE bool isOrthographicCamera(QQuick3DNode *node) const; Q_INVOKABLE QQuick3DNode *createParticleEmitterGizmoModel(QQuick3DNode *emitter, QQuick3DMaterial *material) const; @@ -168,6 +175,9 @@ public: Q_INVOKABLE void requestTimerEvent(const QString &timerId, qint64 delay); + QQuick3DCamera *activeScenePreferredCamera() const; + void setActiveScenePreferredCamera(QQuick3DCamera *camera); + signals: void overlayUpdateNeeded(); void toolStateChanged(const QString &sceneId, const QString &tool, const QVariant &toolState); @@ -180,8 +190,10 @@ signals: void sceneEnvDataChanged(); void requestCameraMove(QQuick3DCamera *camera, const QVector3D &moveVector); void requestRender(); + void requestActiveScenePreferredCamera(); void cameraSpeedChanged(); void requestedTimerEvent(const QString &timerId); + void activeScenePreferredCameraChanged(); private: void handlePendingToolStateUpdate(); @@ -229,6 +241,8 @@ private: QList<QMetaObject::Connection> m_multiSelectConnections; bool m_blockMultiSelectionNodePositioning = false; + QPointer<QQuick3DCamera> m_activeScenePreferredCamera; + bool m_snapAbsolute = true; bool m_snapPosition = false; bool m_snapRotation = false; diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index d81a0aa5644..39f29d5a9f5 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -300,6 +300,30 @@ void Qt5InformationNodeInstanceServer::resolveImportSupport() #endif } +void Qt5InformationNodeInstanceServer::updateActiveScenePreferredCamera() +{ +#ifdef QUICK3D_MODULE + auto preferredCamera = [&]() -> QQuick3DCamera * { + if (auto activeView = qobject_cast<QQuick3DViewport *>(m_active3DView)) { + if (auto camera = activeView->camera()) { + if (hasInstanceForObject(camera) && find3DSceneRoot(camera) == m_active3DScene) + return camera; + } + } + + const QList<ServerNodeInstance> allCameras = allCameraInstances(); + for (const auto &camera : allCameras) { + if (find3DSceneRoot(camera) == m_active3DScene) + return qobject_cast<QQuick3DCamera *>(camera.internalObject()); + } + return nullptr; + }; + + auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper); + helper->setActiveScenePreferredCamera(preferredCamera()); +#endif +} + void Qt5InformationNodeInstanceServer::updateMaterialPreviewData( const QVector<PropertyValueContainer> &valueChanges) { @@ -535,6 +559,11 @@ void Qt5InformationNodeInstanceServer::createEditView3D() QObject::connect(helper, &QmlDesigner::Internal::GeneralHelper::requestRender, this, [this]() { render3DEditView(1); }); + QObject::connect( + helper, + &QmlDesigner::Internal::GeneralHelper::requestActiveScenePreferredCamera, + this, + &Qt5InformationNodeInstanceServer::updateActiveScenePreferredCamera); engine()->rootContext()->setContextProperty("_generalHelper", helper); engine()->addImageProvider(QLatin1String("IconGizmoImageProvider"), new QmlDesigner::Internal::IconGizmoImageProvider); @@ -1035,6 +1064,8 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D([[maybe_unu activeSceneVar = objectToVariant(sceneRoot); } + updateActiveScenePreferredCamera(); + QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection, Q_ARG(QVariant, activeSceneVar), Q_ARG(QVariant, QVariant::fromValue(sceneId))); @@ -2549,6 +2580,9 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionType::ShowCameraFrustum: updatedToolState.insert("showCameraFrustum", command.isEnabled()); break; + case View3DActionType::CameraViewMode: + updatedToolState.insert("cameraViewMode", command.value()); + break; case View3DActionType::SyncEnvBackground: updatedToolState.insert("syncEnvBackground", command.isEnabled()); break; diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 321751cf238..60eebe488ae 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -122,6 +122,7 @@ private: void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances); void handleInputEvents(); void resolveImportSupport(); + void updateActiveScenePreferredCamera(); void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges); void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges); void updateSnapAndCameraSettings(const QVector<PropertyValueContainer> &valueChanges); |