forked from qt-creator/qt-creator
QmlDesigner: Remove MaterialEditor
* For editing materials, the material is forced to be opened by property editor. It means that if property editor is locked, the locked would be ignored. Task-number: QDS-14625 Change-Id: I271cc862750cecb6b2480c66d26e6aa5c6f62d55 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -1,63 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import HelperWidgets as HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
|
||||||
|
|
||||||
StudioControls.PopupDialog {
|
|
||||||
id: colorPopup
|
|
||||||
|
|
||||||
property QtObject loaderItem: loader.item
|
|
||||||
property color originalColor
|
|
||||||
required property color currentColor
|
|
||||||
|
|
||||||
signal activateColor(color : color)
|
|
||||||
|
|
||||||
width: 260
|
|
||||||
|
|
||||||
onOriginalColorChanged: loader.updateOriginalColor()
|
|
||||||
onClosing: loader.active = false
|
|
||||||
|
|
||||||
function open(showItem) {
|
|
||||||
loader.ensureActive()
|
|
||||||
colorPopup.show(showItem)
|
|
||||||
|
|
||||||
loader.updateOriginalColor()
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: loader
|
|
||||||
|
|
||||||
function ensureActive() {
|
|
||||||
if (!loader.active)
|
|
||||||
loader.active = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateOriginalColor() {
|
|
||||||
if (loader.status === Loader.Ready)
|
|
||||||
loader.item.originalColor = colorPopup.originalColor
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceComponent: StudioControls.ColorEditorPopup {
|
|
||||||
width: colorPopup.contentWidth
|
|
||||||
visible: colorPopup.visible
|
|
||||||
|
|
||||||
onActivateColor: (color) => {
|
|
||||||
colorPopup.activateColor(color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Binding {
|
|
||||||
target: loader.item
|
|
||||||
property: "color"
|
|
||||||
value: colorPopup.currentColor
|
|
||||||
when: loader.status === Loader.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
onLoaded: {
|
|
||||||
loader.updateOriginalColor()
|
|
||||||
colorPopup.titleBar = loader.item.titleBarContent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,56 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import HelperWidgets
|
|
||||||
import StudioTheme as StudioTheme
|
|
||||||
|
|
||||||
PropertyEditorPane {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
width: 420
|
|
||||||
height: 420
|
|
||||||
|
|
||||||
signal toolBarAction(int action)
|
|
||||||
signal previewEnvChanged(string env)
|
|
||||||
signal previewModelChanged(string model)
|
|
||||||
|
|
||||||
// Called from C++, dummy methods to avoid warnings
|
|
||||||
function closeContextMenu() {}
|
|
||||||
function initPreviewData(env, model) {}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: col
|
|
||||||
|
|
||||||
MaterialEditorToolBar {
|
|
||||||
width: root.width
|
|
||||||
|
|
||||||
onToolBarAction: (action) => root.toolBarAction(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: root.width - 2 * col.padding
|
|
||||||
height: 150
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: {
|
|
||||||
if (!isQt6Project)
|
|
||||||
qsTr("<b>Material Editor</b> is not supported in Qt5 projects.")
|
|
||||||
else if (!hasQuick3DImport)
|
|
||||||
qsTr("To use <b>Material Editor</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
|
||||||
else if (!hasMaterialLibrary)
|
|
||||||
qsTr("<b>Material Editor</b> is disabled inside a non-visual component.")
|
|
||||||
else
|
|
||||||
qsTr("There are no materials in this project.<br>Select '<b>+</b>' to create one.")
|
|
||||||
}
|
|
||||||
textFormat: Text.RichText
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
font.pixelSize: StudioTheme.Values.mediumFontSize
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
width: root.width
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,155 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtCore
|
|
||||||
import HelperWidgets
|
|
||||||
import StudioControls 1.0 as StudioControls
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property string __previewEnv
|
|
||||||
property string __previewModel
|
|
||||||
|
|
||||||
width: 420
|
|
||||||
height: 420
|
|
||||||
|
|
||||||
signal toolBarAction(int action)
|
|
||||||
signal previewEnvChanged(string env)
|
|
||||||
signal previewModelChanged(string model)
|
|
||||||
|
|
||||||
// invoked from C++ to refresh material preview image
|
|
||||||
signal refreshPreview()
|
|
||||||
|
|
||||||
// Called from C++ to close context menu on focus out
|
|
||||||
function closeContextMenu()
|
|
||||||
{
|
|
||||||
Controller.closeContextMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from C++ to initialize preview menu checkmarks
|
|
||||||
function initPreviewData(env, model) {
|
|
||||||
root.__previewEnv = env
|
|
||||||
root.__previewModel = model
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialEditorToolBar {
|
|
||||||
id: toolbar
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
onToolBarAction: (action) => root.toolBarAction(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings {
|
|
||||||
id: settings
|
|
||||||
|
|
||||||
property var topSection
|
|
||||||
property bool dockMode
|
|
||||||
}
|
|
||||||
|
|
||||||
StudioControls.SplitView {
|
|
||||||
id: splitView
|
|
||||||
|
|
||||||
readonly property bool isHorizontal: splitView.orientation == Qt.Horizontal
|
|
||||||
|
|
||||||
anchors.top: toolbar.bottom
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
width: parent.width
|
|
||||||
orientation: splitView.width > 1000 ? Qt.Horizontal : Qt.Vertical
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: leftSideView
|
|
||||||
|
|
||||||
SplitView.fillWidth: leftSideView.visible
|
|
||||||
SplitView.fillHeight: leftSideView.visible
|
|
||||||
SplitView.minimumWidth: leftSideView.visible ? 300 : 0
|
|
||||||
SplitView.minimumHeight: leftSideView.visible ? 300 : 0
|
|
||||||
|
|
||||||
active: splitView.isHorizontal
|
|
||||||
visible: leftSideView.active && leftSideView.item
|
|
||||||
|
|
||||||
sourceComponent: PreviewComponent {}
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyEditorPane {
|
|
||||||
id: itemPane
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
SplitView.fillWidth: !leftSideView.visible
|
|
||||||
SplitView.fillHeight: true
|
|
||||||
SplitView.minimumWidth: leftSideView.visible ? 400 : 0
|
|
||||||
SplitView.maximumWidth: leftSideView.visible ? 800 : -1
|
|
||||||
|
|
||||||
headerDocked: !leftSideView.visible && settings.dockMode
|
|
||||||
|
|
||||||
headerComponent: MaterialEditorTopSection {
|
|
||||||
id: topSection
|
|
||||||
|
|
||||||
Component.onCompleted: topSection.restoreState(settings.topSection)
|
|
||||||
Component.onDestruction: settings.topSection = topSection.saveState()
|
|
||||||
previewComponent: PreviewComponent {}
|
|
||||||
showImage: !splitView.isHorizontal
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicPropertiesSection {
|
|
||||||
propertiesModel: MaterialEditorDynamicPropertiesModel {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: specificsTwo
|
|
||||||
|
|
||||||
property string theSource: specificQmlData
|
|
||||||
|
|
||||||
width: itemPane.width
|
|
||||||
visible: specificsTwo.theSource !== ""
|
|
||||||
sourceComponent: specificQmlComponent
|
|
||||||
|
|
||||||
onTheSourceChanged: {
|
|
||||||
specificsTwo.active = false
|
|
||||||
specificsTwo.active = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { // spacer
|
|
||||||
width: 1
|
|
||||||
height: 10
|
|
||||||
visible: specificsTwo.visible
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: specificsOne
|
|
||||||
width: itemPane.width
|
|
||||||
source: specificsUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component PreviewComponent : MaterialEditorPreview {
|
|
||||||
id: previewItem
|
|
||||||
|
|
||||||
onPreviewEnvChanged: root.previewEnvChanged(previewEnv)
|
|
||||||
onPreviewModelChanged: root.previewModelChanged(previewModel)
|
|
||||||
|
|
||||||
pinned: settings.dockMode
|
|
||||||
showPinButton: !leftSideView.visible
|
|
||||||
onPinnedChanged: settings.dockMode = previewItem.pinned
|
|
||||||
|
|
||||||
Binding {
|
|
||||||
previewItem.previewEnv: root.__previewEnv
|
|
||||||
previewItem.previewModel: root.__previewModel
|
|
||||||
delayed: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root
|
|
||||||
|
|
||||||
function onRefreshPreview() {
|
|
||||||
previewItem.refreshPreview()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,259 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import HelperWidgets as HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
|
||||||
import StudioTheme as StudioTheme
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property string previewEnv
|
|
||||||
property string previewModel
|
|
||||||
property alias pinned: pinButton.checked
|
|
||||||
property alias showPinButton: pinButton.visible
|
|
||||||
|
|
||||||
property StudioTheme.ControlStyle buttonStyle: StudioTheme.ViewBarButtonStyle {
|
|
||||||
// This is how you can override stuff from the control styles
|
|
||||||
baseIconFontSize: StudioTheme.Values.bigIconFontSize
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: HelperWidgets.Controller
|
|
||||||
|
|
||||||
function onCloseContextMenu() {
|
|
||||||
root.closeContextMenu()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: image.height
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
color: "#000000"
|
|
||||||
|
|
||||||
// Called from C++ to close context menu on focus out
|
|
||||||
function closeContextMenu()
|
|
||||||
{
|
|
||||||
modelMenu.close()
|
|
||||||
envMenu.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshPreview()
|
|
||||||
{
|
|
||||||
image.source = ""
|
|
||||||
image.source = "image://materialEditor/preview"
|
|
||||||
}
|
|
||||||
|
|
||||||
onPreviewEnvChanged: envMenu.updateEnvParams(root.previewEnv)
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: image
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
|
|
||||||
source: "image://materialEditor/preview"
|
|
||||||
cache: false
|
|
||||||
smooth: true
|
|
||||||
|
|
||||||
sourceSize.width: image.width
|
|
||||||
sourceSize.height: image.height
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: toolbarRect
|
|
||||||
|
|
||||||
radius: 10
|
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
|
||||||
width: optionsToolbar.width + 2 * toolbarRect.radius
|
|
||||||
height: optionsToolbar.height + toolbarRect.radius
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: -toolbarRect.radius
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: optionsToolbar
|
|
||||||
|
|
||||||
spacing: 5
|
|
||||||
anchors.centerIn: parent
|
|
||||||
anchors.horizontalCenterOffset: optionsToolbar.spacing
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
id: pinButton
|
|
||||||
|
|
||||||
style: root.buttonStyle
|
|
||||||
buttonIcon: pinButton.checked ? StudioTheme.Constants.pin : StudioTheme.Constants.unpin
|
|
||||||
checkable: true
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
id: previewEnvMenuButton
|
|
||||||
|
|
||||||
style: root.buttonStyle
|
|
||||||
buttonIcon: StudioTheme.Constants.textures_medium
|
|
||||||
tooltip: qsTr("Select preview environment.")
|
|
||||||
onClicked: envMenu.popup()
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
id: previewModelMenuButton
|
|
||||||
|
|
||||||
style: root.buttonStyle
|
|
||||||
buttonIcon: StudioTheme.Constants.cube_medium
|
|
||||||
tooltip: qsTr("Select preview model.")
|
|
||||||
onClicked: modelMenu.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StudioControls.Menu {
|
|
||||||
id: modelMenu
|
|
||||||
|
|
||||||
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
|
|
||||||
|
|
||||||
ListModel {
|
|
||||||
id: modelMenuModel
|
|
||||||
ListElement {
|
|
||||||
modelName: qsTr("Cone")
|
|
||||||
modelStr: "#Cone"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
modelName: qsTr("Cube")
|
|
||||||
modelStr: "#Cube"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
modelName: qsTr("Cylinder")
|
|
||||||
modelStr: "#Cylinder"
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
modelName: qsTr("Sphere")
|
|
||||||
modelStr: "#Sphere"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: modelMenuModel
|
|
||||||
StudioControls.MenuItemWithIcon {
|
|
||||||
text: modelName
|
|
||||||
onClicked: {
|
|
||||||
// Force property change notifications to keep check mark when reselected
|
|
||||||
root.previewModel = ""
|
|
||||||
root.previewModel = modelStr
|
|
||||||
}
|
|
||||||
checkable: true
|
|
||||||
checked: root.previewModel === modelStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StudioControls.Menu {
|
|
||||||
id: envMenu
|
|
||||||
|
|
||||||
property string previewEnvName
|
|
||||||
property string previewEnvValue
|
|
||||||
|
|
||||||
signal envParametersChanged()
|
|
||||||
|
|
||||||
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
|
|
||||||
|
|
||||||
Component.onCompleted: envMenu.updateEnvParams(root.previewEnv)
|
|
||||||
|
|
||||||
function updateEnvParams(str: string) {
|
|
||||||
let eqFound = str.lastIndexOf("=")
|
|
||||||
let newEnvName = (eqFound > 0) ? str.substr(0, eqFound) : str
|
|
||||||
let newEnvValue = (eqFound > 0) ? str.substr(eqFound + 1, str.length - eqFound) : ""
|
|
||||||
|
|
||||||
if (envMenu.previewEnvName !== newEnvName
|
|
||||||
|| envMenu.previewEnvValue !== newEnvValue) {
|
|
||||||
envMenu.previewEnvName = newEnvName
|
|
||||||
envMenu.previewEnvValue = newEnvValue
|
|
||||||
envMenu.envParametersChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EnvMenuItem {
|
|
||||||
envName: qsTr("Basic")
|
|
||||||
envStr: "Basic"
|
|
||||||
}
|
|
||||||
|
|
||||||
EnvMenuItem {
|
|
||||||
id: colorItem
|
|
||||||
|
|
||||||
property color color
|
|
||||||
property bool colorIsValid: false
|
|
||||||
|
|
||||||
envName: qsTr("Color")
|
|
||||||
envStr: "Color"
|
|
||||||
checked: false
|
|
||||||
|
|
||||||
Component.onCompleted: update()
|
|
||||||
onColorIsValidChanged: updatePopupOriginalColor()
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
colorItem.updatePopupOriginalColor()
|
|
||||||
colorPopup.open(colorItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
onColorChanged: {
|
|
||||||
colorItem.envStr = colorItem.checked
|
|
||||||
? "Color=" + color.toString()
|
|
||||||
: "Color"
|
|
||||||
colorItem.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePopupOriginalColor() {
|
|
||||||
if (colorItem.colorIsValid)
|
|
||||||
colorPopup.originalColor = colorItem.color
|
|
||||||
}
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
colorItem.checked = envMenu.previewEnvName === "Color"
|
|
||||||
if (colorItem.checked && envMenu.previewEnvValue) {
|
|
||||||
colorItem.color = envMenu.previewEnvValue
|
|
||||||
colorItem.colorIsValid = true
|
|
||||||
} else {
|
|
||||||
colorItem.colorIsValid = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: envMenu
|
|
||||||
function onEnvParametersChanged() {
|
|
||||||
colorItem.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EnvMenuItem {
|
|
||||||
envName: qsTr("Studio")
|
|
||||||
envStr: "SkyBox=preview_studio"
|
|
||||||
}
|
|
||||||
|
|
||||||
EnvMenuItem {
|
|
||||||
envName: qsTr("Landscape")
|
|
||||||
envStr: "SkyBox=preview_landscape"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorEditorPopup {
|
|
||||||
id: colorPopup
|
|
||||||
|
|
||||||
currentColor: colorItem.color
|
|
||||||
onActivateColor: (color) => colorItem.color = color
|
|
||||||
}
|
|
||||||
|
|
||||||
component EnvMenuItem: StudioControls.MenuItemWithIcon {
|
|
||||||
required property string envName
|
|
||||||
property string envStr
|
|
||||||
|
|
||||||
function commit() {
|
|
||||||
root.previewEnv = envStr
|
|
||||||
}
|
|
||||||
|
|
||||||
text: envName
|
|
||||||
onClicked: commit()
|
|
||||||
checkable: false
|
|
||||||
checked: root.previewEnv === envStr
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,56 +0,0 @@
|
|||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import HelperWidgets as HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
|
||||||
import StudioTheme as StudioTheme
|
|
||||||
import MaterialToolBarAction
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
color: StudioTheme.Values.themeToolbarBackground
|
|
||||||
height: StudioTheme.Values.toolbarHeight
|
|
||||||
|
|
||||||
signal toolBarAction(int action)
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: row
|
|
||||||
spacing: StudioTheme.Values.toolbarSpacing
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
leftPadding: 6
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
|
||||||
buttonIcon: StudioTheme.Constants.apply_medium
|
|
||||||
enabled: hasMaterial && hasModelSelection && hasQuick3DImport && hasMaterialLibrary
|
|
||||||
tooltip: qsTr("Apply material to selected model.")
|
|
||||||
onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
|
||||||
buttonIcon: StudioTheme.Constants.create_medium
|
|
||||||
enabled: hasQuick3DImport && hasMaterialLibrary
|
|
||||||
tooltip: qsTr("Create new material.")
|
|
||||||
onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial)
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
|
||||||
buttonIcon: StudioTheme.Constants.delete_medium
|
|
||||||
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
|
|
||||||
tooltip: qsTr("Delete current material.")
|
|
||||||
onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial)
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.AbstractButton {
|
|
||||||
style: StudioTheme.Values.viewBarButtonStyle
|
|
||||||
buttonIcon: StudioTheme.Constants.materialBrowser_medium
|
|
||||||
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
|
|
||||||
tooltip: qsTr("Open material browser.")
|
|
||||||
onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,93 +0,0 @@
|
|||||||
// Copyright (C) 2023 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import HelperWidgets as HelperWidgets
|
|
||||||
import StudioControls as StudioControls
|
|
||||||
import StudioTheme as StudioTheme
|
|
||||||
|
|
||||||
StudioControls.SplitView {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property alias showImage: previewLoader.active
|
|
||||||
property Component previewComponent: null
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
implicitHeight: showImage ? previewLoader.implicitHeight + nameSection.implicitHeight : nameSection.implicitHeight
|
|
||||||
|
|
||||||
orientation: Qt.Vertical
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: previewLoader
|
|
||||||
|
|
||||||
SplitView.fillWidth: true
|
|
||||||
SplitView.minimumWidth: 152
|
|
||||||
SplitView.preferredHeight: previewLoader.visible ? Math.min(root.width * 0.75, 400) : 0
|
|
||||||
SplitView.minimumHeight: previewLoader.visible ? 150 : 0
|
|
||||||
SplitView.maximumHeight: previewLoader.visible ? 600 : 0
|
|
||||||
|
|
||||||
visible: previewLoader.active && previewLoader.item
|
|
||||||
|
|
||||||
sourceComponent: root.previewComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.Section {
|
|
||||||
id: nameSection
|
|
||||||
|
|
||||||
// Section with hidden header is used so properties are aligned with the other sections' properties
|
|
||||||
hideHeader: true
|
|
||||||
SplitView.fillWidth: true
|
|
||||||
SplitView.preferredHeight: implicitHeight
|
|
||||||
SplitView.maximumHeight: implicitHeight
|
|
||||||
bottomPadding: StudioTheme.Values.sectionPadding * 2
|
|
||||||
collapsible: false
|
|
||||||
|
|
||||||
HelperWidgets.SectionLayout {
|
|
||||||
HelperWidgets.PropertyLabel { text: qsTr("Name") }
|
|
||||||
|
|
||||||
HelperWidgets.SecondColumnLayout {
|
|
||||||
HelperWidgets.Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
|
|
||||||
|
|
||||||
HelperWidgets.LineEdit {
|
|
||||||
id: matName
|
|
||||||
|
|
||||||
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
|
||||||
width: StudioTheme.Values.singleControlColumnWidth
|
|
||||||
placeholderText: qsTr("Material name")
|
|
||||||
showTranslateCheckBox: false
|
|
||||||
showExtendedFunctionButton: false
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
running: true
|
|
||||||
interval: 0
|
|
||||||
onTriggered: matName.backendValue = backendValues.objectName
|
|
||||||
// backendValues.objectName is not available yet without the Timer
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow only alphanumeric characters, underscores, no space at start, and 1 space between words
|
|
||||||
validator: RegularExpressionValidator { regularExpression: /^(\w+\s)*\w+$/ }
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.ExpandingSpacer {}
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.PropertyLabel { text: qsTr("Type") }
|
|
||||||
|
|
||||||
HelperWidgets.SecondColumnLayout {
|
|
||||||
HelperWidgets.Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
|
|
||||||
|
|
||||||
HelperWidgets.ComboBox {
|
|
||||||
currentIndex: possibleTypeIndex
|
|
||||||
model: possibleTypes
|
|
||||||
showExtendedFunctionButton: false
|
|
||||||
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
|
||||||
enabled: possibleTypes.length > 1
|
|
||||||
|
|
||||||
onActivated: changeTypeName(currentValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -52,7 +52,6 @@
|
|||||||
<splitter orientation="Vertical" count="2">
|
<splitter orientation="Vertical" count="2">
|
||||||
<area tabs="3" current="Properties">
|
<area tabs="3" current="Properties">
|
||||||
<widget name="Properties" closed="false"/>
|
<widget name="Properties" closed="false"/>
|
||||||
<widget name="MaterialEditor" closed="false"/>
|
|
||||||
<widget name="TextureEditor" closed="false"/>
|
<widget name="TextureEditor" closed="false"/>
|
||||||
</area>
|
</area>
|
||||||
<area tabs="3" current="MaterialBrowser">
|
<area tabs="3" current="MaterialBrowser">
|
||||||
|
@@ -42,7 +42,6 @@
|
|||||||
<splitter count="2" orientation="Vertical">
|
<splitter count="2" orientation="Vertical">
|
||||||
<area current="Properties" tabs="4">
|
<area current="Properties" tabs="4">
|
||||||
<widget closed="false" name="Properties"/>
|
<widget closed="false" name="Properties"/>
|
||||||
<widget closed="false" name="MaterialEditor"/>
|
|
||||||
<widget closed="false" name="TextureEditor"/>
|
<widget closed="false" name="TextureEditor"/>
|
||||||
<widget closed="true" name="ConnectionView"/>
|
<widget closed="true" name="ConnectionView"/>
|
||||||
</area>
|
</area>
|
||||||
|
@@ -82,7 +82,6 @@ add_qtc_plugin(QmlDesigner
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/components/integration
|
${CMAKE_CURRENT_LIST_DIR}/components/integration
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/itemlibrary
|
${CMAKE_CURRENT_LIST_DIR}/components/itemlibrary
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/materialbrowser
|
${CMAKE_CURRENT_LIST_DIR}/components/materialbrowser
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/materialeditor
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/textureeditor
|
${CMAKE_CURRENT_LIST_DIR}/components/textureeditor
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/navigator
|
${CMAKE_CURRENT_LIST_DIR}/components/navigator
|
||||||
${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor
|
${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor
|
||||||
@@ -438,6 +437,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
qmltexturenodeproxy.cpp qmltexturenodeproxy.h
|
qmltexturenodeproxy.cpp qmltexturenodeproxy.h
|
||||||
quick2propertyeditorview.cpp quick2propertyeditorview.h
|
quick2propertyeditorview.cpp quick2propertyeditorview.h
|
||||||
propertyeditorutils.cpp propertyeditorutils.h
|
propertyeditorutils.cpp propertyeditorutils.h
|
||||||
|
propertyeditor.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
@@ -461,18 +461,6 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
usertexturecategory.cpp usertexturecategory.h
|
usertexturecategory.cpp usertexturecategory.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
|
||||||
SOURCES_PREFIX components/materialeditor
|
|
||||||
SOURCES
|
|
||||||
materialeditorcontextobject.cpp materialeditorcontextobject.h
|
|
||||||
materialeditordynamicpropertiesproxymodel.cpp materialeditordynamicpropertiesproxymodel.h
|
|
||||||
materialeditorimageprovider.cpp materialeditorimageprovider.h
|
|
||||||
materialeditorqmlbackend.cpp materialeditorqmlbackend.h
|
|
||||||
materialeditortransaction.cpp materialeditortransaction.h
|
|
||||||
materialeditorview.cpp materialeditorview.h
|
|
||||||
materialeditor.qrc
|
|
||||||
)
|
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
SOURCES_PREFIX components/textureeditor
|
SOURCES_PREFIX components/textureeditor
|
||||||
SOURCES
|
SOURCES
|
||||||
|
@@ -1001,10 +1001,8 @@ void editMaterial(const SelectionContext &selectionContext)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material.isValid()) {
|
if (material.isValid())
|
||||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor", true);
|
Utils3D::openNodeInPropertyEditor(material);
|
||||||
Utils3D::selectMaterial(material);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addItemToStackedContainer(const SelectionContext &selectionContext)
|
void addItemToStackedContainer(const SelectionContext &selectionContext)
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "utils3d.h"
|
#include "utils3d.h"
|
||||||
|
|
||||||
|
#include <designmodewidget.h>
|
||||||
#include <itemlibraryentry.h>
|
#include <itemlibraryentry.h>
|
||||||
#include <modelutils.h>
|
#include <modelutils.h>
|
||||||
#include <nodeabstractproperty.h>
|
#include <nodeabstractproperty.h>
|
||||||
@@ -186,14 +187,6 @@ ModelNode getMaterialOfModel(const ModelNode &model, int idx)
|
|||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectMaterial(const ModelNode &material)
|
|
||||||
{
|
|
||||||
if (material.metaInfo().isQtQuick3DMaterial()) {
|
|
||||||
material.model()->rootModelNode().setAuxiliaryData(Utils3D::matLibSelectedMaterialProperty,
|
|
||||||
material.id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void selectTexture(const ModelNode &texture)
|
void selectTexture(const ModelNode &texture)
|
||||||
{
|
{
|
||||||
if (texture.metaInfo().isQtQuick3DTexture()) {
|
if (texture.metaInfo().isQtQuick3DTexture()) {
|
||||||
@@ -202,18 +195,6 @@ void selectTexture(const ModelNode &texture)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelNode selectedMaterial(AbstractView *view)
|
|
||||||
{
|
|
||||||
if (!view)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
ModelNode root = view->rootModelNode();
|
|
||||||
|
|
||||||
if (auto selectedProperty = root.auxiliaryData(Utils3D::matLibSelectedMaterialProperty))
|
|
||||||
return view->modelNodeForId(selectedProperty->toString());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelNode selectedTexture(AbstractView *view)
|
ModelNode selectedTexture(AbstractView *view)
|
||||||
{
|
{
|
||||||
if (!view)
|
if (!view)
|
||||||
@@ -597,5 +578,12 @@ void duplicateMaterial(AbstractView *view, const ModelNode &material)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void openNodeInPropertyEditor(const ModelNode &node)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(node, return);
|
||||||
|
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("PropertyEditor", true);
|
||||||
|
node.view()->emitCustomNotification("force_editing_node", {node}); // To PropertyEditor
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Utils3D
|
} // namespace Utils3D
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -15,8 +15,6 @@ namespace Utils3D {
|
|||||||
|
|
||||||
inline constexpr AuxiliaryDataKeyView active3dSceneProperty{AuxiliaryDataType::Temporary,
|
inline constexpr AuxiliaryDataKeyView active3dSceneProperty{AuxiliaryDataType::Temporary,
|
||||||
"active3dScene"};
|
"active3dScene"};
|
||||||
inline constexpr AuxiliaryDataKeyView matLibSelectedMaterialProperty{AuxiliaryDataType::Temporary,
|
|
||||||
"matLibSelMat"};
|
|
||||||
inline constexpr AuxiliaryDataKeyView matLibSelectedTextureProperty{AuxiliaryDataType::Temporary,
|
inline constexpr AuxiliaryDataKeyView matLibSelectedTextureProperty{AuxiliaryDataType::Temporary,
|
||||||
"matLibSelTex"};
|
"matLibSelTex"};
|
||||||
|
|
||||||
@@ -35,9 +33,7 @@ ModelNode getMaterialOfModel(const ModelNode &model, int idx = 0);
|
|||||||
|
|
||||||
// These methods handle selection of material library items for various material library views.
|
// These methods handle selection of material library items for various material library views.
|
||||||
// This is separate selection from the normal selection handling.
|
// This is separate selection from the normal selection handling.
|
||||||
void selectMaterial(const ModelNode &material);
|
|
||||||
void selectTexture(const ModelNode &texture);
|
void selectTexture(const ModelNode &texture);
|
||||||
ModelNode selectedMaterial(AbstractView *view);
|
|
||||||
ModelNode selectedTexture(AbstractView *view);
|
ModelNode selectedTexture(AbstractView *view);
|
||||||
|
|
||||||
ModelNode resolveSceneEnv(AbstractView *view, int sceneId);
|
ModelNode resolveSceneEnv(AbstractView *view, int sceneId);
|
||||||
@@ -50,6 +46,8 @@ void applyMaterialToModels(AbstractView *view, const ModelNode &material,
|
|||||||
|
|
||||||
void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId);
|
void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId);
|
||||||
|
|
||||||
|
void openNodeInPropertyEditor(const ModelNode &node);
|
||||||
|
|
||||||
#ifdef QDS_USE_PROJECTSTORAGE
|
#ifdef QDS_USE_PROJECTSTORAGE
|
||||||
ModelNode createMaterial(AbstractView *view, const TypeName &typeName);
|
ModelNode createMaterial(AbstractView *view, const TypeName &typeName);
|
||||||
#else
|
#else
|
||||||
|
@@ -19,7 +19,6 @@
|
|||||||
#include <formeditorview.h>
|
#include <formeditorview.h>
|
||||||
#include <itemlibraryview.h>
|
#include <itemlibraryview.h>
|
||||||
#include <materialbrowserview.h>
|
#include <materialbrowserview.h>
|
||||||
#include <materialeditorview.h>
|
|
||||||
#include <model/auxiliarypropertystorageview.h>
|
#include <model/auxiliarypropertystorageview.h>
|
||||||
#include <navigatorview.h>
|
#include <navigatorview.h>
|
||||||
#include <nodeinstanceview.h>
|
#include <nodeinstanceview.h>
|
||||||
@@ -73,7 +72,6 @@ public:
|
|||||||
, navigatorView{externalDependencies}
|
, navigatorView{externalDependencies}
|
||||||
, propertyEditorView(imageCache, externalDependencies)
|
, propertyEditorView(imageCache, externalDependencies)
|
||||||
#ifndef QTC_USE_QML_DESIGNER_LITE
|
#ifndef QTC_USE_QML_DESIGNER_LITE
|
||||||
, materialEditorView{externalDependencies}
|
|
||||||
, materialBrowserView{imageCache, externalDependencies}
|
, materialBrowserView{imageCache, externalDependencies}
|
||||||
, textureEditorView{imageCache, externalDependencies}
|
, textureEditorView{imageCache, externalDependencies}
|
||||||
#endif
|
#endif
|
||||||
@@ -103,7 +101,6 @@ public:
|
|||||||
NavigatorView navigatorView;
|
NavigatorView navigatorView;
|
||||||
PropertyEditorView propertyEditorView;
|
PropertyEditorView propertyEditorView;
|
||||||
#ifndef QTC_USE_QML_DESIGNER_LITE
|
#ifndef QTC_USE_QML_DESIGNER_LITE
|
||||||
MaterialEditorView materialEditorView;
|
|
||||||
MaterialBrowserView materialBrowserView;
|
MaterialBrowserView materialBrowserView;
|
||||||
TextureEditorView textureEditorView;
|
TextureEditorView textureEditorView;
|
||||||
#endif
|
#endif
|
||||||
@@ -233,7 +230,6 @@ QList<AbstractView *> ViewManager::standardViews() const
|
|||||||
&d->itemLibraryView,
|
&d->itemLibraryView,
|
||||||
&d->navigatorView,
|
&d->navigatorView,
|
||||||
&d->propertyEditorView,
|
&d->propertyEditorView,
|
||||||
&d->materialEditorView,
|
|
||||||
&d->materialBrowserView,
|
&d->materialBrowserView,
|
||||||
&d->textureEditorView,
|
&d->textureEditorView,
|
||||||
&d->statesEditorView,
|
&d->statesEditorView,
|
||||||
@@ -460,7 +456,6 @@ QList<WidgetInfo> ViewManager::widgetInfos() const
|
|||||||
widgetInfoList.append(d->navigatorView.widgetInfo());
|
widgetInfoList.append(d->navigatorView.widgetInfo());
|
||||||
widgetInfoList.append(d->propertyEditorView.widgetInfo());
|
widgetInfoList.append(d->propertyEditorView.widgetInfo());
|
||||||
#ifndef QTC_USE_QML_DESIGNER_LITE
|
#ifndef QTC_USE_QML_DESIGNER_LITE
|
||||||
widgetInfoList.append(d->materialEditorView.widgetInfo());
|
|
||||||
widgetInfoList.append(d->materialBrowserView.widgetInfo());
|
widgetInfoList.append(d->materialBrowserView.widgetInfo());
|
||||||
widgetInfoList.append(d->textureEditorView.widgetInfo());
|
widgetInfoList.append(d->textureEditorView.widgetInfo());
|
||||||
#endif
|
#endif
|
||||||
|
@@ -181,8 +181,7 @@ QAction *Edit3DMaterialsAction::createMaterialAction(const ModelNode &material,
|
|||||||
|
|
||||||
QAction *editMaterialAction = new QAction(tr("Edit"), menu);
|
QAction *editMaterialAction = new QAction(tr("Edit"), menu);
|
||||||
connect(editMaterialAction, &QAction::triggered, menu, [material] {
|
connect(editMaterialAction, &QAction::triggered, menu, [material] {
|
||||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor", true);
|
Utils3D::openNodeInPropertyEditor(material);
|
||||||
Utils3D::selectMaterial(material);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
menu->addAction(editMaterialAction);
|
menu->addAction(editMaterialAction);
|
||||||
|
@@ -185,21 +185,12 @@ void ComponentView::ensureMatLibTriggered()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool texSelected = Utils3D::selectedTexture(this).isValid();
|
bool texSelected = Utils3D::selectedTexture(this).isValid();
|
||||||
bool matSelected = Utils3D::selectedMaterial(this).isValid();
|
if (!texSelected) {
|
||||||
if (!texSelected || !matSelected) {
|
|
||||||
const QList<ModelNode> matLibNodes = matLib.directSubModelNodes();
|
const QList<ModelNode> matLibNodes = matLib.directSubModelNodes();
|
||||||
for (const ModelNode &node : matLibNodes) {
|
for (const ModelNode &node : matLibNodes) {
|
||||||
if (!texSelected && node.metaInfo().isQtQuick3DTexture()) {
|
if (node.metaInfo().isQtQuick3DTexture()) {
|
||||||
Utils3D::selectTexture(node);
|
Utils3D::selectTexture(node);
|
||||||
if (matSelected)
|
break;
|
||||||
break;
|
|
||||||
texSelected = true;
|
|
||||||
}
|
|
||||||
if (!matSelected && node.metaInfo().isQtQuick3DMaterial()) {
|
|
||||||
Utils3D::selectMaterial(node);
|
|
||||||
if (texSelected)
|
|
||||||
break;
|
|
||||||
matSelected = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,9 +285,7 @@ void ComponentView::nodeIdChanged(const ModelNode& node, const QString& newId, c
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto metaInfo = node.metaInfo();
|
auto metaInfo = node.metaInfo();
|
||||||
if (metaInfo.isQtQuick3DMaterial())
|
if (metaInfo.isQtQuick3DTexture())
|
||||||
maybeSetAuxData(Utils3D::matLibSelectedMaterialProperty);
|
|
||||||
else if (metaInfo.isQtQuick3DTexture())
|
|
||||||
maybeSetAuxData(Utils3D::matLibSelectedTextureProperty);
|
maybeSetAuxData(Utils3D::matLibSelectedTextureProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -82,7 +82,6 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
if (m_widget.isNull()) {
|
if (m_widget.isNull()) {
|
||||||
m_widget = new MaterialBrowserWidget(m_imageCache, this);
|
m_widget = new MaterialBrowserWidget(m_imageCache, this);
|
||||||
|
|
||||||
// custom notifications below are sent to the MaterialEditor
|
|
||||||
MaterialBrowserModel *matBrowserModel = m_widget->materialBrowserModel().data();
|
MaterialBrowserModel *matBrowserModel = m_widget->materialBrowserModel().data();
|
||||||
|
|
||||||
connect(matBrowserModel, &MaterialBrowserModel::applyToSelectedTriggered, this,
|
connect(matBrowserModel, &MaterialBrowserModel::applyToSelectedTriggered, this,
|
||||||
|
@@ -78,7 +78,8 @@ public:
|
|||||||
QSize *size,
|
QSize *size,
|
||||||
[[maybe_unused]] const QSize &requestedSize) override
|
[[maybe_unused]] const QSize &requestedSize) override
|
||||||
{
|
{
|
||||||
static QPixmap defaultPreview = QPixmap::fromImage(QImage(":/materialeditor/images/defaultmaterialpreview.png"));
|
static QPixmap defaultPreview = QPixmap::fromImage(
|
||||||
|
QImage(":/propertyeditor/images/defaultmaterialpreview.png"));
|
||||||
|
|
||||||
QPixmap pixmap{150, 150};
|
QPixmap pixmap{150, 150};
|
||||||
|
|
||||||
|
@@ -1,555 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "materialeditorcontextobject.h"
|
|
||||||
|
|
||||||
#include <bindingproperty.h>
|
|
||||||
#include <documentmanager.h>
|
|
||||||
#include <nodemetainfo.h>
|
|
||||||
#include <qmlobjectnode.h>
|
|
||||||
#include <qmltimeline.h>
|
|
||||||
#include <qmltimelinekeyframegroup.h>
|
|
||||||
#include <variantproperty.h>
|
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QCursor>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QQmlComponent>
|
|
||||||
#include <QQmlContext>
|
|
||||||
#include <QQmlPropertyMap>
|
|
||||||
#include <QQuickWidget>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
MaterialEditorContextObject::MaterialEditorContextObject(QQuickWidget *widget, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_quickWidget(widget)
|
|
||||||
{
|
|
||||||
qmlRegisterUncreatableType<MaterialEditorContextObject>("MaterialToolBarAction", 1, 0, "ToolBarAction", "Enum type");
|
|
||||||
}
|
|
||||||
|
|
||||||
QQmlComponent *MaterialEditorContextObject::specificQmlComponent()
|
|
||||||
{
|
|
||||||
if (m_specificQmlComponent)
|
|
||||||
return m_specificQmlComponent;
|
|
||||||
|
|
||||||
m_specificQmlComponent = new QQmlComponent(m_quickWidget->rootContext()->engine(), this);
|
|
||||||
m_specificQmlComponent->setData(m_specificQmlData.toUtf8(), QUrl::fromLocalFile("specifics.qml"));
|
|
||||||
|
|
||||||
return m_specificQmlComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MaterialEditorContextObject::convertColorToString(const QVariant &color)
|
|
||||||
{
|
|
||||||
QString colorString;
|
|
||||||
QColor theColor;
|
|
||||||
if (color.canConvert(QMetaType(QMetaType::QColor))) {
|
|
||||||
theColor = color.value<QColor>();
|
|
||||||
} else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
|
|
||||||
auto vec = color.value<QVector3D>();
|
|
||||||
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
colorString = theColor.name();
|
|
||||||
|
|
||||||
if (theColor.alpha() != 255) {
|
|
||||||
QString hexAlpha = QString("%1").arg(theColor.alpha(), 2, 16, QLatin1Char('0'));
|
|
||||||
colorString.remove(0, 1);
|
|
||||||
colorString.prepend(hexAlpha);
|
|
||||||
colorString.prepend(QStringLiteral("#"));
|
|
||||||
}
|
|
||||||
return colorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this method is used by the ColorEditor helper widget, check if at all needed?
|
|
||||||
QColor MaterialEditorContextObject::colorFromString(const QString &colorString)
|
|
||||||
{
|
|
||||||
return colorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::changeTypeName(const QString &typeName)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_model && m_model->rewriterView(), return);
|
|
||||||
QTC_ASSERT(m_selectedMaterial.isValid(), return);
|
|
||||||
|
|
||||||
if (m_selectedMaterial.simplifiedTypeName() == typeName)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Ideally we should not misuse the rewriterView
|
|
||||||
// If we add more code here we have to forward the material editor view
|
|
||||||
RewriterView *rewriterView = m_model->rewriterView();
|
|
||||||
|
|
||||||
rewriterView->executeInTransaction("MaterialEditorContextObject::changeTypeName", [&] {
|
|
||||||
NodeMetaInfo metaInfo = m_model->metaInfo(typeName.toLatin1());
|
|
||||||
|
|
||||||
QTC_ASSERT(metaInfo.isValid(), return);
|
|
||||||
|
|
||||||
// Create a list of properties available for the new type
|
|
||||||
PropertyNameList propertiesAndSignals = Utils::transform<PropertyNameList>(
|
|
||||||
metaInfo.properties(), &PropertyMetaInfo::name);
|
|
||||||
// Add signals to the list
|
|
||||||
const PropertyNameList signalNames = metaInfo.signalNames();
|
|
||||||
for (const PropertyName &signal : signalNames) {
|
|
||||||
if (signal.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
PropertyName name = signal;
|
|
||||||
QChar firstChar = QChar(signal.at(0)).toUpper().toLatin1();
|
|
||||||
name[0] = firstChar.toLatin1();
|
|
||||||
name.prepend("on");
|
|
||||||
propertiesAndSignals.append(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add dynamic properties and respective change signals
|
|
||||||
const QList<AbstractProperty> matProps = m_selectedMaterial.properties();
|
|
||||||
for (const auto &property : matProps) {
|
|
||||||
if (!property.isDynamic())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Add dynamic property
|
|
||||||
propertiesAndSignals.append(property.name().toByteArray());
|
|
||||||
// Add its change signal
|
|
||||||
PropertyName name = property.name().toByteArray();
|
|
||||||
QChar firstChar = QChar(property.name().at(0)).toUpper().toLatin1();
|
|
||||||
name[0] = firstChar.toLatin1();
|
|
||||||
name.prepend("on");
|
|
||||||
name.append("Changed");
|
|
||||||
propertiesAndSignals.append(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare current properties and signals with the ones available for change type
|
|
||||||
QList<PropertyName> incompatibleProperties;
|
|
||||||
for (const auto &property : matProps) {
|
|
||||||
if (!propertiesAndSignals.contains(property.name()))
|
|
||||||
incompatibleProperties.append(property.name().toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
// When switching between material types, copy base (diffuse) color and map properties of
|
|
||||||
// source type into corresponding properties of the target type.
|
|
||||||
const QList<PropertyName> baseColors = {"baseColor", "diffuseColor", "albedoColor"};
|
|
||||||
const QList<PropertyName> baseMaps = {"baseColorMap", "diffuseMap", "albedoMap"};
|
|
||||||
int sourceIndex = -1;
|
|
||||||
int targetIndex = -1;
|
|
||||||
NodeMetaInfo oldMetaInfo = m_selectedMaterial.metaInfo();
|
|
||||||
struct CopyData {
|
|
||||||
CopyData() {}
|
|
||||||
CopyData(PropertyName n) : name(n) {}
|
|
||||||
PropertyName name;
|
|
||||||
QVariant value;
|
|
||||||
bool isBinding = false;
|
|
||||||
};
|
|
||||||
QHash<PropertyName, CopyData> copyMap;
|
|
||||||
|
|
||||||
if (oldMetaInfo.isQtQuick3DPrincipledMaterial())
|
|
||||||
sourceIndex = 0;
|
|
||||||
else if (oldMetaInfo.isQtQuick3DDefaultMaterial())
|
|
||||||
sourceIndex = 1;
|
|
||||||
else if (oldMetaInfo.isQtQuick3DSpecularGlossyMaterial())
|
|
||||||
sourceIndex = 2;
|
|
||||||
|
|
||||||
if (metaInfo.isQtQuick3DPrincipledMaterial())
|
|
||||||
targetIndex = 0;
|
|
||||||
else if (metaInfo.isQtQuick3DDefaultMaterial())
|
|
||||||
targetIndex = 1;
|
|
||||||
else if (metaInfo.isQtQuick3DSpecularGlossyMaterial())
|
|
||||||
targetIndex = 2;
|
|
||||||
|
|
||||||
if (sourceIndex >= 0 && targetIndex >= 0) {
|
|
||||||
if (incompatibleProperties.contains(baseColors[sourceIndex])) {
|
|
||||||
copyMap.insert(baseColors[sourceIndex], baseColors[targetIndex]);
|
|
||||||
incompatibleProperties.removeOne(baseColors[sourceIndex]);
|
|
||||||
}
|
|
||||||
if (incompatibleProperties.contains(baseMaps[sourceIndex])) {
|
|
||||||
copyMap.insert(baseMaps[sourceIndex], baseMaps[targetIndex]);
|
|
||||||
incompatibleProperties.removeOne(baseMaps[sourceIndex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto ©Keys = copyMap.keys();
|
|
||||||
|
|
||||||
Utils::sort(incompatibleProperties);
|
|
||||||
|
|
||||||
// Create a dialog showing incompatible properties and signals
|
|
||||||
if (!incompatibleProperties.empty()) {
|
|
||||||
QString detailedText = tr("<b>Incompatible properties:</b><br>");
|
|
||||||
|
|
||||||
for (const auto &p : std::as_const(incompatibleProperties))
|
|
||||||
detailedText.append("- " + QString::fromUtf8(p) + "<br>");
|
|
||||||
|
|
||||||
detailedText.chop(QString("<br>").size());
|
|
||||||
|
|
||||||
QMessageBox msgBox;
|
|
||||||
msgBox.setTextFormat(Qt::RichText);
|
|
||||||
msgBox.setIcon(QMessageBox::Question);
|
|
||||||
msgBox.setWindowTitle(tr("Change Type"));
|
|
||||||
msgBox.setText(tr("Changing the type from %1 to %2 can't be done without removing incompatible properties.<br><br>%3")
|
|
||||||
.arg(m_selectedMaterial.simplifiedTypeName(), typeName, detailedText));
|
|
||||||
msgBox.setInformativeText(tr("Do you want to continue by removing incompatible properties?"));
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
|
||||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
|
||||||
|
|
||||||
if (msgBox.exec() == QMessageBox::Cancel) {
|
|
||||||
updatePossibleTypeIndex();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &p : std::as_const(incompatibleProperties))
|
|
||||||
m_selectedMaterial.removeProperty(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!copyKeys.isEmpty()) {
|
|
||||||
// Copy mapped properties to new name. Note that this will only copy the base
|
|
||||||
// property value and adjust the keyframe groups. Any other bindings related
|
|
||||||
// to the property will be ignored.
|
|
||||||
const QList<ModelNode> timeLines = QmlObjectNode(m_selectedMaterial).allTimelines();
|
|
||||||
for (const auto &key : std::as_const(copyKeys)) {
|
|
||||||
CopyData ©Data = copyMap[key];
|
|
||||||
for (const auto &timeLineNode : timeLines) {
|
|
||||||
QmlTimeline timeLine(timeLineNode);
|
|
||||||
if (timeLine.hasKeyframeGroup(m_selectedMaterial, key)) {
|
|
||||||
QmlTimelineKeyframeGroup group = timeLine.keyframeGroup(m_selectedMaterial,
|
|
||||||
key);
|
|
||||||
group.setPropertyName(copyData.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Property value itself cannot be copied until type has been changed, so store it
|
|
||||||
AbstractProperty prop = m_selectedMaterial.property(key);
|
|
||||||
if (prop.isValid()) {
|
|
||||||
if (prop.isBindingProperty()) {
|
|
||||||
copyData.isBinding = true;
|
|
||||||
copyData.value = prop.toBindingProperty().expression();
|
|
||||||
} else {
|
|
||||||
copyData.value = prop.toVariantProperty().value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_selectedMaterial.removeProperty(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef QDS_USE_PROJECTSTORAGE
|
|
||||||
if (m_selectedMaterial.isRootNode())
|
|
||||||
rewriterView->changeRootNodeType(typeName.toUtf8(), -1, -1);
|
|
||||||
else
|
|
||||||
m_selectedMaterial.changeType(typeName.toUtf8(), -1, -1);
|
|
||||||
#else
|
|
||||||
if (m_selectedMaterial.isRootNode())
|
|
||||||
rewriterView->changeRootNodeType(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion());
|
|
||||||
else
|
|
||||||
m_selectedMaterial.changeType(metaInfo.typeName(),
|
|
||||||
metaInfo.majorVersion(),
|
|
||||||
metaInfo.minorVersion());
|
|
||||||
#endif
|
|
||||||
for (const auto &key : copyKeys) {
|
|
||||||
const CopyData ©Data = copyMap[key];
|
|
||||||
if (copyData.isBinding)
|
|
||||||
m_selectedMaterial.bindingProperty(copyData.name).setExpression(copyData.value.toString());
|
|
||||||
else
|
|
||||||
m_selectedMaterial.variantProperty(copyData.name).setValue(copyData.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::insertKeyframe(const QString &propertyName)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_model && m_model->rewriterView(), return);
|
|
||||||
QTC_ASSERT(m_selectedMaterial.isValid(), return);
|
|
||||||
|
|
||||||
// Ideally we should not missuse the rewriterView
|
|
||||||
// If we add more code here we have to forward the material editor view
|
|
||||||
RewriterView *rewriterView = m_model->rewriterView();
|
|
||||||
|
|
||||||
QmlTimeline timeline = rewriterView->currentTimelineNode();
|
|
||||||
|
|
||||||
QTC_ASSERT(timeline.isValid(), return);
|
|
||||||
|
|
||||||
rewriterView->executeInTransaction("MaterialEditorContextObject::insertKeyframe", [&] {
|
|
||||||
timeline.insertKeyframe(m_selectedMaterial, propertyName.toUtf8());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int MaterialEditorContextObject::majorVersion() const
|
|
||||||
{
|
|
||||||
return m_majorVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setMajorVersion(int majorVersion)
|
|
||||||
{
|
|
||||||
if (m_majorVersion == majorVersion)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_majorVersion = majorVersion;
|
|
||||||
|
|
||||||
emit majorVersionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorContextObject::hasActiveTimeline() const
|
|
||||||
{
|
|
||||||
return m_hasActiveTimeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setHasActiveTimeline(bool b)
|
|
||||||
{
|
|
||||||
if (b == m_hasActiveTimeline)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_hasActiveTimeline = b;
|
|
||||||
emit hasActiveTimelineChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorContextObject::hasQuick3DImport() const
|
|
||||||
{
|
|
||||||
return m_hasQuick3DImport;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setHasQuick3DImport(bool b)
|
|
||||||
{
|
|
||||||
if (b == m_hasQuick3DImport)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_hasQuick3DImport = b;
|
|
||||||
emit hasQuick3DImportChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorContextObject::hasMaterialLibrary() const
|
|
||||||
{
|
|
||||||
return m_hasMaterialLibrary;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setHasMaterialLibrary(bool b)
|
|
||||||
{
|
|
||||||
if (b == m_hasMaterialLibrary)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_hasMaterialLibrary = b;
|
|
||||||
emit hasMaterialLibraryChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorContextObject::isQt6Project() const
|
|
||||||
{
|
|
||||||
return m_isQt6Project;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setIsQt6Project(bool b)
|
|
||||||
{
|
|
||||||
if (m_isQt6Project == b)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_isQt6Project = b;
|
|
||||||
emit isQt6ProjectChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorContextObject::hasModelSelection() const
|
|
||||||
{
|
|
||||||
return m_hasModelSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setHasModelSelection(bool b)
|
|
||||||
{
|
|
||||||
if (b == m_hasModelSelection)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_hasModelSelection = b;
|
|
||||||
emit hasModelSelectionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setSelectedMaterial(const ModelNode &matNode)
|
|
||||||
{
|
|
||||||
m_selectedMaterial = matNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl)
|
|
||||||
{
|
|
||||||
if (newSpecificsUrl == m_specificsUrl)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_specificsUrl = newSpecificsUrl;
|
|
||||||
emit specificsUrlChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setSpecificQmlData(const QString &newSpecificQmlData)
|
|
||||||
{
|
|
||||||
if (newSpecificQmlData == m_specificQmlData)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_specificQmlData = newSpecificQmlData;
|
|
||||||
|
|
||||||
delete m_specificQmlComponent;
|
|
||||||
m_specificQmlComponent = nullptr;
|
|
||||||
|
|
||||||
emit specificQmlComponentChanged();
|
|
||||||
emit specificQmlDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setStateName(const QString &newStateName)
|
|
||||||
{
|
|
||||||
if (newStateName == m_stateName)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_stateName = newStateName;
|
|
||||||
emit stateNameChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setAllStateNames(const QStringList &allStates)
|
|
||||||
{
|
|
||||||
if (allStates == m_allStateNames)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_allStateNames = allStates;
|
|
||||||
emit allStateNamesChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setPossibleTypes(const QStringList &types)
|
|
||||||
{
|
|
||||||
if (types == m_possibleTypes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_possibleTypes = types;
|
|
||||||
emit possibleTypesChanged();
|
|
||||||
|
|
||||||
updatePossibleTypeIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setCurrentType(const QString &type)
|
|
||||||
{
|
|
||||||
m_currentType = type.split('.').last();
|
|
||||||
updatePossibleTypeIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setIsBaseState(bool newIsBaseState)
|
|
||||||
{
|
|
||||||
if (newIsBaseState == m_isBaseState)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_isBaseState = newIsBaseState;
|
|
||||||
emit isBaseStateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setSelectionChanged(bool newSelectionChanged)
|
|
||||||
{
|
|
||||||
if (newSelectionChanged == m_selectionChanged)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_selectionChanged = newSelectionChanged;
|
|
||||||
emit selectionChangedChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setBackendValues(QQmlPropertyMap *newBackendValues)
|
|
||||||
{
|
|
||||||
if (newBackendValues == m_backendValues)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_backendValues = newBackendValues;
|
|
||||||
emit backendValuesChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setModel(Model *model)
|
|
||||||
{
|
|
||||||
m_model = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::triggerSelectionChanged()
|
|
||||||
{
|
|
||||||
setSelectionChanged(!m_selectionChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::setHasAliasExport(bool hasAliasExport)
|
|
||||||
{
|
|
||||||
if (m_aliasExport == hasAliasExport)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_aliasExport = hasAliasExport;
|
|
||||||
emit hasAliasExportChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::updatePossibleTypeIndex()
|
|
||||||
{
|
|
||||||
int newIndex = -1;
|
|
||||||
if (!m_currentType.isEmpty())
|
|
||||||
newIndex = m_possibleTypes.indexOf(m_currentType);
|
|
||||||
|
|
||||||
// Emit valid possible type index change even if the index doesn't change, as currentIndex on
|
|
||||||
// QML side will change to default internally if model is updated
|
|
||||||
if (m_possibleTypeIndex != -1 || m_possibleTypeIndex != newIndex) {
|
|
||||||
m_possibleTypeIndex = newIndex;
|
|
||||||
emit possibleTypeIndexChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::hideCursor()
|
|
||||||
{
|
|
||||||
if (QApplication::overrideCursor())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
|
|
||||||
|
|
||||||
if (QWidget *w = QApplication::activeWindow())
|
|
||||||
m_lastPos = QCursor::pos(w->screen());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::restoreCursor()
|
|
||||||
{
|
|
||||||
if (!QApplication::overrideCursor())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
|
|
||||||
if (QWidget *w = QApplication::activeWindow())
|
|
||||||
QCursor::setPos(w->screen(), m_lastPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::holdCursorInPlace()
|
|
||||||
{
|
|
||||||
if (!QApplication::overrideCursor())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (QWidget *w = QApplication::activeWindow())
|
|
||||||
QCursor::setPos(w->screen(), m_lastPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MaterialEditorContextObject::devicePixelRatio()
|
|
||||||
{
|
|
||||||
if (QWidget *w = QApplication::activeWindow())
|
|
||||||
return w->devicePixelRatio();
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList MaterialEditorContextObject::allStatesForId(const QString &id)
|
|
||||||
{
|
|
||||||
if (m_model && m_model->rewriterView()) {
|
|
||||||
const QmlObjectNode node = m_model->rewriterView()->modelNodeForId(id);
|
|
||||||
if (node.isValid())
|
|
||||||
return node.allStateNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorContextObject::isBlocked(const QString &) const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorContextObject::goIntoComponent()
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_model, return);
|
|
||||||
DocumentManager::goIntoComponent(m_selectedMaterial);
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect MaterialEditorContextObject::screenRect() const
|
|
||||||
{
|
|
||||||
if (m_quickWidget && m_quickWidget->screen())
|
|
||||||
return m_quickWidget->screen()->availableGeometry();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QPoint MaterialEditorContextObject::globalPos(const QPoint &point) const
|
|
||||||
{
|
|
||||||
if (m_quickWidget)
|
|
||||||
return m_quickWidget->mapToGlobal(point);
|
|
||||||
return point;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // QmlDesigner
|
|
@@ -1,182 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <model.h>
|
|
||||||
#include <modelnode.h>
|
|
||||||
|
|
||||||
#include <QColor>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QPoint>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QQmlComponent;
|
|
||||||
class QQmlPropertyMap;
|
|
||||||
class QQuickWidget;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class MaterialEditorContextObject : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
Q_PROPERTY(QUrl specificsUrl READ specificsUrl WRITE setSpecificsUrl NOTIFY specificsUrlChanged)
|
|
||||||
Q_PROPERTY(QString specificQmlData READ specificQmlData WRITE setSpecificQmlData NOTIFY specificQmlDataChanged)
|
|
||||||
Q_PROPERTY(QQmlComponent *specificQmlComponent READ specificQmlComponent NOTIFY specificQmlComponentChanged)
|
|
||||||
|
|
||||||
Q_PROPERTY(QString stateName READ stateName WRITE setStateName NOTIFY stateNameChanged)
|
|
||||||
Q_PROPERTY(QStringList allStateNames READ allStateNames WRITE setAllStateNames NOTIFY allStateNamesChanged)
|
|
||||||
Q_PROPERTY(QStringList possibleTypes READ possibleTypes WRITE setPossibleTypes NOTIFY possibleTypesChanged)
|
|
||||||
Q_PROPERTY(int possibleTypeIndex READ possibleTypeIndex NOTIFY possibleTypeIndexChanged)
|
|
||||||
|
|
||||||
Q_PROPERTY(bool isBaseState READ isBaseState WRITE setIsBaseState NOTIFY isBaseStateChanged)
|
|
||||||
Q_PROPERTY(bool selectionChanged READ selectionChanged WRITE setSelectionChanged NOTIFY selectionChangedChanged)
|
|
||||||
|
|
||||||
Q_PROPERTY(int majorVersion READ majorVersion WRITE setMajorVersion NOTIFY majorVersionChanged)
|
|
||||||
|
|
||||||
Q_PROPERTY(bool hasAliasExport READ hasAliasExport NOTIFY hasAliasExportChanged)
|
|
||||||
Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged)
|
|
||||||
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
|
|
||||||
Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged)
|
|
||||||
Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary WRITE setHasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
|
|
||||||
Q_PROPERTY(bool isQt6Project READ isQt6Project NOTIFY isQt6ProjectChanged)
|
|
||||||
|
|
||||||
Q_PROPERTY(QQmlPropertyMap *backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
MaterialEditorContextObject(QQuickWidget *widget, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
QUrl specificsUrl() const { return m_specificsUrl; }
|
|
||||||
QString specificQmlData() const {return m_specificQmlData; }
|
|
||||||
QQmlComponent *specificQmlComponent();
|
|
||||||
QString stateName() const { return m_stateName; }
|
|
||||||
QStringList allStateNames() const { return m_allStateNames; }
|
|
||||||
QStringList possibleTypes() const { return m_possibleTypes; }
|
|
||||||
int possibleTypeIndex() const { return m_possibleTypeIndex; }
|
|
||||||
|
|
||||||
bool isBaseState() const { return m_isBaseState; }
|
|
||||||
bool selectionChanged() const { return m_selectionChanged; }
|
|
||||||
|
|
||||||
QQmlPropertyMap *backendValues() const { return m_backendValues; }
|
|
||||||
|
|
||||||
Q_INVOKABLE QString convertColorToString(const QVariant &color);
|
|
||||||
Q_INVOKABLE QColor colorFromString(const QString &colorString);
|
|
||||||
|
|
||||||
Q_INVOKABLE void changeTypeName(const QString &typeName);
|
|
||||||
Q_INVOKABLE void insertKeyframe(const QString &propertyName);
|
|
||||||
|
|
||||||
Q_INVOKABLE void hideCursor();
|
|
||||||
Q_INVOKABLE void restoreCursor();
|
|
||||||
Q_INVOKABLE void holdCursorInPlace();
|
|
||||||
|
|
||||||
Q_INVOKABLE int devicePixelRatio();
|
|
||||||
|
|
||||||
Q_INVOKABLE QStringList allStatesForId(const QString &id);
|
|
||||||
|
|
||||||
Q_INVOKABLE bool isBlocked(const QString &propName) const;
|
|
||||||
Q_INVOKABLE void goIntoComponent();
|
|
||||||
|
|
||||||
Q_INVOKABLE QRect screenRect() const;
|
|
||||||
Q_INVOKABLE QPoint globalPos(const QPoint &point) const;
|
|
||||||
|
|
||||||
enum ToolBarAction {
|
|
||||||
ApplyToSelected = 0,
|
|
||||||
ApplyToSelectedAdd,
|
|
||||||
AddNewMaterial,
|
|
||||||
DeleteCurrentMaterial,
|
|
||||||
OpenMaterialBrowser
|
|
||||||
};
|
|
||||||
Q_ENUM(ToolBarAction)
|
|
||||||
|
|
||||||
int majorVersion() const;
|
|
||||||
void setMajorVersion(int majorVersion);
|
|
||||||
|
|
||||||
bool hasActiveTimeline() const;
|
|
||||||
void setHasActiveTimeline(bool b);
|
|
||||||
|
|
||||||
bool hasQuick3DImport() const;
|
|
||||||
void setHasQuick3DImport(bool b);
|
|
||||||
|
|
||||||
bool hasMaterialLibrary() const;
|
|
||||||
void setHasMaterialLibrary(bool b);
|
|
||||||
|
|
||||||
bool isQt6Project() const;
|
|
||||||
void setIsQt6Project(bool b);
|
|
||||||
|
|
||||||
bool hasModelSelection() const;
|
|
||||||
void setHasModelSelection(bool b);
|
|
||||||
|
|
||||||
bool hasAliasExport() const { return m_aliasExport; }
|
|
||||||
|
|
||||||
void setSelectedMaterial(const ModelNode &matNode);
|
|
||||||
|
|
||||||
void setSpecificsUrl(const QUrl &newSpecificsUrl);
|
|
||||||
void setSpecificQmlData(const QString &newSpecificQmlData);
|
|
||||||
void setStateName(const QString &newStateName);
|
|
||||||
void setAllStateNames(const QStringList &allStates);
|
|
||||||
void setPossibleTypes(const QStringList &types);
|
|
||||||
void setCurrentType(const QString &type);
|
|
||||||
void setIsBaseState(bool newIsBaseState);
|
|
||||||
void setSelectionChanged(bool newSelectionChanged);
|
|
||||||
void setBackendValues(QQmlPropertyMap *newBackendValues);
|
|
||||||
void setModel(QmlDesigner::Model *model);
|
|
||||||
|
|
||||||
void triggerSelectionChanged();
|
|
||||||
void setHasAliasExport(bool hasAliasExport);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void specificsUrlChanged();
|
|
||||||
void specificQmlDataChanged();
|
|
||||||
void specificQmlComponentChanged();
|
|
||||||
void stateNameChanged();
|
|
||||||
void allStateNamesChanged();
|
|
||||||
void possibleTypesChanged();
|
|
||||||
void possibleTypeIndexChanged();
|
|
||||||
void isBaseStateChanged();
|
|
||||||
void selectionChangedChanged();
|
|
||||||
void backendValuesChanged();
|
|
||||||
void majorVersionChanged();
|
|
||||||
void hasAliasExportChanged();
|
|
||||||
void hasActiveTimelineChanged();
|
|
||||||
void hasQuick3DImportChanged();
|
|
||||||
void hasMaterialLibraryChanged();
|
|
||||||
void hasModelSelectionChanged();
|
|
||||||
void isQt6ProjectChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void updatePossibleTypeIndex();
|
|
||||||
|
|
||||||
QUrl m_specificsUrl;
|
|
||||||
QString m_specificQmlData;
|
|
||||||
QQmlComponent *m_specificQmlComponent = nullptr;
|
|
||||||
QQuickWidget *m_quickWidget = nullptr;
|
|
||||||
|
|
||||||
QString m_stateName;
|
|
||||||
QStringList m_allStateNames;
|
|
||||||
QStringList m_possibleTypes;
|
|
||||||
int m_possibleTypeIndex = -1;
|
|
||||||
QString m_currentType;
|
|
||||||
|
|
||||||
int m_majorVersion = 1;
|
|
||||||
|
|
||||||
QQmlPropertyMap *m_backendValues = nullptr;
|
|
||||||
Model *m_model = nullptr;
|
|
||||||
|
|
||||||
QPoint m_lastPos;
|
|
||||||
|
|
||||||
bool m_isBaseState = false;
|
|
||||||
bool m_selectionChanged = false;
|
|
||||||
bool m_aliasExport = false;
|
|
||||||
bool m_hasActiveTimeline = false;
|
|
||||||
bool m_hasQuick3DImport = false;
|
|
||||||
bool m_hasMaterialLibrary = false;
|
|
||||||
bool m_hasModelSelection = false;
|
|
||||||
bool m_isQt6Project = false;
|
|
||||||
|
|
||||||
ModelNode m_selectedMaterial;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // QmlDesigner
|
|
@@ -1,47 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "materialeditordynamicpropertiesproxymodel.h"
|
|
||||||
|
|
||||||
#include <dynamicpropertiesmodel.h>
|
|
||||||
|
|
||||||
#include <materialeditorview.h>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
MaterialEditorDynamicPropertiesProxyModel::MaterialEditorDynamicPropertiesProxyModel(QObject *parent)
|
|
||||||
: DynamicPropertiesProxyModel(parent)
|
|
||||||
{
|
|
||||||
if (MaterialEditorView::instance())
|
|
||||||
initModel(MaterialEditorView::instance()->dynamicPropertiesModel());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType()
|
|
||||||
{
|
|
||||||
DynamicPropertiesProxyModel::registerDeclarativeType();
|
|
||||||
qmlRegisterType<MaterialEditorDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "MaterialEditorDynamicPropertiesModel");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,41 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "dynamicpropertiesproxymodel.h"
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class MaterialEditorDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit MaterialEditorDynamicPropertiesProxyModel(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
static void registerDeclarativeType();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,82 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
#include "materialeditorimageprovider.h"
|
|
||||||
|
|
||||||
#include "materialeditorview.h"
|
|
||||||
|
|
||||||
#include <QImage>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
MaterialEditorImageProvider::MaterialEditorImageProvider(MaterialEditorView *materialEditorView)
|
|
||||||
: QQuickImageProvider(Pixmap)
|
|
||||||
, m_delayTimer(new QTimer(this))
|
|
||||||
{
|
|
||||||
m_delayTimer->setInterval(500);
|
|
||||||
m_delayTimer->setSingleShot(true);
|
|
||||||
m_delayTimer->callOnTimeout([this] {
|
|
||||||
if (m_previewPixmap.size() != m_requestedSize)
|
|
||||||
emit this->requestPreview(m_requestedSize);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(this,
|
|
||||||
&MaterialEditorImageProvider::requestPreview,
|
|
||||||
materialEditorView,
|
|
||||||
&MaterialEditorView::handlePreviewSizeChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorImageProvider::setPixmap(const QPixmap &pixmap)
|
|
||||||
{
|
|
||||||
m_previewPixmap = pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap MaterialEditorImageProvider::requestPixmap(const QString &id,
|
|
||||||
QSize *size,
|
|
||||||
const QSize &requestedSize)
|
|
||||||
{
|
|
||||||
static QPixmap defaultPreview = QPixmap::fromImage(
|
|
||||||
QImage(":/materialeditor/images/defaultmaterialpreview.png"));
|
|
||||||
|
|
||||||
QPixmap pixmap{150, 150};
|
|
||||||
|
|
||||||
if (id == "preview") {
|
|
||||||
if (!m_previewPixmap.isNull()) {
|
|
||||||
pixmap = m_previewPixmap;
|
|
||||||
setRequestedSize(requestedSize);
|
|
||||||
} else {
|
|
||||||
if (requestedSize.isEmpty())
|
|
||||||
pixmap = defaultPreview;
|
|
||||||
else
|
|
||||||
pixmap = defaultPreview.scaled(requestedSize, Qt::KeepAspectRatio);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning() << __FUNCTION__ << "Unsupported image id:" << id;
|
|
||||||
pixmap.fill(Qt::red);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
*size = pixmap.size();
|
|
||||||
|
|
||||||
return pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \internal
|
|
||||||
* \brief Sets the requested size. If the requested size is not the same as the
|
|
||||||
* size of the m_previewPixmap, it will ask \l {MaterialEditorView} to provide
|
|
||||||
* an image with the requested size
|
|
||||||
* The requests are delayed until the requested size is stable.
|
|
||||||
*/
|
|
||||||
void MaterialEditorImageProvider::setRequestedSize(const QSize &requestedSize)
|
|
||||||
{
|
|
||||||
if (requestedSize.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_requestedSize = requestedSize;
|
|
||||||
|
|
||||||
if (m_previewPixmap.size() != requestedSize)
|
|
||||||
m_delayTimer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,37 +0,0 @@
|
|||||||
// Copyright (C) 2024 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QQuickImageProvider>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QTimer;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class MaterialEditorView;
|
|
||||||
|
|
||||||
class MaterialEditorImageProvider : public QQuickImageProvider
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MaterialEditorImageProvider(MaterialEditorView *materialEditorView);
|
|
||||||
|
|
||||||
void setPixmap(const QPixmap &pixmap);
|
|
||||||
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void requestPreview(QSize);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setRequestedSize(const QSize &requestedSize);
|
|
||||||
|
|
||||||
QPixmap m_previewPixmap;
|
|
||||||
QSize m_requestedSize;
|
|
||||||
QTimer *m_delayTimer = nullptr; // Delays the preview requests
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,299 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "materialeditorqmlbackend.h"
|
|
||||||
|
|
||||||
#include "materialeditorcontextobject.h"
|
|
||||||
#include "materialeditorimageprovider.h"
|
|
||||||
#include "materialeditortransaction.h"
|
|
||||||
|
|
||||||
#include <bindingproperty.h>
|
|
||||||
#include <nodemetainfo.h>
|
|
||||||
#include <propertyeditorqmlbackend.h>
|
|
||||||
#include <propertyeditorvalue.h>
|
|
||||||
#include <qmldesignerconstants.h>
|
|
||||||
#include <qmlobjectnode.h>
|
|
||||||
#include <qmltimeline.h>
|
|
||||||
#include <variantproperty.h>
|
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
|
||||||
#include <utils/algorithm.h>
|
|
||||||
#include <utils/environment.h>
|
|
||||||
#include <utils/fileutils.h>
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
|
||||||
#include <QQuickItem>
|
|
||||||
#include <QQuickWidget>
|
|
||||||
#include <QVector2D>
|
|
||||||
#include <QVector3D>
|
|
||||||
#include <QVector4D>
|
|
||||||
|
|
||||||
static QObject *variantToQObject(const QVariant &value)
|
|
||||||
{
|
|
||||||
if (value.typeId() == QMetaType::QObjectStar || value.typeId() > QMetaType::User)
|
|
||||||
return *(QObject **)value.constData();
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialEditor)
|
|
||||||
: m_quickWidget(Utils::makeUniqueObjectPtr<QQuickWidget>())
|
|
||||||
, m_materialEditorTransaction(std::make_unique<MaterialEditorTransaction>(materialEditor))
|
|
||||||
, m_contextObject(std::make_unique<MaterialEditorContextObject>(m_quickWidget.get()))
|
|
||||||
, m_materialEditorImageProvider(new MaterialEditorImageProvider(materialEditor))
|
|
||||||
{
|
|
||||||
m_quickWidget->setObjectName(Constants::OBJECT_NAME_MATERIAL_EDITOR);
|
|
||||||
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
|
||||||
m_quickWidget->engine()->addImportPath(PropertyEditorQmlBackend::propertyEditorResourcesPath() + "/imports");
|
|
||||||
m_quickWidget->engine()->addImageProvider("materialEditor", m_materialEditorImageProvider);
|
|
||||||
m_contextObject->setBackendValues(&m_backendValuesPropertyMap);
|
|
||||||
m_contextObject->setModel(materialEditor->model());
|
|
||||||
context()->setContextObject(m_contextObject.get());
|
|
||||||
context()->setContextProperty("hasMaterial", QVariant(false));
|
|
||||||
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
|
|
||||||
|
|
||||||
QObject::connect(&m_backendValuesPropertyMap, &DesignerPropertyMap::valueChanged,
|
|
||||||
materialEditor, &MaterialEditorView::changeValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialEditorQmlBackend::~MaterialEditorQmlBackend()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyName MaterialEditorQmlBackend::auxNamePostFix(PropertyNameView propertyName)
|
|
||||||
{
|
|
||||||
return propertyName + "__AUX";
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
|
|
||||||
PropertyNameView name,
|
|
||||||
const QVariant &value,
|
|
||||||
MaterialEditorView *materialEditor)
|
|
||||||
{
|
|
||||||
PropertyName propertyName(name.toByteArray());
|
|
||||||
propertyName.replace('.', '_');
|
|
||||||
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(backendValuesPropertyMap().value(QString::fromUtf8(propertyName))));
|
|
||||||
if (!valueObject) {
|
|
||||||
valueObject = new PropertyEditorValue(&backendValuesPropertyMap());
|
|
||||||
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
|
|
||||||
QObject::connect(valueObject, &PropertyEditorValue::expressionChanged, materialEditor, &MaterialEditorView::changeExpression);
|
|
||||||
QObject::connect(valueObject, &PropertyEditorValue::exportPropertyAsAliasRequested, materialEditor, &MaterialEditorView::exportPropertyAsAlias);
|
|
||||||
QObject::connect(valueObject, &PropertyEditorValue::removeAliasExportRequested, materialEditor, &MaterialEditorView::removeAliasExport);
|
|
||||||
backendValuesPropertyMap().insert(QString::fromUtf8(propertyName), QVariant::fromValue(valueObject));
|
|
||||||
}
|
|
||||||
valueObject->setName(name);
|
|
||||||
valueObject->setModelNode(qmlObjectNode);
|
|
||||||
|
|
||||||
if (qmlObjectNode.propertyAffectedByCurrentState(name) && !(qmlObjectNode.modelNode().property(name).isBindingProperty()))
|
|
||||||
valueObject->setValue(qmlObjectNode.modelValue(name));
|
|
||||||
else
|
|
||||||
valueObject->setValue(value);
|
|
||||||
|
|
||||||
if (propertyName != "id" && qmlObjectNode.currentState().isBaseState()
|
|
||||||
&& qmlObjectNode.modelNode().property(propertyName).isBindingProperty()) {
|
|
||||||
valueObject->setExpression(qmlObjectNode.modelNode().bindingProperty(propertyName).expression());
|
|
||||||
} else {
|
|
||||||
if (qmlObjectNode.hasBindingProperty(name))
|
|
||||||
valueObject->setExpression(qmlObjectNode.expression(name));
|
|
||||||
else
|
|
||||||
valueObject->setExpression(qmlObjectNode.instanceValue(name).toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::setValue(const QmlObjectNode &,
|
|
||||||
PropertyNameView name,
|
|
||||||
const QVariant &value)
|
|
||||||
{
|
|
||||||
// Vector*D values need to be split into their subcomponents
|
|
||||||
if (value.typeId() == QMetaType::QVector2D) {
|
|
||||||
const char *suffix[2] = {"_x", "_y"};
|
|
||||||
auto vecValue = value.value<QVector2D>();
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
|
||||||
PropertyName subPropName(name.size() + 2, '\0');
|
|
||||||
subPropName.replace(0, name.size(), name);
|
|
||||||
subPropName.replace(name.size(), 2, suffix[i]);
|
|
||||||
auto propertyValue = qobject_cast<PropertyEditorValue *>(variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(subPropName))));
|
|
||||||
if (propertyValue)
|
|
||||||
propertyValue->setValue(QVariant(vecValue[i]));
|
|
||||||
}
|
|
||||||
} else if (value.typeId() == QMetaType::QVector3D) {
|
|
||||||
const char *suffix[3] = {"_x", "_y", "_z"};
|
|
||||||
auto vecValue = value.value<QVector3D>();
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
PropertyName subPropName(name.size() + 2, '\0');
|
|
||||||
subPropName.replace(0, name.size(), name);
|
|
||||||
subPropName.replace(name.size(), 2, suffix[i]);
|
|
||||||
auto propertyValue = qobject_cast<PropertyEditorValue *>(variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(subPropName))));
|
|
||||||
if (propertyValue)
|
|
||||||
propertyValue->setValue(QVariant(vecValue[i]));
|
|
||||||
}
|
|
||||||
} else if (value.typeId() == QMetaType::QVector4D) {
|
|
||||||
const char *suffix[4] = {"_x", "_y", "_z", "_w"};
|
|
||||||
auto vecValue = value.value<QVector4D>();
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
PropertyName subPropName(name.size() + 2, '\0');
|
|
||||||
subPropName.replace(0, name.size(), name);
|
|
||||||
subPropName.replace(name.size(), 2, suffix[i]);
|
|
||||||
auto propertyValue = qobject_cast<PropertyEditorValue *>(
|
|
||||||
variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(subPropName))));
|
|
||||||
if (propertyValue)
|
|
||||||
propertyValue->setValue(QVariant(vecValue[i]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PropertyName propertyName = name.toByteArray();
|
|
||||||
propertyName.replace('.', '_');
|
|
||||||
auto propertyValue = qobject_cast<PropertyEditorValue *>(variantToQObject(m_backendValuesPropertyMap.value(QString::fromUtf8(propertyName))));
|
|
||||||
if (propertyValue)
|
|
||||||
propertyValue->setValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::setExpression(PropertyNameView propName, const QString &exp)
|
|
||||||
{
|
|
||||||
PropertyEditorValue *propertyValue = propertyValueForName(QString::fromUtf8(propName));
|
|
||||||
if (propertyValue)
|
|
||||||
propertyValue->setExpression(exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
QQmlContext *MaterialEditorQmlBackend::context() const
|
|
||||||
{
|
|
||||||
return m_quickWidget->rootContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialEditorContextObject *MaterialEditorQmlBackend::contextObject() const
|
|
||||||
{
|
|
||||||
return m_contextObject.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
QQuickWidget *MaterialEditorQmlBackend::widget() const
|
|
||||||
{
|
|
||||||
return m_quickWidget.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::setSource(const QUrl &url)
|
|
||||||
{
|
|
||||||
m_quickWidget->setSource(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
QmlAnchorBindingProxy &MaterialEditorQmlBackend::backendAnchorBinding()
|
|
||||||
{
|
|
||||||
return m_backendAnchorBinding;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::updateMaterialPreview(const QPixmap &pixmap)
|
|
||||||
{
|
|
||||||
m_materialEditorImageProvider->setPixmap(pixmap);
|
|
||||||
QMetaObject::invokeMethod(m_quickWidget->rootObject(), "refreshPreview");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::refreshBackendModel()
|
|
||||||
{
|
|
||||||
m_backendModelNode.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
DesignerPropertyMap &MaterialEditorQmlBackend::backendValuesPropertyMap()
|
|
||||||
{
|
|
||||||
return m_backendValuesPropertyMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialEditorTransaction *MaterialEditorQmlBackend::materialEditorTransaction() const
|
|
||||||
{
|
|
||||||
return m_materialEditorTransaction.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyEditorValue *MaterialEditorQmlBackend::propertyValueForName(const QString &propertyName)
|
|
||||||
{
|
|
||||||
return qobject_cast<PropertyEditorValue *>(variantToQObject(backendValuesPropertyMap().value(propertyName)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::setup(const QmlObjectNode &selectedMaterialNode, const QString &stateName,
|
|
||||||
const QUrl &qmlSpecificsFile, MaterialEditorView *materialEditor)
|
|
||||||
{
|
|
||||||
if (selectedMaterialNode.isValid()) {
|
|
||||||
m_contextObject->setModel(materialEditor->model());
|
|
||||||
|
|
||||||
for (const auto &property : selectedMaterialNode.modelNode().metaInfo().properties()) {
|
|
||||||
createPropertyEditorValue(selectedMaterialNode,
|
|
||||||
property.name(),
|
|
||||||
selectedMaterialNode.instanceValue(property.name()),
|
|
||||||
materialEditor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// model node
|
|
||||||
m_backendModelNode.setup(selectedMaterialNode);
|
|
||||||
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
|
|
||||||
context()->setContextProperty("hasMaterial", QVariant(true));
|
|
||||||
|
|
||||||
// className
|
|
||||||
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
|
|
||||||
m_backendValuesPropertyMap.value(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)));
|
|
||||||
if (!valueObject)
|
|
||||||
valueObject = new PropertyEditorValue(&m_backendValuesPropertyMap);
|
|
||||||
valueObject->setName(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY);
|
|
||||||
valueObject->setModelNode(selectedMaterialNode.modelNode());
|
|
||||||
valueObject->setValue(m_backendModelNode.simplifiedTypeName());
|
|
||||||
QObject::connect(valueObject,
|
|
||||||
&PropertyEditorValue::valueChanged,
|
|
||||||
&backendValuesPropertyMap(),
|
|
||||||
&DesignerPropertyMap::valueChanged);
|
|
||||||
m_backendValuesPropertyMap.insert(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY,
|
|
||||||
QVariant::fromValue(valueObject));
|
|
||||||
|
|
||||||
// anchors
|
|
||||||
m_backendAnchorBinding.setup(selectedMaterialNode.modelNode());
|
|
||||||
context()->setContextProperties(QVector<QQmlContext::PropertyPair>{
|
|
||||||
{{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
|
|
||||||
{{"transaction"}, QVariant::fromValue(m_materialEditorTransaction.get())}});
|
|
||||||
|
|
||||||
contextObject()->setSpecificsUrl(qmlSpecificsFile);
|
|
||||||
contextObject()->setStateName(stateName);
|
|
||||||
|
|
||||||
QStringList stateNames = selectedMaterialNode.allStateNames();
|
|
||||||
stateNames.prepend("base state");
|
|
||||||
contextObject()->setAllStateNames(stateNames);
|
|
||||||
contextObject()->setSelectedMaterial(selectedMaterialNode);
|
|
||||||
contextObject()->setIsBaseState(selectedMaterialNode.isInBaseState());
|
|
||||||
contextObject()->setHasAliasExport(selectedMaterialNode.isAliasExported());
|
|
||||||
contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(selectedMaterialNode.view()));
|
|
||||||
|
|
||||||
contextObject()->setSelectionChanged(false);
|
|
||||||
|
|
||||||
#ifndef QDS_USE_PROJECTSTORAGE
|
|
||||||
NodeMetaInfo metaInfo = selectedMaterialNode.modelNode().metaInfo();
|
|
||||||
contextObject()->setMajorVersion(metaInfo.isValid() ? metaInfo.majorVersion() : -1);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
context()->setContextProperty("hasMaterial", QVariant(false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
QString MaterialEditorQmlBackend::materialEditorResourcesPath()
|
|
||||||
{
|
|
||||||
#ifdef SHARE_QML_PATH
|
|
||||||
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
|
|
||||||
return QLatin1String(SHARE_QML_PATH) + "/materialEditorQmlSources";
|
|
||||||
#endif
|
|
||||||
return Core::ICore::resourcePath("qmldesigner/materialEditorQmlSources").toUrlishString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::emitSelectionToBeChanged()
|
|
||||||
{
|
|
||||||
m_backendModelNode.emitSelectionToBeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::emitSelectionChanged()
|
|
||||||
{
|
|
||||||
m_backendModelNode.emitSelectionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorQmlBackend::setValueforAuxiliaryProperties(const QmlObjectNode &qmlObjectNode,
|
|
||||||
AuxiliaryDataKeyView key)
|
|
||||||
{
|
|
||||||
const PropertyName propertyName = auxNamePostFix(key.name.toByteArray());
|
|
||||||
setValue(qmlObjectNode, propertyName, qmlObjectNode.modelNode().auxiliaryDataWithDefault(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,80 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "designerpropertymap.h"
|
|
||||||
#include "qmlanchorbindingproxy.h"
|
|
||||||
#include "qmlmodelnodeproxy.h"
|
|
||||||
|
|
||||||
#include <utils/uniqueobjectptr.h>
|
|
||||||
|
|
||||||
#include <nodemetainfo.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class PropertyEditorValue;
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QQuickWidget;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class MaterialEditorContextObject;
|
|
||||||
class MaterialEditorImageProvider;
|
|
||||||
class MaterialEditorTransaction;
|
|
||||||
class MaterialEditorView;
|
|
||||||
|
|
||||||
class MaterialEditorQmlBackend
|
|
||||||
{
|
|
||||||
Q_DISABLE_COPY(MaterialEditorQmlBackend)
|
|
||||||
|
|
||||||
public:
|
|
||||||
MaterialEditorQmlBackend(MaterialEditorView *materialEditor);
|
|
||||||
~MaterialEditorQmlBackend();
|
|
||||||
|
|
||||||
void setup(const QmlObjectNode &selectedMaterialNode, const QString &stateName, const QUrl &qmlSpecificsFile,
|
|
||||||
MaterialEditorView *materialEditor);
|
|
||||||
void setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value);
|
|
||||||
void setExpression(PropertyNameView propName, const QString &exp);
|
|
||||||
|
|
||||||
QQmlContext *context() const;
|
|
||||||
MaterialEditorContextObject *contextObject() const;
|
|
||||||
QQuickWidget *widget() const;
|
|
||||||
void setSource(const QUrl &url);
|
|
||||||
QmlAnchorBindingProxy &backendAnchorBinding();
|
|
||||||
void updateMaterialPreview(const QPixmap &pixmap);
|
|
||||||
void refreshBackendModel();
|
|
||||||
DesignerPropertyMap &backendValuesPropertyMap();
|
|
||||||
MaterialEditorTransaction *materialEditorTransaction() const;
|
|
||||||
|
|
||||||
PropertyEditorValue *propertyValueForName(const QString &propertyName);
|
|
||||||
|
|
||||||
static QString materialEditorResourcesPath();
|
|
||||||
|
|
||||||
void emitSelectionToBeChanged();
|
|
||||||
void emitSelectionChanged();
|
|
||||||
|
|
||||||
void setValueforAuxiliaryProperties(const QmlObjectNode &qmlObjectNode, AuxiliaryDataKeyView key);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
|
|
||||||
PropertyNameView name,
|
|
||||||
const QVariant &value,
|
|
||||||
MaterialEditorView *materialEditor);
|
|
||||||
PropertyName auxNamePostFix(PropertyNameView propertyName);
|
|
||||||
|
|
||||||
// to avoid a crash while destructing DesignerPropertyMap in the QQmlData
|
|
||||||
// this needs be destructed after m_quickWidget->engine() is destructed
|
|
||||||
DesignerPropertyMap m_backendValuesPropertyMap;
|
|
||||||
|
|
||||||
Utils::UniqueObjectPtr<QQuickWidget> m_quickWidget = nullptr;
|
|
||||||
QmlAnchorBindingProxy m_backendAnchorBinding;
|
|
||||||
QmlModelNodeProxy m_backendModelNode;
|
|
||||||
std::unique_ptr<MaterialEditorTransaction> m_materialEditorTransaction;
|
|
||||||
std::unique_ptr<MaterialEditorContextObject> m_contextObject;
|
|
||||||
QPointer<MaterialEditorImageProvider> m_materialEditorImageProvider;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
@@ -1,51 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "materialeditortransaction.h"
|
|
||||||
|
|
||||||
#include <QTimerEvent>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
MaterialEditorTransaction::MaterialEditorTransaction(QmlDesigner::MaterialEditorView *materialEditor)
|
|
||||||
: QObject(materialEditor),
|
|
||||||
m_materialEditor(materialEditor)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorTransaction::start()
|
|
||||||
{
|
|
||||||
if (!m_materialEditor->model())
|
|
||||||
return;
|
|
||||||
if (m_rewriterTransaction.isValid())
|
|
||||||
m_rewriterTransaction.commit();
|
|
||||||
m_rewriterTransaction = m_materialEditor->beginRewriterTransaction(QByteArrayLiteral("MaterialEditorTransaction::start"));
|
|
||||||
m_timerId = startTimer(10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorTransaction::end()
|
|
||||||
{
|
|
||||||
if (m_rewriterTransaction.isValid() && m_materialEditor->model()) {
|
|
||||||
killTimer(m_timerId);
|
|
||||||
m_rewriterTransaction.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MaterialEditorTransaction::active() const
|
|
||||||
{
|
|
||||||
return m_rewriterTransaction.isValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialEditorTransaction::timerEvent(QTimerEvent *timerEvent)
|
|
||||||
{
|
|
||||||
if (timerEvent->timerId() != m_timerId)
|
|
||||||
return;
|
|
||||||
killTimer(timerEvent->timerId());
|
|
||||||
if (m_rewriterTransaction.isValid())
|
|
||||||
m_rewriterTransaction.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
||||||
|
|
@@ -1,32 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "materialeditorview.h"
|
|
||||||
#include "rewritertransaction.h"
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class MaterialEditorTransaction : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
MaterialEditorTransaction(MaterialEditorView *materialEditor);
|
|
||||||
|
|
||||||
Q_INVOKABLE void start();
|
|
||||||
Q_INVOKABLE void end();
|
|
||||||
|
|
||||||
Q_INVOKABLE bool active() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void timerEvent(QTimerEvent *event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
MaterialEditorView *m_materialEditor = nullptr;
|
|
||||||
RewriterTransaction m_rewriterTransaction;
|
|
||||||
int m_timerId = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,154 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <abstractview.h>
|
|
||||||
|
|
||||||
#include <propertyeditorcomponentgenerator.h>
|
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QSize>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QShortcut;
|
|
||||||
class QStackedWidget;
|
|
||||||
class QUrl;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
|
||||||
|
|
||||||
class DynamicPropertiesModel;
|
|
||||||
class ItemLibraryInfo;
|
|
||||||
class MaterialEditorQmlBackend;
|
|
||||||
class QmlObjectNode;
|
|
||||||
class SourcePathCacheInterface;
|
|
||||||
|
|
||||||
class MaterialEditorView : public AbstractView
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
MaterialEditorView(ExternalDependenciesInterface &externalDependencies);
|
|
||||||
~MaterialEditorView() override;
|
|
||||||
|
|
||||||
bool hasWidget() const override;
|
|
||||||
WidgetInfo widgetInfo() override;
|
|
||||||
|
|
||||||
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
|
|
||||||
const QList<ModelNode> &lastSelectedNodeList) override;
|
|
||||||
|
|
||||||
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
|
|
||||||
|
|
||||||
void modelAttached(Model *model) override;
|
|
||||||
void modelAboutToBeDetached(Model *model) override;
|
|
||||||
|
|
||||||
void variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags propertyChange) override;
|
|
||||||
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags propertyChange) override;
|
|
||||||
void auxiliaryDataChanged(const ModelNode &node,
|
|
||||||
AuxiliaryDataKeyView key,
|
|
||||||
const QVariant &data) override;
|
|
||||||
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
|
|
||||||
|
|
||||||
void resetView();
|
|
||||||
void currentStateChanged(const ModelNode &node) override;
|
|
||||||
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
|
|
||||||
|
|
||||||
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
|
|
||||||
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
|
|
||||||
void modelNodePreviewPixmapChanged(const ModelNode &node,
|
|
||||||
const QPixmap &pixmap,
|
|
||||||
const QByteArray &requestId) override;
|
|
||||||
void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
|
|
||||||
|
|
||||||
void nodeReparented(const ModelNode &node,
|
|
||||||
const NodeAbstractProperty &newPropertyParent,
|
|
||||||
const NodeAbstractProperty &oldPropertyParent,
|
|
||||||
AbstractView::PropertyChangeFlags propertyChange) override;
|
|
||||||
|
|
||||||
void nodeIdChanged(const ModelNode &node, const QString &newId, const QString &oldId) override;
|
|
||||||
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
|
|
||||||
void nodeRemoved(const ModelNode &removedNode,
|
|
||||||
const NodeAbstractProperty &parentProperty,
|
|
||||||
PropertyChangeFlags propertyChange) override;
|
|
||||||
|
|
||||||
void dragStarted(QMimeData *mimeData) override;
|
|
||||||
void dragEnded() override;
|
|
||||||
|
|
||||||
void changeValue(const QString &name);
|
|
||||||
void changeExpression(const QString &name);
|
|
||||||
void exportPropertyAsAlias(const QString &name);
|
|
||||||
void removeAliasExport(const QString &name);
|
|
||||||
|
|
||||||
bool locked() const;
|
|
||||||
|
|
||||||
void currentTimelineChanged(const ModelNode &node) override;
|
|
||||||
|
|
||||||
void refreshMetaInfos(const TypeIds &deletedTypeIds) override;
|
|
||||||
|
|
||||||
DynamicPropertiesModel *dynamicPropertiesModel() const;
|
|
||||||
|
|
||||||
static MaterialEditorView *instance();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void handleToolBarAction(int action);
|
|
||||||
void handlePreviewEnvChanged(const QString &envAndValue);
|
|
||||||
void handlePreviewModelChanged(const QString &modelStr);
|
|
||||||
void handlePreviewSizeChanged(const QSizeF &size);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void timerEvent(QTimerEvent *event) override;
|
|
||||||
void setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value);
|
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void reloadQml();
|
|
||||||
void highlightSupportedProperties(bool highlight = true);
|
|
||||||
|
|
||||||
void requestPreviewRender();
|
|
||||||
|
|
||||||
void setupQmlBackend();
|
|
||||||
MaterialEditorQmlBackend *getQmlBackend(const QUrl &qmlFileUrl);
|
|
||||||
QUrl getPaneUrl();
|
|
||||||
void setupCurrentQmlBackend(const ModelNode &selectedNode,
|
|
||||||
const QUrl &qmlSpecificsFile,
|
|
||||||
const QString &specificQmlData);
|
|
||||||
void setupWidget();
|
|
||||||
|
|
||||||
void commitVariantValueToModel(PropertyNameView propertyName, const QVariant &value);
|
|
||||||
void commitAuxValueToModel(PropertyNameView propertyName, const QVariant &value);
|
|
||||||
void removePropertyFromModel(PropertyNameView propertyName);
|
|
||||||
void renameMaterial(ModelNode &material, const QString &newName);
|
|
||||||
void duplicateMaterial(const ModelNode &material);
|
|
||||||
|
|
||||||
bool noValidSelection() const;
|
|
||||||
|
|
||||||
void initPreviewData();
|
|
||||||
void updatePossibleTypes();
|
|
||||||
void asyncResetView();
|
|
||||||
|
|
||||||
ModelNode m_selectedMaterial;
|
|
||||||
QShortcut *m_updateShortcut = nullptr;
|
|
||||||
int m_timerId = 0;
|
|
||||||
QStackedWidget *m_stackedWidget = nullptr;
|
|
||||||
QHash<QString, MaterialEditorQmlBackend *> m_qmlBackendHash;
|
|
||||||
MaterialEditorQmlBackend *m_qmlBackEnd = nullptr;
|
|
||||||
PropertyComponentGenerator m_propertyComponentGenerator;
|
|
||||||
PropertyEditorComponentGenerator m_propertyEditorComponentGenerator{m_propertyComponentGenerator};
|
|
||||||
bool m_locked = false;
|
|
||||||
bool m_setupCompleted = false;
|
|
||||||
bool m_hasQuick3DImport = false;
|
|
||||||
bool m_hasMaterialRoot = false;
|
|
||||||
bool m_initializingPreviewData = false;
|
|
||||||
bool m_textureAboutToBeRemoved = false;
|
|
||||||
ModelNode m_newSelectedMaterial;
|
|
||||||
bool m_selectedMaterialChanged = false;
|
|
||||||
QSize m_previewSize;
|
|
||||||
QByteArray m_previewRequestId;
|
|
||||||
|
|
||||||
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
|
|
||||||
DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -32,7 +32,7 @@ QPixmap InstanceImageProvider::requestPixmap(const QString &id, QSize *size, con
|
|||||||
{
|
{
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
static const QPixmap defaultImage = QPixmap::fromImage(
|
static const QPixmap defaultImage = QPixmap::fromImage(
|
||||||
QImage(":/materialeditor/images/defaultmaterialpreview.png"));
|
QImage(":/propertyeditor/images/defaultmaterialpreview.png"));
|
||||||
|
|
||||||
if (id != "preview")
|
if (id != "preview")
|
||||||
return defaultImage;
|
return defaultImage;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/materialeditor">
|
<qresource prefix="/propertyeditor">
|
||||||
<file>images/defaultmaterialpreview.png</file>
|
<file>images/defaultmaterialpreview.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
@@ -1160,6 +1160,18 @@ void PropertyEditorView::setActiveNodeToSelection()
|
|||||||
setActiveNode(node);
|
setActiveNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropertyEditorView::forceSelection(const ModelNode &node)
|
||||||
|
{
|
||||||
|
if (node == activeNode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_isSelectionLocked)
|
||||||
|
setActiveNode(node);
|
||||||
|
ModelNode(node).selectNode();
|
||||||
|
|
||||||
|
resetView();
|
||||||
|
}
|
||||||
|
|
||||||
bool PropertyEditorView::hasWidget() const
|
bool PropertyEditorView::hasWidget() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -1260,6 +1272,17 @@ void PropertyEditorView::importsChanged(const Imports &addedImports, const Impor
|
|||||||
m_qmlBackEndForCurrentType->contextObject()->setHasQuick3DImport(true);
|
m_qmlBackEndForCurrentType->contextObject()->setHasQuick3DImport(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropertyEditorView::customNotification([[maybe_unused]] const AbstractView *view,
|
||||||
|
const QString &identifier,
|
||||||
|
const QList<ModelNode> &nodeList,
|
||||||
|
[[maybe_unused]] const QList<QVariant> &data)
|
||||||
|
{
|
||||||
|
if (identifier == "force_editing_node") {
|
||||||
|
if (!nodeList.isEmpty())
|
||||||
|
forceSelection(nodeList.first());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PropertyEditorView::modelNodePreviewPixmapChanged(const ModelNode &node,
|
void PropertyEditorView::modelNodePreviewPixmapChanged(const ModelNode &node,
|
||||||
const QPixmap &pixmap,
|
const QPixmap &pixmap,
|
||||||
const QByteArray &requestId)
|
const QByteArray &requestId)
|
||||||
|
@@ -83,6 +83,10 @@ public:
|
|||||||
const QByteArray &requestId) override;
|
const QByteArray &requestId) override;
|
||||||
|
|
||||||
void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
|
void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
|
||||||
|
void customNotification(const AbstractView *view,
|
||||||
|
const QString &identifier,
|
||||||
|
const QList<ModelNode> &nodeList,
|
||||||
|
const QList<QVariant> &data) override;
|
||||||
|
|
||||||
void dragStarted(QMimeData *mimeData) override;
|
void dragStarted(QMimeData *mimeData) override;
|
||||||
void dragEnded() override;
|
void dragEnded() override;
|
||||||
@@ -123,6 +127,7 @@ private: //functions
|
|||||||
|
|
||||||
void select();
|
void select();
|
||||||
void setActiveNodeToSelection();
|
void setActiveNodeToSelection();
|
||||||
|
void forceSelection(const ModelNode &node);
|
||||||
|
|
||||||
void delayedResetView();
|
void delayedResetView();
|
||||||
void setupQmlBackend();
|
void setupQmlBackend();
|
||||||
|
@@ -19,7 +19,8 @@ void TextureEditorTransaction::start()
|
|||||||
return;
|
return;
|
||||||
if (m_rewriterTransaction.isValid())
|
if (m_rewriterTransaction.isValid())
|
||||||
m_rewriterTransaction.commit();
|
m_rewriterTransaction.commit();
|
||||||
m_rewriterTransaction = m_textureEditor->beginRewriterTransaction(QByteArrayLiteral("MaterialEditorTransaction::start"));
|
m_rewriterTransaction = m_textureEditor->beginRewriterTransaction(
|
||||||
|
QByteArrayLiteral("TextureEditorTransaction::start"));
|
||||||
m_timerId = startTimer(10000);
|
m_timerId = startTimer(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -559,9 +559,8 @@ void TextureEditorView::commitAuxValueToModel(PropertyNameView propertyName, con
|
|||||||
void TextureEditorView::removePropertyFromModel(PropertyNameView propertyName)
|
void TextureEditorView::removePropertyFromModel(PropertyNameView propertyName)
|
||||||
{
|
{
|
||||||
m_locked = true;
|
m_locked = true;
|
||||||
executeInTransaction("MaterialEditorView:removePropertyFromModel", [&] {
|
executeInTransaction(__FUNCTION__,
|
||||||
QmlObjectNode(m_selectedTexture).removeProperty(propertyName);
|
[&] { QmlObjectNode(m_selectedTexture).removeProperty(propertyName); });
|
||||||
});
|
|
||||||
m_locked = false;
|
m_locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -512,8 +512,12 @@ void DesignModeWidget::setup()
|
|||||||
|
|
||||||
static bool isMcuDisabledView(const QString viewId)
|
static bool isMcuDisabledView(const QString viewId)
|
||||||
{
|
{
|
||||||
static const QStringList mcuDisabledViews = {"Editor3D", "MaterialEditor", "MaterialBrowser",
|
static const QStringList mcuDisabledViews = {
|
||||||
"TextureEditor", "EffectComposer"};
|
"Editor3D",
|
||||||
|
"MaterialBrowser",
|
||||||
|
"TextureEditor",
|
||||||
|
"EffectComposer",
|
||||||
|
};
|
||||||
return mcuDisabledViews.contains(viewId);
|
return mcuDisabledViews.contains(viewId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -124,7 +124,6 @@ inline constexpr char EVENT_EFFECTCOMPOSER_TIME[] = "effectComposerTime";
|
|||||||
inline constexpr char EVENT_ITEMLIBRARY_TIME[] = "itemLibrary";
|
inline constexpr char EVENT_ITEMLIBRARY_TIME[] = "itemLibrary";
|
||||||
inline constexpr char EVENT_TRANSLATIONVIEW_TIME[] = "translationView";
|
inline constexpr char EVENT_TRANSLATIONVIEW_TIME[] = "translationView";
|
||||||
inline constexpr char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView";
|
inline constexpr char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView";
|
||||||
inline constexpr char EVENT_MATERIALEDITOR_TIME[] = "materialEditor";
|
|
||||||
inline constexpr char EVENT_MATERIALBROWSER_TIME[] = "materialBrowser";
|
inline constexpr char EVENT_MATERIALBROWSER_TIME[] = "materialBrowser";
|
||||||
inline constexpr char EVENT_CONTENTLIBRARY_TIME[] = "contentLibrary";
|
inline constexpr char EVENT_CONTENTLIBRARY_TIME[] = "contentLibrary";
|
||||||
inline constexpr char EVENT_INSIGHT_TIME[] = "insight";
|
inline constexpr char EVENT_INSIGHT_TIME[] = "insight";
|
||||||
@@ -177,7 +176,6 @@ inline constexpr char OBJECT_NAME_COMPONENT_LIBRARY[] = "QQuickWidgetComponentLi
|
|||||||
inline constexpr char OBJECT_NAME_DESIGN_SYSTEM[] = "QQuickWidgetDesignSystem";
|
inline constexpr char OBJECT_NAME_DESIGN_SYSTEM[] = "QQuickWidgetDesignSystem";
|
||||||
inline constexpr char OBJECT_NAME_EFFECT_COMPOSER[] = "QQuickWidgetEffectComposer";
|
inline constexpr char OBJECT_NAME_EFFECT_COMPOSER[] = "QQuickWidgetEffectComposer";
|
||||||
inline constexpr char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser";
|
inline constexpr char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser";
|
||||||
inline constexpr char OBJECT_NAME_MATERIAL_EDITOR[] = "QQuickWidgetMaterialEditor";
|
|
||||||
inline constexpr char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";
|
inline constexpr char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";
|
||||||
inline constexpr char OBJECT_NAME_STATES_EDITOR[] = "QQuickWidgetStatesEditor";
|
inline constexpr char OBJECT_NAME_STATES_EDITOR[] = "QQuickWidgetStatesEditor";
|
||||||
inline constexpr char OBJECT_NAME_TEXTURE_EDITOR[] = "QQuickWidgetTextureEditor";
|
inline constexpr char OBJECT_NAME_TEXTURE_EDITOR[] = "QQuickWidgetTextureEditor";
|
||||||
|
Reference in New Issue
Block a user