2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
#include "materialeditorview.h"
|
|
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
#include "asset.h"
|
|
|
|
|
#include "auxiliarydataproperties.h"
|
2023-09-21 13:00:40 +02:00
|
|
|
#include "bindingproperty.h"
|
2023-03-15 14:26:20 +02:00
|
|
|
#include "designdocument.h"
|
|
|
|
|
#include "designmodewidget.h"
|
|
|
|
|
#include "dynamicpropertiesmodel.h"
|
2023-09-14 17:08:56 +03:00
|
|
|
#include "externaldependenciesinterface.h"
|
2022-03-18 17:28:28 +02:00
|
|
|
#include "materialeditorcontextobject.h"
|
2022-07-22 16:46:48 +02:00
|
|
|
#include "materialeditordynamicpropertiesproxymodel.h"
|
2023-09-21 13:00:40 +02:00
|
|
|
#include "materialeditorqmlbackend.h"
|
2022-03-18 17:28:28 +02:00
|
|
|
#include "materialeditortransaction.h"
|
2023-03-15 14:26:20 +02:00
|
|
|
#include "metainfo.h"
|
|
|
|
|
#include "nodeinstanceview.h"
|
|
|
|
|
#include "nodelistproperty.h"
|
|
|
|
|
#include "nodemetainfo.h"
|
|
|
|
|
#include "propertyeditorqmlbackend.h"
|
|
|
|
|
#include "propertyeditorvalue.h"
|
|
|
|
|
#include "qmldesignerconstants.h"
|
|
|
|
|
#include "qmldesignerplugin.h"
|
|
|
|
|
#include "qmltimeline.h"
|
|
|
|
|
#include "variantproperty.h"
|
2024-02-20 18:05:38 +01:00
|
|
|
#include <utils3d.h>
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/messagebox.h>
|
2023-03-15 14:26:20 +02:00
|
|
|
|
2022-08-24 14:57:43 +02:00
|
|
|
#include <utils/environment.h>
|
2022-03-18 17:28:28 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QQuickItem>
|
|
|
|
|
#include <QStackedWidget>
|
|
|
|
|
#include <QShortcut>
|
2022-08-05 17:14:05 +03:00
|
|
|
#include <QColorDialog>
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
2022-09-15 15:01:49 +02:00
|
|
|
MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDependencies)
|
|
|
|
|
: AbstractView{externalDependencies}
|
|
|
|
|
, m_stackedWidget(new QStackedWidget)
|
2023-03-16 16:26:36 +02:00
|
|
|
, m_dynamicPropertiesModel(new DynamicPropertiesModel(true, this))
|
2022-03-18 17:28:28 +02:00
|
|
|
{
|
2023-06-09 09:30:41 +02:00
|
|
|
m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_F7), m_stackedWidget);
|
2022-03-18 17:28:28 +02:00
|
|
|
connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml);
|
|
|
|
|
|
2022-06-15 16:54:31 +03:00
|
|
|
m_ensureMatLibTimer.callOnTimeout([this] {
|
2022-06-22 14:46:27 +03:00
|
|
|
if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()
|
|
|
|
|
&& model()->rewriterView()->errors().isEmpty()) {
|
2023-01-31 14:08:16 +02:00
|
|
|
DesignDocument *doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
|
|
|
|
if (doc && !doc->inFileComponentModelActive())
|
2024-02-20 18:05:38 +01:00
|
|
|
Utils3D::ensureMaterialLibraryNode(this);
|
2022-11-17 17:52:26 +02:00
|
|
|
if (m_qmlBackEnd && m_qmlBackEnd->contextObject())
|
2024-02-20 18:05:38 +01:00
|
|
|
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(
|
|
|
|
|
Utils3D::materialLibraryNode(this).isValid());
|
2022-06-15 16:54:31 +03:00
|
|
|
m_ensureMatLibTimer.stop();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2022-07-13 14:05:44 +02:00
|
|
|
QmlDesignerPlugin::trackWidgetFocusTime(m_stackedWidget, Constants::EVENT_MATERIALEDITOR_TIME);
|
2022-07-22 16:46:48 +02:00
|
|
|
|
|
|
|
|
MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType();
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MaterialEditorView::~MaterialEditorView()
|
|
|
|
|
{
|
|
|
|
|
qDeleteAll(m_qmlBackendHash);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// from material editor to model
|
|
|
|
|
void MaterialEditorView::changeValue(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
PropertyName propertyName = name.toUtf8();
|
|
|
|
|
|
|
|
|
|
if (propertyName.isNull() || locked() || noValidSelection() || propertyName == "id"
|
|
|
|
|
|| propertyName == Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (propertyName == "objectName") {
|
|
|
|
|
renameMaterial(m_selectedMaterial, m_qmlBackEnd->propertyValueForName("objectName")->value().toString());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PropertyName underscoreName(propertyName);
|
|
|
|
|
underscoreName.replace('.', '_');
|
|
|
|
|
PropertyEditorValue *value = m_qmlBackEnd->propertyValueForName(QString::fromLatin1(underscoreName));
|
|
|
|
|
|
|
|
|
|
if (!value)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (propertyName.endsWith("__AUX")) {
|
|
|
|
|
commitAuxValueToModel(propertyName, value->value());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo();
|
|
|
|
|
|
|
|
|
|
QVariant castedValue;
|
|
|
|
|
|
2022-08-31 10:25:18 +02:00
|
|
|
if (auto property = metaInfo.property(propertyName)) {
|
|
|
|
|
castedValue = property.castedValue(value->value());
|
2022-03-18 17:28:28 +02:00
|
|
|
} else {
|
|
|
|
|
qWarning() << __FUNCTION__ << propertyName << "cannot be casted (metainfo)";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value->value().isValid() && !castedValue.isValid()) {
|
|
|
|
|
qWarning() << __FUNCTION__ << propertyName << "not properly casted (metainfo)";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool propertyTypeUrl = false;
|
|
|
|
|
|
2022-08-31 10:25:18 +02:00
|
|
|
if (auto property = metaInfo.property(propertyName)) {
|
|
|
|
|
if (property.propertyType().isUrl()) {
|
2022-03-18 17:28:28 +02:00
|
|
|
// turn absolute local file paths into relative paths
|
|
|
|
|
propertyTypeUrl = true;
|
|
|
|
|
QString filePath = castedValue.toUrl().toString();
|
|
|
|
|
QFileInfo fi(filePath);
|
|
|
|
|
if (fi.exists() && fi.isAbsolute()) {
|
|
|
|
|
QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
|
|
|
|
|
castedValue = QUrl(fileDir.relativeFilePath(filePath));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name == "state" && castedValue.toString() == "base state")
|
|
|
|
|
castedValue = "";
|
|
|
|
|
|
2023-06-09 09:32:42 +02:00
|
|
|
if (castedValue.typeId() == QVariant::Color) {
|
2022-03-18 17:28:28 +02:00
|
|
|
QColor color = castedValue.value<QColor>();
|
|
|
|
|
QColor newColor = QColor(color.name());
|
|
|
|
|
newColor.setAlpha(color.alpha());
|
|
|
|
|
castedValue = QVariant(newColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!value->value().isValid() || (propertyTypeUrl && value->value().toString().isEmpty())) { // reset
|
|
|
|
|
removePropertyFromModel(propertyName);
|
|
|
|
|
} else {
|
|
|
|
|
// QVector*D(0, 0, 0) detects as null variant though it is valid value
|
|
|
|
|
if (castedValue.isValid()
|
2023-06-09 09:32:42 +02:00
|
|
|
&& (!castedValue.isNull() || castedValue.typeId() == QVariant::Vector2D
|
|
|
|
|
|| castedValue.typeId() == QVariant::Vector3D
|
|
|
|
|
|| castedValue.typeId() == QVariant::Vector4D)) {
|
2022-03-18 17:28:28 +02:00
|
|
|
commitVariantValueToModel(propertyName, castedValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestPreviewRender();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isTrueFalseLiteral(const QString &expression)
|
|
|
|
|
{
|
|
|
|
|
return (expression.compare("false", Qt::CaseInsensitive) == 0)
|
|
|
|
|
|| (expression.compare("true", Qt::CaseInsensitive) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::changeExpression(const QString &propertyName)
|
|
|
|
|
{
|
|
|
|
|
PropertyName name = propertyName.toUtf8();
|
|
|
|
|
|
|
|
|
|
if (name.isNull() || locked() || noValidSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [this, name] {
|
2022-03-18 17:28:28 +02:00
|
|
|
PropertyName underscoreName(name);
|
|
|
|
|
underscoreName.replace('.', '_');
|
|
|
|
|
|
|
|
|
|
QmlObjectNode qmlObjectNode(m_selectedMaterial);
|
|
|
|
|
PropertyEditorValue *value = m_qmlBackEnd->propertyValueForName(QString::fromLatin1(underscoreName));
|
|
|
|
|
|
|
|
|
|
if (!value) {
|
|
|
|
|
qWarning() << __FUNCTION__ << "no value for " << underscoreName;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 10:25:18 +02:00
|
|
|
if (auto property = m_selectedMaterial.metaInfo().property(name)) {
|
2023-07-13 12:10:14 +02:00
|
|
|
auto propertyType = property.propertyType();
|
|
|
|
|
if (propertyType.isColor()) {
|
2022-03-18 17:28:28 +02:00
|
|
|
if (QColor(value->expression().remove('"')).isValid()) {
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, QColor(value->expression().remove('"')));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-07-13 12:10:14 +02:00
|
|
|
} else if (propertyType.isBool()) {
|
2022-03-18 17:28:28 +02:00
|
|
|
if (isTrueFalseLiteral(value->expression())) {
|
|
|
|
|
if (value->expression().compare("true", Qt::CaseInsensitive) == 0)
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, true);
|
|
|
|
|
else
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-07-13 12:10:14 +02:00
|
|
|
} else if (propertyType.isInteger()) {
|
2022-03-18 17:28:28 +02:00
|
|
|
bool ok;
|
|
|
|
|
int intValue = value->expression().toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, intValue);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-07-13 12:10:14 +02:00
|
|
|
} else if (propertyType.isFloat()) {
|
2022-03-18 17:28:28 +02:00
|
|
|
bool ok;
|
|
|
|
|
qreal realValue = value->expression().toDouble(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, realValue);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-07-13 12:10:14 +02:00
|
|
|
} else if (propertyType.isVariant()) {
|
2022-03-18 17:28:28 +02:00
|
|
|
bool ok;
|
|
|
|
|
qreal realValue = value->expression().toDouble(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, realValue);
|
|
|
|
|
return;
|
|
|
|
|
} else if (isTrueFalseLiteral(value->expression())) {
|
|
|
|
|
if (value->expression().compare("true", Qt::CaseInsensitive) == 0)
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, true);
|
|
|
|
|
else
|
|
|
|
|
qmlObjectNode.setVariantProperty(name, false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value->expression().isEmpty()) {
|
|
|
|
|
value->resetValue();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (qmlObjectNode.expression(name) != value->expression() || !qmlObjectNode.propertyAffectedByCurrentState(name))
|
|
|
|
|
qmlObjectNode.setBindingProperty(name, value->expression());
|
|
|
|
|
|
|
|
|
|
requestPreviewRender();
|
|
|
|
|
}); // end of transaction
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::exportPropertyAsAlias(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
if (name.isNull() || locked() || noValidSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [this, name] {
|
2022-03-18 17:28:28 +02:00
|
|
|
const QString id = m_selectedMaterial.validId();
|
|
|
|
|
QString upperCasePropertyName = name;
|
|
|
|
|
upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper());
|
|
|
|
|
QString aliasName = id + upperCasePropertyName;
|
|
|
|
|
aliasName.replace(".", ""); //remove all dots
|
|
|
|
|
|
|
|
|
|
PropertyName propertyName = aliasName.toUtf8();
|
|
|
|
|
if (rootModelNode().hasProperty(propertyName)) {
|
|
|
|
|
Core::AsynchronousMessageBox::warning(tr("Cannot Export Property as Alias"),
|
|
|
|
|
tr("Property %1 does already exist for root component.").arg(aliasName));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
rootModelNode().bindingProperty(propertyName).setDynamicTypeNameAndExpression("alias", id + "." + name);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::removeAliasExport(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
if (name.isNull() || locked() || noValidSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [this, name] {
|
2022-03-18 17:28:28 +02:00
|
|
|
const QString id = m_selectedMaterial.validId();
|
|
|
|
|
|
|
|
|
|
const QList<BindingProperty> bindingProps = rootModelNode().bindingProperties();
|
|
|
|
|
for (const BindingProperty &property : bindingProps) {
|
|
|
|
|
if (property.expression() == (id + "." + name)) {
|
|
|
|
|
rootModelNode().removeProperty(property.name());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MaterialEditorView::locked() const
|
|
|
|
|
{
|
|
|
|
|
return m_locked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::currentTimelineChanged(const ModelNode &)
|
|
|
|
|
{
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(this));
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-16 16:26:36 +02:00
|
|
|
DynamicPropertiesModel *MaterialEditorView::dynamicPropertiesModel() const
|
2022-07-22 16:46:48 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
void MaterialEditorView::timerEvent(QTimerEvent *timerEvent)
|
|
|
|
|
{
|
|
|
|
|
if (m_timerId == timerEvent->timerId())
|
|
|
|
|
resetView();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::resetView()
|
|
|
|
|
{
|
|
|
|
|
if (!model())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_locked = true;
|
|
|
|
|
|
|
|
|
|
if (m_timerId)
|
|
|
|
|
killTimer(m_timerId);
|
|
|
|
|
|
|
|
|
|
setupQmlBackend();
|
|
|
|
|
|
2024-05-02 14:03:50 +03:00
|
|
|
if (m_qmlBackEnd) {
|
2022-03-18 17:28:28 +02:00
|
|
|
m_qmlBackEnd->emitSelectionChanged();
|
2024-05-02 14:03:50 +03:00
|
|
|
updatePossibleTypes();
|
|
|
|
|
}
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender);
|
|
|
|
|
|
|
|
|
|
m_locked = false;
|
|
|
|
|
|
|
|
|
|
if (m_timerId)
|
|
|
|
|
m_timerId = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
QString MaterialEditorView::materialEditorResourcesPath()
|
|
|
|
|
{
|
|
|
|
|
#ifdef SHARE_QML_PATH
|
2022-08-24 14:57:43 +02:00
|
|
|
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
|
2022-03-18 17:28:28 +02:00
|
|
|
return QLatin1String(SHARE_QML_PATH) + "/materialEditorQmlSources";
|
|
|
|
|
#endif
|
|
|
|
|
return Core::ICore::resourcePath("qmldesigner/materialEditorQmlSources").toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::applyMaterialToSelectedModels(const ModelNode &material, bool add)
|
|
|
|
|
{
|
|
|
|
|
if (m_selectedModels.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(material.isValid(), return);
|
|
|
|
|
|
|
|
|
|
auto expToList = [](const QString &exp) {
|
|
|
|
|
QString copy = exp;
|
|
|
|
|
copy = copy.remove("[").remove("]");
|
|
|
|
|
|
|
|
|
|
QStringList tmp = copy.split(',', Qt::SkipEmptyParts);
|
|
|
|
|
for (QString &str : tmp)
|
|
|
|
|
str = str.trimmed();
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto listToExp = [](QStringList &stringList) {
|
|
|
|
|
if (stringList.size() > 1)
|
|
|
|
|
return QString("[" + stringList.join(",") + "]");
|
|
|
|
|
|
|
|
|
|
if (stringList.size() == 1)
|
|
|
|
|
return stringList.first();
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2022-03-18 17:28:28 +02:00
|
|
|
for (const ModelNode &node : std::as_const(m_selectedModels)) {
|
|
|
|
|
QmlObjectNode qmlObjNode(node);
|
|
|
|
|
if (add) {
|
|
|
|
|
QStringList matList = expToList(qmlObjNode.expression("materials"));
|
|
|
|
|
matList.append(material.id());
|
|
|
|
|
QString updatedExp = listToExp(matList);
|
|
|
|
|
qmlObjNode.setBindingProperty("materials", updatedExp);
|
|
|
|
|
} else {
|
|
|
|
|
qmlObjNode.setBindingProperty("materials", material.id());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::handleToolBarAction(int action)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_hasQuick3DImport, return);
|
|
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
|
case MaterialEditorContextObject::ApplyToSelected: {
|
|
|
|
|
applyMaterialToSelectedModels(m_selectedMaterial);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MaterialEditorContextObject::ApplyToSelectedAdd: {
|
|
|
|
|
applyMaterialToSelectedModels(m_selectedMaterial, true);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MaterialEditorContextObject::AddNewMaterial: {
|
2022-06-27 11:07:32 +03:00
|
|
|
if (!model())
|
|
|
|
|
break;
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2024-02-20 18:05:38 +01:00
|
|
|
ModelNode matLib = Utils3D::materialLibraryNode(this);
|
2022-08-11 12:45:05 +03:00
|
|
|
if (!matLib.isValid())
|
|
|
|
|
return;
|
2024-03-07 15:49:41 +01:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
|
ModelNode newMatNode = createModelNode("PrincipledMaterial");
|
|
|
|
|
#else
|
2023-02-28 15:31:11 +02:00
|
|
|
NodeMetaInfo metaInfo = model()->qtQuick3DPrincipledMaterialMetaInfo();
|
|
|
|
|
ModelNode newMatNode = createModelNode("QtQuick3D.PrincipledMaterial",
|
|
|
|
|
metaInfo.majorVersion(),
|
|
|
|
|
metaInfo.minorVersion());
|
2024-03-07 15:49:41 +01:00
|
|
|
#endif
|
2022-03-18 17:28:28 +02:00
|
|
|
renameMaterial(newMatNode, "New Material");
|
2022-08-11 12:45:05 +03:00
|
|
|
matLib.defaultNodeListProperty().reparentHere(newMatNode);
|
2022-03-18 17:28:28 +02:00
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MaterialEditorContextObject::DeleteCurrentMaterial: {
|
2023-06-27 12:49:36 +03:00
|
|
|
if (m_selectedMaterial.isValid()) {
|
|
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
|
|
|
|
m_selectedMaterial.destroy();
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-03-18 17:28:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MaterialEditorContextObject::OpenMaterialBrowser: {
|
2022-05-24 16:04:50 +03:00
|
|
|
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser", true);
|
2022-03-18 17:28:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 17:14:05 +03:00
|
|
|
void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue)
|
|
|
|
|
{
|
2022-09-08 17:10:34 +03:00
|
|
|
if (envAndValue.isEmpty() || m_initializingPreviewData)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(m_hasQuick3DImport, return);
|
|
|
|
|
QTC_ASSERT(model(), return);
|
|
|
|
|
QTC_ASSERT(model()->nodeInstanceView(), return);
|
|
|
|
|
|
|
|
|
|
QStringList parts = envAndValue.split('=');
|
|
|
|
|
QString env = parts[0];
|
|
|
|
|
QString value;
|
|
|
|
|
if (parts.size() > 1)
|
|
|
|
|
value = parts[1];
|
|
|
|
|
|
2024-02-06 14:01:07 +01:00
|
|
|
auto renderPreviews = [this](const QString &auxEnv, const QString &auxValue) {
|
2022-09-08 17:10:34 +03:00
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewEnvDocProperty, auxEnv);
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewEnvProperty, auxEnv);
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewEnvValueDocProperty, auxValue);
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewEnvValueProperty, auxValue);
|
|
|
|
|
QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender);
|
|
|
|
|
emitCustomNotification("refresh_material_browser", {});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (env == "Color") {
|
|
|
|
|
m_colorDialog.clear();
|
|
|
|
|
|
|
|
|
|
// Store color to separate property to persist selection over non-color env changes
|
|
|
|
|
auto oldColorPropVal = rootModelNode().auxiliaryData(materialPreviewColorDocProperty);
|
|
|
|
|
auto oldEnvPropVal = rootModelNode().auxiliaryData(materialPreviewEnvDocProperty);
|
|
|
|
|
auto oldValuePropVal = rootModelNode().auxiliaryData(materialPreviewEnvValueDocProperty);
|
|
|
|
|
QString oldColor = oldColorPropVal ? oldColorPropVal->toString() : "";
|
|
|
|
|
QString oldEnv = oldEnvPropVal ? oldEnvPropVal->toString() : "";
|
|
|
|
|
QString oldValue = oldValuePropVal ? oldValuePropVal->toString() : "";
|
|
|
|
|
|
|
|
|
|
m_colorDialog = new QColorDialog(Core::ICore::dialogParent());
|
|
|
|
|
m_colorDialog->setModal(true);
|
|
|
|
|
m_colorDialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
m_colorDialog->setCurrentColor(QColor(oldColor));
|
|
|
|
|
m_colorDialog->show();
|
|
|
|
|
|
|
|
|
|
QObject::connect(m_colorDialog, &QColorDialog::currentColorChanged,
|
|
|
|
|
m_colorDialog, [=](const QColor &color) {
|
|
|
|
|
renderPreviews(env, color.name());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
QObject::connect(m_colorDialog, &QColorDialog::colorSelected,
|
2024-02-06 14:01:07 +01:00
|
|
|
m_colorDialog, [this, renderPreviews, env](const QColor &color) {
|
2022-09-08 17:10:34 +03:00
|
|
|
renderPreviews(env, color.name());
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewColorDocProperty, color.name());
|
|
|
|
|
});
|
|
|
|
|
|
2024-02-06 14:01:07 +01:00
|
|
|
QObject::connect(m_colorDialog, &QColorDialog::rejected, m_colorDialog,
|
|
|
|
|
[this, renderPreviews, oldEnv, oldValue] {
|
2022-09-08 17:10:34 +03:00
|
|
|
renderPreviews(oldEnv, oldValue);
|
|
|
|
|
initPreviewData();
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
renderPreviews(env, value);
|
2022-08-05 17:14:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::handlePreviewModelChanged(const QString &modelStr)
|
|
|
|
|
{
|
2022-09-08 17:10:34 +03:00
|
|
|
if (modelStr.isEmpty() || m_initializingPreviewData)
|
|
|
|
|
return;
|
2022-08-05 17:14:05 +03:00
|
|
|
|
2022-09-08 17:10:34 +03:00
|
|
|
QTC_ASSERT(m_hasQuick3DImport, return);
|
|
|
|
|
QTC_ASSERT(model(), return);
|
|
|
|
|
QTC_ASSERT(model()->nodeInstanceView(), return);
|
2022-08-05 17:14:05 +03:00
|
|
|
|
2022-09-08 17:10:34 +03:00
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewModelDocProperty, modelStr);
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewModelProperty, modelStr);
|
2022-08-05 17:14:05 +03:00
|
|
|
|
2022-09-08 17:10:34 +03:00
|
|
|
QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender);
|
|
|
|
|
emitCustomNotification("refresh_material_browser", {});
|
2022-08-05 17:14:05 +03:00
|
|
|
}
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
void MaterialEditorView::setupQmlBackend()
|
|
|
|
|
{
|
2024-03-07 15:49:41 +01:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
|
// TODO unify implementation with property editor view
|
|
|
|
|
#else
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
QUrl qmlPaneUrl;
|
|
|
|
|
QUrl qmlSpecificsUrl;
|
2022-08-12 12:47:21 +03:00
|
|
|
QString specificQmlData;
|
|
|
|
|
QString currentTypeName;
|
2022-03-18 17:28:28 +02:00
|
|
|
|
2024-02-20 18:05:38 +01:00
|
|
|
if (m_selectedMaterial.isValid() && m_hasQuick3DImport
|
|
|
|
|
&& (Utils3D::materialLibraryNode(this).isValid() || m_hasMaterialRoot)) {
|
2022-03-18 17:28:28 +02:00
|
|
|
qmlPaneUrl = QUrl::fromLocalFile(materialEditorResourcesPath() + "/MaterialEditorPane.qml");
|
|
|
|
|
|
2022-08-12 12:47:21 +03:00
|
|
|
TypeName diffClassName;
|
2022-08-31 10:25:18 +02:00
|
|
|
if (NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo()) {
|
2022-08-12 12:47:21 +03:00
|
|
|
diffClassName = metaInfo.typeName();
|
2023-07-05 14:04:26 +02:00
|
|
|
for (const NodeMetaInfo &metaInfo : metaInfo.selfAndPrototypes()) {
|
2022-08-12 12:47:21 +03:00
|
|
|
if (PropertyEditorQmlBackend::checkIfUrlExists(qmlSpecificsUrl))
|
|
|
|
|
break;
|
|
|
|
|
qmlSpecificsUrl = PropertyEditorQmlBackend::getQmlFileUrl(metaInfo.typeName()
|
|
|
|
|
+ "Specifics", metaInfo);
|
|
|
|
|
diffClassName = metaInfo.typeName();
|
|
|
|
|
}
|
2022-08-31 10:25:18 +02:00
|
|
|
|
|
|
|
|
if (diffClassName != m_selectedMaterial.type()) {
|
|
|
|
|
specificQmlData = PropertyEditorQmlBackend::templateGeneration(metaInfo,
|
|
|
|
|
model()->metaInfo(
|
|
|
|
|
diffClassName),
|
|
|
|
|
m_selectedMaterial);
|
|
|
|
|
}
|
2022-08-12 12:47:21 +03:00
|
|
|
}
|
|
|
|
|
currentTypeName = QString::fromLatin1(m_selectedMaterial.type());
|
2022-03-18 17:28:28 +02:00
|
|
|
} else {
|
|
|
|
|
qmlPaneUrl = QUrl::fromLocalFile(materialEditorResourcesPath() + "/EmptyMaterialEditorPane.qml");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MaterialEditorQmlBackend *currentQmlBackend = m_qmlBackendHash.value(qmlPaneUrl.toString());
|
|
|
|
|
|
|
|
|
|
QString currentStateName = currentState().isBaseState() ? currentState().name() : "invalid state";
|
|
|
|
|
|
|
|
|
|
if (!currentQmlBackend) {
|
|
|
|
|
currentQmlBackend = new MaterialEditorQmlBackend(this);
|
|
|
|
|
|
|
|
|
|
m_stackedWidget->addWidget(currentQmlBackend->widget());
|
|
|
|
|
m_qmlBackendHash.insert(qmlPaneUrl.toString(), currentQmlBackend);
|
|
|
|
|
|
|
|
|
|
currentQmlBackend->setup(m_selectedMaterial, currentStateName, qmlSpecificsUrl, this);
|
|
|
|
|
|
|
|
|
|
currentQmlBackend->setSource(qmlPaneUrl);
|
|
|
|
|
|
2022-08-05 17:14:05 +03:00
|
|
|
QObject *rootObj = currentQmlBackend->widget()->rootObject();
|
|
|
|
|
QObject::connect(rootObj, SIGNAL(toolBarAction(int)),
|
2022-03-18 17:28:28 +02:00
|
|
|
this, SLOT(handleToolBarAction(int)));
|
2022-08-05 17:14:05 +03:00
|
|
|
QObject::connect(rootObj, SIGNAL(previewEnvChanged(QString)),
|
|
|
|
|
this, SLOT(handlePreviewEnvChanged(QString)));
|
|
|
|
|
QObject::connect(rootObj, SIGNAL(previewModelChanged(QString)),
|
|
|
|
|
this, SLOT(handlePreviewModelChanged(QString)));
|
2022-03-18 17:28:28 +02:00
|
|
|
} else {
|
|
|
|
|
currentQmlBackend->setup(m_selectedMaterial, currentStateName, qmlSpecificsUrl, this);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 17:14:05 +03:00
|
|
|
currentQmlBackend->widget()->installEventFilter(this);
|
2022-03-18 17:28:28 +02:00
|
|
|
currentQmlBackend->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
|
2024-02-20 18:05:38 +01:00
|
|
|
currentQmlBackend->contextObject()->setHasMaterialLibrary(
|
|
|
|
|
Utils3D::materialLibraryNode(this).isValid());
|
2022-08-12 12:47:21 +03:00
|
|
|
currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
|
|
|
|
|
currentQmlBackend->contextObject()->setCurrentType(currentTypeName);
|
2023-09-14 17:08:56 +03:00
|
|
|
currentQmlBackend->contextObject()->setIsQt6Project(externalDependencies().isQt6Project());
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
m_qmlBackEnd = currentQmlBackend;
|
2022-08-12 12:47:21 +03:00
|
|
|
|
2022-07-22 16:46:48 +02:00
|
|
|
if (m_hasMaterialRoot)
|
|
|
|
|
m_dynamicPropertiesModel->setSelectedNode(m_selectedMaterial);
|
|
|
|
|
else
|
|
|
|
|
m_dynamicPropertiesModel->reset();
|
|
|
|
|
|
2022-08-05 17:14:05 +03:00
|
|
|
initPreviewData();
|
2022-08-12 12:47:21 +03:00
|
|
|
|
|
|
|
|
m_stackedWidget->setCurrentWidget(m_qmlBackEnd->widget());
|
2023-10-12 20:53:39 +02:00
|
|
|
m_stackedWidget->setMinimumSize({400, 300});
|
2024-03-07 15:49:41 +01:00
|
|
|
#endif
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value)
|
|
|
|
|
{
|
|
|
|
|
m_locked = true;
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2022-03-18 17:28:28 +02:00
|
|
|
QmlObjectNode(m_selectedMaterial).setVariantProperty(propertyName, value);
|
|
|
|
|
});
|
|
|
|
|
m_locked = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::commitAuxValueToModel(const PropertyName &propertyName, const QVariant &value)
|
|
|
|
|
{
|
|
|
|
|
m_locked = true;
|
|
|
|
|
|
|
|
|
|
PropertyName name = propertyName;
|
|
|
|
|
name.chop(5);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (value.isValid())
|
2022-07-25 20:16:58 +02:00
|
|
|
m_selectedMaterial.setAuxiliaryData(AuxiliaryDataType::Document, name, value);
|
2022-03-18 17:28:28 +02:00
|
|
|
else
|
2022-07-25 20:16:58 +02:00
|
|
|
m_selectedMaterial.removeAuxiliaryData(AuxiliaryDataType::Document, name);
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
catch (const Exception &e) {
|
|
|
|
|
e.showException();
|
|
|
|
|
}
|
|
|
|
|
m_locked = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::removePropertyFromModel(const PropertyName &propertyName)
|
|
|
|
|
{
|
|
|
|
|
m_locked = true;
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2022-03-18 17:28:28 +02:00
|
|
|
QmlObjectNode(m_selectedMaterial).removeProperty(propertyName);
|
|
|
|
|
});
|
|
|
|
|
m_locked = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MaterialEditorView::noValidSelection() const
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_qmlBackEnd, return true);
|
|
|
|
|
return !QmlObjectNode::isValidQmlObjectNode(m_selectedMaterial);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 17:14:05 +03:00
|
|
|
void MaterialEditorView::initPreviewData()
|
|
|
|
|
{
|
2022-09-08 17:10:34 +03:00
|
|
|
if (model() && m_qmlBackEnd) {
|
|
|
|
|
auto envPropVal = rootModelNode().auxiliaryData(materialPreviewEnvDocProperty);
|
|
|
|
|
auto envValuePropVal = rootModelNode().auxiliaryData(materialPreviewEnvValueDocProperty);
|
|
|
|
|
auto modelStrPropVal = rootModelNode().auxiliaryData(materialPreviewModelDocProperty);
|
|
|
|
|
QString env = envPropVal ? envPropVal->toString() : "";
|
|
|
|
|
QString envValue = envValuePropVal ? envValuePropVal->toString() : "";
|
|
|
|
|
QString modelStr = modelStrPropVal ? modelStrPropVal->toString() : "";
|
|
|
|
|
// Initialize corresponding instance aux values used by puppet
|
2022-09-12 18:14:30 +03:00
|
|
|
QTimer::singleShot(0, this, [this, env, envValue, modelStr]() {
|
|
|
|
|
if (model()) {
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewEnvProperty, env);
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewEnvValueProperty, envValue);
|
|
|
|
|
rootModelNode().setAuxiliaryData(materialPreviewModelProperty, modelStr);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2022-09-08 17:10:34 +03:00
|
|
|
if (!envValue.isEmpty() && env != "Color" && env != "Basic") {
|
|
|
|
|
env += '=';
|
|
|
|
|
env += envValue;
|
|
|
|
|
}
|
|
|
|
|
if (env.isEmpty())
|
|
|
|
|
env = "SkyBox=preview_studio";
|
|
|
|
|
if (modelStr.isEmpty())
|
|
|
|
|
modelStr = "#Sphere";
|
|
|
|
|
m_initializingPreviewData = true;
|
|
|
|
|
QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(),
|
|
|
|
|
"initPreviewData",
|
|
|
|
|
Q_ARG(QVariant, env), Q_ARG(QVariant, modelStr));
|
|
|
|
|
m_initializingPreviewData = false;
|
|
|
|
|
}
|
2022-08-05 17:14:05 +03:00
|
|
|
}
|
|
|
|
|
|
2022-08-12 12:47:21 +03:00
|
|
|
void MaterialEditorView::updatePossibleTypes()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(model(), return);
|
|
|
|
|
|
|
|
|
|
if (!m_qmlBackEnd)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-05-02 14:03:50 +03:00
|
|
|
static const QStringList basicTypes {
|
|
|
|
|
"CustomMaterial",
|
|
|
|
|
"DefaultMaterial",
|
|
|
|
|
"PrincipledMaterial",
|
|
|
|
|
"SpecularGlossyMaterial"
|
|
|
|
|
};
|
2023-09-21 13:00:40 +02:00
|
|
|
|
2024-05-02 14:03:50 +03:00
|
|
|
const QString matType = m_selectedMaterial.simplifiedTypeName();
|
2022-10-25 15:28:43 +03:00
|
|
|
|
2024-05-02 14:03:50 +03:00
|
|
|
if (basicTypes.contains(matType)) {
|
|
|
|
|
m_qmlBackEnd->contextObject()->setPossibleTypes(basicTypes);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-10-25 15:28:43 +03:00
|
|
|
|
2024-05-02 14:03:50 +03:00
|
|
|
m_qmlBackEnd->contextObject()->setPossibleTypes({matType});
|
2022-08-12 12:47:21 +03:00
|
|
|
}
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
void MaterialEditorView::modelAttached(Model *model)
|
|
|
|
|
{
|
|
|
|
|
AbstractView::modelAttached(model);
|
|
|
|
|
|
|
|
|
|
m_locked = true;
|
|
|
|
|
|
|
|
|
|
m_hasQuick3DImport = model->hasImport("QtQuick3D");
|
2022-08-24 13:11:33 +02:00
|
|
|
m_hasMaterialRoot = rootModelNode().metaInfo().isQtQuick3DMaterial();
|
2022-03-18 17:28:28 +02:00
|
|
|
|
2022-08-11 12:45:05 +03:00
|
|
|
if (m_hasMaterialRoot) {
|
|
|
|
|
m_selectedMaterial = rootModelNode();
|
|
|
|
|
} else if (m_hasQuick3DImport) {
|
|
|
|
|
// Creating the material library node on model attach causes errors as long as the type
|
|
|
|
|
// information is not complete yet, so we keep checking until type info is complete.
|
2022-06-15 16:54:31 +03:00
|
|
|
m_ensureMatLibTimer.start(500);
|
2022-08-11 12:45:05 +03:00
|
|
|
}
|
2022-06-15 16:54:31 +03:00
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
if (!m_setupCompleted) {
|
|
|
|
|
reloadQml();
|
|
|
|
|
m_setupCompleted = true;
|
|
|
|
|
}
|
|
|
|
|
resetView();
|
|
|
|
|
|
|
|
|
|
m_locked = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::modelAboutToBeDetached(Model *model)
|
|
|
|
|
{
|
|
|
|
|
AbstractView::modelAboutToBeDetached(model);
|
2022-07-22 16:46:48 +02:00
|
|
|
m_dynamicPropertiesModel->reset();
|
2022-03-18 17:28:28 +02:00
|
|
|
m_qmlBackEnd->materialEditorTransaction()->end();
|
2022-11-17 17:52:26 +02:00
|
|
|
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(false);
|
2023-10-24 17:11:14 +03:00
|
|
|
m_selectedMaterial = {};
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
|
|
|
|
|
{
|
|
|
|
|
if (noValidSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-06-22 14:43:43 +03:00
|
|
|
bool changed = false;
|
2022-03-18 17:28:28 +02:00
|
|
|
for (const AbstractProperty &property : propertyList) {
|
|
|
|
|
ModelNode node(property.parentModelNode());
|
|
|
|
|
|
|
|
|
|
if (node.isRootNode())
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedMaterial).isAliasExported());
|
|
|
|
|
|
|
|
|
|
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
|
|
|
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
2022-06-22 14:43:43 +03:00
|
|
|
changed = true;
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
2022-09-09 16:33:23 +02:00
|
|
|
|
|
|
|
|
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
2022-06-22 14:43:43 +03:00
|
|
|
if (changed)
|
|
|
|
|
requestPreviewRender();
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags /*propertyChange*/)
|
|
|
|
|
{
|
|
|
|
|
if (noValidSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
for (const VariantProperty &property : propertyList) {
|
|
|
|
|
ModelNode node(property.parentModelNode());
|
|
|
|
|
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
2022-07-22 16:46:48 +02:00
|
|
|
if (property.isDynamic())
|
2023-08-23 12:12:07 +02:00
|
|
|
m_dynamicPropertiesModel->updateItem(property);
|
2022-03-18 17:28:28 +02:00
|
|
|
if (m_selectedMaterial.property(property.name()).isBindingProperty())
|
|
|
|
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
|
|
|
|
else
|
|
|
|
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).modelValue(property.name()));
|
|
|
|
|
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
2022-09-09 16:33:23 +02:00
|
|
|
|
2022-11-17 12:54:19 +02:00
|
|
|
if (!changed && node.metaInfo().isQtQuick3DTexture()
|
|
|
|
|
&& m_selectedMaterial.bindingProperties().size() > 0) {
|
|
|
|
|
// update preview when editing texture properties if the material has binding properties
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-09 16:33:23 +02:00
|
|
|
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
if (changed)
|
|
|
|
|
requestPreviewRender();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags /*propertyChange*/)
|
|
|
|
|
{
|
|
|
|
|
if (noValidSelection())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
for (const BindingProperty &property : propertyList) {
|
|
|
|
|
ModelNode node(property.parentModelNode());
|
|
|
|
|
|
|
|
|
|
if (property.isAliasExport())
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedMaterial).isAliasExported());
|
|
|
|
|
|
|
|
|
|
if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) {
|
2022-07-22 16:46:48 +02:00
|
|
|
if (property.isDynamic())
|
2023-08-23 12:12:07 +02:00
|
|
|
m_dynamicPropertiesModel->updateItem(property);
|
2022-03-18 17:28:28 +02:00
|
|
|
if (QmlObjectNode(m_selectedMaterial).modelNode().property(property.name()).isBindingProperty())
|
|
|
|
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
|
|
|
|
else
|
|
|
|
|
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).modelValue(property.name()));
|
|
|
|
|
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
2022-09-09 16:33:23 +02:00
|
|
|
|
|
|
|
|
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
if (changed)
|
|
|
|
|
requestPreviewRender();
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-25 20:16:58 +02:00
|
|
|
void MaterialEditorView::auxiliaryDataChanged(const ModelNode &node,
|
|
|
|
|
AuxiliaryDataKeyView key,
|
|
|
|
|
const QVariant &)
|
2022-03-18 17:28:28 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (noValidSelection() || !node.isSelected())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-07-25 20:16:58 +02:00
|
|
|
m_qmlBackEnd->setValueforAuxiliaryProperties(m_selectedMaterial, key);
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-22 16:46:48 +02:00
|
|
|
void MaterialEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList)
|
|
|
|
|
{
|
2023-08-23 12:12:07 +02:00
|
|
|
for (const auto &property : propertyList)
|
|
|
|
|
m_dynamicPropertiesModel->removeItem(property);
|
2022-07-22 16:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
// request render image for the selected material node
|
|
|
|
|
void MaterialEditorView::requestPreviewRender()
|
|
|
|
|
{
|
2022-06-27 11:07:32 +03:00
|
|
|
if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid())
|
2022-03-18 17:28:28 +02:00
|
|
|
model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MaterialEditorView::hasWidget() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WidgetInfo MaterialEditorView::widgetInfo()
|
|
|
|
|
{
|
2022-05-25 09:57:44 +02:00
|
|
|
return createWidgetInfo(m_stackedWidget,
|
|
|
|
|
"MaterialEditor",
|
|
|
|
|
WidgetInfo::RightPane,
|
|
|
|
|
0,
|
2023-01-20 16:41:46 +01:00
|
|
|
tr("Material Editor"),
|
|
|
|
|
tr("Material Editor view"));
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
|
2022-07-07 18:04:18 +02:00
|
|
|
[[maybe_unused]] const QList<ModelNode> &lastSelectedNodeList)
|
2022-03-18 17:28:28 +02:00
|
|
|
{
|
|
|
|
|
m_selectedModels.clear();
|
|
|
|
|
|
|
|
|
|
for (const ModelNode &node : selectedNodeList) {
|
2022-08-24 13:11:33 +02:00
|
|
|
if (node.metaInfo().isQtQuick3DModel())
|
2022-03-18 17:28:28 +02:00
|
|
|
m_selectedModels.append(node);
|
|
|
|
|
}
|
2022-05-24 14:14:14 +03:00
|
|
|
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasModelSelection(!m_selectedModels.isEmpty());
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::currentStateChanged(const ModelNode &node)
|
|
|
|
|
{
|
|
|
|
|
QmlModelState newQmlModelState(node);
|
|
|
|
|
Q_ASSERT(newQmlModelState.isValid());
|
2023-03-15 14:26:20 +02:00
|
|
|
|
2022-11-10 16:56:10 +01:00
|
|
|
resetView();
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList)
|
|
|
|
|
{
|
|
|
|
|
if (!m_selectedMaterial.isValid() || !m_qmlBackEnd)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_locked = true;
|
|
|
|
|
|
2022-06-22 14:43:43 +03:00
|
|
|
bool changed = false;
|
2022-03-18 17:28:28 +02:00
|
|
|
for (const QPair<ModelNode, PropertyName> &propertyPair : propertyList) {
|
|
|
|
|
const ModelNode modelNode = propertyPair.first;
|
|
|
|
|
const QmlObjectNode qmlObjectNode(modelNode);
|
|
|
|
|
const PropertyName propertyName = propertyPair.second;
|
|
|
|
|
|
|
|
|
|
if (qmlObjectNode.isValid() && modelNode == m_selectedMaterial && qmlObjectNode.currentState().isValid()) {
|
|
|
|
|
const AbstractProperty property = modelNode.property(propertyName);
|
|
|
|
|
if (!modelNode.hasProperty(propertyName) || modelNode.property(property.name()).isBindingProperty())
|
|
|
|
|
setValue(modelNode, property.name(), qmlObjectNode.instanceValue(property.name()));
|
|
|
|
|
else
|
|
|
|
|
setValue(modelNode, property.name(), qmlObjectNode.modelValue(property.name()));
|
2022-06-22 14:43:43 +03:00
|
|
|
changed = true;
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-06-22 14:43:43 +03:00
|
|
|
if (changed)
|
|
|
|
|
requestPreviewRender();
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
m_locked = false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-12 12:47:21 +03:00
|
|
|
void MaterialEditorView::nodeTypeChanged(const ModelNode &node, const TypeName &typeName, int, int)
|
2022-03-18 17:28:28 +02:00
|
|
|
{
|
2022-08-12 12:47:21 +03:00
|
|
|
if (node == m_selectedMaterial) {
|
|
|
|
|
m_qmlBackEnd->contextObject()->setCurrentType(QString::fromLatin1(typeName));
|
2022-11-10 16:56:10 +01:00
|
|
|
resetView();
|
2022-08-12 12:47:21 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::rootNodeTypeChanged(const QString &type, int, int)
|
|
|
|
|
{
|
|
|
|
|
if (rootModelNode() == m_selectedMaterial) {
|
|
|
|
|
m_qmlBackEnd->contextObject()->setCurrentType(type);
|
2022-11-10 16:56:10 +01:00
|
|
|
resetView();
|
2022-08-12 12:47:21 +03:00
|
|
|
}
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
|
|
|
|
|
{
|
|
|
|
|
if (node == m_selectedMaterial)
|
|
|
|
|
m_qmlBackEnd->updateMaterialPreview(pixmap);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-30 13:14:17 +02:00
|
|
|
void MaterialEditorView::importsChanged([[maybe_unused]] const Imports &addedImports,
|
|
|
|
|
[[maybe_unused]] const Imports &removedImports)
|
2022-03-18 17:28:28 +02:00
|
|
|
{
|
|
|
|
|
m_hasQuick3DImport = model()->hasImport("QtQuick3D");
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
|
|
|
|
|
|
2022-06-23 15:37:26 +03:00
|
|
|
if (m_hasQuick3DImport)
|
|
|
|
|
m_ensureMatLibTimer.start(500);
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
resetView();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::renameMaterial(ModelNode &material, const QString &newName)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(material.isValid(), return);
|
|
|
|
|
|
2022-11-08 13:02:06 +02:00
|
|
|
QVariant objName = material.variantProperty("objectName").value();
|
|
|
|
|
if (objName.isValid() && objName.toString() == newName)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2022-09-06 15:50:31 +03:00
|
|
|
material.setIdWithRefactoring(model()->generateIdFromName(newName, "material"));
|
2022-03-18 17:28:28 +02:00
|
|
|
|
|
|
|
|
VariantProperty objNameProp = material.variantProperty("objectName");
|
|
|
|
|
objNameProp.setValue(newName);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 21:42:15 +03:00
|
|
|
void MaterialEditorView::duplicateMaterial(const ModelNode &material)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(material.isValid(), return);
|
|
|
|
|
|
2022-06-27 11:07:32 +03:00
|
|
|
if (!model())
|
|
|
|
|
return;
|
2022-05-25 21:42:15 +03:00
|
|
|
|
|
|
|
|
TypeName matType = material.type();
|
|
|
|
|
QmlObjectNode sourceMat(material);
|
2022-10-25 18:06:43 +03:00
|
|
|
ModelNode duplicateMatNode;
|
|
|
|
|
QList<AbstractProperty> dynamicProps;
|
2022-05-25 21:42:15 +03:00
|
|
|
|
|
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
2024-02-20 18:05:38 +01:00
|
|
|
ModelNode matLib = Utils3D::materialLibraryNode(this);
|
2022-08-11 12:45:05 +03:00
|
|
|
if (!matLib.isValid())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-05-25 21:42:15 +03:00
|
|
|
// create the duplicate material
|
2024-03-07 15:49:41 +01:00
|
|
|
#ifdef QDS_USE_PROJECTSTORAGE
|
|
|
|
|
QmlObjectNode duplicateMat = createModelNode(matType);
|
|
|
|
|
#else
|
2022-05-25 21:42:15 +03:00
|
|
|
NodeMetaInfo metaInfo = model()->metaInfo(matType);
|
|
|
|
|
QmlObjectNode duplicateMat = createModelNode(matType, metaInfo.majorVersion(), metaInfo.minorVersion());
|
2024-03-07 15:49:41 +01:00
|
|
|
#endif
|
2022-10-25 18:06:43 +03:00
|
|
|
duplicateMatNode = duplicateMat.modelNode();
|
|
|
|
|
|
2022-05-25 21:42:15 +03:00
|
|
|
// set name and id
|
|
|
|
|
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
|
2023-03-15 14:26:20 +02:00
|
|
|
VariantProperty objNameProp = duplicateMatNode.variantProperty("objectName");
|
|
|
|
|
objNameProp.setValue(newName);
|
2022-10-25 18:06:43 +03:00
|
|
|
duplicateMatNode.setIdWithoutRefactoring(model()->generateIdFromName(newName, "material"));
|
2022-05-25 21:42:15 +03:00
|
|
|
|
2022-10-25 18:06:43 +03:00
|
|
|
// sync properties. Only the base state is duplicated.
|
2022-05-25 21:42:15 +03:00
|
|
|
const QList<AbstractProperty> props = material.properties();
|
|
|
|
|
for (const AbstractProperty &prop : props) {
|
2022-10-25 18:06:43 +03:00
|
|
|
if (prop.name() == "objectName" || prop.name() == "data")
|
2022-05-25 21:42:15 +03:00
|
|
|
continue;
|
|
|
|
|
|
2022-10-25 18:06:43 +03:00
|
|
|
if (prop.isVariantProperty()) {
|
|
|
|
|
if (prop.isDynamic()) {
|
|
|
|
|
dynamicProps.append(prop);
|
|
|
|
|
} else {
|
2023-03-15 14:26:20 +02:00
|
|
|
VariantProperty variantProp = duplicateMatNode.variantProperty(prop.name());
|
|
|
|
|
variantProp.setValue(prop.toVariantProperty().value());
|
2022-10-25 18:06:43 +03:00
|
|
|
}
|
|
|
|
|
} else if (prop.isBindingProperty()) {
|
|
|
|
|
if (prop.isDynamic()) {
|
|
|
|
|
dynamicProps.append(prop);
|
|
|
|
|
} else {
|
2023-03-15 14:26:20 +02:00
|
|
|
BindingProperty bindingProp = duplicateMatNode.bindingProperty(prop.name());
|
|
|
|
|
bindingProp.setExpression(prop.toBindingProperty().expression());
|
2022-10-25 18:06:43 +03:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-25 21:42:15 +03:00
|
|
|
}
|
|
|
|
|
|
2022-08-11 12:45:05 +03:00
|
|
|
matLib.defaultNodeListProperty().reparentHere(duplicateMat);
|
2022-05-25 21:42:15 +03:00
|
|
|
});
|
2022-10-25 18:06:43 +03:00
|
|
|
|
|
|
|
|
// For some reason, creating dynamic properties in the same transaction doesn't work, so
|
|
|
|
|
// let's do it in separate transaction.
|
|
|
|
|
// TODO: Fix the issue and merge transactions (QDS-8094)
|
|
|
|
|
if (!dynamicProps.isEmpty()) {
|
|
|
|
|
executeInTransaction(__FUNCTION__, [&] {
|
|
|
|
|
for (const AbstractProperty &prop : std::as_const(dynamicProps)) {
|
|
|
|
|
if (prop.isVariantProperty()) {
|
2023-03-15 14:26:20 +02:00
|
|
|
VariantProperty variantProp = duplicateMatNode.variantProperty(prop.name());
|
|
|
|
|
variantProp.setDynamicTypeNameAndValue(prop.dynamicTypeName(),
|
|
|
|
|
prop.toVariantProperty().value());
|
2022-10-25 18:06:43 +03:00
|
|
|
} else if (prop.isBindingProperty()) {
|
2023-03-15 14:26:20 +02:00
|
|
|
BindingProperty bindingProp = duplicateMatNode.bindingProperty(prop.name());
|
|
|
|
|
bindingProp.setDynamicTypeNameAndExpression(prop.dynamicTypeName(),
|
|
|
|
|
prop.toBindingProperty().expression());
|
2022-10-25 18:06:43 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-05-25 21:42:15 +03:00
|
|
|
}
|
|
|
|
|
|
2022-07-07 18:04:18 +02:00
|
|
|
void MaterialEditorView::customNotification([[maybe_unused]] const AbstractView *view,
|
|
|
|
|
const QString &identifier,
|
|
|
|
|
const QList<ModelNode> &nodeList,
|
|
|
|
|
const QList<QVariant> &data)
|
2022-03-18 17:28:28 +02:00
|
|
|
{
|
|
|
|
|
if (identifier == "selected_material_changed") {
|
2022-08-11 12:45:05 +03:00
|
|
|
if (!m_hasMaterialRoot) {
|
|
|
|
|
m_selectedMaterial = nodeList.first();
|
2022-07-22 16:46:48 +02:00
|
|
|
m_dynamicPropertiesModel->setSelectedNode(m_selectedMaterial);
|
2022-08-11 12:45:05 +03:00
|
|
|
QTimer::singleShot(0, this, &MaterialEditorView::resetView);
|
|
|
|
|
}
|
2022-03-18 17:28:28 +02:00
|
|
|
} else if (identifier == "apply_to_selected_triggered") {
|
|
|
|
|
applyMaterialToSelectedModels(nodeList.first(), data.first().toBool());
|
|
|
|
|
} else if (identifier == "rename_material") {
|
|
|
|
|
if (m_selectedMaterial == nodeList.first())
|
|
|
|
|
renameMaterial(m_selectedMaterial, data.first().toString());
|
|
|
|
|
} else if (identifier == "add_new_material") {
|
|
|
|
|
handleToolBarAction(MaterialEditorContextObject::AddNewMaterial);
|
2022-05-25 21:42:15 +03:00
|
|
|
} else if (identifier == "duplicate_material") {
|
|
|
|
|
duplicateMaterial(nodeList.first());
|
2022-03-18 17:28:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 17:52:26 +02:00
|
|
|
void MaterialEditorView::nodeReparented(const ModelNode &node,
|
2022-11-23 13:59:18 +02:00
|
|
|
[[maybe_unused]] const NodeAbstractProperty &newPropertyParent,
|
|
|
|
|
[[maybe_unused]] const NodeAbstractProperty &oldPropertyParent,
|
|
|
|
|
[[maybe_unused]] PropertyChangeFlags propertyChange)
|
2022-11-17 17:52:26 +02:00
|
|
|
{
|
|
|
|
|
if (node.id() == Constants::MATERIAL_LIB_ID && m_qmlBackEnd && m_qmlBackEnd->contextObject())
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
|
|
|
|
|
{
|
|
|
|
|
if (removedNode.id() == Constants::MATERIAL_LIB_ID && m_qmlBackEnd && m_qmlBackEnd->contextObject())
|
|
|
|
|
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(false);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-30 15:31:13 +03:00
|
|
|
void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highlight)
|
|
|
|
|
{
|
2022-06-07 21:19:44 +03:00
|
|
|
if (!m_selectedMaterial.isValid())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-05-30 15:31:13 +03:00
|
|
|
DesignerPropertyMap &propMap = m_qmlBackEnd->backendValuesPropertyMap();
|
|
|
|
|
const QStringList propNames = propMap.keys();
|
2022-06-07 21:19:44 +03:00
|
|
|
NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo();
|
|
|
|
|
QTC_ASSERT(metaInfo.isValid(), return);
|
2022-05-30 15:31:13 +03:00
|
|
|
|
|
|
|
|
for (const QString &propName : propNames) {
|
2022-08-23 16:43:44 +02:00
|
|
|
if (metaInfo.property(propName.toUtf8()).propertyType().isQtQuick3DTexture()) {
|
2022-05-30 15:31:13 +03:00
|
|
|
QObject *propEditorValObj = propMap.value(propName).value<QObject *>();
|
|
|
|
|
PropertyEditorValue *propEditorVal = qobject_cast<PropertyEditorValue *>(propEditorValObj);
|
|
|
|
|
propEditorVal->setHasActiveDrag(highlight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::dragStarted(QMimeData *mimeData)
|
|
|
|
|
{
|
2022-11-22 17:19:12 +02:00
|
|
|
if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) {
|
|
|
|
|
const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',')[0];
|
2023-03-15 14:26:20 +02:00
|
|
|
Asset asset(assetPath);
|
2022-05-30 15:31:13 +03:00
|
|
|
|
2023-03-15 14:26:20 +02:00
|
|
|
if (!asset.isValidTextureSource()) // currently only image assets have dnd-supported properties
|
2022-11-22 17:19:12 +02:00
|
|
|
return;
|
2022-05-30 15:31:13 +03:00
|
|
|
|
2022-11-22 17:19:12 +02:00
|
|
|
highlightSupportedProperties();
|
2023-01-20 13:52:00 +02:00
|
|
|
} else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)
|
|
|
|
|
|| mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
|
2022-11-22 17:19:12 +02:00
|
|
|
highlightSupportedProperties();
|
|
|
|
|
}
|
2022-05-30 15:31:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialEditorView::dragEnded()
|
|
|
|
|
{
|
|
|
|
|
highlightSupportedProperties(false);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
// from model to material editor
|
|
|
|
|
void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value)
|
|
|
|
|
{
|
|
|
|
|
m_locked = true;
|
|
|
|
|
m_qmlBackEnd->setValue(qmlObjectNode, name, value);
|
|
|
|
|
m_locked = false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 17:14:05 +03:00
|
|
|
bool MaterialEditorView::eventFilter(QObject *obj, QEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->type() == QEvent::FocusOut) {
|
|
|
|
|
if (m_qmlBackEnd && m_qmlBackEnd->widget() == obj)
|
|
|
|
|
QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), "closeContextMenu");
|
|
|
|
|
}
|
2022-11-15 21:36:09 +02:00
|
|
|
return AbstractView::eventFilter(obj, event);
|
2022-08-05 17:14:05 +03:00
|
|
|
}
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
void MaterialEditorView::reloadQml()
|
|
|
|
|
{
|
|
|
|
|
m_qmlBackendHash.clear();
|
|
|
|
|
while (QWidget *widget = m_stackedWidget->widget(0)) {
|
|
|
|
|
m_stackedWidget->removeWidget(widget);
|
|
|
|
|
delete widget;
|
|
|
|
|
}
|
|
|
|
|
m_qmlBackEnd = nullptr;
|
|
|
|
|
|
|
|
|
|
resetView();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace QmlDesigner
|