forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/8.0'
Conflicts: .github/workflows/build_cmake.yml src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp src/plugins/qmldesigner/components/materialeditor/materialeditorview.h src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp src/plugins/qmldesigner/designercore/model/model.cpp Change-Id: I111b9140375b894a5487cc012b17cc32100bdb8d
This commit is contained in:
2
.github/workflows/build_cmake.yml
vendored
2
.github/workflows/build_cmake.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- 'doc/**'
|
- 'doc/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 6.3.1
|
QT_VERSION: 6.3.2
|
||||||
CLANG_VERSION: 15.0.0
|
CLANG_VERSION: 15.0.0
|
||||||
ELFUTILS_VERSION: 0.175
|
ELFUTILS_VERSION: 0.175
|
||||||
CMAKE_VERSION: 3.21.1
|
CMAKE_VERSION: 3.21.1
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ instructions:
|
|||||||
instructions:
|
instructions:
|
||||||
- type: EnvironmentVariable
|
- type: EnvironmentVariable
|
||||||
variableName: QTC_QT_BASE_URL
|
variableName: QTC_QT_BASE_URL
|
||||||
variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.3/6.3.1-final-released/Qt6.3.1"
|
variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.3/6.3.2-final-released/Qt"
|
||||||
- type: EnvironmentVariable
|
- type: EnvironmentVariable
|
||||||
variableName: QTC_QT_MODULES
|
variableName: QTC_QT_MODULES
|
||||||
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations qtwebengine"
|
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations qtwebengine"
|
||||||
|
|||||||
BIN
doc/qtdesignstudio/images/icons/3d-background-color.png
Normal file
BIN
doc/qtdesignstudio/images/icons/3d-background-color.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 335 B |
@@ -264,6 +264,28 @@
|
|||||||
selected in the \uicontrol{3D} view.
|
selected in the \uicontrol{3D} view.
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
\section1 Changing Colors
|
||||||
|
|
||||||
|
To change the \uicontrol 3D view background or grid color, select
|
||||||
|
\inlineimage icons/3d-background-color.png
|
||||||
|
in the toolbar. This opens a menu with the following options:
|
||||||
|
|
||||||
|
\table
|
||||||
|
\row
|
||||||
|
\li Select Background Color
|
||||||
|
\li Select a color for the background.
|
||||||
|
\row
|
||||||
|
\li Select Grid Color
|
||||||
|
\li Select a color for the grid.
|
||||||
|
\row
|
||||||
|
\li Use Scene Environment Color
|
||||||
|
\li Sets the 3D view to use the scene environment color as background
|
||||||
|
color.
|
||||||
|
\row
|
||||||
|
\li Reset Colors
|
||||||
|
\li Resets the background and grid colors to the default colors.
|
||||||
|
\endtable
|
||||||
|
|
||||||
\section1 Particle Editor
|
\section1 Particle Editor
|
||||||
|
|
||||||
The particle editor tools help you preview your particle systems in
|
The particle editor tools help you preview your particle systems in
|
||||||
@@ -359,6 +381,11 @@
|
|||||||
\li Visibility Toggles
|
\li Visibility Toggles
|
||||||
\li
|
\li
|
||||||
\li \l{Toggling Visibility}
|
\li \l{Toggling Visibility}
|
||||||
|
\row
|
||||||
|
\li \inlineimage icons/3d-background-color.png
|
||||||
|
\li Background Color Actions
|
||||||
|
\li
|
||||||
|
\li \l{Changing Colors}
|
||||||
\row
|
\row
|
||||||
\li \inlineimage icons/particles-seek.png
|
\li \inlineimage icons/particles-seek.png
|
||||||
\li Seek Particle System Time
|
\li Seek Particle System Time
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public:
|
|||||||
ActiveSceneChanged,
|
ActiveSceneChanged,
|
||||||
RenderModelNodePreviewImage,
|
RenderModelNodePreviewImage,
|
||||||
Import3DSupport,
|
Import3DSupport,
|
||||||
ModelAtPos,
|
NodeAtPos,
|
||||||
None };
|
None };
|
||||||
|
|
||||||
PuppetToCreatorCommand(Type type, const QVariant &data);
|
PuppetToCreatorCommand(Type type, const QVariant &data);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
SelectGridColor,
|
SelectGridColor,
|
||||||
ResetBackgroundColor,
|
ResetBackgroundColor,
|
||||||
SyncBackgroundColor,
|
SyncBackgroundColor,
|
||||||
GetModelAtPos
|
GetNodeAtPos
|
||||||
};
|
};
|
||||||
|
|
||||||
View3DActionCommand(Type type, const QVariant &value);
|
View3DActionCommand(Type type, const QVariant &value);
|
||||||
|
|||||||
@@ -525,6 +525,19 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function gizmoAt(x, y)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < lightIconGizmos.length; ++i) {
|
||||||
|
if (lightIconGizmos[i].visible && lightIconGizmos[i].hasPoint(x, y))
|
||||||
|
return lightIconGizmos[i].targetNode;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < cameraGizmos.length; ++i) {
|
||||||
|
if (cameraGizmos[i].visible && cameraGizmos[i].hasPoint(x, y))
|
||||||
|
return cameraGizmos[i].targetNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
createEditView();
|
createEditView();
|
||||||
selectObjects([]);
|
selectObjects([]);
|
||||||
|
|||||||
@@ -30,6 +30,17 @@ Item {
|
|||||||
|
|
||||||
signal clicked(Node node, bool multi)
|
signal clicked(Node node, bool multi)
|
||||||
|
|
||||||
|
function hasPoint(x, y)
|
||||||
|
{
|
||||||
|
if (!view3D || !targetNode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var point = view3D.mapToItem(iconMouseArea, x, y);
|
||||||
|
|
||||||
|
return point.x >= iconMouseArea.x && (point.x <= iconMouseArea.x + iconMouseArea.width)
|
||||||
|
&& point.y >= iconMouseArea.y && (point.y <= iconMouseArea.y + iconMouseArea.height);
|
||||||
|
}
|
||||||
|
|
||||||
onSelectedChanged: {
|
onSelectedChanged: {
|
||||||
if (selected)
|
if (selected)
|
||||||
hasMouse = false;
|
hasMouse = false;
|
||||||
|
|||||||
@@ -648,6 +648,23 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function gizmoAt(x, y)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < lightIconGizmos.length; ++i) {
|
||||||
|
if (lightIconGizmos[i].visible && lightIconGizmos[i].hasPoint(x, y))
|
||||||
|
return lightIconGizmos[i].targetNode;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < cameraGizmos.length; ++i) {
|
||||||
|
if (cameraGizmos[i].visible && cameraGizmos[i].hasPoint(x, y))
|
||||||
|
return cameraGizmos[i].targetNode;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < particleSystemIconGizmos.length; ++i) {
|
||||||
|
if (particleSystemIconGizmos[i].visible && particleSystemIconGizmos[i].hasPoint(x, y))
|
||||||
|
return particleSystemIconGizmos[i].targetNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
createEditView();
|
createEditView();
|
||||||
selectObjects([]);
|
selectObjects([]);
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ Item {
|
|||||||
|
|
||||||
signal clicked(Node node, bool multi)
|
signal clicked(Node node, bool multi)
|
||||||
|
|
||||||
|
function hasPoint(x, y)
|
||||||
|
{
|
||||||
|
if (!view3D || !targetNode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var point = view3D.mapToItem(iconMouseArea, x, y);
|
||||||
|
|
||||||
|
return point.x >= iconMouseArea.x && (point.x <= iconMouseArea.x + iconMouseArea.width)
|
||||||
|
&& point.y >= iconMouseArea.y && (point.y <= iconMouseArea.y + iconMouseArea.height);
|
||||||
|
}
|
||||||
|
|
||||||
onSelectedChanged: {
|
onSelectedChanged: {
|
||||||
if (selected)
|
if (selected)
|
||||||
hasMouse = false;
|
hasMouse = false;
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ void Qt5InformationNodeInstanceServer::handleInputEvents()
|
|||||||
|
|
||||||
// Context menu requested
|
// Context menu requested
|
||||||
if (command.button() == Qt::RightButton && command.modifiers() == Qt::NoModifier)
|
if (command.button() == Qt::RightButton && command.modifiers() == Qt::NoModifier)
|
||||||
getModelAtPos(command.pos());
|
getNodeAtPos(command.pos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,7 +386,7 @@ void Qt5InformationNodeInstanceServer::removeRotationBlocks(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::getModelAtPos(const QPointF &pos)
|
void Qt5InformationNodeInstanceServer::getNodeAtPos(const QPointF &pos)
|
||||||
{
|
{
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
// pick a Quick3DModel at view position
|
// pick a Quick3DModel at view position
|
||||||
@@ -398,13 +398,25 @@ void Qt5InformationNodeInstanceServer::getModelAtPos(const QPointF &pos)
|
|||||||
QObject *obj = qvariant_cast<QObject *>(editViewProp.read());
|
QObject *obj = qvariant_cast<QObject *>(editViewProp.read());
|
||||||
QQuick3DViewport *editView = qobject_cast<QQuick3DViewport *>(obj);
|
QQuick3DViewport *editView = qobject_cast<QQuick3DViewport *>(obj);
|
||||||
|
|
||||||
QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit();
|
// Non-model nodes with icon gizmos are also valid results
|
||||||
|
QVariant gizmoVar;
|
||||||
|
QMetaObject::invokeMethod(m_editView3DData.rootItem, "gizmoAt", Qt::DirectConnection,
|
||||||
|
Q_RETURN_ARG(QVariant, gizmoVar),
|
||||||
|
Q_ARG(QVariant, pos.x()),
|
||||||
|
Q_ARG(QVariant, pos.y()));
|
||||||
|
QObject *gizmoObj = qvariant_cast<QObject *>(gizmoVar);
|
||||||
|
QVariant instance = -1;
|
||||||
|
|
||||||
// filter out picks of models created dynamically or inside components
|
if (gizmoObj && hasInstanceForObject(gizmoObj)) {
|
||||||
QQuick3DModel *resolvedPick = qobject_cast<QQuick3DModel *>(helper->resolvePick(hitModel));
|
instance = instanceForObject(gizmoObj).instanceId();
|
||||||
|
} else {
|
||||||
|
QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit();
|
||||||
|
QObject *resolvedPick = helper->resolvePick(hitModel);
|
||||||
|
if (hasInstanceForObject(resolvedPick))
|
||||||
|
instance = instanceForObject(resolvedPick).instanceId();
|
||||||
|
}
|
||||||
|
|
||||||
QVariant instance = resolvedPick ? instanceForObject(resolvedPick).instanceId() : -1;
|
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::NodeAtPos, instance});
|
||||||
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ModelAtPos, instance});
|
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(pos)
|
Q_UNUSED(pos)
|
||||||
#endif
|
#endif
|
||||||
@@ -2387,8 +2399,8 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
case View3DActionCommand::GetModelAtPos: {
|
case View3DActionCommand::GetNodeAtPos: {
|
||||||
getModelAtPos(command.value().toPointF());
|
getNodeAtPos(command.value().toPointF());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ private:
|
|||||||
void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges);
|
void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges);
|
||||||
void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges);
|
void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges);
|
||||||
void removeRotationBlocks(const QVector<qint32> &instanceIds);
|
void removeRotationBlocks(const QVector<qint32> &instanceIds);
|
||||||
void getModelAtPos(const QPointF &pos);
|
void getNodeAtPos(const QPointF &pos);
|
||||||
|
|
||||||
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
|
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
|
||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ PropertyEditorPane {
|
|||||||
|
|
||||||
Item { width: 1; height: 10 }
|
Item { width: 1; height: 10 }
|
||||||
|
|
||||||
|
DynamicPropertiesSection {
|
||||||
|
propertiesModel: MaterialEditorDynamicPropertiesModel {}
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: specificsTwo
|
id: specificsTwo
|
||||||
|
|
||||||
@@ -57,7 +61,11 @@ PropertyEditorPane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: 1; height: 10 }
|
Item {
|
||||||
|
width: 1
|
||||||
|
height: 10
|
||||||
|
visible: specificsTwo.visible
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: specificsOne
|
id: specificsOne
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
PropertyLabel {
|
||||||
|
text: "%1"
|
||||||
|
tooltip: "%1"
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
ItemFilterComboBox {
|
||||||
|
typeFilter: "QtQuick3D.%3"
|
||||||
|
validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
|
||||||
|
backendValue: backendValues.%2
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
width: implicitWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
@@ -56,4 +56,25 @@ AutoTypes {
|
|||||||
sourceFile: "ImageEditorTemplate.template"
|
sourceFile: "ImageEditorTemplate.template"
|
||||||
separateSection: true
|
separateSection: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
typeNames: ["TextureInput", "Texture"]
|
||||||
|
sourceFile: "3DItemFilterComboBoxEditorTemplate.template"
|
||||||
|
needsTypeArg: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
typeNames: ["vector2d"]
|
||||||
|
sourceFile: "Vector2dEditorTemplate.template"
|
||||||
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
typeNames: ["vector3d"]
|
||||||
|
sourceFile: "Vector3dEditorTemplate.template"
|
||||||
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
typeNames: ["vector4d"]
|
||||||
|
sourceFile: "Vector4dEditorTemplate.template"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
PropertyLabel {
|
||||||
|
text: "%1"
|
||||||
|
tooltip: "%1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_x
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "X"
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_y
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Y"
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
PropertyLabel {
|
||||||
|
text: "%1"
|
||||||
|
tooltip: "%1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_x
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "X"
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_y
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Y"
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_z
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Z"
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
PropertyLabel {
|
||||||
|
text: "%1"
|
||||||
|
tooltip: "%1"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_x
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "X"
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_y
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Y"
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_z
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Z"
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
backendValue: backendValues.%2_w
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "W"
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,10 @@ PropertyEditorPane {
|
|||||||
showState: true
|
showState: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynamicPropertiesSection {
|
||||||
|
propertiesModel: SelectionDynamicPropertiesModel {}
|
||||||
|
}
|
||||||
|
|
||||||
GeometrySection {}
|
GeometrySection {}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ PropertyEditorPane {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
DynamicPropertiesSection {
|
||||||
|
propertiesModel: SelectionDynamicPropertiesModel {}
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: specificsTwo
|
id: specificsTwo
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ SecondColumnLayout {
|
|||||||
colorEditor.backendValue.resetValue()
|
colorEditor.backendValue.resetValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initEditor() {
|
||||||
|
cePopup.initEditor()
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
id: backendConnection
|
id: backendConnection
|
||||||
target: colorEditor
|
target: colorEditor
|
||||||
|
|||||||
@@ -22,6 +22,23 @@ T.Popup {
|
|||||||
|
|
||||||
property bool isInValidState: false
|
property bool isInValidState: false
|
||||||
|
|
||||||
|
function initEditor() {
|
||||||
|
if (colorEditor.supportGradient && gradientModel.hasGradient) {
|
||||||
|
colorEditor.color = gradientLine.currentColor
|
||||||
|
gradientLine.currentColor = colorEditor.color
|
||||||
|
hexTextField.text = colorEditor.color
|
||||||
|
popupHexTextField.text = colorEditor.color
|
||||||
|
}
|
||||||
|
|
||||||
|
cePopup.isInValidState = true
|
||||||
|
colorEditor.originalColor = colorEditor.color
|
||||||
|
colorPalette.selectedColor = colorEditor.color
|
||||||
|
colorPicker.color = colorEditor.color
|
||||||
|
|
||||||
|
cePopup.createModel()
|
||||||
|
cePopup.determineActiveColorMode()
|
||||||
|
}
|
||||||
|
|
||||||
function commitGradientColor() {
|
function commitGradientColor() {
|
||||||
var hexColor = convertColorToString(colorEditor.color)
|
var hexColor = convertColorToString(colorEditor.color)
|
||||||
cePopup.popupHexTextField.text = hexColor
|
cePopup.popupHexTextField.text = hexColor
|
||||||
@@ -453,24 +470,10 @@ T.Popup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: modelNodeBackend
|
target: modelNodeBackend
|
||||||
function onSelectionChanged() {
|
function onSelectionChanged() {
|
||||||
if (colorEditor.supportGradient && gradientModel.hasGradient) {
|
cePopup.initEditor()
|
||||||
colorEditor.color = gradientLine.currentColor
|
|
||||||
gradientLine.currentColor = colorEditor.color
|
|
||||||
hexTextField.text = colorEditor.color
|
|
||||||
popupHexTextField.text = colorEditor.color
|
|
||||||
}
|
|
||||||
|
|
||||||
cePopup.isInValidState = true
|
|
||||||
colorEditor.originalColor = colorEditor.color
|
|
||||||
colorPalette.selectedColor = colorEditor.color
|
|
||||||
colorPicker.color = colorEditor.color
|
|
||||||
|
|
||||||
cePopup.createModel()
|
|
||||||
cePopup.determineActiveColorMode()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,772 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import QtQuick.Templates 2.15 as T
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
Section {
|
||||||
|
id: root
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
caption: qsTr("User Added Properties")
|
||||||
|
|
||||||
|
property DynamicPropertiesModel propertiesModel: null
|
||||||
|
|
||||||
|
property Component colorEditor: Component {
|
||||||
|
id: colorEditor
|
||||||
|
ColorEditor {
|
||||||
|
id: colorEditorControl
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
supportGradient: false
|
||||||
|
spacer.visible: false
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: colorEditorControl.remove()
|
||||||
|
}
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component intEditor: Component {
|
||||||
|
id: intEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutInt
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
maximumValue: 9999999
|
||||||
|
minimumValue: -9999999
|
||||||
|
backendValue: layoutInt.backendValue
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: 10
|
||||||
|
implicitWidth: {
|
||||||
|
return StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutInt.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component realEditor: Component {
|
||||||
|
id: realEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutReal
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
backendValue: layoutReal.backendValue
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
stepSize: 0.1
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: 10
|
||||||
|
implicitWidth: {
|
||||||
|
return StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutReal.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component stringEditor: Component {
|
||||||
|
id: stringEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutString
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
LineEdit {
|
||||||
|
backendValue: layoutString.backendValue
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutString.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component boolEditor: Component {
|
||||||
|
id: boolEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutBool
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
text: layoutBool.backendValue.value
|
||||||
|
backendValue: layoutBool.backendValue
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: 10
|
||||||
|
implicitWidth: {
|
||||||
|
return StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutBool.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component urlEditor: Component {
|
||||||
|
id: urlEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutUrl
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
UrlChooser {
|
||||||
|
backendValue: layoutUrl.backendValue
|
||||||
|
comboBox.implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
spacer.implicitWidth: StudioTheme.Values.controlLabelGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutUrl.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component aliasEditor: Component {
|
||||||
|
id: aliasEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutAlias
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
property alias lineEdit: lineEdit
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
function updateLineEditText() {
|
||||||
|
lineEdit.text = lineEdit.backendValue.expression
|
||||||
|
}
|
||||||
|
|
||||||
|
LineEdit {
|
||||||
|
id: lineEdit
|
||||||
|
backendValue: layoutAlias.backendValue
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
writeAsExpression: true
|
||||||
|
showTranslateCheckBox: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutAlias.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component textureInputEditor: Component {
|
||||||
|
id: textureInputEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutTextureInput
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
ItemFilterComboBox {
|
||||||
|
typeFilter: "QtQuick3D.TextureInput"
|
||||||
|
validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
|
||||||
|
backendValue: layoutTextureInput.backendValue
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutTextureInput.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component vectorEditor: Component {
|
||||||
|
id: vectorEditor
|
||||||
|
ColumnLayout {
|
||||||
|
id: layoutVector
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
property int vecSize: 0
|
||||||
|
property var proxyValues: []
|
||||||
|
property var spinBoxes: [boxX, boxY, boxZ, boxW]
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
onVecSizeChanged: updateProxyValues()
|
||||||
|
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
function isValidValue(v) {
|
||||||
|
return !(v === undefined || isNaN(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateExpression() {
|
||||||
|
for (let i = 0; i < vecSize; ++i) {
|
||||||
|
if (!isValidValue(proxyValues[i].value))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let expStr = "Qt.vector" + vecSize + "d("+proxyValues[0].value
|
||||||
|
for (let j=1; j < vecSize; ++j)
|
||||||
|
expStr += ", " + proxyValues[j].value
|
||||||
|
expStr += ")"
|
||||||
|
|
||||||
|
layoutVector.backendValue.expression = expStr
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProxyValues() {
|
||||||
|
if (!backendValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const startIndex = backendValue.expression.indexOf('(')
|
||||||
|
const endIndex = backendValue.expression.indexOf(')')
|
||||||
|
if (startIndex === -1 || endIndex === -1 || endIndex < startIndex)
|
||||||
|
return
|
||||||
|
const numberStr = backendValue.expression.slice(startIndex + 1, endIndex)
|
||||||
|
const numbers = numberStr.split(",")
|
||||||
|
if (!Array.isArray(numbers) || numbers.length !== vecSize)
|
||||||
|
return
|
||||||
|
|
||||||
|
let vals = []
|
||||||
|
for (let i = 0; i < vecSize; ++i) {
|
||||||
|
vals[i] = parseFloat(numbers[i])
|
||||||
|
if (!isValidValue(vals[i]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < vecSize; ++j)
|
||||||
|
proxyValues[j].value = vals[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
id: boxX
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "X"
|
||||||
|
tooltip: "X"
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
id: boxY
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Y"
|
||||||
|
tooltip: "Y"
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutVector.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
visible: vecSize > 2
|
||||||
|
SpinBox {
|
||||||
|
id: boxZ
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "Z"
|
||||||
|
tooltip: "Z"
|
||||||
|
visible: vecSize > 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
id: boxW
|
||||||
|
minimumValue: -9999999
|
||||||
|
maximumValue: 9999999
|
||||||
|
decimals: 2
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
visible: vecSize > 3
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
|
||||||
|
|
||||||
|
ControlLabel {
|
||||||
|
text: "W"
|
||||||
|
tooltip: "W"
|
||||||
|
visible: vecSize > 3
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: 10
|
||||||
|
implicitWidth: {
|
||||||
|
return StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
visible: vecSize === 2 // Placeholder for last spinbox
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property Component readonlyEditor: Component {
|
||||||
|
id: readonlyEditor
|
||||||
|
SecondColumnLayout {
|
||||||
|
id: layoutReadonly
|
||||||
|
property var backendValue
|
||||||
|
property string propertyType
|
||||||
|
|
||||||
|
signal remove
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
tooltip: layoutReadonly.propertyType
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
leftPadding: StudioTheme.Values.actionIndicatorWidth
|
||||||
|
text: qsTr("No editor for type: ") + layoutReadonly.propertyType
|
||||||
|
|
||||||
|
width: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||||
|
}
|
||||||
|
IconIndicator {
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
icon: StudioTheme.Constants.closeCross
|
||||||
|
onClicked: layoutReadonly.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: repeater
|
||||||
|
model: root.propertiesModel
|
||||||
|
|
||||||
|
property bool loadActive: true
|
||||||
|
onCountChanged: {
|
||||||
|
repeater.loadActive = false
|
||||||
|
repeater.loadActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
DynamicPropertyRow {
|
||||||
|
id: propertyRow
|
||||||
|
model: root.propertiesModel
|
||||||
|
row: index
|
||||||
|
}
|
||||||
|
PropertyLabel {
|
||||||
|
text: propertyName
|
||||||
|
tooltip: propertyType
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
asynchronous: true
|
||||||
|
active: repeater.loadActive
|
||||||
|
width: loader.item ? loader.item.width : 0
|
||||||
|
height: loader.item ? loader.item.height : 0
|
||||||
|
|
||||||
|
sourceComponent: {
|
||||||
|
if (propertyType == "color")
|
||||||
|
return colorEditor
|
||||||
|
if (propertyType == "int")
|
||||||
|
return intEditor
|
||||||
|
if (propertyType == "real")
|
||||||
|
return realEditor
|
||||||
|
if (propertyType == "string")
|
||||||
|
return stringEditor
|
||||||
|
if (propertyType == "bool")
|
||||||
|
return boolEditor
|
||||||
|
if (propertyType == "url")
|
||||||
|
return urlEditor
|
||||||
|
if (propertyType == "alias")
|
||||||
|
return aliasEditor
|
||||||
|
if (propertyType == "variant")
|
||||||
|
return readonlyEditor
|
||||||
|
if (propertyType == "TextureInput")
|
||||||
|
return textureInputEditor
|
||||||
|
if (propertyType == "vector2d" || propertyType == "vector3d" || propertyType == "vector4d")
|
||||||
|
return vectorEditor
|
||||||
|
|
||||||
|
return readonlyEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
loader.item.backendValue = propertyRow.backendValue
|
||||||
|
loader.item.propertyType = propertyType
|
||||||
|
if (sourceComponent == vectorEditor) {
|
||||||
|
let vecSize = 2
|
||||||
|
if (propertyType == "vector3d")
|
||||||
|
vecSize = 3
|
||||||
|
else if (propertyType == "vector4d")
|
||||||
|
vecSize = 4
|
||||||
|
propertyRow.clearProxyBackendValues()
|
||||||
|
|
||||||
|
for (let i = 0; i < vecSize; ++i) {
|
||||||
|
var newProxyValue = propertyRow.createProxyBackendValue()
|
||||||
|
loader.item.proxyValues.push(newProxyValue)
|
||||||
|
newProxyValue.valueChangedQml.connect(loader.item.updateExpression)
|
||||||
|
loader.item.spinBoxes[i].backendValue = newProxyValue
|
||||||
|
}
|
||||||
|
propertyRow.backendValue.expressionChanged.connect(loader.item.updateProxyValues)
|
||||||
|
loader.item.vecSize = vecSize
|
||||||
|
loader.item.updateProxyValues()
|
||||||
|
} else if (sourceComponent == aliasEditor) {
|
||||||
|
loader.item.lineEdit.text = propertyRow.backendValue.expression
|
||||||
|
loader.item.backendValue.expressionChanged.connect(loader.item.updateLineEditText)
|
||||||
|
} else if (sourceComponent == colorEditor) {
|
||||||
|
loader.item.initEditor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: loader.item
|
||||||
|
function onRemove() {
|
||||||
|
propertyRow.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
text: ""
|
||||||
|
tooltip: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
|
||||||
|
|
||||||
|
StudioControls.AbstractButton {
|
||||||
|
|
||||||
|
id: plusButton
|
||||||
|
buttonIcon: StudioTheme.Constants.plus
|
||||||
|
onClicked: {
|
||||||
|
cePopup.opened ? cePopup.close() : cePopup.open()
|
||||||
|
forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property T.Popup popup: T.Popup {
|
||||||
|
id: cePopup
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
cePopup.setPopupY()
|
||||||
|
cePopup.setMainScrollViewHeight()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMainScrollViewHeight() {
|
||||||
|
if (Controller.mainScrollView == null)
|
||||||
|
return
|
||||||
|
|
||||||
|
var mappedPos = plusButton.mapToItem(Controller.mainScrollView.contentItem,
|
||||||
|
cePopup.x, cePopup.y)
|
||||||
|
Controller.mainScrollView.temporaryHeight = mappedPos.y + cePopup.height
|
||||||
|
+ StudioTheme.Values.colorEditorPopupMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPopupY() {
|
||||||
|
if (Controller.mainScrollView == null)
|
||||||
|
return
|
||||||
|
|
||||||
|
var mappedPos = plusButton.mapToItem(Controller.mainScrollView.contentItem,
|
||||||
|
plusButton.x, plusButton.y)
|
||||||
|
cePopup.y = Math.max(-mappedPos.y + StudioTheme.Values.colorEditorPopupMargin,
|
||||||
|
cePopup.__defaultY)
|
||||||
|
|
||||||
|
textField.text = root.propertiesModel.newPropertyName()
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: Controller.mainScrollView.temporaryHeight = 0
|
||||||
|
|
||||||
|
property real __defaultX: (Controller.mainScrollView.contentItem.width
|
||||||
|
- StudioTheme.Values.colorEditorPopupWidth * 1.5) / 2
|
||||||
|
|
||||||
|
property real __defaultY: - StudioTheme.Values.colorEditorPopupPadding
|
||||||
|
- (StudioTheme.Values.colorEditorPopupSpacing * 2)
|
||||||
|
- StudioTheme.Values.defaultControlHeight
|
||||||
|
- StudioTheme.Values.colorEditorPopupLineHeight
|
||||||
|
+ plusButton.width * 0.5
|
||||||
|
|
||||||
|
x: cePopup.__defaultX
|
||||||
|
y: cePopup.__defaultY
|
||||||
|
|
||||||
|
width: 270
|
||||||
|
height: 160
|
||||||
|
|
||||||
|
property int itemWidth: width / 2
|
||||||
|
property int labelWidth: itemWidth - 32
|
||||||
|
|
||||||
|
padding: StudioTheme.Values.border
|
||||||
|
margins: 2 // If not defined margin will be -1
|
||||||
|
|
||||||
|
closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
id: content
|
||||||
|
Column {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
RowLayout {
|
||||||
|
width: cePopup.width - 8
|
||||||
|
PropertyLabel {
|
||||||
|
text: "Add New Property"
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
leftPadding: 8
|
||||||
|
width: cePopup.width - closeIndicator.width - 24
|
||||||
|
}
|
||||||
|
IconIndicator {
|
||||||
|
id: closeIndicator
|
||||||
|
icon: StudioTheme.Constants.colorPopupClose
|
||||||
|
pixelSize: StudioTheme.Values.myIconFontSize * 1.4
|
||||||
|
onClicked: cePopup.close()
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
id: textLabel
|
||||||
|
text: "Name"
|
||||||
|
width: cePopup.labelWidth
|
||||||
|
}
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: textField
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicatorVisible: false
|
||||||
|
width: cePopup.itemWidth
|
||||||
|
rightPadding: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
text: "Type"
|
||||||
|
width: cePopup.labelWidth
|
||||||
|
}
|
||||||
|
StudioControls.ComboBox {
|
||||||
|
id: comboBox
|
||||||
|
actionIndicator.visible: false
|
||||||
|
model: ["int", "real", "color", "string", "bool", "url", "alias",
|
||||||
|
"TextureInput", "vector2d", "vector3d", "vector4d"]
|
||||||
|
width: cePopup.itemWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
width: 1
|
||||||
|
height: StudioTheme.Values.sectionRowSpacing
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: cePopup.width
|
||||||
|
|
||||||
|
StudioControls.AbstractButton {
|
||||||
|
id: acceptButton
|
||||||
|
|
||||||
|
buttonIcon: qsTr("Add Property")
|
||||||
|
iconFont: StudioTheme.Constants.font
|
||||||
|
width: cePopup.width / 3
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.propertiesModel.createProperty(textField.text, comboBox.currentText)
|
||||||
|
cePopup.close()
|
||||||
|
}
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: StudioTheme.Values.themeControlBackground
|
||||||
|
border.color: StudioTheme.Values.themeInteraction
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
MouseArea {
|
||||||
|
// This area is to eat clicks so they do not go through the popup
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.AllButtons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enter: Transition {}
|
||||||
|
exit: Transition {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ HelperWidgets.ComboBox {
|
|||||||
|
|
||||||
comboBox.currentIndex = comboBox.find(text)
|
comboBox.currentIndex = comboBox.find(text)
|
||||||
|
|
||||||
if (text === "") {
|
if (text === "" || text === "null") {
|
||||||
comboBox.currentIndex = 0
|
comboBox.currentIndex = 0
|
||||||
comboBox.editText = comboBox.defaultItem
|
comboBox.editText = comboBox.defaultItem
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBackendValueChanged: {
|
||||||
|
spinBox.enabled = backendValue === undefined ? false : !isBlocked(backendValue.name)
|
||||||
|
}
|
||||||
|
|
||||||
StudioControls.RealSpinBox {
|
StudioControls.RealSpinBox {
|
||||||
id: spinBox
|
id: spinBox
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ ComponentSection 2.0 ComponentSection.qml
|
|||||||
ControlLabel 2.0 ControlLabel.qml
|
ControlLabel 2.0 ControlLabel.qml
|
||||||
singleton Controller 2.0 Controller.qml
|
singleton Controller 2.0 Controller.qml
|
||||||
DoubleSpinBox 2.0 DoubleSpinBox.qml
|
DoubleSpinBox 2.0 DoubleSpinBox.qml
|
||||||
|
DynamicPropertiesSection 2.0 DynamicPropertiesSection.qml
|
||||||
EditableListView 2.0 EditableListView.qml
|
EditableListView 2.0 EditableListView.qml
|
||||||
ExpandingSpacer 2.0 ExpandingSpacer.qml
|
ExpandingSpacer 2.0 ExpandingSpacer.qml
|
||||||
ExpressionTextField 2.0 ExpressionTextField.qml
|
ExpressionTextField 2.0 ExpressionTextField.qml
|
||||||
|
|||||||
@@ -20,13 +20,17 @@ Project {
|
|||||||
directory: "content"
|
directory: "content"
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaScriptFiles {
|
JavaScriptFiles {
|
||||||
directory: "imports"
|
directory: "imports"
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageFiles {
|
ImageFiles {
|
||||||
directory: "content"
|
directory: "content"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageFiles {
|
||||||
|
directory: "asset_imports"
|
||||||
|
}
|
||||||
|
|
||||||
Files {
|
Files {
|
||||||
filter: "*.conf"
|
filter: "*.conf"
|
||||||
@@ -95,7 +99,7 @@ Project {
|
|||||||
/* Required for deployment */
|
/* Required for deployment */
|
||||||
targetDirectory: "/opt/%{ProjectName}"
|
targetDirectory: "/opt/%{ProjectName}"
|
||||||
|
|
||||||
qdsVersion: "3.5"
|
qdsVersion: "3.7"
|
||||||
|
|
||||||
quickVersion: "%{QtQuickVersion}"
|
quickVersion: "%{QtQuickVersion}"
|
||||||
|
|
||||||
|
|||||||
@@ -372,6 +372,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
fileresourcesmodel.cpp fileresourcesmodel.h
|
fileresourcesmodel.cpp fileresourcesmodel.h
|
||||||
itemfiltermodel.cpp itemfiltermodel.h
|
itemfiltermodel.cpp itemfiltermodel.h
|
||||||
gradientmodel.cpp gradientmodel.h
|
gradientmodel.cpp gradientmodel.h
|
||||||
|
dynamicpropertiesproxymodel.cpp dynamicpropertiesproxymodel.h
|
||||||
gradientpresetcustomlistmodel.cpp gradientpresetcustomlistmodel.h
|
gradientpresetcustomlistmodel.cpp gradientpresetcustomlistmodel.h
|
||||||
gradientpresetdefaultlistmodel.cpp gradientpresetdefaultlistmodel.h
|
gradientpresetdefaultlistmodel.cpp gradientpresetdefaultlistmodel.h
|
||||||
gradientpresetitem.cpp gradientpresetitem.h
|
gradientpresetitem.cpp gradientpresetitem.h
|
||||||
@@ -393,6 +394,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
SOURCES_PREFIX components/materialeditor
|
SOURCES_PREFIX components/materialeditor
|
||||||
SOURCES
|
SOURCES
|
||||||
materialeditorcontextobject.cpp materialeditorcontextobject.h
|
materialeditorcontextobject.cpp materialeditorcontextobject.h
|
||||||
|
materialeditordynamicpropertiesproxymodel.cpp materialeditordynamicpropertiesproxymodel.h
|
||||||
materialeditorqmlbackend.cpp materialeditorqmlbackend.h
|
materialeditorqmlbackend.cpp materialeditorqmlbackend.h
|
||||||
materialeditortransaction.cpp materialeditortransaction.h
|
materialeditortransaction.cpp materialeditortransaction.h
|
||||||
materialeditorview.cpp materialeditorview.h
|
materialeditorview.cpp materialeditorview.h
|
||||||
@@ -405,6 +407,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
materialbrowserview.cpp materialbrowserview.h
|
materialbrowserview.cpp materialbrowserview.h
|
||||||
materialbrowserwidget.cpp materialbrowserwidget.h
|
materialbrowserwidget.cpp materialbrowserwidget.h
|
||||||
materialbrowsermodel.cpp materialbrowsermodel.h
|
materialbrowsermodel.cpp materialbrowsermodel.h
|
||||||
|
bundleimporter.cpp bundleimporter.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
@@ -560,6 +563,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
connectionviewwidget.cpp connectionviewwidget.h connectionviewwidget.ui
|
connectionviewwidget.cpp connectionviewwidget.h connectionviewwidget.ui
|
||||||
delegates.cpp delegates.h
|
delegates.cpp delegates.h
|
||||||
dynamicpropertiesmodel.cpp dynamicpropertiesmodel.h
|
dynamicpropertiesmodel.cpp dynamicpropertiesmodel.h
|
||||||
|
selectiondynamicpropertiesproxymodel.cpp selectiondynamicpropertiesproxymodel.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
|
|||||||
@@ -60,41 +60,52 @@ bool Navigation2dFilter::gestureEvent(QGestureEvent *event)
|
|||||||
|
|
||||||
bool Navigation2dFilter::wheelEvent(QWheelEvent *event)
|
bool Navigation2dFilter::wheelEvent(QWheelEvent *event)
|
||||||
{
|
{
|
||||||
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
if (!event->modifiers().testFlag(Qt::ControlModifier)) {
|
||||||
if (event->modifiers().testFlag(Qt::ControlModifier)) {
|
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
||||||
if (QPointF delta = event->pixelDelta(); !delta.isNull()) {
|
|
||||||
double dist = std::abs(delta.x()) > std::abs(delta.y()) ? -delta.x() : delta.y();
|
|
||||||
emit zoomChanged(dist/200.0, event->position());
|
|
||||||
event->accept();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
emit panChanged(QPointF(event->pixelDelta()));
|
emit panChanged(QPointF(event->pixelDelta()));
|
||||||
event->accept();
|
event->accept();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (event->source() == Qt::MouseEventNotSynthesized) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto zoomInSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomIn);
|
auto zoomChangedSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomChanged);
|
||||||
bool zoomInConnected = QObject::isSignalConnected(zoomInSignal);
|
bool zoomChangedConnected = QObject::isSignalConnected(zoomChangedSignal);
|
||||||
|
|
||||||
auto zoomOutSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomOut);
|
if (zoomChangedConnected) {
|
||||||
bool zoomOutConnected = QObject::isSignalConnected(zoomOutSignal);
|
if (QPointF delta = event->pixelDelta(); !delta.isNull()) {
|
||||||
|
double dist = std::abs(delta.x()) > std::abs(delta.y()) ? -delta.x() : delta.y();
|
||||||
|
emit zoomChanged(dist/200.0, event->position());
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
} else if (QPointF delta = event->angleDelta(); !delta.isNull()) {
|
||||||
|
double dist = std::abs(delta.x()) > std::abs(delta.y()) ? -delta.x() : delta.y();
|
||||||
|
dist = dist / (8*15);
|
||||||
|
emit zoomChanged(dist/200.0, event->position());
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (zoomInConnected && zoomOutConnected) {
|
auto zoomInSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomIn);
|
||||||
if (event->modifiers().testFlag(Qt::ControlModifier)) {
|
bool zoomInConnected = QObject::isSignalConnected(zoomInSignal);
|
||||||
if (QPointF angle = event->angleDelta(); !angle.isNull()) {
|
|
||||||
double delta = std::abs(angle.x()) > std::abs(angle.y()) ? angle.x() : angle.y();
|
auto zoomOutSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomOut);
|
||||||
if (delta > 0)
|
bool zoomOutConnected = QObject::isSignalConnected(zoomOutSignal);
|
||||||
emit zoomIn();
|
|
||||||
else
|
if (zoomInConnected && zoomOutConnected) {
|
||||||
emit zoomOut();
|
if (QPointF angle = event->angleDelta(); !angle.isNull()) {
|
||||||
event->accept();
|
double delta = std::abs(angle.x()) > std::abs(angle.y()) ? angle.x() : angle.y();
|
||||||
return true;
|
if (delta > 0)
|
||||||
}
|
emit zoomIn();
|
||||||
}
|
else
|
||||||
|
emit zoomOut();
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ ConnectionView::ConnectionView(QObject *parent) : AbstractView(parent),
|
|||||||
m_connectionViewWidget(new ConnectionViewWidget()),
|
m_connectionViewWidget(new ConnectionViewWidget()),
|
||||||
m_connectionModel(new ConnectionModel(this)),
|
m_connectionModel(new ConnectionModel(this)),
|
||||||
m_bindingModel(new BindingModel(this)),
|
m_bindingModel(new BindingModel(this)),
|
||||||
m_dynamicPropertiesModel(new DynamicPropertiesModel(this)),
|
m_dynamicPropertiesModel(new DynamicPropertiesModel(false, this)),
|
||||||
m_backendModel(new BackendModel(this))
|
m_backendModel(new BackendModel(this))
|
||||||
{
|
{
|
||||||
connectionViewWidget()->setBindingModel(m_bindingModel);
|
connectionViewWidget()->setBindingModel(m_bindingModel);
|
||||||
@@ -43,7 +43,7 @@ void ConnectionView::modelAttached(Model *model)
|
|||||||
{
|
{
|
||||||
AbstractView::modelAttached(model);
|
AbstractView::modelAttached(model);
|
||||||
bindingModel()->selectionChanged(QList<ModelNode>());
|
bindingModel()->selectionChanged(QList<ModelNode>());
|
||||||
dynamicPropertiesModel()->selectionChanged(QList<ModelNode>());
|
dynamicPropertiesModel()->reset();
|
||||||
connectionModel()->resetModel();
|
connectionModel()->resetModel();
|
||||||
connectionViewWidget()->resetItemViews();
|
connectionViewWidget()->resetItemViews();
|
||||||
backendModel()->resetModel();
|
backendModel()->resetModel();
|
||||||
@@ -53,7 +53,7 @@ void ConnectionView::modelAboutToBeDetached(Model *model)
|
|||||||
{
|
{
|
||||||
AbstractView::modelAboutToBeDetached(model);
|
AbstractView::modelAboutToBeDetached(model);
|
||||||
bindingModel()->selectionChanged(QList<ModelNode>());
|
bindingModel()->selectionChanged(QList<ModelNode>());
|
||||||
dynamicPropertiesModel()->selectionChanged(QList<ModelNode>());
|
dynamicPropertiesModel()->reset();
|
||||||
connectionModel()->resetModel();
|
connectionModel()->resetModel();
|
||||||
connectionViewWidget()->resetItemViews();
|
connectionViewWidget()->resetItemViews();
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ void ConnectionView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &p
|
|||||||
bindingModel()->bindingRemoved(property.toBindingProperty());
|
bindingModel()->bindingRemoved(property.toBindingProperty());
|
||||||
dynamicPropertiesModel()->bindingRemoved(property.toBindingProperty());
|
dynamicPropertiesModel()->bindingRemoved(property.toBindingProperty());
|
||||||
} else if (property.isVariantProperty()) {
|
} else if (property.isVariantProperty()) {
|
||||||
//### dynamicPropertiesModel->bindingRemoved(property.toVariantProperty());
|
dynamicPropertiesModel()->variantRemoved(property.toVariantProperty());
|
||||||
} else if (property.isSignalHandlerProperty()) {
|
} else if (property.isSignalHandlerProperty()) {
|
||||||
connectionModel()->removeRowFromTable(property.toSignalHandlerProperty());
|
connectionModel()->removeRowFromTable(property.toSignalHandlerProperty());
|
||||||
}
|
}
|
||||||
@@ -145,7 +145,7 @@ void ConnectionView::selectedNodesChanged(const QList<ModelNode> & selectedNodeL
|
|||||||
const QList<ModelNode> & /*lastSelectedNodeList*/)
|
const QList<ModelNode> & /*lastSelectedNodeList*/)
|
||||||
{
|
{
|
||||||
bindingModel()->selectionChanged(selectedNodeList);
|
bindingModel()->selectionChanged(selectedNodeList);
|
||||||
dynamicPropertiesModel()->selectionChanged(selectedNodeList);
|
dynamicPropertiesModel()->reset();
|
||||||
connectionViewWidget()->bindingTableViewSelectionChanged(QModelIndex(), QModelIndex());
|
connectionViewWidget()->bindingTableViewSelectionChanged(QModelIndex(), QModelIndex());
|
||||||
connectionViewWidget()->dynamicPropertiesTableViewSelectionChanged(QModelIndex(), QModelIndex());
|
connectionViewWidget()->dynamicPropertiesTableViewSelectionChanged(QModelIndex(), QModelIndex());
|
||||||
|
|
||||||
@@ -184,6 +184,11 @@ void ConnectionView::importsChanged(const QList<Import> & /*addedImports*/, cons
|
|||||||
backendModel()->resetModel();
|
backendModel()->resetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectionView::currentStateChanged(const ModelNode &node)
|
||||||
|
{
|
||||||
|
dynamicPropertiesModel()->reset();
|
||||||
|
}
|
||||||
|
|
||||||
WidgetInfo ConnectionView::widgetInfo()
|
WidgetInfo ConnectionView::widgetInfo()
|
||||||
{
|
{
|
||||||
return createWidgetInfo(m_connectionViewWidget.data(),
|
return createWidgetInfo(m_connectionViewWidget.data(),
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ public:
|
|||||||
|
|
||||||
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
|
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
|
||||||
|
|
||||||
|
void currentStateChanged(const ModelNode &node) override;
|
||||||
|
|
||||||
WidgetInfo widgetInfo() override;
|
WidgetInfo widgetInfo() override;
|
||||||
bool hasWidget() const override;
|
bool hasWidget() const override;
|
||||||
bool isWidgetEnabled();
|
bool isWidgetEnabled();
|
||||||
|
|||||||
@@ -355,8 +355,8 @@ void ConnectionViewWidget::invalidateButtonStatus()
|
|||||||
} else if (currentTab() == DynamicPropertiesTab) {
|
} else if (currentTab() == DynamicPropertiesTab) {
|
||||||
emit setEnabledRemoveButton(ui->dynamicPropertiesView->selectionModel()->hasSelection());
|
emit setEnabledRemoveButton(ui->dynamicPropertiesView->selectionModel()->hasSelection());
|
||||||
auto dynamicPropertiesModel = qobject_cast<DynamicPropertiesModel*>(ui->dynamicPropertiesView->model());
|
auto dynamicPropertiesModel = qobject_cast<DynamicPropertiesModel*>(ui->dynamicPropertiesView->model());
|
||||||
emit setEnabledAddButton(dynamicPropertiesModel->connectionView()->model() &&
|
emit setEnabledAddButton(dynamicPropertiesModel->view()->model() &&
|
||||||
dynamicPropertiesModel->connectionView()->selectedModelNodes().count() == 1);
|
dynamicPropertiesModel->selectedNodes().count() == 1);
|
||||||
} else if (currentTab() == BackendTab) {
|
} else if (currentTab() == BackendTab) {
|
||||||
emit setEnabledAddButton(true);
|
emit setEnabledAddButton(true);
|
||||||
emit setEnabledRemoveButton(ui->backendView->selectionModel()->hasSelection());
|
emit setEnabledRemoveButton(ui->backendView->selectionModel()->hasSelection());
|
||||||
@@ -526,9 +526,9 @@ void ConnectionViewWidget::editorForDynamic()
|
|||||||
QString newValue = m_dynamicEditor->bindingValue().trimmed();
|
QString newValue = m_dynamicEditor->bindingValue().trimmed();
|
||||||
|
|
||||||
if (m_dynamicIndex.isValid()) {
|
if (m_dynamicIndex.isValid()) {
|
||||||
if (propertiesModel->connectionView()->isWidgetEnabled()
|
if (qobject_cast<ConnectionView *>(propertiesModel->view())->isWidgetEnabled()
|
||||||
&& (propertiesModel->rowCount() > m_dynamicIndex.row())) {
|
&& (propertiesModel->rowCount() > m_dynamicIndex.row())) {
|
||||||
propertiesModel->connectionView()->executeInTransaction(
|
propertiesModel->view()->executeInTransaction(
|
||||||
"ConnectionView::setBinding", [this, propertiesModel, newValue]() {
|
"ConnectionView::setBinding", [this, propertiesModel, newValue]() {
|
||||||
AbstractProperty abProp = propertiesModel->abstractPropertyForRow(
|
AbstractProperty abProp = propertiesModel->abstractPropertyForRow(
|
||||||
m_dynamicIndex.row());
|
m_dynamicIndex.row());
|
||||||
|
|||||||
@@ -187,11 +187,11 @@ QWidget *DynamicPropertiesDelegate::createEditor(QWidget *parent, const QStyleOp
|
|||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!model->connectionView()) {
|
if (!model->view()) {
|
||||||
qWarning() << "BindingDelegate::createEditor no connection view";
|
qWarning() << "BindingDelegate::createEditor no connection view";
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
model->connectionView()->allModelNodes();
|
model->view()->allModelNodes();
|
||||||
|
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case DynamicPropertiesModel::TargetModelNodeRow: {
|
case DynamicPropertiesModel::TargetModelNodeRow: {
|
||||||
@@ -209,7 +209,7 @@ QWidget *DynamicPropertiesDelegate::createEditor(QWidget *parent, const QStyleOp
|
|||||||
});
|
});
|
||||||
|
|
||||||
dynamicPropertiesComboBox->addItem(QLatin1String("alias"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("alias"));
|
||||||
//dynamicPropertiesComboBox->addItem(QLatin1String("Item"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("Item"));
|
||||||
dynamicPropertiesComboBox->addItem(QLatin1String("real"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("real"));
|
||||||
dynamicPropertiesComboBox->addItem(QLatin1String("int"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("int"));
|
||||||
dynamicPropertiesComboBox->addItem(QLatin1String("string"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("string"));
|
||||||
@@ -217,6 +217,10 @@ QWidget *DynamicPropertiesDelegate::createEditor(QWidget *parent, const QStyleOp
|
|||||||
dynamicPropertiesComboBox->addItem(QLatin1String("url"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("url"));
|
||||||
dynamicPropertiesComboBox->addItem(QLatin1String("color"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("color"));
|
||||||
dynamicPropertiesComboBox->addItem(QLatin1String("variant"));
|
dynamicPropertiesComboBox->addItem(QLatin1String("variant"));
|
||||||
|
dynamicPropertiesComboBox->addItem(QLatin1String("TextureInput"));
|
||||||
|
dynamicPropertiesComboBox->addItem(QLatin1String("vector2d"));
|
||||||
|
dynamicPropertiesComboBox->addItem(QLatin1String("vector3d"));
|
||||||
|
dynamicPropertiesComboBox->addItem(QLatin1String("vector4d"));
|
||||||
return dynamicPropertiesComboBox;
|
return dynamicPropertiesComboBox;
|
||||||
};
|
};
|
||||||
case DynamicPropertiesModel::PropertyValueRow: {
|
case DynamicPropertiesModel::PropertyValueRow: {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@@ -69,8 +70,18 @@ QVariant convertVariantForTypeName(const QVariant &variant, const QmlDesigner::T
|
|||||||
} else {
|
} else {
|
||||||
returnValue = QColor(Qt::black);
|
returnValue = QColor(Qt::black);
|
||||||
}
|
}
|
||||||
|
} else if (typeName == "vector2d") {
|
||||||
|
returnValue = "Qt.vector2d(0, 0)";
|
||||||
|
} else if (typeName == "vector3d") {
|
||||||
|
returnValue = "Qt.vector3d(0, 0, 0)";
|
||||||
|
} else if (typeName == "vector4d") {
|
||||||
|
returnValue = "Qt.vector4d(0, 0, 0 ,0)";
|
||||||
|
} else if (typeName == "TextureInput") {
|
||||||
|
returnValue = "null";
|
||||||
|
} else if (typeName == "alias") {
|
||||||
|
returnValue = "null";
|
||||||
} else if (typeName == "Item") {
|
} else if (typeName == "Item") {
|
||||||
returnValue = 0;
|
returnValue = "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@@ -86,7 +97,7 @@ QmlDesigner::PropertyName DynamicPropertiesModel::unusedProperty(const QmlDesign
|
|||||||
{
|
{
|
||||||
QmlDesigner::PropertyName propertyName = "property";
|
QmlDesigner::PropertyName propertyName = "property";
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (modelNode.metaInfo().isValid()) {
|
if (modelNode.isValid() && modelNode.metaInfo().isValid()) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const QmlDesigner::PropertyName currentPropertyName = propertyName + QString::number(i).toLatin1();
|
const QmlDesigner::PropertyName currentPropertyName = propertyName + QString::number(i).toLatin1();
|
||||||
if (!modelNode.hasProperty(currentPropertyName) && !modelNode.metaInfo().hasProperty(currentPropertyName))
|
if (!modelNode.hasProperty(currentPropertyName) && !modelNode.metaInfo().hasProperty(currentPropertyName))
|
||||||
@@ -98,9 +109,18 @@ QmlDesigner::PropertyName DynamicPropertiesModel::unusedProperty(const QmlDesign
|
|||||||
return propertyName;
|
return propertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicPropertiesModel::DynamicPropertiesModel(ConnectionView *parent)
|
bool DynamicPropertiesModel::isValueType(const TypeName &type)
|
||||||
|
{
|
||||||
|
// "variant" is considered value type as it is initialized as one.
|
||||||
|
// This may need to change if we provide any kind of proper editor for it.
|
||||||
|
static const QSet<TypeName> valueTypes {"int", "real", "color", "string", "bool", "url", "variant"};
|
||||||
|
return valueTypes.contains(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPropertiesModel::DynamicPropertiesModel(bool explicitSelection, AbstractView *parent)
|
||||||
: QStandardItemModel(parent)
|
: QStandardItemModel(parent)
|
||||||
, m_connectionView(parent)
|
, m_view(parent)
|
||||||
|
, m_explicitSelection(explicitSelection)
|
||||||
{
|
{
|
||||||
connect(this, &QStandardItemModel::dataChanged, this, &DynamicPropertiesModel::handleDataChanged);
|
connect(this, &QStandardItemModel::dataChanged, this, &DynamicPropertiesModel::handleDataChanged);
|
||||||
}
|
}
|
||||||
@@ -112,8 +132,9 @@ void DynamicPropertiesModel::resetModel()
|
|||||||
setHorizontalHeaderLabels(
|
setHorizontalHeaderLabels(
|
||||||
QStringList({tr("Item"), tr("Property"), tr("Property Type"), tr("Property Value")}));
|
QStringList({tr("Item"), tr("Property"), tr("Property Type"), tr("Property Value")}));
|
||||||
|
|
||||||
if (connectionView()->isAttached()) {
|
if (m_view->isAttached()) {
|
||||||
for (const ModelNode &modelNode : connectionView()->selectedModelNodes())
|
const auto nodes = selectedNodes();
|
||||||
|
for (const ModelNode &modelNode : nodes)
|
||||||
addModelNode(modelNode);
|
addModelNode(modelNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,8 +146,8 @@ void DynamicPropertiesModel::resetModel()
|
|||||||
//Value copying is optional
|
//Value copying is optional
|
||||||
BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const PropertyName &name, bool copyValue)
|
BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const PropertyName &name, bool copyValue)
|
||||||
{
|
{
|
||||||
if (connectionView()->selectedModelNodes().count() == 1) {
|
if (selectedNodes().count() == 1) {
|
||||||
const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst();
|
const ModelNode modelNode = selectedNodes().constFirst();
|
||||||
if (modelNode.isValid()) {
|
if (modelNode.isValid()) {
|
||||||
if (modelNode.hasVariantProperty(name)) {
|
if (modelNode.hasVariantProperty(name)) {
|
||||||
try {
|
try {
|
||||||
@@ -160,8 +181,8 @@ BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const Property
|
|||||||
//If it's a BindingProperty, then replaces it with empty VariantProperty
|
//If it's a BindingProperty, then replaces it with empty VariantProperty
|
||||||
void DynamicPropertiesModel::resetProperty(const PropertyName &name)
|
void DynamicPropertiesModel::resetProperty(const PropertyName &name)
|
||||||
{
|
{
|
||||||
if (connectionView()->selectedModelNodes().count() == 1) {
|
if (selectedNodes().count() == 1) {
|
||||||
const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst();
|
const ModelNode modelNode = selectedNodes().constFirst();
|
||||||
if (modelNode.isValid()) {
|
if (modelNode.isValid()) {
|
||||||
if (modelNode.hasProperty(name)) {
|
if (modelNode.hasProperty(name)) {
|
||||||
try {
|
try {
|
||||||
@@ -169,11 +190,10 @@ void DynamicPropertiesModel::resetProperty(const PropertyName &name)
|
|||||||
|
|
||||||
if (abProp.isVariantProperty()) {
|
if (abProp.isVariantProperty()) {
|
||||||
VariantProperty property = abProp.toVariantProperty();
|
VariantProperty property = abProp.toVariantProperty();
|
||||||
QVariant newValue = convertVariantForTypeName(QVariant("none.none"), property.dynamicTypeName());
|
QVariant newValue = convertVariantForTypeName({}, property.dynamicTypeName());
|
||||||
property.setDynamicTypeNameAndValue(property.dynamicTypeName(),
|
property.setDynamicTypeNameAndValue(property.dynamicTypeName(),
|
||||||
newValue);
|
newValue);
|
||||||
}
|
} else if (abProp.isBindingProperty()) {
|
||||||
else if (abProp.isBindingProperty()) {
|
|
||||||
BindingProperty property = abProp.toBindingProperty();
|
BindingProperty property = abProp.toBindingProperty();
|
||||||
TypeName oldType = property.dynamicTypeName();
|
TypeName oldType = property.dynamicTypeName();
|
||||||
|
|
||||||
@@ -181,9 +201,8 @@ void DynamicPropertiesModel::resetProperty(const PropertyName &name)
|
|||||||
modelNode.removeProperty(name);
|
modelNode.removeProperty(name);
|
||||||
|
|
||||||
VariantProperty newProperty = modelNode.variantProperty(name);
|
VariantProperty newProperty = modelNode.variantProperty(name);
|
||||||
QVariant newValue = convertVariantForTypeName(QVariant("none.none"), oldType);
|
QVariant newValue = convertVariantForTypeName({}, oldType);
|
||||||
newProperty.setDynamicTypeNameAndValue(oldType,
|
newProperty.setDynamicTypeNameAndValue(oldType, newValue);
|
||||||
newValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (RewritingException &e) {
|
} catch (RewritingException &e) {
|
||||||
@@ -205,8 +224,8 @@ void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindi
|
|||||||
|
|
||||||
m_handleDataChanged = false;
|
m_handleDataChanged = false;
|
||||||
|
|
||||||
QList<ModelNode> selectedNodes = connectionView()->selectedModelNodes();
|
const QList<ModelNode> nodes = selectedNodes();
|
||||||
if (!selectedNodes.contains(bindingProperty.parentModelNode()))
|
if (!nodes.contains(bindingProperty.parentModelNode()))
|
||||||
return;
|
return;
|
||||||
if (!m_lock) {
|
if (!m_lock) {
|
||||||
int rowNumber = findRowForBindingProperty(bindingProperty);
|
int rowNumber = findRowForBindingProperty(bindingProperty);
|
||||||
@@ -228,17 +247,16 @@ void DynamicPropertiesModel::variantPropertyChanged(const VariantProperty &varia
|
|||||||
|
|
||||||
m_handleDataChanged = false;
|
m_handleDataChanged = false;
|
||||||
|
|
||||||
QList<ModelNode> selectedNodes = connectionView()->selectedModelNodes();
|
const QList<ModelNode> nodes = selectedNodes();
|
||||||
if (!selectedNodes.contains(variantProperty.parentModelNode()))
|
if (!nodes.contains(variantProperty.parentModelNode()))
|
||||||
return;
|
return;
|
||||||
if (!m_lock) {
|
if (!m_lock) {
|
||||||
int rowNumber = findRowForVariantProperty(variantProperty);
|
int rowNumber = findRowForVariantProperty(variantProperty);
|
||||||
|
|
||||||
if (rowNumber == -1) {
|
if (rowNumber == -1)
|
||||||
addVariantProperty(variantProperty);
|
addVariantProperty(variantProperty);
|
||||||
} else {
|
else
|
||||||
updateVariantProperty(rowNumber);
|
updateVariantProperty(rowNumber);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_handleDataChanged = true;
|
m_handleDataChanged = true;
|
||||||
@@ -248,8 +266,8 @@ void DynamicPropertiesModel::bindingRemoved(const BindingProperty &bindingProper
|
|||||||
{
|
{
|
||||||
m_handleDataChanged = false;
|
m_handleDataChanged = false;
|
||||||
|
|
||||||
QList<ModelNode> selectedNodes = connectionView()->selectedModelNodes();
|
const QList<ModelNode> nodes = selectedNodes();
|
||||||
if (!selectedNodes.contains(bindingProperty.parentModelNode()))
|
if (!nodes.contains(bindingProperty.parentModelNode()))
|
||||||
return;
|
return;
|
||||||
if (!m_lock) {
|
if (!m_lock) {
|
||||||
int rowNumber = findRowForBindingProperty(bindingProperty);
|
int rowNumber = findRowForBindingProperty(bindingProperty);
|
||||||
@@ -259,16 +277,36 @@ void DynamicPropertiesModel::bindingRemoved(const BindingProperty &bindingProper
|
|||||||
m_handleDataChanged = true;
|
m_handleDataChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicPropertiesModel::selectionChanged([[maybe_unused]] const QList<ModelNode> &selectedNodes)
|
void DynamicPropertiesModel::variantRemoved(const VariantProperty &variantProperty)
|
||||||
|
{
|
||||||
|
m_handleDataChanged = false;
|
||||||
|
|
||||||
|
const QList<ModelNode> nodes = selectedNodes();
|
||||||
|
if (!nodes.contains(variantProperty.parentModelNode()))
|
||||||
|
return;
|
||||||
|
if (!m_lock) {
|
||||||
|
int rowNumber = findRowForVariantProperty(variantProperty);
|
||||||
|
removeRow(rowNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_handleDataChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertiesModel::reset()
|
||||||
{
|
{
|
||||||
m_handleDataChanged = false;
|
m_handleDataChanged = false;
|
||||||
resetModel();
|
resetModel();
|
||||||
m_handleDataChanged = true;
|
m_handleDataChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionView *DynamicPropertiesModel::connectionView() const
|
void DynamicPropertiesModel::setSelectedNode(const ModelNode &node)
|
||||||
{
|
{
|
||||||
return m_connectionView;
|
QTC_ASSERT(m_explicitSelection, return);
|
||||||
|
QTC_ASSERT(node.isValid(), return);
|
||||||
|
|
||||||
|
m_selectedNodes.clear();
|
||||||
|
m_selectedNodes.append(node);
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const
|
AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const
|
||||||
@@ -276,10 +314,10 @@ AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) c
|
|||||||
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
|
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
|
||||||
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
|
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
|
||||||
|
|
||||||
if (!connectionView()->isAttached())
|
if (!m_view->isAttached())
|
||||||
return AbstractProperty();
|
return AbstractProperty();
|
||||||
|
|
||||||
ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
|
ModelNode modelNode = m_view->modelNodeForInternalId(internalId);
|
||||||
|
|
||||||
if (modelNode.isValid())
|
if (modelNode.isValid())
|
||||||
return modelNode.property(targetPropertyName.toUtf8());
|
return modelNode.property(targetPropertyName.toUtf8());
|
||||||
@@ -292,7 +330,7 @@ BindingProperty DynamicPropertiesModel::bindingPropertyForRow(int rowNumber) con
|
|||||||
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
|
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
|
||||||
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
|
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
|
||||||
|
|
||||||
ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
|
ModelNode modelNode = m_view->modelNodeForInternalId(internalId);
|
||||||
|
|
||||||
if (modelNode.isValid())
|
if (modelNode.isValid())
|
||||||
return modelNode.bindingProperty(targetPropertyName.toUtf8());
|
return modelNode.bindingProperty(targetPropertyName.toUtf8());
|
||||||
@@ -305,7 +343,7 @@ VariantProperty DynamicPropertiesModel::variantPropertyForRow(int rowNumber) con
|
|||||||
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
|
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
|
||||||
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
|
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
|
||||||
|
|
||||||
ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
|
ModelNode modelNode = m_view->modelNodeForInternalId(internalId);
|
||||||
|
|
||||||
if (modelNode.isValid())
|
if (modelNode.isValid())
|
||||||
return modelNode.variantProperty(targetPropertyName.toUtf8());
|
return modelNode.variantProperty(targetPropertyName.toUtf8());
|
||||||
@@ -341,8 +379,8 @@ void DynamicPropertiesModel::addDynamicPropertyForCurrentNode()
|
|||||||
{
|
{
|
||||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
|
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
|
||||||
|
|
||||||
if (connectionView()->selectedModelNodes().count() == 1) {
|
if (selectedNodes().count() == 1) {
|
||||||
const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst();
|
const ModelNode modelNode = selectedNodes().constFirst();
|
||||||
if (modelNode.isValid()) {
|
if (modelNode.isValid()) {
|
||||||
try {
|
try {
|
||||||
modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", QLatin1String("none.none"));
|
modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", QLatin1String("none.none"));
|
||||||
@@ -396,16 +434,14 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
|
|||||||
|
|
||||||
void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
|
void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
|
||||||
{
|
{
|
||||||
connectionView()->executeInTransaction("DynamicPropertiesModel::deleteDynamicPropertyByRow", [this, rowNumber]() {
|
m_view->executeInTransaction("DynamicPropertiesModel::deleteDynamicPropertyByRow", [this, rowNumber]() {
|
||||||
BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
|
BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
|
||||||
if (bindingProperty.isValid()) {
|
if (bindingProperty.isValid()) {
|
||||||
bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
|
bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
|
||||||
}
|
} else {
|
||||||
|
VariantProperty variantProperty = variantPropertyForRow(rowNumber);
|
||||||
VariantProperty variantProperty = variantPropertyForRow(rowNumber);
|
if (variantProperty.isValid())
|
||||||
|
variantProperty.parentModelNode().removeProperty(variantProperty.name());
|
||||||
if (variantProperty.isValid()) {
|
|
||||||
variantProperty.parentModelNode().removeProperty(variantProperty.name());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -431,7 +467,6 @@ void DynamicPropertiesModel::addProperty(const QVariant &propertyValue,
|
|||||||
items.append(idItem);
|
items.append(idItem);
|
||||||
items.append(propertyNameItem);
|
items.append(propertyNameItem);
|
||||||
|
|
||||||
|
|
||||||
propertyTypeItem = new QStandardItem(propertyType);
|
propertyTypeItem = new QStandardItem(propertyType);
|
||||||
items.append(propertyTypeItem);
|
items.append(propertyTypeItem);
|
||||||
|
|
||||||
@@ -487,6 +522,9 @@ void DynamicPropertiesModel::updateVariantProperty(int rowNumber)
|
|||||||
|
|
||||||
void DynamicPropertiesModel::addModelNode(const ModelNode &modelNode)
|
void DynamicPropertiesModel::addModelNode(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
|
if (!modelNode.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
const QList<BindingProperty> bindingProperties = modelNode.bindingProperties();
|
const QList<BindingProperty> bindingProperties = modelNode.bindingProperties();
|
||||||
for (const BindingProperty &bindingProperty : bindingProperties) {
|
for (const BindingProperty &bindingProperty : bindingProperties) {
|
||||||
if (bindingProperty.isDynamic())
|
if (bindingProperty.isDynamic())
|
||||||
@@ -507,7 +545,7 @@ void DynamicPropertiesModel::updateValue(int row)
|
|||||||
if (bindingProperty.isBindingProperty()) {
|
if (bindingProperty.isBindingProperty()) {
|
||||||
const QString expression = data(index(row, PropertyValueRow)).toString();
|
const QString expression = data(index(row, PropertyValueRow)).toString();
|
||||||
|
|
||||||
RewriterTransaction transaction = connectionView()->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
|
RewriterTransaction transaction = m_view->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
|
||||||
try {
|
try {
|
||||||
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(), expression);
|
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(), expression);
|
||||||
transaction.commit(); //committing in the try block
|
transaction.commit(); //committing in the try block
|
||||||
@@ -523,7 +561,7 @@ void DynamicPropertiesModel::updateValue(int row)
|
|||||||
if (variantProperty.isVariantProperty()) {
|
if (variantProperty.isVariantProperty()) {
|
||||||
const QVariant value = data(index(row, PropertyValueRow));
|
const QVariant value = data(index(row, PropertyValueRow));
|
||||||
|
|
||||||
RewriterTransaction transaction = connectionView()->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
|
RewriterTransaction transaction = m_view->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
|
||||||
try {
|
try {
|
||||||
variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
|
variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
|
||||||
transaction.commit(); //committing in the try block
|
transaction.commit(); //committing in the try block
|
||||||
@@ -547,7 +585,7 @@ void DynamicPropertiesModel::updatePropertyName(int rowNumber)
|
|||||||
ModelNode targetNode = bindingProperty.parentModelNode();
|
ModelNode targetNode = bindingProperty.parentModelNode();
|
||||||
|
|
||||||
if (bindingProperty.isBindingProperty()) {
|
if (bindingProperty.isBindingProperty()) {
|
||||||
connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [bindingProperty, newName, &targetNode](){
|
m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [bindingProperty, newName, &targetNode](){
|
||||||
const QString expression = bindingProperty.expression();
|
const QString expression = bindingProperty.expression();
|
||||||
const PropertyName dynamicPropertyType = bindingProperty.dynamicTypeName();
|
const PropertyName dynamicPropertyType = bindingProperty.dynamicTypeName();
|
||||||
|
|
||||||
@@ -566,7 +604,7 @@ void DynamicPropertiesModel::updatePropertyName(int rowNumber)
|
|||||||
const PropertyName dynamicPropertyType = variantProperty.dynamicTypeName();
|
const PropertyName dynamicPropertyType = variantProperty.dynamicTypeName();
|
||||||
ModelNode targetNode = variantProperty.parentModelNode();
|
ModelNode targetNode = variantProperty.parentModelNode();
|
||||||
|
|
||||||
connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [=](){
|
m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [=](){
|
||||||
targetNode.variantProperty(newName).setDynamicTypeNameAndValue(dynamicPropertyType, value);
|
targetNode.variantProperty(newName).setDynamicTypeNameAndValue(dynamicPropertyType, value);
|
||||||
targetNode.removeProperty(variantProperty.name());
|
targetNode.removeProperty(variantProperty.name());
|
||||||
});
|
});
|
||||||
@@ -592,7 +630,7 @@ void DynamicPropertiesModel::updatePropertyType(int rowNumber)
|
|||||||
const PropertyName propertyName = bindingProperty.name();
|
const PropertyName propertyName = bindingProperty.name();
|
||||||
ModelNode targetNode = bindingProperty.parentModelNode();
|
ModelNode targetNode = bindingProperty.parentModelNode();
|
||||||
|
|
||||||
connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
|
m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
|
||||||
targetNode.removeProperty(bindingProperty.name());
|
targetNode.removeProperty(bindingProperty.name());
|
||||||
targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(newType, expression);
|
targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(newType, expression);
|
||||||
});
|
});
|
||||||
@@ -608,12 +646,14 @@ void DynamicPropertiesModel::updatePropertyType(int rowNumber)
|
|||||||
ModelNode targetNode = variantProperty.parentModelNode();
|
ModelNode targetNode = variantProperty.parentModelNode();
|
||||||
const PropertyName propertyName = variantProperty.name();
|
const PropertyName propertyName = variantProperty.name();
|
||||||
|
|
||||||
connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
|
m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
|
||||||
targetNode.removeProperty(variantProperty.name());
|
targetNode.removeProperty(variantProperty.name());
|
||||||
if (newType == "alias") { //alias properties have to be bindings
|
if (!isValueType(newType)) {
|
||||||
targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(newType, QLatin1String("none.none"));
|
targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(
|
||||||
|
newType, convertVariantForTypeName({}, newType).toString());
|
||||||
} else {
|
} else {
|
||||||
targetNode.variantProperty(propertyName).setDynamicTypeNameAndValue(newType, convertVariantForTypeName(value, newType));
|
targetNode.variantProperty(propertyName).setDynamicTypeNameAndValue(
|
||||||
|
newType, convertVariantForTypeName(value, newType));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -632,7 +672,7 @@ ModelNode DynamicPropertiesModel::getNodeByIdOrParent(const QString &id, const M
|
|||||||
ModelNode modelNode;
|
ModelNode modelNode;
|
||||||
|
|
||||||
if (id != QLatin1String("parent")) {
|
if (id != QLatin1String("parent")) {
|
||||||
modelNode = connectionView()->modelNodeForId(id);
|
modelNode = m_view->modelNodeForId(id);
|
||||||
} else {
|
} else {
|
||||||
if (targetNode.hasParentProperty()) {
|
if (targetNode.hasParentProperty()) {
|
||||||
modelNode = targetNode.parentProperty().parentModelNode();
|
modelNode = targetNode.parentProperty().parentModelNode();
|
||||||
@@ -752,6 +792,24 @@ void DynamicPropertiesModel::handleException()
|
|||||||
resetModel();
|
resetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QList<ModelNode> DynamicPropertiesModel::selectedNodes() const
|
||||||
|
{
|
||||||
|
// If selected nodes are explicitly set, return those.
|
||||||
|
// Otherwise return actual selected nodes of the model.
|
||||||
|
if (m_explicitSelection)
|
||||||
|
return m_selectedNodes;
|
||||||
|
else
|
||||||
|
return m_view->selectedModelNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModelNode DynamicPropertiesModel::singleSelectedNode() const
|
||||||
|
{
|
||||||
|
if (m_explicitSelection)
|
||||||
|
return m_selectedNodes.first();
|
||||||
|
else
|
||||||
|
return m_view->singleSelectedModelNode();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
namespace Internal {
|
class AbstractView;
|
||||||
|
|
||||||
class ConnectionView;
|
namespace Internal {
|
||||||
|
|
||||||
class DynamicPropertiesModel : public QStandardItemModel
|
class DynamicPropertiesModel : public QStandardItemModel
|
||||||
{
|
{
|
||||||
@@ -26,13 +26,17 @@ public:
|
|||||||
PropertyTypeRow = 2,
|
PropertyTypeRow = 2,
|
||||||
PropertyValueRow = 3
|
PropertyValueRow = 3
|
||||||
};
|
};
|
||||||
DynamicPropertiesModel(ConnectionView *parent = nullptr);
|
DynamicPropertiesModel(bool explicitSelection, AbstractView *parent);
|
||||||
void bindingPropertyChanged(const BindingProperty &bindingProperty);
|
void bindingPropertyChanged(const BindingProperty &bindingProperty);
|
||||||
void variantPropertyChanged(const VariantProperty &variantProperty);
|
void variantPropertyChanged(const VariantProperty &variantProperty);
|
||||||
void bindingRemoved(const BindingProperty &bindingProperty);
|
void bindingRemoved(const BindingProperty &bindingProperty);
|
||||||
void selectionChanged(const QList<ModelNode> &selectedNodes);
|
void variantRemoved(const VariantProperty &variantProperty);
|
||||||
|
void reset();
|
||||||
|
void setSelectedNode(const ModelNode &node);
|
||||||
|
const QList<ModelNode> selectedNodes() const;
|
||||||
|
const ModelNode singleSelectedNode() const;
|
||||||
|
|
||||||
ConnectionView *connectionView() const;
|
AbstractView *view() const { return m_view; }
|
||||||
AbstractProperty abstractPropertyForRow(int rowNumber) const;
|
AbstractProperty abstractPropertyForRow(int rowNumber) const;
|
||||||
BindingProperty bindingPropertyForRow(int rowNumber) const;
|
BindingProperty bindingPropertyForRow(int rowNumber) const;
|
||||||
VariantProperty variantPropertyForRow(int rowNumber) const;
|
VariantProperty variantPropertyForRow(int rowNumber) const;
|
||||||
@@ -49,6 +53,8 @@ public:
|
|||||||
|
|
||||||
QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode);
|
QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode);
|
||||||
|
|
||||||
|
static bool isValueType(const TypeName &type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addProperty(const QVariant &propertyValue,
|
void addProperty(const QVariant &propertyValue,
|
||||||
const QString &propertyType,
|
const QString &propertyType,
|
||||||
@@ -75,12 +81,12 @@ private:
|
|||||||
void handleDataChanged(const QModelIndex &topLeft, const QModelIndex& bottomRight);
|
void handleDataChanged(const QModelIndex &topLeft, const QModelIndex& bottomRight);
|
||||||
void handleException();
|
void handleException();
|
||||||
|
|
||||||
private:
|
AbstractView *m_view = nullptr;
|
||||||
ConnectionView *m_connectionView;
|
|
||||||
bool m_lock = false;
|
bool m_lock = false;
|
||||||
bool m_handleDataChanged = false;
|
bool m_handleDataChanged = false;
|
||||||
QString m_exceptionError;
|
QString m_exceptionError;
|
||||||
|
QList<ModelNode> m_selectedNodes;
|
||||||
|
bool m_explicitSelection = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "selectiondynamicpropertiesproxymodel.h"
|
||||||
|
|
||||||
|
#include <dynamicpropertiesmodel.h>
|
||||||
|
#include <connectionview.h>
|
||||||
|
|
||||||
|
using namespace QmlDesigner::Internal;
|
||||||
|
|
||||||
|
SelectionDynamicPropertiesProxyModel::SelectionDynamicPropertiesProxyModel(QObject *parent)
|
||||||
|
: DynamicPropertiesProxyModel(parent)
|
||||||
|
{
|
||||||
|
initModel(ConnectionView::instance()->dynamicPropertiesModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionDynamicPropertiesProxyModel::registerDeclarativeType()
|
||||||
|
{
|
||||||
|
DynamicPropertiesProxyModel::registerDeclarativeType();
|
||||||
|
qmlRegisterType<SelectionDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "SelectionDynamicPropertiesModel");
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <dynamicpropertiesproxymodel.h>
|
||||||
|
|
||||||
|
class SelectionDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SelectionDynamicPropertiesProxyModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
static void registerDeclarativeType();
|
||||||
|
};
|
||||||
@@ -219,7 +219,7 @@ void Edit3DView::handleEntriesChanged()
|
|||||||
|
|
||||||
const QList<ItemLibraryEntry> itemLibEntries = model()->metaInfo().itemLibraryInfo()->entries();
|
const QList<ItemLibraryEntry> itemLibEntries = model()->metaInfo().itemLibraryInfo()->entries();
|
||||||
for (const ItemLibraryEntry &entry : itemLibEntries) {
|
for (const ItemLibraryEntry &entry : itemLibEntries) {
|
||||||
if (entry.typeName() == "QtQuick3D.Model") {
|
if (entry.typeName() == "QtQuick3D.Model" && entry.name() != "Empty") {
|
||||||
entriesMap[primitives].append(entry);
|
entriesMap[primitives].append(entry);
|
||||||
} else if (entry.typeName() == "QtQuick3D.DirectionalLight"
|
} else if (entry.typeName() == "QtQuick3D.DirectionalLight"
|
||||||
|| entry.typeName() == "QtQuick3D.PointLight"
|
|| entry.typeName() == "QtQuick3D.PointLight"
|
||||||
@@ -264,28 +264,31 @@ void Edit3DView::customNotification([[maybe_unused]] const AbstractView *view,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get model at position from puppet process
|
* @brief Get node at position from puppet process
|
||||||
*
|
*
|
||||||
* Response from puppet process for the model at requested position
|
* Response from puppet process for the model at requested position
|
||||||
*
|
*
|
||||||
* @param modelNode 3D model picked at the requested position, invalid node if no model exists
|
* @param modelNode Node picked at the requested position or invalid node if nothing could be picked
|
||||||
*/
|
*/
|
||||||
void Edit3DView::modelAtPosReady(const ModelNode &modelNode)
|
void Edit3DView::nodeAtPosReady(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
if (m_modelAtPosReqType == ModelAtPosReqType::ContextMenu) {
|
if (m_nodeAtPosReqType == NodeAtPosReqType::ContextMenu) {
|
||||||
// Make sure right-clicked item is selected. Due to a bug in puppet side right-clicking an item
|
// Make sure right-clicked item is selected. Due to a bug in puppet side right-clicking an item
|
||||||
// while the context-menu is shown doesn't select the item.
|
// while the context-menu is shown doesn't select the item.
|
||||||
if (modelNode.isValid() && !modelNode.isSelected())
|
if (modelNode.isValid() && !modelNode.isSelected())
|
||||||
setSelectedModelNode(modelNode);
|
setSelectedModelNode(modelNode);
|
||||||
m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode);
|
m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode);
|
||||||
} else if (m_modelAtPosReqType == ModelAtPosReqType::MaterialDrop) {
|
} else if (m_nodeAtPosReqType == NodeAtPosReqType::MaterialDrop) {
|
||||||
if (m_droppedMaterial.isValid() && modelNode.isValid()) {
|
// TODO: this is from 8.0 branch that doesn't apply anymore:
|
||||||
|
// const bool isModel = modelNode.isSubclassOf("QtQuick3D.Model");
|
||||||
|
const bool isModel = false;
|
||||||
|
if (m_droppedMaterial.isValid() && modelNode.isValid() && isModel) {
|
||||||
executeInTransaction(__FUNCTION__, [&] {
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
assignMaterialTo3dModel(modelNode, m_droppedMaterial);
|
assignMaterialTo3dModel(modelNode, m_droppedMaterial);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_modelAtPosReqType = ModelAtPosReqType::None;
|
m_nodeAtPosReqType = NodeAtPosReqType::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Edit3DView::sendInputEvent(QInputEvent *e) const
|
void Edit3DView::sendInputEvent(QInputEvent *e) const
|
||||||
@@ -671,18 +674,18 @@ void Edit3DView::addQuick3DImport()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This method is called upon right-clicking the view to prepare for context-menu creation. The actual
|
// This method is called upon right-clicking the view to prepare for context-menu creation. The actual
|
||||||
// context menu is created when modelAtPosReady() is received from puppet
|
// context menu is created when nodeAtPosReady() is received from puppet
|
||||||
void Edit3DView::startContextMenu(const QPoint &pos)
|
void Edit3DView::startContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
m_contextMenuPos = pos;
|
m_contextMenuPos = pos;
|
||||||
m_modelAtPosReqType = ModelAtPosReqType::ContextMenu;
|
m_nodeAtPosReqType = NodeAtPosReqType::ContextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos)
|
void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos)
|
||||||
{
|
{
|
||||||
m_modelAtPosReqType = ModelAtPosReqType::MaterialDrop;
|
m_nodeAtPosReqType = NodeAtPosReqType::MaterialDrop;
|
||||||
m_droppedMaterial = matNode;
|
m_droppedMaterial = matNode;
|
||||||
QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos});
|
QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetNodeAtPos, pos});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
void modelAboutToBeDetached(Model *model) override;
|
void modelAboutToBeDetached(Model *model) override;
|
||||||
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
|
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
|
||||||
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
|
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
|
||||||
void modelAtPosReady(const ModelNode &modelNode) override;
|
void nodeAtPosReady(const ModelNode &modelNode) override;
|
||||||
|
|
||||||
void sendInputEvent(QInputEvent *e) const;
|
void sendInputEvent(QInputEvent *e) const;
|
||||||
void edit3DViewResized(const QSize &size) const;
|
void edit3DViewResized(const QSize &size) const;
|
||||||
@@ -63,7 +63,7 @@ private slots:
|
|||||||
void onEntriesChanged();
|
void onEntriesChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class ModelAtPosReqType {
|
enum class NodeAtPosReqType {
|
||||||
MaterialDrop,
|
MaterialDrop,
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
None
|
None
|
||||||
@@ -108,7 +108,7 @@ private:
|
|||||||
int particlemode;
|
int particlemode;
|
||||||
ModelCache<QImage> m_canvasCache;
|
ModelCache<QImage> m_canvasCache;
|
||||||
ModelNode m_droppedMaterial;
|
ModelNode m_droppedMaterial;
|
||||||
ModelAtPosReqType m_modelAtPosReqType;
|
NodeAtPosReqType m_nodeAtPosReqType;
|
||||||
QPoint m_contextMenuPos;
|
QPoint m_contextMenuPos;
|
||||||
QTimer m_compressionTimer;
|
QTimer m_compressionTimer;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -278,8 +278,12 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
|
|||||||
{
|
{
|
||||||
m_contextMenuTarget = modelNode;
|
m_contextMenuTarget = modelNode;
|
||||||
|
|
||||||
m_editMaterialAction->setEnabled(modelNode.isValid());
|
const bool isValid = modelNode.isValid();
|
||||||
m_deleteAction->setEnabled(modelNode.isValid());
|
// TODO: this is from 8.0 branch that doesn't apply anymore:
|
||||||
|
// const bool isModel = isValid && modelNode.isSubclassOf("QtQuick3D.Model");
|
||||||
|
const bool isModel = false;
|
||||||
|
m_editMaterialAction->setEnabled(isModel);
|
||||||
|
m_deleteAction->setEnabled(isValid && !modelNode.isRootNode());
|
||||||
|
|
||||||
m_contextMenu->popup(mapToGlobal(pos));
|
m_contextMenu->popup(mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "bundleimporter.h"
|
||||||
|
|
||||||
|
#include "import.h"
|
||||||
|
#include "model.h"
|
||||||
|
#include "qmldesignerconstants.h"
|
||||||
|
#include "qmldesignerplugin.h"
|
||||||
|
#include "rewritingexception.h"
|
||||||
|
|
||||||
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QSaveFile>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace QmlDesigner::Internal {
|
||||||
|
|
||||||
|
BundleImporter::BundleImporter(const QString &bundleDir,
|
||||||
|
const QString &bundleId,
|
||||||
|
const QStringList &sharedFiles,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_bundleDir(FilePath::fromString(bundleDir))
|
||||||
|
, m_bundleId(bundleId)
|
||||||
|
, m_sharedFiles(sharedFiles)
|
||||||
|
{
|
||||||
|
m_importTimer.setInterval(200);
|
||||||
|
connect(&m_importTimer, &QTimer::timeout, this, &BundleImporter::handleImportTimer);
|
||||||
|
m_moduleName = QStringLiteral("%1.%2").arg(
|
||||||
|
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER),
|
||||||
|
m_bundleId).mid(1); // Chop leading slash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns empty string on success or an error message on failure.
|
||||||
|
// Note that there is also an asynchronous portion to the import, which will only
|
||||||
|
// be done if this method returns success. Once the asynchronous portion of the
|
||||||
|
// import is completed, importFinished signal will be emitted.
|
||||||
|
QString BundleImporter::importComponent(const QString &qmlFile,
|
||||||
|
const QStringList &files)
|
||||||
|
{
|
||||||
|
FilePath bundleImportPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
|
||||||
|
if (bundleImportPath.isEmpty())
|
||||||
|
return "Failed to resolve current project path";
|
||||||
|
|
||||||
|
const QString projectBundlePath = QStringLiteral("%1%2/%3").arg(
|
||||||
|
QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER),
|
||||||
|
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER),
|
||||||
|
m_bundleId).mid(1); // Chop leading slash
|
||||||
|
bundleImportPath = bundleImportPath.resolvePath(projectBundlePath);
|
||||||
|
|
||||||
|
if (!bundleImportPath.exists()) {
|
||||||
|
if (!bundleImportPath.createDir())
|
||||||
|
return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString &file : qAsConst(m_sharedFiles)) {
|
||||||
|
FilePath target = bundleImportPath.resolvePath(file);
|
||||||
|
if (!target.exists()) {
|
||||||
|
FilePath parentDir = target.parentDir();
|
||||||
|
if (!parentDir.exists() && !parentDir.createDir())
|
||||||
|
return QStringLiteral("Failed to create folder for: '%1'").arg(target.toString());
|
||||||
|
FilePath source = m_bundleDir.resolvePath(file);
|
||||||
|
if (!source.copyFile(target))
|
||||||
|
return QStringLiteral("Failed to copy shared file: '%1'").arg(source.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath qmldirPath = bundleImportPath.resolvePath(QStringLiteral("qmldir"));
|
||||||
|
QFile qmldirFile(qmldirPath.toString());
|
||||||
|
|
||||||
|
QString qmldirContent;
|
||||||
|
if (qmldirPath.exists()) {
|
||||||
|
if (!qmldirFile.open(QIODeviceBase::ReadOnly))
|
||||||
|
return QStringLiteral("Failed to open qmldir file for reading: '%1'").arg(qmldirPath.toString());
|
||||||
|
qmldirContent = QString::fromUtf8(qmldirFile.readAll());
|
||||||
|
qmldirFile.close();
|
||||||
|
} else {
|
||||||
|
qmldirContent.append("module ");
|
||||||
|
qmldirContent.append(m_moduleName);
|
||||||
|
qmldirContent.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath qmlSourceFile = FilePath::fromString(qmlFile);
|
||||||
|
const bool qmlFileExists = qmlSourceFile.exists();
|
||||||
|
const QString qmlType = qmlSourceFile.baseName();
|
||||||
|
m_pendingTypes.append(QStringLiteral("%1.%2")
|
||||||
|
.arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), qmlType));
|
||||||
|
if (!qmldirContent.contains(qmlFile)) {
|
||||||
|
QSaveFile qmldirSaveFile(qmldirPath.toString());
|
||||||
|
if (!qmldirSaveFile.open(QIODeviceBase::WriteOnly | QIODeviceBase::Truncate))
|
||||||
|
return QStringLiteral("Failed to open qmldir file for writing: '%1'").arg(qmldirPath.toString());
|
||||||
|
|
||||||
|
qmldirContent.append(qmlType);
|
||||||
|
qmldirContent.append(" 1.0 ");
|
||||||
|
qmldirContent.append(qmlFile);
|
||||||
|
qmldirContent.append('\n');
|
||||||
|
|
||||||
|
qmldirSaveFile.write(qmldirContent.toUtf8());
|
||||||
|
qmldirSaveFile.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList allFiles;
|
||||||
|
allFiles.append(files);
|
||||||
|
allFiles.append(qmlFile);
|
||||||
|
for (const QString &file : qAsConst(allFiles)) {
|
||||||
|
FilePath target = bundleImportPath.resolvePath(file);
|
||||||
|
FilePath parentDir = target.parentDir();
|
||||||
|
if (!parentDir.exists() && !parentDir.createDir())
|
||||||
|
return QStringLiteral("Failed to create folder for: '%1'").arg(target.toString());
|
||||||
|
|
||||||
|
FilePath source = m_bundleDir.resolvePath(file);
|
||||||
|
if (target.exists()) {
|
||||||
|
if (source.lastModified() == target.lastModified())
|
||||||
|
continue;
|
||||||
|
target.removeFile(); // Remove existing file for update
|
||||||
|
}
|
||||||
|
if (!source.copyFile(target))
|
||||||
|
return QStringLiteral("Failed to copy file: '%1'").arg(source.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fullReset = !qmlFileExists;
|
||||||
|
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||||
|
Model *model = doc ? doc->currentModel() : nullptr;
|
||||||
|
if (!model)
|
||||||
|
return "Model not available, cannot add import statement or update code model";
|
||||||
|
|
||||||
|
Import import = Import::createLibraryImport(m_moduleName, "1.0");
|
||||||
|
if (!model->hasImport(import)) {
|
||||||
|
if (model->possibleImports().contains(import)) {
|
||||||
|
m_importAddPending = false;
|
||||||
|
try {
|
||||||
|
model->changeImports({import}, {});
|
||||||
|
} catch (const RewritingException &) {
|
||||||
|
// No point in trying to add import asynchronously either, so just fail out
|
||||||
|
return QStringLiteral("Failed to add import statement for: '%1'").arg(m_moduleName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If import is not yet possible, import statement needs to be added asynchronously to
|
||||||
|
// avoid errors, as code model update takes a while. Full reset is not necessary
|
||||||
|
// in this case, as new import directory appearing will trigger scanning of it.
|
||||||
|
m_importAddPending = true;
|
||||||
|
m_fullReset = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_importTimerCount = 0;
|
||||||
|
m_importTimer.start();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void BundleImporter::handleImportTimer()
|
||||||
|
{
|
||||||
|
auto handleFailure = [this]() {
|
||||||
|
m_importTimer.stop();
|
||||||
|
m_fullReset = false;
|
||||||
|
m_importAddPending = false;
|
||||||
|
m_importTimerCount = 0;
|
||||||
|
m_pendingTypes.clear();
|
||||||
|
emit importFinished({});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||||
|
Model *model = doc ? doc->currentModel() : nullptr;
|
||||||
|
if (!model || ++m_importTimerCount > 100) {
|
||||||
|
handleFailure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fullReset) {
|
||||||
|
// Force code model reset to notice changes to existing module
|
||||||
|
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||||
|
if (modelManager)
|
||||||
|
modelManager->resetCodeModel();
|
||||||
|
m_fullReset = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_importAddPending) {
|
||||||
|
try {
|
||||||
|
Import import = Import::createLibraryImport(m_moduleName, "1.0");
|
||||||
|
if (model->possibleImports().contains(import)) {
|
||||||
|
model->changeImports({import}, {});
|
||||||
|
m_importAddPending = false;
|
||||||
|
}
|
||||||
|
} catch (const RewritingException &) {
|
||||||
|
// Import adding is unlikely to succeed later, either, so just bail out
|
||||||
|
handleFailure();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect when the code model has the new material(s) fully available
|
||||||
|
const QStringList pendingTypes = m_pendingTypes;
|
||||||
|
for (const QString &pendingType : pendingTypes) {
|
||||||
|
NodeMetaInfo metaInfo = model->metaInfo(pendingType.toUtf8());
|
||||||
|
if (metaInfo.isValid() && !metaInfo.superClasses().empty()) {
|
||||||
|
m_pendingTypes.removeAll(pendingType);
|
||||||
|
emit importFinished(metaInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pendingTypes.isEmpty()) {
|
||||||
|
m_importTimer.stop();
|
||||||
|
m_importTimerCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner::Internal
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <utils/filepath.h>
|
||||||
|
|
||||||
|
#include "nodemetainfo.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace QmlDesigner::Internal {
|
||||||
|
|
||||||
|
class BundleImporter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
BundleImporter(const QString &bundleDir,
|
||||||
|
const QString &bundleId,
|
||||||
|
const QStringList &sharedFiles,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
~BundleImporter() = default;
|
||||||
|
|
||||||
|
QString importComponent(const QString &qmlFile,
|
||||||
|
const QStringList &files);
|
||||||
|
signals:
|
||||||
|
// The metaInfo parameter will be invalid if an error was encountered during
|
||||||
|
// asynchronous part of the import. In this case all remaining pending imports have been
|
||||||
|
// terminated, and will not receive separate importFinished notifications.
|
||||||
|
void importFinished(const QmlDesigner::NodeMetaInfo &metaInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleImportTimer();
|
||||||
|
|
||||||
|
Utils::FilePath m_bundleDir;
|
||||||
|
QString m_bundleId;
|
||||||
|
QString m_moduleName;
|
||||||
|
QStringList m_sharedFiles;
|
||||||
|
QTimer m_importTimer;
|
||||||
|
int m_importTimerCount = 0;
|
||||||
|
bool m_importAddPending = false;
|
||||||
|
bool m_fullReset = false;
|
||||||
|
QStringList m_pendingTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner::Internal
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "materialeditordynamicpropertiesproxymodel.h"
|
||||||
|
|
||||||
|
#include <dynamicpropertiesmodel.h>
|
||||||
|
|
||||||
|
#include <materialeditorview.h>
|
||||||
|
|
||||||
|
using namespace QmlDesigner;
|
||||||
|
|
||||||
|
MaterialEditorDynamicPropertiesProxyModel::MaterialEditorDynamicPropertiesProxyModel(QObject *parent)
|
||||||
|
: DynamicPropertiesProxyModel(parent)
|
||||||
|
{
|
||||||
|
initModel(MaterialEditorView::instance()->dynamicPropertiesModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType()
|
||||||
|
{
|
||||||
|
DynamicPropertiesProxyModel::registerDeclarativeType();
|
||||||
|
qmlRegisterType<MaterialEditorDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "MaterialEditorDynamicPropertiesModel");
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "dynamicpropertiesproxymodel.h"
|
||||||
|
|
||||||
|
class MaterialEditorDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MaterialEditorDynamicPropertiesProxyModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
static void registerDeclarativeType();
|
||||||
|
};
|
||||||
@@ -5,12 +5,14 @@
|
|||||||
|
|
||||||
#include "materialeditorqmlbackend.h"
|
#include "materialeditorqmlbackend.h"
|
||||||
#include "materialeditorcontextobject.h"
|
#include "materialeditorcontextobject.h"
|
||||||
|
#include "materialeditordynamicpropertiesproxymodel.h"
|
||||||
#include "propertyeditorvalue.h"
|
#include "propertyeditorvalue.h"
|
||||||
#include "materialeditortransaction.h"
|
#include "materialeditortransaction.h"
|
||||||
#include "assetslibrarywidget.h"
|
#include "assetslibrarywidget.h"
|
||||||
|
|
||||||
#include <auxiliarydataproperties.h>
|
#include <auxiliarydataproperties.h>
|
||||||
#include <bindingproperty.h>
|
#include <bindingproperty.h>
|
||||||
|
#include <dynamicpropertiesmodel.h>
|
||||||
#include <metainfo.h>
|
#include <metainfo.h>
|
||||||
#include <nodeinstanceview.h>
|
#include <nodeinstanceview.h>
|
||||||
#include <nodelistproperty.h>
|
#include <nodelistproperty.h>
|
||||||
@@ -49,6 +51,7 @@ namespace QmlDesigner {
|
|||||||
MaterialEditorView::MaterialEditorView(QWidget *parent)
|
MaterialEditorView::MaterialEditorView(QWidget *parent)
|
||||||
: AbstractView(parent)
|
: AbstractView(parent)
|
||||||
, m_stackedWidget(new QStackedWidget(parent))
|
, m_stackedWidget(new QStackedWidget(parent))
|
||||||
|
, m_dynamicPropertiesModel(new Internal::DynamicPropertiesModel(true, this))
|
||||||
{
|
{
|
||||||
m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7), m_stackedWidget);
|
m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7), m_stackedWidget);
|
||||||
connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml);
|
connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml);
|
||||||
@@ -71,6 +74,8 @@ MaterialEditorView::MaterialEditorView(QWidget *parent)
|
|||||||
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
|
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
|
||||||
m_stackedWidget->setMinimumWidth(250);
|
m_stackedWidget->setMinimumWidth(250);
|
||||||
QmlDesignerPlugin::trackWidgetFocusTime(m_stackedWidget, Constants::EVENT_MATERIALEDITOR_TIME);
|
QmlDesignerPlugin::trackWidgetFocusTime(m_stackedWidget, Constants::EVENT_MATERIALEDITOR_TIME);
|
||||||
|
|
||||||
|
MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialEditorView::~MaterialEditorView()
|
MaterialEditorView::~MaterialEditorView()
|
||||||
@@ -294,6 +299,29 @@ void MaterialEditorView::currentTimelineChanged(const ModelNode &)
|
|||||||
m_qmlBackEnd->contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(this));
|
m_qmlBackEnd->contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Internal::DynamicPropertiesModel *MaterialEditorView::dynamicPropertiesModel() const
|
||||||
|
{
|
||||||
|
return m_dynamicPropertiesModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialEditorView *MaterialEditorView::instance()
|
||||||
|
{
|
||||||
|
static MaterialEditorView *s_instance = nullptr;
|
||||||
|
|
||||||
|
if (s_instance)
|
||||||
|
return s_instance;
|
||||||
|
|
||||||
|
const auto views = QmlDesignerPlugin::instance()->viewManager().views();
|
||||||
|
for (auto *view : views) {
|
||||||
|
MaterialEditorView *myView = qobject_cast<MaterialEditorView *>(view);
|
||||||
|
if (myView)
|
||||||
|
s_instance = myView;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTC_ASSERT(s_instance, return nullptr);
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
void MaterialEditorView::delayedResetView()
|
void MaterialEditorView::delayedResetView()
|
||||||
{
|
{
|
||||||
// TODO: it seems the delayed reset is not needed. Leaving it commented out for now just in case it
|
// TODO: it seems the delayed reset is not needed. Leaving it commented out for now just in case it
|
||||||
@@ -575,6 +603,11 @@ void MaterialEditorView::setupQmlBackend()
|
|||||||
|
|
||||||
m_qmlBackEnd = currentQmlBackend;
|
m_qmlBackEnd = currentQmlBackend;
|
||||||
|
|
||||||
|
if (m_hasMaterialRoot)
|
||||||
|
m_dynamicPropertiesModel->setSelectedNode(m_selectedMaterial);
|
||||||
|
else
|
||||||
|
m_dynamicPropertiesModel->reset();
|
||||||
|
|
||||||
delayedTypeUpdate();
|
delayedTypeUpdate();
|
||||||
initPreviewData();
|
initPreviewData();
|
||||||
|
|
||||||
@@ -746,6 +779,7 @@ void MaterialEditorView::modelAttached(Model *model)
|
|||||||
void MaterialEditorView::modelAboutToBeDetached(Model *model)
|
void MaterialEditorView::modelAboutToBeDetached(Model *model)
|
||||||
{
|
{
|
||||||
AbstractView::modelAboutToBeDetached(model);
|
AbstractView::modelAboutToBeDetached(model);
|
||||||
|
m_dynamicPropertiesModel->reset();
|
||||||
m_qmlBackEnd->materialEditorTransaction()->end();
|
m_qmlBackEnd->materialEditorTransaction()->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,8 +812,9 @@ void MaterialEditorView::variantPropertiesChanged(const QList<VariantProperty> &
|
|||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (const VariantProperty &property : propertyList) {
|
for (const VariantProperty &property : propertyList) {
|
||||||
ModelNode node(property.parentModelNode());
|
ModelNode node(property.parentModelNode());
|
||||||
|
|
||||||
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
||||||
|
if (property.isDynamic())
|
||||||
|
m_dynamicPropertiesModel->variantPropertyChanged(property);
|
||||||
if (m_selectedMaterial.property(property.name()).isBindingProperty())
|
if (m_selectedMaterial.property(property.name()).isBindingProperty())
|
||||||
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
||||||
else
|
else
|
||||||
@@ -805,6 +840,8 @@ void MaterialEditorView::bindingPropertiesChanged(const QList<BindingProperty> &
|
|||||||
m_qmlBackEnd->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedMaterial).isAliasExported());
|
m_qmlBackEnd->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedMaterial).isAliasExported());
|
||||||
|
|
||||||
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
||||||
|
if (property.isDynamic())
|
||||||
|
m_dynamicPropertiesModel->bindingPropertyChanged(property);
|
||||||
if (QmlObjectNode(m_selectedMaterial).modelNode().property(property.name()).isBindingProperty())
|
if (QmlObjectNode(m_selectedMaterial).modelNode().property(property.name()).isBindingProperty())
|
||||||
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
||||||
else
|
else
|
||||||
@@ -828,6 +865,16 @@ void MaterialEditorView::auxiliaryDataChanged(const ModelNode &node,
|
|||||||
m_qmlBackEnd->setValueforAuxiliaryProperties(m_selectedMaterial, key);
|
m_qmlBackEnd->setValueforAuxiliaryProperties(m_selectedMaterial, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MaterialEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList)
|
||||||
|
{
|
||||||
|
for (const auto &property : propertyList) {
|
||||||
|
if (property.isBindingProperty())
|
||||||
|
m_dynamicPropertiesModel->bindingRemoved(property.toBindingProperty());
|
||||||
|
else if (property.isVariantProperty())
|
||||||
|
m_dynamicPropertiesModel->variantRemoved(property.toVariantProperty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// request render image for the selected material node
|
// request render image for the selected material node
|
||||||
void MaterialEditorView::requestPreviewRender()
|
void MaterialEditorView::requestPreviewRender()
|
||||||
{
|
{
|
||||||
@@ -936,7 +983,7 @@ void MaterialEditorView::renameMaterial(ModelNode &material, const QString &newN
|
|||||||
QTC_ASSERT(material.isValid(), return);
|
QTC_ASSERT(material.isValid(), return);
|
||||||
|
|
||||||
executeInTransaction("MaterialEditorView:renameMaterial", [&] {
|
executeInTransaction("MaterialEditorView:renameMaterial", [&] {
|
||||||
material.setIdWithRefactoring(generateIdFromName(newName));
|
material.setIdWithRefactoring(model()->generateIdFromName(newName, "material"));
|
||||||
|
|
||||||
VariantProperty objNameProp = material.variantProperty("objectName");
|
VariantProperty objNameProp = material.variantProperty("objectName");
|
||||||
objNameProp.setValue(newName);
|
objNameProp.setValue(newName);
|
||||||
@@ -965,7 +1012,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
|
|||||||
// set name and id
|
// set name and id
|
||||||
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
|
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
|
||||||
duplicateMat.modelNode().variantProperty("objectName").setValue(newName);
|
duplicateMat.modelNode().variantProperty("objectName").setValue(newName);
|
||||||
duplicateMat.modelNode().setIdWithoutRefactoring(generateIdFromName(newName));
|
duplicateMat.modelNode().setIdWithoutRefactoring(model()->generateIdFromName(newName, "material"));
|
||||||
|
|
||||||
// sync properties
|
// sync properties
|
||||||
const QList<AbstractProperty> props = material.properties();
|
const QList<AbstractProperty> props = material.properties();
|
||||||
@@ -991,6 +1038,7 @@ void MaterialEditorView::customNotification([[maybe_unused]] const AbstractView
|
|||||||
if (identifier == "selected_material_changed") {
|
if (identifier == "selected_material_changed") {
|
||||||
if (!m_hasMaterialRoot) {
|
if (!m_hasMaterialRoot) {
|
||||||
m_selectedMaterial = nodeList.first();
|
m_selectedMaterial = nodeList.first();
|
||||||
|
m_dynamicPropertiesModel->setSelectedNode(m_selectedMaterial);
|
||||||
QTimer::singleShot(0, this, &MaterialEditorView::resetView);
|
QTimer::singleShot(0, this, &MaterialEditorView::resetView);
|
||||||
}
|
}
|
||||||
} else if (identifier == "apply_to_selected_triggered") {
|
} else if (identifier == "apply_to_selected_triggered") {
|
||||||
@@ -1072,38 +1120,4 @@ void MaterialEditorView::reloadQml()
|
|||||||
resetView();
|
resetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a unique camelCase id from a name
|
|
||||||
QString MaterialEditorView::generateIdFromName(const QString &name)
|
|
||||||
{
|
|
||||||
QString newId;
|
|
||||||
if (name.isEmpty()) {
|
|
||||||
newId = "material";
|
|
||||||
} else {
|
|
||||||
// convert to camel case
|
|
||||||
QStringList nameWords = name.split(" ");
|
|
||||||
nameWords[0] = nameWords[0].at(0).toLower() + nameWords[0].mid(1);
|
|
||||||
for (int i = 1; i < nameWords.size(); ++i)
|
|
||||||
nameWords[i] = nameWords[i].at(0).toUpper() + nameWords[i].mid(1);
|
|
||||||
newId = nameWords.join("");
|
|
||||||
|
|
||||||
// if id starts with a number prepend an underscore
|
|
||||||
if (newId.at(0).isDigit())
|
|
||||||
newId.prepend('_');
|
|
||||||
}
|
|
||||||
|
|
||||||
QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
|
|
||||||
while (hasId(newId)) { // id exists
|
|
||||||
QRegularExpressionMatch match = rgx.match(newId);
|
|
||||||
if (match.hasMatch()) { // ends with a number, increment it
|
|
||||||
QString numStr = match.captured();
|
|
||||||
int num = numStr.toInt() + 1;
|
|
||||||
newId = newId.mid(0, match.capturedStart()) + QString::number(num);
|
|
||||||
} else {
|
|
||||||
newId.append('1');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newId;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ namespace QmlDesigner {
|
|||||||
class ModelNode;
|
class ModelNode;
|
||||||
class MaterialEditorQmlBackend;
|
class MaterialEditorQmlBackend;
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
class DynamicPropertiesModel;
|
||||||
|
}
|
||||||
|
|
||||||
class MaterialEditorView : public AbstractView
|
class MaterialEditorView : public AbstractView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -46,6 +50,7 @@ public:
|
|||||||
void auxiliaryDataChanged(const ModelNode &node,
|
void auxiliaryDataChanged(const ModelNode &node,
|
||||||
AuxiliaryDataKeyView key,
|
AuxiliaryDataKeyView key,
|
||||||
const QVariant &data) override;
|
const QVariant &data) override;
|
||||||
|
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
|
||||||
|
|
||||||
void resetView();
|
void resetView();
|
||||||
void currentStateChanged(const ModelNode &node) override;
|
void currentStateChanged(const ModelNode &node) override;
|
||||||
@@ -70,6 +75,10 @@ public:
|
|||||||
|
|
||||||
void currentTimelineChanged(const ModelNode &node) override;
|
void currentTimelineChanged(const ModelNode &node) override;
|
||||||
|
|
||||||
|
Internal::DynamicPropertiesModel *dynamicPropertiesModel() const;
|
||||||
|
|
||||||
|
static MaterialEditorView *instance();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void handleToolBarAction(int action);
|
void handleToolBarAction(int action);
|
||||||
void handlePreviewEnvChanged(const QString &envAndValue);
|
void handlePreviewEnvChanged(const QString &envAndValue);
|
||||||
@@ -85,7 +94,6 @@ private:
|
|||||||
|
|
||||||
void reloadQml();
|
void reloadQml();
|
||||||
void highlightSupportedProperties(bool highlight = true);
|
void highlightSupportedProperties(bool highlight = true);
|
||||||
QString generateIdFromName(const QString &name);
|
|
||||||
|
|
||||||
void requestPreviewRender();
|
void requestPreviewRender();
|
||||||
void applyMaterialToSelectedModels(const ModelNode &material, bool add = false);
|
void applyMaterialToSelectedModels(const ModelNode &material, bool add = false);
|
||||||
@@ -122,6 +130,7 @@ private:
|
|||||||
|
|
||||||
QPointer<QColorDialog> m_colorDialog;
|
QPointer<QColorDialog> m_colorDialog;
|
||||||
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
|
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
|
||||||
|
Internal::DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -0,0 +1,392 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "dynamicpropertiesproxymodel.h"
|
||||||
|
|
||||||
|
#include "propertyeditorvalue.h"
|
||||||
|
|
||||||
|
#include <dynamicpropertiesmodel.h>
|
||||||
|
|
||||||
|
#include <abstractproperty.h>
|
||||||
|
#include <bindingeditor.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <qmldesignerconstants.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QScopeGuard>
|
||||||
|
|
||||||
|
using namespace QmlDesigner;
|
||||||
|
|
||||||
|
static const int propertyNameRole = Qt::UserRole + 1;
|
||||||
|
static const int propertyTypeRole = Qt::UserRole + 2;
|
||||||
|
static const int propertyValueRole = Qt::UserRole + 3;
|
||||||
|
static const int propertyBindingRole = Qt::UserRole + 4;
|
||||||
|
|
||||||
|
DynamicPropertiesProxyModel::DynamicPropertiesProxyModel(QObject *parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertiesProxyModel::initModel(QmlDesigner::Internal::DynamicPropertiesModel *model)
|
||||||
|
{
|
||||||
|
m_model = model;
|
||||||
|
|
||||||
|
connect(m_model, &QAbstractItemModel::modelAboutToBeReset,
|
||||||
|
this, &QAbstractItemModel::modelAboutToBeReset);
|
||||||
|
connect(m_model, &QAbstractItemModel::modelReset,
|
||||||
|
this, &QAbstractItemModel::modelReset);
|
||||||
|
|
||||||
|
connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
|
||||||
|
this, &QAbstractItemModel::rowsAboutToBeRemoved);
|
||||||
|
connect(m_model, &QAbstractItemModel::rowsRemoved,
|
||||||
|
this, &QAbstractItemModel::rowsRemoved);
|
||||||
|
connect(m_model, &QAbstractItemModel::rowsInserted,
|
||||||
|
this, &QAbstractItemModel::rowsInserted);
|
||||||
|
|
||||||
|
connect(m_model, &QAbstractItemModel::dataChanged,
|
||||||
|
this, [this](const QModelIndex &topLeft, const QModelIndex &, const QList<int> &) {
|
||||||
|
emit dataChanged(index(topLeft.row(), 0),
|
||||||
|
index(topLeft.row(), 0),
|
||||||
|
{ propertyNameRole, propertyTypeRole,
|
||||||
|
propertyValueRole, propertyBindingRole });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int DynamicPropertiesProxyModel::rowCount(const QModelIndex &) const
|
||||||
|
{
|
||||||
|
return m_model->rowCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> DynamicPropertiesProxyModel::roleNames() const
|
||||||
|
{
|
||||||
|
static QHash<int, QByteArray> roleNames{{propertyNameRole, "propertyName"},
|
||||||
|
{propertyTypeRole, "propertyType"},
|
||||||
|
{propertyValueRole, "propertyValue"},
|
||||||
|
{propertyBindingRole, "propertyBinding"}};
|
||||||
|
|
||||||
|
return roleNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DynamicPropertiesProxyModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (index.isValid() && index.row() < rowCount()) {
|
||||||
|
AbstractProperty property = m_model->abstractPropertyForRow(index.row());
|
||||||
|
|
||||||
|
QTC_ASSERT(property.isValid(), return QVariant());
|
||||||
|
|
||||||
|
if (role == propertyNameRole) {
|
||||||
|
return property.name();
|
||||||
|
} else if (propertyTypeRole) {
|
||||||
|
return property.dynamicTypeName();
|
||||||
|
} else if (role == propertyValueRole) {
|
||||||
|
QmlObjectNode objectNode = property.parentQmlObjectNode();
|
||||||
|
return objectNode.modelValue(property.name());
|
||||||
|
} else if (role == propertyBindingRole) {
|
||||||
|
if (property.isBindingProperty())
|
||||||
|
return property.toBindingProperty().expression();
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
qWarning() << Q_FUNC_INFO << "invalid role";
|
||||||
|
} else {
|
||||||
|
qWarning() << Q_FUNC_INFO << "invalid index";
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertiesProxyModel::registerDeclarativeType()
|
||||||
|
{
|
||||||
|
static bool registered = false;
|
||||||
|
if (!registered)
|
||||||
|
qmlRegisterType<DynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "DynamicPropertiesModel");
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlDesigner::Internal::DynamicPropertiesModel *DynamicPropertiesProxyModel::dynamicPropertiesModel() const
|
||||||
|
{
|
||||||
|
return m_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DynamicPropertiesProxyModel::newPropertyName() const
|
||||||
|
{
|
||||||
|
auto propertiesModel = dynamicPropertiesModel();
|
||||||
|
|
||||||
|
return QString::fromUtf8(propertiesModel->unusedProperty(
|
||||||
|
propertiesModel->singleSelectedNode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertiesProxyModel::createProperty(const QString &name, const QString &type)
|
||||||
|
{
|
||||||
|
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
|
||||||
|
|
||||||
|
const auto selectedNodes = dynamicPropertiesModel()->selectedNodes();
|
||||||
|
if (selectedNodes.count() == 1) {
|
||||||
|
const ModelNode modelNode = selectedNodes.constFirst();
|
||||||
|
if (modelNode.isValid()) {
|
||||||
|
try {
|
||||||
|
if (Internal::DynamicPropertiesModel::isValueType(type.toUtf8())) {
|
||||||
|
QVariant value;
|
||||||
|
if (type == "int")
|
||||||
|
value = 0;
|
||||||
|
else if (type == "real")
|
||||||
|
value = 0.0;
|
||||||
|
else if (type == "color")
|
||||||
|
value = QColor(255, 255, 255);
|
||||||
|
else if (type == "string")
|
||||||
|
value = "";
|
||||||
|
else if (type == "bool")
|
||||||
|
value = false;
|
||||||
|
else if (type == "url")
|
||||||
|
value = "";
|
||||||
|
else if (type == "variant")
|
||||||
|
value = "";
|
||||||
|
|
||||||
|
modelNode.variantProperty(name.toUtf8())
|
||||||
|
.setDynamicTypeNameAndValue(type.toUtf8(), value);
|
||||||
|
} else {
|
||||||
|
QString expression;
|
||||||
|
if (type == "alias")
|
||||||
|
expression = "null";
|
||||||
|
else if (type == "TextureInput")
|
||||||
|
expression = "null";
|
||||||
|
else if (type == "vector2d")
|
||||||
|
expression = "Qt.vector2d(0, 0)";
|
||||||
|
else if (type == "vector3d")
|
||||||
|
expression = "Qt.vector3d(0, 0, 0)";
|
||||||
|
else if (type == "vector4d")
|
||||||
|
expression = "Qt.vector4d(0, 0, 0 ,0)";
|
||||||
|
|
||||||
|
modelNode.bindingProperty(name.toUtf8())
|
||||||
|
.setDynamicTypeNameAndExpression(type.toUtf8(), expression);
|
||||||
|
}
|
||||||
|
} catch (Exception &e) {
|
||||||
|
e.showException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << " BindingModel::addBindingForCurrentNode not one node selected";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPropertyRow::DynamicPropertyRow(QObject *parent)
|
||||||
|
{
|
||||||
|
m_backendValue = new PropertyEditorValue(this);
|
||||||
|
|
||||||
|
QObject::connect(m_backendValue,
|
||||||
|
&PropertyEditorValue::valueChanged,
|
||||||
|
this,
|
||||||
|
[this](const QString &, const QVariant &value) { commitValue(value); });
|
||||||
|
|
||||||
|
QObject::connect(m_backendValue,
|
||||||
|
&PropertyEditorValue::expressionChanged,
|
||||||
|
this,
|
||||||
|
[this](const QString &) { commitExpression(m_backendValue->expression()); });
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPropertyRow::~DynamicPropertyRow()
|
||||||
|
{
|
||||||
|
clearProxyBackendValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::registerDeclarativeType()
|
||||||
|
{
|
||||||
|
qmlRegisterType<DynamicPropertyRow>("HelperWidgets", 2, 0, "DynamicPropertyRow");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::setRow(int r)
|
||||||
|
{
|
||||||
|
if (m_row == r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_row = r;
|
||||||
|
setupBackendValue();
|
||||||
|
emit rowChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
int DynamicPropertyRow::row() const
|
||||||
|
{
|
||||||
|
return m_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::setModel(DynamicPropertiesProxyModel *model)
|
||||||
|
{
|
||||||
|
if (model == m_model)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_model) {
|
||||||
|
disconnect(m_model, &QAbstractItemModel::dataChanged,
|
||||||
|
this, &DynamicPropertyRow::handleDataChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_model = model;
|
||||||
|
|
||||||
|
if (m_model) {
|
||||||
|
connect(m_model, &QAbstractItemModel::dataChanged,
|
||||||
|
this, &DynamicPropertyRow::handleDataChanged);
|
||||||
|
|
||||||
|
if (m_row != -1)
|
||||||
|
setupBackendValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit modelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPropertiesProxyModel *DynamicPropertyRow::model() const
|
||||||
|
{
|
||||||
|
return m_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyEditorValue *DynamicPropertyRow::backendValue() const
|
||||||
|
{
|
||||||
|
return m_backendValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::remove()
|
||||||
|
{
|
||||||
|
m_model->dynamicPropertiesModel()->deleteDynamicPropertyByRow(m_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyEditorValue *DynamicPropertyRow::createProxyBackendValue()
|
||||||
|
{
|
||||||
|
|
||||||
|
PropertyEditorValue *newValue = new PropertyEditorValue(this);
|
||||||
|
m_proxyBackendValues.append(newValue);
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::clearProxyBackendValues()
|
||||||
|
{
|
||||||
|
qDeleteAll(m_proxyBackendValues);
|
||||||
|
m_proxyBackendValues.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::setupBackendValue()
|
||||||
|
{
|
||||||
|
if (!m_model)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QmlDesigner::AbstractProperty property = m_model->dynamicPropertiesModel()->abstractPropertyForRow(m_row);
|
||||||
|
if (!property.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_backendValue->name() != property.name())
|
||||||
|
m_backendValue->setName(property.name());
|
||||||
|
|
||||||
|
ModelNode node = property.parentModelNode();
|
||||||
|
if (node != m_backendValue->modelNode())
|
||||||
|
m_backendValue->setModelNode(node);
|
||||||
|
|
||||||
|
QVariant modelValue = property.parentQmlObjectNode().modelValue(property.name());
|
||||||
|
if (modelValue != m_backendValue->value()) {
|
||||||
|
m_backendValue->setValue({});
|
||||||
|
m_backendValue->setValue(modelValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property.isBindingProperty()) {
|
||||||
|
QString expression = property.toBindingProperty().expression();
|
||||||
|
if (m_backendValue->expression() != expression)
|
||||||
|
m_backendValue->setExpression(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit m_backendValue->isBoundChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::commitValue(const QVariant &value)
|
||||||
|
{
|
||||||
|
if (m_lock)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_row < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto propertiesModel = m_model->dynamicPropertiesModel();
|
||||||
|
VariantProperty variantProperty = propertiesModel->variantPropertyForRow(m_row);
|
||||||
|
|
||||||
|
if (!Internal::DynamicPropertiesModel::isValueType(variantProperty.dynamicTypeName()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_lock = true;
|
||||||
|
auto unlock = qScopeGuard([this] { m_lock = false; });
|
||||||
|
|
||||||
|
auto view = propertiesModel->view();
|
||||||
|
RewriterTransaction transaction = view->beginRewriterTransaction(
|
||||||
|
QByteArrayLiteral("DynamicPropertiesModel::commitValue"));
|
||||||
|
try {
|
||||||
|
if (view->currentState().isBaseState()) {
|
||||||
|
if (variantProperty.value() != value)
|
||||||
|
variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
|
||||||
|
} else {
|
||||||
|
QmlObjectNode objectNode = variantProperty.parentQmlObjectNode();
|
||||||
|
QTC_CHECK(objectNode.isValid());
|
||||||
|
PropertyName name = variantProperty.name();
|
||||||
|
if (objectNode.isValid() && objectNode.modelValue(name) != value)
|
||||||
|
objectNode.setVariantProperty(name, value);
|
||||||
|
}
|
||||||
|
transaction.commit(); //committing in the try block
|
||||||
|
} catch (Exception &e) {
|
||||||
|
e.showException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::commitExpression(const QString &expression)
|
||||||
|
{
|
||||||
|
if (m_lock)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_row < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_lock = true;
|
||||||
|
auto unlock = qScopeGuard([this] { m_lock = false; });
|
||||||
|
|
||||||
|
auto propertiesModel = m_model->dynamicPropertiesModel();
|
||||||
|
BindingProperty bindingProperty = propertiesModel->bindingPropertyForRow(m_row);
|
||||||
|
|
||||||
|
auto view = propertiesModel->view();
|
||||||
|
RewriterTransaction transaction = view->beginRewriterTransaction(
|
||||||
|
QByteArrayLiteral("DynamicPropertiesModel::commitExpression"));
|
||||||
|
try {
|
||||||
|
QString theExpression = expression;
|
||||||
|
if (theExpression.isEmpty())
|
||||||
|
theExpression = "null";
|
||||||
|
|
||||||
|
if (bindingProperty.expression() != theExpression) {
|
||||||
|
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(),
|
||||||
|
theExpression);
|
||||||
|
}
|
||||||
|
transaction.commit(); //committing in the try block
|
||||||
|
} catch (Exception &e) {
|
||||||
|
e.showException();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicPropertyRow::handleDataChanged(const QModelIndex &topLeft, const QModelIndex &, const QList<int> &)
|
||||||
|
{
|
||||||
|
if (topLeft.row() == m_row)
|
||||||
|
setupBackendValue();
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "propertyeditorvalue.h"
|
||||||
|
|
||||||
|
#include <abstractview.h>
|
||||||
|
#include <qmlitemnode.h>
|
||||||
|
|
||||||
|
#include <enumeration.h>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QtQml>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
namespace Internal {
|
||||||
|
class DynamicPropertiesModel;
|
||||||
|
}
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
|
||||||
|
class DynamicPropertiesProxyModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DynamicPropertiesProxyModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
static void registerDeclarativeType();
|
||||||
|
|
||||||
|
QmlDesigner::Internal::DynamicPropertiesModel *dynamicPropertiesModel() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE QString newPropertyName() const;
|
||||||
|
Q_INVOKABLE void createProperty(const QString &name, const QString &type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void initModel(QmlDesigner::Internal::DynamicPropertiesModel *model);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QmlDesigner::Internal::DynamicPropertiesModel *m_model = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DynamicPropertyRow : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged FINAL)
|
||||||
|
Q_PROPERTY(PropertyEditorValue *backendValue READ backendValue NOTIFY rowChanged FINAL)
|
||||||
|
Q_PROPERTY(DynamicPropertiesProxyModel *model READ model WRITE setModel NOTIFY modelChanged FINAL)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DynamicPropertyRow(QObject *parent = nullptr);
|
||||||
|
~DynamicPropertyRow();
|
||||||
|
|
||||||
|
static void registerDeclarativeType();
|
||||||
|
|
||||||
|
void setRow(int r);
|
||||||
|
int row() const;
|
||||||
|
void setModel(DynamicPropertiesProxyModel *model);
|
||||||
|
DynamicPropertiesProxyModel *model() const;
|
||||||
|
PropertyEditorValue *backendValue() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE void remove();
|
||||||
|
Q_INVOKABLE PropertyEditorValue *createProxyBackendValue();
|
||||||
|
Q_INVOKABLE void clearProxyBackendValues();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void rowChanged();
|
||||||
|
void modelChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupBackendValue();
|
||||||
|
void commitValue(const QVariant &value);
|
||||||
|
void commitExpression(const QString &expression);
|
||||||
|
void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &, const QList<int> &);
|
||||||
|
|
||||||
|
int m_row = -1;
|
||||||
|
PropertyEditorValue *m_backendValue = nullptr;
|
||||||
|
DynamicPropertiesProxyModel *m_model = nullptr;
|
||||||
|
QList<PropertyEditorValue *> m_proxyBackendValues;
|
||||||
|
bool m_lock = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
QML_DECLARE_TYPE(DynamicPropertyRow)
|
||||||
@@ -567,6 +567,13 @@ inline bool dotPropertyHeuristic(const QmlObjectNode &node, const NodeMetaInfo &
|
|||||||
if (propertyType.isFont() || itemInfo.hasProperty(itemProperty)
|
if (propertyType.isFont() || itemInfo.hasProperty(itemProperty)
|
||||||
|| propertyType.isBasedOn(textInfo, rectangleInfo, imageInfo))
|
|| propertyType.isBasedOn(textInfo, rectangleInfo, imageInfo))
|
||||||
return false;
|
return false;
|
||||||
|
// TODO In 8.0 this is now the following, which conflicts with master:
|
||||||
|
// if (typeName == "font" || typeName == "Texture" || typeName == "vector4d"
|
||||||
|
// || itemInfo.hasProperty(itemProperty)
|
||||||
|
// || textInfo.isSubclassOf(typeName)
|
||||||
|
// || rectangleInfo.isSubclassOf(typeName)
|
||||||
|
// || imageInfo.isSubclassOf(typeName))
|
||||||
|
// return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -582,10 +589,13 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
|
|||||||
|
|
||||||
QStringList allTypes; // all template types
|
QStringList allTypes; // all template types
|
||||||
QStringList separateSectionTypes; // separate section types only
|
QStringList separateSectionTypes; // separate section types only
|
||||||
|
QStringList needsTypeArgTypes; // types that need type as third parameter
|
||||||
|
|
||||||
for (const QmlJS::SimpleReaderNode::Ptr &node : nodes) {
|
for (const QmlJS::SimpleReaderNode::Ptr &node : nodes) {
|
||||||
if (node->propertyNames().contains("separateSection"))
|
if (node->propertyNames().contains("separateSection"))
|
||||||
separateSectionTypes.append(variantToStringList(node->property("typeNames").value));
|
separateSectionTypes.append(variantToStringList(node->property("typeNames").value));
|
||||||
|
if (node->propertyNames().contains("needsTypeArg"))
|
||||||
|
needsTypeArgTypes.append(variantToStringList(node->property("typeNames").value));
|
||||||
|
|
||||||
allTypes.append(variantToStringList(node->property("typeNames").value));
|
allTypes.append(variantToStringList(node->property("typeNames").value));
|
||||||
}
|
}
|
||||||
@@ -643,8 +653,8 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
|
|||||||
|
|
||||||
Utils::sort(basicProperties, propertyMetaInfoCompare);
|
Utils::sort(basicProperties, propertyMetaInfoCompare);
|
||||||
|
|
||||||
auto findAndFillTemplate = [&nodes, &node](const PropertyName &label,
|
auto findAndFillTemplate = [&nodes, &node, &needsTypeArgTypes](const PropertyName &label,
|
||||||
const PropertyMetaInfo &property) {
|
const PropertyMetaInfo &property) {
|
||||||
const auto &propertyName = property.name();
|
const auto &propertyName = property.name();
|
||||||
PropertyName underscoreProperty = propertyName;
|
PropertyName underscoreProperty = propertyName;
|
||||||
underscoreProperty.replace('.', '_');
|
underscoreProperty.replace('.', '_');
|
||||||
@@ -663,7 +673,14 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
|
|||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
QString source = QString::fromUtf8(file.readAll());
|
QString source = QString::fromUtf8(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
filledTemplate = source.arg(QString::fromUtf8(label)).arg(QString::fromUtf8(underscoreProperty));
|
if (needsTypeArgTypes.contains(QString::fromUtf8(typeName))) {
|
||||||
|
filledTemplate = source.arg(QString::fromUtf8(label),
|
||||||
|
QString::fromUtf8(underscoreProperty),
|
||||||
|
QString::fromUtf8(typeName));
|
||||||
|
} else {
|
||||||
|
filledTemplate = source.arg(QString::fromUtf8(label),
|
||||||
|
QString::fromUtf8(underscoreProperty));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning().nospace() << "template definition source file not found:" << fileName;
|
qWarning().nospace() << "template definition source file not found:" << fileName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "bindingeditor/actioneditor.h"
|
#include "bindingeditor/actioneditor.h"
|
||||||
#include "bindingeditor/bindingeditor.h"
|
#include "bindingeditor/bindingeditor.h"
|
||||||
#include "colorpalettebackend.h"
|
#include "colorpalettebackend.h"
|
||||||
|
#include "selectiondynamicpropertiesproxymodel.h"
|
||||||
#include "fileresourcesmodel.h"
|
#include "fileresourcesmodel.h"
|
||||||
#include "gradientmodel.h"
|
#include "gradientmodel.h"
|
||||||
#include "gradientpresetcustomlistmodel.h"
|
#include "gradientpresetcustomlistmodel.h"
|
||||||
@@ -53,6 +54,8 @@ void Quick2PropertyEditorView::registerQmlTypes()
|
|||||||
Tooltip::registerDeclarativeType();
|
Tooltip::registerDeclarativeType();
|
||||||
EasingCurveEditor::registerDeclarativeType();
|
EasingCurveEditor::registerDeclarativeType();
|
||||||
RichTextEditorProxy::registerDeclarativeType();
|
RichTextEditorProxy::registerDeclarativeType();
|
||||||
|
SelectionDynamicPropertiesProxyModel::registerDeclarativeType();
|
||||||
|
DynamicPropertyRow::registerDeclarativeType();
|
||||||
|
|
||||||
const QString resourcePath = PropertyEditorQmlBackend::propertyEditorResourcesPath();
|
const QString resourcePath = PropertyEditorQmlBackend::propertyEditorResourcesPath();
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="4" column="3">
|
<item row="4" column="3">
|
||||||
<widget class="QLabel" name="label_16">
|
<widget class="QLabel" name="label_16">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Number of times the animation runs before it stops.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Loops:</string>
|
<string>Loops:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -49,6 +52,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="label_15">
|
<widget class="QLabel" name="label_15">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sets the animation to loop indefinitely.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Continuous</string>
|
<string>Continuous</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -113,6 +119,9 @@
|
|||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Name for the animation.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Animation ID:</string>
|
<string>Animation ID:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -158,6 +167,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QLabel" name="label_23">
|
<widget class="QLabel" name="label_23">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>State to activate when the animation finishes.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Finished:</string>
|
<string>Finished:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -165,6 +177,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="4" column="7">
|
<item row="4" column="7">
|
||||||
<widget class="QLabel" name="label_17">
|
<widget class="QLabel" name="label_17">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Runs the animation backwards to the beginning when it reaches the end.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ping pong</string>
|
<string>Ping pong</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -218,6 +233,9 @@
|
|||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Runs the animation automatically when the base state is active.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Running in base state</string>
|
<string>Running in base state</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -253,6 +271,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLabel" name="label_12">
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>First frame of the animation.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Start frame:</string>
|
<string>Start frame:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -286,6 +307,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="7">
|
<item row="3" column="7">
|
||||||
<widget class="QLabel" name="label_14">
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Length of the animation in milliseconds. If you set a shorter duration than the number of frames, frames are left out from the end of the animation.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Duration:</string>
|
<string>Duration:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -293,6 +317,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="3">
|
<item row="3" column="3">
|
||||||
<widget class="QLabel" name="label_13">
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Last frame of the animation.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>End frame:</string>
|
<string>End frame:</string>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
@@ -42,6 +42,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="2" column="4">
|
<item row="2" column="4">
|
||||||
<widget class="QLabel" name="label_7">
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Last frame of the timeline.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>End frame:</string>
|
<string>End frame:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -52,6 +55,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>First frame of the timeline. Negative numbers are allowed.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Start frame:</string>
|
<string>Start frame:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -87,6 +93,9 @@
|
|||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>To create an expression binding animation, delete all animations from this timeline.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Expression binding</string>
|
<string>Expression binding</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -94,6 +103,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Name for the timeline.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Timeline ID:</string>
|
<string>Timeline ID:</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -152,6 +164,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="label_8">
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sets the expression to bind the current keyframe to.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Expression binding:</string>
|
<string>Expression binding:</string>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public:
|
|||||||
void emitUpdateActiveScene3D(const QVariantMap &sceneState);
|
void emitUpdateActiveScene3D(const QVariantMap &sceneState);
|
||||||
void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
||||||
void emitImport3DSupportChanged(const QVariantMap &supportMap);
|
void emitImport3DSupportChanged(const QVariantMap &supportMap);
|
||||||
void emitModelAtPosResult(const ModelNode &modelNode);
|
void emitNodeAtPosResult(const ModelNode &modelNode);
|
||||||
|
|
||||||
void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
|
void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ public:
|
|||||||
virtual void renderImage3DChanged(const QImage &image);
|
virtual void renderImage3DChanged(const QImage &image);
|
||||||
virtual void updateActiveScene3D(const QVariantMap &sceneState);
|
virtual void updateActiveScene3D(const QVariantMap &sceneState);
|
||||||
virtual void updateImport3DSupport(const QVariantMap &supportMap);
|
virtual void updateImport3DSupport(const QVariantMap &supportMap);
|
||||||
virtual void modelAtPosReady(const ModelNode &modelNode);
|
virtual void nodeAtPosReady(const ModelNode &modelNode);
|
||||||
virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
||||||
|
|
||||||
virtual void dragStarted(QMimeData *mimeData);
|
virtual void dragStarted(QMimeData *mimeData);
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ public:
|
|||||||
bool hasId(const QString &id) const;
|
bool hasId(const QString &id) const;
|
||||||
bool hasImport(const QString &importUrl) const;
|
bool hasImport(const QString &importUrl) const;
|
||||||
|
|
||||||
QString generateNewId(const QString &prefixName) const;
|
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix = "element") const;
|
||||||
QString generateNewId(const QString &prefixName, const QString &fallbackPrefix) const;
|
QString generateIdFromName(const QString &name, const QString &fallbackId = "element") const;
|
||||||
|
|
||||||
void startDrag(QMimeData *mimeData, const QPixmap &icon);
|
void startDrag(QMimeData *mimeData, const QPixmap &icon);
|
||||||
void endDrag();
|
void endDrag();
|
||||||
|
|||||||
@@ -97,6 +97,11 @@ public:
|
|||||||
static QVariant instanceValue(const ModelNode &modelNode, const PropertyName &name);
|
static QVariant instanceValue(const ModelNode &modelNode, const PropertyName &name);
|
||||||
|
|
||||||
static QString generateTranslatableText(const QString& text);
|
static QString generateTranslatableText(const QString& text);
|
||||||
|
|
||||||
|
static QString stripedTranslatableTextFunction(const QString &text);
|
||||||
|
|
||||||
|
static QString convertToCorrectTranslatableFunction(const QString &text);
|
||||||
|
|
||||||
QString simplifiedTypeName() const;
|
QString simplifiedTypeName() const;
|
||||||
|
|
||||||
QStringList allStateNames() const;
|
QStringList allStateNames() const;
|
||||||
|
|||||||
@@ -1736,9 +1736,9 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
|
|||||||
} else if (command.type() == PuppetToCreatorCommand::Import3DSupport) {
|
} else if (command.type() == PuppetToCreatorCommand::Import3DSupport) {
|
||||||
const QVariantMap supportMap = qvariant_cast<QVariantMap>(command.data());
|
const QVariantMap supportMap = qvariant_cast<QVariantMap>(command.data());
|
||||||
emitImport3DSupportChanged(supportMap);
|
emitImport3DSupportChanged(supportMap);
|
||||||
} else if (command.type() == PuppetToCreatorCommand::ModelAtPos) {
|
} else if (command.type() == PuppetToCreatorCommand::NodeAtPos) {
|
||||||
ModelNode modelNode = modelNodeForInternalId(command.data().toUInt());
|
ModelNode modelNode = modelNodeForInternalId(command.data().toUInt());
|
||||||
emitModelAtPosResult(modelNode);
|
emitNodeAtPosResult(modelNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1955,6 +1955,9 @@ void NodeInstanceView::endNanotrace()
|
|||||||
|
|
||||||
QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &modelNode, const ModelNode &renderNode)
|
QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &modelNode, const ModelNode &renderNode)
|
||||||
{
|
{
|
||||||
|
if (!modelNode.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
ModelNodePreviewImageData imageData;
|
ModelNodePreviewImageData imageData;
|
||||||
|
|
||||||
// We need puppet to generate the image, which needs to be asynchronous.
|
// We need puppet to generate the image, which needs to be asynchronous.
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// a Quick3DModel that is picked at the requested position in the 3D Editor
|
// a Quick3DModel that is picked at the requested position in the 3D Editor
|
||||||
void AbstractView::modelAtPosReady(const ModelNode & /*modelNode*/) {}
|
void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/) {}
|
||||||
|
|
||||||
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/)
|
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/)
|
||||||
{
|
{
|
||||||
@@ -781,10 +781,10 @@ void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap)
|
|||||||
model()->d->notifyImport3DSupportChanged(supportMap);
|
model()->d->notifyImport3DSupportChanged(supportMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractView::emitModelAtPosResult(const ModelNode &modelNode)
|
void AbstractView::emitNodeAtPosResult(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
if (model())
|
if (model())
|
||||||
model()->d->notifyModelAtPosResult(modelNode);
|
model()->d->notifyNodeAtPosResult(modelNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractView::emitRewriterEndTransaction()
|
void AbstractView::emitRewriterEndTransaction()
|
||||||
|
|||||||
@@ -299,9 +299,10 @@ void BindingProperty::setDynamicTypeNameAndExpression(const TypeName &typeName,
|
|||||||
Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name());
|
Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name());
|
||||||
if (internalProperty->isBindingProperty()
|
if (internalProperty->isBindingProperty()
|
||||||
&& internalProperty->toBindingProperty()->expression() == expression
|
&& internalProperty->toBindingProperty()->expression() == expression
|
||||||
&& internalProperty->toBindingProperty()->dynamicTypeName() == typeName)
|
&& internalProperty->toBindingProperty()->dynamicTypeName() == typeName) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
|
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
|
||||||
|
|||||||
@@ -579,9 +579,9 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap)
|
|||||||
notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); });
|
notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelPrivate::notifyModelAtPosResult(const ModelNode &modelNode)
|
void ModelPrivate::notifyNodeAtPosResult(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
notifyInstanceChanges([&](AbstractView *view) { view->modelAtPosReady(modelNode); });
|
notifyInstanceChanges([&](AbstractView *view) { view->nodeAtPosReady(modelNode); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelPrivate::notifyDragStarted(QMimeData *mimeData)
|
void ModelPrivate::notifyDragStarted(QMimeData *mimeData)
|
||||||
@@ -1539,6 +1539,41 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP
|
|||||||
return newId;
|
return newId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a unique camelCase id from a name
|
||||||
|
// note: this methods does the same as generateNewId(). The 2 methods should be merged into one
|
||||||
|
QString Model::generateIdFromName(const QString &name, const QString &fallbackId) const
|
||||||
|
{
|
||||||
|
QString newId;
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
newId = fallbackId;
|
||||||
|
} else {
|
||||||
|
// convert to camel case
|
||||||
|
QStringList nameWords = name.split(" ");
|
||||||
|
nameWords[0] = nameWords[0].at(0).toLower() + nameWords[0].mid(1);
|
||||||
|
for (int i = 1; i < nameWords.size(); ++i)
|
||||||
|
nameWords[i] = nameWords[i].at(0).toUpper() + nameWords[i].mid(1);
|
||||||
|
newId = nameWords.join("");
|
||||||
|
|
||||||
|
// if id starts with a number prepend an underscore
|
||||||
|
if (newId.at(0).isDigit())
|
||||||
|
newId.prepend('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
|
||||||
|
while (hasId(newId)) { // id exists
|
||||||
|
QRegularExpressionMatch match = rgx.match(newId);
|
||||||
|
if (match.hasMatch()) { // ends with a number, increment it
|
||||||
|
QString numStr = match.captured();
|
||||||
|
int num = numStr.toInt() + 1;
|
||||||
|
newId = newId.mid(0, match.capturedStart()) + QString::number(num);
|
||||||
|
} else {
|
||||||
|
newId.append('1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newId;
|
||||||
|
}
|
||||||
|
|
||||||
void Model::startDrag(QMimeData *mimeData, const QPixmap &icon)
|
void Model::startDrag(QMimeData *mimeData, const QPixmap &icon)
|
||||||
{
|
{
|
||||||
d->notifyDragStarted(mimeData);
|
d->notifyDragStarted(mimeData);
|
||||||
@@ -1562,11 +1597,6 @@ NotNullPointer<const ProjectStorage<Sqlite::Database>> Model::projectStorage() c
|
|||||||
return d->projectStorage;
|
return d->projectStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Model::generateNewId(const QString &prefixName) const
|
|
||||||
{
|
|
||||||
return generateNewId(prefixName, QStringLiteral("element"));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowHigherVersion) const
|
bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowHigherVersion) const
|
||||||
{
|
{
|
||||||
if (imports().contains(import))
|
if (imports().contains(import))
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ public:
|
|||||||
void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
|
void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
|
||||||
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
||||||
void notifyImport3DSupportChanged(const QVariantMap &supportMap);
|
void notifyImport3DSupportChanged(const QVariantMap &supportMap);
|
||||||
void notifyModelAtPosResult(const ModelNode &modelNode);
|
void notifyNodeAtPosResult(const ModelNode &modelNode);
|
||||||
|
|
||||||
void notifyDragStarted(QMimeData *mimeData);
|
void notifyDragStarted(QMimeData *mimeData);
|
||||||
void notifyDragEnded();
|
void notifyDragEnded();
|
||||||
|
|||||||
@@ -637,7 +637,7 @@ QString QmlObjectNode::generateTranslatableText([[maybe_unused]] const QString &
|
|||||||
DesignerSettingsKey::TYPE_OF_QSTR_FUNCTION).toInt()) {
|
DesignerSettingsKey::TYPE_OF_QSTR_FUNCTION).toInt()) {
|
||||||
case 0: return QString(QStringLiteral("qsTr(\"%1\")")).arg(text);
|
case 0: return QString(QStringLiteral("qsTr(\"%1\")")).arg(text);
|
||||||
case 1: return QString(QStringLiteral("qsTrId(\"%1\")")).arg(text);
|
case 1: return QString(QStringLiteral("qsTrId(\"%1\")")).arg(text);
|
||||||
case 2: return QString(QStringLiteral("qsTranslate(\"\"\"%1\")")).arg(text);
|
case 2: return QString(QStringLiteral("qsTranslate(\"%1\", \"context\")")).arg(text);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -648,6 +648,21 @@ QString QmlObjectNode::generateTranslatableText([[maybe_unused]] const QString &
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QmlObjectNode::stripedTranslatableTextFunction(const QString &text)
|
||||||
|
{
|
||||||
|
const QRegularExpression regularExpressionPattern(
|
||||||
|
QLatin1String("^qsTr(|Id|anslate)\\(\"(.*)\"\\)$"));
|
||||||
|
const QRegularExpressionMatch match = regularExpressionPattern.match(text);
|
||||||
|
if (match.hasMatch())
|
||||||
|
return match.captured(2);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QmlObjectNode::convertToCorrectTranslatableFunction(const QString &text)
|
||||||
|
{
|
||||||
|
return generateTranslatableText(stripedTranslatableTextFunction(text));
|
||||||
|
}
|
||||||
|
|
||||||
TypeName QmlObjectNode::instanceType(const PropertyName &name) const
|
TypeName QmlObjectNode::instanceType(const PropertyName &name) const
|
||||||
{
|
{
|
||||||
return nodeInstance().instanceType(name);
|
return nodeInstance().instanceType(name);
|
||||||
|
|||||||
@@ -274,7 +274,8 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
|
|||||||
|
|
||||||
for (const auto &property : itemLibraryEntry.properties()) {
|
for (const auto &property : itemLibraryEntry.properties()) {
|
||||||
if (property.type() == "binding") {
|
if (property.type() == "binding") {
|
||||||
propertyBindingList.append(PropertyBindingEntry(property.name(), property.value().toString()));
|
const QString value = QmlObjectNode::convertToCorrectTranslatableFunction(property.value().toString());
|
||||||
|
propertyBindingList.append(PropertyBindingEntry(property.name(), value));
|
||||||
} else if (property.type() == "enum") {
|
} else if (property.type() == "enum") {
|
||||||
propertyEnumList.append(PropertyBindingEntry(property.name(), property.value().toString()));
|
propertyEnumList.append(PropertyBindingEntry(property.name(), property.value().toString()));
|
||||||
} else if (property.value().toString() == QString::fromLatin1(imagePlaceHolder)) {
|
} else if (property.value().toString() == QString::fromLatin1(imagePlaceHolder)) {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ void DesignerSettings::fromSettings(QSettings *settings)
|
|||||||
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue);
|
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue);
|
||||||
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, "#aaaaaa");
|
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, "#aaaaaa");
|
||||||
restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false);
|
restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false);
|
||||||
|
restoreValue(settings, DesignerSettingsKey::SHOW_DEBUG_SETTINGS, false);
|
||||||
|
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const char EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundC
|
|||||||
|
|
||||||
|
|
||||||
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
|
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
|
||||||
|
const char COMPONENT_BUNDLES_FOLDER[] = "/ComponentBundles";
|
||||||
const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";
|
const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";
|
||||||
const char QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX[] = "_libicon";
|
const char QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX[] = "_libicon";
|
||||||
const char QUICK_3D_ASSET_ICON_DIR[] = "_icons";
|
const char QUICK_3D_ASSET_ICON_DIR[] = "_icons";
|
||||||
|
|||||||
@@ -733,8 +733,12 @@ Project {
|
|||||||
"materialbrowser/materialbrowserview.h",
|
"materialbrowser/materialbrowserview.h",
|
||||||
"materialbrowser/materialbrowserwidget.cpp",
|
"materialbrowser/materialbrowserwidget.cpp",
|
||||||
"materialbrowser/materialbrowserwidget.h",
|
"materialbrowser/materialbrowserwidget.h",
|
||||||
|
"materialbrowser/bundleimporter.cpp",
|
||||||
|
"materialbrowser/bundleimporter.h",
|
||||||
"materialeditor/materialeditorcontextobject.cpp",
|
"materialeditor/materialeditorcontextobject.cpp",
|
||||||
"materialeditor/materialeditorcontextobject.h",
|
"materialeditor/materialeditorcontextobject.h",
|
||||||
|
"materialeditor/materialeditordynamicpropertiesproxymodel.cpp",
|
||||||
|
"materialeditor/materialeditordynamicpropertiesproxymodel.h",
|
||||||
"materialeditor/materialeditorqmlbackend.cpp",
|
"materialeditor/materialeditorqmlbackend.cpp",
|
||||||
"materialeditor/materialeditorqmlbackend.h",
|
"materialeditor/materialeditorqmlbackend.h",
|
||||||
"materialeditor/materialeditortransaction.cpp",
|
"materialeditor/materialeditortransaction.cpp",
|
||||||
@@ -769,6 +773,8 @@ Project {
|
|||||||
"propertyeditor/colorpalettebackend.h",
|
"propertyeditor/colorpalettebackend.h",
|
||||||
"propertyeditor/designerpropertymap.cpp",
|
"propertyeditor/designerpropertymap.cpp",
|
||||||
"propertyeditor/designerpropertymap.h",
|
"propertyeditor/designerpropertymap.h",
|
||||||
|
"propertyeditor/dynamicpropertiesproxymodel.cpp",
|
||||||
|
"propertyeditor/dynamicpropertiesproxymodel.h",
|
||||||
"propertyeditor/fileresourcesmodel.cpp",
|
"propertyeditor/fileresourcesmodel.cpp",
|
||||||
"propertyeditor/fileresourcesmodel.h",
|
"propertyeditor/fileresourcesmodel.h",
|
||||||
"propertyeditor/itemfiltermodel.cpp",
|
"propertyeditor/itemfiltermodel.cpp",
|
||||||
@@ -887,6 +893,8 @@ Project {
|
|||||||
"connectioneditor/connectionviewwidget.ui",
|
"connectioneditor/connectionviewwidget.ui",
|
||||||
"connectioneditor/dynamicpropertiesmodel.cpp",
|
"connectioneditor/dynamicpropertiesmodel.cpp",
|
||||||
"connectioneditor/dynamicpropertiesmodel.h",
|
"connectioneditor/dynamicpropertiesmodel.h",
|
||||||
|
"connectioneditor/selectiondynamicpropertiesproxymodel.cpp",
|
||||||
|
"connectioneditor/selectiondynamicpropertiesproxymodel.h",
|
||||||
"connectioneditor/stylesheet.css",
|
"connectioneditor/stylesheet.css",
|
||||||
"curveeditor/curveeditorview.cpp",
|
"curveeditor/curveeditorview.cpp",
|
||||||
"curveeditor/curveeditorview.h",
|
"curveeditor/curveeditorview.h",
|
||||||
|
|||||||
@@ -666,6 +666,8 @@ void ExampleSetModel::selectExampleSet(int index)
|
|||||||
if (getType(m_selectedExampleSetIndex) == ExampleSetModel::QtExampleSet) {
|
if (getType(m_selectedExampleSetIndex) == ExampleSetModel::QtExampleSet) {
|
||||||
QtVersion *selectedQtVersion = QtVersionManager::version(getQtId(m_selectedExampleSetIndex));
|
QtVersion *selectedQtVersion = QtVersionManager::version(getQtId(m_selectedExampleSetIndex));
|
||||||
m_selectedQtTypes = selectedQtVersion->targetDeviceTypes();
|
m_selectedQtTypes = selectedQtVersion->targetDeviceTypes();
|
||||||
|
} else {
|
||||||
|
m_selectedQtTypes.clear();
|
||||||
}
|
}
|
||||||
emit selectedExampleSetChanged(m_selectedExampleSetIndex);
|
emit selectedExampleSetChanged(m_selectedExampleSetIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ GenericDirectUploadService::GenericDirectUploadService(QObject *parent)
|
|||||||
{
|
{
|
||||||
connect(&d->uploader, &FileTransfer::done, this, [this](const ProcessResultData &result) {
|
connect(&d->uploader, &FileTransfer::done, this, [this](const ProcessResultData &result) {
|
||||||
QTC_ASSERT(d->state == Uploading, return);
|
QTC_ASSERT(d->state == Uploading, return);
|
||||||
if (result.m_error != QProcess::UnknownError) {
|
if (result.m_error != QProcess::UnknownError || result.m_exitCode != 0) {
|
||||||
emit errorMessage(result.m_errorString);
|
emit errorMessage(result.m_errorString);
|
||||||
setFinished();
|
setFinished();
|
||||||
handleDeploymentDone();
|
handleDeploymentDone();
|
||||||
|
|||||||
@@ -7851,7 +7851,7 @@ void TextEditorWidget::dropEvent(QDropEvent *e)
|
|||||||
MultiTextCursor cursor = multiTextCursor();
|
MultiTextCursor cursor = multiTextCursor();
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
const QTextCursor eventCursor = cursorForPosition(e->pos());
|
const QTextCursor eventCursor = cursorForPosition(e->pos());
|
||||||
if (e->dropAction() == Qt::MoveAction)
|
if (e->dropAction() == Qt::MoveAction && e->source() == viewport())
|
||||||
cursor.removeSelectedText();
|
cursor.removeSelectedText();
|
||||||
cursor.setCursors({eventCursor});
|
cursor.setCursors({eventCursor});
|
||||||
setMultiTextCursor(cursor);
|
setMultiTextCursor(cursor);
|
||||||
@@ -7864,6 +7864,7 @@ void TextEditorWidget::dropEvent(QDropEvent *e)
|
|||||||
insertFromMimeData(mime);
|
insertFromMimeData(mime);
|
||||||
delete mimeOverwrite;
|
delete mimeOverwrite;
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
|
e->acceptProposedAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMimeData *TextEditorWidget::duplicateMimeData(const QMimeData *source)
|
QMimeData *TextEditorWidget::duplicateMimeData(const QMimeData *source)
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ void VcsOutputWindow::append(const QString &text, MessageStyle style, bool silen
|
|||||||
|
|
||||||
void VcsOutputWindow::appendError(const QString &text)
|
void VcsOutputWindow::appendError(const QString &text)
|
||||||
{
|
{
|
||||||
append(text.endsWith('\n') ? text : text + '\n', Error, false);
|
append((text.endsWith('\n') || text.endsWith('\r')) ? text : text + '\n', Error, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VcsOutputWindow::appendWarning(const QString &text)
|
void VcsOutputWindow::appendWarning(const QString &text)
|
||||||
|
|||||||
BIN
src/share/3rdparty/fonts/SourceCodePro-Bold.ttf
vendored
BIN
src/share/3rdparty/fonts/SourceCodePro-Bold.ttf
vendored
Binary file not shown.
BIN
src/share/3rdparty/fonts/SourceCodePro-BoldIt.ttf
vendored
BIN
src/share/3rdparty/fonts/SourceCodePro-BoldIt.ttf
vendored
Binary file not shown.
BIN
src/share/3rdparty/fonts/SourceCodePro-It.ttf
vendored
BIN
src/share/3rdparty/fonts/SourceCodePro-It.ttf
vendored
Binary file not shown.
BIN
src/share/3rdparty/fonts/SourceCodePro-Regular.ttf
vendored
BIN
src/share/3rdparty/fonts/SourceCodePro-Regular.ttf
vendored
Binary file not shown.
Reference in New Issue
Block a user