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:
Rafal Andrusieczko
2024-12-12 22:55:42 +01:00
parent 1a135ac7ba
commit e17d213580
23 changed files with 1099 additions and 8 deletions

View File

@@ -2,18 +2,87 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme import StudioTheme as StudioTheme
import QuickQanava as Qan
import Editor as Editor
import NodeGraphEditorBackend import NodeGraphEditorBackend
Rectangle { Item {
id: root id: root
color: StudioTheme.Values.themePanelBackground Editor.ContextMenu {
id: contextMenu
Rectangle { graph: graphView.graph
anchors.centerIn: parent }
color: "yellow"
height: 100 Column {
width: 100 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
}
}
} }
} }

View File

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

View File

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

View File

@@ -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[^*/><?\\|:]*)$/
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
module Nodes
singleton Components 1.0 Components.qml

View File

@@ -369,6 +369,9 @@ extend_qtc_plugin(QmlDesigner
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/nodegrapheditor SOURCES_PREFIX components/nodegrapheditor
DEPENDS
QuickQanava
QuickQanavaplugin
SOURCES SOURCES
nodegrapheditorimageprovider.cpp nodegrapheditorimageprovider.h nodegrapheditorimageprovider.cpp nodegrapheditorimageprovider.h
nodegrapheditormodel.cpp nodegrapheditormodel.h nodegrapheditormodel.cpp nodegrapheditormodel.h

View File

@@ -3,6 +3,9 @@
#include "nodegrapheditorimageprovider.h" #include "nodegrapheditorimageprovider.h"
#include <documentmanager.h>
#include <utils/filepath.h>
namespace QmlDesigner::Internal { namespace QmlDesigner::Internal {
NodeGraphEditorImageProvider::NodeGraphEditorImageProvider() 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() const QSize newSize = requestedSize.isEmpty()
? QSize(100, 100) ? QSize(100, 100)
: requestedSize; : requestedSize;

View File

@@ -23,6 +23,8 @@
#include <QQuickItem> #include <QQuickItem>
#include <QShortcut> #include <QShortcut>
#include <QuickQanava>
namespace QmlDesigner { namespace QmlDesigner {
static QString propertyEditorResourcesPath() static QString propertyEditorResourcesPath()
@@ -34,6 +36,11 @@ static QString propertyEditorResourcesPath()
return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString(); return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
} }
static Utils::FilePath materialsPath()
{
return DocumentManager::currentResourcePath().pathAppended("materials");
}
NodeGraphEditorWidget::NodeGraphEditorWidget(NodeGraphEditorView *nodeGraphEditorView, NodeGraphEditorWidget::NodeGraphEditorWidget(NodeGraphEditorView *nodeGraphEditorView,
NodeGraphEditorModel *nodeGraphEditorModel) NodeGraphEditorModel *nodeGraphEditorModel)
: m_editorView(nodeGraphEditorView) : m_editorView(nodeGraphEditorView)
@@ -56,12 +63,15 @@ NodeGraphEditorWidget::NodeGraphEditorWidget(NodeGraphEditorView *nodeGraphEdito
auto map = registerPropertyMap("NodeGraphEditorBackend"); auto map = registerPropertyMap("NodeGraphEditorBackend");
map->setProperties({{"nodeGraphEditorModel", QVariant::fromValue(nodeGraphEditorModel)}}); map->setProperties({{"nodeGraphEditorModel", QVariant::fromValue(nodeGraphEditorModel)}});
map->setProperties({{"widget", QVariant::fromValue(this)}});
Theme::setupTheme(engine()); Theme::setupTheme(engine());
setWindowTitle(tr("Node Graph", "Title of Editor widget")); setWindowTitle(tr("Node Graph", "Title of Editor widget"));
setMinimumSize(QSize(256, 256)); setMinimumSize(QSize(256, 256));
QuickQanava::initialize(engine());
// init the first load of the QML UI elements // init the first load of the QML UI elements
reloadQmlSource(); reloadQmlSource();
} }
@@ -75,6 +85,11 @@ QString NodeGraphEditorWidget::qmlSourcesPath()
return Core::ICore::resourcePath("qmldesigner/nodegrapheditor").toString(); return Core::ICore::resourcePath("qmldesigner/nodegrapheditor").toString();
} }
QString NodeGraphEditorWidget::generateUUID() const
{
return QUuid::createUuid().toString();
}
void NodeGraphEditorWidget::showEvent(QShowEvent *event) void NodeGraphEditorWidget::showEvent(QShowEvent *event)
{ {
StudioQuickWidget::showEvent(event); StudioQuickWidget::showEvent(event);

View File

@@ -32,6 +32,8 @@ public:
static QString qmlSourcesPath(); static QString qmlSourcesPath();
Q_INVOKABLE QString generateUUID() const;
protected: protected:
void showEvent(QShowEvent *) override; void showEvent(QShowEvent *) override;
void focusOutEvent(QFocusEvent *focusEvent) override; void focusOutEvent(QFocusEvent *focusEvent) override;