// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick import QtQuick.Window import QtQuick.Controls import QtQuick.Shapes import QQEMLib 1.0 NodeViewItem { id: nodeViewItem property bool initialized: false readonly property color borderColor: Qt.lighter(mainView.backgroundColor1, 2.0) readonly property color connectorColor: "#80d0d040" function showAddNodeDialog(startNodeId, endNodeId) { addNodeDialog.reset(); effectManager.updateAddNodeData(); addNodeDialog.startNodeId = startNodeId; addNodeDialog.endNodeId = endNodeId; addNodeDialog.open(); } function showRenameNodeDialog() { renameNodeDialog.open(); } focus: true Component.onCompleted: { nodeViewItem.updateActiveNodesList(); effectManager.initialize(); } Timer { running: true interval: 1 onTriggered: { // Do the layout when views have correct sizes layoutNodes(false); initialized = true; } } onDoubleClickNode: { mainToolbar.setDesignMode(false); } onOpenDeleteNodeDialog: { mainWindow.deleteNodeAction(); } onOpenNodeContextMenu: { nodeContextMenu.popup(); } RenameNodeDialog { id: renameNodeDialog x: mainWindow.width * 0.5 - width * 0.5 y: mainWindow.height * 0.5 - height * 0.5 } AddNodeDialog { id: addNodeDialog x: mainWindow.width * 0.5 - width * 0.5 y: mainWindow.height * 0.5 - height * 0.5 } Image { anchors.fill: parent source: "images/nodeview_background.jpg" } // Render nodes Repeater { model: nodeViewItem.nodesModel delegate: Rectangle { width: model.width height: model.height x: model.x y: model.y border.color: model.selected ? highlightColor : borderColor color: mainView.backgroundColor1 opacity: model.disabled ? 0.4 : 1.0 border.width: 2 radius: model.type > 1 ? 6 : height * 0.5 Text { anchors.centerIn: parent horizontalAlignment: Text.AlignHCenter width: model.width - 20 elide: Text.ElideRight text: model.name font.pixelSize: 14 opacity: model.disabled ? 0.5 : 1.0 color: mainView.foregroundColor2 } Image { id: disableIconButton anchors.top: parent.top anchors.topMargin: 2 anchors.left: parent.left anchors.leftMargin: 6 width: 16 height: 16 mipmap: true visible: model.type === 2 source: model.disabled ? "images/icon_visibility_off.png" : "images/icon_visibility_on.png" opacity: model.disabled ? 1.0 : 0.2 MouseArea { anchors.fill: parent anchors.margins: -4 onClicked: { model.disabled = !model.disabled; nodeViewItem.updateActiveNodesList(); effectManager.bakeShaders(true); } } } // Connectors Rectangle { width: 10 height: 10 x: parent.width * 0.5 - width * 0.5 y: -height * 0.5 radius: width * 0.5 visible: model.type !== 0 border.width: 2 border.color: connectorColor color: mainView.backgroundColor1 } Rectangle { width: 10 height: 10 x: parent.width * 0.5 - width * 0.5 y: parent.height - height * 0.5 radius: width * 0.5 visible: model.type !== 1 border.width: 2 border.color: connectorColor color: mainView.backgroundColor1 } } } // Render arrows between nodes Repeater { model: nodeViewItem.arrowsModel delegate: Shape { anchors.fill: parent ShapePath { strokeWidth: 2 strokeColor: connectorColor capStyle: ShapePath.RoundCap startX: model.startX startY: model.startY PathLine { x: model.endX y: model.endY } } } } // Render '+' into arrows Repeater { model: nodeViewItem.arrowsModel delegate: Rectangle { property real arrowWidth: Math.sqrt(Math.pow(model.endX - model.startX, 2) + Math.pow(model.endY - model.startY, 2)) x: model.startX + (model.endX - model.startX) * 0.5 - width * 0.5 y: model.startY + (model.endY - model.startY) * 0.5 - height * 0.5 width: 20 height: 20 radius: width * 0.5 border.width: 1 color: mainView.backgroundColor1 border.color: highlightColor visible: arrowWidth > 50 Rectangle { width: 8 height: 2 anchors.centerIn: parent color: mainView.foregroundColor2 } Rectangle { width: 2 height: 8 anchors.centerIn: parent color: mainView.foregroundColor2 } MouseArea { anchors.fill: parent onClicked: { nodeViewItem.showAddNodeDialog(model.startNodeId, model.endNodeId); } } Text { anchors.left: parent.right anchors.leftMargin: 10 anchors.verticalCenter: parent.verticalCenter font.pixelSize: 16 color: mainView.foregroundColor1 visible: nodeViewItem.nodeGraphComplete && nodeViewItem.arrowsModel.rowCount === 1 text: "Add Node" } } } // Add node button Rectangle { anchors.left: parent.left anchors.leftMargin: 20 anchors.top: parent.top anchors.topMargin: 20 width: 30 height: 30 radius: width * 0.5 border.width: 2 color: mainView.backgroundColor1 border.color: borderColor Rectangle { width: 8 height: 2 anchors.centerIn: parent color: mainView.foregroundColor2 } Rectangle { width: 2 height: 8 anchors.centerIn: parent color: mainView.foregroundColor2 } MouseArea { anchors.fill: parent onClicked: { nodeViewItem.showAddNodeDialog(-1, -1); } } Text { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.right anchors.leftMargin: 10 font.pixelSize: 16 color: mainView.foregroundColor1 text: "Add Node" } } // Active arrow user modifies Shape { anchors.fill: parent visible: nodeViewItem.activeArrowEnabled opacity: 0.4 ShapePath { strokeWidth: 4 strokeColor: connectorColor strokeStyle: ShapePath.DashLine dashPattern: [2, 2] capStyle: ShapePath.RoundCap startX: nodeViewItem.activeArrowStartPoint.x startY: nodeViewItem.activeArrowStartPoint.y PathLine { x: nodeViewItem.activeArrowEndPoint.x y: nodeViewItem.activeArrowEndPoint.y } } } }