QmlDesigner: Add environment and model selectors to material preview

The model and the scene environment used to render material previews
can now be selected via buttons next to the preview in material editor.

Task-number: QDS-7347
Change-Id: I03089029e8420f80ed65be1c7b7a1ce4581f2fd4
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Miikka Heikkinen
2022-08-05 17:14:05 +03:00
parent 774010d96e
commit 45f93a817a
20 changed files with 543 additions and 112 deletions

View File

@@ -16,6 +16,8 @@
<file>mockfiles/images/static_floor.png</file>
<file>mockfiles/images/spot.png</file>
<file>mockfiles/images/spot@2x.png</file>
<file>mockfiles/images/preview_landscape.hdr</file>
<file>mockfiles/images/preview_studio.hdr</file>
<file>mockfiles/qt5/AdjustableArrow.qml</file>
<file>mockfiles/qt5/AreaLightHandle.qml</file>
<file>mockfiles/qt5/Arrow.qml</file>

View File

@@ -18,6 +18,8 @@
<file>mockfiles/images/floor_tex.png</file>
<file>mockfiles/images/spot.png</file>
<file>mockfiles/images/spot@2x.png</file>
<file>mockfiles/images/preview_landscape.hdr</file>
<file>mockfiles/images/preview_studio.hdr</file>
<file>mockfiles/qt6/AdjustableArrow.qml</file>
<file>mockfiles/qt6/AreaLightHandle.qml</file>
<file>mockfiles/qt6/Arrow.qml</file>

View File

@@ -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
}
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
y: 50
source: "#Sphere"
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)
}
}
}
}
}

View File

@@ -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;
}

View File

@@ -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
}
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
y: 50
source: "#Sphere"
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
}
}
}
}
}

View File

@@ -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

View File

@@ -339,6 +339,31 @@ void Qt5InformationNodeInstanceServer::resolveImportSupport()
#endif
}
void Qt5InformationNodeInstanceServer::updateMaterialPreviewData(const QVector<PropertyValueContainer> &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<PropertyValueContainer> &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();
}

View File

@@ -145,6 +145,7 @@ private:
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
void handleInputEvents();
void resolveImportSupport();
void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges);
void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges);
void removeRotationBlocks(const QVector<qint32> &instanceIds);
@@ -191,6 +192,13 @@ private:
QObject *m_3dHelper = nullptr;
int m_need3DEditViewRender = 0;
QSet<QObject *> m_dynamicObjectConstructors;
struct PreviewData {
QString env;
QString envValue;
QString model;
};
PreviewData m_materialPreviewData;
};
} // namespace QmlDesigner

View File

@@ -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

View File

@@ -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 }

View File

@@ -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,11 +64,96 @@ Column {
Item { width: 1; height: 10 } // spacer
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"
anchors.horizontalCenter: parent.horizontalCenter
Image {
id: materialPreview
@@ -69,6 +165,36 @@ Column {
}
}
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 {
// Section with hidden header is used so properties are aligned with the other sections' properties
hideHeader: true

View File

@@ -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,

View File

@@ -130,6 +130,8 @@ public:
listView,
lockOff,
lockOn,
materialPreviewEnvironment,
materialPreviewModel,
mergeCells,
minus,
mirror,

View File

@@ -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);
});
}
}

View File

@@ -62,6 +62,7 @@
#include <QStackedWidget>
#include <QShortcut>
#include <QTimer>
#include <QColorDialog>
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();

View File

@@ -27,12 +27,14 @@
#include <abstractview.h>
#include <QHash>
#include <QPointer>
#include <QTimer>
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<QColorDialog> m_colorDialog;
};
} // namespace QmlDesigner

View File

@@ -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)) {