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

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
SOURCES_PREFIX components/nodegrapheditor
DEPENDS
QuickQanava
QuickQanavaplugin
SOURCES
nodegrapheditorimageprovider.cpp nodegrapheditorimageprovider.h
nodegrapheditormodel.cpp nodegrapheditormodel.h

View File

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

View File

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

View File

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