diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc
index bbe9a910db6..d4127574a69 100644
--- a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc
+++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc
@@ -16,6 +16,8 @@
mockfiles/images/static_floor.png
mockfiles/images/spot.png
mockfiles/images/spot@2x.png
+ mockfiles/images/preview_landscape.hdr
+ mockfiles/images/preview_studio.hdr
mockfiles/qt5/AdjustableArrow.qml
mockfiles/qt5/AreaLightHandle.qml
mockfiles/qt5/Arrow.qml
diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc
index 05459423349..bb29d683a07 100644
--- a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc
+++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc
@@ -18,6 +18,8 @@
mockfiles/images/floor_tex.png
mockfiles/images/spot.png
mockfiles/images/spot@2x.png
+ mockfiles/images/preview_landscape.hdr
+ mockfiles/images/preview_studio.hdr
mockfiles/qt6/AdjustableArrow.qml
mockfiles/qt6/AreaLightHandle.qml
mockfiles/qt6/Arrow.qml
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_landscape.hdr b/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_landscape.hdr
new file mode 100644
index 00000000000..2c6b4372d47
Binary files /dev/null and b/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_landscape.hdr differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_studio.hdr b/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_studio.hdr
new file mode 100644
index 00000000000..8ab060c1f45
Binary files /dev/null and b/share/qtcreator/qml/qmlpuppet/mockfiles/images/preview_studio.hdr differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml
index 9fee06e0ad1..067e34928b7 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml
@@ -29,8 +29,12 @@ View3D {
id: root
anchors.fill: parent
environment: sceneEnv
+ camera: envMode === "SkyBox" && envValue === "preview_studio" ? studioCamera : defaultCamera
property Material previewMaterial
+ property string envMode
+ property string envValue
+ property string modelSrc: "#Sphere"
function fitToViewPort(closeUp)
{
@@ -41,28 +45,59 @@ View3D {
id: sceneEnv
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.High
+ backgroundMode: envMode === "Color" ? SceneEnvironment.Color
+ : envMode === "SkyBox" ? SceneEnvironment.SkyBox
+ : SceneEnvironment.Transparent
+ clearColor: envMode === "Color" ? envValue : "#000000"
+ lightProbe: envMode === "SkyBox" ? skyBoxTex : null
+
+ Texture {
+ id: skyBoxTex
+ source: envMode === "SkyBox" ? "../images/" + envValue + ".hdr"
+ : ""
+ }
}
Node {
DirectionalLight {
eulerRotation.x: -26
- eulerRotation.y: -57
+ eulerRotation.y: modelSrc === "#Cube" ? -10 : -50
+ brightness: envMode !== "SkyBox" ? 100 : 0
}
PerspectiveCamera {
- y: 125.331
- z: 120
- eulerRotation.x: -31
+ id: defaultCamera
+ y: 70
+ z: 200
+ eulerRotation.x: -5.71
clipNear: 1
clipFar: 1000
}
- Model {
- id: model
+ PerspectiveCamera {
+ id: studioCamera
+ y: 232
+ z: 85
+ eulerRotation.x: -64.98
+ clipNear: 1
+ clipFar: 1000
+ }
+ Node {
+ rotation: root.camera.rotation
y: 50
- source: "#Sphere"
- materials: previewMaterial
+ Node {
+ y: modelSrc === "#Cone" ? -40 : 10
+ eulerRotation.x: 35
+ Model {
+ id: model
+ source: modelSrc ? modelSrc : "#Sphere"
+ eulerRotation.y: 45
+ materials: previewMaterial
+ scale: !modelSrc || modelSrc === "#Sphere"
+ ? Qt.vector3d(1.7, 1.7, 1.7) : Qt.vector3d(1.2, 1.2, 1.2)
+ }
+ }
}
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml
index 70b9dbc4d0e..d32a1ea915d 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml
@@ -50,25 +50,28 @@ Item {
view.destroy();
}
- function createViewForObject(obj)
+ function createViewForObject(obj, env, envValue, model)
{
if (obj instanceof Material)
- createViewForMaterial(obj);
+ createViewForMaterial(obj, env, envValue, model);
else if (obj instanceof Model)
createViewForModel(obj);
else if (obj instanceof Node)
createViewForNode(obj);
}
- function createViewForMaterial(material)
+ function createViewForMaterial(material, env, envValue, model)
{
if (!materialViewComponent)
materialViewComponent = Qt.createComponent("MaterialNodeView.qml");
// Always recreate the view to ensure material is up to date
- if (materialViewComponent.status === Component.Ready)
- view = materialViewComponent.createObject(viewRect, {"previewMaterial": material});
-
+ if (materialViewComponent.status === Component.Ready) {
+ view = materialViewComponent.createObject(viewRect, {"previewMaterial": material,
+ "envMode": env,
+ "envValue": envValue,
+ "modelSrc": model});
+ }
previewObject = material;
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml
index 94051d5f6e6..12fdd3048eb 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml
@@ -29,8 +29,12 @@ View3D {
id: root
anchors.fill: parent
environment: sceneEnv
+ camera: envMode === "SkyBox" && envValue === "preview_studio" ? studioCamera : defaultCamera
property Material previewMaterial
+ property string envMode
+ property string envValue
+ property string modelSrc: "#Sphere"
function fitToViewPort(closeUp)
{
@@ -41,30 +45,79 @@ View3D {
id: sceneEnv
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.High
+ backgroundMode: envMode === "Color" ? SceneEnvironment.Color
+ : envMode === "SkyBox" ? SceneEnvironment.SkyBox
+ : SceneEnvironment.Transparent
+ clearColor: envMode === "Color" ? envValue : "#000000"
+ lightProbe: envMode === "SkyBox" ? skyBoxTex : null
+
+ Texture {
+ id: skyBoxTex
+ source: envMode === "SkyBox" ? "../images/" + envValue + ".hdr"
+ : ""
+ }
}
Node {
DirectionalLight {
eulerRotation.x: -26
- eulerRotation.y: -57
+ eulerRotation.y: modelSrc === "#Cube" ? -10 : -50
+ brightness: envMode !== "SkyBox" ? 1 : 0
}
PerspectiveCamera {
- y: 125.331
- z: 120
- eulerRotation.x: -31
+ id: defaultCamera
+ y: 70
+ z: 200
+ eulerRotation.x: -5.71
clipNear: 1
clipFar: 1000
}
- Model {
- id: model
- readonly property bool _edit3dLocked: true // Make this non-pickable
-
- y: 50
- source: "#Sphere"
- materials: previewMaterial
+ PerspectiveCamera {
+ id: studioCamera
+ y: 232
+ z: 85
+ eulerRotation.x: -64.98
+ clipNear: 1
+ clipFar: 1000
}
+ Node {
+ rotation: root.camera.rotation
+ y: 50
+ Node {
+ y: modelSrc === "#Cone" ? -40 : 10
+ eulerRotation.x: 35
+ Model {
+ id: model
+ readonly property bool _edit3dLocked: true // Make this non-pickable
+ source: modelSrc ? modelSrc : "#Sphere"
+ eulerRotation.y: 45
+ materials: previewMaterial
+ scale: !modelSrc || modelSrc === "#Sphere"
+ ? Qt.vector3d(1.7, 1.7, 1.7) : Qt.vector3d(1.2, 1.2, 1.2)
+ }
+ }
+ }
+ Model {
+ id: floorModel
+ source: "#Rectangle"
+ scale.y: 8
+ scale.x: 8
+ eulerRotation.x: -60
+ visible: !envMode || envMode === "Default"
+ materials: floorMaterial
+ DefaultMaterial {
+ id: floorMaterial
+ diffuseMap: floorTex
+ Texture {
+ id: floorTex
+ source: "../images/floor_tex.png"
+ scaleU: floorModel.scale.x
+ scaleV: floorModel.scale.y
+ }
+ }
+ }
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml
index 031d01d65fb..e409e35aee0 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml
@@ -50,25 +50,31 @@ Item {
view.destroy();
}
- function createViewForObject(obj)
+ function createViewForObject(obj, env, envValue, model)
{
+ backgroundView3d.visible = true;
if (obj instanceof Material)
- createViewForMaterial(obj);
+ createViewForMaterial(obj, env, envValue, model);
else if (obj instanceof Model)
createViewForModel(obj);
else if (obj instanceof Node)
createViewForNode(obj);
}
- function createViewForMaterial(material)
+ function createViewForMaterial(material, env, envValue, model)
{
if (!materialViewComponent)
materialViewComponent = Qt.createComponent("MaterialNodeView.qml");
// Always recreate the view to ensure material is up to date
- if (materialViewComponent.status === Component.Ready)
- view = materialViewComponent.createObject(viewRect, {"previewMaterial": material});
-
+ if (materialViewComponent.status === Component.Ready) {
+ view = materialViewComponent.createObject(viewRect, {"previewMaterial": material,
+ "envMode": env,
+ "envValue": envValue,
+ "modelSrc": model});
+ }
+ // Floor must be in same view as material so material can reflect it, so hide it in this one
+ backgroundView3d.visible = false;
previewObject = material;
}
@@ -129,6 +135,7 @@ Item {
// Use View3D instead of static image to make background look good on all resolutions
View3D {
+ id: backgroundView3d
anchors.fill: parent
environment: sceneEnv
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index 516213588c4..365aca3cd3b 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -339,6 +339,31 @@ void Qt5InformationNodeInstanceServer::resolveImportSupport()
#endif
}
+void Qt5InformationNodeInstanceServer::updateMaterialPreviewData(const QVector &valueChanges)
+{
+ const PropertyName matPrevPrefix("matPrev");
+ qint32 materialLibraryId = -1;
+ for (const auto &container : valueChanges) {
+ if (container.name().startsWith(matPrevPrefix)) {
+ if (!hasInstanceForId(container.instanceId()))
+ continue;
+ if (materialLibraryId < 0) {
+ ServerNodeInstance instance = instanceForId(container.instanceId());
+ if (instance.id() == "__materialLibrary__")
+ materialLibraryId = container.instanceId();
+ }
+ if (container.instanceId() == materialLibraryId) {
+ if (container.name() == "matPrevEnv")
+ m_materialPreviewData.env = container.value().toString();
+ else if (container.name() == "matPrevEnvValue")
+ m_materialPreviewData.envValue = container.value().toString();
+ else if (container.name() == "matPrevModel")
+ m_materialPreviewData.model = container.value().toString();
+ }
+ }
+ }
+}
+
void Qt5InformationNodeInstanceServer::updateRotationBlocks(const QVector &valueChanges)
{
#ifdef QUICK3D_MODULE
@@ -1184,7 +1209,10 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView(const Reques
} else {
QMetaObject::invokeMethod(
m_modelNode3DImageViewData.rootItem, "createViewForObject",
- Q_ARG(QVariant, objectToVariant(instanceObj)));
+ Q_ARG(QVariant, objectToVariant(instanceObj)),
+ Q_ARG(QVariant, m_materialPreviewData.env),
+ Q_ARG(QVariant, m_materialPreviewData.envValue),
+ Q_ARG(QVariant, m_materialPreviewData.model));
}
// Need to render twice, first render updates spatial nodes
@@ -2027,6 +2055,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
if (ViewConfig::isQuick3DMode()) {
setup3DEditView(instanceList, command);
updateRotationBlocks(command.auxiliaryChanges);
+ updateMaterialPreviewData(command.auxiliaryChanges);
}
QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout,
@@ -2431,6 +2460,7 @@ void Qt5InformationNodeInstanceServer::requestModelNodePreviewImage(const Reques
void Qt5InformationNodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &command)
{
updateRotationBlocks(command.auxiliaryChanges);
+ updateMaterialPreviewData(command.auxiliaryChanges);
Qt5NodeInstanceServer::changeAuxiliaryValues(command);
render3DEditView();
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
index f3448de4add..ea104442a6e 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
@@ -145,6 +145,7 @@ private:
void updateLockedAndHiddenStates(const QSet &instances);
void handleInputEvents();
void resolveImportSupport();
+ void updateMaterialPreviewData(const QVector &valueChanges);
void updateRotationBlocks(const QVector &valueChanges);
void removeRotationBlocks(const QVector &instanceIds);
@@ -191,6 +192,13 @@ private:
QObject *m_3dHelper = nullptr;
int m_need3DEditViewRender = 0;
QSet m_dynamicObjectConstructors;
+
+ struct PreviewData {
+ QString env;
+ QString envValue;
+ QString model;
+ };
+ PreviewData m_materialPreviewData;
};
} // namespace QmlDesigner
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml
index a9e272b6d51..50b5ce6a7e8 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml
@@ -33,6 +33,12 @@ PropertyEditorPane {
id: root
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
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
index cfc037bc24f..67b5042c492 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
@@ -31,6 +31,8 @@ PropertyEditorPane {
id: itemPane
signal toolBarAction(int action)
+ signal previewEnvChanged(string env)
+ signal previewModelChanged(string model)
// invoked from C++ to refresh material preview image
function refreshPreview()
@@ -38,10 +40,25 @@ PropertyEditorPane {
topSection.refreshPreview()
}
+ // Called also from C++ to close context menu on focus out
+ function closeContextMenu()
+ {
+ topSection.closeContextMenu()
+ }
+
+ // Called from C++ to initialize preview menu checkmarks
+ function initPreviewData(env, model)
+ {
+ topSection.previewEnv = env;
+ topSection.previewModel = model
+ }
+
MaterialEditorTopSection {
id: topSection
onToolBarAction: (action) => itemPane.toolBarAction(action)
+ onPreviewEnvChanged: itemPane.previewEnvChanged(previewEnv)
+ onPreviewModelChanged: itemPane.previewModelChanged(previewModel)
}
Item { width: 1; height: 10 }
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
index 2e21d5814ac..0a5bcfab0d9 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
@@ -29,6 +29,7 @@ import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0
import QtQuick.Templates 2.15 as T
import HelperWidgets 2.0
+import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Column {
@@ -36,12 +37,22 @@ Column {
signal toolBarAction(int action)
+ property string previewEnv
+ property string previewModel
+
function refreshPreview()
{
materialPreview.source = ""
materialPreview.source = "image://materialEditor/preview"
}
+ // Called from C++ to close context menu on focus out
+ function closeContextMenu()
+ {
+ modelMenu.close()
+ envMenu.close()
+ }
+
anchors.left: parent.left
anchors.right: parent.right
@@ -53,20 +64,135 @@ Column {
Item { width: 1; height: 10 } // spacer
- Rectangle {
- width: 152
- height: 152
- color: "#000000"
- anchors.horizontalCenter: parent.horizontalCenter
- Image {
- id: materialPreview
- width: 150
- height: 150
- anchors.centerIn: parent
- source: "image://materialEditor/preview"
- cache: false
+ 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
+ closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
+
+ ListModel {
+ id: envMenuModel
+ ListElement {
+ envName: qsTr("Default")
+ envStr: "Default"
+ }
+ ListElement {
+ envName: qsTr("Color")
+ envStr: "Color"
+ }
+ ListElement {
+ envName: qsTr("Studio")
+ envStr: "SkyBox=preview_studio"
+ }
+ ListElement {
+ envName: qsTr("Landscape")
+ envStr: "SkyBox=preview_landscape"
+ }
+ }
+
+ Repeater {
+ model: envMenuModel
+ StudioControls.MenuItemWithIcon {
+ text: envName
+ onClicked: {
+ // Force property change notifications to keep check mark when reselected
+ root.previewEnv = ""
+ root.previewEnv = envStr
+ }
+ checkable: true
+ checked: root.previewEnv === envStr
+ }
+ }
+ }
+
+ Item {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: parent.width
+ height: previewRect.height
+
+ Rectangle {
+ id: previewRect
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: 152
+ height: 152
+ color: "#000000"
+
+ Image {
+ id: materialPreview
+ width: 150
+ height: 150
+ anchors.centerIn: parent
+ source: "image://materialEditor/preview"
+ cache: false
+ }
+ }
+
+ Item {
+ id: previewOptions
+ width: 40
+ height: previewRect.height
+ anchors.top: previewRect.top
+ anchors.left: previewRect.right
+
+ Column {
+ anchors.horizontalCenter: parent.horizontalCenter
+ IconButton {
+ icon: StudioTheme.Constants.materialPreviewEnvironment
+ normalColor: "transparent"
+ iconSize: StudioTheme.Values.bigIconFontSize
+ buttonSize: previewOptions.width
+ tooltip: qsTr("Select preview environment.")
+ onClicked: envMenu.popup()
+ }
+ IconButton {
+ icon: StudioTheme.Constants.materialPreviewModel
+ normalColor: "transparent"
+ iconSize: StudioTheme.Values.bigIconFontSize
+ buttonSize: previewOptions.width
+ tooltip: qsTr("Select preview model.")
+ onClicked: modelMenu.popup()
+ }
+ }
+ }
+
}
Section {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
index 5972e56e04c..46b3679198c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
@@ -122,72 +122,74 @@ QtObject {
readonly property string listView: "\u0075"
readonly property string lockOff: "\u0076"
readonly property string lockOn: "\u0077"
- readonly property string mergeCells: "\u0078"
- readonly property string minus: "\u0079"
- readonly property string mirror: "\u007A"
- readonly property string newMaterial: "\u007B"
- readonly property string openMaterialBrowser: "\u007C"
- readonly property string orientation: "\u007D"
- readonly property string paddingEdge: "\u007E"
- readonly property string paddingFrame: "\u007F"
- readonly property string pasteStyle: "\u0080"
- readonly property string pause: "\u0081"
- readonly property string pin: "\u0082"
- readonly property string play: "\u0083"
- readonly property string plus: "\u0084"
- readonly property string promote: "\u0085"
- readonly property string readOnly: "\u0086"
- readonly property string redo: "\u0087"
- readonly property string rotationFill: "\u0088"
- readonly property string rotationOutline: "\u0089"
- readonly property string search: "\u008A"
- readonly property string sectionToggle: "\u008B"
- readonly property string splitColumns: "\u008C"
- readonly property string splitRows: "\u008D"
- readonly property string startNode: "\u008E"
- readonly property string testIcon: "\u008F"
- readonly property string textAlignBottom: "\u0090"
- readonly property string textAlignCenter: "\u0091"
- readonly property string textAlignJustified: "\u0092"
- readonly property string textAlignLeft: "\u0093"
- readonly property string textAlignMiddle: "\u0094"
- readonly property string textAlignRight: "\u0095"
- readonly property string textAlignTop: "\u0096"
- readonly property string textBulletList: "\u0097"
- readonly property string textFullJustification: "\u0098"
- readonly property string textNumberedList: "\u0099"
- readonly property string tickIcon: "\u009A"
- readonly property string translationCreateFiles: "\u009B"
- readonly property string translationCreateReport: "\u009D"
- readonly property string translationExport: "\u009E"
- readonly property string translationImport: "\u009F"
- readonly property string translationSelectLanguages: "\u00A0"
- readonly property string translationTest: "\u00A1"
- readonly property string transparent: "\u00A2"
- readonly property string triState: "\u00A3"
- readonly property string triangleArcA: "\u00A4"
- readonly property string triangleArcB: "\u00A5"
- readonly property string triangleCornerA: "\u00A6"
- readonly property string triangleCornerB: "\u00A7"
- readonly property string unLinked: "\u00A8"
- readonly property string undo: "\u00A9"
- readonly property string unpin: "\u00AA"
- readonly property string upDownIcon: "\u00AB"
- readonly property string upDownSquare2: "\u00AC"
- readonly property string visibilityOff: "\u00AE"
- readonly property string visibilityOn: "\u00AF"
- readonly property string wildcard: "\u00B0"
- readonly property string wizardsAutomotive: "\u00B1"
- readonly property string wizardsDesktop: "\u00B2"
- readonly property string wizardsGeneric: "\u00B3"
- readonly property string wizardsMcuEmpty: "\u00B4"
- readonly property string wizardsMcuGraph: "\u00B5"
- readonly property string wizardsMobile: "\u00B6"
- readonly property string wizardsUnknown: "\u00B7"
- readonly property string zoomAll: "\u00B8"
- readonly property string zoomIn: "\u00B9"
- readonly property string zoomOut: "\u00BA"
- readonly property string zoomSelection: "\u00BB"
+ readonly property string materialPreviewEnvironment: "\u0078"
+ readonly property string materialPreviewModel: "\u0079"
+ readonly property string mergeCells: "\u007A"
+ readonly property string minus: "\u007B"
+ readonly property string mirror: "\u007C"
+ readonly property string newMaterial: "\u007D"
+ readonly property string openMaterialBrowser: "\u007E"
+ readonly property string orientation: "\u007F"
+ readonly property string paddingEdge: "\u0080"
+ readonly property string paddingFrame: "\u0081"
+ readonly property string pasteStyle: "\u0082"
+ readonly property string pause: "\u0083"
+ readonly property string pin: "\u0084"
+ readonly property string play: "\u0085"
+ readonly property string plus: "\u0086"
+ readonly property string promote: "\u0087"
+ readonly property string readOnly: "\u0088"
+ readonly property string redo: "\u0089"
+ readonly property string rotationFill: "\u008A"
+ readonly property string rotationOutline: "\u008B"
+ readonly property string search: "\u008C"
+ readonly property string sectionToggle: "\u008D"
+ readonly property string splitColumns: "\u008E"
+ readonly property string splitRows: "\u008F"
+ readonly property string startNode: "\u0090"
+ readonly property string testIcon: "\u0091"
+ readonly property string textAlignBottom: "\u0092"
+ readonly property string textAlignCenter: "\u0093"
+ readonly property string textAlignJustified: "\u0094"
+ readonly property string textAlignLeft: "\u0095"
+ readonly property string textAlignMiddle: "\u0096"
+ readonly property string textAlignRight: "\u0097"
+ readonly property string textAlignTop: "\u0098"
+ readonly property string textBulletList: "\u0099"
+ readonly property string textFullJustification: "\u009A"
+ readonly property string textNumberedList: "\u009B"
+ readonly property string tickIcon: "\u009D"
+ readonly property string translationCreateFiles: "\u009E"
+ readonly property string translationCreateReport: "\u009F"
+ readonly property string translationExport: "\u00A0"
+ readonly property string translationImport: "\u00A1"
+ readonly property string translationSelectLanguages: "\u00A2"
+ readonly property string translationTest: "\u00A3"
+ readonly property string transparent: "\u00A4"
+ readonly property string triState: "\u00A5"
+ readonly property string triangleArcA: "\u00A6"
+ readonly property string triangleArcB: "\u00A7"
+ readonly property string triangleCornerA: "\u00A8"
+ readonly property string triangleCornerB: "\u00A9"
+ readonly property string unLinked: "\u00AA"
+ readonly property string undo: "\u00AB"
+ readonly property string unpin: "\u00AC"
+ readonly property string upDownIcon: "\u00AE"
+ readonly property string upDownSquare2: "\u00AF"
+ readonly property string visibilityOff: "\u00B0"
+ readonly property string visibilityOn: "\u00B1"
+ readonly property string wildcard: "\u00B2"
+ readonly property string wizardsAutomotive: "\u00B3"
+ readonly property string wizardsDesktop: "\u00B4"
+ readonly property string wizardsGeneric: "\u00B5"
+ readonly property string wizardsMcuEmpty: "\u00B6"
+ readonly property string wizardsMcuGraph: "\u00B7"
+ readonly property string wizardsMobile: "\u00B8"
+ readonly property string wizardsUnknown: "\u00B9"
+ readonly property string zoomAll: "\u00BA"
+ readonly property string zoomIn: "\u00BB"
+ readonly property string zoomOut: "\u00BC"
+ readonly property string zoomSelection: "\u00BD"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
index cefd1d7d866..934c22110e5 100644
Binary files a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf and b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf differ
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index d8853cc7906..7707cdeb12b 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -130,6 +130,8 @@ public:
listView,
lockOff,
lockOn,
+ materialPreviewEnvironment,
+ materialPreviewModel,
mergeCells,
minus,
mirror,
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
index 7684e4fe1bc..ae04c193ca9 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -284,6 +284,10 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt
int idx = m_widget->materialBrowserModel()->materialIndex(nodeList.first());
if (idx != -1)
m_widget->materialBrowserModel()->selectMaterial(idx);
+ } else if (identifier == "refresh_material_browser") {
+ QTimer::singleShot(0, this, [this]() {
+ refreshModel(true);
+ });
}
}
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index 974435b5104..c0b766648b6 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -62,6 +62,7 @@
#include
#include
#include
+#include
namespace QmlDesigner {
@@ -442,6 +443,90 @@ void MaterialEditorView::handleToolBarAction(int action)
}
}
+void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue)
+{
+ if (envAndValue.isEmpty())
+ return;
+
+ QTC_ASSERT(m_hasQuick3DImport, return);
+ QTC_ASSERT(model(), return);
+ QTC_ASSERT(model()->nodeInstanceView(), return);
+
+ QStringList parts = envAndValue.split('=');
+ QString env = parts[0];
+ QString value;
+ if (parts.size() > 1)
+ value = parts[1];
+
+ PropertyName matPrevEnvAuxProp("matPrevEnv");
+ PropertyName matPrevEnvValueAuxProp("matPrevEnvValue");
+
+ auto renderPreviews = [=](const QString &auxEnv, const QString &auxValue) {
+ ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
+ QTC_ASSERT(matLib.isValid(), return);
+ matLib.setAuxiliaryData(matPrevEnvAuxProp, auxEnv);
+ matLib.setAuxiliaryData(matPrevEnvValueAuxProp, auxValue);
+ QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender);
+ emitCustomNotification("refresh_material_browser", {});
+ };
+
+ if (env == "Color") {
+ m_colorDialog.clear();
+
+ ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
+ QTC_ASSERT(matLib.isValid(), return);
+ // Store color to separate property to persist selection over non-color env changes
+ PropertyName colorAuxProp("matPrevColor");
+ QString oldColor = matLib.auxiliaryData(colorAuxProp).toString();
+ QString oldEnv = matLib.auxiliaryData(matPrevEnvAuxProp).toString();
+ QString oldValue = matLib.auxiliaryData(matPrevEnvValueAuxProp).toString();
+
+ m_colorDialog = new QColorDialog(Core::ICore::dialogParent());
+ m_colorDialog->setModal(true);
+ m_colorDialog->setAttribute(Qt::WA_DeleteOnClose);
+ m_colorDialog->setCurrentColor(QColor(oldColor));
+ m_colorDialog->show();
+
+ QObject::connect(m_colorDialog, &QColorDialog::currentColorChanged,
+ m_colorDialog, [=](const QColor &color) {
+ renderPreviews(env, color.name());
+ });
+
+ QObject::connect(m_colorDialog, &QColorDialog::colorSelected,
+ m_colorDialog, [=](const QColor &color) {
+ renderPreviews(env, color.name());
+ ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
+ QTC_ASSERT(matLib.isValid(), return);
+ matLib.setAuxiliaryData(colorAuxProp, color.name());
+ });
+
+ QObject::connect(m_colorDialog, &QColorDialog::rejected,
+ m_colorDialog, [=]() {
+ renderPreviews(oldEnv, oldValue);
+ initPreviewData();
+ });
+ return;
+ }
+ renderPreviews(env, value);
+}
+
+void MaterialEditorView::handlePreviewModelChanged(const QString &modelStr)
+{
+ if (modelStr.isEmpty())
+ return;
+
+ QTC_ASSERT(m_hasQuick3DImport, return);
+ QTC_ASSERT(model(), return);
+ QTC_ASSERT(model()->nodeInstanceView(), return);
+
+ ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
+ QTC_ASSERT(matLib.isValid(), return);
+ matLib.setAuxiliaryData("matPrevModel", modelStr);
+
+ QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender);
+ emitCustomNotification("refresh_material_browser", {});
+}
+
void MaterialEditorView::setupQmlBackend()
{
QUrl qmlPaneUrl;
@@ -472,17 +557,24 @@ void MaterialEditorView::setupQmlBackend()
currentQmlBackend->setSource(qmlPaneUrl);
- QObject::connect(currentQmlBackend->widget()->rootObject(), SIGNAL(toolBarAction(int)),
+ QObject *rootObj = currentQmlBackend->widget()->rootObject();
+ QObject::connect(rootObj, SIGNAL(toolBarAction(int)),
this, SLOT(handleToolBarAction(int)));
+ QObject::connect(rootObj, SIGNAL(previewEnvChanged(QString)),
+ this, SLOT(handlePreviewEnvChanged(QString)));
+ QObject::connect(rootObj, SIGNAL(previewModelChanged(QString)),
+ this, SLOT(handlePreviewModelChanged(QString)));
} else {
currentQmlBackend->setup(m_selectedMaterial, currentStateName, qmlSpecificsUrl, this);
}
+ currentQmlBackend->widget()->installEventFilter(this);
currentQmlBackend->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
m_stackedWidget->setCurrentWidget(currentQmlBackend->widget());
m_qmlBackEnd = currentQmlBackend;
+ initPreviewData();
}
void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value)
@@ -528,6 +620,29 @@ bool MaterialEditorView::noValidSelection() const
return !QmlObjectNode::isValidQmlObjectNode(m_selectedMaterial);
}
+void MaterialEditorView::initPreviewData()
+{
+ if (model() && m_qmlBackEnd) {
+ ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
+ if (matLib.isValid()) {
+ QString env = matLib.auxiliaryData("matPrevEnv").toString();
+ QString envValue = matLib.auxiliaryData("matPrevEnvValue").toString();
+ QString modelStr = matLib.auxiliaryData("matPrevModel").toString();
+ if (!envValue.isEmpty() && env != "Color" && env != "Default") {
+ env += '=';
+ env += envValue;
+ }
+ if (env.isEmpty())
+ env = "Default";
+ if (modelStr.isEmpty())
+ modelStr = "#Sphere";
+ QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(),
+ "initPreviewData",
+ Q_ARG(QVariant, env), Q_ARG(QVariant, modelStr));
+ }
+ }
+}
+
void MaterialEditorView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
@@ -844,6 +959,15 @@ void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const Prop
m_locked = false;
}
+bool MaterialEditorView::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::FocusOut) {
+ if (m_qmlBackEnd && m_qmlBackEnd->widget() == obj)
+ QMetaObject::invokeMethod(m_qmlBackEnd->widget()->rootObject(), "closeContextMenu");
+ }
+ return QObject::eventFilter(obj, event);
+}
+
void MaterialEditorView::reloadQml()
{
m_qmlBackendHash.clear();
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index ff734ed30b8..1c52be87cfa 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
@@ -27,12 +27,14 @@
#include
#include
+#include
#include
QT_BEGIN_NAMESPACE
class QShortcut;
class QStackedWidget;
class QTimer;
+class QColorDialog;
QT_END_NAMESPACE
namespace QmlDesigner {
@@ -87,10 +89,13 @@ public:
public slots:
void handleToolBarAction(int action);
+ void handlePreviewEnvChanged(const QString &envAndValue);
+ void handlePreviewModelChanged(const QString &modelStr);
protected:
void timerEvent(QTimerEvent *event) override;
void setValue(const QmlObjectNode &fxObjectNode, const PropertyName &name, const QVariant &value);
+ bool eventFilter(QObject *obj, QEvent *event) override;
private:
static QString materialEditorResourcesPath();
@@ -113,6 +118,8 @@ private:
bool noValidSelection() const;
+ void initPreviewData();
+
ModelNode m_selectedMaterial;
QTimer m_ensureMatLibTimer;
QShortcut *m_updateShortcut = nullptr;
@@ -124,6 +131,8 @@ private:
bool m_locked = false;
bool m_setupCompleted = false;
bool m_hasQuick3DImport = false;
+
+ QPointer m_colorDialog;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 4522c14a54f..e84f9224d61 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -660,7 +660,8 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
const QVariant &value)
{
QTC_ASSERT(m_nodeInstanceServer, return);
- const bool forceAuxChange = name == "invisible" || name == "locked" || name == "rotBlocked@Internal";
+ const bool forceAuxChange = name == "invisible" || name == "locked"
+ || name == "rotBlocked@Internal" || name.startsWith("matPrev");
if (((node.isRootNode() && (name == "width" || name == "height")) || forceAuxChange)
|| name.endsWith(PropertyName("@NodeInstance"))) {
if (hasInstanceForModelNode(node)) {