forked from qt-creator/qt-creator
QmlDesigner: Implement copy/paste material properties
Fixes: QDS-7014 Change-Id: I2a8b779f97de353836a4d506b715720b490c349f Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -92,27 +92,48 @@ Item {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Apply to selected (replace)")
|
text: qsTr("Apply to selected (replace)")
|
||||||
enabled: currentMaterial && materialBrowserModel.hasModelSelection
|
enabled: root.currentMaterial && materialBrowserModel.hasModelSelection
|
||||||
onTriggered: materialBrowserModel.applyToSelected(currentMaterial.materialInternalId, false)
|
onTriggered: materialBrowserModel.applyToSelected(root.currentMaterial.materialInternalId, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Apply to selected (add)")
|
text: qsTr("Apply to selected (add)")
|
||||||
enabled: currentMaterial && materialBrowserModel.hasModelSelection
|
enabled: root.currentMaterial && materialBrowserModel.hasModelSelection
|
||||||
onTriggered: materialBrowserModel.applyToSelected(currentMaterial.materialInternalId, true)
|
onTriggered: materialBrowserModel.applyToSelected(root.currentMaterial.materialInternalId, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuSeparator {
|
||||||
|
height: StudioTheme.Values.border
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Copy properties")
|
||||||
|
enabled: root.currentMaterial
|
||||||
|
onTriggered: materialBrowserModel.copyMaterialProperties(root.currentMaterialIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Paste properties")
|
||||||
|
enabled: root.currentMaterial && root.currentMaterial.materialType.toString()
|
||||||
|
=== materialBrowserModel.copiedMaterialType.toString()
|
||||||
|
onTriggered: materialBrowserModel.pasteMaterialProperties(root.currentMaterialIdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.MenuSeparator {
|
||||||
|
height: StudioTheme.Values.border
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Duplicate")
|
text: qsTr("Duplicate")
|
||||||
enabled: currentMaterial
|
enabled: root.currentMaterial
|
||||||
onTriggered: materialBrowserModel.duplicateMaterial(currentMaterialIdx)
|
onTriggered: materialBrowserModel.duplicateMaterial(root.currentMaterialIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Rename")
|
text: qsTr("Rename")
|
||||||
enabled: currentMaterial
|
enabled: root.currentMaterial
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var item = gridRepeater.itemAt(currentMaterialIdx);
|
var item = gridRepeater.itemAt(root.currentMaterialIdx);
|
||||||
if (item)
|
if (item)
|
||||||
item.startRename();
|
item.startRename();
|
||||||
}
|
}
|
||||||
@@ -120,9 +141,9 @@ Item {
|
|||||||
|
|
||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
enabled: currentMaterial
|
enabled: root.currentMaterial
|
||||||
|
|
||||||
onTriggered: materialBrowserModel.deleteMaterial(currentMaterialIdx)
|
onTriggered: materialBrowserModel.deleteMaterial(root.currentMaterialIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuSeparator {}
|
StudioControls.MenuSeparator {}
|
||||||
|
@@ -24,9 +24,13 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "materialbrowsermodel.h"
|
#include "materialbrowsermodel.h"
|
||||||
#include "variantproperty.h"
|
|
||||||
|
#include <bindingproperty.h>
|
||||||
#include <designmodewidget.h>
|
#include <designmodewidget.h>
|
||||||
#include <qmldesignerplugin.h>
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <qmlobjectnode.h>
|
||||||
|
#include "variantproperty.h"
|
||||||
|
#include "utils/qtcassert.h"
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -46,24 +50,23 @@ int MaterialBrowserModel::rowCount(const QModelIndex &) const
|
|||||||
|
|
||||||
QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const
|
QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (!index.isValid() || index.row() >= m_materialList.count()) {
|
QTC_ASSERT(index.isValid() && index.row() < m_materialList.count(), return {});
|
||||||
qWarning() << Q_FUNC_INFO << "invalid index requested";
|
QTC_ASSERT(roleNames().contains(role), return {});
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (roleNames().value(role) == "materialName") {
|
QByteArray roleName = roleNames().value(role);
|
||||||
|
if (roleName == "materialName") {
|
||||||
QVariant objName = m_materialList.at(index.row()).variantProperty("objectName").value();
|
QVariant objName = m_materialList.at(index.row()).variantProperty("objectName").value();
|
||||||
return objName.isValid() ? objName : "";
|
return objName.isValid() ? objName : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roleNames().value(role) == "materialInternalId")
|
if (roleName == "materialInternalId")
|
||||||
return m_materialList.at(index.row()).internalId();
|
return m_materialList.at(index.row()).internalId();
|
||||||
|
|
||||||
if (roleNames().value(role) == "materialVisible")
|
if (roleName == "materialVisible")
|
||||||
return isMaterialVisible(index.row());
|
return isMaterialVisible(index.row());
|
||||||
|
|
||||||
if (!roleNames().contains(role))
|
if (roleName == "materialType")
|
||||||
qWarning() << Q_FUNC_INFO << "invalid role requested";
|
return m_materialList.at(index.row()).type();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -88,6 +91,7 @@ QHash<int, QByteArray> MaterialBrowserModel::roleNames() const
|
|||||||
{Qt::UserRole + 1, "materialName"},
|
{Qt::UserRole + 1, "materialName"},
|
||||||
{Qt::UserRole + 2, "materialInternalId"},
|
{Qt::UserRole + 2, "materialInternalId"},
|
||||||
{Qt::UserRole + 3, "materialVisible"},
|
{Qt::UserRole + 3, "materialVisible"},
|
||||||
|
{Qt::UserRole + 4, "materialType"}
|
||||||
};
|
};
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
@@ -120,6 +124,20 @@ void MaterialBrowserModel::setHasModelSelection(bool b)
|
|||||||
emit hasModelSelectionChanged();
|
emit hasModelSelectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeName MaterialBrowserModel::copiedMaterialType() const
|
||||||
|
{
|
||||||
|
return m_copiedMaterialType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialBrowserModel::setCopiedMaterialType(const TypeName &matType)
|
||||||
|
{
|
||||||
|
if (matType == m_copiedMaterialType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_copiedMaterialType = matType;
|
||||||
|
emit copiedMaterialTypeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
QList<ModelNode> MaterialBrowserModel::materials() const
|
QList<ModelNode> MaterialBrowserModel::materials() const
|
||||||
{
|
{
|
||||||
return m_materialList;
|
return m_materialList;
|
||||||
@@ -262,6 +280,18 @@ void MaterialBrowserModel::duplicateMaterial(int idx)
|
|||||||
emit duplicateMaterialTriggered(m_materialList.at(idx));
|
emit duplicateMaterialTriggered(m_materialList.at(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MaterialBrowserModel::copyMaterialProperties(int idx)
|
||||||
|
{
|
||||||
|
ModelNode mat = m_materialList.at(idx);
|
||||||
|
m_copiedMaterialProps = mat.properties();
|
||||||
|
setCopiedMaterialType(mat.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialBrowserModel::pasteMaterialProperties(int idx)
|
||||||
|
{
|
||||||
|
emit pasteMaterialPropertiesTriggered(m_materialList.at(idx), m_copiedMaterialProps);
|
||||||
|
}
|
||||||
|
|
||||||
void MaterialBrowserModel::deleteMaterial(int idx)
|
void MaterialBrowserModel::deleteMaterial(int idx)
|
||||||
{
|
{
|
||||||
m_materialList[idx].destroy();
|
m_materialList[idx].destroy();
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <modelnode.h>
|
#include <modelnode.h>
|
||||||
|
#include <qmlobjectnode.h>
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -41,6 +42,7 @@ class MaterialBrowserModel : public QAbstractListModel
|
|||||||
Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged)
|
Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged)
|
||||||
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
|
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
|
||||||
Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged)
|
Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged)
|
||||||
|
Q_PROPERTY(TypeName copiedMaterialType READ copiedMaterialType WRITE setCopiedMaterialType NOTIFY copiedMaterialTypeChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MaterialBrowserModel(QObject *parent = nullptr);
|
MaterialBrowserModel(QObject *parent = nullptr);
|
||||||
@@ -58,6 +60,9 @@ public:
|
|||||||
bool hasModelSelection() const;
|
bool hasModelSelection() const;
|
||||||
void setHasModelSelection(bool b);
|
void setHasModelSelection(bool b);
|
||||||
|
|
||||||
|
TypeName copiedMaterialType() const;
|
||||||
|
void setCopiedMaterialType(const TypeName &matType);
|
||||||
|
|
||||||
QList<ModelNode> materials() const;
|
QList<ModelNode> materials() const;
|
||||||
void setMaterials(const QList<ModelNode> &materials, bool hasQuick3DImport);
|
void setMaterials(const QList<ModelNode> &materials, bool hasQuick3DImport);
|
||||||
void removeMaterial(const ModelNode &material);
|
void removeMaterial(const ModelNode &material);
|
||||||
@@ -71,6 +76,8 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void selectMaterial(int idx, bool force = false);
|
Q_INVOKABLE void selectMaterial(int idx, bool force = false);
|
||||||
Q_INVOKABLE void duplicateMaterial(int idx);
|
Q_INVOKABLE void duplicateMaterial(int idx);
|
||||||
|
Q_INVOKABLE void copyMaterialProperties(int idx);
|
||||||
|
Q_INVOKABLE void pasteMaterialProperties(int idx);
|
||||||
Q_INVOKABLE void deleteMaterial(int idx);
|
Q_INVOKABLE void deleteMaterial(int idx);
|
||||||
Q_INVOKABLE void renameMaterial(int idx, const QString &newName);
|
Q_INVOKABLE void renameMaterial(int idx, const QString &newName);
|
||||||
Q_INVOKABLE void addNewMaterial();
|
Q_INVOKABLE void addNewMaterial();
|
||||||
@@ -81,11 +88,14 @@ signals:
|
|||||||
void isEmptyChanged();
|
void isEmptyChanged();
|
||||||
void hasQuick3DImportChanged();
|
void hasQuick3DImportChanged();
|
||||||
void hasModelSelectionChanged();
|
void hasModelSelectionChanged();
|
||||||
|
void copiedMaterialTypeChanged();
|
||||||
void selectedIndexChanged(int idx);
|
void selectedIndexChanged(int idx);
|
||||||
void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName);
|
void renameMaterialTriggered(const QmlDesigner::ModelNode &material, const QString &newName);
|
||||||
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,
|
||||||
|
const QList<QmlDesigner::AbstractProperty> &props);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isMaterialVisible(int idx) const;
|
bool isMaterialVisible(int idx) const;
|
||||||
@@ -93,12 +103,14 @@ private:
|
|||||||
|
|
||||||
QString m_searchText;
|
QString m_searchText;
|
||||||
QList<ModelNode> m_materialList;
|
QList<ModelNode> m_materialList;
|
||||||
|
QList<AbstractProperty> m_copiedMaterialProps;
|
||||||
QHash<qint32, int> m_materialIndexHash; // internalId -> index
|
QHash<qint32, int> m_materialIndexHash; // internalId -> index
|
||||||
|
|
||||||
int m_selectedIndex = 0;
|
int m_selectedIndex = 0;
|
||||||
bool m_isEmpty = true;
|
bool m_isEmpty = true;
|
||||||
bool m_hasQuick3DImport = false;
|
bool m_hasQuick3DImport = false;
|
||||||
bool m_hasModelSelection = false;
|
bool m_hasModelSelection = false;
|
||||||
|
TypeName m_copiedMaterialType;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -24,15 +24,18 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "materialbrowserview.h"
|
#include "materialbrowserview.h"
|
||||||
|
|
||||||
|
#include "bindingproperty.h"
|
||||||
#include "materialbrowserwidget.h"
|
#include "materialbrowserwidget.h"
|
||||||
#include "materialbrowsermodel.h"
|
#include "materialbrowsermodel.h"
|
||||||
#include "nodeabstractproperty.h"
|
#include "nodeabstractproperty.h"
|
||||||
#include "qmlobjectnode.h"
|
#include "qmlobjectnode.h"
|
||||||
#include "variantproperty.h"
|
#include "variantproperty.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <designmodecontext.h>
|
||||||
#include <nodeinstanceview.h>
|
#include <nodeinstanceview.h>
|
||||||
#include <qmldesignerconstants.h>
|
#include <qmldesignerconstants.h>
|
||||||
#include <designmodecontext.h>
|
|
||||||
|
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
|
||||||
@@ -86,6 +89,30 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
[&] (const ModelNode &material) {
|
[&] (const ModelNode &material) {
|
||||||
emitCustomNotification("duplicate_material", {material});
|
emitCustomNotification("duplicate_material", {material});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(matBrowserModel, &MaterialBrowserModel::pasteMaterialPropertiesTriggered, this,
|
||||||
|
[&] (const ModelNode &material, const QList<AbstractProperty> &props) {
|
||||||
|
QmlObjectNode mat(material);
|
||||||
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
|
// remove current properties
|
||||||
|
const PropertyNameList propNames = material.propertyNames();
|
||||||
|
for (const PropertyName &propName : propNames) {
|
||||||
|
if (propName != "objectName")
|
||||||
|
mat.removeProperty(propName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply pasted properties
|
||||||
|
for (const AbstractProperty &prop : props) {
|
||||||
|
if (prop.name() == "objectName")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (prop.isVariantProperty())
|
||||||
|
mat.setVariantProperty(prop.name(), prop.toVariantProperty().value());
|
||||||
|
else if (prop.isBindingProperty())
|
||||||
|
mat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return createWidgetInfo(m_widget.data(),
|
return createWidgetInfo(m_widget.data(),
|
||||||
|
Reference in New Issue
Block a user