Skip to content

Commit dd30cf2

Browse files
committed
[ui] NodeActions: Explore graph to check if we can compute/submit
1 parent c937d84 commit dd30cf2

File tree

2 files changed

+51
-43
lines changed

2 files changed

+51
-43
lines changed

meshroom/ui/graph.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,8 +1169,29 @@ def pasteNodes(self, serializedData: str, position: Optional[QPoint]=None) -> li
11691169
logging.warning("Content is not a valid graph data.")
11701170
return []
11711171
return result
1172-
1173-
1172+
1173+
@Slot(Node, result=bool)
1174+
def canComputeNode(self, node: Node) -> bool:
1175+
""" Check if the node can be computed """
1176+
if node.isCompatibilityNode or not node.isComputableType:
1177+
return False
1178+
if node.isComputed:
1179+
return True
1180+
if self._graph.canComputeTopologically(node) and self._graph.canSubmitOrCompute(node) % 2 == 1:
1181+
return True
1182+
return False
1183+
1184+
@Slot(Node, result=bool)
1185+
def canSubmitNode(self, node: Node) -> bool:
1186+
""" Check if the node can be submitted """
1187+
if node.isCompatibilityNode or not node.isComputableType:
1188+
return False
1189+
if node.isComputed:
1190+
return True
1191+
if self._graph.canComputeTopologically(node) and self._graph.canSubmitOrCompute(node)> 1:
1192+
return True
1193+
return False
1194+
11741195
undoStack = Property(QObject, lambda self: self._undoStack, constant=True)
11751196
graphChanged = Signal()
11761197
graph = Property(Graph, lambda self: self._graph, notify=graphChanged)

meshroom/ui/qml/Controls/NodeActions.qml

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,9 @@ Item {
7474
// Update position
7575
function updatePosition() {
7676
if (!selectedNodeDelegate || !draggable) return
77-
7877
// Calculate node position in screen coordinates
7978
const nodeScreenX = selectedNodeDelegate.x * draggable.scale + draggable.x
8079
const nodeScreenY = selectedNodeDelegate.y * draggable.scale + draggable.y
81-
8280
// Position header above the node (fixed offset in screen pixels)
8381
x = nodeScreenX + (selectedNodeDelegate.width * draggable.scale - width) / 2
8482
y = nodeScreenY - height - headerOffset
@@ -105,7 +103,11 @@ Item {
105103
//
106104

107105
property bool nodeIsLocked: false
108-
property bool submittedExternally: false
106+
property bool canComputeNode: false
107+
property bool canStopNode: false
108+
property bool canSubmitNode: false
109+
property bool nodeSubmitted: false
110+
109111
property int computeButtonState: NodeActions.ButtonState.LAUNCHABLE
110112
property string computeButtonIcon: {
111113
switch (computeButtonState) {
@@ -117,57 +119,40 @@ Item {
117119
property int submitButtonState: NodeActions.ButtonState.LAUNCHABLE
118120

119121
function getComputeButtonState(node) {
120-
if (!node.isComputableType || node.isCompatibilityNode)
121-
return NodeActions.ButtonState.DISABLED
122-
if (node.canBeStopped()) return NodeActions.ButtonState.STOPPABLE
123-
if (node.canBeCanceled()) return NodeActions.ButtonState.STOPPABLE
124-
if (actionHeader.nodeIsLocked) return NodeActions.ButtonState.DISABLED
125-
switch (node.globalStatus) {
126-
case "NONE":
127-
case "ERROR":
128-
case "STOPPED":
129-
case "KILLED":
130-
return NodeActions.ButtonState.LAUNCHABLE
131-
case "SUCCESS":
132-
return NodeActions.ButtonState.DELETABLE
133-
}
122+
if (actionHeader.canStopNode)
123+
return NodeActions.ButtonState.STOPPABLE
124+
if (!actionHeader.nodeIsLocked && node.globalStatus == "SUCCESS")
125+
return NodeActions.ButtonState.DELETABLE
126+
if (!actionHeader.nodeIsLocked && actionHeader.canComputeNode)
127+
return NodeActions.ButtonState.LAUNCHABLE
134128
return NodeActions.ButtonState.DISABLED
135129
}
136130

137131
function getSubmitButtonState(node) {
138-
if (!node.isComputableType || node.isCompatibilityNode)
132+
if (actionHeader.nodeIsLocked || actionHeader.canStopNode)
139133
return NodeActions.ButtonState.DISABLED
140-
if (actionHeader.nodeIsLocked || node.canBeStopped()) {
141-
return NodeActions.ButtonState.DISABLED
142-
}
143-
switch (node.globalStatus) {
144-
case "NONE":
145-
case "ERROR":
146-
case "STOPPED":
147-
case "KILLED":
148-
case "SUCCESS":
149-
return NodeActions.ButtonState.LAUNCHABLE
150-
return NodeActions.ButtonState.LAUNCHABLE
151-
break
152-
// SUBMITTED / RUNNING / INPUT -> DISABLED
153-
}
134+
if (!actionHeader.nodeIsLocked && actionHeader.canSubmitNode)
135+
return NodeActions.ButtonState.LAUNCHABLE
154136
return NodeActions.ButtonState.DISABLED
155137
}
156138

157139
function isSubmittedExternally(node) {
158-
if (node.globalExecMode == "EXTERN" && node.globalStatus == "SUBMITTED")
159-
return true
160-
return false
140+
return node.globalExecMode == "EXTERN" && ["RUNNING", "SUBMITTED"].includes(node.globalStatus)
161141
}
162142

163143
function updateProperties(node) {
144+
if (!node) return
145+
// Update properties values
146+
actionHeader.canComputeNode = uigraph.canComputeNode(node)
147+
actionHeader.canSubmitNode = uigraph.canSubmitNode(node)
148+
actionHeader.canStopNode = node.canBeStopped()
164149
actionHeader.nodeIsLocked = node.locked
150+
actionHeader.nodeSubmitted = isSubmittedExternally(node)
151+
// Update button states
165152
actionHeader.computeButtonState = getComputeButtonState(node)
166153
actionHeader.submitButtonState = getSubmitButtonState(node)
167-
actionHeader.submittedExternally = isSubmittedExternally(node)
168154
}
169155

170-
171156
// Set initial state & position
172157
onSelectedNodeDelegateChanged: {
173158
updatePosition()
@@ -208,7 +193,7 @@ Item {
208193
font.pointSize: 16
209194
text: actionHeader.computeButtonIcon
210195
padding: 6
211-
ToolTip.text: "Start/Stop Compute"
196+
ToolTip.text: "Start/Stop/Restart Compute"
212197
ToolTip.visible: hovered
213198
ToolTip.delay: 1000
214199
enabled: actionHeader.computeButtonState != NodeActions.ButtonState.DISABLED
@@ -233,6 +218,10 @@ Item {
233218
radius: 3
234219
}
235220
onClicked: {
221+
// The remaining issue with this design is that if we computed half the chunks
222+
// then the only option we have is to resume the compute
223+
// We don't have a restart from zero (delete + start) in this case
224+
// But this would require an additional button
236225
switch (actionHeader.computeButtonState) {
237226
case NodeActions.ButtonState.STOPPABLE:
238227
root.stopComputeRequest(actionHeader.selectedNode)
@@ -243,7 +232,6 @@ Item {
243232
case NodeActions.ButtonState.DELETABLE:
244233
root.deleteDataRequest(actionHeader.selectedNode)
245234
break
246-
default: break
247235
}
248236
}
249237
}
@@ -259,10 +247,9 @@ Item {
259247
ToolTip.delay: 1000
260248
visible: root.uigraph ? root.uigraph.canSubmit : false
261249
enabled: actionHeader.submitButtonState != NodeActions.ButtonState.DISABLED
262-
// enabled: actionHeader.selectedNode ? !actionHeader.nodeLocked : false
263250
background: Rectangle {
264251
color: {
265-
if (actionHeader.submittedExternally)
252+
if (actionHeader.nodeSubmitted)
266253
return Qt.darker(Colors.statusColors["SUBMITTED"], 1.2)
267254
if (!submitButton.enabled) return activePalette.button
268255
if (submitButton.hovered) return activePalette.highlight

0 commit comments

Comments
 (0)