forked from qt-creator/qt-creator
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:
@@ -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>
|
||||
|
@@ -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>
|
||||
|
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 }
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
Binary file not shown.
@@ -130,6 +130,8 @@ public:
|
||||
listView,
|
||||
lockOff,
|
||||
lockOn,
|
||||
materialPreviewEnvironment,
|
||||
materialPreviewModel,
|
||||
mergeCells,
|
||||
minus,
|
||||
mirror,
|
||||
|
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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)) {
|
||||
|
Reference in New Issue
Block a user