QmlDesigner: Remove MaterialEditor

* For editing materials, the material is forced to be opened by
property editor. It means that if property editor is locked, the locked
would be ignored.

Task-number: QDS-14625
Change-Id: I271cc862750cecb6b2480c66d26e6aa5c6f62d55
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Ali Kianian
2025-03-17 16:20:14 +02:00
parent f4a67aa7a1
commit c4381e573b
38 changed files with 60 additions and 3552 deletions

View File

@@ -1,63 +0,0 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
StudioControls.PopupDialog {
id: colorPopup
property QtObject loaderItem: loader.item
property color originalColor
required property color currentColor
signal activateColor(color : color)
width: 260
onOriginalColorChanged: loader.updateOriginalColor()
onClosing: loader.active = false
function open(showItem) {
loader.ensureActive()
colorPopup.show(showItem)
loader.updateOriginalColor()
}
Loader {
id: loader
function ensureActive() {
if (!loader.active)
loader.active = true
}
function updateOriginalColor() {
if (loader.status === Loader.Ready)
loader.item.originalColor = colorPopup.originalColor
}
sourceComponent: StudioControls.ColorEditorPopup {
width: colorPopup.contentWidth
visible: colorPopup.visible
onActivateColor: (color) => {
colorPopup.activateColor(color)
}
}
Binding {
target: loader.item
property: "color"
value: colorPopup.currentColor
when: loader.status === Loader.Ready
}
onLoaded: {
loader.updateOriginalColor()
colorPopup.titleBar = loader.item.titleBarContent
}
}
}

View File

@@ -1,56 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import HelperWidgets
import StudioTheme as StudioTheme
PropertyEditorPane {
id: root
width: 420
height: 420
signal toolBarAction(int action)
signal previewEnvChanged(string env)
signal previewModelChanged(string model)
// Called from C++, dummy methods to avoid warnings
function closeContextMenu() {}
function initPreviewData(env, model) {}
Column {
id: col
MaterialEditorToolBar {
width: root.width
onToolBarAction: (action) => root.toolBarAction(action)
}
Item {
width: root.width - 2 * col.padding
height: 150
Text {
text: {
if (!isQt6Project)
qsTr("<b>Material Editor</b> is not supported in Qt5 projects.")
else if (!hasQuick3DImport)
qsTr("To use <b>Material Editor</b>, first add the QtQuick3D module in the <b>Components</b> view.")
else if (!hasMaterialLibrary)
qsTr("<b>Material Editor</b> is disabled inside a non-visual component.")
else
qsTr("There are no materials in this project.<br>Select '<b>+</b>' to create one.")
}
textFormat: Text.RichText
color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.mediumFontSize
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
width: root.width
anchors.centerIn: parent
}
}
}
}

View File

@@ -1,155 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtCore
import HelperWidgets
import StudioControls 1.0 as StudioControls
Item {
id: root
property string __previewEnv
property string __previewModel
width: 420
height: 420
signal toolBarAction(int action)
signal previewEnvChanged(string env)
signal previewModelChanged(string model)
// invoked from C++ to refresh material preview image
signal refreshPreview()
// Called from C++ to close context menu on focus out
function closeContextMenu()
{
Controller.closeContextMenu()
}
// Called from C++ to initialize preview menu checkmarks
function initPreviewData(env, model) {
root.__previewEnv = env
root.__previewModel = model
}
MaterialEditorToolBar {
id: toolbar
width: parent.width
onToolBarAction: (action) => root.toolBarAction(action)
}
Settings {
id: settings
property var topSection
property bool dockMode
}
StudioControls.SplitView {
id: splitView
readonly property bool isHorizontal: splitView.orientation == Qt.Horizontal
anchors.top: toolbar.bottom
anchors.bottom: parent.bottom
width: parent.width
orientation: splitView.width > 1000 ? Qt.Horizontal : Qt.Vertical
clip: true
Loader {
id: leftSideView
SplitView.fillWidth: leftSideView.visible
SplitView.fillHeight: leftSideView.visible
SplitView.minimumWidth: leftSideView.visible ? 300 : 0
SplitView.minimumHeight: leftSideView.visible ? 300 : 0
active: splitView.isHorizontal
visible: leftSideView.active && leftSideView.item
sourceComponent: PreviewComponent {}
}
PropertyEditorPane {
id: itemPane
clip: true
SplitView.fillWidth: !leftSideView.visible
SplitView.fillHeight: true
SplitView.minimumWidth: leftSideView.visible ? 400 : 0
SplitView.maximumWidth: leftSideView.visible ? 800 : -1
headerDocked: !leftSideView.visible && settings.dockMode
headerComponent: MaterialEditorTopSection {
id: topSection
Component.onCompleted: topSection.restoreState(settings.topSection)
Component.onDestruction: settings.topSection = topSection.saveState()
previewComponent: PreviewComponent {}
showImage: !splitView.isHorizontal
}
DynamicPropertiesSection {
propertiesModel: MaterialEditorDynamicPropertiesModel {}
}
Loader {
id: specificsTwo
property string theSource: specificQmlData
width: itemPane.width
visible: specificsTwo.theSource !== ""
sourceComponent: specificQmlComponent
onTheSourceChanged: {
specificsTwo.active = false
specificsTwo.active = true
}
}
Item { // spacer
width: 1
height: 10
visible: specificsTwo.visible
}
Loader {
id: specificsOne
width: itemPane.width
source: specificsUrl
}
}
}
component PreviewComponent : MaterialEditorPreview {
id: previewItem
onPreviewEnvChanged: root.previewEnvChanged(previewEnv)
onPreviewModelChanged: root.previewModelChanged(previewModel)
pinned: settings.dockMode
showPinButton: !leftSideView.visible
onPinnedChanged: settings.dockMode = previewItem.pinned
Binding {
previewItem.previewEnv: root.__previewEnv
previewItem.previewModel: root.__previewModel
delayed: true
}
Connections {
target: root
function onRefreshPreview() {
previewItem.refreshPreview()
}
}
}
}

View File

@@ -1,259 +0,0 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
Rectangle {
id: root
property string previewEnv
property string previewModel
property alias pinned: pinButton.checked
property alias showPinButton: pinButton.visible
property StudioTheme.ControlStyle buttonStyle: StudioTheme.ViewBarButtonStyle {
// This is how you can override stuff from the control styles
baseIconFontSize: StudioTheme.Values.bigIconFontSize
}
Connections {
target: HelperWidgets.Controller
function onCloseContextMenu() {
root.closeContextMenu()
}
}
implicitHeight: image.height
clip: true
color: "#000000"
// Called from C++ to close context menu on focus out
function closeContextMenu()
{
modelMenu.close()
envMenu.close()
}
function refreshPreview()
{
image.source = ""
image.source = "image://materialEditor/preview"
}
onPreviewEnvChanged: envMenu.updateEnvParams(root.previewEnv)
Image {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "image://materialEditor/preview"
cache: false
smooth: true
sourceSize.width: image.width
sourceSize.height: image.height
Rectangle {
id: toolbarRect
radius: 10
color: StudioTheme.Values.themeToolbarBackground
width: optionsToolbar.width + 2 * toolbarRect.radius
height: optionsToolbar.height + toolbarRect.radius
anchors.left: parent.left
anchors.leftMargin: -toolbarRect.radius
anchors.verticalCenter: parent.verticalCenter
Column {
id: optionsToolbar
spacing: 5
anchors.centerIn: parent
anchors.horizontalCenterOffset: optionsToolbar.spacing
HelperWidgets.AbstractButton {
id: pinButton
style: root.buttonStyle
buttonIcon: pinButton.checked ? StudioTheme.Constants.pin : StudioTheme.Constants.unpin
checkable: true
}
HelperWidgets.AbstractButton {
id: previewEnvMenuButton
style: root.buttonStyle
buttonIcon: StudioTheme.Constants.textures_medium
tooltip: qsTr("Select preview environment.")
onClicked: envMenu.popup()
}
HelperWidgets.AbstractButton {
id: previewModelMenuButton
style: root.buttonStyle
buttonIcon: StudioTheme.Constants.cube_medium
tooltip: qsTr("Select preview model.")
onClicked: modelMenu.popup()
}
}
}
}
StudioControls.Menu {
id: modelMenu
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
ListModel {
id: modelMenuModel
ListElement {
modelName: qsTr("Cone")
modelStr: "#Cone"
}
ListElement {
modelName: qsTr("Cube")
modelStr: "#Cube"
}
ListElement {
modelName: qsTr("Cylinder")
modelStr: "#Cylinder"
}
ListElement {
modelName: qsTr("Sphere")
modelStr: "#Sphere"
}
}
Repeater {
model: modelMenuModel
StudioControls.MenuItemWithIcon {
text: modelName
onClicked: {
// Force property change notifications to keep check mark when reselected
root.previewModel = ""
root.previewModel = modelStr
}
checkable: true
checked: root.previewModel === modelStr
}
}
}
StudioControls.Menu {
id: envMenu
property string previewEnvName
property string previewEnvValue
signal envParametersChanged()
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
Component.onCompleted: envMenu.updateEnvParams(root.previewEnv)
function updateEnvParams(str: string) {
let eqFound = str.lastIndexOf("=")
let newEnvName = (eqFound > 0) ? str.substr(0, eqFound) : str
let newEnvValue = (eqFound > 0) ? str.substr(eqFound + 1, str.length - eqFound) : ""
if (envMenu.previewEnvName !== newEnvName
|| envMenu.previewEnvValue !== newEnvValue) {
envMenu.previewEnvName = newEnvName
envMenu.previewEnvValue = newEnvValue
envMenu.envParametersChanged()
}
}
EnvMenuItem {
envName: qsTr("Basic")
envStr: "Basic"
}
EnvMenuItem {
id: colorItem
property color color
property bool colorIsValid: false
envName: qsTr("Color")
envStr: "Color"
checked: false
Component.onCompleted: update()
onColorIsValidChanged: updatePopupOriginalColor()
onClicked: {
colorItem.updatePopupOriginalColor()
colorPopup.open(colorItem)
}
onColorChanged: {
colorItem.envStr = colorItem.checked
? "Color=" + color.toString()
: "Color"
colorItem.commit()
}
function updatePopupOriginalColor() {
if (colorItem.colorIsValid)
colorPopup.originalColor = colorItem.color
}
function update() {
colorItem.checked = envMenu.previewEnvName === "Color"
if (colorItem.checked && envMenu.previewEnvValue) {
colorItem.color = envMenu.previewEnvValue
colorItem.colorIsValid = true
} else {
colorItem.colorIsValid = false
}
}
Connections {
target: envMenu
function onEnvParametersChanged() {
colorItem.update();
}
}
}
EnvMenuItem {
envName: qsTr("Studio")
envStr: "SkyBox=preview_studio"
}
EnvMenuItem {
envName: qsTr("Landscape")
envStr: "SkyBox=preview_landscape"
}
}
ColorEditorPopup {
id: colorPopup
currentColor: colorItem.color
onActivateColor: (color) => colorItem.color = color
}
component EnvMenuItem: StudioControls.MenuItemWithIcon {
required property string envName
property string envStr
function commit() {
root.previewEnv = envStr
}
text: envName
onClicked: commit()
checkable: false
checked: root.previewEnv === envStr
}
}

View File

@@ -1,56 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
import MaterialToolBarAction
Rectangle {
id: root
color: StudioTheme.Values.themeToolbarBackground
height: StudioTheme.Values.toolbarHeight
signal toolBarAction(int action)
Row {
id: row
spacing: StudioTheme.Values.toolbarSpacing
anchors.verticalCenter: parent.verticalCenter
leftPadding: 6
HelperWidgets.AbstractButton {
style: StudioTheme.Values.viewBarButtonStyle
buttonIcon: StudioTheme.Constants.apply_medium
enabled: hasMaterial && hasModelSelection && hasQuick3DImport && hasMaterialLibrary
tooltip: qsTr("Apply material to selected model.")
onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
}
HelperWidgets.AbstractButton {
style: StudioTheme.Values.viewBarButtonStyle
buttonIcon: StudioTheme.Constants.create_medium
enabled: hasQuick3DImport && hasMaterialLibrary
tooltip: qsTr("Create new material.")
onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial)
}
HelperWidgets.AbstractButton {
style: StudioTheme.Values.viewBarButtonStyle
buttonIcon: StudioTheme.Constants.delete_medium
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
tooltip: qsTr("Delete current material.")
onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial)
}
HelperWidgets.AbstractButton {
style: StudioTheme.Values.viewBarButtonStyle
buttonIcon: StudioTheme.Constants.materialBrowser_medium
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
tooltip: qsTr("Open material browser.")
onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
}
}
}

View File

@@ -1,93 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
StudioControls.SplitView {
id: root
property alias showImage: previewLoader.active
property Component previewComponent: null
width: parent.width
implicitHeight: showImage ? previewLoader.implicitHeight + nameSection.implicitHeight : nameSection.implicitHeight
orientation: Qt.Vertical
Loader {
id: previewLoader
SplitView.fillWidth: true
SplitView.minimumWidth: 152
SplitView.preferredHeight: previewLoader.visible ? Math.min(root.width * 0.75, 400) : 0
SplitView.minimumHeight: previewLoader.visible ? 150 : 0
SplitView.maximumHeight: previewLoader.visible ? 600 : 0
visible: previewLoader.active && previewLoader.item
sourceComponent: root.previewComponent
}
HelperWidgets.Section {
id: nameSection
// Section with hidden header is used so properties are aligned with the other sections' properties
hideHeader: true
SplitView.fillWidth: true
SplitView.preferredHeight: implicitHeight
SplitView.maximumHeight: implicitHeight
bottomPadding: StudioTheme.Values.sectionPadding * 2
collapsible: false
HelperWidgets.SectionLayout {
HelperWidgets.PropertyLabel { text: qsTr("Name") }
HelperWidgets.SecondColumnLayout {
HelperWidgets.Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
HelperWidgets.LineEdit {
id: matName
implicitWidth: StudioTheme.Values.singleControlColumnWidth
width: StudioTheme.Values.singleControlColumnWidth
placeholderText: qsTr("Material name")
showTranslateCheckBox: false
showExtendedFunctionButton: false
Timer {
running: true
interval: 0
onTriggered: matName.backendValue = backendValues.objectName
// backendValues.objectName is not available yet without the Timer
}
// allow only alphanumeric characters, underscores, no space at start, and 1 space between words
validator: RegularExpressionValidator { regularExpression: /^(\w+\s)*\w+$/ }
}
HelperWidgets.ExpandingSpacer {}
}
HelperWidgets.PropertyLabel { text: qsTr("Type") }
HelperWidgets.SecondColumnLayout {
HelperWidgets.Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
HelperWidgets.ComboBox {
currentIndex: possibleTypeIndex
model: possibleTypes
showExtendedFunctionButton: false
implicitWidth: StudioTheme.Values.singleControlColumnWidth
enabled: possibleTypes.length > 1
onActivated: changeTypeName(currentValue)
}
}
}
}
}

View File

@@ -52,7 +52,6 @@
<splitter orientation="Vertical" count="2"> <splitter orientation="Vertical" count="2">
<area tabs="3" current="Properties"> <area tabs="3" current="Properties">
<widget name="Properties" closed="false"/> <widget name="Properties" closed="false"/>
<widget name="MaterialEditor" closed="false"/>
<widget name="TextureEditor" closed="false"/> <widget name="TextureEditor" closed="false"/>
</area> </area>
<area tabs="3" current="MaterialBrowser"> <area tabs="3" current="MaterialBrowser">

View File

@@ -42,7 +42,6 @@
<splitter count="2" orientation="Vertical"> <splitter count="2" orientation="Vertical">
<area current="Properties" tabs="4"> <area current="Properties" tabs="4">
<widget closed="false" name="Properties"/> <widget closed="false" name="Properties"/>
<widget closed="false" name="MaterialEditor"/>
<widget closed="false" name="TextureEditor"/> <widget closed="false" name="TextureEditor"/>
<widget closed="true" name="ConnectionView"/> <widget closed="true" name="ConnectionView"/>
</area> </area>

View File

@@ -82,7 +82,6 @@ add_qtc_plugin(QmlDesigner
${CMAKE_CURRENT_LIST_DIR}/components/integration ${CMAKE_CURRENT_LIST_DIR}/components/integration
${CMAKE_CURRENT_LIST_DIR}/components/itemlibrary ${CMAKE_CURRENT_LIST_DIR}/components/itemlibrary
${CMAKE_CURRENT_LIST_DIR}/components/materialbrowser ${CMAKE_CURRENT_LIST_DIR}/components/materialbrowser
${CMAKE_CURRENT_LIST_DIR}/components/materialeditor
${CMAKE_CURRENT_LIST_DIR}/components/textureeditor ${CMAKE_CURRENT_LIST_DIR}/components/textureeditor
${CMAKE_CURRENT_LIST_DIR}/components/navigator ${CMAKE_CURRENT_LIST_DIR}/components/navigator
${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor ${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor
@@ -438,6 +437,7 @@ extend_qtc_plugin(QmlDesigner
qmltexturenodeproxy.cpp qmltexturenodeproxy.h qmltexturenodeproxy.cpp qmltexturenodeproxy.h
quick2propertyeditorview.cpp quick2propertyeditorview.h quick2propertyeditorview.cpp quick2propertyeditorview.h
propertyeditorutils.cpp propertyeditorutils.h propertyeditorutils.cpp propertyeditorutils.h
propertyeditor.qrc
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
@@ -461,18 +461,6 @@ extend_qtc_plugin(QmlDesigner
usertexturecategory.cpp usertexturecategory.h usertexturecategory.cpp usertexturecategory.h
) )
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/materialeditor
SOURCES
materialeditorcontextobject.cpp materialeditorcontextobject.h
materialeditordynamicpropertiesproxymodel.cpp materialeditordynamicpropertiesproxymodel.h
materialeditorimageprovider.cpp materialeditorimageprovider.h
materialeditorqmlbackend.cpp materialeditorqmlbackend.h
materialeditortransaction.cpp materialeditortransaction.h
materialeditorview.cpp materialeditorview.h
materialeditor.qrc
)
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/textureeditor SOURCES_PREFIX components/textureeditor
SOURCES SOURCES

View File

@@ -1001,10 +1001,8 @@ void editMaterial(const SelectionContext &selectionContext)
} }
} }
if (material.isValid()) { if (material.isValid())
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor", true); Utils3D::openNodeInPropertyEditor(material);
Utils3D::selectMaterial(material);
}
} }
void addItemToStackedContainer(const SelectionContext &selectionContext) void addItemToStackedContainer(const SelectionContext &selectionContext)

View File

@@ -3,6 +3,7 @@
#include "utils3d.h" #include "utils3d.h"
#include <designmodewidget.h>
#include <itemlibraryentry.h> #include <itemlibraryentry.h>
#include <modelutils.h> #include <modelutils.h>
#include <nodeabstractproperty.h> #include <nodeabstractproperty.h>
@@ -186,14 +187,6 @@ ModelNode getMaterialOfModel(const ModelNode &model, int idx)
return mat; return mat;
} }
void selectMaterial(const ModelNode &material)
{
if (material.metaInfo().isQtQuick3DMaterial()) {
material.model()->rootModelNode().setAuxiliaryData(Utils3D::matLibSelectedMaterialProperty,
material.id());
}
}
void selectTexture(const ModelNode &texture) void selectTexture(const ModelNode &texture)
{ {
if (texture.metaInfo().isQtQuick3DTexture()) { if (texture.metaInfo().isQtQuick3DTexture()) {
@@ -202,18 +195,6 @@ void selectTexture(const ModelNode &texture)
} }
} }
ModelNode selectedMaterial(AbstractView *view)
{
if (!view)
return {};
ModelNode root = view->rootModelNode();
if (auto selectedProperty = root.auxiliaryData(Utils3D::matLibSelectedMaterialProperty))
return view->modelNodeForId(selectedProperty->toString());
return {};
}
ModelNode selectedTexture(AbstractView *view) ModelNode selectedTexture(AbstractView *view)
{ {
if (!view) if (!view)
@@ -597,5 +578,12 @@ void duplicateMaterial(AbstractView *view, const ModelNode &material)
} }
} }
void openNodeInPropertyEditor(const ModelNode &node)
{
QTC_ASSERT(node, return);
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("PropertyEditor", true);
node.view()->emitCustomNotification("force_editing_node", {node}); // To PropertyEditor
}
} // namespace Utils3D } // namespace Utils3D
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -15,8 +15,6 @@ namespace Utils3D {
inline constexpr AuxiliaryDataKeyView active3dSceneProperty{AuxiliaryDataType::Temporary, inline constexpr AuxiliaryDataKeyView active3dSceneProperty{AuxiliaryDataType::Temporary,
"active3dScene"}; "active3dScene"};
inline constexpr AuxiliaryDataKeyView matLibSelectedMaterialProperty{AuxiliaryDataType::Temporary,
"matLibSelMat"};
inline constexpr AuxiliaryDataKeyView matLibSelectedTextureProperty{AuxiliaryDataType::Temporary, inline constexpr AuxiliaryDataKeyView matLibSelectedTextureProperty{AuxiliaryDataType::Temporary,
"matLibSelTex"}; "matLibSelTex"};
@@ -35,9 +33,7 @@ ModelNode getMaterialOfModel(const ModelNode &model, int idx = 0);
// These methods handle selection of material library items for various material library views. // These methods handle selection of material library items for various material library views.
// This is separate selection from the normal selection handling. // This is separate selection from the normal selection handling.
void selectMaterial(const ModelNode &material);
void selectTexture(const ModelNode &texture); void selectTexture(const ModelNode &texture);
ModelNode selectedMaterial(AbstractView *view);
ModelNode selectedTexture(AbstractView *view); ModelNode selectedTexture(AbstractView *view);
ModelNode resolveSceneEnv(AbstractView *view, int sceneId); ModelNode resolveSceneEnv(AbstractView *view, int sceneId);
@@ -50,6 +46,8 @@ void applyMaterialToModels(AbstractView *view, const ModelNode &material,
void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId); void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId);
void openNodeInPropertyEditor(const ModelNode &node);
#ifdef QDS_USE_PROJECTSTORAGE #ifdef QDS_USE_PROJECTSTORAGE
ModelNode createMaterial(AbstractView *view, const TypeName &typeName); ModelNode createMaterial(AbstractView *view, const TypeName &typeName);
#else #else

View File

@@ -19,7 +19,6 @@
#include <formeditorview.h> #include <formeditorview.h>
#include <itemlibraryview.h> #include <itemlibraryview.h>
#include <materialbrowserview.h> #include <materialbrowserview.h>
#include <materialeditorview.h>
#include <model/auxiliarypropertystorageview.h> #include <model/auxiliarypropertystorageview.h>
#include <navigatorview.h> #include <navigatorview.h>
#include <nodeinstanceview.h> #include <nodeinstanceview.h>
@@ -73,7 +72,6 @@ public:
, navigatorView{externalDependencies} , navigatorView{externalDependencies}
, propertyEditorView(imageCache, externalDependencies) , propertyEditorView(imageCache, externalDependencies)
#ifndef QTC_USE_QML_DESIGNER_LITE #ifndef QTC_USE_QML_DESIGNER_LITE
, materialEditorView{externalDependencies}
, materialBrowserView{imageCache, externalDependencies} , materialBrowserView{imageCache, externalDependencies}
, textureEditorView{imageCache, externalDependencies} , textureEditorView{imageCache, externalDependencies}
#endif #endif
@@ -103,7 +101,6 @@ public:
NavigatorView navigatorView; NavigatorView navigatorView;
PropertyEditorView propertyEditorView; PropertyEditorView propertyEditorView;
#ifndef QTC_USE_QML_DESIGNER_LITE #ifndef QTC_USE_QML_DESIGNER_LITE
MaterialEditorView materialEditorView;
MaterialBrowserView materialBrowserView; MaterialBrowserView materialBrowserView;
TextureEditorView textureEditorView; TextureEditorView textureEditorView;
#endif #endif
@@ -233,7 +230,6 @@ QList<AbstractView *> ViewManager::standardViews() const
&d->itemLibraryView, &d->itemLibraryView,
&d->navigatorView, &d->navigatorView,
&d->propertyEditorView, &d->propertyEditorView,
&d->materialEditorView,
&d->materialBrowserView, &d->materialBrowserView,
&d->textureEditorView, &d->textureEditorView,
&d->statesEditorView, &d->statesEditorView,
@@ -460,7 +456,6 @@ QList<WidgetInfo> ViewManager::widgetInfos() const
widgetInfoList.append(d->navigatorView.widgetInfo()); widgetInfoList.append(d->navigatorView.widgetInfo());
widgetInfoList.append(d->propertyEditorView.widgetInfo()); widgetInfoList.append(d->propertyEditorView.widgetInfo());
#ifndef QTC_USE_QML_DESIGNER_LITE #ifndef QTC_USE_QML_DESIGNER_LITE
widgetInfoList.append(d->materialEditorView.widgetInfo());
widgetInfoList.append(d->materialBrowserView.widgetInfo()); widgetInfoList.append(d->materialBrowserView.widgetInfo());
widgetInfoList.append(d->textureEditorView.widgetInfo()); widgetInfoList.append(d->textureEditorView.widgetInfo());
#endif #endif

View File

@@ -181,8 +181,7 @@ QAction *Edit3DMaterialsAction::createMaterialAction(const ModelNode &material,
QAction *editMaterialAction = new QAction(tr("Edit"), menu); QAction *editMaterialAction = new QAction(tr("Edit"), menu);
connect(editMaterialAction, &QAction::triggered, menu, [material] { connect(editMaterialAction, &QAction::triggered, menu, [material] {
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor", true); Utils3D::openNodeInPropertyEditor(material);
Utils3D::selectMaterial(material);
}); });
menu->addAction(editMaterialAction); menu->addAction(editMaterialAction);

View File

@@ -185,21 +185,12 @@ void ComponentView::ensureMatLibTriggered()
return; return;
bool texSelected = Utils3D::selectedTexture(this).isValid(); bool texSelected = Utils3D::selectedTexture(this).isValid();
bool matSelected = Utils3D::selectedMaterial(this).isValid(); if (!texSelected) {
if (!texSelected || !matSelected) {
const QList<ModelNode> matLibNodes = matLib.directSubModelNodes(); const QList<ModelNode> matLibNodes = matLib.directSubModelNodes();
for (const ModelNode &node : matLibNodes) { for (const ModelNode &node : matLibNodes) {
if (!texSelected && node.metaInfo().isQtQuick3DTexture()) { if (node.metaInfo().isQtQuick3DTexture()) {
Utils3D::selectTexture(node); Utils3D::selectTexture(node);
if (matSelected) break;
break;
texSelected = true;
}
if (!matSelected && node.metaInfo().isQtQuick3DMaterial()) {
Utils3D::selectMaterial(node);
if (texSelected)
break;
matSelected = true;
} }
} }
} }
@@ -294,9 +285,7 @@ void ComponentView::nodeIdChanged(const ModelNode& node, const QString& newId, c
}; };
auto metaInfo = node.metaInfo(); auto metaInfo = node.metaInfo();
if (metaInfo.isQtQuick3DMaterial()) if (metaInfo.isQtQuick3DTexture())
maybeSetAuxData(Utils3D::matLibSelectedMaterialProperty);
else if (metaInfo.isQtQuick3DTexture())
maybeSetAuxData(Utils3D::matLibSelectedTextureProperty); maybeSetAuxData(Utils3D::matLibSelectedTextureProperty);
} }

View File

@@ -82,7 +82,6 @@ WidgetInfo MaterialBrowserView::widgetInfo()
if (m_widget.isNull()) { if (m_widget.isNull()) {
m_widget = new MaterialBrowserWidget(m_imageCache, this); m_widget = new MaterialBrowserWidget(m_imageCache, this);
// custom notifications below are sent to the MaterialEditor
MaterialBrowserModel *matBrowserModel = m_widget->materialBrowserModel().data(); MaterialBrowserModel *matBrowserModel = m_widget->materialBrowserModel().data();
connect(matBrowserModel, &MaterialBrowserModel::applyToSelectedTriggered, this, connect(matBrowserModel, &MaterialBrowserModel::applyToSelectedTriggered, this,

View File

@@ -78,7 +78,8 @@ public:
QSize *size, QSize *size,
[[maybe_unused]] const QSize &requestedSize) override [[maybe_unused]] const QSize &requestedSize) override
{ {
static QPixmap defaultPreview = QPixmap::fromImage(QImage(":/materialeditor/images/defaultmaterialpreview.png")); static QPixmap defaultPreview = QPixmap::fromImage(
QImage(":/propertyeditor/images/defaultmaterialpreview.png"));
QPixmap pixmap{150, 150}; QPixmap pixmap{150, 150};

View File

@@ -1,555 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "materialeditorcontextobject.h"
#include <bindingproperty.h>
#include <documentmanager.h>
#include <nodemetainfo.h>
#include <qmlobjectnode.h>
#include <qmltimeline.h>
#include <qmltimelinekeyframegroup.h>
#include <variantproperty.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QApplication>
#include <QCursor>
#include <QMessageBox>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQmlPropertyMap>
#include <QQuickWidget>
namespace QmlDesigner {
MaterialEditorContextObject::MaterialEditorContextObject(QQuickWidget *widget, QObject *parent)
: QObject(parent)
, m_quickWidget(widget)
{
qmlRegisterUncreatableType<MaterialEditorContextObject>("MaterialToolBarAction", 1, 0, "ToolBarAction", "Enum type");
}
QQmlComponent *MaterialEditorContextObject::specificQmlComponent()
{
if (m_specificQmlComponent)
return m_specificQmlComponent;
m_specificQmlComponent = new QQmlComponent(m_quickWidget->rootContext()->engine(), this);
m_specificQmlComponent->setData(m_specificQmlData.toUtf8(), QUrl::fromLocalFile("specifics.qml"));
return m_specificQmlComponent;
}
QString MaterialEditorContextObject::convertColorToString(const QVariant &color)
{
QString colorString;
QColor theColor;
if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>();
} else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
}
colorString = theColor.name();
if (theColor.alpha() != 255) {
QString hexAlpha = QString("%1").arg(theColor.alpha(), 2, 16, QLatin1Char('0'));
colorString.remove(0, 1);
colorString.prepend(hexAlpha);
colorString.prepend(QStringLiteral("#"));
}
return colorString;
}
// TODO: this method is used by the ColorEditor helper widget, check if at all needed?
QColor MaterialEditorContextObject::colorFromString(const QString &colorString)
{
return colorString;
}
void MaterialEditorContextObject::changeTypeName(const QString &typeName)
{
QTC_ASSERT(m_model && m_model->rewriterView(), return);
QTC_ASSERT(m_selectedMaterial.isValid(), return);
if (m_selectedMaterial.simplifiedTypeName() == typeName)
return;
// Ideally we should not misuse the rewriterView
// If we add more code here we have to forward the material editor view
RewriterView *rewriterView = m_model->rewriterView();
rewriterView->executeInTransaction("MaterialEditorContextObject::changeTypeName", [&] {
NodeMetaInfo metaInfo = m_model->metaInfo(typeName.toLatin1());
QTC_ASSERT(metaInfo.isValid(), return);
// Create a list of properties available for the new type
PropertyNameList propertiesAndSignals = Utils::transform<PropertyNameList>(
metaInfo.properties(), &PropertyMetaInfo::name);
// Add signals to the list
const PropertyNameList signalNames = metaInfo.signalNames();
for (const PropertyName &signal : signalNames) {
if (signal.isEmpty())
continue;
PropertyName name = signal;
QChar firstChar = QChar(signal.at(0)).toUpper().toLatin1();
name[0] = firstChar.toLatin1();
name.prepend("on");
propertiesAndSignals.append(name);
}
// Add dynamic properties and respective change signals
const QList<AbstractProperty> matProps = m_selectedMaterial.properties();
for (const auto &property : matProps) {
if (!property.isDynamic())
continue;
// Add dynamic property
propertiesAndSignals.append(property.name().toByteArray());
// Add its change signal
PropertyName name = property.name().toByteArray();
QChar firstChar = QChar(property.name().at(0)).toUpper().toLatin1();
name[0] = firstChar.toLatin1();
name.prepend("on");
name.append("Changed");
propertiesAndSignals.append(name);
}
// Compare current properties and signals with the ones available for change type
QList<PropertyName> incompatibleProperties;
for (const auto &property : matProps) {
if (!propertiesAndSignals.contains(property.name()))
incompatibleProperties.append(property.name().toByteArray());
}
// When switching between material types, copy base (diffuse) color and map properties of
// source type into corresponding properties of the target type.
const QList<PropertyName> baseColors = {"baseColor", "diffuseColor", "albedoColor"};
const QList<PropertyName> baseMaps = {"baseColorMap", "diffuseMap", "albedoMap"};
int sourceIndex = -1;
int targetIndex = -1;
NodeMetaInfo oldMetaInfo = m_selectedMaterial.metaInfo();
struct CopyData {
CopyData() {}
CopyData(PropertyName n) : name(n) {}
PropertyName name;
QVariant value;
bool isBinding = false;
};
QHash<PropertyName, CopyData> copyMap;
if (oldMetaInfo.isQtQuick3DPrincipledMaterial())
sourceIndex = 0;
else if (oldMetaInfo.isQtQuick3DDefaultMaterial())
sourceIndex = 1;
else if (oldMetaInfo.isQtQuick3DSpecularGlossyMaterial())
sourceIndex = 2;
if (metaInfo.isQtQuick3DPrincipledMaterial())
targetIndex = 0;
else if (metaInfo.isQtQuick3DDefaultMaterial())
targetIndex = 1;
else if (metaInfo.isQtQuick3DSpecularGlossyMaterial())
targetIndex = 2;
if (sourceIndex >= 0 && targetIndex >= 0) {
if (incompatibleProperties.contains(baseColors[sourceIndex])) {
copyMap.insert(baseColors[sourceIndex], baseColors[targetIndex]);
incompatibleProperties.removeOne(baseColors[sourceIndex]);
}
if (incompatibleProperties.contains(baseMaps[sourceIndex])) {
copyMap.insert(baseMaps[sourceIndex], baseMaps[targetIndex]);
incompatibleProperties.removeOne(baseMaps[sourceIndex]);
}
}
const auto &copyKeys = copyMap.keys();
Utils::sort(incompatibleProperties);
// Create a dialog showing incompatible properties and signals
if (!incompatibleProperties.empty()) {
QString detailedText = tr("<b>Incompatible properties:</b><br>");
for (const auto &p : std::as_const(incompatibleProperties))
detailedText.append("- " + QString::fromUtf8(p) + "<br>");
detailedText.chop(QString("<br>").size());
QMessageBox msgBox;
msgBox.setTextFormat(Qt::RichText);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("Change Type"));
msgBox.setText(tr("Changing the type from %1 to %2 can't be done without removing incompatible properties.<br><br>%3")
.arg(m_selectedMaterial.simplifiedTypeName(), typeName, detailedText));
msgBox.setInformativeText(tr("Do you want to continue by removing incompatible properties?"));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
if (msgBox.exec() == QMessageBox::Cancel) {
updatePossibleTypeIndex();
return;
}
for (const auto &p : std::as_const(incompatibleProperties))
m_selectedMaterial.removeProperty(p);
}
if (!copyKeys.isEmpty()) {
// 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(m_selectedMaterial).allTimelines();
for (const auto &key : std::as_const(copyKeys)) {
CopyData &copyData = copyMap[key];
for (const auto &timeLineNode : timeLines) {
QmlTimeline timeLine(timeLineNode);
if (timeLine.hasKeyframeGroup(m_selectedMaterial, key)) {
QmlTimelineKeyframeGroup group = timeLine.keyframeGroup(m_selectedMaterial,
key);
group.setPropertyName(copyData.name);
}
}
// Property value itself cannot be copied until type has been changed, so store it
AbstractProperty prop = m_selectedMaterial.property(key);
if (prop.isValid()) {
if (prop.isBindingProperty()) {
copyData.isBinding = true;
copyData.value = prop.toBindingProperty().expression();
} else {
copyData.value = prop.toVariantProperty().value();
}
}
m_selectedMaterial.removeProperty(key);
}
}
#ifdef QDS_USE_PROJECTSTORAGE
if (m_selectedMaterial.isRootNode())
rewriterView->changeRootNodeType(typeName.toUtf8(), -1, -1);
else
m_selectedMaterial.changeType(typeName.toUtf8(), -1, -1);
#else
if (m_selectedMaterial.isRootNode())
rewriterView->changeRootNodeType(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion());
else
m_selectedMaterial.changeType(metaInfo.typeName(),
metaInfo.majorVersion(),
metaInfo.minorVersion());
#endif
for (const auto &key : copyKeys) {
const CopyData &copyData = copyMap[key];
if (copyData.isBinding)
m_selectedMaterial.bindingProperty(copyData.name).setExpression(copyData.value.toString());
else
m_selectedMaterial.variantProperty(copyData.name).setValue(copyData.value);
}
});
}
void MaterialEditorContextObject::insertKeyframe(const QString &propertyName)
{
QTC_ASSERT(m_model && m_model->rewriterView(), return);
QTC_ASSERT(m_selectedMaterial.isValid(), return);
// Ideally we should not missuse the rewriterView
// If we add more code here we have to forward the material editor view
RewriterView *rewriterView = m_model->rewriterView();
QmlTimeline timeline = rewriterView->currentTimelineNode();
QTC_ASSERT(timeline.isValid(), return);
rewriterView->executeInTransaction("MaterialEditorContextObject::insertKeyframe", [&] {
timeline.insertKeyframe(m_selectedMaterial, propertyName.toUtf8());
});
}
int MaterialEditorContextObject::majorVersion() const
{
return m_majorVersion;
}
void MaterialEditorContextObject::setMajorVersion(int majorVersion)
{
if (m_majorVersion == majorVersion)
return;
m_majorVersion = majorVersion;
emit majorVersionChanged();
}
bool MaterialEditorContextObject::hasActiveTimeline() const
{
return m_hasActiveTimeline;
}
void MaterialEditorContextObject::setHasActiveTimeline(bool b)
{
if (b == m_hasActiveTimeline)
return;
m_hasActiveTimeline = b;
emit hasActiveTimelineChanged();
}
bool MaterialEditorContextObject::hasQuick3DImport() const
{
return m_hasQuick3DImport;
}
void MaterialEditorContextObject::setHasQuick3DImport(bool b)
{
if (b == m_hasQuick3DImport)
return;
m_hasQuick3DImport = b;
emit hasQuick3DImportChanged();
}
bool MaterialEditorContextObject::hasMaterialLibrary() const
{
return m_hasMaterialLibrary;
}
void MaterialEditorContextObject::setHasMaterialLibrary(bool b)
{
if (b == m_hasMaterialLibrary)
return;
m_hasMaterialLibrary = b;
emit hasMaterialLibraryChanged();
}
bool MaterialEditorContextObject::isQt6Project() const
{
return m_isQt6Project;
}
void MaterialEditorContextObject::setIsQt6Project(bool b)
{
if (m_isQt6Project == b)
return;
m_isQt6Project = b;
emit isQt6ProjectChanged();
}
bool MaterialEditorContextObject::hasModelSelection() const
{
return m_hasModelSelection;
}
void MaterialEditorContextObject::setHasModelSelection(bool b)
{
if (b == m_hasModelSelection)
return;
m_hasModelSelection = b;
emit hasModelSelectionChanged();
}
void MaterialEditorContextObject::setSelectedMaterial(const ModelNode &matNode)
{
m_selectedMaterial = matNode;
}
void MaterialEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl)
{
if (newSpecificsUrl == m_specificsUrl)
return;
m_specificsUrl = newSpecificsUrl;
emit specificsUrlChanged();
}
void MaterialEditorContextObject::setSpecificQmlData(const QString &newSpecificQmlData)
{
if (newSpecificQmlData == m_specificQmlData)
return;
m_specificQmlData = newSpecificQmlData;
delete m_specificQmlComponent;
m_specificQmlComponent = nullptr;
emit specificQmlComponentChanged();
emit specificQmlDataChanged();
}
void MaterialEditorContextObject::setStateName(const QString &newStateName)
{
if (newStateName == m_stateName)
return;
m_stateName = newStateName;
emit stateNameChanged();
}
void MaterialEditorContextObject::setAllStateNames(const QStringList &allStates)
{
if (allStates == m_allStateNames)
return;
m_allStateNames = allStates;
emit allStateNamesChanged();
}
void MaterialEditorContextObject::setPossibleTypes(const QStringList &types)
{
if (types == m_possibleTypes)
return;
m_possibleTypes = types;
emit possibleTypesChanged();
updatePossibleTypeIndex();
}
void MaterialEditorContextObject::setCurrentType(const QString &type)
{
m_currentType = type.split('.').last();
updatePossibleTypeIndex();
}
void MaterialEditorContextObject::setIsBaseState(bool newIsBaseState)
{
if (newIsBaseState == m_isBaseState)
return;
m_isBaseState = newIsBaseState;
emit isBaseStateChanged();
}
void MaterialEditorContextObject::setSelectionChanged(bool newSelectionChanged)
{
if (newSelectionChanged == m_selectionChanged)
return;
m_selectionChanged = newSelectionChanged;
emit selectionChangedChanged();
}
void MaterialEditorContextObject::setBackendValues(QQmlPropertyMap *newBackendValues)
{
if (newBackendValues == m_backendValues)
return;
m_backendValues = newBackendValues;
emit backendValuesChanged();
}
void MaterialEditorContextObject::setModel(Model *model)
{
m_model = model;
}
void MaterialEditorContextObject::triggerSelectionChanged()
{
setSelectionChanged(!m_selectionChanged);
}
void MaterialEditorContextObject::setHasAliasExport(bool hasAliasExport)
{
if (m_aliasExport == hasAliasExport)
return;
m_aliasExport = hasAliasExport;
emit hasAliasExportChanged();
}
void MaterialEditorContextObject::updatePossibleTypeIndex()
{
int newIndex = -1;
if (!m_currentType.isEmpty())
newIndex = m_possibleTypes.indexOf(m_currentType);
// Emit valid possible type index change even if the index doesn't change, as currentIndex on
// QML side will change to default internally if model is updated
if (m_possibleTypeIndex != -1 || m_possibleTypeIndex != newIndex) {
m_possibleTypeIndex = newIndex;
emit possibleTypeIndexChanged();
}
}
void MaterialEditorContextObject::hideCursor()
{
if (QApplication::overrideCursor())
return;
QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
if (QWidget *w = QApplication::activeWindow())
m_lastPos = QCursor::pos(w->screen());
}
void MaterialEditorContextObject::restoreCursor()
{
if (!QApplication::overrideCursor())
return;
QApplication::restoreOverrideCursor();
if (QWidget *w = QApplication::activeWindow())
QCursor::setPos(w->screen(), m_lastPos);
}
void MaterialEditorContextObject::holdCursorInPlace()
{
if (!QApplication::overrideCursor())
return;
if (QWidget *w = QApplication::activeWindow())
QCursor::setPos(w->screen(), m_lastPos);
}
int MaterialEditorContextObject::devicePixelRatio()
{
if (QWidget *w = QApplication::activeWindow())
return w->devicePixelRatio();
return 1;
}
QStringList MaterialEditorContextObject::allStatesForId(const QString &id)
{
if (m_model && m_model->rewriterView()) {
const QmlObjectNode node = m_model->rewriterView()->modelNodeForId(id);
if (node.isValid())
return node.allStateNames();
}
return {};
}
bool MaterialEditorContextObject::isBlocked(const QString &) const
{
return false;
}
void MaterialEditorContextObject::goIntoComponent()
{
QTC_ASSERT(m_model, return);
DocumentManager::goIntoComponent(m_selectedMaterial);
}
QRect MaterialEditorContextObject::screenRect() const
{
if (m_quickWidget && m_quickWidget->screen())
return m_quickWidget->screen()->availableGeometry();
return {};
}
QPoint MaterialEditorContextObject::globalPos(const QPoint &point) const
{
if (m_quickWidget)
return m_quickWidget->mapToGlobal(point);
return point;
}
} // QmlDesigner

View File

@@ -1,182 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <model.h>
#include <modelnode.h>
#include <QColor>
#include <QObject>
#include <QPoint>
#include <QUrl>
QT_BEGIN_NAMESPACE
class QQmlComponent;
class QQmlPropertyMap;
class QQuickWidget;
QT_END_NAMESPACE
namespace QmlDesigner {
class MaterialEditorContextObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QUrl specificsUrl READ specificsUrl WRITE setSpecificsUrl NOTIFY specificsUrlChanged)
Q_PROPERTY(QString specificQmlData READ specificQmlData WRITE setSpecificQmlData NOTIFY specificQmlDataChanged)
Q_PROPERTY(QQmlComponent *specificQmlComponent READ specificQmlComponent NOTIFY specificQmlComponentChanged)
Q_PROPERTY(QString stateName READ stateName WRITE setStateName NOTIFY stateNameChanged)
Q_PROPERTY(QStringList allStateNames READ allStateNames WRITE setAllStateNames NOTIFY allStateNamesChanged)
Q_PROPERTY(QStringList possibleTypes READ possibleTypes WRITE setPossibleTypes NOTIFY possibleTypesChanged)
Q_PROPERTY(int possibleTypeIndex READ possibleTypeIndex NOTIFY possibleTypeIndexChanged)
Q_PROPERTY(bool isBaseState READ isBaseState WRITE setIsBaseState NOTIFY isBaseStateChanged)
Q_PROPERTY(bool selectionChanged READ selectionChanged WRITE setSelectionChanged NOTIFY selectionChangedChanged)
Q_PROPERTY(int majorVersion READ majorVersion WRITE setMajorVersion NOTIFY majorVersionChanged)
Q_PROPERTY(bool hasAliasExport READ hasAliasExport NOTIFY hasAliasExportChanged)
Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged)
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged)
Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary WRITE setHasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
Q_PROPERTY(bool isQt6Project READ isQt6Project NOTIFY isQt6ProjectChanged)
Q_PROPERTY(QQmlPropertyMap *backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged)
public:
MaterialEditorContextObject(QQuickWidget *widget, QObject *parent = nullptr);
QUrl specificsUrl() const { return m_specificsUrl; }
QString specificQmlData() const {return m_specificQmlData; }
QQmlComponent *specificQmlComponent();
QString stateName() const { return m_stateName; }
QStringList allStateNames() const { return m_allStateNames; }
QStringList possibleTypes() const { return m_possibleTypes; }
int possibleTypeIndex() const { return m_possibleTypeIndex; }
bool isBaseState() const { return m_isBaseState; }
bool selectionChanged() const { return m_selectionChanged; }
QQmlPropertyMap *backendValues() const { return m_backendValues; }
Q_INVOKABLE QString convertColorToString(const QVariant &color);
Q_INVOKABLE QColor colorFromString(const QString &colorString);
Q_INVOKABLE void changeTypeName(const QString &typeName);
Q_INVOKABLE void insertKeyframe(const QString &propertyName);
Q_INVOKABLE void hideCursor();
Q_INVOKABLE void restoreCursor();
Q_INVOKABLE void holdCursorInPlace();
Q_INVOKABLE int devicePixelRatio();
Q_INVOKABLE QStringList allStatesForId(const QString &id);
Q_INVOKABLE bool isBlocked(const QString &propName) const;
Q_INVOKABLE void goIntoComponent();
Q_INVOKABLE QRect screenRect() const;
Q_INVOKABLE QPoint globalPos(const QPoint &point) const;
enum ToolBarAction {
ApplyToSelected = 0,
ApplyToSelectedAdd,
AddNewMaterial,
DeleteCurrentMaterial,
OpenMaterialBrowser
};
Q_ENUM(ToolBarAction)
int majorVersion() const;
void setMajorVersion(int majorVersion);
bool hasActiveTimeline() const;
void setHasActiveTimeline(bool b);
bool hasQuick3DImport() const;
void setHasQuick3DImport(bool b);
bool hasMaterialLibrary() const;
void setHasMaterialLibrary(bool b);
bool isQt6Project() const;
void setIsQt6Project(bool b);
bool hasModelSelection() const;
void setHasModelSelection(bool b);
bool hasAliasExport() const { return m_aliasExport; }
void setSelectedMaterial(const ModelNode &matNode);
void setSpecificsUrl(const QUrl &newSpecificsUrl);
void setSpecificQmlData(const QString &newSpecificQmlData);
void setStateName(const QString &newStateName);
void setAllStateNames(const QStringList &allStates);
void setPossibleTypes(const QStringList &types);
void setCurrentType(const QString &type);
void setIsBaseState(bool newIsBaseState);
void setSelectionChanged(bool newSelectionChanged);
void setBackendValues(QQmlPropertyMap *newBackendValues);
void setModel(QmlDesigner::Model *model);
void triggerSelectionChanged();
void setHasAliasExport(bool hasAliasExport);
signals:
void specificsUrlChanged();
void specificQmlDataChanged();
void specificQmlComponentChanged();
void stateNameChanged();
void allStateNamesChanged();
void possibleTypesChanged();
void possibleTypeIndexChanged();
void isBaseStateChanged();
void selectionChangedChanged();
void backendValuesChanged();
void majorVersionChanged();
void hasAliasExportChanged();
void hasActiveTimelineChanged();
void hasQuick3DImportChanged();
void hasMaterialLibraryChanged();
void hasModelSelectionChanged();
void isQt6ProjectChanged();
private:
void updatePossibleTypeIndex();
QUrl m_specificsUrl;
QString m_specificQmlData;
QQmlComponent *m_specificQmlComponent = nullptr;
QQuickWidget *m_quickWidget = nullptr;
QString m_stateName;
QStringList m_allStateNames;
QStringList m_possibleTypes;
int m_possibleTypeIndex = -1;
QString m_currentType;
int m_majorVersion = 1;
QQmlPropertyMap *m_backendValues = nullptr;
Model *m_model = nullptr;
QPoint m_lastPos;
bool m_isBaseState = false;
bool m_selectionChanged = false;
bool m_aliasExport = false;
bool m_hasActiveTimeline = false;
bool m_hasQuick3DImport = false;
bool m_hasMaterialLibrary = false;
bool m_hasModelSelection = false;
bool m_isQt6Project = false;
ModelNode m_selectedMaterial;
};
} // QmlDesigner

View File

@@ -1,47 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "materialeditordynamicpropertiesproxymodel.h"
#include <dynamicpropertiesmodel.h>
#include <materialeditorview.h>
namespace QmlDesigner {
MaterialEditorDynamicPropertiesProxyModel::MaterialEditorDynamicPropertiesProxyModel(QObject *parent)
: DynamicPropertiesProxyModel(parent)
{
if (MaterialEditorView::instance())
initModel(MaterialEditorView::instance()->dynamicPropertiesModel());
}
void MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType()
{
DynamicPropertiesProxyModel::registerDeclarativeType();
qmlRegisterType<MaterialEditorDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "MaterialEditorDynamicPropertiesModel");
}
} // namespace QmlDesigner

View File

@@ -1,41 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "dynamicpropertiesproxymodel.h"
namespace QmlDesigner {
class MaterialEditorDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
{
Q_OBJECT
public:
explicit MaterialEditorDynamicPropertiesProxyModel(QObject *parent = nullptr);
static void registerDeclarativeType();
};
} // namespace QmlDesigner

View File

@@ -1,82 +0,0 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "materialeditorimageprovider.h"
#include "materialeditorview.h"
#include <QImage>
#include <QTimer>
namespace QmlDesigner {
MaterialEditorImageProvider::MaterialEditorImageProvider(MaterialEditorView *materialEditorView)
: QQuickImageProvider(Pixmap)
, m_delayTimer(new QTimer(this))
{
m_delayTimer->setInterval(500);
m_delayTimer->setSingleShot(true);
m_delayTimer->callOnTimeout([this] {
if (m_previewPixmap.size() != m_requestedSize)
emit this->requestPreview(m_requestedSize);
});
connect(this,
&MaterialEditorImageProvider::requestPreview,
materialEditorView,
&MaterialEditorView::handlePreviewSizeChanged);
}
void MaterialEditorImageProvider::setPixmap(const QPixmap &pixmap)
{
m_previewPixmap = pixmap;
}
QPixmap MaterialEditorImageProvider::requestPixmap(const QString &id,
QSize *size,
const QSize &requestedSize)
{
static QPixmap defaultPreview = QPixmap::fromImage(
QImage(":/materialeditor/images/defaultmaterialpreview.png"));
QPixmap pixmap{150, 150};
if (id == "preview") {
if (!m_previewPixmap.isNull()) {
pixmap = m_previewPixmap;
setRequestedSize(requestedSize);
} else {
if (requestedSize.isEmpty())
pixmap = defaultPreview;
else
pixmap = defaultPreview.scaled(requestedSize, Qt::KeepAspectRatio);
}
} else {
qWarning() << __FUNCTION__ << "Unsupported image id:" << id;
pixmap.fill(Qt::red);
}
if (size)
*size = pixmap.size();
return pixmap;
}
/*!
* \internal
* \brief Sets the requested size. If the requested size is not the same as the
* size of the m_previewPixmap, it will ask \l {MaterialEditorView} to provide
* an image with the requested size
* The requests are delayed until the requested size is stable.
*/
void MaterialEditorImageProvider::setRequestedSize(const QSize &requestedSize)
{
if (requestedSize.isEmpty())
return;
m_requestedSize = requestedSize;
if (m_previewPixmap.size() != requestedSize)
m_delayTimer->start();
}
} // namespace QmlDesigner

View File

@@ -1,37 +0,0 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <QQuickImageProvider>
QT_BEGIN_NAMESPACE
class QTimer;
QT_END_NAMESPACE
namespace QmlDesigner {
class MaterialEditorView;
class MaterialEditorImageProvider : public QQuickImageProvider
{
Q_OBJECT
public:
explicit MaterialEditorImageProvider(MaterialEditorView *materialEditorView);
void setPixmap(const QPixmap &pixmap);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
signals:
void requestPreview(QSize);
private:
void setRequestedSize(const QSize &requestedSize);
QPixmap m_previewPixmap;
QSize m_requestedSize;
QTimer *m_delayTimer = nullptr; // Delays the preview requests
};
} // namespace QmlDesigner

View File

@@ -1,299 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "materialeditorqmlbackend.h"
#include "materialeditorcontextobject.h"
#include "materialeditorimageprovider.h"
#include "materialeditortransaction.h"
#include <bindingproperty.h>
#include <nodemetainfo.h>
#include <propertyeditorqmlbackend.h>
#include <propertyeditorvalue.h>
#include <qmldesignerconstants.h>
#include <qmlobjectnode.h>
#include <qmltimeline.h>
#include <variantproperty.h>
#include <coreplugin/icore.h>
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QQuickItem>
#include <QQuickWidget>
#include <QVector2D>
#include <QVector3D>
#include <QVector4D>
static QObject *variantToQObject(const QVariant &value)
{
if (value.typeId() == QMetaType::QObjectStar || value.typeId() > QMetaType::User)
return *(QObject **)value.constData();
return nullptr;
}
namespace QmlDesigner {
MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialEditor)
: m_quickWidget(Utils::makeUniqueObjectPtr<QQuickWidget>())
, m_materialEditorTransaction(std::make_unique<MaterialEditorTransaction>(materialEditor))
, m_contextObject(std::make_unique<MaterialEditorContextObject>(m_quickWidget.get()))
, m_materialEditorImageProvider(new MaterialEditorImageProvider(materialEditor))
{
m_quickWidget->setObjectName(Constants::OBJECT_NAME_MATERIAL_EDITOR);
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_quickWidget->engine()->addImportPath(PropertyEditorQmlBackend::propertyEditorResourcesPath() + "/imports");
m_quickWidget->engine()->addImageProvider("materialEditor", m_materialEditorImageProvider);
m_contextObject->setBackendValues(&m_backendValuesPropertyMap);
m_contextObject->setModel(materialEditor->model());
context()->setContextObject(m_contextObject.get());
context()->setContextProperty("hasMaterial", QVariant(false));
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
QObject::connect(&m_backendValuesPropertyMap, &DesignerPropertyMap::valueChanged,
materialEditor, &MaterialEditorView::changeValue);
}
MaterialEditorQmlBackend::~MaterialEditorQmlBackend()
{
}
PropertyName MaterialEditorQmlBackend::auxNamePostFix(PropertyNameView propertyName)
{
return propertyName + "__AUX";
}
void MaterialEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
PropertyNameView name,
const QVariant &value,
MaterialEditorView *materialEditor)
{
PropertyName propertyName(name.toByteArray());
propertyName.replace('.', '_');
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(backendValuesPropertyMap().value(QString::fromUtf8(propertyName))));
if (!valueObject) {
valueObject = new PropertyEditorValue(&backendValuesPropertyMap());
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
QObject::connect(valueObject, &PropertyEditorValue::expressionChanged, materialEditor, &MaterialEditorView::changeExpression);
QObject::connect(valueObject, &PropertyEditorValue::exportPropertyAsAliasRequested, materialEditor, &MaterialEditorView::exportPropertyAsAlias);
QObject::connect(valueObject, &PropertyEditorValue::removeAliasExportRequested, materialEditor, &MaterialEditorView::removeAliasExport);
backendValuesPropertyMap().insert(QString::fromUtf8(propertyName), QVariant::fromValue(valueObject));
}
valueObject->setName(name);
valueObject->setModelNode(qmlObjectNode);
if (qmlObjectNode.propertyAffectedByCurrentState(name) && !(qmlObjectNode.modelNode().property(name).isBindingProperty()))
valueObject->setValue(qmlObjectNode.modelValue(name));
else
valueObject->setValue(value);
if (propertyName != "id" && qmlObjectNode.currentState().isBaseState()
&& qmlObjectNode.modelNode().property(propertyName).isBindingProperty()) {
valueObject->setExpression(qmlObjectNode.modelNode().bindingProperty(propertyName).expression());
} else {
if (qmlObjectNode.hasBindingProperty(name))
valueObject->setExpression(qmlObjectNode.expression(name));
else
valueObject->setExpression(qmlObjectNode.instanceValue(name).toString());
}
}
void MaterialEditorQmlBackend::setValue(const QmlObjectNode &,
PropertyNameView name,
const QVariant &value)
{
// Vector*D values need to be split into their subcomponents
if (value.typeId() == QMetaType::QVector2D) {
const char *suffix[2] = {"_x", "_y"};
auto vecValue = value.value<QVector2D>();
for (int i = 0; i < 2; ++i) {
PropertyName subPropName(name.size() + 2, '\0');
subPropName.replace(0, name.size(), name);
subPropName.replace(name.size(), 2, suffix[i]);
auto propertyValue = qobject_cast<PropertyEditorValue *>(variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(subPropName))));
if (propertyValue)
propertyValue->setValue(QVariant(vecValue[i]));
}
} else if (value.typeId() == QMetaType::QVector3D) {
const char *suffix[3] = {"_x", "_y", "_z"};
auto vecValue = value.value<QVector3D>();
for (int i = 0; i < 3; ++i) {
PropertyName subPropName(name.size() + 2, '\0');
subPropName.replace(0, name.size(), name);
subPropName.replace(name.size(), 2, suffix[i]);
auto propertyValue = qobject_cast<PropertyEditorValue *>(variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(subPropName))));
if (propertyValue)
propertyValue->setValue(QVariant(vecValue[i]));
}
} else if (value.typeId() == QMetaType::QVector4D) {
const char *suffix[4] = {"_x", "_y", "_z", "_w"};
auto vecValue = value.value<QVector4D>();
for (int i = 0; i < 4; ++i) {
PropertyName subPropName(name.size() + 2, '\0');
subPropName.replace(0, name.size(), name);
subPropName.replace(name.size(), 2, suffix[i]);
auto propertyValue = qobject_cast<PropertyEditorValue *>(
variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(subPropName))));
if (propertyValue)
propertyValue->setValue(QVariant(vecValue[i]));
}
} else {
PropertyName propertyName = name.toByteArray();
propertyName.replace('.', '_');
auto propertyValue = qobject_cast<PropertyEditorValue *>(variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(propertyName))));
if (propertyValue)
propertyValue->setValue(value);
}
}
void MaterialEditorQmlBackend::setExpression(PropertyNameView propName, const QString &exp)
{
PropertyEditorValue *propertyValue = propertyValueForName(QString::fromUtf8(propName));
if (propertyValue)
propertyValue->setExpression(exp);
}
QQmlContext *MaterialEditorQmlBackend::context() const
{
return m_quickWidget->rootContext();
}
MaterialEditorContextObject *MaterialEditorQmlBackend::contextObject() const
{
return m_contextObject.get();
}
QQuickWidget *MaterialEditorQmlBackend::widget() const
{
return m_quickWidget.get();
}
void MaterialEditorQmlBackend::setSource(const QUrl &url)
{
m_quickWidget->setSource(url);
}
QmlAnchorBindingProxy &MaterialEditorQmlBackend::backendAnchorBinding()
{
return m_backendAnchorBinding;
}
void MaterialEditorQmlBackend::updateMaterialPreview(const QPixmap &pixmap)
{
m_materialEditorImageProvider->setPixmap(pixmap);
QMetaObject::invokeMethod(m_quickWidget->rootObject(), "refreshPreview");
}
void MaterialEditorQmlBackend::refreshBackendModel()
{
m_backendModelNode.refresh();
}
DesignerPropertyMap &MaterialEditorQmlBackend::backendValuesPropertyMap()
{
return m_backendValuesPropertyMap;
}
MaterialEditorTransaction *MaterialEditorQmlBackend::materialEditorTransaction() const
{
return m_materialEditorTransaction.get();
}
PropertyEditorValue *MaterialEditorQmlBackend::propertyValueForName(const QString &propertyName)
{
return qobject_cast<PropertyEditorValue *>(variantToQObject(backendValuesPropertyMap().value(propertyName)));
}
void MaterialEditorQmlBackend::setup(const QmlObjectNode &selectedMaterialNode, const QString &stateName,
const QUrl &qmlSpecificsFile, MaterialEditorView *materialEditor)
{
if (selectedMaterialNode.isValid()) {
m_contextObject->setModel(materialEditor->model());
for (const auto &property : selectedMaterialNode.modelNode().metaInfo().properties()) {
createPropertyEditorValue(selectedMaterialNode,
property.name(),
selectedMaterialNode.instanceValue(property.name()),
materialEditor);
}
// model node
m_backendModelNode.setup(selectedMaterialNode);
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
context()->setContextProperty("hasMaterial", QVariant(true));
// className
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
m_backendValuesPropertyMap.value(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)));
if (!valueObject)
valueObject = new PropertyEditorValue(&m_backendValuesPropertyMap);
valueObject->setName(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY);
valueObject->setModelNode(selectedMaterialNode.modelNode());
valueObject->setValue(m_backendModelNode.simplifiedTypeName());
QObject::connect(valueObject,
&PropertyEditorValue::valueChanged,
&backendValuesPropertyMap(),
&DesignerPropertyMap::valueChanged);
m_backendValuesPropertyMap.insert(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY,
QVariant::fromValue(valueObject));
// anchors
m_backendAnchorBinding.setup(selectedMaterialNode.modelNode());
context()->setContextProperties(QVector<QQmlContext::PropertyPair>{
{{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
{{"transaction"}, QVariant::fromValue(m_materialEditorTransaction.get())}});
contextObject()->setSpecificsUrl(qmlSpecificsFile);
contextObject()->setStateName(stateName);
QStringList stateNames = selectedMaterialNode.allStateNames();
stateNames.prepend("base state");
contextObject()->setAllStateNames(stateNames);
contextObject()->setSelectedMaterial(selectedMaterialNode);
contextObject()->setIsBaseState(selectedMaterialNode.isInBaseState());
contextObject()->setHasAliasExport(selectedMaterialNode.isAliasExported());
contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(selectedMaterialNode.view()));
contextObject()->setSelectionChanged(false);
#ifndef QDS_USE_PROJECTSTORAGE
NodeMetaInfo metaInfo = selectedMaterialNode.modelNode().metaInfo();
contextObject()->setMajorVersion(metaInfo.isValid() ? metaInfo.majorVersion() : -1);
#endif
} else {
context()->setContextProperty("hasMaterial", QVariant(false));
}
}
// static
QString MaterialEditorQmlBackend::materialEditorResourcesPath()
{
#ifdef SHARE_QML_PATH
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
return QLatin1String(SHARE_QML_PATH) + "/materialEditorQmlSources";
#endif
return Core::ICore::resourcePath("qmldesigner/materialEditorQmlSources").toUrlishString();
}
void MaterialEditorQmlBackend::emitSelectionToBeChanged()
{
m_backendModelNode.emitSelectionToBeChanged();
}
void MaterialEditorQmlBackend::emitSelectionChanged()
{
m_backendModelNode.emitSelectionChanged();
}
void MaterialEditorQmlBackend::setValueforAuxiliaryProperties(const QmlObjectNode &qmlObjectNode,
AuxiliaryDataKeyView key)
{
const PropertyName propertyName = auxNamePostFix(key.name.toByteArray());
setValue(qmlObjectNode, propertyName, qmlObjectNode.modelNode().auxiliaryDataWithDefault(key));
}
} // namespace QmlDesigner

View File

@@ -1,80 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "designerpropertymap.h"
#include "qmlanchorbindingproxy.h"
#include "qmlmodelnodeproxy.h"
#include <utils/uniqueobjectptr.h>
#include <nodemetainfo.h>
#include <memory>
class PropertyEditorValue;
QT_BEGIN_NAMESPACE
class QQuickWidget;
QT_END_NAMESPACE
namespace QmlDesigner {
class MaterialEditorContextObject;
class MaterialEditorImageProvider;
class MaterialEditorTransaction;
class MaterialEditorView;
class MaterialEditorQmlBackend
{
Q_DISABLE_COPY(MaterialEditorQmlBackend)
public:
MaterialEditorQmlBackend(MaterialEditorView *materialEditor);
~MaterialEditorQmlBackend();
void setup(const QmlObjectNode &selectedMaterialNode, const QString &stateName, const QUrl &qmlSpecificsFile,
MaterialEditorView *materialEditor);
void setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value);
void setExpression(PropertyNameView propName, const QString &exp);
QQmlContext *context() const;
MaterialEditorContextObject *contextObject() const;
QQuickWidget *widget() const;
void setSource(const QUrl &url);
QmlAnchorBindingProxy &backendAnchorBinding();
void updateMaterialPreview(const QPixmap &pixmap);
void refreshBackendModel();
DesignerPropertyMap &backendValuesPropertyMap();
MaterialEditorTransaction *materialEditorTransaction() const;
PropertyEditorValue *propertyValueForName(const QString &propertyName);
static QString materialEditorResourcesPath();
void emitSelectionToBeChanged();
void emitSelectionChanged();
void setValueforAuxiliaryProperties(const QmlObjectNode &qmlObjectNode, AuxiliaryDataKeyView key);
private:
void createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
PropertyNameView name,
const QVariant &value,
MaterialEditorView *materialEditor);
PropertyName auxNamePostFix(PropertyNameView propertyName);
// to avoid a crash while destructing DesignerPropertyMap in the QQmlData
// this needs be destructed after m_quickWidget->engine() is destructed
DesignerPropertyMap m_backendValuesPropertyMap;
Utils::UniqueObjectPtr<QQuickWidget> m_quickWidget = nullptr;
QmlAnchorBindingProxy m_backendAnchorBinding;
QmlModelNodeProxy m_backendModelNode;
std::unique_ptr<MaterialEditorTransaction> m_materialEditorTransaction;
std::unique_ptr<MaterialEditorContextObject> m_contextObject;
QPointer<MaterialEditorImageProvider> m_materialEditorImageProvider;
};
} // namespace QmlDesigner

View File

@@ -1,51 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "materialeditortransaction.h"
#include <QTimerEvent>
#include <QDebug>
namespace QmlDesigner {
MaterialEditorTransaction::MaterialEditorTransaction(QmlDesigner::MaterialEditorView *materialEditor)
: QObject(materialEditor),
m_materialEditor(materialEditor)
{
}
void MaterialEditorTransaction::start()
{
if (!m_materialEditor->model())
return;
if (m_rewriterTransaction.isValid())
m_rewriterTransaction.commit();
m_rewriterTransaction = m_materialEditor->beginRewriterTransaction(QByteArrayLiteral("MaterialEditorTransaction::start"));
m_timerId = startTimer(10000);
}
void MaterialEditorTransaction::end()
{
if (m_rewriterTransaction.isValid() && m_materialEditor->model()) {
killTimer(m_timerId);
m_rewriterTransaction.commit();
}
}
bool MaterialEditorTransaction::active() const
{
return m_rewriterTransaction.isValid();
}
void MaterialEditorTransaction::timerEvent(QTimerEvent *timerEvent)
{
if (timerEvent->timerId() != m_timerId)
return;
killTimer(timerEvent->timerId());
if (m_rewriterTransaction.isValid())
m_rewriterTransaction.commit();
}
} // namespace QmlDesigner

View File

@@ -1,32 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "materialeditorview.h"
#include "rewritertransaction.h"
namespace QmlDesigner {
class MaterialEditorTransaction : public QObject
{
Q_OBJECT
public:
MaterialEditorTransaction(MaterialEditorView *materialEditor);
Q_INVOKABLE void start();
Q_INVOKABLE void end();
Q_INVOKABLE bool active() const;
protected:
void timerEvent(QTimerEvent *event) override;
private:
MaterialEditorView *m_materialEditor = nullptr;
RewriterTransaction m_rewriterTransaction;
int m_timerId = -1;
};
} // namespace QmlDesigner

View File

@@ -1,154 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <abstractview.h>
#include <propertyeditorcomponentgenerator.h>
#include <QHash>
#include <QPointer>
#include <QSize>
QT_BEGIN_NAMESPACE
class QShortcut;
class QStackedWidget;
class QUrl;
QT_END_NAMESPACE
namespace QmlDesigner {
class DynamicPropertiesModel;
class ItemLibraryInfo;
class MaterialEditorQmlBackend;
class QmlObjectNode;
class SourcePathCacheInterface;
class MaterialEditorView : public AbstractView
{
Q_OBJECT
public:
MaterialEditorView(ExternalDependenciesInterface &externalDependencies);
~MaterialEditorView() override;
bool hasWidget() const override;
WidgetInfo widgetInfo() override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
void variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags propertyChange) override;
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags propertyChange) override;
void auxiliaryDataChanged(const ModelNode &node,
AuxiliaryDataKeyView key,
const QVariant &data) override;
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
void resetView();
void currentStateChanged(const ModelNode &node) override;
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId) override;
void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void nodeReparented(const ModelNode &node,
const NodeAbstractProperty &newPropertyParent,
const NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange) override;
void nodeIdChanged(const ModelNode &node, const QString &newId, const QString &oldId) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeRemoved(const ModelNode &removedNode,
const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange) override;
void dragStarted(QMimeData *mimeData) override;
void dragEnded() override;
void changeValue(const QString &name);
void changeExpression(const QString &name);
void exportPropertyAsAlias(const QString &name);
void removeAliasExport(const QString &name);
bool locked() const;
void currentTimelineChanged(const ModelNode &node) override;
void refreshMetaInfos(const TypeIds &deletedTypeIds) override;
DynamicPropertiesModel *dynamicPropertiesModel() const;
static MaterialEditorView *instance();
public slots:
void handleToolBarAction(int action);
void handlePreviewEnvChanged(const QString &envAndValue);
void handlePreviewModelChanged(const QString &modelStr);
void handlePreviewSizeChanged(const QSizeF &size);
protected:
void timerEvent(QTimerEvent *event) override;
void setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value);
bool eventFilter(QObject *obj, QEvent *event) override;
private:
void reloadQml();
void highlightSupportedProperties(bool highlight = true);
void requestPreviewRender();
void setupQmlBackend();
MaterialEditorQmlBackend *getQmlBackend(const QUrl &qmlFileUrl);
QUrl getPaneUrl();
void setupCurrentQmlBackend(const ModelNode &selectedNode,
const QUrl &qmlSpecificsFile,
const QString &specificQmlData);
void setupWidget();
void commitVariantValueToModel(PropertyNameView propertyName, const QVariant &value);
void commitAuxValueToModel(PropertyNameView propertyName, const QVariant &value);
void removePropertyFromModel(PropertyNameView propertyName);
void renameMaterial(ModelNode &material, const QString &newName);
void duplicateMaterial(const ModelNode &material);
bool noValidSelection() const;
void initPreviewData();
void updatePossibleTypes();
void asyncResetView();
ModelNode m_selectedMaterial;
QShortcut *m_updateShortcut = nullptr;
int m_timerId = 0;
QStackedWidget *m_stackedWidget = nullptr;
QHash<QString, MaterialEditorQmlBackend *> m_qmlBackendHash;
MaterialEditorQmlBackend *m_qmlBackEnd = nullptr;
PropertyComponentGenerator m_propertyComponentGenerator;
PropertyEditorComponentGenerator m_propertyEditorComponentGenerator{m_propertyComponentGenerator};
bool m_locked = false;
bool m_setupCompleted = false;
bool m_hasQuick3DImport = false;
bool m_hasMaterialRoot = false;
bool m_initializingPreviewData = false;
bool m_textureAboutToBeRemoved = false;
ModelNode m_newSelectedMaterial;
bool m_selectedMaterialChanged = false;
QSize m_previewSize;
QByteArray m_previewRequestId;
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
};
} // namespace QmlDesigner

View File

@@ -32,7 +32,7 @@ QPixmap InstanceImageProvider::requestPixmap(const QString &id, QSize *size, con
{ {
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
static const QPixmap defaultImage = QPixmap::fromImage( static const QPixmap defaultImage = QPixmap::fromImage(
QImage(":/materialeditor/images/defaultmaterialpreview.png")); QImage(":/propertyeditor/images/defaultmaterialpreview.png"));
if (id != "preview") if (id != "preview")
return defaultImage; return defaultImage;

View File

@@ -1,5 +1,5 @@
<RCC> <RCC>
<qresource prefix="/materialeditor"> <qresource prefix="/propertyeditor">
<file>images/defaultmaterialpreview.png</file> <file>images/defaultmaterialpreview.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -1160,6 +1160,18 @@ void PropertyEditorView::setActiveNodeToSelection()
setActiveNode(node); setActiveNode(node);
} }
void PropertyEditorView::forceSelection(const ModelNode &node)
{
if (node == activeNode())
return;
if (m_isSelectionLocked)
setActiveNode(node);
ModelNode(node).selectNode();
resetView();
}
bool PropertyEditorView::hasWidget() const bool PropertyEditorView::hasWidget() const
{ {
return true; return true;
@@ -1260,6 +1272,17 @@ void PropertyEditorView::importsChanged(const Imports &addedImports, const Impor
m_qmlBackEndForCurrentType->contextObject()->setHasQuick3DImport(true); m_qmlBackEndForCurrentType->contextObject()->setHasQuick3DImport(true);
} }
void PropertyEditorView::customNotification([[maybe_unused]] const AbstractView *view,
const QString &identifier,
const QList<ModelNode> &nodeList,
[[maybe_unused]] const QList<QVariant> &data)
{
if (identifier == "force_editing_node") {
if (!nodeList.isEmpty())
forceSelection(nodeList.first());
}
}
void PropertyEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, void PropertyEditorView::modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap, const QPixmap &pixmap,
const QByteArray &requestId) const QByteArray &requestId)

View File

@@ -83,6 +83,10 @@ public:
const QByteArray &requestId) override; const QByteArray &requestId) override;
void importsChanged(const Imports &addedImports, const Imports &removedImports) override; void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void customNotification(const AbstractView *view,
const QString &identifier,
const QList<ModelNode> &nodeList,
const QList<QVariant> &data) override;
void dragStarted(QMimeData *mimeData) override; void dragStarted(QMimeData *mimeData) override;
void dragEnded() override; void dragEnded() override;
@@ -123,6 +127,7 @@ private: //functions
void select(); void select();
void setActiveNodeToSelection(); void setActiveNodeToSelection();
void forceSelection(const ModelNode &node);
void delayedResetView(); void delayedResetView();
void setupQmlBackend(); void setupQmlBackend();

View File

@@ -19,7 +19,8 @@ void TextureEditorTransaction::start()
return; return;
if (m_rewriterTransaction.isValid()) if (m_rewriterTransaction.isValid())
m_rewriterTransaction.commit(); m_rewriterTransaction.commit();
m_rewriterTransaction = m_textureEditor->beginRewriterTransaction(QByteArrayLiteral("MaterialEditorTransaction::start")); m_rewriterTransaction = m_textureEditor->beginRewriterTransaction(
QByteArrayLiteral("TextureEditorTransaction::start"));
m_timerId = startTimer(10000); m_timerId = startTimer(10000);
} }

View File

@@ -559,9 +559,8 @@ void TextureEditorView::commitAuxValueToModel(PropertyNameView propertyName, con
void TextureEditorView::removePropertyFromModel(PropertyNameView propertyName) void TextureEditorView::removePropertyFromModel(PropertyNameView propertyName)
{ {
m_locked = true; m_locked = true;
executeInTransaction("MaterialEditorView:removePropertyFromModel", [&] { executeInTransaction(__FUNCTION__,
QmlObjectNode(m_selectedTexture).removeProperty(propertyName); [&] { QmlObjectNode(m_selectedTexture).removeProperty(propertyName); });
});
m_locked = false; m_locked = false;
} }

View File

@@ -512,8 +512,12 @@ void DesignModeWidget::setup()
static bool isMcuDisabledView(const QString viewId) static bool isMcuDisabledView(const QString viewId)
{ {
static const QStringList mcuDisabledViews = {"Editor3D", "MaterialEditor", "MaterialBrowser", static const QStringList mcuDisabledViews = {
"TextureEditor", "EffectComposer"}; "Editor3D",
"MaterialBrowser",
"TextureEditor",
"EffectComposer",
};
return mcuDisabledViews.contains(viewId); return mcuDisabledViews.contains(viewId);
} }

View File

@@ -124,7 +124,6 @@ inline constexpr char EVENT_EFFECTCOMPOSER_TIME[] = "effectComposerTime";
inline constexpr char EVENT_ITEMLIBRARY_TIME[] = "itemLibrary"; inline constexpr char EVENT_ITEMLIBRARY_TIME[] = "itemLibrary";
inline constexpr char EVENT_TRANSLATIONVIEW_TIME[] = "translationView"; inline constexpr char EVENT_TRANSLATIONVIEW_TIME[] = "translationView";
inline constexpr char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView"; inline constexpr char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView";
inline constexpr char EVENT_MATERIALEDITOR_TIME[] = "materialEditor";
inline constexpr char EVENT_MATERIALBROWSER_TIME[] = "materialBrowser"; inline constexpr char EVENT_MATERIALBROWSER_TIME[] = "materialBrowser";
inline constexpr char EVENT_CONTENTLIBRARY_TIME[] = "contentLibrary"; inline constexpr char EVENT_CONTENTLIBRARY_TIME[] = "contentLibrary";
inline constexpr char EVENT_INSIGHT_TIME[] = "insight"; inline constexpr char EVENT_INSIGHT_TIME[] = "insight";
@@ -177,7 +176,6 @@ inline constexpr char OBJECT_NAME_COMPONENT_LIBRARY[] = "QQuickWidgetComponentLi
inline constexpr char OBJECT_NAME_DESIGN_SYSTEM[] = "QQuickWidgetDesignSystem"; inline constexpr char OBJECT_NAME_DESIGN_SYSTEM[] = "QQuickWidgetDesignSystem";
inline constexpr char OBJECT_NAME_EFFECT_COMPOSER[] = "QQuickWidgetEffectComposer"; inline constexpr char OBJECT_NAME_EFFECT_COMPOSER[] = "QQuickWidgetEffectComposer";
inline constexpr char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser"; inline constexpr char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser";
inline constexpr char OBJECT_NAME_MATERIAL_EDITOR[] = "QQuickWidgetMaterialEditor";
inline constexpr char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor"; inline constexpr char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";
inline constexpr char OBJECT_NAME_STATES_EDITOR[] = "QQuickWidgetStatesEditor"; inline constexpr char OBJECT_NAME_STATES_EDITOR[] = "QQuickWidgetStatesEditor";
inline constexpr char OBJECT_NAME_TEXTURE_EDITOR[] = "QQuickWidgetTextureEditor"; inline constexpr char OBJECT_NAME_TEXTURE_EDITOR[] = "QQuickWidgetTextureEditor";