forked from qt-creator/qt-creator
QmlDesigner: Add backend for textures in PropertyEditor
Task-number: QDS-14805 Change-Id: I71a5935af3c2cddbeb87f496d2e15464244639c2 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -424,6 +424,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
qmlanchorbindingproxy.cpp qmlanchorbindingproxy.h
|
||||
qmlmaterialnodeproxy.cpp qmlmaterialnodeproxy.h
|
||||
qmlmodelnodeproxy.cpp qmlmodelnodeproxy.h
|
||||
qmltexturenodeproxy.cpp qmltexturenodeproxy.h
|
||||
quick2propertyeditorview.cpp quick2propertyeditorview.h
|
||||
propertyeditorutils.cpp propertyeditorutils.h
|
||||
)
|
||||
|
@@ -339,6 +339,7 @@ void PropertyEditorQmlBackend::handleVariantPropertyChangedInModelNodeProxy(cons
|
||||
void PropertyEditorQmlBackend::handleBindingPropertyChangedInModelNodeProxy(const BindingProperty &property)
|
||||
{
|
||||
m_backendModelNode.handleBindingPropertyChanged(property);
|
||||
m_backendTextureNode.handleBindingPropertyChanged(property);
|
||||
updateInstanceImage();
|
||||
}
|
||||
|
||||
@@ -350,11 +351,13 @@ void PropertyEditorQmlBackend::handleBindingPropertyInModelNodeProxyAboutToChang
|
||||
if (expressionNode.metaInfo().isQtQuick3DTexture())
|
||||
updateInstanceImage();
|
||||
}
|
||||
m_backendTextureNode.handleBindingPropertyChanged(property);
|
||||
}
|
||||
|
||||
void PropertyEditorQmlBackend::handlePropertiesRemovedInModelNodeProxy(const AbstractProperty &property)
|
||||
{
|
||||
m_backendModelNode.handlePropertiesRemoved(property);
|
||||
m_backendTextureNode.handlePropertiesRemoved(property);
|
||||
updateInstanceImage();
|
||||
}
|
||||
|
||||
@@ -559,6 +562,7 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
|
||||
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
|
||||
|
||||
m_backendMaterialNode.setup(qmlObjectNode);
|
||||
m_backendTextureNode.setup(qmlObjectNode);
|
||||
|
||||
// className
|
||||
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
|
||||
@@ -995,6 +999,7 @@ void PropertyEditorQmlBackend::setupContextProperties()
|
||||
context()->setContextProperties({
|
||||
{"modelNodeBackend", QVariant::fromValue(&m_backendModelNode)},
|
||||
{"materialNodeBackend", QVariant::fromValue(&m_backendMaterialNode)},
|
||||
{"textureNodeBackend", QVariant::fromValue(&m_backendTextureNode)},
|
||||
{"anchorBackend", QVariant::fromValue(&m_backendAnchorBinding)},
|
||||
{"transaction", QVariant::fromValue(m_propertyEditorTransaction.get())},
|
||||
{"dummyBackendValue", QVariant::fromValue(m_dummyPropertyEditorValue.get())},
|
||||
@@ -1051,6 +1056,7 @@ bool PropertyEditorQmlBackend::checkIfUrlExists(const QUrl &url)
|
||||
void PropertyEditorQmlBackend::emitSelectionToBeChanged()
|
||||
{
|
||||
m_backendModelNode.emitSelectionToBeChanged();
|
||||
m_backendTextureNode.updateSelectionDetails();
|
||||
}
|
||||
|
||||
void PropertyEditorQmlBackend::emitSelectionChanged()
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "qmlanchorbindingproxy.h"
|
||||
#include "qmlmaterialnodeproxy.h"
|
||||
#include "qmlmodelnodeproxy.h"
|
||||
#include "qmltexturenodeproxy.h"
|
||||
#include "quick2propertyeditorview.h"
|
||||
|
||||
#include <utils/uniqueobjectptr.h>
|
||||
@@ -129,6 +130,7 @@ private:
|
||||
Utils::UniqueObjectPtr<Quick2PropertyEditorView> m_view = nullptr;
|
||||
QmlAnchorBindingProxy m_backendAnchorBinding;
|
||||
QmlMaterialNodeProxy m_backendMaterialNode;
|
||||
QmlTextureNodeProxy m_backendTextureNode;
|
||||
QmlModelNodeProxy m_backendModelNode;
|
||||
std::unique_ptr<PropertyEditorTransaction> m_propertyEditorTransaction;
|
||||
std::unique_ptr<PropertyEditorValue> m_dummyPropertyEditorValue;
|
||||
|
@@ -0,0 +1,170 @@
|
||||
// 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 "qmltexturenodeproxy.h"
|
||||
|
||||
#include <abstractview.h>
|
||||
#include <createtexture.h>
|
||||
#include <designmodewidget.h>
|
||||
#include <model.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <qqml.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
QmlTextureNodeProxy::QmlTextureNodeProxy() = default;
|
||||
|
||||
QmlTextureNodeProxy::~QmlTextureNodeProxy() = default;
|
||||
|
||||
void QmlTextureNodeProxy::setup(const QmlObjectNode &objectNode)
|
||||
{
|
||||
const QmlObjectNode texture = objectNode.metaInfo().isQtQuick3DTexture() ? objectNode
|
||||
: QmlObjectNode{};
|
||||
|
||||
setTextureNode(texture);
|
||||
updateSelectionDetails();
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::updateSelectionDetails()
|
||||
{
|
||||
QScopeGuard falseSetter{
|
||||
std::bind_front(&QmlTextureNodeProxy::setSelectedNodeAcceptsMaterial, this, false)};
|
||||
|
||||
if (!textureNode())
|
||||
return;
|
||||
|
||||
QmlObjectNode selectedNode = textureNode().view()->singleSelectedModelNode();
|
||||
if (!selectedNode)
|
||||
return;
|
||||
|
||||
falseSetter.dismiss();
|
||||
setSelectedNodeAcceptsMaterial(selectedNode.hasBindingProperty("materials"));
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::handlePropertyChanged(const AbstractProperty &property)
|
||||
{
|
||||
if (!textureNode())
|
||||
return;
|
||||
|
||||
QmlObjectNode node = property.parentModelNode();
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
QmlObjectNode selectedNode = textureNode().view()->singleSelectedModelNode();
|
||||
if (!selectedNode)
|
||||
return;
|
||||
|
||||
if (property.name() == "materials"_L1
|
||||
&& (selectedNode == node || selectedNode.propertyChangeForCurrentState() == node)) {
|
||||
updateSelectionDetails();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::handleBindingPropertyChanged(const BindingProperty &property)
|
||||
{
|
||||
handlePropertyChanged(property);
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::handlePropertiesRemoved(const AbstractProperty &property)
|
||||
{
|
||||
handlePropertyChanged(property);
|
||||
}
|
||||
|
||||
QmlObjectNode QmlTextureNodeProxy::textureNode() const
|
||||
{
|
||||
return m_textureNode;
|
||||
}
|
||||
|
||||
bool QmlTextureNodeProxy::hasTexture() const
|
||||
{
|
||||
return textureNode().isValid();
|
||||
}
|
||||
|
||||
bool QmlTextureNodeProxy::selectedNodeAcceptsMaterial() const
|
||||
{
|
||||
return m_selectedNodeAcceptsMaterial;
|
||||
}
|
||||
|
||||
QString QmlTextureNodeProxy::resolveResourcePath(const QString &path) const
|
||||
{
|
||||
if (Utils::FilePath::fromString(path).isAbsolutePath())
|
||||
return path;
|
||||
|
||||
return QmlDesignerPlugin::instance()
|
||||
->documentManager()
|
||||
.currentDesignDocument()
|
||||
->fileName()
|
||||
.absolutePath()
|
||||
.pathAppended(path)
|
||||
.cleanPath()
|
||||
.toUrlishString();
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::toolbarAction(int action)
|
||||
{
|
||||
if (!hasQuick3DImport())
|
||||
return;
|
||||
|
||||
switch (action) {
|
||||
case ToolBarAction::ApplyToSelected: {
|
||||
if (!textureNode())
|
||||
return;
|
||||
AbstractView *view = textureNode().view();
|
||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser");
|
||||
ModelNode targetNode = view->singleSelectedModelNode();
|
||||
view->emitCustomNotification("apply_texture_to_model3D", {targetNode, textureNode()});
|
||||
} break;
|
||||
|
||||
case ToolBarAction::AddNewTexture: {
|
||||
if (!textureNode())
|
||||
break;
|
||||
ModelNode newTexture = CreateTexture(textureNode().view()).execute();
|
||||
QTimer::singleShot(0, this, [newTexture]() {
|
||||
if (newTexture)
|
||||
newTexture.model()->setSelectedModelNodes({newTexture});
|
||||
});
|
||||
} break;
|
||||
|
||||
case ToolBarAction::DeleteCurrentTexture: {
|
||||
if (textureNode()) {
|
||||
AbstractView *view = textureNode().view();
|
||||
view->executeInTransaction(__FUNCTION__, [&] { textureNode().destroy(); });
|
||||
}
|
||||
} break;
|
||||
|
||||
case ToolBarAction::OpenMaterialBrowser: {
|
||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser", true);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::registerDeclarativeType()
|
||||
{
|
||||
qmlRegisterType<QmlTextureNodeProxy>("HelperWidgets", 2, 0, "QmlTextureNodeProxy");
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::setTextureNode(const QmlObjectNode &node)
|
||||
{
|
||||
if (m_textureNode == node)
|
||||
return;
|
||||
m_textureNode = node;
|
||||
emit textureNodeChanged();
|
||||
}
|
||||
|
||||
void QmlTextureNodeProxy::setSelectedNodeAcceptsMaterial(bool value)
|
||||
{
|
||||
if (m_selectedNodeAcceptsMaterial == value)
|
||||
return;
|
||||
m_selectedNodeAcceptsMaterial = value;
|
||||
emit selectedNodeAcceptsMaterialChanged();
|
||||
}
|
||||
|
||||
bool QmlTextureNodeProxy::hasQuick3DImport() const
|
||||
{
|
||||
return textureNode().isValid() && textureNode().model()->hasImport("QtQuick3D"_L1);
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -0,0 +1,64 @@
|
||||
// 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 <qmlobjectnode.h>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class QmlTextureNodeProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QmlObjectNode textureNode READ textureNode NOTIFY textureNodeChanged)
|
||||
Q_PROPERTY(bool hasTexture READ hasTexture NOTIFY textureNodeChanged)
|
||||
Q_PROPERTY(
|
||||
bool selectedNodeAcceptsMaterial
|
||||
READ selectedNodeAcceptsMaterial
|
||||
NOTIFY selectedNodeAcceptsMaterialChanged)
|
||||
|
||||
public:
|
||||
enum ToolBarAction {
|
||||
ApplyToSelected,
|
||||
AddNewTexture,
|
||||
DeleteCurrentTexture,
|
||||
OpenMaterialBrowser
|
||||
};
|
||||
Q_ENUM(ToolBarAction)
|
||||
|
||||
explicit QmlTextureNodeProxy();
|
||||
~QmlTextureNodeProxy() override;
|
||||
|
||||
void setup(const QmlObjectNode &objectNode);
|
||||
|
||||
void updateSelectionDetails();
|
||||
void handlePropertyChanged(const AbstractProperty &property);
|
||||
void handleBindingPropertyChanged(const BindingProperty &property);
|
||||
void handlePropertiesRemoved(const AbstractProperty &property);
|
||||
|
||||
QmlObjectNode textureNode() const;
|
||||
bool hasTexture() const;
|
||||
bool selectedNodeAcceptsMaterial() const;
|
||||
|
||||
Q_INVOKABLE QString resolveResourcePath(const QString &path) const;
|
||||
Q_INVOKABLE void toolbarAction(int action);
|
||||
|
||||
static void registerDeclarativeType();
|
||||
|
||||
signals:
|
||||
void textureNodeChanged();
|
||||
void selectedNodeAcceptsMaterialChanged();
|
||||
|
||||
private:
|
||||
void setTextureNode(const QmlObjectNode &node);
|
||||
void setSelectedNodeAcceptsMaterial(bool value);
|
||||
bool hasQuick3DImport() const;
|
||||
|
||||
QmlObjectNode m_textureNode;
|
||||
bool m_selectedNodeAcceptsMaterial = false;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -27,6 +27,7 @@
|
||||
#include "propertynamevalidator.h"
|
||||
#include "qmlanchorbindingproxy.h"
|
||||
#include "qmlmaterialnodeproxy.h"
|
||||
#include "qmltexturenodeproxy.h"
|
||||
#include "richtexteditor/richtexteditorproxy.h"
|
||||
#include "selectiondynamicpropertiesproxymodel.h"
|
||||
#include "theme.h"
|
||||
@@ -67,6 +68,7 @@ void Quick2PropertyEditorView::registerQmlTypes()
|
||||
ColorPaletteBackend::registerDeclarativeType();
|
||||
QmlAnchorBindingProxy::registerDeclarativeType();
|
||||
QmlMaterialNodeProxy::registerDeclarativeType();
|
||||
QmlTextureNodeProxy::registerDeclarativeType();
|
||||
BindingEditor::registerDeclarativeType();
|
||||
ActionEditor::registerDeclarativeType();
|
||||
AnnotationEditor::registerDeclarativeType();
|
||||
|
Reference in New Issue
Block a user