forked from qt-creator/qt-creator
PropertyEditor: Copy material compatible properties in type changes
Fixes: QDS-14946 Change-Id: If8f1e15ffd19f99ffdb70ef7650ce5a7c4a07d3a Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -411,6 +411,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
aligndistribute.cpp aligndistribute.h
|
||||
assetimageprovider.cpp assetimageprovider.h
|
||||
colorpalettebackend.cpp colorpalettebackend.h
|
||||
compatibleproperties.cpp compatibleproperties.h
|
||||
designerpropertymap.cpp designerpropertymap.h
|
||||
fileresourcesmodel.cpp fileresourcesmodel.h
|
||||
itemfiltermodel.cpp itemfiltermodel.h
|
||||
|
@@ -0,0 +1,110 @@
|
||||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "compatibleproperties.h"
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <qmlobjectnode.h>
|
||||
#include <qmltimelinekeyframegroup.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Extracts and removes compatible properties from \param properties.
|
||||
* compatible properties will be stored.
|
||||
*/
|
||||
void CompatibleProperties::createCompatibilityMap(QList<PropertyName> &properties)
|
||||
{
|
||||
m_compatibilityMap.clear();
|
||||
if (m_oldInfo == m_newInfo || !m_oldInfo.isQtQuick3DMaterial() || !m_newInfo.isQtQuick3DMaterial())
|
||||
return;
|
||||
|
||||
enum class MaterialType { Unknown, Principled, Default, SpecularGlossy };
|
||||
auto getMaterialType = [](const NodeMetaInfo &info) {
|
||||
if (info.isQtQuick3DPrincipledMaterial())
|
||||
return MaterialType::Principled;
|
||||
else if (info.isQtQuick3DDefaultMaterial())
|
||||
return MaterialType::Default;
|
||||
else if (info.isQtQuick3DSpecularGlossyMaterial())
|
||||
return MaterialType::SpecularGlossy;
|
||||
return MaterialType::Unknown;
|
||||
};
|
||||
|
||||
static const QHash<MaterialType, PropertyName> baseColors = {
|
||||
{MaterialType::Principled, "baseColor"},
|
||||
{MaterialType::Default, "diffuseColor"},
|
||||
{MaterialType::SpecularGlossy, "albedoColor"},
|
||||
};
|
||||
|
||||
static const QHash<MaterialType, PropertyName> baseMaps = {
|
||||
{MaterialType::Principled, "baseColorMap"},
|
||||
{MaterialType::Default, "diffuseMap"},
|
||||
{MaterialType::SpecularGlossy, "albedoMap"},
|
||||
};
|
||||
|
||||
MaterialType sourceMaterialType = getMaterialType(m_oldInfo);
|
||||
MaterialType destMaterialType = getMaterialType(m_newInfo);
|
||||
|
||||
if (sourceMaterialType == MaterialType::Unknown || destMaterialType == MaterialType::Unknown)
|
||||
return;
|
||||
|
||||
if (properties.contains(baseColors.value(sourceMaterialType))) {
|
||||
m_compatibilityMap.insert(baseColors[sourceMaterialType], baseColors[destMaterialType]);
|
||||
properties.removeOne(baseColors[sourceMaterialType]);
|
||||
}
|
||||
|
||||
if (properties.contains(baseMaps[sourceMaterialType])) {
|
||||
m_compatibilityMap.insert(baseMaps[sourceMaterialType], baseMaps[destMaterialType]);
|
||||
properties.removeOne(baseMaps[sourceMaterialType]);
|
||||
}
|
||||
}
|
||||
|
||||
void CompatibleProperties::copyMappedProperties(const ModelNode &node)
|
||||
{
|
||||
if (m_compatibilityMap.isEmpty())
|
||||
return;
|
||||
// Copy mapped properties to new name. Note that this will only copy the base
|
||||
// property value and adjust the keyframe groups. Any other bindings related
|
||||
// to the property will be ignored.
|
||||
const QList<ModelNode> timeLines = QmlObjectNode(node).allTimelines();
|
||||
for (const auto &pair : m_compatibilityMap.asKeyValueRange()) {
|
||||
const PropertyName &key = pair.first;
|
||||
CopyData ©Data = pair.second;
|
||||
for (const ModelNode &timeLineNode : timeLines) {
|
||||
QmlTimeline timeLine(timeLineNode);
|
||||
if (timeLine.hasKeyframeGroup(node, key)) {
|
||||
QmlTimelineKeyframeGroup group = timeLine.keyframeGroup(node, key);
|
||||
group.setPropertyName(copyData.name);
|
||||
}
|
||||
}
|
||||
// Property value itself cannot be copied until type has been changed, so store it
|
||||
AbstractProperty prop = node.property(key);
|
||||
if (prop.isValid()) {
|
||||
if (prop.isBindingProperty()) {
|
||||
copyData.isBinding = true;
|
||||
copyData.value = prop.toBindingProperty().expression();
|
||||
} else {
|
||||
copyData.value = prop.toVariantProperty().value();
|
||||
}
|
||||
}
|
||||
node.removeProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
void CompatibleProperties::applyCompatibleProperties(const ModelNode &node)
|
||||
{
|
||||
for (const auto &pair : m_compatibilityMap.asKeyValueRange()) {
|
||||
const CopyData ©Data = pair.second;
|
||||
if (copyData.isBinding) {
|
||||
BindingProperty property = node.bindingProperty(copyData.name);
|
||||
property.setExpression(copyData.value.toString());
|
||||
} else {
|
||||
VariantProperty property = node.variantProperty(copyData.name);
|
||||
property.setValue(copyData.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <modelfwd.h>
|
||||
#include <nodemetainfo.h>
|
||||
|
||||
#include <QHash>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
// Currently this compatibility is only checked for the materials
|
||||
// If there are more compatible types in the future, we can make a proxy model for Compatibility
|
||||
class CompatibleProperties
|
||||
{
|
||||
public:
|
||||
CompatibleProperties(const NodeMetaInfo &oldInfo, NodeMetaInfo &newInfo)
|
||||
: m_oldInfo(oldInfo)
|
||||
, m_newInfo(newInfo)
|
||||
{}
|
||||
|
||||
void createCompatibilityMap(QList<PropertyName> &properties);
|
||||
void copyMappedProperties(const ModelNode &node);
|
||||
void applyCompatibleProperties(const ModelNode &node);
|
||||
|
||||
private:
|
||||
void *operator new(size_t) = delete;
|
||||
|
||||
struct CopyData
|
||||
{
|
||||
CopyData() = default;
|
||||
|
||||
CopyData(PropertyName n)
|
||||
: name(n)
|
||||
{}
|
||||
|
||||
PropertyName name;
|
||||
QVariant value;
|
||||
bool isBinding = false;
|
||||
};
|
||||
|
||||
NodeMetaInfo m_oldInfo;
|
||||
NodeMetaInfo m_newInfo;
|
||||
|
||||
QHash<PropertyName, CopyData> m_compatibilityMap;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -4,6 +4,7 @@
|
||||
#include "propertyeditorcontextobject.h"
|
||||
|
||||
#include "abstractview.h"
|
||||
#include "compatibleproperties.h"
|
||||
#include "easingcurvedialog.h"
|
||||
#include "nodemetainfo.h"
|
||||
#include "propertyeditorutils.h"
|
||||
@@ -189,7 +190,7 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
|
||||
* If we add more code here we have to forward the property editor view */
|
||||
RewriterView *rewriterView = m_model->rewriterView();
|
||||
|
||||
QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return);
|
||||
QTC_ASSERT(!m_editorNodes.isEmpty(), return);
|
||||
|
||||
auto changeNodeTypeName = [&](ModelNode &selectedNode) {
|
||||
// Check if the requested type is the same as already set
|
||||
@@ -244,6 +245,9 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
|
||||
incompatibleProperties.append(property.name().toByteArray());
|
||||
}
|
||||
|
||||
CompatibleProperties compatibleProps(selectedNode.metaInfo(), metaInfo);
|
||||
compatibleProps.createCompatibilityMap(incompatibleProperties);
|
||||
|
||||
Utils::sort(incompatibleProperties);
|
||||
|
||||
// Create a dialog showing incompatible properties and signals
|
||||
@@ -274,6 +278,7 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
|
||||
selectedNode.removeProperty(p);
|
||||
}
|
||||
|
||||
compatibleProps.copyMappedProperties(selectedNode);
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
if (selectedNode.isRootNode())
|
||||
rewriterView->changeRootNodeType(typeName.toUtf8(), -1, -1);
|
||||
@@ -289,6 +294,7 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
|
||||
metaInfo.majorVersion(),
|
||||
metaInfo.minorVersion());
|
||||
#endif
|
||||
compatibleProps.applyCompatibleProperties(selectedNode);
|
||||
};
|
||||
|
||||
try {
|
||||
|
Reference in New Issue
Block a user