// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick import QtQuick.Controls CustomPopup { id: rootItem property int startNodeId: -1 property int endNodeId: -1 property string selectedNodeFile property string selectedNodeName property string selectedNodeDescription property string selectedNodeRequires property var selectedNodeProperties: [] property bool selectedNodeCanBeAdded: true property real showHideAnimationSpeed: 400 // All currently open node groups property var openGroups: [] function reset() { startNodeId = -1; endNodeId = -1; selectedNodeFile = ""; selectedNodeName = ""; selectedNodeDescription = ""; selectedNodeRequires = ""; selectedNodeProperties = []; selectedNodeCanBeAdded = true; } function addSelectedNode() { effectManager.addEffectNode(selectedNodeFile, rootItem.startNodeId, rootItem.endNodeId); rootItem.close(); } modal: true width: 700 height: 500 padding: 10 Text { id: dialogTitle anchors.horizontalCenter: parent.horizontalCenter text: "Add Effect Node" font.pixelSize: 16 color: mainView.foregroundColor2 } Row { anchors.top: dialogTitle.bottom anchors.topMargin: 10 anchors.bottom: buttonBar.top anchors.bottomMargin: 10 width: parent.width Component { id: sectionHeading Item { required property string section readonly property bool show: openGroups.includes(section) width: effectsListView.width - scrollBar.width - 5 height: 40 Rectangle { anchors.fill: parent anchors.margins: 2 color: mainView.backgroundColor2 border.width: 1 border.color: mainView.foregroundColor1 } Image { x: 10 source: "images/icon_arrow.png" anchors.verticalCenter: parent.verticalCenter rotation: show ? 90 : 0 scale: 0.5 Behavior on rotation { NumberAnimation { duration: showHideAnimationSpeed easing.type: Easing.InOutQuad } } } Text { anchors.verticalCenter: parent.verticalCenter x: 30 color: mainView.foregroundColor2 font.bold: true font.pixelSize: 12 text: parent.section font.capitalization: Font.AllUppercase } MouseArea { anchors.fill: parent onClicked: { // Show/hide the group const index = openGroups.indexOf(section); if (index > -1) openGroups.splice(index, 1); else openGroups.push(section); // Triggering manually required for array properties // so 'show' is updated. openGroupsChanged(); effectManager.showHideAddNodeGroup(parent.section, show); } } } } ListView { id: effectsListView width: parent.width * 0.35 height: parent.height model: effectManager.addNodeModel clip: true cacheBuffer: 10000 ScrollBar.vertical: ScrollBar { id: scrollBar policy: ScrollBar.AlwaysOn } section.property: "group" section.criteria: ViewSection.FullString section.delegate: sectionHeading delegate: Item { property real showAnimated: model.show x: 2 width: effectsListView.width - scrollBar.width - 9 height: showAnimated * 30 visible: opacity opacity: showAnimated Behavior on showAnimated { NumberAnimation { duration: showHideAnimationSpeed easing.type: Easing.InOutQuad } } Rectangle { anchors.fill: parent color: mainView.backgroundColor1 border.color: (selectedNodeFile === model.file) ? highlightColor : "transparent" border.width: 2 } Text { anchors.verticalCenter: parent.verticalCenter width: parent.width horizontalAlignment: Text.AlignHCenter text: model.name color: mainView.foregroundColor2 font.pixelSize: 14 elide: Text.ElideRight } Image { anchors.right: parent.right anchors.rightMargin: 5 anchors.verticalCenter: parent.verticalCenter height: parent.height * 0.4 width: height source: "images/icon_requires.png" mipmap: true visible: model.requires !== "" opacity: 0.2 MouseArea { id: requiresIconMouseArea anchors.fill: parent hoverEnabled: true } ToolTip { parent: parent visible: requiresIconMouseArea.containsMouse delay: 1000 text: "Requires: " + model.requires } } MouseArea { anchors.fill: parent onClicked: { selectedNodeName = model.name; selectedNodeFile = model.file; selectedNodeDescription = model.description; selectedNodeRequires = model.requires; selectedNodeProperties = model.properties; selectedNodeCanBeAdded = model.canBeAdded; } onDoubleClicked: { if (model.canBeAdded) addSelectedNode(); } } } BusyIndicator { id: refreshNodesIndicator anchors.centerIn: parent opacity: 0.0 running: opacity > 0 visible: running function show() { nodesLoadingIndicatorAnimation.restart(); } SequentialAnimation { id: nodesLoadingIndicatorAnimation NumberAnimation { target: refreshNodesIndicator property: "opacity" to: 1.0 duration: 250 easing.type: Easing.InOutQuad } PauseAnimation { duration: 500 } NumberAnimation { target: refreshNodesIndicator property: "opacity" to: 0.0 duration: 250 easing.type: Easing.InOutQuad } } } } Flickable { id: nodeInfoFlickable readonly property int padding: 10 width: parent.width - effectsListView.width height: parent.height contentHeight: nodeInfo.height clip: true ScrollBar.vertical: ScrollBar { width: 15 active: true } Column { id: nodeInfo y: nodeInfoFlickable.padding x: nodeInfoFlickable.padding width: parent.width - nodeInfoFlickable.padding * 3 spacing: nodeInfoFlickable.padding Text { anchors.horizontalCenter: parent.horizontalCenter text: selectedNodeName font.pixelSize: 16 font.bold: true color: mainView.foregroundColor2 } Text { width: parent.width text: selectedNodeDescription font.pixelSize: 14 color: mainView.foregroundColor2 wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Text { width: parent.width text: "Requires: " + selectedNodeRequires font.pixelSize: 14 font.bold: true color: mainView.foregroundColor2 wrapMode: Text.WrapAtWordBoundaryOrAnywhere visible: selectedNodeRequires !== "" } Text { font.pixelSize: 12 font.bold: true color: mainView.foregroundColor2 text: "PROPERTIES:" visible: selectedNodeProperties.length > 0 } Rectangle { id: propertiesArea width: parent.width height: childrenRect.height + nodeInfoFlickable.padding color: mainView.backgroundColor2 border.width: 1 border.color: mainView.foregroundColor1 visible: selectedNodeProperties.length > 0 Column { width: parent.width - nodeInfoFlickable.padding * 2 x: nodeInfoFlickable.padding y: nodeInfoFlickable.padding * 0.5 Repeater { model: selectedNodeProperties Text { property var nodeProperty: selectedNodeProperties[index] width: parent.width elide: Text.ElideRight font.pixelSize: 14 color: mainView.foregroundColor2 text: "" + nodeProperty.type + " " + nodeProperty.name } } } } Item { width: 1 height: nodeInfoFlickable.padding } } } } Item { id: buttonBar anchors.bottom: parent.bottom anchors.left: parent.left anchors.leftMargin: 10 anchors.right: parent.right anchors.rightMargin: 10 height: 40 Button { id: cancelButton anchors.left: parent.left height: parent.height text: "Cancel" onPressed: { rootItem.close(); } } Button { id: refreshButton anchors.left: cancelButton.right anchors.leftMargin: 10 height: parent.height text: "Refresh" onPressed: { refreshNodesIndicator.show(); effectManager.refreshAddNodesList(); } } Button { id: addButton anchors.right: parent.right height: parent.height text: "Add" enabled: selectedNodeFile != "" && selectedNodeCanBeAdded onPressed: { rootItem.addSelectedNode(); } } } }