forked from qt-creator/qt-creator
QmlDesigner: add nodes to the Node Graph Editor
Nodes: - Material => PrincipledMaterial - BaseColor => part of PrincipledMaterial - Metalness => part of PrincipledMaterial - Roughness => part of PrincipledMaterial - CheckBox - Color - ComboBox - RealSpinBox - Texture Nodes can transfer data, which is set using input nodes Change-Id: I36a5ea95d6ee5b7c04dab47264db295c73a65874 Reviewed-by: Rafal Andrusieczko <rnd@spyro-soft.com>
This commit is contained in:
@@ -2,18 +2,87 @@
|
||||
// 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 QuickQanava as Qan
|
||||
import Editor as Editor
|
||||
|
||||
import NodeGraphEditorBackend
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
color: StudioTheme.Values.themePanelBackground
|
||||
Editor.ContextMenu {
|
||||
id: contextMenu
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
color: "yellow"
|
||||
height: 100
|
||||
width: 100
|
||||
graph: graphView.graph
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
id: toolbar
|
||||
|
||||
color: StudioTheme.Values.themeToolbarBackground
|
||||
height: StudioTheme.Values.toolbarHeight
|
||||
width: parent.width
|
||||
|
||||
Row {
|
||||
anchors.bottomMargin: StudioTheme.Values.toolbarVerticalMargin
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: StudioTheme.Values.toolbarHorizontalMargin
|
||||
anchors.rightMargin: StudioTheme.Values.toolbarHorizontalMargin
|
||||
anchors.topMargin: StudioTheme.Values.toolbarVerticalMargin
|
||||
spacing: 6
|
||||
|
||||
HelperWidgets.AbstractButton {
|
||||
buttonIcon: StudioTheme.Constants.add_medium
|
||||
style: StudioTheme.Values.viewBarButtonStyle
|
||||
tooltip: qsTr("Add a new graph node.")
|
||||
|
||||
onClicked: () => {
|
||||
newNodeGraphDialog.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: graphContent
|
||||
|
||||
clip: true
|
||||
color: StudioTheme.Values.themePanelBackground
|
||||
height: parent.height - toolbar.height
|
||||
width: parent.width
|
||||
|
||||
Qan.GraphView {
|
||||
id: graphView
|
||||
|
||||
anchors.fill: parent
|
||||
navigable: true
|
||||
|
||||
graph: Editor.Graph {
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Delete) {
|
||||
graph.removeSelection();
|
||||
}
|
||||
}
|
||||
onRightClicked: function (pos) {
|
||||
contextMenu.popup();
|
||||
}
|
||||
}
|
||||
|
||||
Editor.NewNodeGraphDialog {
|
||||
id: newNodeGraphDialog
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,91 @@
|
||||
// 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 HelperWidgets as HelperWidgets
|
||||
import StudioControls as StudioControls
|
||||
import StudioTheme as StudioTheme
|
||||
|
||||
import Nodes as Nodes
|
||||
|
||||
StudioControls.Menu {
|
||||
id: contextMenu
|
||||
|
||||
required property var graph
|
||||
|
||||
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("BaseColor")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.baseColor);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Metalness")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.metalness);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Roughness")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.roughness);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("CheckBox")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.checkBox);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Color")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.color);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("ComboBox")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.comboBox);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Material")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.material);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("RealSpinBox")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.realSpinBox);
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Texture")
|
||||
|
||||
onTriggered: () => {
|
||||
contextMenu.graph.insertNode(Nodes.Components.texture);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
// 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 QuickQanava as Qan
|
||||
|
||||
Qan.Graph {
|
||||
id: root
|
||||
|
||||
connectorCreateDefaultEdge: false
|
||||
connectorEnabled: true
|
||||
|
||||
portDelegate: Port {
|
||||
}
|
||||
|
||||
onConnectorRequestEdgeCreation: (srcNode, dstNode, srcPortItem, dstPortItem) => {
|
||||
if (srcPortItem.dataType !== dstPortItem.dataType) {
|
||||
return;
|
||||
}
|
||||
|
||||
const edge = root.insertEdge(srcNode, dstNode);
|
||||
root.bindEdge(edge, srcPortItem, dstPortItem);
|
||||
|
||||
if (dstPortItem.dataBinding) {
|
||||
dstPortItem.dataBinding(srcNode.item.value);
|
||||
} else {
|
||||
// TODO: change old implementation
|
||||
dstNode.item.value[dstPortItem.dataName] = Qt.binding(() => {
|
||||
if (srcPortItem.dataName !== "")
|
||||
return srcNode.item.value[srcPortItem.dataName];
|
||||
|
||||
return srcNode.item.value;
|
||||
});
|
||||
}
|
||||
}
|
||||
onNodeRemoved: node => {}
|
||||
onOnEdgeRemoved: edge => {
|
||||
const srcNode = edge.getSource();
|
||||
const dstNode = edge.getDestination();
|
||||
const srcPortItem = edge.item.sourceItem;
|
||||
const dstPortItem = edge.item.destinationItem;
|
||||
|
||||
// TODO: add reset binding function
|
||||
dstNode.item.value[dstPortItem.dataName] = dstNode.item.reset[dstPortItem.dataName];
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
// 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 HelperWidgets as HelperWidgets
|
||||
import StudioControls as StudioControls
|
||||
import StudioTheme as StudioTheme
|
||||
|
||||
StudioControls.Dialog {
|
||||
id: root
|
||||
|
||||
anchors.centerIn: parent
|
||||
closePolicy: Popup.CloseOnEscape
|
||||
modal: true
|
||||
title: qsTr("Create Node Graph")
|
||||
|
||||
contentItem: Column {
|
||||
spacing: 2
|
||||
|
||||
Row {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
text: qsTr("Name: ")
|
||||
}
|
||||
|
||||
StudioControls.TextField {
|
||||
id: tfName
|
||||
|
||||
actionIndicator.visible: false
|
||||
translationIndicator.visible: false
|
||||
validator: nameValidator
|
||||
|
||||
Keys.onEnterPressed: btnCreate.onClicked()
|
||||
Keys.onEscapePressed: root.reject()
|
||||
Keys.onReturnPressed: btnCreate.onClicked()
|
||||
onTextChanged: () => {}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
text: qsTr("Type: ")
|
||||
}
|
||||
|
||||
StudioControls.ComboBox {
|
||||
id: cbType
|
||||
|
||||
actionIndicatorVisible: false
|
||||
model: [
|
||||
{
|
||||
value: "principled_material",
|
||||
text: "Principled Material"
|
||||
},
|
||||
]
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
|
||||
onActivated: () => {}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: 20
|
||||
width: 1
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
|
||||
HelperWidgets.Button {
|
||||
id: btnCreate
|
||||
|
||||
text: qsTr("Create")
|
||||
|
||||
onClicked: () => {}
|
||||
}
|
||||
|
||||
HelperWidgets.Button {
|
||||
text: qsTr("Cancel")
|
||||
|
||||
onClicked: root.reject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: () => {}
|
||||
onRejected: () => {}
|
||||
|
||||
HelperWidgets.RegExpValidator {
|
||||
id: nameValidator
|
||||
|
||||
regExp: /^(\w[^*/><?\\|:]*)$/
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
// 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 QuickQanava as Qan
|
||||
|
||||
Qan.Port {
|
||||
id: root
|
||||
|
||||
property var dataBinding: null
|
||||
property string dataName: ""
|
||||
property string dataType: ""
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
module Editor
|
||||
ContextMenu 1.0 ContextMenu.qml
|
||||
Graph 1.0 Graph.qml
|
||||
NewNodeGraphDialog 1.0 NewNodeGraphDialog.qml
|
||||
Port 1.0 Port.qml
|
@@ -0,0 +1,72 @@
|
||||
// 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.Layouts
|
||||
|
||||
import QuickQanava as Qan
|
||||
|
||||
import NodeGraphEditorBackend
|
||||
|
||||
Qan.NodeItem {
|
||||
id: root
|
||||
|
||||
default property alias data: content.data
|
||||
property QtObject portsMetaData: QtObject {
|
||||
// {
|
||||
// id: "",
|
||||
// alias: "",
|
||||
// name: "",
|
||||
// type: "",
|
||||
// binding: (values) => {}
|
||||
// }
|
||||
property var pin: []
|
||||
property var pout: []
|
||||
}
|
||||
readonly property string uuid: NodeGraphEditorBackend.widget.generateUUID()
|
||||
|
||||
Layout.preferredHeight: 60
|
||||
Layout.preferredWidth: 100
|
||||
connectable: Qan.NodeItem.UnConnectable
|
||||
height: Layout.preferredHeight
|
||||
width: Layout.preferredWidth
|
||||
|
||||
Component.onCompleted: {
|
||||
internal.configurePorts(root.graph);
|
||||
}
|
||||
|
||||
Qan.RectNodeTemplate {
|
||||
anchors.fill: parent
|
||||
nodeItem: parent
|
||||
|
||||
Item {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: internal
|
||||
|
||||
function configurePorts(graph) {
|
||||
const initPort = (portItem, data) => {
|
||||
if (data.binding) {
|
||||
portItem.dataBinding = data.binding;
|
||||
}
|
||||
portItem.dataName = data.alias;
|
||||
portItem.dataType = data.type;
|
||||
};
|
||||
|
||||
root.portsMetaData.pin.forEach(data => {
|
||||
const portItem = graph.insertPort(root.node, Qan.NodeItem.Left, Qan.PortItem.In, `${data.name} (${data.type})`, data.id);
|
||||
initPort(portItem, data);
|
||||
});
|
||||
|
||||
root.portsMetaData.pout.forEach(data => {
|
||||
const portItem = graph.insertPort(root.node, Qan.NodeItem.Right, Qan.PortItem.Out, `${data.name}`, data.id);
|
||||
initPort(portItem, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
import QtQuick3D as QtQuick3D
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtObject reset: QtObject {
|
||||
property int channel
|
||||
property color color
|
||||
property QtQuick3D.Texture map
|
||||
property bool singleChannelEnabled
|
||||
}
|
||||
readonly property QtObject value: QtObject {
|
||||
property int channel
|
||||
property color color
|
||||
property QtQuick3D.Texture map
|
||||
property bool singleChannelEnabled
|
||||
}
|
||||
|
||||
Layout.preferredHeight: 150
|
||||
Layout.preferredWidth: 150
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: [
|
||||
{
|
||||
id: "basecolor_in_baseColor",
|
||||
alias: "color",
|
||||
name: "Color",
|
||||
type: "QColor"
|
||||
},
|
||||
{
|
||||
id: "basecolor_in_baseColorMap",
|
||||
alias: "map",
|
||||
name: "Map",
|
||||
type: "Texture"
|
||||
},
|
||||
{
|
||||
id: "basecolor_in_baseColorSingleChannelEnabled",
|
||||
alias: "singleChannelEnabled",
|
||||
name: "Single Channel Enabled",
|
||||
type: "bool"
|
||||
},
|
||||
{
|
||||
id: "basecolor_in_baseColorChannel",
|
||||
alias: "channel",
|
||||
name: "Channel",
|
||||
type: "QQuick3DMaterial::TextureChannelMapping"
|
||||
},
|
||||
]
|
||||
property var pout: [
|
||||
{
|
||||
id: "basecolor_out",
|
||||
alias: "",
|
||||
name: "OUT",
|
||||
type: "nge::BaseColor"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "Base Color";
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
import StudioControls as StudioControls
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtObject value: QtObject {
|
||||
property bool binary: checkBox.checked
|
||||
}
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: []
|
||||
property var pout: [
|
||||
{
|
||||
id: "checkbox_out",
|
||||
alias: "binary",
|
||||
name: "OUT",
|
||||
type: "bool"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "CheckBox (bool)";
|
||||
}
|
||||
|
||||
StudioControls.CheckBox {
|
||||
id: checkBox
|
||||
|
||||
actionIndicatorVisible: false
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtObject value: QtObject {
|
||||
property color color
|
||||
}
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: []
|
||||
property var pout: [
|
||||
{
|
||||
id: "checkbox_out",
|
||||
alias: "color",
|
||||
name: "OUT",
|
||||
type: "QColor"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "Color (QColor)";
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
color: root.value.color
|
||||
height: 32
|
||||
width: 32
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: colorPopup.open(root)
|
||||
}
|
||||
|
||||
ColorEditorPopup {
|
||||
id: colorPopup
|
||||
|
||||
currentColor: root.value.color
|
||||
|
||||
onActivateColor: color => root.value.color = color
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
// 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
|
||||
|
||||
required property color currentColor
|
||||
property QtObject loaderItem: loader.item
|
||||
property color originalColor
|
||||
|
||||
signal activateColor(color: color)
|
||||
|
||||
function open(showItem) {
|
||||
loader.ensureActive();
|
||||
colorPopup.show(showItem);
|
||||
|
||||
loader.updateOriginalColor();
|
||||
}
|
||||
|
||||
width: 260
|
||||
|
||||
onClosing: loader.active = false
|
||||
onOriginalColorChanged: 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 {
|
||||
visible: colorPopup.visible
|
||||
width: colorPopup.contentWidth
|
||||
|
||||
onActivateColor: color => {
|
||||
colorPopup.activateColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
loader.updateOriginalColor();
|
||||
colorPopup.titleBar = loader.item.titleBarContent;
|
||||
}
|
||||
|
||||
Binding {
|
||||
property: "color"
|
||||
target: loader.item
|
||||
value: colorPopup.currentColor
|
||||
when: loader.status === Loader.Ready
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
import HelperWidgets as HelperWidgets
|
||||
import StudioControls as StudioControls
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
property QtObject value: QtObject {
|
||||
property url text: `image://qmldesigner_nodegrapheditor/${comboBox.currentValue}`
|
||||
}
|
||||
|
||||
Layout.preferredWidth: 175
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: []
|
||||
property var pout: [
|
||||
{
|
||||
id: "combobox_out",
|
||||
alias: "text",
|
||||
name: "OUT",
|
||||
type: "QUrl"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "ComboBox";
|
||||
}
|
||||
|
||||
HelperWidgets.FileResourcesModel {
|
||||
id: fileModel
|
||||
|
||||
filter: "*.png *.gif *.jpg *.bmp *.jpeg *.svg *.pbm *.pgm *.ppm *.xbm *.xpm *.hdr *.ktx *.webp"
|
||||
modelNodeBackendProperty: modelNodeBackend
|
||||
}
|
||||
|
||||
StudioControls.ComboBox {
|
||||
id: comboBox
|
||||
|
||||
actionIndicatorVisible: false
|
||||
anchors.centerIn: parent
|
||||
model: fileModel.model
|
||||
textRole: "fileName"
|
||||
valueRole: "relativeFilePath"
|
||||
|
||||
// valueRole: "absoluteFilePath"
|
||||
|
||||
// model: [
|
||||
// {
|
||||
// text: "#1 (ONE)",
|
||||
// value: "one"
|
||||
// },
|
||||
// {
|
||||
// text: "#2 (TWO)",
|
||||
// value: "two"
|
||||
// },
|
||||
// {
|
||||
// text: "#3 (THREE)",
|
||||
// value: "three"
|
||||
// }
|
||||
// ]
|
||||
// textRole: "text"
|
||||
// valueRole: "value"
|
||||
|
||||
// onActivated: () => {
|
||||
// // root.value.text = comboBox.currentValue;
|
||||
// root.value.text = `image://qmldesigner_nodegrapheditor/${comboBox.currentValue}`;
|
||||
// }
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
// 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 Singleton
|
||||
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property Component baseColor: Component {
|
||||
BaseColor {
|
||||
}
|
||||
}
|
||||
readonly property Component checkBox: Component {
|
||||
CheckBox {
|
||||
}
|
||||
}
|
||||
readonly property Component color: Component {
|
||||
Color {
|
||||
}
|
||||
}
|
||||
readonly property Component comboBox: Component {
|
||||
ComboBox {
|
||||
}
|
||||
}
|
||||
readonly property Component material: Component {
|
||||
Material {
|
||||
}
|
||||
}
|
||||
readonly property Component metalness: Component {
|
||||
Metalness {
|
||||
}
|
||||
}
|
||||
readonly property Component realSpinBox: Component {
|
||||
RealSpinBox {
|
||||
}
|
||||
}
|
||||
readonly property Component roughness: Component {
|
||||
Roughness {
|
||||
}
|
||||
}
|
||||
readonly property Component texture: Component {
|
||||
Texture {
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,127 @@
|
||||
// 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.Layouts
|
||||
import QtQuick3D as QtQuick3D
|
||||
|
||||
import QuickQanava as Qan
|
||||
|
||||
import NodeGraphEditorBackend
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtQuick3D.PrincipledMaterial reset: QtQuick3D.PrincipledMaterial {
|
||||
}
|
||||
readonly property QtQuick3D.PrincipledMaterial value: QtQuick3D.PrincipledMaterial {
|
||||
}
|
||||
|
||||
Layout.preferredHeight: 150
|
||||
Layout.preferredWidth: 150
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: [
|
||||
{
|
||||
id: "principledmaterial_in_basecolor",
|
||||
alias: "",
|
||||
name: "Base Color",
|
||||
type: "nge::BaseColor",
|
||||
binding: values => {
|
||||
root.value.baseColor = Qt.binding(() => {
|
||||
return values.color;
|
||||
});
|
||||
root.value.baseColorChannel = Qt.binding(() => {
|
||||
return values.channel;
|
||||
});
|
||||
root.value.baseColorMap = Qt.binding(() => {
|
||||
return values.map;
|
||||
});
|
||||
root.value.baseColorSingleChannelEnabled = Qt.binding(() => {
|
||||
return values.singleChannelEnabled;
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "principledmaterial_in_metalness",
|
||||
alias: "",
|
||||
name: "Metalness",
|
||||
type: "nge::Metalness",
|
||||
binding: values => {
|
||||
root.value.metalness = Qt.binding(() => {
|
||||
return values.metalness;
|
||||
});
|
||||
root.value.metalnessChannel = Qt.binding(() => {
|
||||
return values.channel;
|
||||
});
|
||||
root.value.metalnessMap = Qt.binding(() => {
|
||||
return values.map;
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "principledmaterial_in_roughness",
|
||||
alias: "",
|
||||
name: "Roughness",
|
||||
type: "nge::Roughness",
|
||||
binding: values => {
|
||||
root.value.roughness = Qt.binding(() => {
|
||||
return values.roughness;
|
||||
});
|
||||
root.value.roughnessChannel = Qt.binding(() => {
|
||||
return values.channel;
|
||||
});
|
||||
root.value.roughnessMap = Qt.binding(() => {
|
||||
return values.map;
|
||||
});
|
||||
}
|
||||
},
|
||||
]
|
||||
property var pout: []
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "Principled Material";
|
||||
}
|
||||
|
||||
QtQuick3D.View3D {
|
||||
id: view3D
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
camera: QtQuick3D.PerspectiveCamera {
|
||||
clipFar: 1000
|
||||
clipNear: 1
|
||||
eulerRotation.x: -5.71
|
||||
y: 70
|
||||
z: 200
|
||||
}
|
||||
environment: QtQuick3D.SceneEnvironment {
|
||||
antialiasingMode: QtQuick3D.SceneEnvironment.MSAA
|
||||
antialiasingQuality: QtQuick3D.SceneEnvironment.High
|
||||
backgroundMode: QtQuick3D.SceneEnvironment.Transparent
|
||||
clearColor: "#000000"
|
||||
}
|
||||
|
||||
QtQuick3D.Node {
|
||||
QtQuick3D.DirectionalLight {
|
||||
brightness: 1
|
||||
eulerRotation.x: -26
|
||||
eulerRotation.y: -50
|
||||
}
|
||||
|
||||
QtQuick3D.Node {
|
||||
y: 60
|
||||
|
||||
QtQuick3D.Model {
|
||||
id: model
|
||||
|
||||
eulerRotation.y: 45
|
||||
materials: root.value
|
||||
scale: Qt.vector3d(1.7, 1.7, 1.7)
|
||||
source: "#Sphere"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
import QtQuick3D as QtQuick3D
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtObject reset: QtObject {
|
||||
property int channel
|
||||
property QtQuick3D.Texture map
|
||||
property real metalness
|
||||
}
|
||||
readonly property QtObject value: QtObject {
|
||||
property int channel
|
||||
property QtQuick3D.Texture map
|
||||
property real metalness
|
||||
}
|
||||
|
||||
Layout.preferredHeight: 150
|
||||
Layout.preferredWidth: 150
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: [
|
||||
{
|
||||
id: "metalness_in_metalness",
|
||||
alias: "metalness",
|
||||
name: "Metalness",
|
||||
type: "real"
|
||||
},
|
||||
{
|
||||
id: "metalness_in_metalnessChannel",
|
||||
alias: "channel",
|
||||
name: "Channel",
|
||||
type: "QQuick3DMaterial::TextureChannelMapping"
|
||||
},
|
||||
{
|
||||
id: "metalness_in_metalnessMap ",
|
||||
alias: "map",
|
||||
name: "Map",
|
||||
type: "Texture"
|
||||
},
|
||||
]
|
||||
property var pout: [
|
||||
{
|
||||
id: "metalness_out",
|
||||
alias: "",
|
||||
name: "OUT",
|
||||
type: "nge::Metalness"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "Metalness";
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
import StudioControls as StudioControls
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtObject value: QtObject {
|
||||
property real floating: realSpinBox.realValue
|
||||
}
|
||||
|
||||
Layout.preferredWidth: 175
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: []
|
||||
property var pout: [
|
||||
{
|
||||
id: "realspinbox_out",
|
||||
alias: "floating",
|
||||
name: "OUT",
|
||||
type: "real"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "RealSpinBox (real)";
|
||||
}
|
||||
|
||||
StudioControls.RealSpinBox {
|
||||
id: realSpinBox
|
||||
|
||||
actionIndicatorVisible: false
|
||||
anchors.centerIn: parent
|
||||
decimals: 2
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
// 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 QtQuick.Layouts
|
||||
|
||||
import QtQuick3D as QtQuick3D
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtObject reset: QtObject {
|
||||
property int channel
|
||||
property QtQuick3D.Texture map
|
||||
property real roughness
|
||||
}
|
||||
readonly property QtObject value: QtObject {
|
||||
property int channel
|
||||
property QtQuick3D.Texture map
|
||||
property real roughness
|
||||
}
|
||||
|
||||
Layout.preferredHeight: 150
|
||||
Layout.preferredWidth: 150
|
||||
|
||||
portsMetaData: QtObject {
|
||||
property var pin: [
|
||||
{
|
||||
id: "roughness_in_roughness",
|
||||
alias: "roughness",
|
||||
name: "Roughness",
|
||||
type: "real"
|
||||
},
|
||||
{
|
||||
id: "roughness_in_roughnessChannel",
|
||||
alias: "channel",
|
||||
name: "Channel",
|
||||
type: "QQuick3DMaterial::TextureChannelMapping"
|
||||
},
|
||||
{
|
||||
id: "roughness_in_roughnessMap ",
|
||||
alias: "map",
|
||||
name: "Map",
|
||||
type: "Texture"
|
||||
},
|
||||
]
|
||||
property var pout: [
|
||||
{
|
||||
id: "roughness_out",
|
||||
alias: "",
|
||||
name: "OUT",
|
||||
type: "nge::Roughness"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "Roughness";
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
// 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.Layouts
|
||||
import QtQuick3D as QtQuick3D
|
||||
|
||||
import QuickQanava as Qan
|
||||
|
||||
import NodeGraphEditorBackend
|
||||
|
||||
Base {
|
||||
id: root
|
||||
|
||||
readonly property QtQuick3D.Texture reset: QtQuick3D.Texture {
|
||||
}
|
||||
readonly property QtQuick3D.Texture value: QtQuick3D.Texture {
|
||||
}
|
||||
|
||||
Layout.preferredHeight: 150
|
||||
Layout.preferredWidth: 150
|
||||
|
||||
Component.onCompleted: {
|
||||
node.label = "Texture";
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
height: 96
|
||||
source: root.value.source
|
||||
width: 96
|
||||
}
|
||||
}
|
@@ -0,0 +1,2 @@
|
||||
module Nodes
|
||||
singleton Components 1.0 Components.qml
|
@@ -369,6 +369,9 @@ extend_qtc_plugin(QmlDesigner
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX components/nodegrapheditor
|
||||
DEPENDS
|
||||
QuickQanava
|
||||
QuickQanavaplugin
|
||||
SOURCES
|
||||
nodegrapheditorimageprovider.cpp nodegrapheditorimageprovider.h
|
||||
nodegrapheditormodel.cpp nodegrapheditormodel.h
|
||||
|
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "nodegrapheditorimageprovider.h"
|
||||
|
||||
#include <documentmanager.h>
|
||||
#include <utils/filepath.h>
|
||||
|
||||
namespace QmlDesigner::Internal {
|
||||
|
||||
NodeGraphEditorImageProvider::NodeGraphEditorImageProvider()
|
||||
@@ -10,8 +13,17 @@ NodeGraphEditorImageProvider::NodeGraphEditorImageProvider()
|
||||
{
|
||||
}
|
||||
|
||||
QImage NodeGraphEditorImageProvider::requestImage(const QString &/*id*/, QSize */*size*/, const QSize &requestedSize)
|
||||
QImage NodeGraphEditorImageProvider::requestImage(const QString &id, QSize */*size*/, const QSize &requestedSize)
|
||||
{
|
||||
Utils::FilePath path = DocumentManager::currentResourcePath().pathAppended(id);
|
||||
|
||||
QImage img;
|
||||
img.load(path.toString());
|
||||
|
||||
if (!img.isNull()) {
|
||||
return img;
|
||||
}
|
||||
|
||||
const QSize newSize = requestedSize.isEmpty()
|
||||
? QSize(100, 100)
|
||||
: requestedSize;
|
||||
|
@@ -23,6 +23,8 @@
|
||||
#include <QQuickItem>
|
||||
#include <QShortcut>
|
||||
|
||||
#include <QuickQanava>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static QString propertyEditorResourcesPath()
|
||||
@@ -34,6 +36,11 @@ static QString propertyEditorResourcesPath()
|
||||
return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
|
||||
}
|
||||
|
||||
static Utils::FilePath materialsPath()
|
||||
{
|
||||
return DocumentManager::currentResourcePath().pathAppended("materials");
|
||||
}
|
||||
|
||||
NodeGraphEditorWidget::NodeGraphEditorWidget(NodeGraphEditorView *nodeGraphEditorView,
|
||||
NodeGraphEditorModel *nodeGraphEditorModel)
|
||||
: m_editorView(nodeGraphEditorView)
|
||||
@@ -56,12 +63,15 @@ NodeGraphEditorWidget::NodeGraphEditorWidget(NodeGraphEditorView *nodeGraphEdito
|
||||
|
||||
auto map = registerPropertyMap("NodeGraphEditorBackend");
|
||||
map->setProperties({{"nodeGraphEditorModel", QVariant::fromValue(nodeGraphEditorModel)}});
|
||||
map->setProperties({{"widget", QVariant::fromValue(this)}});
|
||||
|
||||
Theme::setupTheme(engine());
|
||||
|
||||
setWindowTitle(tr("Node Graph", "Title of Editor widget"));
|
||||
setMinimumSize(QSize(256, 256));
|
||||
|
||||
QuickQanava::initialize(engine());
|
||||
|
||||
// init the first load of the QML UI elements
|
||||
reloadQmlSource();
|
||||
}
|
||||
@@ -75,6 +85,11 @@ QString NodeGraphEditorWidget::qmlSourcesPath()
|
||||
return Core::ICore::resourcePath("qmldesigner/nodegrapheditor").toString();
|
||||
}
|
||||
|
||||
QString NodeGraphEditorWidget::generateUUID() const
|
||||
{
|
||||
return QUuid::createUuid().toString();
|
||||
}
|
||||
|
||||
void NodeGraphEditorWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
StudioQuickWidget::showEvent(event);
|
||||
|
@@ -32,6 +32,8 @@ public:
|
||||
|
||||
static QString qmlSourcesPath();
|
||||
|
||||
Q_INVOKABLE QString generateUUID() const;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *) override;
|
||||
void focusOutEvent(QFocusEvent *focusEvent) override;
|
||||
|
Reference in New Issue
Block a user