Merge "Merge remote-tracking branch 'origin/7.0' into 8.0" into 8.0

This commit is contained in:
The Qt Project
2022-06-02 09:06:12 +00:00
77 changed files with 937 additions and 440 deletions

View File

@@ -28,6 +28,8 @@
#include <QSize>
#include <QUrl>
#include <QVector>
#include <QList>
#include <QColor>
#include <qmetatype.h>
#include "instancecontainer.h"
@@ -58,7 +60,8 @@ public:
const QString &language,
QSize captureImageMinimumSize,
QSize captureImageMaximumSize,
qint32 stateInstanceId)
qint32 stateInstanceId,
const QList<QColor> &edit3dBackgroundColor)
: instances(instanceContainer)
, reparentInstances(reparentContainer)
, ids(idVector)
@@ -74,6 +77,7 @@ public:
, captureImageMinimumSize(captureImageMinimumSize)
, captureImageMaximumSize(captureImageMaximumSize)
, stateInstanceId{stateInstanceId}
, edit3dBackgroundColor{edit3dBackgroundColor}
{}
friend QDataStream &operator<<(QDataStream &out, const CreateSceneCommand &command)
@@ -93,6 +97,7 @@ public:
out << command.stateInstanceId;
out << command.captureImageMinimumSize;
out << command.captureImageMaximumSize;
out << command.edit3dBackgroundColor;
return out;
}
@@ -114,6 +119,7 @@ public:
in >> command.stateInstanceId;
in >> command.captureImageMinimumSize;
in >> command.captureImageMaximumSize;
in >> command.edit3dBackgroundColor;
return in;
}
@@ -134,6 +140,7 @@ public:
QSize captureImageMinimumSize;
QSize captureImageMaximumSize;
qint32 stateInstanceId = 0;
QList<QColor> edit3dBackgroundColor;
};
QDebug operator<<(QDebug debug, const CreateSceneCommand &command);

View File

@@ -30,24 +30,27 @@
namespace QmlDesigner {
View3DActionCommand::View3DActionCommand(Type type, bool enable)
View3DActionCommand::View3DActionCommand(Type type, const QVariant &value)
: m_type(type)
, m_enabled(enable)
, m_position(0)
, m_value(value)
{
}
View3DActionCommand::View3DActionCommand(int pos)
: m_type(ParticlesSeek)
, m_enabled(true)
, m_position(pos)
, m_value(pos)
{
}
bool View3DActionCommand::isEnabled() const
{
return m_enabled;
return m_value.toBool();
}
QVariant View3DActionCommand::value() const
{
return m_value;
}
View3DActionCommand::Type View3DActionCommand::type() const
@@ -57,29 +60,32 @@ View3DActionCommand::Type View3DActionCommand::type() const
int View3DActionCommand::position() const
{
return m_position;
bool ok = false;
int result = m_value.toInt(&ok);
if (!ok) {
qWarning() << "View3DActionCommand: returning a position that is not int; command type = "
<< m_type;
}
return result;
}
QDataStream &operator<<(QDataStream &out, const View3DActionCommand &command)
{
out << qint32(command.isEnabled());
out << command.value();
out << qint32(command.type());
out << qint32(command.position());
return out;
}
QDataStream &operator>>(QDataStream &in, View3DActionCommand &command)
{
qint32 enabled;
QVariant value;
qint32 type;
qint32 pos;
in >> enabled;
in >> value;
in >> type;
in >> pos;
command.m_enabled = bool(enabled);
command.m_value = value;
command.m_type = View3DActionCommand::Type(type);
command.m_position = pos;
return in;
}
@@ -88,7 +94,7 @@ QDebug operator<<(QDebug debug, const View3DActionCommand &command)
{
return debug.nospace() << "View3DActionCommand(type: "
<< command.m_type << ","
<< command.m_enabled << ")";
<< command.m_value << ")\n";
}
} // namespace QmlDesigner

View File

@@ -26,6 +26,7 @@
#pragma once
#include <QMetaType>
#include <QVariant>
namespace QmlDesigner {
@@ -55,20 +56,22 @@ public:
ParticlesPlay,
ParticlesRestart,
ParticlesSeek,
SelectBackgroundColor,
ResetBackgroundColor,
};
explicit View3DActionCommand(Type type, bool enable);
explicit View3DActionCommand(Type type, const QVariant &value);
View3DActionCommand() = default;
bool isEnabled() const;
QVariant value() const;
Type type() const;
int position() const;
private:
Type m_type = Empty;
bool m_enabled = false;
int m_position = 0;
QVariant m_value;
protected:
View3DActionCommand(int pos);

View File

@@ -32,7 +32,6 @@
<file>mockfiles/qt6/FadeHandle.qml</file>
<file>mockfiles/qt6/HelperGrid.qml</file>
<file>mockfiles/qt6/IconGizmo.qml</file>
<file>mockfiles/qt6/IconRenderer3D.qml</file>
<file>mockfiles/qt6/LightGizmo.qml</file>
<file>mockfiles/qt6/LightIconGizmo.qml</file>
<file>mockfiles/qt6/LightModel.qml</file>

View File

@@ -142,6 +142,7 @@ void NodeInstanceServerInterface::registerCommands()
registerCommand<View3DActionCommand>("View3DActionCommand");
registerCommand<RequestModelNodePreviewImageCommand>("RequestModelNodePreviewImageCommand");
registerCommand<QPair<int, int>>("QPairIntInt");
registerCommand<QList<QColor>>("QColorList");
registerCommand<ChangeLanguageCommand>("ChangeLanguageCommand");
registerCommand<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
registerCommand<CapturedDataCommand>("CapturedDataCommand");

View File

@@ -45,6 +45,8 @@ Item {
property bool usePerspective: true
property bool globalOrientation: false
property alias contentItem: contentItem
property color backgroundGradientColorStart: "#222222"
property color backgroundGradientColorEnd: "#999999"
enum SelectionMode { Item, Group }
enum TransformMode { Move, Rotate, Scale }
@@ -212,6 +214,15 @@ Item {
cameraControl.alignView(selectedNodes);
}
function updateViewStates(viewStates)
{
if ("selectBackgroundColor" in viewStates) {
var color = viewStates.selectBackgroundColor
backgroundGradientColorStart = color[0];
backgroundGradientColorEnd = color[1];
}
}
// If resetToDefault is true, tool states not specifically set to anything will be reset to
// their default state.
function updateToolStates(toolStates, resetToDefault)
@@ -329,6 +340,15 @@ Item {
function handleObjectClicked(object, multi)
{
if (object instanceof View3D) {
// View3D can be the resolved pick target in case the 3D editor is showing content
// of a component that has View3D as root. In that case locking is resolved on C++ side
// and we ignore multiselection.
selectObjects([]);
selectionChanged([object]);
return;
}
var clickedObject;
// Click on locked object is treated same as click on empty space
@@ -721,8 +741,8 @@ Item {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 1.0; color: "#222222" }
GradientStop { position: 0.0; color: "#999999" }
GradientStop { position: 1.0; color: backgroundGradientColorStart }
GradientStop { position: 0.0; color: backgroundGradientColorEnd }
}
MouseArea {
@@ -740,7 +760,7 @@ Item {
handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
mouse.modifiers & Qt.ControlModifier);
if (pickResult.objectHit) {
if (pickResult.objectHit && pickResult.objectHit instanceof Node) {
if (transformMode === EditView3D.TransformMode.Move)
freeDraggerArea = moveGizmo.freeDraggerArea;
else if (transformMode === EditView3D.TransformMode.Rotate)

View File

@@ -32,7 +32,7 @@ View3D {
property Material previewMaterial
function fitToViewPort()
function fitToViewPort(closeUp)
{
// No need to zoom this view, this is here just to avoid runtime warnings
}

View File

@@ -41,6 +41,8 @@ Item {
property var modelViewComponent
property var nodeViewComponent
property bool closeUp: false
function destroyView()
{
previewObject = null;
@@ -96,7 +98,15 @@ Item {
function fitToViewPort()
{
view.fitToViewPort();
view.fitToViewPort(closeUp);
}
// Enables/disables icon mode. When in icon mode, camera is zoomed bit closer to reduce margins
// and the background is removed, in order to generate a preview suitable for library icons.
function setIconMode(enable)
{
closeUp = enable;
backgroundRect.visible = !enable;
}
View3D {
@@ -108,10 +118,15 @@ Item {
id: contentItem
anchors.fill: parent
Rectangle {
Item {
id: viewRect
anchors.fill: parent
}
Rectangle {
id: backgroundRect
anchors.fill: parent
z: -1
gradient: Gradient {
GradientStop { position: 1.0; color: "#222222" }
GradientStop { position: 0.0; color: "#999999" }

View File

@@ -34,11 +34,11 @@ View3D {
property Model sourceModel
function fitToViewPort()
function fitToViewPort(closeUp)
{
// The magic number is the distance from camera default pos to origin
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
1040);
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root,
1040, closeUp);
}
SceneEnvironment {

View File

@@ -32,11 +32,11 @@ View3D {
environment: sceneEnv
camera: theCamera
function fitToViewPort()
function fitToViewPort(closeUp)
{
// The magic number is the distance from camera default pos to origin
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
1040);
1040, closeUp);
}
SceneEnvironment {

View File

@@ -46,6 +46,8 @@ Item {
property bool usePerspective: true
property bool globalOrientation: false
property alias contentItem: contentItem
property color backgroundGradientColorStart: "#222222"
property color backgroundGradientColorEnd: "#999999"
enum SelectionMode { Item, Group }
enum TransformMode { Move, Rotate, Scale }
@@ -206,6 +208,15 @@ Item {
cameraControl.alignView(selectedNodes);
}
function updateViewStates(viewStates)
{
if ("selectBackgroundColor" in viewStates) {
var color = viewStates.selectBackgroundColor
backgroundGradientColorStart = color[0];
backgroundGradientColorEnd = color[1];
}
}
// If resetToDefault is true, tool states not specifically set to anything will be reset to
// their default state.
function updateToolStates(toolStates, resetToDefault)
@@ -329,6 +340,15 @@ Item {
function handleObjectClicked(object, multi)
{
if (object instanceof View3D) {
// View3D can be the resolved pick target in case the 3D editor is showing content
// of a component that has View3D as root. In that case locking is resolved on C++ side
// and we ignore multiselection.
selectObjects([]);
selectionChanged([object]);
return;
}
var clickedObject;
// Click on locked object is treated same as click on empty space
@@ -866,8 +886,8 @@ Item {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 1.0; color: "#222222" }
GradientStop { position: 0.0; color: "#999999" }
GradientStop { position: 1.0; color: backgroundGradientColorStart }
GradientStop { position: 0.0; color: backgroundGradientColorEnd }
}
MouseArea {
@@ -892,7 +912,7 @@ Item {
handleObjectClicked(resolvedResult, mouse.modifiers & Qt.ControlModifier);
if (pickResult.objectHit) {
if (pickResult.objectHit && pickResult.objectHit instanceof Node) {
if (transformMode === EditView3D.TransformMode.Move)
freeDraggerArea = moveGizmo.freeDraggerArea;
else if (transformMode === EditView3D.TransformMode.Rotate)

View File

@@ -1,88 +0,0 @@
/****************************************************************************
**
** 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 6.0
import QtQuick3D 6.0
Item {
id: viewRoot
width: 1024
height: 1024
visible: true
property alias view3D: view3D
property alias camPos: viewCamera.position
function setSceneToBox()
{
selectionBox.targetNode = view3D.importScene;
}
function fitAndHideBox()
{
cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true, true);
if (cameraControl._zoomFactor < 0.1)
view3D.importScene.scale = view3D.importScene.scale.times(10);
if (cameraControl._zoomFactor > 10)
view3D.importScene.scale = view3D.importScene.scale.times(0.1);
selectionBox.visible = false;
}
View3D {
id: view3D
camera: viewCamera
environment: sceneEnv
SceneEnvironment {
id: sceneEnv
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.VeryHigh
}
PerspectiveCamera {
id: viewCamera
position: Qt.vector3d(-200, 200, 200)
eulerRotation: Qt.vector3d(-45, -45, 0)
}
DirectionalLight {
rotation: viewCamera.rotation
}
SelectionBox {
id: selectionBox
view3D: view3D
geometryName: "SB"
}
EditCameraController {
id: cameraControl
camera: view3D.camera
view3d: view3D
ignoreToolState: true
}
}
}

View File

@@ -32,7 +32,7 @@ View3D {
property Material previewMaterial
function fitToViewPort()
function fitToViewPort(closeUp)
{
// No need to zoom this view, this is here just to avoid runtime warnings
}

View File

@@ -41,6 +41,8 @@ Item {
property var modelViewComponent
property var nodeViewComponent
property bool closeUp: false
function destroyView()
{
previewObject = null;
@@ -96,17 +98,30 @@ Item {
function fitToViewPort()
{
view.fitToViewPort();
view.fitToViewPort(closeUp);
}
// Enables/disables icon mode. When in icon mode, camera is zoomed bit closer to reduce margins
// and the background is removed, in order to generate a preview suitable for library icons.
function setIconMode(enable)
{
closeUp = enable;
backgroundRect.visible = !enable;
}
Item {
id: contentItem
anchors.fill: parent
Rectangle {
Item {
id: viewRect
anchors.fill: parent
}
Rectangle {
id: backgroundRect
anchors.fill: parent
z: -1
gradient: Gradient {
GradientStop { position: 1.0; color: "#222222" }
GradientStop { position: 0.0; color: "#999999" }

View File

@@ -34,11 +34,11 @@ View3D {
property Model sourceModel
function fitToViewPort()
function fitToViewPort(closeUp)
{
// The magic number is the distance from camera default pos to origin
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root,
1040);
1040, closeUp);
}
SceneEnvironment {

View File

@@ -32,11 +32,11 @@ View3D {
environment: sceneEnv
camera: theCamera
function fitToViewPort()
function fitToViewPort(closeUp)
{
// The magic number is the distance from camera default pos to origin
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
1040);
1040, closeUp);
}
SceneEnvironment {

View File

@@ -308,7 +308,7 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul
// and recalculating bounds for every frame is not a problem.
void GeneralHelper::calculateNodeBoundsAndFocusCamera(
QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort,
float defaultLookAtDistance)
float defaultLookAtDistance, bool closeUp)
{
QVector3D minBounds;
QVector3D maxBounds;
@@ -317,7 +317,9 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera(
QVector3D extents = maxBounds - minBounds;
QVector3D lookAt = minBounds + (extents / 2.f);
float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z()));
float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x())
+ qreal(extents.y()) * qreal(extents.y())
+ qreal(extents.z()) * qreal(extents.z()));
// Reset camera position to default zoom
QMatrix4x4 m = camera->sceneTransform();
@@ -328,9 +330,27 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera(
camera->setPosition(lookAt + newLookVector);
float newZoomFactor = maxExtent / 725.f; // Divisor taken from focusNodesToCamera function
// CloseUp divisor is used for icon generation, where we can allow some extreme models to go
// slightly out of bounds for better results generally. The other divisor is used for other
// previews, where the image is larger to begin with and we would also like some margin
// between preview edge and the rendered model, so we can be more conservative with the zoom.
// The divisor values are empirically selected to provide nice result.
float divisor = closeUp ? 1250.f : 1050.f;
float newZoomFactor = maxExtent / divisor;
zoomCamera(viewPort, camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
if (auto perspectiveCamera = qobject_cast<QQuick3DPerspectiveCamera *>(camera)) {
// Fix camera near/far clips in case we are dealing with extreme zooms
const float cameraDist = qAbs((camera->position() - lookAt).length());
const float minDist = cameraDist - (maxExtent / 2.f);
const float maxDist = cameraDist + (maxExtent / 2.f);
if (minDist < perspectiveCamera->clipNear() || maxDist > perspectiveCamera->clipFar()) {
perspectiveCamera->setClipNear(minDist * 0.99);
perspectiveCamera->setClipFar(maxDist * 1.01);
}
}
}
// Aligns any cameras found in nodes list to a camera.
@@ -418,15 +438,15 @@ QQuick3DPickResult GeneralHelper::pickViewAt(QQuick3DViewport *view, float posX,
return QQuick3DPickResult();
}
QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
QObject *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
{
if (pickNode) {
// Check if the picked node actually specifies another node as the pick target
// Check if the picked node actually specifies another object as the pick target
QVariant componentVar = pickNode->property("_pickTarget");
if (componentVar.isValid()) {
auto componentNode = componentVar.value<QQuick3DNode *>();
if (componentNode)
return componentNode;
auto componentObj = componentVar.value<QObject *>();
if (componentObj)
return componentObj;
}
}
return pickNode;
@@ -823,12 +843,13 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec
if (auto childNode = qobject_cast<QQuick3DNode *>(child)) {
QVector3D newMinBounds = minBounds;
QVector3D newMaxBounds = maxBounds;
hasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true);
bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true);
// Ignore any subtrees that do not have Model in them as we don't need those
// for visual bounds calculations
if (hasModel) {
if (childHasModel) {
minBoundsVec << newMinBounds;
maxBoundsVec << newMaxBounds;
hasModel = true;
}
}
}

View File

@@ -77,7 +77,7 @@ public:
bool closeUp = false);
Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
QQuick3DViewport *viewPort,
float defaultLookAtDistance);
float defaultLookAtDistance, bool closeUp);
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes,
const QVector3D &lookAtPoint);
@@ -85,7 +85,7 @@ public:
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
const QVariant& value);
Q_INVOKABLE QQuick3DPickResult pickViewAt(QQuick3DViewport *view, float posX, float posY);
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
Q_INVOKABLE QObject *resolvePick(QQuick3DNode *pickNode);
Q_INVOKABLE bool isLocked(QQuick3DNode *node) const;
Q_INVOKABLE bool isHidden(QQuick3DNode *node) const;

View File

@@ -77,9 +77,8 @@ void import3D(const QString &sourceAsset, const QString &outDir, const QString &
}
}
// Allow little time for file operations to finish
QTimer::singleShot(2000, nullptr, []() {
qApp->exit(0);
QTimer::singleShot(0, nullptr, []() {
qApp->quit();
});
}

View File

@@ -1561,6 +1561,10 @@ void NodeInstanceServer::handleInstanceHidden(const ServerNodeInstance &/*instan
{
}
void NodeInstanceServer::handlePickTarget(const ServerNodeInstance &/*instance*/)
{
}
void NodeInstanceServer::setupState(qint32 stateInstanceId)
{
if (hasInstanceForId(stateInstanceId)) {

View File

@@ -226,6 +226,7 @@ public:
virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors);
virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors);
virtual void handlePickTarget(const ServerNodeInstance &instance);
virtual QImage grabWindow() = 0;
virtual QImage grabItem(QQuickItem *item) = 0;

View File

@@ -553,7 +553,18 @@ void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &ob
auto obj = object.value<QObject *>();
if (obj) {
ServerNodeInstance instance = instanceForObject(obj);
instanceList << instance;
// If instance is a View3D, make sure it is not locked
bool locked = false;
if (instance.isSubclassOf("QQuick3DViewport")) {
locked = instance.internalInstance()->isLockedInEditor();
auto parentInst = instance.parent();
while (!locked && parentInst.isValid()) {
locked = parentInst.internalInstance()->isLockedInEditor();
parentInst = parentInst.parent();
}
}
if (!locked)
instanceList << instance;
#ifdef QUICK3D_PARTICLES_MODULE
if (!skipSystemDeselect) {
auto particleSystem = parentParticleSystem(instance.internalObject());
@@ -1452,8 +1463,9 @@ void Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout()
void Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout()
{
#ifdef QUICK3D_MODULE
for (auto obj : std::as_const(m_dynamicObjectConstructors)) {
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
#ifdef QUICK3D_MODULE
auto handleHiding = [this](QQuick3DNode *node) -> bool {
if (node && hasInstanceForObject(node)) {
ServerNodeInstance instance = instanceForObject(node);
@@ -1468,8 +1480,22 @@ void Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout()
if (auto pickTarget = obj->property("_pickTarget").value<QQuick3DNode *>())
handleHiding(pickTarget);
}
}
#endif
#else
auto handlePicking = [this](QObject *object) -> bool {
if (object && hasInstanceForObject(object)) {
ServerNodeInstance instance = instanceForObject(object);
handlePickTarget(instance);
return true;
}
return false;
};
if (!handlePicking(obj)) {
if (auto pickTarget = obj->property("_pickTarget").value<QObject *>())
handlePicking(pickTarget);
}
#endif
}
m_dynamicObjectConstructors.clear();
}
@@ -1932,6 +1958,12 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
#ifdef IMPORT_QUICK3D_ASSETS
QTimer::singleShot(0, this, &Qt5InformationNodeInstanceServer::resolveImportSupport);
#endif
if (!command.edit3dBackgroundColor.isEmpty()) {
View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectBackgroundColor,
QVariant::fromValue(command.edit3dBackgroundColor));
view3DAction(backgroundColorCommand);
}
}
void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList<ServerNodeInstance> &childList)
@@ -2147,18 +2179,19 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
if (!m_editView3DSetupDone)
return;
QVariantMap updatedState;
QVariantMap updatedToolState;
QVariantMap updatedViewState;
int renderCount = 1;
switch (command.type()) {
case View3DActionCommand::MoveTool:
updatedState.insert("transformMode", 0);
updatedToolState.insert("transformMode", 0);
break;
case View3DActionCommand::RotateTool:
updatedState.insert("transformMode", 1);
updatedToolState.insert("transformMode", 1);
break;
case View3DActionCommand::ScaleTool:
updatedState.insert("transformMode", 2);
updatedToolState.insert("transformMode", 2);
break;
case View3DActionCommand::FitToView:
QMetaObject::invokeMethod(m_editView3DData.rootItem, "fitToView");
@@ -2170,38 +2203,42 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
QMetaObject::invokeMethod(m_editView3DData.rootItem, "alignViewToCamera");
break;
case View3DActionCommand::SelectionModeToggle:
updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0);
updatedToolState.insert("selectionMode", command.isEnabled() ? 1 : 0);
break;
case View3DActionCommand::CameraToggle:
updatedState.insert("usePerspective", command.isEnabled());
updatedToolState.insert("usePerspective", command.isEnabled());
// It can take a couple frames to properly update icon gizmo positions
renderCount = 2;
break;
case View3DActionCommand::OrientationToggle:
updatedState.insert("globalOrientation", command.isEnabled());
updatedToolState.insert("globalOrientation", command.isEnabled());
break;
case View3DActionCommand::EditLightToggle:
updatedState.insert("showEditLight", command.isEnabled());
updatedToolState.insert("showEditLight", command.isEnabled());
break;
case View3DActionCommand::ShowGrid:
updatedState.insert("showGrid", command.isEnabled());
updatedToolState.insert("showGrid", command.isEnabled());
break;
case View3DActionCommand::ShowSelectionBox:
updatedState.insert("showSelectionBox", command.isEnabled());
updatedToolState.insert("showSelectionBox", command.isEnabled());
break;
case View3DActionCommand::ShowIconGizmo:
updatedState.insert("showIconGizmo", command.isEnabled());
updatedToolState.insert("showIconGizmo", command.isEnabled());
break;
case View3DActionCommand::ShowCameraFrustum:
updatedState.insert("showCameraFrustum", command.isEnabled());
updatedToolState.insert("showCameraFrustum", command.isEnabled());
break;
case View3DActionCommand::SelectBackgroundColor: {
updatedViewState.insert("selectBackgroundColor", command.value());
break;
}
#ifdef QUICK3D_PARTICLES_MODULE
case View3DActionCommand::ShowParticleEmitter:
updatedState.insert("showParticleEmitter", command.isEnabled());
updatedToolState.insert("showParticleEmitter", command.isEnabled());
break;
case View3DActionCommand::ParticlesPlay:
m_particleAnimationPlaying = command.isEnabled();
updatedState.insert("particlePlay", command.isEnabled());
updatedToolState.insert("particlePlay", command.isEnabled());
if (m_particleAnimationPlaying) {
m_particleAnimationDriver->play();
m_particleAnimationDriver->setSeekerEnabled(false);
@@ -2227,12 +2264,17 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
break;
}
if (!updatedState.isEmpty()) {
if (!updatedToolState.isEmpty()) {
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates",
Q_ARG(QVariant, updatedState),
Q_ARG(QVariant, updatedToolState),
Q_ARG(QVariant, QVariant::fromValue(false)));
}
if (!updatedViewState.isEmpty()) {
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateViewStates",
Q_ARG(QVariant, updatedViewState));
}
render3DEditView(renderCount);
}
@@ -2332,9 +2374,9 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst
}
}
#else
Q_UNUSED(instance);
Q_UNUSED(enable);
Q_UNUSED(checkAncestors);
Q_UNUSED(instance)
Q_UNUSED(enable)
Q_UNUSED(checkAncestors)
#endif
}
@@ -2388,6 +2430,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst
// Don't override explicit hide in children
handleInstanceHidden(quick3dInstance, edit3dHidden || isInstanceHidden, false);
} else {
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
// Children of components do not have instances, but will still need to be pickable
std::function<void(QQuick3DNode *)> checkChildren;
checkChildren = [&](QQuick3DNode *checkNode) {
@@ -2402,9 +2445,7 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst
value = QVariant::fromValue(node);
// Specify the actual pick target with dynamic property
checkModel->setProperty("_pickTarget", value);
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
checkModel->setPickable(!edit3dHidden);
#endif
} else {
auto checkRepeater = qobject_cast<QQuick3DRepeater *>(checkNode);
auto checkLoader = qobject_cast<QQuick3DLoader *>(checkNode);
@@ -2436,13 +2477,102 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst
};
if (auto childNode = qobject_cast<QQuick3DNode *>(childItem))
checkChildren(childNode);
#endif
}
}
}
#else
Q_UNUSED(instance);
Q_UNUSED(enable);
Q_UNUSED(checkAncestors);
Q_UNUSED(instance)
Q_UNUSED(enable)
Q_UNUSED(checkAncestors)
#endif
}
void Qt5InformationNodeInstanceServer::handlePickTarget(const ServerNodeInstance &instance)
{
#if defined(QUICK3D_MODULE) && (QT_VERSION >= QT_VERSION_CHECK(6, 2, 1))
// Picking is dependent on hidden status prior to global picking support (<6.2.1), so it is
// handled in handleInstanceHidden() method in those builds
if (!ViewConfig::isQuick3DMode())
return;
QObject *obj = instance.internalObject();
QList<QQuick3DObject *> childItems;
if (auto node = qobject_cast<QQuick3DNode *>(obj)) {
childItems = node->childItems();
} else if (auto view = qobject_cast<QQuick3DViewport *>(obj)) {
// We only need to handle views that are components
// View is a component if its scene is not an instance and scene has node children that
// have no instances
QQuick3DNode *node = view->scene();
if (node) {
if (hasInstanceForObject(node))
return;
childItems = node->childItems();
bool allHaveInstance = true;
for (const auto &childItem : childItems) {
if (qobject_cast<QQuick3DNode *>(childItem) && !hasInstanceForObject(childItem)) {
allHaveInstance = false;
break;
}
}
if (allHaveInstance)
return;
}
} else {
return;
}
for (auto childItem : qAsConst(childItems)) {
if (!hasInstanceForObject(childItem)) {
// Children of components do not have instances, but will still need to be pickable
// and redirect their pick to the component
std::function<void(QQuick3DNode *)> checkChildren;
checkChildren = [&](QQuick3DNode *checkNode) {
const auto childItems = checkNode->childItems();
for (auto child : childItems) {
if (auto childNode = qobject_cast<QQuick3DNode *>(child))
checkChildren(childNode);
}
if (auto checkModel = qobject_cast<QQuick3DModel *>(checkNode)) {
// Specify the actual pick target with dynamic property
checkModel->setProperty("_pickTarget", QVariant::fromValue(obj));
} else {
auto checkRepeater = qobject_cast<QQuick3DRepeater *>(checkNode);
auto checkLoader = qobject_cast<QQuick3DLoader *>(checkNode);
#if defined(QUICK3D_ASSET_UTILS_MODULE)
auto checkRunLoader = qobject_cast<QQuick3DRuntimeLoader *>(checkNode);
if (checkRepeater || checkLoader || checkRunLoader) {
#else
if (checkRepeater || checkLoader) {
#endif
// Repeaters/loaders may not yet have created their children, so we set
// _pickTarget on them and connect the notifier.
if (checkNode->property("_pickTarget").isNull()) {
if (checkRepeater) {
QObject::connect(checkRepeater, &QQuick3DRepeater::objectAdded,
this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject);
#if defined(QUICK3D_ASSET_UTILS_MODULE)
} else if (checkRunLoader) {
QObject::connect(checkRunLoader, &QQuick3DRuntimeLoader::statusChanged,
this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject);
#endif
} else {
QObject::connect(checkLoader, &QQuick3DLoader::loaded,
this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject);
}
}
checkNode->setProperty("_pickTarget", QVariant::fromValue(obj));
}
}
};
if (auto childNode = qobject_cast<QQuick3DNode *>(childItem))
checkChildren(childNode);
}
}
#else
Q_UNUSED(instance)
#endif
}

View File

@@ -80,6 +80,7 @@ public:
void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override;
void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override;
void handlePickTarget(const ServerNodeInstance &instance) override;
bool isInformationServer() const override;
void handleDynamicAddObject();

View File

@@ -57,6 +57,9 @@ void Quick3DRenderableNodeInstance::initialize(const ObjectNodeInstance::Pointer
// In case this is the scene root, we need to create a dummy View3D for the scene
// in preview puppets
if (instanceId() == 0 && (!nodeInstanceServer()->isInformationServer())) {
nodeInstanceServer()->quickWindow()->setDefaultAlphaBuffer(true);
nodeInstanceServer()->quickWindow()->setColor(Qt::transparent);
auto helper = new QmlDesigner::Internal::GeneralHelper();
engine()->rootContext()->setContextProperty("_generalHelper", helper);
@@ -199,6 +202,14 @@ QQuickItem *Quick3DRenderableNodeInstance::contentItem() const
return m_dummyRootView;
}
void Quick3DRenderableNodeInstance::setPropertyVariant(const PropertyName &name,
const QVariant &value)
{
if (m_dummyRootView && name == "isLibraryIcon")
QMetaObject::invokeMethod(m_dummyRootView, "setIconMode", Q_ARG(QVariant, value));
ObjectNodeInstance::setPropertyVariant(name, value);
}
Qt5NodeInstanceServer *Quick3DRenderableNodeInstance::qt5NodeInstanceServer() const
{
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());

View File

@@ -52,6 +52,7 @@ public:
QList<ServerNodeInstance> stateInstances() const override;
QQuickItem *contentItem() const override;
void setPropertyVariant(const PropertyName &name, const QVariant &value) override;
protected:
explicit Quick3DRenderableNodeInstance(QObject *node);

View File

@@ -323,8 +323,12 @@ ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceSe
instance.internalInstance()->initialize(instance.m_nodeInstance, instanceContainer.metaFlags());
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
// Handle hidden state to initialize pickable state
nodeInstanceServer->handleInstanceHidden(instance, false, false);
#else
nodeInstanceServer->handlePickTarget(instance);
#endif
return instance;
}

View File

@@ -41,6 +41,8 @@ StudioControls.ComboBox {
onModelChanged: colorLogic.invalidate()
hasActiveDrag: comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag
// This is available in all editors.
onValueTypeChanged: {
@@ -83,16 +85,15 @@ StudioControls.ComboBox {
onEntered: (drag) => {
dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0]
drag.accepted = comboBox.backendValue !== undefined && comboBox.backendValue.isSupportedDrop(dropArea.assetPath)
comboBox.hasActiveDrag = drag.accepted
drag.accepted = comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag
comboBox.hasActiveHoverDrag = drag.accepted
}
onExited: comboBox.hasActiveDrag = false
onExited: comboBox.hasActiveHoverDrag = false
onDropped: {
comboBox.backendValue.commitDrop(dropArea.assetPath)
comboBox.hasActiveDrag = false
comboBox.hasActiveHoverDrag = false
}
}

View File

@@ -39,7 +39,8 @@ T.ComboBox {
&& myComboBox.enabled
property bool edit: myComboBox.activeFocus && myComboBox.editable
property bool open: comboBoxPopup.opened
property bool hasActiveDrag: false
property bool hasActiveDrag: false // an item that can be dropped on the combobox is being dragged
property bool hasActiveHoverDrag: false // an item that can be dropped on the combobox is being hovered on the combobox
property bool dirty: false // user modification flag
@@ -49,6 +50,9 @@ T.ComboBox {
property alias textInput: comboBoxInput
property int borderWidth: myComboBox.hasActiveHoverDrag ? StudioTheme.Values.borderHover
: StudioTheme.Values.border
signal compressedActivated(int index, int reason)
enum ActivatedReason { EditingFinished, Other }
@@ -57,7 +61,7 @@ T.ComboBox {
height: StudioTheme.Values.defaultControlHeight
leftPadding: actionIndicator.width
rightPadding: popupIndicator.width + StudioTheme.Values.border
rightPadding: popupIndicator.width + myComboBox.borderWidth
font.pixelSize: StudioTheme.Values.myFontSize
wheelEnabled: false
@@ -87,6 +91,7 @@ T.ComboBox {
myControl: myComboBox
text: myComboBox.editText
borderWidth: myComboBox.borderWidth
onEditingFinished: {
comboBoxInput.deselect()
@@ -108,16 +113,16 @@ T.ComboBox {
myControl: myComboBox
myPopup: myComboBox.popup
x: comboBoxInput.x + comboBoxInput.width
y: StudioTheme.Values.border
width: StudioTheme.Values.checkIndicatorWidth - StudioTheme.Values.border
height: StudioTheme.Values.checkIndicatorHeight - (StudioTheme.Values.border * 2)
y: myComboBox.borderWidth
width: StudioTheme.Values.checkIndicatorWidth - myComboBox.borderWidth
height: StudioTheme.Values.checkIndicatorHeight - myComboBox.borderWidth * 2
}
background: Rectangle {
id: comboBoxBackground
color: StudioTheme.Values.themeControlBackground
border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border
border.width: myComboBox.borderWidth
x: actionIndicator.width
width: myComboBox.width - actionIndicator.width
height: myComboBox.height
@@ -144,7 +149,7 @@ T.ComboBox {
width: comboBoxPopup.width - comboBoxPopup.leftPadding - comboBoxPopup.rightPadding
- (comboBoxPopupScrollBar.visible ? comboBoxPopupScrollBar.contentItem.implicitWidth
+ 2 : 0) // TODO Magic number
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
height: StudioTheme.Values.height - 2 * myComboBox.borderWidth
padding: 0
enabled: model.enabled === undefined ? true : model.enabled
@@ -198,9 +203,9 @@ T.ComboBox {
popup: T.Popup {
id: comboBoxPopup
x: actionIndicator.width + StudioTheme.Values.border
x: actionIndicator.width + myComboBox.borderWidth
y: myComboBox.height
width: myComboBox.width - actionIndicator.width - (StudioTheme.Values.border * 2)
width: myComboBox.width - actionIndicator.width - myComboBox.borderWidth * 2
// TODO Setting the height on the popup solved the problem with the popup of height 0,
// but it has the problem that it sometimes extend over the border of the actual window
// and is then cut off.
@@ -208,7 +213,7 @@ T.ComboBox {
+ comboBoxPopup.bottomPadding,
myComboBox.Window.height - topMargin - bottomMargin,
StudioTheme.Values.maxComboBoxPopupHeight)
padding: StudioTheme.Values.border
padding: myComboBox.borderWidth
margins: 0 // If not defined margin will be -1
closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent
| T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside
@@ -252,8 +257,9 @@ T.ComboBox {
PropertyChanges {
target: comboBoxBackground
color: StudioTheme.Values.themeControlBackground
border.color: hasActiveDrag ? StudioTheme.Values.themeInteraction
: StudioTheme.Values.themeControlOutline
border.color: myComboBox.hasActiveDrag ? StudioTheme.Values.themeInteraction
: StudioTheme.Values.themeControlOutline
border.width: myComboBox.borderWidth
}
},
// This state is intended for ComboBoxes which aren't editable, but have focus e.g. via

View File

@@ -34,6 +34,7 @@ TextInput {
property bool edit: textInput.activeFocus
property bool hover: mouseArea.containsMouse && textInput.enabled
property int borderWidth: StudioTheme.Values.border
z: 2
font: myControl.font
@@ -55,11 +56,11 @@ TextInput {
Rectangle {
id: textInputBackground
x: StudioTheme.Values.border
y: StudioTheme.Values.border
x: textInput.borderWidth
y: textInput.borderWidth
z: -1
width: textInput.width
height: StudioTheme.Values.height - (StudioTheme.Values.border * 2)
height: StudioTheme.Values.height - textInput.borderWidth * 2
color: StudioTheme.Values.themeControlBackground
border.width: 0
}

View File

@@ -86,6 +86,7 @@ QtObject {
property real marginTopBottom: 4
property real border: 1
property real borderHover: 3
property real maxComboBoxPopupHeight: Math.round(300 * values.scaleFactor)
property real maxTextAreaPopupHeight: Math.round(150 * values.scaleFactor)

View File

@@ -17,21 +17,23 @@
{ "key": "ProjectPluginName", "value": "%{ProjectName}plugin" },
{ "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" },
{ "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "UIClassName", "value": "Screen01" },
{ "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" },
{ "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" },
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
{ "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" }
{ "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" }
],
"pages":
@@ -243,21 +245,24 @@
"trKey": "Qt 5",
"value":
"({
'TargetQuickVersion': '2.15'
'TargetQuickVersion': '2.15',
'TargetQuick3DVersion': '1.15'
})"
},
{
"trKey": "Qt 6.2",
"value":
"({
'TargetQuickVersion': '6.2'
'TargetQuickVersion': '6.2',
'TargetQuick3DVersion': '6.2'
})"
},
{
"trKey": "Qt 6.3",
"value":
"({
'TargetQuickVersion': '6.3'
'TargetQuickVersion': '6.3',
'TargetQuick3DVersion': '6.3'
})"
}
]

View File

@@ -20,20 +20,20 @@
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "UIClassName", "value": "Screen01" },
{ "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
{ "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('QtQuickVersion') === '' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" },
{ "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" },
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" },
{ "key": "DefaultStyle", "value": "%{JS: value('QtQuickVersion') === '' ? 'Basic' : 'Default'}" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" }
{ "key": "DefaultStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? 'Basic' : 'Default'}" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" }
],
"pages":

View File

@@ -20,17 +20,19 @@
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "UIClassName", "value": "Screen01" },
{ "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" },
{ "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" },
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
{ "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" }
{ "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" }
],
"pages":
@@ -235,7 +237,6 @@
"data":
{
"index": 1,
"items":
"items":
[
{

View File

@@ -18,19 +18,19 @@
{ "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" },
{ "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" },
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "UIClassName", "value": "Screen01" },
{ "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" },
{ "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" },
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
{ "key": "UseVirtualKeyboard", "value": "%{JS: false}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" }
{ "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" }
],
"pages":

View File

@@ -18,17 +18,19 @@
{ "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" },
{ "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" },
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" },
{ "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" },
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
{ "key": "UseVirtualKeyboard", "value": "%{JS: false}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" }
{ "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" }
],
"pages":

View File

@@ -18,17 +18,19 @@
{ "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" },
{ "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" },
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt5", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyle}" },
{ "key": "QtQuickControlsStyleInternalQt6", "value": "%{JS: value('QtQuickControlsStyleInternalQt5') === 'Default' ? 'Basic' : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyle", "value": "%{JS: value('IsQt6Project') === 'true' ? value('QtQuickControlsStyleInternalQt6') : value('QtQuickControlsStyleInternalQt5')}" },
{ "key": "QtQuickControlsStyleTheme", "value": "%{JS: %{ControlsStyle}.QtQuickControlsStyleTheme}" },
{ "key": "ApplicationImport", "value": "%{JS: value('QtQuickVersion') === '' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "ApplicationImport", "value": "%{JS: value('IsQt6Project') === 'true' ? '%{ImportModuleName}' : '%{ImportModuleName} 1.0'}" },
{ "key": "UseStandardResolution", "value": "%{JS: value('CustomScreenWidth') === '' || value('CustomScreenHeight') === ''}" },
{ "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" },
{ "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" },
{ "key": "UseVirtualKeyboard", "value": "%{JS: false}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') === '' }" },
{ "key": "ImportModuleVersion", "value": "%{JS: value('QtQuickVersion') === '' ? '' : '1.0'}" }
{ "key": "ImportModuleVersion", "value": "%{JS: value('IsQt6Project') === 'true' ? '' : '1.0'}" }
],
"pages":

View File

@@ -67,10 +67,7 @@ public:
, m_stdErr(stdErr) {}
QByteArray stdOut() const { return m_stdOut; }
QByteArray stdErr() const { return m_stdErr; }
void mergeWith(LauncherReadyReadSignal *newSignal) {
m_stdOut += newSignal->stdOut();
m_stdErr += newSignal->stdErr();
}
private:
QByteArray m_stdOut;
QByteArray m_stdErr;
@@ -203,31 +200,6 @@ void CallerHandle::appendSignal(LauncherSignal *newSignal)
QMutexLocker locker(&m_mutex);
QTC_ASSERT(isCalledFromLaunchersThread(), return);
// TODO: we might assert if the caller's state is proper, e.g.
// start signal can't appear if we are in Running or NotRunning state,
// or finish signal can't appear if we are in NotRunning or Starting state,
// or readyRead signal can't appear if we are in NotRunning or Starting state,
// or error signal can't appear if we are in NotRunning state
// or FailedToStart error signal can't appear if we are in Running state
// or other than FailedToStart error signal can't appear if we are in Starting state.
if (!m_signals.isEmpty()) {
LauncherSignal *lastSignal = m_signals.last();
QTC_ASSERT(lastSignal->signalType() != SignalType::Done,
qWarning() << "Buffering new signal for process" << m_command
<< "while the last done() signal wasn't flushed yet.");
// Merge ReadyRead signals into one.
if (lastSignal->signalType() == SignalType::ReadyRead
&& newSignal->signalType() == SignalType::ReadyRead) {
LauncherReadyReadSignal *lastRead = static_cast<LauncherReadyReadSignal *>(lastSignal);
LauncherReadyReadSignal *newRead = static_cast<LauncherReadyReadSignal *>(newSignal);
lastRead->mergeWith(newRead);
delete newRead;
return;
}
}
m_signals.append(newSignal);
}

View File

@@ -103,6 +103,7 @@ IAssistProposal *FunctionHintProcessor::perform(const AssistInterface *interface
void FunctionHintProcessor::cancel()
{
QTC_ASSERT(m_client, return);
if (running()) {
m_client->cancelRequest(*m_currentRequest);
m_client->removeAssistProcessor(this);
@@ -112,6 +113,7 @@ void FunctionHintProcessor::cancel()
void FunctionHintProcessor::handleSignatureResponse(const SignatureHelpRequest::Response &response)
{
QTC_ASSERT(m_client, setAsyncProposalAvailable(nullptr); return);
m_currentRequest.reset();
if (auto error = response.error())
m_client->log(*error);

View File

@@ -165,6 +165,7 @@ extend_qtc_plugin(QmlDesigner
edit3dcanvas.cpp edit3dcanvas.h
edit3dactions.cpp edit3dactions.h
edit3dvisibilitytogglesmenu.cpp edit3dvisibilitytogglesmenu.h
backgroundcolorselection.cpp backgroundcolorselection.h
edit3d.qrc
)

View File

@@ -81,30 +81,20 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event)
if (obj == m_assetsWidget.data())
QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut");
} else if (event->type() == QMouseEvent::MouseMove) {
if (!m_assetsToDrag.isEmpty()) {
if (!m_assetsToDrag.isEmpty() && !m_model.isNull()) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) {
auto drag = new QDrag(this);
drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128}));
QMimeData *mimeData = new QMimeData;
mimeData->setData(Constants::MIME_TYPE_ASSETS, m_assetsToDrag.join(',').toUtf8());
drag->setMimeData(mimeData);
drag->exec();
drag->deleteLater();
m_model->startDrag(mimeData,
m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128}));
m_assetsToDrag.clear();
}
}
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
m_assetsToDrag.clear();
QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator");
if (view) {
NavigatorWidget *navView = qobject_cast<NavigatorWidget *>(view);
if (navView) {
navView->setDragType("");
navView->update();
}
}
if (m_model)
m_model->endDrag();
}
return QObject::eventFilter(obj, event);

View File

@@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2022 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 "backgroundcolorselection.h"
#include <nodeinstanceview.h>
#include <utils/qtcassert.h>
#include <view3dactioncommand.h>
#include <qmldesignerplugin.h>
using namespace QmlDesigner;
namespace {
QList<QColor> readBackgroundColorConfiguration()
{
QVariant var = QmlDesigner::DesignerSettings::getValue(
QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR);
if (!var.isValid())
return {};
auto colorNameList = var.value<QList<QString>>();
QTC_ASSERT(colorNameList.size() == 2, return {});
return {colorNameList[0], colorNameList[1]};
}
void setBackgroundColorConfiguration(const QList<QColor> &colorConfig)
{
auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView();
View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor,
QVariant::fromValue(colorConfig));
view->view3DAction(cmd);
}
void saveBackgroundColorConfiguration(const QList<QColor> &colorConfig)
{
QList<QString> colorsSaved = {colorConfig[0].name(), colorConfig[1].name()};
QmlDesigner::DesignerSettings::setValue(
QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR,
QVariant::fromValue(colorsSaved));
}
} // namespace
QColorDialog *BackgroundColorSelection::createDialog(QWidget *parent)
{
auto dialog = new QColorDialog(parent);
dialog->setModal(true);
dialog->setAttribute(Qt::WA_DeleteOnClose);
const QList<QColor> oldColorConfig = readBackgroundColorConfiguration();
dialog->show();
QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [](const QColor &color) {
setBackgroundColorConfiguration({color, color});
});
QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [](const QColor &color) {
saveBackgroundColorConfiguration({color, color});
});
if (!oldColorConfig.isEmpty()) {
QObject::connect(dialog, &QColorDialog::rejected, dialog, [oldColorConfig]() {
setBackgroundColorConfiguration(oldColorConfig);
});
}
return dialog;
}
void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent)
{
if (m_dialog)
return;
m_dialog = BackgroundColorSelection::createDialog(parent);
QTC_ASSERT(m_dialog, return);
QObject::connect(m_dialog, &QWidget::destroyed, m_dialog, [&]() {
m_dialog = nullptr;
});
}

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2022 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 <QColorDialog>
namespace QmlDesigner {
class BackgroundColorSelection : public QObject
{
Q_OBJECT
public:
explicit BackgroundColorSelection(QObject *parent = nullptr)
: QObject{parent}
{}
static void showBackgroundColorSelectionWidget(QWidget *parent);
private:
static QColorDialog *createDialog(QWidget *parent);
inline static QColorDialog *m_dialog = nullptr;
};
} // namespace QmlDesigner

View File

@@ -44,5 +44,7 @@
<file>images/align_camera_on@2x.png</file>
<file>images/align_view_on.png</file>
<file>images/align_view_on@2x.png</file>
<file>images/color_palette.png</file>
<file>images/color_palette@2x.png</file>
</qresource>
</RCC>

View File

@@ -48,9 +48,10 @@ Edit3DActionTemplate::Edit3DActionTemplate(const QString &description,
void Edit3DActionTemplate::actionTriggered(bool b)
{
if (m_type != View3DActionCommand::Empty) {
QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()
->view3DAction(View3DActionCommand(m_type, b));
if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor) {
auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView();
View3DActionCommand cmd(m_type, b);
view->view3DAction(cmd);
}
if (m_action)

View File

@@ -42,6 +42,8 @@
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <backgroundcolorselection.h>
#include <QDebug>
#include <QToolButton>
@@ -336,6 +338,32 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_G), true, true, {}, {}, nullptr,
QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid."));
SelectionContextOperation showBackgroundColorSelection = [this](const SelectionContext &) {
BackgroundColorSelection::showBackgroundColorSelectionWidget(edit3DWidget());
};
m_backgroundColorSelectionAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor,
QCoreApplication::translate("SelectBackgroundColorAction", "Select Background color"),
{}, false, false, {}, {}, showBackgroundColorSelection,
QCoreApplication::translate("SelectBackgroundColorAction", "Choose a color for the background."));
m_resetBackgroundColorAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor,
QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background color"),
{}, false, false, {}, {}, [](const SelectionContext &) {
QList<QColor> colors = {QRgb(0x222222), QRgb(0x999999)};
auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView();
View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, QVariant::fromValue(colors));
view->view3DAction(cmd);
QList<QString> colorsToSave = {colors[0].name(), colors[1].name()};
QmlDesigner::DesignerSettings::setValue(
QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR,
QVariant::fromValue(colorsToSave));
},
QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background color to the default value."));
m_showSelectionBoxAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX, View3DActionCommand::ShowSelectionBox,
QCoreApplication::translate("ShowSelectionBoxAction", "Show Selection Boxes"),
@@ -438,6 +466,29 @@ void Edit3DView::createEdit3DActions()
QKeySequence(), false, false, Utils::Icons::EYE_OPEN_TOOLBAR.icon(),
{}, visibilityTogglesTrigger);
SelectionContextOperation backgroundColorActionsTrigger = [this](const SelectionContext &) {
if (!edit3DWidget()->backgroundColorMenu())
return;
QPoint pos;
const auto &actionWidgets = m_backgrondColorMenuAction->action()->associatedWidgets();
for (auto actionWidget : actionWidgets) {
if (auto button = qobject_cast<QToolButton *>(actionWidget)) {
pos = button->mapToGlobal(QPoint(0, 0));
break;
}
}
edit3DWidget()->showBackgroundColorMenu(!edit3DWidget()->backgroundColorMenu()->isVisible(),
pos);
};
m_backgrondColorMenuAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_BACKGROUND_COLOR_ACTIONS, View3DActionCommand::Empty,
QCoreApplication::translate("BackgroundColorMenuActions", "Background Color Actions"),
QKeySequence(), false, false, Icons::COLOR_PALETTE.icon(),
{}, backgroundColorActionsTrigger);
m_leftActions << m_selectionModeAction;
m_leftActions << nullptr; // Null indicates separator
m_leftActions << nullptr; // Second null after separator indicates an exclusive group
@@ -455,6 +506,8 @@ void Edit3DView::createEdit3DActions()
m_leftActions << m_alignViewAction;
m_leftActions << nullptr;
m_leftActions << m_visibilityTogglesAction;
m_leftActions << nullptr;
m_leftActions << m_backgrondColorMenuAction;
m_rightActions << m_particleViewModeAction;
m_rightActions << m_particlesPlayAction;
@@ -467,6 +520,9 @@ void Edit3DView::createEdit3DActions()
m_visibilityToggleActions << m_showIconGizmoAction;
m_visibilityToggleActions << m_showCameraFrustumAction;
m_visibilityToggleActions << m_showParticleEmitterAction;
m_backgroundColorActions << m_backgroundColorSelectionAction;
m_backgroundColorActions << m_resetBackgroundColorAction;
}
QVector<Edit3DAction *> Edit3DView::leftActions() const
@@ -484,6 +540,11 @@ QVector<Edit3DAction *> Edit3DView::visibilityToggleActions() const
return m_visibilityToggleActions;
}
QVector<Edit3DAction *> Edit3DView::backgroundColorActions() const
{
return m_backgroundColorActions;
}
void Edit3DView::addQuick3DImport()
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();

View File

@@ -74,6 +74,7 @@ public:
QVector<Edit3DAction *> leftActions() const;
QVector<Edit3DAction *> rightActions() const;
QVector<Edit3DAction *> visibilityToggleActions() const;
QVector<Edit3DAction *> backgroundColorActions() const;
void setSeeker(SeekerSlider *slider);
void addQuick3DImport();
@@ -88,6 +89,7 @@ private:
QVector<Edit3DAction *> m_leftActions;
QVector<Edit3DAction *> m_rightActions;
QVector<Edit3DAction *> m_visibilityToggleActions;
QVector<Edit3DAction *> m_backgroundColorActions;
Edit3DAction *m_selectionModeAction = nullptr;
Edit3DAction *m_moveToolAction = nullptr;
Edit3DAction *m_rotateToolAction = nullptr;
@@ -99,6 +101,8 @@ private:
Edit3DAction *m_orientationModeAction = nullptr;
Edit3DAction *m_editLightAction = nullptr;
Edit3DAction *m_showGridAction = nullptr;
Edit3DAction *m_backgroundColorSelectionAction = nullptr;
Edit3DAction *m_resetBackgroundColorAction = nullptr;
Edit3DAction *m_showSelectionBoxAction = nullptr;
Edit3DAction *m_showIconGizmoAction = nullptr;
Edit3DAction *m_showCameraFrustumAction = nullptr;
@@ -108,6 +112,7 @@ private:
Edit3DAction *m_particlesPlayAction = nullptr;
Edit3DAction *m_particlesRestartAction = nullptr;
Edit3DAction *m_visibilityTogglesAction = nullptr;
Edit3DAction *m_backgrondColorMenuAction = nullptr;
SeekerSlider *m_seeker = nullptr;
int particlemode;
ModelCache<QImage> m_canvasCache;

View File

@@ -141,6 +141,9 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
m_visibilityTogglesMenu = new Edit3DVisibilityTogglesMenu(this);
handleActions(view->visibilityToggleActions(), m_visibilityTogglesMenu, false);
m_backgroundColorMenu = new Edit3DVisibilityTogglesMenu(this);
handleActions(view->backgroundColorActions(), m_backgroundColorMenu, false);
view->setSeeker(seeker);
seeker->setToolTip(QLatin1String("Seek particle system time when paused."));
@@ -201,6 +204,21 @@ void Edit3DWidget::showVisibilityTogglesMenu(bool show, const QPoint &pos)
m_visibilityTogglesMenu->close();
}
QMenu *Edit3DWidget::backgroundColorMenu() const
{
return m_backgroundColorMenu.data();
}
void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos)
{
if (m_backgroundColorMenu.isNull())
return;
if (show)
m_backgroundColorMenu->popup(pos);
else
m_backgroundColorMenu->close();
}
void Edit3DWidget::linkActivated(const QString &link)
{
Q_UNUSED(link)

View File

@@ -51,6 +51,9 @@ public:
QMenu *visibilityTogglesMenu() const;
void showVisibilityTogglesMenu(bool show, const QPoint &pos);
QMenu *backgroundColorMenu() const;
void showBackgroundColorMenu(bool show, const QPoint &pos);
protected:
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
void dropEvent(QDropEvent *dropEvent) override;
@@ -65,6 +68,7 @@ private:
QPointer<ToolBox> m_toolBox;
Core::IContext *m_context = nullptr;
QPointer<QMenu> m_visibilityTogglesMenu;
QPointer<QMenu> m_backgroundColorMenu;
};
} // namespace QmlDesigner

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

View File

@@ -401,7 +401,6 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
qmlInfo.append(outDir.relativeFilePath(qmlIt.filePath()));
qmlInfo.append('\n');
// Generate item library icon for qml file based on root component
QFile qmlFile(qmlIt.filePath());
if (qmlFile.open(QIODevice::ReadOnly)) {
QString iconFileName = outDir.path() + '/'
@@ -410,6 +409,8 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
QString iconFileName2x = iconFileName + "@2x";
QByteArray content = qmlFile.readAll();
int braceIdx = content.indexOf('{');
QString impVersionStr;
int impVersionMajor = -1;
if (braceIdx != -1) {
int nlIdx = content.lastIndexOf('\n', braceIdx);
QByteArray rootItem = content.mid(nlIdx, braceIdx - nlIdx).trimmed();
@@ -423,8 +424,9 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
out << "canBeDroppedInView3D: true" << Qt::endl;
file.close();
// Add quick3D import unless it is already added
if (m_requiredImports.first().url() != "QtQuick3D") {
// Assume that all assets import the same QtQuick3D version,
// since they are being imported with same kit
if (impVersionMajor == -1) {
QByteArray import3dStr{"import QtQuick3D"};
int importIdx = content.indexOf(import3dStr);
if (importIdx != -1 && importIdx < braceIdx) {
@@ -433,15 +435,25 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
QByteArray versionStr = content.mid(importIdx, nlIdx - importIdx).trimmed();
// There could be 'as abc' after version, so just take first part
QList<QByteArray> parts = versionStr.split(' ');
QString impVersion;
if (parts.size() >= 1)
impVersion = QString::fromUtf8(parts[0]);
m_requiredImports.prepend(Import::createLibraryImport(
"QtQuick3D", impVersion));
if (parts.size() >= 1) {
impVersionStr = QString::fromUtf8(parts[0]);
if (impVersionStr.isEmpty())
impVersionMajor = 6;
else
impVersionMajor = impVersionStr.left(1).toInt();
}
}
}
// Add quick3D import unless it is already added
if (impVersionMajor > 0
&& m_requiredImports.first().url() != "QtQuick3D") {
m_requiredImports.prepend(Import::createLibraryImport(
"QtQuick3D", impVersionStr));
}
}
if (startIconProcess(24, iconFileName, qmlIt.filePath())) {
if (impVersionMajor > 0 && impVersionMajor < 6
&& startIconProcess(24, iconFileName, qmlIt.filePath())) {
// Since icon is generated by external process, the file won't be
// ready for asset gathering below, so assume its generation succeeds
// and add it now.

View File

@@ -92,7 +92,9 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS
}
},
Qt::QueuedConnection);
});
},
"libIcon",
ImageCache::LibraryIconAuxiliaryData{true});
return response.release();
}

View File

@@ -30,12 +30,6 @@
#include <asynchronousimagecache.h>
#include <bindingproperty.h>
#include <coreplugin/icore.h>
#include <imagecache/imagecachecollector.h>
#include <imagecache/imagecacheconnectionmanager.h>
#include <imagecache/imagecachefontcollector.h>
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
#include <imagecache/timestampprovider.h>
#include <import.h>
#include <nodelistproperty.h>
#include <projectexplorer/kit.h>
@@ -44,7 +38,6 @@
#include <projectexplorer/target.h>
#include <rewriterview.h>
#include <sqlitedatabase.h>
#include <synchronousimagecache.h>
#include <utils/algorithm.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
@@ -52,38 +45,9 @@
namespace QmlDesigner {
namespace {
ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
{
if (project)
return project->activeTarget();
return {};
}
} // namespace
class ItemLibraryView::ImageCacheData
{
public:
Sqlite::Database database{Utils::PathString{
Core::ICore::cacheResourcePath("imagecache-v2.db").toString()},
Sqlite::JournalMode::Wal,
Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}};
ImageCacheFontCollector fontCollector;
ImageCacheGenerator generator{collector, storage};
ImageCacheGenerator fontGenerator{fontCollector, storage};
TimeStampProvider timeStampProvider;
AsynchronousImageCache cache{storage, generator, timeStampProvider};
AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider};
SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector};
};
ItemLibraryView::ItemLibraryView(QObject* parent)
: AbstractView(parent)
ItemLibraryView::ItemLibraryView(AsynchronousImageCache &imageCache)
: AbstractView()
, m_imageCache(imageCache)
{}
ItemLibraryView::~ItemLibraryView()
@@ -97,11 +61,8 @@ bool ItemLibraryView::hasWidget() const
WidgetInfo ItemLibraryView::widgetInfo()
{
if (m_widget.isNull()) {
m_widget = new ItemLibraryWidget{imageCacheData()->cache,
imageCacheData()->asynchronousFontImageCache,
imageCacheData()->synchronousFontImageCache};
}
if (m_widget.isNull())
m_widget = new ItemLibraryWidget{m_imageCache};
return createWidgetInfo(m_widget.data(), "Components", WidgetInfo::LeftPane, 0, tr("Components"));
}
@@ -177,43 +138,6 @@ void ItemLibraryView::usedImportsChanged(const QList<Import> &usedImports)
m_widget->updateUsedImports(usedImports);
}
ItemLibraryView::ImageCacheData *ItemLibraryView::imageCacheData()
{
std::call_once(imageCacheFlag, [this]() {
m_imageCacheData = std::make_unique<ImageCacheData>();
auto setTargetInImageCache =
[imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) {
if (target == imageCacheData->collector.target())
return;
if (target)
imageCacheData->cache.clean();
imageCacheData->collector.setTarget(target);
};
if (auto project = ProjectExplorer::SessionManager::startupProject(); project) {
m_imageCacheData->collector.setTarget(project->activeTarget());
connect(project,
&ProjectExplorer::Project::activeTargetChanged,
this,
setTargetInImageCache);
}
connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged,
this,
[=](ProjectExplorer::Project *project) {
setTargetInImageCache(activeTarget(project));
});
});
return m_imageCacheData.get();
}
AsynchronousImageCache &ItemLibraryView::imageCache()
{
return imageCacheData()->cache;
}
void ItemLibraryView::documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &)
{
if (m_hasErrors && errors.isEmpty())

View File

@@ -29,19 +29,16 @@
#include <QPointer>
#include <mutex>
namespace QmlDesigner {
class ItemLibraryWidget;
class AsynchronousImageCache;
class ItemLibraryView : public AbstractView
{
Q_OBJECT
public:
ItemLibraryView(QObject* parent = nullptr);
ItemLibraryView(class AsynchronousImageCache &imageCache);
~ItemLibraryView() override;
bool hasWidget() const override;
@@ -58,17 +55,11 @@ public:
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
AsynchronousImageCache &imageCache();
protected:
void updateImports();
private:
class ImageCacheData;
ImageCacheData *imageCacheData();
std::once_flag imageCacheFlag;
std::unique_ptr<ImageCacheData> m_imageCacheData;
AsynchronousImageCache &m_imageCache;
QPointer<ItemLibraryWidget> m_widget;
bool m_hasErrors = false;
QVariantMap m_importableExtensions3DMap;

View File

@@ -140,18 +140,13 @@ void ItemLibraryWidget::resizeEvent(QResizeEvent *event)
isHorizontalLayout = event->size().width() >= HORIZONTAL_LAYOUT_WIDTH_LIMIT;
}
ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache)
ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
: m_itemIconSize(24, 24)
, m_fontImageCache(synchronousFontImageCache)
, m_itemLibraryModel(new ItemLibraryModel(this))
, m_addModuleModel(new ItemLibraryAddImportModel(this))
, m_itemsWidget(new QQuickWidget(this))
, m_imageCache{imageCache}
{
Q_UNUSED(asynchronousFontImageCache)
m_compressionTimer.setInterval(200);
m_compressionTimer.setSingleShot(true);
ItemLibraryModel::registerQmlTypes();

View File

@@ -56,7 +56,6 @@ class Model;
class ItemLibraryModel;
class ItemLibraryAddImportModel;
class ItemLibraryResourceView;
class SynchronousImageCache;
class AsynchronousImageCache;
class ImageCacheCollector;
@@ -67,9 +66,7 @@ class ItemLibraryWidget : public QFrame
public:
Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged)
ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache);
ItemLibraryWidget(AsynchronousImageCache &imageCache);
~ItemLibraryWidget();
void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo);
@@ -115,7 +112,6 @@ private:
QTimer m_compressionTimer;
QSize m_itemIconSize;
SynchronousImageCache &m_fontImageCache;
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
QPointer<ItemLibraryModel> m_itemLibraryModel;

View File

@@ -29,6 +29,7 @@
#include "materialeditorcontextobject.h"
#include "propertyeditorvalue.h"
#include "materialeditortransaction.h"
#include "assetslibrarywidget.h"
#include <qmldesignerconstants.h>
#include <qmltimeline.h>
@@ -809,6 +810,39 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr
}
}
void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highlight)
{
DesignerPropertyMap &propMap = m_qmlBackEnd->backendValuesPropertyMap();
const QStringList propNames = propMap.keys();
for (const QString &propName : propNames) {
if (propName.endsWith("Map")) {
QObject *propEditorValObj = propMap.value(propName).value<QObject *>();
PropertyEditorValue *propEditorVal = qobject_cast<PropertyEditorValue *>(propEditorValObj);
propEditorVal->setHasActiveDrag(highlight);
}
}
}
void MaterialEditorView::dragStarted(QMimeData *mimeData)
{
if (!mimeData->hasFormat(Constants::MIME_TYPE_ASSETS))
return;
const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',')[0];
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType != Constants::MIME_TYPE_ASSET_IMAGE) // currently only image assets have dnd-supported properties
return;
highlightSupportedProperties();
}
void MaterialEditorView::dragEnded()
{
highlightSupportedProperties(false);
}
// from model to material editor
void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value)
{

View File

@@ -73,6 +73,9 @@ public:
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void dragStarted(QMimeData *mimeData) override;
void dragEnded() override;
void changeValue(const QString &name);
void changeExpression(const QString &name);
void exportPropertyAsAlias(const QString &name);
@@ -93,6 +96,7 @@ private:
static QString materialEditorResourcesPath();
void reloadQml();
void highlightSupportedProperties(bool highlight = true);
QString generateIdFromName(const QString &name);
void ensureMaterialLibraryNode();

View File

@@ -274,6 +274,19 @@ bool PropertyEditorValue::isTranslated() const
return false;
}
bool PropertyEditorValue::hasActiveDrag() const
{
return m_hasActiveDrag;
}
void PropertyEditorValue::setHasActiveDrag(bool val)
{
if (m_hasActiveDrag != val) {
m_hasActiveDrag = val;
emit hasActiveDragChanged();
}
}
static bool isAllowedSubclassType(const QString &type, const QmlDesigner::NodeMetaInfo &metaInfo)
{
if (!metaInfo.isValid())
@@ -371,18 +384,6 @@ void PropertyEditorValue::setEnumeration(const QString &scope, const QString &na
setValueWithEmit(QVariant::fromValue(newEnumeration));
}
bool PropertyEditorValue::isSupportedDrop(const QString &path)
{
QString suffix = "*." + QFileInfo(path).suffix().toLower();
if (m_modelNode.isSubclassOf("QtQuick3D.Material") && nameAsQString().endsWith("Map"))
return QmlDesigner::AssetsLibraryModel::supportedImageSuffixes().contains(suffix);
// TODO: handle support for other object properties dnd here (like image source)
return false;
}
void PropertyEditorValue::exportPropertyAsAlias()
{
emit exportPropertyAsAliasRequested(nameAsQString());

View File

@@ -82,6 +82,7 @@ class PropertyEditorValue : public QObject
Q_PROPERTY(bool isBound READ isBound NOTIFY isBoundChanged FINAL)
Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged FINAL)
Q_PROPERTY(bool isTranslated READ isTranslated NOTIFY expressionChanged FINAL)
Q_PROPERTY(bool hasActiveDrag READ hasActiveDrag WRITE setHasActiveDrag NOTIFY hasActiveDragChanged FINAL)
Q_PROPERTY(bool isIdList READ isIdList NOTIFY expressionChanged FINAL)
Q_PROPERTY(QStringList expressionAsList READ getExpressionAsList NOTIFY expressionChanged FINAL)
@@ -117,6 +118,9 @@ public:
bool isTranslated() const;
bool hasActiveDrag() const;
void setHasActiveDrag(bool val);
bool isAvailable() const;
QmlDesigner::PropertyName name() const;
@@ -148,7 +152,6 @@ public:
public slots:
void resetValue();
void setEnumeration(const QString &scope, const QString &name);
bool isSupportedDrop(const QString &path);
signals:
void valueChanged(const QString &name, const QVariant&);
@@ -164,6 +167,7 @@ signals:
void isBoundChanged();
void isValidChanged();
void isExplicitChanged();
void hasActiveDragChanged();
private:
QStringList generateStringList(const QString &string) const;
@@ -176,6 +180,7 @@ private:
bool m_isInSubState;
bool m_isInModel;
bool m_isBound;
bool m_hasActiveDrag = false;
bool m_isValid; // if the property value belongs to a non-existing complexProperty it is invalid
PropertyEditorNodeWrapper *m_complexNode;
};

View File

@@ -74,7 +74,7 @@ ImageCacheCollector::~ImageCacheCollector() = default;
void ImageCacheCollector::start(Utils::SmallStringView name,
Utils::SmallStringView state,
const ImageCache::AuxiliaryData &,
const ImageCache::AuxiliaryData &auxiliaryData,
CaptureCallback captureCallback,
AbortCallback abortCallback)
{
@@ -96,13 +96,22 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
model->setRewriterView(&rewriterView);
bool is3DRoot = !rewriterView.inErrorState()
&& (rewriterView.rootModelNode().isSubclassOf("Quick3D.Node")
|| rewriterView.rootModelNode().isSubclassOf("Quick3D.Material"));
if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem()
&& !rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") )) {
&& !is3DRoot)) {
if (abortCallback)
abortCallback(ImageCache::AbortReason::Failed);
return;
}
if (is3DRoot) {
if (auto libIcon = Utils::get_if<ImageCache::LibraryIconAuxiliaryData>(&auxiliaryData))
rewriterView.rootModelNode().setAuxiliaryData("isLibraryIcon@NodeInstance", libIcon->enable);
}
ModelNode stateNode = rewriterView.modelNodeForId(QString{state});
if (stateNode.isValid())

View File

@@ -54,7 +54,16 @@ public:
QString text;
};
using AuxiliaryData = Utils::variant<Utils::monostate, FontCollectorSizeAuxiliaryData, FontCollectorSizesAuxiliaryData>;
class LibraryIconAuxiliaryData
{
public:
bool enable;
};
using AuxiliaryData = Utils::variant<Utils::monostate,
LibraryIconAuxiliaryData,
FontCollectorSizeAuxiliaryData,
FontCollectorSizesAuxiliaryData>;
enum class AbortReason : char { Abort, Failed };

View File

@@ -35,6 +35,7 @@
#include <import.h>
QT_BEGIN_NAMESPACE
class QPixmap;
class QUrl;
QT_END_NAMESPACE
@@ -44,7 +45,7 @@ namespace Internal {
class ModelPrivate;
class WriteLocker;
class NodeMetaInfoPrivate;
} //Internal
} // namespace Internal
class AnchorLine;
class ModelNode;
@@ -130,7 +131,7 @@ public:
QString generateNewId(const QString &prefixName) const;
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const;
void startDrag(QMimeData *mimeData, const QString iconPath = {});
void startDrag(QMimeData *mimeData, const QPixmap &icon);
void endDrag();
protected:
@@ -140,4 +141,4 @@ private:
Internal::ModelPrivate *d;
};
}
} // namespace QmlDesigner

View File

@@ -47,12 +47,11 @@ class Edit3DView;
namespace Internal { class DesignModeWidget; }
class ViewManagerData;
class AsynchronousImageCache;
class QMLDESIGNERCORE_EXPORT ViewManager
{
public:
ViewManager();
ViewManager(class AsynchronousImageCache &imageCache);
~ViewManager();
void attachRewriterView();
@@ -107,8 +106,6 @@ public:
void disableStandardViews();
void enableStandardViews();
AsynchronousImageCache &imageCache();
private: // functions
Q_DISABLE_COPY(ViewManager)

View File

@@ -600,11 +600,9 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP
// Reset puppet when particle emitter/affector is reparented to work around issue in
// autodetecting the particle system it belongs to. QTBUG-101157
// Reset is also needed when particle shapes are reparented. QTBUG-101882
if (((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D")
if ((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D")
|| node.isSubclassOf("QtQuick.Particles3D.Affector3D"))
&& node.property("system").toBindingProperty().expression().isEmpty())
|| node.isSubclassOf("QQuick3DParticleAbstractShape")) {
&& node.property("system").toBindingProperty().expression().isEmpty()) {
resetPuppet();
}
}
@@ -987,6 +985,17 @@ QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList)
return filteredNodeList;
}
QList<QColor> readBackgroundColorConfiguration(const QVariant &var)
{
if (!var.isValid())
return {};
auto colorNameList = var.value<QList<QString>>();
QTC_ASSERT(colorNameList.size() == 2, return {});
return {colorNameList[0], colorNameList[1]};
}
CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
{
QList<ModelNode> nodeList = allModelNodes();
@@ -1141,6 +1150,17 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0))
stateInstanceId = stateNode.internalId();
auto value
#ifndef QMLDESIGNER_TEST
= QmlDesigner::DesignerSettings::getValue(
QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR);
#else
= QColor();
#endif
QList<QColor> edit3dBackgroundColor;
if (value.isValid())
edit3dBackgroundColor = readBackgroundColorConfiguration(value);
return CreateSceneCommand(
instanceContainerList,
reparentContainerList,
@@ -1161,7 +1181,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
lastUsedLanguage,
m_captureImageMinimumSize,
m_captureImageMaximumSize,
stateInstanceId);
stateInstanceId,
edit3dBackgroundColor);
}
ClearSceneCommand NodeInstanceView::createClearSceneCommand() const
@@ -2190,9 +2211,8 @@ void NodeInstanceView::maybeResetOnPropertyChange(const PropertyName &name, cons
{
bool reset = false;
if (flags & AbstractView::PropertiesAdded
&& name == "model" && (node.isSubclassOf("QtQuick.Repeater")
|| node.isSubclassOf("QtQuick3D.Repeater3D"))) {
// TODO: This is a workaround for QTBUG-97583 (2D) and QTBUG-97586 (3D):
&& name == "model" && node.isSubclassOf("QtQuick.Repeater")) {
// TODO: This is a workaround for QTBUG-97583:
// Reset puppet when repeater model is first added, if there is already a delegate
if (node.hasProperty("delegate"))
reset = true;

View File

@@ -452,10 +452,9 @@ void SubComponentManager::parseQuick3DAssetsItem(const QString &importUrl, const
QString iconPath = qmlIt.fileInfo().absolutePath() + '/'
+ Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name
+ Constants::QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX;
if (!QFileInfo::exists(iconPath))
iconPath = defaultIconPath;
itemLibraryEntry.setLibraryEntryIconPath(iconPath);
itemLibraryEntry.setTypeIcon(QIcon(iconPath));
if (QFileInfo::exists(iconPath))
itemLibraryEntry.setLibraryEntryIconPath(iconPath);
itemLibraryEntry.setTypeIcon(QIcon(defaultIconPath));
// load hints file if exists
QFile hintsFile(qmlIt.fileInfo().absolutePath() + '/' + name + ".hints");

View File

@@ -1510,12 +1510,12 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP
return newId;
}
void Model::startDrag(QMimeData *mimeData, const QString iconPath)
void Model::startDrag(QMimeData *mimeData, const QPixmap &icon)
{
d->notifyDragStarted(mimeData);
auto drag = new QDrag(this);
drag->setPixmap(iconPath);
drag->setPixmap(icon);
drag->setMimeData(mimeData);
drag->exec();
drag->deleteLater();

View File

@@ -62,6 +62,10 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg)
class ViewManagerData
{
public:
ViewManagerData(AsynchronousImageCache &imageCache)
: itemLibraryView(imageCache)
{}
InteractiveConnectionManager connectionManager;
CapturingConnectionManager capturingConnectionManager;
QmlModelState savedState;
@@ -90,12 +94,13 @@ static CrumbleBar *crumbleBar() {
return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar();
}
ViewManager::ViewManager()
: d(std::make_unique<ViewManagerData>())
ViewManager::ViewManager(AsynchronousImageCache &imageCache)
: d(std::make_unique<ViewManagerData>(imageCache))
{
d->formEditorView.setGotoErrorCallback([this](int line, int column) {
d->textEditorView.gotoCursorPosition(line, column);
if (Internal::DesignModeWidget *designModeWidget = QmlDesignerPlugin::instance()->mainWidget())
if (Internal::DesignModeWidget *designModeWidget = QmlDesignerPlugin::instance()
->mainWidget())
designModeWidget->showDockWidget("TextEditor");
});
}
@@ -439,11 +444,6 @@ void ViewManager::enableStandardViews()
attachViewsExceptRewriterAndComponetView();
}
AsynchronousImageCache &ViewManager::imageCache()
{
return d->itemLibraryView.imageCache();
}
void ViewManager::addView(std::unique_ptr<AbstractView> &&view)
{
d->additionalViews.push_back(std::move(view));

View File

@@ -80,6 +80,7 @@ void DesignerSettings::fromSettings(QSettings *settings)
restoreValue(settings, DesignerSettingsKey::ALWAYS_DESIGN_MODE, true);
restoreValue(settings, DesignerSettingsKey::DISABLE_ITEM_LIBRARY_UPDATE_TIMER, false);
restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, QList<QString>{"#222222", "#999999"});
settings->endGroup();
settings->endGroup();

View File

@@ -49,6 +49,7 @@ const char WARNING_FOR_QML_FILES_INSTEAD_OF_UIQML_FILES[] = "WarnAboutQmlFilesIn
const char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[] = "WarnAboutQtQuickDesignerFeaturesInCodeEditor";
const char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView";
const char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView";
const char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor";
const char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar";
const char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet";
const char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory";

View File

@@ -65,6 +65,8 @@ const char EDIT3D_EDIT_CAMERA[] = "QmlDesigner.Editor3D.EditCameraToggle";
const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle";
const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle";
const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid";
const char EDIT3D_EDIT_SELECT_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.SelectBackgroundColor";
const char EDIT3D_EDIT_RESET_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.ResetBackgroundColor";
const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox";
const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo";
const char EDIT3D_EDIT_SHOW_CAMERA_FRUSTUM[] = "QmlDesigner.Editor3D.ToggleCameraFrustum";
@@ -74,6 +76,7 @@ const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeTo
const char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay";
const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart";
const char EDIT3D_VISIBILITY_TOGGLES[] = "QmlDesigner.Editor3D.VisibilityToggles";
const char EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundColorActions";
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";

View File

@@ -91,6 +91,8 @@ const Utils::Icon EDIT3D_ALIGN_CAMERA_ON({
{":/edit3d/images/align_camera_on.png", Utils::Theme::IconsBaseColor}});
const Utils::Icon EDIT3D_ALIGN_VIEW_ON({
{":/edit3d/images/align_view_on.png", Utils::Theme::IconsBaseColor}});
const Utils::Icon COLOR_PALETTE({
{":/edit3d/images/color_palette.png", Utils::Theme::IconsBaseColor}});
} // Icons
} // QmlDesigner

View File

@@ -135,7 +135,7 @@ class QmlDesignerPluginPrivate
{
public:
QmlDesignerProjectManager projectManager;
ViewManager viewManager;
ViewManager viewManager{projectManager.asynchronousImageCache()};
DocumentManager documentManager;
ShortCutManager shortCutManager;
SettingsPage settingsPage;
@@ -666,7 +666,7 @@ void QmlDesignerPlugin::emitUsageStatisticsHelpRequested(const QString &identifi
AsynchronousImageCache &QmlDesignerPlugin::imageCache()
{
return m_instance->d->viewManager.imageCache();
return m_instance->d->projectManager.asynchronousImageCache();
}
void QmlDesignerPlugin::registerPreviewImageProvider(QQmlEngine *engine)

View File

@@ -526,6 +526,8 @@ Project {
"debugview/debugviewwidget.ui",
"edit3d/edit3dview.cpp",
"edit3d/edit3dview.h",
"edit3d/backgroundcolorselection.cpp",
"edit3d/backgroundcolorselection.h",
"edit3d/edit3dwidget.cpp",
"edit3d/edit3dwidget.h",
"edit3d/edit3dcanvas.cpp",

View File

@@ -44,6 +44,7 @@
#include <qtsupport/qtkitinformation.h>
#include <asynchronousexplicitimagecache.h>
#include <asynchronousimagecache.h>
#include <imagecache/asynchronousimagefactory.h>
#include <imagecache/explicitimagecacheimageprovider.h>
#include <imagecache/imagecachecollector.h>
@@ -60,6 +61,14 @@ namespace QmlDesigner {
namespace {
ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
{
if (project)
return project->activeTarget();
return {};
}
QString defaultImagePath()
{
return Core::ICore::resourcePath("qmldesigner/welcomepage/images/newThumbnail.png").toString();
@@ -89,7 +98,22 @@ public:
} // namespace
class PreviewImageCacheData
class QmlDesignerProjectManager::ImageCacheData
{
public:
Sqlite::Database database{Utils::PathString{
Core::ICore::cacheResourcePath("imagecache-v2.db").toString()},
Sqlite::JournalMode::Wal,
Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}};
ImageCacheGenerator generator{collector, storage};
TimeStampProvider timeStampProvider;
AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider};
};
class QmlDesignerProjectManager::PreviewImageCacheData
{
public:
Sqlite::Database database{Utils::PathString{
@@ -100,7 +124,7 @@ public:
AsynchronousExplicitImageCache cache{storage};
};
class QmlDesignerProjectManagerProjectData
class QmlDesignerProjectManager::QmlDesignerProjectManagerProjectData
{
public:
QmlDesignerProjectManagerProjectData(ImageCacheStorage<Sqlite::Database> &storage)
@@ -117,7 +141,7 @@ public:
};
QmlDesignerProjectManager::QmlDesignerProjectManager()
: m_imageCacheData{std::make_unique<PreviewImageCacheData>()}
: m_previewImageCacheData{std::make_unique<PreviewImageCacheData>()}
{
auto editorManager = ::Core::EditorManager::instance();
QObject::connect(editorManager, &::Core::EditorManager::editorOpened, [&](auto *editor) {
@@ -145,12 +169,17 @@ QmlDesignerProjectManager::~QmlDesignerProjectManager() = default;
void QmlDesignerProjectManager::registerPreviewImageProvider(QQmlEngine *engine) const
{
auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(m_imageCacheData->cache,
auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(m_previewImageCacheData->cache,
QImage{defaultImagePath()});
engine->addImageProvider("project_preview", imageProvider.release());
}
AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache()
{
return imageCacheData()->asynchronousImageCache;
}
void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {}
void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *)
@@ -171,7 +200,7 @@ void QmlDesignerProjectManager::editorsClosed(const QList<::Core::IEditor *> &)
void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project)
{
m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_imageCacheData->storage);
m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage);
m_projectData->activeTarget = project->activeTarget();
}
@@ -183,4 +212,36 @@ void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project
void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {}
QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCacheData()
{
std::call_once(imageCacheFlag, [this]() {
m_imageCacheData = std::make_unique<ImageCacheData>();
auto setTargetInImageCache =
[imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) {
if (target == imageCacheData->collector.target())
return;
if (target)
imageCacheData->asynchronousImageCache.clean();
imageCacheData->collector.setTarget(target);
};
if (auto project = ProjectExplorer::SessionManager::startupProject(); project) {
m_imageCacheData->collector.setTarget(project->activeTarget());
QObject::connect(project,
&ProjectExplorer::Project::activeTargetChanged,
this,
setTargetInImageCache);
}
QObject::connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged,
this,
[=](ProjectExplorer::Project *project) {
setTargetInImageCache(activeTarget(project));
});
});
return m_imageCacheData.get();
}
} // namespace QmlDesigner

View File

@@ -26,8 +26,10 @@
#pragma once
#include <QList>
#include <QObject>
#include <memory>
#include <mutex>
QT_FORWARD_DECLARE_CLASS(QQmlEngine)
@@ -42,17 +44,22 @@ class Target;
namespace QmlDesigner {
class QmlDesignerProjectManagerProjectData;
class PreviewImageCacheData;
class QmlDesignerProjectManager
class QmlDesignerProjectManager : public QObject
{
Q_OBJECT
class QmlDesignerProjectManagerProjectData;
class PreviewImageCacheData;
class ImageCacheData;
public:
QmlDesignerProjectManager();
~QmlDesignerProjectManager();
void registerPreviewImageProvider(QQmlEngine *engine) const;
class AsynchronousImageCache &asynchronousImageCache();
private:
void editorOpened(::Core::IEditor *editor);
void currentEditorChanged(::Core::IEditor *);
@@ -60,9 +67,12 @@ private:
void projectAdded(::ProjectExplorer::Project *project);
void aboutToRemoveProject(::ProjectExplorer::Project *project);
void projectRemoved(::ProjectExplorer::Project *project);
ImageCacheData *imageCacheData();
private:
std::unique_ptr<PreviewImageCacheData> m_imageCacheData;
std::once_flag imageCacheFlag;
std::unique_ptr<ImageCacheData> m_imageCacheData;
std::unique_ptr<PreviewImageCacheData> m_previewImageCacheData;
std::unique_ptr<QmlDesignerProjectManagerProjectData> m_projectData;
};
} // namespace QmlDesigner

View File

@@ -57,6 +57,12 @@
using namespace Utils;
static bool enableDownload()
{
const QString lastQDSVersionEntry = "QML/Designer/EnableWelcomePageDownload";
return Core::ICore::settings()->value(lastQDSVersionEntry, false).toBool();
}
void ExampleCheckout::registerTypes()
{
static bool once = []() {
@@ -186,6 +192,12 @@ bool FileDownloader::available() const
void FileDownloader::probeUrl()
{
if (!enableDownload()) {
m_available = false;
emit availableChanged();
return;
}
auto request = QNetworkRequest(m_url);
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::UserVerifiedRedirectPolicy);
@@ -448,6 +460,13 @@ DataModelDownloader::DataModelDownloader(QObject * /* parent */)
void DataModelDownloader::start()
{
if (!enableDownload()) {
m_available = false;
emit availableChanged();
return;
}
m_fileDownloader.setUrl(QUrl::fromUserInput(
"https://download.qt.io/learning/examples/qtdesignstudio/dataImports.zip"));