mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-04-29 10:17:27 +02:00
Merge pull request #2624 from alicevision/fix/NodeEditorTab
[ui] NodeEditor: Addressed Tab Retention when switching Node selection
This commit is contained in:
commit
05863369f5
4 changed files with 217 additions and 182 deletions
|
@ -215,6 +215,7 @@ class Graph(BaseObject):
|
||||||
super(Graph, self).__init__(parent)
|
super(Graph, self).__init__(parent)
|
||||||
self.name = name
|
self.name = name
|
||||||
self._loading = False
|
self._loading = False
|
||||||
|
self._saving = False
|
||||||
self._updateEnabled = True
|
self._updateEnabled = True
|
||||||
self._updateRequested = False
|
self._updateRequested = False
|
||||||
self.dirtyTopology = False
|
self.dirtyTopology = False
|
||||||
|
@ -252,6 +253,11 @@ class Graph(BaseObject):
|
||||||
""" Return True if the graph is currently being loaded. """
|
""" Return True if the graph is currently being loaded. """
|
||||||
return self._loading
|
return self._loading
|
||||||
|
|
||||||
|
@property
|
||||||
|
def isSaving(self):
|
||||||
|
""" Return True if the graph is currently being saved. """
|
||||||
|
return self._saving
|
||||||
|
|
||||||
@Slot(str)
|
@Slot(str)
|
||||||
def load(self, filepath, setupProjectFile=True, importProject=False, publishOutputs=False):
|
def load(self, filepath, setupProjectFile=True, importProject=False, publishOutputs=False):
|
||||||
"""
|
"""
|
||||||
|
@ -1347,6 +1353,23 @@ class Graph(BaseObject):
|
||||||
return str(self.toDict())
|
return str(self.toDict())
|
||||||
|
|
||||||
def save(self, filepath=None, setupProjectFile=True, template=False):
|
def save(self, filepath=None, setupProjectFile=True, template=False):
|
||||||
|
"""
|
||||||
|
Save the current Meshroom graph as a serialized ".mg" file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filepath: project filepath to save as.
|
||||||
|
setupProjectFile: Store the reference to the project file and setup the cache directory.
|
||||||
|
If false, it only saves the graph of the project file as a template.
|
||||||
|
template: If true, saves the current graph as a template.
|
||||||
|
"""
|
||||||
|
# Update the saving flag indicating that the current graph is being saved
|
||||||
|
self._saving = True
|
||||||
|
try:
|
||||||
|
self._save(filepath=filepath, setupProjectFile=setupProjectFile, template=template)
|
||||||
|
finally:
|
||||||
|
self._saving = False
|
||||||
|
|
||||||
|
def _save(self, filepath=None, setupProjectFile=True, template=False):
|
||||||
path = filepath or self._filepath
|
path = filepath or self._filepath
|
||||||
if not path:
|
if not path:
|
||||||
raise ValueError("filepath must be specified for unsaved files.")
|
raise ValueError("filepath must be specified for unsaved files.")
|
||||||
|
@ -1636,6 +1659,7 @@ class Graph(BaseObject):
|
||||||
edges = Property(BaseObject, edges.fget, constant=True)
|
edges = Property(BaseObject, edges.fget, constant=True)
|
||||||
filepathChanged = Signal()
|
filepathChanged = Signal()
|
||||||
filepath = Property(str, lambda self: self._filepath, notify=filepathChanged)
|
filepath = Property(str, lambda self: self._filepath, notify=filepathChanged)
|
||||||
|
isSaving = Property(bool, isSaving.fget, constant=True)
|
||||||
fileReleaseVersion = Property(str, lambda self: self.header.get(Graph.IO.Keys.ReleaseVersion, "0.0"),
|
fileReleaseVersion = Property(str, lambda self: self.header.get(Graph.IO.Keys.ReleaseVersion, "0.0"),
|
||||||
notify=filepathChanged)
|
notify=filepathChanged)
|
||||||
fileDateVersion = Property(float, fileDateVersion.fget, fileDateVersion.fset, notify=filepathChanged)
|
fileDateVersion = Property(float, fileDateVersion.fget, fileDateVersion.fset, notify=filepathChanged)
|
||||||
|
|
|
@ -20,6 +20,16 @@ Page {
|
||||||
property alias unsavedDialog: unsavedDialog
|
property alias unsavedDialog: unsavedDialog
|
||||||
property alias workspaceView: workspaceView
|
property alias workspaceView: workspaceView
|
||||||
|
|
||||||
|
readonly property var scenefile: _reconstruction ? _reconstruction.graph.filepath : "";
|
||||||
|
|
||||||
|
onScenefileChanged: {
|
||||||
|
// Check if we're not currently saving and emit the currentProjectChanged signal
|
||||||
|
if (! _reconstruction.graph.isSaving) {
|
||||||
|
// Refresh the NodeEditor
|
||||||
|
nodeEditor.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
id: settingsUILayout
|
id: settingsUILayout
|
||||||
category: "UILayout"
|
category: "UILayout"
|
||||||
|
|
|
@ -42,6 +42,14 @@ Panel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
/**
|
||||||
|
* Refresh properties of the Node Editor.
|
||||||
|
*/
|
||||||
|
// Reset tab bar's current index
|
||||||
|
tabBar.currentIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
headerBar: RowLayout {
|
headerBar: RowLayout {
|
||||||
Label {
|
Label {
|
||||||
id: computationInfo
|
id: computationInfo
|
||||||
|
@ -372,6 +380,9 @@ Panel {
|
||||||
|
|
||||||
property bool isComputable: root.node !== null && root.node.isComputable
|
property bool isComputable: root.node !== null && root.node.isComputable
|
||||||
|
|
||||||
|
// The indices of the tab bar which can be shown for incomputable nodes
|
||||||
|
readonly property var nonComputableTabIndices: [0, 4, 5];
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
position: TabBar.Footer
|
position: TabBar.Footer
|
||||||
|
@ -415,9 +426,11 @@ Panel {
|
||||||
rightPadding: leftPadding
|
rightPadding: leftPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
onIsComputableChanged: {
|
onVisibleChanged: {
|
||||||
if (!isComputable) {
|
// If we have a node selected and the node is not Computable
|
||||||
tabBar.currentIndex = 0
|
// Reset the currentIndex to 0, if the current index is not allowed for an incomputable node
|
||||||
|
if ((root.node && !root.node.isComputable) && (nonComputableTabIndices.indexOf(tabBar.currentIndex) === -1)) {
|
||||||
|
tabBar.currentIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,220 +310,208 @@ Item {
|
||||||
*** CPU UI ***
|
*** CPU UI ***
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
ColumnLayout {
|
Button {
|
||||||
|
id: toggleCpuBtn
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
text: "Toggle CPU's"
|
||||||
|
state: "closed"
|
||||||
|
|
||||||
Button {
|
onClicked: state === "opened" ? state = "closed" : state = "opened"
|
||||||
id: toggleCpuBtn
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: "Toggle CPU's"
|
|
||||||
state: "closed"
|
|
||||||
|
|
||||||
onClicked: state === "opened" ? state = "closed" : state = "opened"
|
MaterialLabel {
|
||||||
|
text: MaterialIcons.arrow_drop_down
|
||||||
MaterialLabel {
|
font.pointSize: 14
|
||||||
text: MaterialIcons.arrow_drop_down
|
anchors.right: parent.right
|
||||||
font.pointSize: 14
|
|
||||||
anchors.right: parent.right
|
|
||||||
}
|
|
||||||
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: "opened"
|
|
||||||
PropertyChanges { target: cpuBtnContainer; visible: true }
|
|
||||||
PropertyChanges { target: toggleCpuBtn; down: true }
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "closed"
|
|
||||||
PropertyChanges { target: cpuBtnContainer; visible: false }
|
|
||||||
PropertyChanges { target: toggleCpuBtn; down: false }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
states: [
|
||||||
id: cpuBtnContainer
|
State {
|
||||||
|
name: "opened"
|
||||||
|
PropertyChanges { target: cpuBtnContainer; visible: true }
|
||||||
|
PropertyChanges { target: toggleCpuBtn; down: true }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "closed"
|
||||||
|
PropertyChanges { target: cpuBtnContainer; visible: false }
|
||||||
|
PropertyChanges { target: toggleCpuBtn; down: false }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Item {
|
||||||
implicitHeight: childrenRect.height
|
id: cpuBtnContainer
|
||||||
Layout.leftMargin: 25
|
|
||||||
|
|
||||||
RowLayout {
|
Layout.fillWidth: true
|
||||||
width: parent.width
|
implicitHeight: childrenRect.height
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
Layout.leftMargin: 25
|
||||||
|
|
||||||
ChartViewCheckBox {
|
RowLayout {
|
||||||
id: allCPU
|
width: parent.width
|
||||||
text: "ALL"
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
color: textColor
|
|
||||||
checkState: cpuLegend.buttonGroup.checkState
|
ChartViewCheckBox {
|
||||||
leftPadding: 0
|
id: allCPU
|
||||||
onClicked: {
|
text: "ALL"
|
||||||
var _checked = checked;
|
color: textColor
|
||||||
for (var i = 0; i < cpuChart.count; ++i) {
|
checkState: cpuLegend.buttonGroup.checkState
|
||||||
cpuChart.series(i).visible = _checked
|
leftPadding: 0
|
||||||
}
|
onClicked: {
|
||||||
|
var _checked = checked;
|
||||||
|
for (var i = 0; i < cpuChart.count; ++i) {
|
||||||
|
cpuChart.series(i).visible = _checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChartViewLegend {
|
|
||||||
id: cpuLegend
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
chartView: cpuChart
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InteractiveChartView {
|
|
||||||
id: cpuChart
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: width / 2
|
|
||||||
margins.top: 0
|
|
||||||
margins.bottom: 0
|
|
||||||
antialiasing: true
|
|
||||||
|
|
||||||
legend.visible: false
|
|
||||||
theme: ChartView.ChartThemeLight
|
|
||||||
backgroundColor: "transparent"
|
|
||||||
plotAreaColor: "transparent"
|
|
||||||
titleColor: textColor
|
|
||||||
|
|
||||||
visible: (root.fileVersion > 0.0) // Only visible if we have valid information
|
|
||||||
title: "CPU: " + root.nbCores + " cores, " + root.cpuFrequency + "MHz"
|
|
||||||
|
|
||||||
ValueAxis {
|
|
||||||
id: valueCpuY
|
|
||||||
min: 0
|
|
||||||
max: 100
|
|
||||||
titleText: "<span style='color: " + textColor + "'>%</span>"
|
|
||||||
color: textColor
|
|
||||||
gridLineColor: textColor
|
|
||||||
minorGridLineColor: textColor
|
|
||||||
shadesColor: textColor
|
|
||||||
shadesBorderColor: textColor
|
|
||||||
labelsColor: textColor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueAxis {
|
ChartViewLegend {
|
||||||
id: valueCpuX
|
id: cpuLegend
|
||||||
min: 0
|
Layout.fillWidth: true
|
||||||
max: root.deltaTime * Math.max(1, root.nbReads)
|
Layout.fillHeight: true
|
||||||
titleText: "<span style='color: " + textColor + "'>Minutes</span>"
|
chartView: cpuChart
|
||||||
color: textColor
|
|
||||||
gridLineColor: textColor
|
|
||||||
minorGridLineColor: textColor
|
|
||||||
shadesColor: textColor
|
|
||||||
shadesBorderColor: textColor
|
|
||||||
labelsColor: textColor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InteractiveChartView {
|
||||||
|
id: cpuChart
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: width / 2
|
||||||
|
margins.top: 0
|
||||||
|
margins.bottom: 0
|
||||||
|
antialiasing: true
|
||||||
|
|
||||||
|
legend.visible: false
|
||||||
|
theme: ChartView.ChartThemeLight
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
plotAreaColor: "transparent"
|
||||||
|
titleColor: textColor
|
||||||
|
|
||||||
|
visible: (root.fileVersion > 0.0) // Only visible if we have valid information
|
||||||
|
title: "CPU: " + root.nbCores + " cores, " + root.cpuFrequency + "MHz"
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: valueCpuY
|
||||||
|
min: 0
|
||||||
|
max: 100
|
||||||
|
titleText: "<span style='color: " + textColor + "'>%</span>"
|
||||||
|
color: textColor
|
||||||
|
gridLineColor: textColor
|
||||||
|
minorGridLineColor: textColor
|
||||||
|
shadesColor: textColor
|
||||||
|
shadesBorderColor: textColor
|
||||||
|
labelsColor: textColor
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: valueCpuX
|
||||||
|
min: 0
|
||||||
|
max: root.deltaTime * Math.max(1, root.nbReads)
|
||||||
|
titleText: "<span style='color: " + textColor + "'>Minutes</span>"
|
||||||
|
color: textColor
|
||||||
|
gridLineColor: textColor
|
||||||
|
minorGridLineColor: textColor
|
||||||
|
shadesColor: textColor
|
||||||
|
shadesBorderColor: textColor
|
||||||
|
labelsColor: textColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
*** RAM UI ***
|
*** RAM UI ***
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
ColumnLayout {
|
InteractiveChartView {
|
||||||
|
id: ramChart
|
||||||
|
margins.top: 0
|
||||||
|
margins.bottom: 0
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: width / 2
|
||||||
|
antialiasing: true
|
||||||
|
legend.color: textColor
|
||||||
|
legend.labelColor: textColor
|
||||||
|
legend.visible: false
|
||||||
|
theme: ChartView.ChartThemeLight
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
plotAreaColor: "transparent"
|
||||||
|
titleColor: textColor
|
||||||
|
|
||||||
InteractiveChartView {
|
visible: (root.fileVersion > 0.0) // Only visible if we have valid information
|
||||||
id: ramChart
|
title: root.ramLabel + root.ramTotal + "GB"
|
||||||
margins.top: 0
|
|
||||||
margins.bottom: 0
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: width / 2
|
|
||||||
antialiasing: true
|
|
||||||
legend.color: textColor
|
|
||||||
legend.labelColor: textColor
|
|
||||||
legend.visible: false
|
|
||||||
theme: ChartView.ChartThemeLight
|
|
||||||
backgroundColor: "transparent"
|
|
||||||
plotAreaColor: "transparent"
|
|
||||||
titleColor: textColor
|
|
||||||
|
|
||||||
visible: (root.fileVersion > 0.0) // Only visible if we have valid information
|
ValueAxis {
|
||||||
title: root.ramLabel + root.ramTotal + "GB"
|
id: valueRamY
|
||||||
|
min: 0
|
||||||
|
max: 100
|
||||||
|
titleText: "<span style='color: " + textColor + "'>%</span>"
|
||||||
|
color: textColor
|
||||||
|
gridLineColor: textColor
|
||||||
|
minorGridLineColor: textColor
|
||||||
|
shadesColor: textColor
|
||||||
|
shadesBorderColor: textColor
|
||||||
|
labelsColor: textColor
|
||||||
|
}
|
||||||
|
|
||||||
ValueAxis {
|
ValueAxis {
|
||||||
id: valueRamY
|
id: valueRamX
|
||||||
min: 0
|
min: 0
|
||||||
max: 100
|
max: root.deltaTime * Math.max(1, root.nbReads)
|
||||||
titleText: "<span style='color: " + textColor + "'>%</span>"
|
titleText: "<span style='color: " + textColor + "'>Minutes</span>"
|
||||||
color: textColor
|
color: textColor
|
||||||
gridLineColor: textColor
|
gridLineColor: textColor
|
||||||
minorGridLineColor: textColor
|
minorGridLineColor: textColor
|
||||||
shadesColor: textColor
|
shadesColor: textColor
|
||||||
shadesBorderColor: textColor
|
shadesBorderColor: textColor
|
||||||
labelsColor: textColor
|
labelsColor: textColor
|
||||||
}
|
|
||||||
|
|
||||||
ValueAxis {
|
|
||||||
id: valueRamX
|
|
||||||
min: 0
|
|
||||||
max: root.deltaTime * Math.max(1, root.nbReads)
|
|
||||||
titleText: "<span style='color: " + textColor + "'>Minutes</span>"
|
|
||||||
color: textColor
|
|
||||||
gridLineColor: textColor
|
|
||||||
minorGridLineColor: textColor
|
|
||||||
shadesColor: textColor
|
|
||||||
shadesBorderColor: textColor
|
|
||||||
labelsColor: textColor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
*** GPU UI ***
|
*** GPU UI ***
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
ColumnLayout {
|
InteractiveChartView {
|
||||||
|
id: gpuChart
|
||||||
|
|
||||||
InteractiveChartView {
|
Layout.fillWidth: true
|
||||||
id: gpuChart
|
Layout.preferredHeight: width/2
|
||||||
|
margins.top: 0
|
||||||
|
margins.bottom: 0
|
||||||
|
antialiasing: true
|
||||||
|
legend.color: textColor
|
||||||
|
legend.labelColor: textColor
|
||||||
|
theme: ChartView.ChartThemeLight
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
plotAreaColor: "transparent"
|
||||||
|
titleColor: textColor
|
||||||
|
|
||||||
Layout.fillWidth: true
|
visible: (root.fileVersion >= 2.0) // No GPU information was collected before stats 2.0 fileVersion
|
||||||
Layout.preferredHeight: width/2
|
title: (root.gpuName || root.gpuTotalMemory) ? ("GPU: " + root.gpuName + ", " + root.gpuTotalMemory + "MB") : "No GPU"
|
||||||
margins.top: 0
|
|
||||||
margins.bottom: 0
|
|
||||||
antialiasing: true
|
|
||||||
legend.color: textColor
|
|
||||||
legend.labelColor: textColor
|
|
||||||
theme: ChartView.ChartThemeLight
|
|
||||||
backgroundColor: "transparent"
|
|
||||||
plotAreaColor: "transparent"
|
|
||||||
titleColor: textColor
|
|
||||||
|
|
||||||
visible: (root.fileVersion >= 2.0) // No GPU information was collected before stats 2.0 fileVersion
|
ValueAxis {
|
||||||
title: (root.gpuName || root.gpuTotalMemory) ? ("GPU: " + root.gpuName + ", " + root.gpuTotalMemory + "MB") : "No GPU"
|
id: valueGpuY
|
||||||
|
min: 0
|
||||||
|
max: root.gpuMaxAxis
|
||||||
|
titleText: "<span style='color: " + textColor + "'>%, °C</span>"
|
||||||
|
color: textColor
|
||||||
|
gridLineColor: textColor
|
||||||
|
minorGridLineColor: textColor
|
||||||
|
shadesColor: textColor
|
||||||
|
shadesBorderColor: textColor
|
||||||
|
labelsColor: textColor
|
||||||
|
}
|
||||||
|
|
||||||
ValueAxis {
|
ValueAxis {
|
||||||
id: valueGpuY
|
id: valueGpuX
|
||||||
min: 0
|
min: 0
|
||||||
max: root.gpuMaxAxis
|
max: root.deltaTime * Math.max(1, root.nbReads)
|
||||||
titleText: "<span style='color: " + textColor + "'>%, °C</span>"
|
titleText: "<span style='color: " + textColor + "'>Minutes</span>"
|
||||||
color: textColor
|
color: textColor
|
||||||
gridLineColor: textColor
|
gridLineColor: textColor
|
||||||
minorGridLineColor: textColor
|
minorGridLineColor: textColor
|
||||||
shadesColor: textColor
|
shadesColor: textColor
|
||||||
shadesBorderColor: textColor
|
shadesBorderColor: textColor
|
||||||
labelsColor: textColor
|
labelsColor: textColor
|
||||||
}
|
|
||||||
|
|
||||||
ValueAxis {
|
|
||||||
id: valueGpuX
|
|
||||||
min: 0
|
|
||||||
max: root.deltaTime * Math.max(1, root.nbReads)
|
|
||||||
titleText: "<span style='color: " + textColor + "'>Minutes</span>"
|
|
||||||
color: textColor
|
|
||||||
gridLineColor: textColor
|
|
||||||
minorGridLineColor: textColor
|
|
||||||
shadesColor: textColor
|
|
||||||
shadesBorderColor: textColor
|
|
||||||
labelsColor: textColor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue