mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-04-28 17:57:16 +02:00
425 lines
16 KiB
QML
425 lines
16 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
|
|
import Controls 1.0
|
|
import MaterialIcons 2.2
|
|
import Utils 1.0
|
|
|
|
/**
|
|
* NodeEditor allows to visualize and edit the parameters of a Node.
|
|
* It mainly provides an attribute editor and a log inspector.
|
|
*/
|
|
|
|
Panel {
|
|
id: root
|
|
|
|
property variant node
|
|
property string globalStatus : node !== null ? node.globalStatus : ""
|
|
property bool readOnly: false
|
|
property bool isCompatibilityNode: node && node.compatibilityIssue !== undefined
|
|
property string nodeStartDateTime: ""
|
|
|
|
signal attributeDoubleClicked(var mouse, var attribute)
|
|
signal upgradeRequest()
|
|
|
|
title: "Node" + (node !== null ? " - <b>" + node.label + "</b>" + (node.label !== node.defaultLabel ? " (" + node.defaultLabel + ")" : "") : "")
|
|
icon: MaterialLabel { text: MaterialIcons.tune }
|
|
|
|
onGlobalStatusChanged: {
|
|
nodeStartDateTime = ""
|
|
if (node !== null && node.isRunning()) {
|
|
timer.start()
|
|
}
|
|
else {
|
|
timer.stop()
|
|
if (node !== null && (node.isFinishedOrRunning() || globalStatus == "ERROR")) {
|
|
computationInfo.text = Format.sec2timeStr(node.elapsedTime)
|
|
}
|
|
else {
|
|
computationInfo.text = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
headerBar: RowLayout {
|
|
Label {
|
|
id: computationInfo
|
|
color: node && node.isComputable ? Colors.statusColors[node.globalStatus] : palette.text
|
|
Timer {
|
|
id: timer
|
|
interval: 2500
|
|
triggeredOnStart: true
|
|
repeat: true
|
|
running: node !== null && node.isRunning()
|
|
onTriggered: {
|
|
if (nodeStartDateTime === "") {
|
|
nodeStartDateTime = new Date(node.getStartDateTime()).getTime()
|
|
}
|
|
var now = new Date().getTime()
|
|
parent.text = Format.sec2timeStr((now-nodeStartDateTime)/1000)
|
|
}
|
|
}
|
|
padding: 2
|
|
font.italic: true
|
|
visible: {
|
|
if (node !== null) {
|
|
if (node.isComputable && (node.isFinishedOrRunning() || node.isSubmittedOrRunning() || node.globalStatus=="ERROR")) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
ToolTip.text: {
|
|
if (node !== null && (node.isFinishedOrRunning() || (node.isSubmittedOrRunning() && node.elapsedTime > 0))) {
|
|
var longestChunkTime = getLongestChunkTime(node.chunks)
|
|
if (longestChunkTime > 0)
|
|
return "Longest chunk: " + Format.sec2timeStr(longestChunkTime) + " (" + node.chunks.count + " chunks)"
|
|
else
|
|
return ""
|
|
} else {
|
|
return ""
|
|
}
|
|
}
|
|
ToolTip.visible: ToolTip.text ? runningTimeMa.containsMouse : false
|
|
MouseArea {
|
|
id: runningTimeMa
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
}
|
|
|
|
function getLongestChunkTime(chunks) {
|
|
if (chunks.count <= 1)
|
|
return 0
|
|
|
|
var longestChunkTime = 0
|
|
for (var i = 0; i < chunks.count; i++) {
|
|
var elapsedTime = chunks.at(i).elapsedTime
|
|
longestChunkTime = elapsedTime > longestChunkTime ? elapsedTime : longestChunkTime
|
|
}
|
|
return longestChunkTime
|
|
}
|
|
}
|
|
|
|
SearchBar {
|
|
id: searchBar
|
|
toggle: true // Enable toggling the actual text field by the search button
|
|
Layout.minimumWidth: searchBar.width
|
|
maxWidth: 150
|
|
enabled: tabBar.currentIndex === 0 || tabBar.currentIndex === 5
|
|
}
|
|
|
|
MaterialToolButton {
|
|
text: MaterialIcons.more_vert
|
|
font.pointSize: 11
|
|
padding: 2
|
|
onClicked: settingsMenu.open()
|
|
checkable: true
|
|
checked: settingsMenu.visible
|
|
Menu {
|
|
id: settingsMenu
|
|
y: parent.height
|
|
|
|
Menu {
|
|
id: filterAttributesMenu
|
|
title: "Filter Attributes"
|
|
RowLayout {
|
|
CheckBox {
|
|
id: outputToggle
|
|
text: "Output"
|
|
checkable: true
|
|
checked: GraphEditorSettings.showOutputAttributes
|
|
onClicked: GraphEditorSettings.showOutputAttributes = !GraphEditorSettings.showOutputAttributes
|
|
enabled: tabBar.currentIndex === 0
|
|
}
|
|
CheckBox {
|
|
id: inputToggle
|
|
text: "Input"
|
|
checkable: true
|
|
checked: GraphEditorSettings.showInputAttributes
|
|
onClicked: GraphEditorSettings.showInputAttributes = !GraphEditorSettings.showInputAttributes
|
|
enabled: tabBar.currentIndex === 0
|
|
}
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
RowLayout {
|
|
CheckBox {
|
|
id: defaultToggle
|
|
text: "Default"
|
|
checkable: true
|
|
checked: GraphEditorSettings.showDefaultAttributes
|
|
onClicked: GraphEditorSettings.showDefaultAttributes = !GraphEditorSettings.showDefaultAttributes
|
|
enabled: tabBar.currentIndex === 0
|
|
}
|
|
CheckBox {
|
|
id: modifiedToggle
|
|
text: "Modified"
|
|
checkable: true
|
|
checked: GraphEditorSettings.showModifiedAttributes
|
|
onClicked: GraphEditorSettings.showModifiedAttributes = !GraphEditorSettings.showModifiedAttributes
|
|
enabled: tabBar.currentIndex === 0
|
|
}
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
RowLayout {
|
|
CheckBox {
|
|
id: linkToggle
|
|
text: "Link"
|
|
checkable: true
|
|
checked: GraphEditorSettings.showLinkAttributes
|
|
onClicked: GraphEditorSettings.showLinkAttributes = !GraphEditorSettings.showLinkAttributes
|
|
enabled: tabBar.currentIndex === 0
|
|
}
|
|
CheckBox {
|
|
id: notLinkToggle
|
|
text: "Not Link"
|
|
checkable: true
|
|
checked: GraphEditorSettings.showNotLinkAttributes
|
|
onClicked: GraphEditorSettings.showNotLinkAttributes = !GraphEditorSettings.showNotLinkAttributes
|
|
enabled: tabBar.currentIndex === 0
|
|
}
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
CheckBox {
|
|
id: advancedToggle
|
|
text: "Advanced"
|
|
MaterialLabel {
|
|
anchors.right: parent.right; anchors.rightMargin: parent.padding;
|
|
text: MaterialIcons.build
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
font.pointSize: 8
|
|
}
|
|
checkable: true
|
|
checked: GraphEditorSettings.showAdvancedAttributes
|
|
onClicked: GraphEditorSettings.showAdvancedAttributes = !GraphEditorSettings.showAdvancedAttributes
|
|
}
|
|
}
|
|
MenuItem {
|
|
text: "Open Cache Folder"
|
|
enabled: root.node !== null
|
|
onClicked: Qt.openUrlExternally(Filepath.stringToUrl(root.node.internalFolder))
|
|
}
|
|
|
|
MenuSeparator {}
|
|
|
|
MenuItem {
|
|
enabled: root.node !== null
|
|
text: "Clear Pending Status"
|
|
onClicked: {
|
|
node.clearSubmittedChunks()
|
|
timer.stop()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
|
|
// CompatibilityBadge banner for CompatibilityNode
|
|
Loader {
|
|
active: root.isCompatibilityNode
|
|
Layout.fillWidth: true
|
|
visible: active // For layout update
|
|
|
|
sourceComponent: CompatibilityBadge {
|
|
canUpgrade: root.node.canUpgrade
|
|
issueDetails: root.node.issueDetails
|
|
onUpgradeRequest: root.upgradeRequest()
|
|
sourceComponent: bannerDelegate
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
sourceComponent: root.node ? editor_component : placeholder_component
|
|
|
|
Component {
|
|
id: placeholder_component
|
|
|
|
Item {
|
|
Column {
|
|
anchors.centerIn: parent
|
|
MaterialLabel {
|
|
text: MaterialIcons.select_all
|
|
font.pointSize: 34
|
|
color: Qt.lighter(palette.mid, 1.2)
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
Label {
|
|
color: Qt.lighter(palette.mid, 1.2)
|
|
text: "Select a Node to access its Details"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: editor_component
|
|
|
|
MSplitView {
|
|
anchors.fill: parent
|
|
|
|
// The list of chunks
|
|
ChunksListView {
|
|
id: chunksLV
|
|
visible: (tabBar.currentIndex >= 1 && tabBar.currentIndex <= 3)
|
|
chunks: root.node.chunks
|
|
SplitView.preferredWidth: 55
|
|
SplitView.minimumWidth: 20
|
|
}
|
|
|
|
StackLayout {
|
|
SplitView.fillWidth: true
|
|
|
|
currentIndex: tabBar.currentIndex
|
|
|
|
AttributeEditor {
|
|
id: inOutAttr
|
|
objectsHideable: true
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
model: root.node.attributes
|
|
readOnly: root.readOnly || root.isCompatibilityNode
|
|
onAttributeDoubleClicked: function(mouse, attribute) { root.attributeDoubleClicked(mouse, attribute) }
|
|
onUpgradeRequest: root.upgradeRequest()
|
|
filterText: searchBar.text
|
|
}
|
|
|
|
Loader {
|
|
active: (tabBar.currentIndex === 1)
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
sourceComponent: NodeLog {
|
|
// anchors.fill: parent
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
width: parent.width
|
|
height: parent.height
|
|
id: nodeLog
|
|
node: root.node
|
|
currentChunkIndex: chunksLV.currentIndex
|
|
currentChunk: chunksLV.currentChunk
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
active: (tabBar.currentIndex === 2)
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
sourceComponent: NodeStatistics {
|
|
id: nodeStatistics
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
node: root.node
|
|
currentChunkIndex: chunksLV.currentIndex
|
|
currentChunk: chunksLV.currentChunk
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
active: (tabBar.currentIndex === 3)
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
sourceComponent: NodeStatus {
|
|
id: nodeStatus
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
node: root.node
|
|
currentChunkIndex: chunksLV.currentIndex
|
|
currentChunk: chunksLV.currentChunk
|
|
}
|
|
}
|
|
|
|
NodeDocumentation {
|
|
id: nodeDocumentation
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
node: root.node
|
|
}
|
|
|
|
AttributeEditor {
|
|
id: nodeInternalAttr
|
|
objectsHideable: false
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
model: root.node.internalAttributes
|
|
readOnly: root.readOnly || root.isCompatibilityNode
|
|
onAttributeDoubleClicked: function(mouse, attribute) { root.attributeDoubleClicked(mouse, attribute) }
|
|
onUpgradeRequest: root.upgradeRequest()
|
|
filterText: searchBar.text
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TabBar {
|
|
id: tabBar
|
|
visible: root.node !== null
|
|
|
|
property bool isComputable: root.node !== null && root.node.isComputable
|
|
|
|
Layout.fillWidth: true
|
|
width: childrenRect.width
|
|
position: TabBar.Footer
|
|
currentIndex: 0
|
|
TabButton {
|
|
text: "Attributes"
|
|
padding: 4
|
|
leftPadding: 8
|
|
rightPadding: leftPadding
|
|
}
|
|
TabButton {
|
|
visible: tabBar.isComputable
|
|
width: !visible ? 0 : tabBar.width / tabBar.count
|
|
text: "Log"
|
|
leftPadding: 8
|
|
rightPadding: leftPadding
|
|
}
|
|
TabButton {
|
|
visible: tabBar.isComputable
|
|
width: !visible ? 0 : tabBar.width / tabBar.count
|
|
text: "Statistics"
|
|
leftPadding: 8
|
|
rightPadding: leftPadding
|
|
}
|
|
TabButton {
|
|
visible: tabBar.isComputable
|
|
width: !visible ? 0 : tabBar.width / tabBar.count
|
|
text: "Status"
|
|
leftPadding: 8
|
|
rightPadding: leftPadding
|
|
}
|
|
TabButton {
|
|
text: "Documentation"
|
|
leftPadding: 8
|
|
rightPadding: leftPadding
|
|
}
|
|
TabButton {
|
|
text: "Notes"
|
|
padding: 4
|
|
leftPadding: 8
|
|
rightPadding: leftPadding
|
|
}
|
|
|
|
onIsComputableChanged: {
|
|
if (!isComputable) {
|
|
tabBar.currentIndex = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|