| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- // 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.Window
- import QtQuick.Controls
- import QtQuick.Layouts
- import QtQuick.Dialogs
- import QtCore
- import QtQuick3D.MaterialEditor
- ApplicationWindow {
- id: window
- height: 720
- width: 1024
- visible: true
- title: qsTr("Custom Material Editor")
- // Context property (see main.cpp)
- property url projectFolder: _qtProjectDir // qmllint disable unqualified
- Settings {
- id: settings
- property alias windowX: window.x
- property alias windowY: window.y
- property alias windowWidth: window.width
- property alias windowHeight: window.height
- property alias windowVisibility: window.visibility
- }
- Component.onCompleted: {
- mainSplitView.restoreState(settings.value("ui/mainSplitView"))
- editorView.restoreState(settings.value("ui/editorView"))
- }
- Component.onDestruction: {
- settings.setValue("ui/mainSplitView", mainSplitView.saveState())
- settings.setValue("ui/editorView", editorView.saveState())
- }
- QtObject {
- id: resourceStore
- objectName: "QtQuick3DResourceStorePrivate"
- }
- FileDialog {
- id: openMaterialDialog
- title: "Open a Material Project File"
- nameFilters: [ "Material Editor Project (*.qmp)"]
- currentFolder: window.projectFolder
- onAccepted: {
- if (openMaterialDialog.selectedFile !== null)
- materialAdapter.loadMaterial(openMaterialDialog.selectedFile);
- }
- }
- FileDialog {
- id: saveAsDialog
- fileMode: FileDialog.SaveFile
- currentFolder: window.projectFolder
- nameFilters: [ "Material Editor Project (*.qmp)"]
- onAccepted: materialAdapter.saveMaterial(selectedFile)
- }
- FileDialog {
- id: fragmentShaderImportDialog
- title: "Fragment Shader to import"
- nameFilters: [ "Fragment Shader (*.frag *.fs *.glsl)" ]
- currentFolder: window.projectFolder
- onAccepted: {
- if (fragmentShaderImportDialog.selectedFile !== null) {
- materialAdapter.importFragmentShader(fragmentShaderImportDialog.selectedFile)
- }
- }
- }
- FileDialog {
- id: vertexShaderImportDialog
- title: "Vertex Shader to import"
- nameFilters: [ "Vertex Shader (*.vert *.vs *.glsl)" ]
- currentFolder: window.projectFolder
- onAccepted: {
- if (vertexShaderImportDialog.selectedFile !== null) {
- materialAdapter.importVertexShader(vertexShaderImportDialog.selectedFile)
- }
- }
- }
- FileDialog {
- id: saveCompFileDialog
- title: "Choose file"
- nameFilters: [ "QML Componen (*.qml)" ]
- fileMode: FileDialog.SaveFile
- currentFolder: window.projectFolder
- onAccepted: {
- if (selectedFile !== null)
- componentFilePath.text = selectedFile
- }
- }
- RegularExpressionValidator {
- id: nameValidator
- regularExpression: /[a-zA-Z0-9_-]*/
- }
- Dialog {
- id: exportMaterialDialog
- title: "Export material"
- anchors.centerIn: parent
- ColumnLayout {
- id: exportFiles
- anchors.fill: parent
- spacing: 1
- RowLayout {
- Text {
- text: qsTr("Component")
- color: palette.text
- }
- TextField {
- id: componentFilePath
- readOnly: true
- }
- Button {
- text: qsTr("Choose...")
- onClicked: {
- saveCompFileDialog.open()
- exportMaterialDialog.aboutToHide()
- }
- }
- }
- RowLayout {
- Text {
- text: qsTr("Vertex:")
- color: palette.text
- }
- TextField {
- id: vertexFilename
- enabled: (editorView.vertexEditor.text !== "")
- validator: nameValidator
- }
- }
- RowLayout {
- Text {
- text: qsTr("Fragment:")
- color: palette.text
- }
- TextField {
- id: fragmentFilename
- enabled: (editorView.fragmentEditor.text !== "")
- validator: nameValidator
- }
- }
- DialogButtonBox {
- Button {
- text: qsTr("Export")
- enabled: (componentFilePath.text !== "" && (!vertexFilename.enabled || (vertexFilename.enabled && vertexFilename.text !== "")) && (!fragmentFilename.enabled || (fragmentFilename.enabled && fragmentFilename.text !== "")))
- DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
- onClicked: exportMaterialDialog.accept()
- }
- Button {
- text: qsTr("Cancel")
- DialogButtonBox.buttonRole: DialogButtonBox.DestructiveRole
- onClicked: exportMaterialDialog.reject()
- }
- }
- }
- onAccepted: {
- materialAdapter.exportQmlComponent(componentFilePath.text, vertexFilename.text, fragmentFilename.text)
- }
- }
- SaveChangesDialog {
- id: saveChangesDialog
- materialAdapter: materialAdapter
- saveAsDialog: saveAsDialog
- anchors.centerIn: parent
- }
- AboutDialog {
- id: aboutDialog
- parent: Overlay.overlay
- anchors.centerIn: parent
- }
- function saveAction() {
- // 1. No file name(s) given (call saveAs)
- let materialSaveFileUrl = new URL(materialAdapter.materialSaveFile)
- if (materialSaveFileUrl.toString().length > 0)
- materialAdapter.save()
- else
- saveAsAction()
- }
- function openAction() {
- openMaterialDialog.open()
- }
- function newAction() {
- saveChangesDialog.doIfChangesSavedOrDiscarded(() => { materialAdapter.reset() });
- materialAdapter.reset()
- }
- function saveAsAction() {
- saveAsDialog.open()
- }
- function quitAction() {
- Qt.quit()
- }
- function aboutAction() {
- aboutDialog.open()
- }
- function importFragmentShader() {
- fragmentShaderImportDialog.open()
- }
- function importVertexShader() {
- vertexShaderImportDialog.open()
- }
- function exportMaterial() {
- exportMaterialDialog.open()
- }
- menuBar: MenuBar {
- Menu {
- title: qsTr("&File")
- Action { text: qsTr("&New..."); onTriggered: window.newAction(); }
- Action { text: qsTr("&Open..."); onTriggered: window.openAction(); }
- Action { text: qsTr("&Save"); onTriggered: window.saveAction(); }
- Action { text: qsTr("Save &As..."); onTriggered: window.saveAsAction(); }
- MenuSeparator { }
- Menu {
- title: qsTr("Import")
- Action { text: qsTr("Fragment Shader"); onTriggered: window.importFragmentShader(); }
- Action { text: qsTr("Vertex Shader"); onTriggered: window.importVertexShader(); }
- }
- Action { text: qsTr("Export"); onTriggered: window.exportMaterial(); }
- MenuSeparator { }
- Action { text: qsTr("&Quit"); onTriggered: window.quitAction(); }
- }
- Menu {
- title: qsTr("&Help")
- Action { text: qsTr("&About"); onTriggered: window.aboutAction(); }
- }
- }
- SplitView {
- id: mainSplitView
- anchors.fill: parent
- orientation: Qt.Horizontal
- EditorView {
- id: editorView
- vertexTabText: "Vertex Shader"
- fragmentTabText: "Fragment Shader"
- SplitView.preferredWidth: window.width * 0.5
- SplitView.fillWidth: true
- materialAdapter: materialAdapter
- instanceEntry: preview.instanceEntry
- targetModel: preview.modelInstance
- }
- Preview {
- id: preview
- implicitWidth: parent.width * 0.5
- currentMaterial: materialAdapter.material
- }
- }
- function outputLine(lineText) {
- // Prepend
- editorView.outputTextItem.text = lineText + "\n" + editorView.outputTextItem.text;
- }
- function printShaderStatusError(stage, msg) {
- let outputString = ""
- outputString += msg.filename + " => " + msg.message
- if (msg.identifier !== null && msg.identifier !== "")
- outputString += " '" + msg.identifier + "'";
- if (msg.line >= 0)
- outputString += ", on line: " + msg.line
- outputLine(outputString)
- }
- MaterialAdapter {
- id: materialAdapter
- vertexShader: editorView.vertexEditor.text
- fragmentShader: editorView.fragmentEditor.text
- rootNode: preview.rootNode
- uniformModel: editorView.uniformModel
- onVertexStatusChanged: {
- if (vertexStatus.status !== ShaderConstants.Success) {
- editorView.tabBarInfoView.currentIndex = 1
- window.printShaderStatusError(ShaderConstants.Vertex, vertexStatus)
- } else if (fragmentStatus.status === ShaderConstants.Success){
- // both work, clear
- editorView.outputTextItem.text = "";
- }
- }
- onFragmentStatusChanged: {
- if (fragmentStatus.status !== ShaderConstants.Success) {
- editorView.tabBarInfoView.currentIndex = 1
- window.printShaderStatusError(ShaderConstants.Fragment, fragmentStatus)
- } else if (vertexStatus.status === ShaderConstants.Success) {
- // both work, clear
- editorView.outputTextItem.text = "";
- }
- }
- onVertexShaderChanged: {
- editorView.vertexEditor.text = materialAdapter.vertexShader
- }
- onFragmentShaderChanged: {
- editorView.fragmentEditor.text = materialAdapter.fragmentShader
- }
- }
- }
|