forked from qt-creator/qt-creator
QmlDesigner: Store current value at material property copy
Now we store the current value of copied properties at copy time instead of just storing a reference to copied property. This ensures we paste the correct value. When copying all properties, properties set by base state, current state, and active timeline are copied. Fixes: QDS-7804 Change-Id: Id6315dde96b30304fde007a87da578faaab43233 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
@@ -29,7 +29,8 @@
|
|||||||
#include <designmodewidget.h>
|
#include <designmodewidget.h>
|
||||||
#include <qmldesignerplugin.h>
|
#include <qmldesignerplugin.h>
|
||||||
#include <qmlobjectnode.h>
|
#include <qmlobjectnode.h>
|
||||||
#include "variantproperty.h"
|
#include <variantproperty.h>
|
||||||
|
#include <qmltimelinekeyframegroup.h>
|
||||||
#include "utils/qtcassert.h"
|
#include "utils/qtcassert.h"
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -349,6 +350,9 @@ void MaterialBrowserModel::duplicateMaterial(int idx)
|
|||||||
void MaterialBrowserModel::copyMaterialProperties(int idx, const QString §ion)
|
void MaterialBrowserModel::copyMaterialProperties(int idx, const QString §ion)
|
||||||
{
|
{
|
||||||
m_copiedMaterial = m_materialList.at(idx);
|
m_copiedMaterial = m_materialList.at(idx);
|
||||||
|
|
||||||
|
QTC_ASSERT(m_copiedMaterial.isValid(), return);
|
||||||
|
|
||||||
QString matType = QString::fromLatin1(m_copiedMaterial.type());
|
QString matType = QString::fromLatin1(m_copiedMaterial.type());
|
||||||
|
|
||||||
if (matType.startsWith("QtQuick3D."))
|
if (matType.startsWith("QtQuick3D."))
|
||||||
@@ -356,27 +360,66 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString §io
|
|||||||
|
|
||||||
setCopiedMaterialType(matType);
|
setCopiedMaterialType(matType);
|
||||||
m_allPropsCopied = section == "All";
|
m_allPropsCopied = section == "All";
|
||||||
|
QmlObjectNode mat(m_copiedMaterial);
|
||||||
|
|
||||||
|
QSet<PropertyName> validProps;
|
||||||
|
PropertyNameList copiedProps;
|
||||||
|
|
||||||
|
// Base state properties are always valid
|
||||||
|
const auto baseProps = m_copiedMaterial.propertyNames();
|
||||||
|
for (const auto &baseProp : baseProps)
|
||||||
|
validProps.insert(baseProp);
|
||||||
|
|
||||||
|
if (!mat.isInBaseState()) {
|
||||||
|
QmlPropertyChanges changes = mat.propertyChangeForCurrentState();
|
||||||
|
if (changes.isValid()) {
|
||||||
|
const QList<AbstractProperty> changedProps = changes.targetProperties();
|
||||||
|
for (const auto &changedProp : changedProps)
|
||||||
|
validProps.insert(changedProp.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mat.timelineIsActive()) {
|
||||||
|
const QList<QmlTimelineKeyframeGroup> keyframeGroups
|
||||||
|
= mat.currentTimeline().keyframeGroupsForTarget(m_copiedMaterial);
|
||||||
|
for (const auto &kfg : keyframeGroups)
|
||||||
|
validProps.insert(kfg.propertyName());
|
||||||
|
}
|
||||||
|
|
||||||
if (m_allPropsCopied || m_propertyGroupsObj.empty()) {
|
if (m_allPropsCopied || m_propertyGroupsObj.empty()) {
|
||||||
m_copiedMaterialProps = m_copiedMaterial.properties();
|
copiedProps = validProps.values();
|
||||||
} else {
|
} else {
|
||||||
QJsonObject propsSpecObj = m_propertyGroupsObj.value(m_copiedMaterialType).toObject();
|
QJsonObject propsSpecObj = m_propertyGroupsObj.value(m_copiedMaterialType).toObject();
|
||||||
if (propsSpecObj.contains(section)) { // should always be true
|
if (propsSpecObj.contains(section)) { // should always be true
|
||||||
m_copiedMaterialProps.clear();
|
|
||||||
const QJsonArray propNames = propsSpecObj.value(section).toArray();
|
const QJsonArray propNames = propsSpecObj.value(section).toArray();
|
||||||
// auto == QJsonValueConstRef after 04dc959d49e5e3 / Qt 6.4, QJsonValueRef before
|
// auto == QJsonValueConstRef after 04dc959d49e5e3 / Qt 6.4, QJsonValueRef before
|
||||||
for (const auto &propName : propNames)
|
for (const auto &propName : propNames)
|
||||||
m_copiedMaterialProps.append(m_copiedMaterial.property(propName.toString().toLatin1()));
|
copiedProps.append(propName.toString().toLatin1());
|
||||||
|
|
||||||
if (section == "Base") { // add QtQuick3D.Material base props as well
|
if (section == "Base") { // add QtQuick3D.Material base props as well
|
||||||
QJsonObject propsMatObj = m_propertyGroupsObj.value("Material").toObject();
|
QJsonObject propsMatObj = m_propertyGroupsObj.value("Material").toObject();
|
||||||
const QJsonArray propNames = propsMatObj.value("Base").toArray();
|
const QJsonArray propNames = propsMatObj.value("Base").toArray();
|
||||||
// auto == QJsonValueConstRef after 04dc959d49e5e3 / Qt 6.4, QJsonValueRef before
|
// auto == QJsonValueConstRef after 04dc959d49e5e3 / Qt 6.4, QJsonValueRef before
|
||||||
for (const auto &propName : propNames)
|
for (const auto &propName : propNames)
|
||||||
m_copiedMaterialProps.append(m_copiedMaterial.property(propName.toString().toLatin1()));
|
copiedProps.append(propName.toString().toLatin1());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_copiedMaterialProps.clear();
|
||||||
|
for (const auto &propName : copiedProps) {
|
||||||
|
PropertyCopyData data;
|
||||||
|
data.name = propName;
|
||||||
|
data.isValid = m_allPropsCopied || validProps.contains(propName);
|
||||||
|
data.isBinding = mat.hasBindingProperty(propName);
|
||||||
|
if (data.isValid) {
|
||||||
|
if (data.isBinding)
|
||||||
|
data.value = mat.expression(propName);
|
||||||
|
else
|
||||||
|
data.value = mat.modelValue(propName);
|
||||||
|
}
|
||||||
|
m_copiedMaterialProps.append(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserModel::pasteMaterialProperties(int idx)
|
void MaterialBrowserModel::pasteMaterialProperties(int idx)
|
||||||
|
@@ -94,6 +94,14 @@ public:
|
|||||||
Q_INVOKABLE void openMaterialEditor();
|
Q_INVOKABLE void openMaterialEditor();
|
||||||
Q_INVOKABLE bool isCopiedMaterialValid() const;
|
Q_INVOKABLE bool isCopiedMaterialValid() const;
|
||||||
|
|
||||||
|
struct PropertyCopyData
|
||||||
|
{
|
||||||
|
PropertyName name;
|
||||||
|
QVariant value;
|
||||||
|
bool isBinding = false;
|
||||||
|
bool isValid = false;
|
||||||
|
};
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void isEmptyChanged();
|
void isEmptyChanged();
|
||||||
void hasQuick3DImportChanged();
|
void hasQuick3DImportChanged();
|
||||||
@@ -106,9 +114,10 @@ signals:
|
|||||||
void applyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false);
|
void applyToSelectedTriggered(const QmlDesigner::ModelNode &material, bool add = false);
|
||||||
void addNewMaterialTriggered();
|
void addNewMaterialTriggered();
|
||||||
void duplicateMaterialTriggered(const QmlDesigner::ModelNode &material);
|
void duplicateMaterialTriggered(const QmlDesigner::ModelNode &material);
|
||||||
void pasteMaterialPropertiesTriggered(const QmlDesigner::ModelNode &material,
|
void pasteMaterialPropertiesTriggered(
|
||||||
const QList<QmlDesigner::AbstractProperty> &props,
|
const QmlDesigner::ModelNode &material,
|
||||||
bool all);
|
const QList<QmlDesigner::MaterialBrowserModel::PropertyCopyData> &props,
|
||||||
|
bool all);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isMaterialVisible(int idx) const;
|
bool isMaterialVisible(int idx) const;
|
||||||
@@ -120,7 +129,7 @@ private:
|
|||||||
QStringList m_principledMaterialSections;
|
QStringList m_principledMaterialSections;
|
||||||
QStringList m_customMaterialSections;
|
QStringList m_customMaterialSections;
|
||||||
ModelNode m_copiedMaterial;
|
ModelNode m_copiedMaterial;
|
||||||
QList<AbstractProperty> m_copiedMaterialProps;
|
QList<PropertyCopyData> m_copiedMaterialProps;
|
||||||
QHash<qint32, int> m_materialIndexHash; // internalId -> index
|
QHash<qint32, int> m_materialIndexHash; // internalId -> index
|
||||||
QJsonObject m_propertyGroupsObj;
|
QJsonObject m_propertyGroupsObj;
|
||||||
|
|
||||||
|
@@ -96,29 +96,43 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect(matBrowserModel, &MaterialBrowserModel::pasteMaterialPropertiesTriggered, this,
|
connect(matBrowserModel, &MaterialBrowserModel::pasteMaterialPropertiesTriggered, this,
|
||||||
[&] (const ModelNode &material, const QList<AbstractProperty> &props, bool all) {
|
[&] (const ModelNode &material,
|
||||||
|
const QList<QmlDesigner::MaterialBrowserModel::PropertyCopyData> &propDatas,
|
||||||
|
bool all) {
|
||||||
QmlObjectNode mat(material);
|
QmlObjectNode mat(material);
|
||||||
executeInTransaction(__FUNCTION__, [&] {
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
if (all) { // all material properties copied
|
if (all) { // all material properties copied
|
||||||
// remove current properties
|
// remove current properties
|
||||||
const PropertyNameList propNames = material.propertyNames();
|
PropertyNameList propNames;
|
||||||
for (const PropertyName &propName : propNames) {
|
if (mat.isInBaseState()) {
|
||||||
|
propNames = material.propertyNames();
|
||||||
|
} else {
|
||||||
|
QmlPropertyChanges changes = mat.propertyChangeForCurrentState();
|
||||||
|
if (changes.isValid()) {
|
||||||
|
const QList<AbstractProperty> changedProps = changes.targetProperties();
|
||||||
|
for (const auto &changedProp : changedProps)
|
||||||
|
propNames.append(changedProp.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const PropertyName &propName : qAsConst(propNames)) {
|
||||||
if (propName != "objectName")
|
if (propName != "objectName")
|
||||||
mat.removeProperty(propName);
|
mat.removeProperty(propName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply pasted properties
|
// apply pasted properties
|
||||||
for (const AbstractProperty &prop : props) {
|
for (const QmlDesigner::MaterialBrowserModel::PropertyCopyData &propData : propDatas) {
|
||||||
if (prop.name() == "objectName" || !prop.isValid())
|
if (propData.name == "objectName")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (prop.isVariantProperty())
|
if (propData.isValid) {
|
||||||
mat.setVariantProperty(prop.name(), prop.toVariantProperty().value());
|
if (propData.isBinding)
|
||||||
else if (prop.isBindingProperty())
|
mat.setBindingProperty(propData.name, propData.value.toString());
|
||||||
mat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
|
else
|
||||||
else if (!all)
|
mat.setVariantProperty(propData.name, propData.value);
|
||||||
mat.removeProperty(prop.name());
|
} else {
|
||||||
|
mat.removeProperty(propData.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user