Fix copying dynamic properties on materials

Fixes: QDS-7803
Change-Id: I24c8cd269965552a62fbbbc521efbff00811fa43
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Miikka Heikkinen
2022-09-27 15:05:26 +03:00
parent b0fa747565
commit b8f4cd97d1
6 changed files with 88 additions and 29 deletions

View File

@@ -125,7 +125,10 @@ Item {
width: parent.width
onAboutToShow: {
root.matSectionsModel = ["All"];
if (root.currentMaterial.hasDynamicProperties)
root.matSectionsModel = ["All", "Custom"];
else
root.matSectionsModel = ["All"];
switch (root.currentMaterial.materialType) {
case "DefaultMaterial":

View File

@@ -73,6 +73,9 @@ QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const
return matType;
}
if (roleName == "hasDynamicProperties")
return !m_materialList.at(index.row()).dynamicProperties().isEmpty();
return {};
}
@@ -143,7 +146,8 @@ QHash<int, QByteArray> MaterialBrowserModel::roleNames() const
{Qt::UserRole + 1, "materialName"},
{Qt::UserRole + 2, "materialInternalId"},
{Qt::UserRole + 3, "materialVisible"},
{Qt::UserRole + 4, "materialType"}
{Qt::UserRole + 4, "materialType"},
{Qt::UserRole + 5, "hasDynamicProperties"}
};
return roles;
}
@@ -360,33 +364,47 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString &sectio
setCopiedMaterialType(matType);
m_allPropsCopied = section == "All";
bool dynamicPropsCopied = section == "Custom";
QmlObjectNode mat(m_copiedMaterial);
QSet<PropertyName> validProps;
QHash<PropertyName, TypeName> dynamicProps;
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 (dynamicPropsCopied || m_allPropsCopied) {
// Dynamic properties must always be set in base state
const QList<AbstractProperty> dynProps = m_copiedMaterial.dynamicProperties();
for (const auto &prop : dynProps) {
dynamicProps.insert(prop.name(), prop.dynamicTypeName());
validProps.insert(prop.name());
}
}
if (mat.timelineIsActive()) {
const QList<QmlTimelineKeyframeGroup> keyframeGroups
= mat.currentTimeline().keyframeGroupsForTarget(m_copiedMaterial);
for (const auto &kfg : keyframeGroups)
validProps.insert(kfg.propertyName());
}
if (!dynamicPropsCopied) {
// Base state properties are always valid
const auto baseProps = m_copiedMaterial.propertyNames();
for (const auto &baseProp : baseProps)
validProps.insert(baseProp);
if (m_allPropsCopied || m_propertyGroupsObj.empty()) {
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());
}
}
validProps.remove("objectName");
if (m_allPropsCopied || dynamicPropsCopied || m_propertyGroupsObj.empty()) {
copiedProps = validProps.values();
} else {
QJsonObject propsSpecObj = m_propertyGroupsObj.value(m_copiedMaterialType).toObject();
@@ -411,8 +429,10 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString &sectio
PropertyCopyData data;
data.name = propName;
data.isValid = m_allPropsCopied || validProps.contains(propName);
data.isBinding = mat.hasBindingProperty(propName);
if (data.isValid) {
if (dynamicProps.contains(propName))
data.dynamicTypeName = dynamicProps[propName];
data.isBinding = mat.hasBindingProperty(propName);
if (data.isBinding)
data.value = mat.expression(propName);
else

View File

@@ -97,6 +97,7 @@ public:
struct PropertyCopyData
{
PropertyName name;
TypeName dynamicTypeName;
QVariant value;
bool isBinding = false;
bool isValid = false;

View File

@@ -25,6 +25,7 @@
#include "materialbrowserview.h"
#include "bindingproperty.h"
#include "bundlematerial.h"
#include "materialbrowserwidget.h"
#include "materialbrowsermodel.h"
@@ -105,13 +106,19 @@ WidgetInfo MaterialBrowserView::widgetInfo()
// remove current properties
PropertyNameList propNames;
if (mat.isInBaseState()) {
propNames = material.propertyNames();
const QList<AbstractProperty> baseProps = material.properties();
for (const auto &baseProp : baseProps) {
if (!baseProp.isDynamic())
propNames.append(baseProp.name());
}
} 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 auto &changedProp : changedProps) {
if (!changedProp.isDynamic())
propNames.append(changedProp.name());
}
}
}
for (const PropertyName &propName : qAsConst(propNames)) {
@@ -122,14 +129,29 @@ WidgetInfo MaterialBrowserView::widgetInfo()
// apply pasted properties
for (const QmlDesigner::MaterialBrowserModel::PropertyCopyData &propData : propDatas) {
if (propData.name == "objectName")
continue;
if (propData.isValid) {
if (propData.isBinding)
const bool isDynamic = !propData.dynamicTypeName.isEmpty();
const bool isBaseState = currentState().isBaseState();
const bool hasProperty = mat.hasProperty(propData.name);
if (propData.isBinding) {
if (isDynamic && (!hasProperty || isBaseState)) {
mat.modelNode().bindingProperty(propData.name)
.setDynamicTypeNameAndExpression(
propData.dynamicTypeName, propData.value.toString());
continue;
}
mat.setBindingProperty(propData.name, propData.value.toString());
else
} else {
const bool isRecording = mat.timelineIsActive()
&& mat.currentTimeline().isRecording();
if (isDynamic && (!hasProperty || (isBaseState && !isRecording))) {
mat.modelNode().variantProperty(propData.name)
.setDynamicTypeNameAndValue(
propData.dynamicTypeName, propData.value);
continue;
}
mat.setVariantProperty(propData.name, propData.value);
}
} else {
mat.removeProperty(propData.name);
}

View File

@@ -145,6 +145,7 @@ public:
QList<NodeListProperty> nodeListProperties() const;
QList<BindingProperty> bindingProperties() const;
QList<SignalHandlerProperty> signalProperties() const;
QList<AbstractProperty> dynamicProperties() const;
PropertyNameList propertyNames() const;
bool hasProperties() const;

View File

@@ -691,6 +691,18 @@ QList<SignalHandlerProperty> ModelNode::signalProperties() const
return propertyList;
}
QList<AbstractProperty> ModelNode::dynamicProperties() const
{
QList<AbstractProperty> propertyList;
const QList<AbstractProperty> abstractProperties = properties();
for (const AbstractProperty &abstractProperty : abstractProperties) {
if (abstractProperty.isDynamic())
propertyList.append(abstractProperty);
}
return propertyList;
}
/*!
\brief removes a property from this node
\param name name of the property