99 id: root
1010
1111 // Settings
12- property real headerOffset: 10 // Distance above the node in screen pixels
13- property real _opacity: 0.9
12+ readonly property real headerOffset: 10 // Distance above the node in screen pixels
13+ readonly property real _opacity: 0.9
1414
1515 // Objects passed from the graph editor
1616 property var uigraph: null
2222 signal stopComputeRequest (var node)
2323 signal reComputeRequest (var node)
2424 signal submitRequest (var node)
25- signal reSubmitRequest (var node)
2625
2726 SystemPalette { id: activePalette }
2827
@@ -32,15 +31,20 @@ Item {
3231 function nodeDelegate (node ) {
3332 if (! nodeRepeater)
3433 return null
35-
3634 for (var i = 0 ; i < nodeRepeater .count ; ++ i) {
3735 if (nodeRepeater .itemAt (i).node === node)
3836 return nodeRepeater .itemAt (i)
3937 }
40-
4138 return null
4239 }
43-
40+
41+ enum ButtonState {
42+ LAUNCHABLE ,
43+ STOPPABLE ,
44+ RELAUNCHABLE ,
45+ DISABLED
46+ }
47+
4448 Rectangle {
4549 id: actionHeader
4650
@@ -53,19 +57,9 @@ Item {
5357 width: actionItemsRow .width
5458 height: actionItemsRow .height
5559
56- // State properties
57- property string currentExecMode: selectedNode ? selectedNode .globalExecMode : " NONE"
58- property string currentStatus: selectedNode ? selectedNode .globalStatus : " NONE"
59- property bool nodeCanBeStopped: selectedNode ? selectedNode .canBeStopped () : false
60- property bool nodeIsExternal: selectedNode ? selectedNode .isExternal : false
61- property bool nodeLocked: selectedNode ? selectedNode .locked : false
62-
63- // Derived values
64- readonly property bool runningExternally: currentExecMode === " EXTERN"
65- && [" SUBMITTED" , " RUNNING" ].includes (currentStatus)
66- readonly property bool stoppable: selectedNode && currentStatus === " RUNNING" && nodeCanBeStopped
67- readonly property bool launchable: selectedNode &&
68- (nodeCanBeStopped || [" NONE" ," STOPPED" ," KILLED" ," ERROR" ].includes (currentStatus))
60+ //
61+ // ===== Manage NodeActions position =====
62+ //
6963
7064 // Prevents losing focus on the node when we click on buttons of the actionItems
7165 MouseArea {
@@ -80,11 +74,11 @@ Item {
8074 // Update position
8175 function updatePosition () {
8276 if (! selectedNodeDelegate || ! draggable) return
83-
77+
8478 // Calculate node position in screen coordinates
8579 const nodeScreenX = selectedNodeDelegate .x * draggable .scale + draggable .x
8680 const nodeScreenY = selectedNodeDelegate .y * draggable .scale + draggable .y
87-
81+
8882 // Position header above the node (fixed offset in screen pixels)
8983 x = nodeScreenX + (selectedNodeDelegate .width * draggable .scale - width) / 2
9084 y = nodeScreenY - height - headerOffset
@@ -97,36 +91,104 @@ Item {
9791 function onYChanged () { actionHeader .updatePosition () }
9892 function onScaleChanged () { actionHeader .updatePosition () }
9993 }
100-
94+
10195 // Update position when nodes are moved
10296 Connections {
10397 target: actionHeader .selectedNodeDelegate
10498 function onXChanged () { actionHeader .updatePosition () }
10599 function onYChanged () { actionHeader .updatePosition () }
106100 ignoreUnknownSignals: true
107101 }
102+
103+ //
104+ // ===== Manage buttons =====
105+ //
106+
107+ property bool nodeIsLocked: false
108+ property bool submittedExternally: false
109+ property int computeButtonState: NodeActions .ButtonState .LAUNCHABLE
110+ property string computeButtonIcon: {
111+ switch (computeButtonState) {
112+ case NodeActions .ButtonState .STOPPABLE : return MaterialIcons .cancel_schedule_send
113+ case NodeActions .ButtonState .RELAUNCHABLE : return MaterialIcons .autorenew
114+ default : return MaterialIcons .send
115+ }
116+ }
117+ property int submitButtonState: NodeActions .ButtonState .LAUNCHABLE
118+
119+ function getComputeButtonState (node ) {
120+ if (node .canBeStopped ()) return NodeActions .ButtonState .STOPPABLE
121+ if (node .canBeCanceled ()) return NodeActions .ButtonState .STOPPABLE
122+ if (actionHeader .nodeIsLocked ) return NodeActions .ButtonState .DISABLED
123+ switch (node .globalStatus ) {
124+ case " NONE" :
125+ case " ERROR" :
126+ case " STOPPED" :
127+ case " KILLED" :
128+ return NodeActions .ButtonState .LAUNCHABLE
129+ case " SUCCESS" :
130+ return NodeActions .ButtonState .RELAUNCHABLE
131+ }
132+ return NodeActions .ButtonState .DISABLED
133+ }
134+
135+ function getSubmitButtonState (node ) {
136+ if (actionHeader .nodeIsLocked || node .canBeStopped ()) {
137+ return NodeActions .ButtonState .DISABLED
138+ }
139+ switch (node .globalStatus ) {
140+ case " NONE" :
141+ case " ERROR" :
142+ case " STOPPED" :
143+ case " KILLED" :
144+ case " SUCCESS" :
145+ return NodeActions .ButtonState .LAUNCHABLE
146+ return NodeActions .ButtonState .LAUNCHABLE
147+ break
148+ // SUBMITTED / RUNNING / INPUT -> DISABLED
149+ }
150+ return NodeActions .ButtonState .DISABLED
151+ }
108152
109- // Set initial position
110- onSelectedNodeDelegateChanged: updatePosition ()
153+ function isSubmittedExternally (node ) {
154+ if (node .globalExecMode == " EXTERN" && node .globalStatus == " SUBMITTED" )
155+ return true
156+ return false
157+ }
158+
159+ function updateProperties (node ) {
160+ actionHeader .nodeIsLocked = node .locked
161+ actionHeader .computeButtonState = getComputeButtonState (node)
162+ actionHeader .submitButtonState = getSubmitButtonState (node)
163+ actionHeader .submittedExternally = isSubmittedExternally (node)
164+ }
165+
166+
167+ // Set initial state & position
168+ onSelectedNodeDelegateChanged: {
169+ updatePosition ()
170+ if (actionHeader .selectedNode ) {
171+ actionHeader .updateProperties (actionHeader .selectedNode )
172+ }
173+ }
111174
112175 // Listen to updates to status
113176 Connections {
114177 target: actionHeader .selectedNode
115- function onGlobalStatusChanged () { actionHeader .currentStatus = target .globalStatus }
116- function onGlobalExecModeChanged () { actionHeader .currentExecMode = target .globalExecMode }
117- function onIsComputedChanged () { actionHeader .nodeCanBeStopped = target .canBeStopped () }
118- function onLockedChanged () { actionHeader .nodeLocked = target .locked }
178+ function onGlobalStatusChanged () {
179+ actionHeader .updateProperties (target)
180+ }
181+ function onLockedChanged () {
182+ actionHeader .nodeIsLocked = target .locked
183+ }
119184 ignoreUnknownSignals: true
120185 }
121186
122- // Also listen to uigraph for status updates
187+ // Listen to updates from nodes that are not selected
123188 Connections {
124189 target: root .uigraph
125- function onComputationStatusChanged () {
126- actionHeader .currentStatus = actionHeader .selectedNode ? actionHeader .selectedNode .globalStatus : " NONE"
127- }
128- function onNodeStatusUpdated () {
129- actionHeader .currentStatus = actionHeader .selectedNode ? actionHeader .selectedNode .globalStatus : " NONE"
190+ function onComputingChanged () {
191+ actionHeader .updateProperties (actionHeader .selectedNode )
130192 }
131193 ignoreUnknownSignals: true
132194 }
@@ -135,66 +197,46 @@ Item {
135197 id: actionItemsRow
136198 anchors .centerIn : parent
137199 spacing: 2
138-
200+
139201 // Compute button
140202 MaterialToolButton {
141203 id: computeButton
142204 font .pointSize : 16
143- text: actionHeader .stoppable ? MaterialIcons . cancel_schedule_send : MaterialIcons . send
205+ text: actionHeader .computeButtonIcon
144206 padding: 6
145207 ToolTip .text : " Start/Stop Compute"
146208 ToolTip .visible : hovered
147209 ToolTip .delay : 1000
148- enabled: actionHeader .selectedNode && actionHeader . launchable
210+ enabled: actionHeader .computeButtonState != NodeActions . ButtonState . DISABLED
149211 background: Rectangle {
150212 color: {
151213 if (! computeButton .enabled ) return activePalette .button
152- if (actionHeader .currentStatus === " RUNNING" ) {
153- if (computeButton .hovered ) return Colors .statusColors [" STOPPED" ]
154- return Qt .darker (Colors .statusColors [" STOPPED" ], 1.3 )
155- } else {
156- if (computeButton .hovered ) return activePalette .highlight
157- return activePalette .button
214+ switch (actionHeader .computeButtonState ) {
215+ case NodeActions .ButtonState .STOPPABLE :
216+ if (computeButton .hovered ) return Colors .statusColors [" STOPPED" ]
217+ return Qt .darker (Colors .statusColors [" STOPPED" ], 1.3 )
218+ default : break
158219 }
220+ if (computeButton .hovered ) return activePalette .highlight
221+ return activePalette .button
159222 }
160223 opacity: computeButton .hovered ? 1 : root ._opacity
161224 border .color : computeButton .hovered ? activePalette .highlight : Qt .darker (activePalette .window , 1.3 )
162225 border .width : 1
163226 radius: 3
164227 }
165228 onClicked: {
166- if (actionHeader .selectedNode && ! actionHeader .nodeIsExternal && actionHeader .currentStatus === " RUNNING" ) {
167- root .stopComputeRequest (actionHeader .selectedNode )
168- } else {
169- root .computeRequest (actionHeader .selectedNode )
170- }
171- }
172- }
173-
174- // Re-compute button : stop local process and relaunch locally
175- MaterialToolButton {
176- id: reComputeButton
177- font .pointSize : 16
178- text: MaterialIcons .autorenew
179- padding: 6
180- ToolTip .text : " Re-compute"
181- ToolTip .visible : hovered
182- ToolTip .delay : 1000
183- enabled: actionHeader .selectedNode && ! actionHeader .runningExternally
184- background: Rectangle {
185- color: {
186- if (! reComputeButton .enabled ) return activePalette .button
187- if (reComputeButton .hovered ) return activePalette .highlight
188- return activePalette .button
189- }
190- opacity: reComputeButton .hovered ? 1 : root ._opacity
191- border .color : reComputeButton .hovered ? activePalette .highlight : Qt .darker (activePalette .window , 1.3 )
192- border .width : 1
193- radius: 3
194- }
195- onClicked: {
196- if (actionHeader .selectedNode ) {
197- root .reComputeRequest (actionHeader .selectedNode )
229+ switch (actionHeader .computeButtonState ) {
230+ case NodeActions .ButtonState .STOPPABLE :
231+ root .stopComputeRequest (actionHeader .selectedNode )
232+ break
233+ case NodeActions .ButtonState .LAUNCHABLE :
234+ root .computeRequest (actionHeader .selectedNode )
235+ break
236+ case NodeActions .ButtonState .RELAUNCHABLE :
237+ root .reComputeRequest (actionHeader .selectedNode )
238+ break
239+ default : break
198240 }
199241 }
200242 }
@@ -209,11 +251,13 @@ Item {
209251 ToolTip .visible : hovered
210252 ToolTip .delay : 1000
211253 visible: root .uigraph ? root .uigraph .canSubmit : false
212- enabled: actionHeader .selectedNode ? ! actionHeader .nodeLocked : false
254+ enabled: actionHeader .submitButtonState != NodeActions .ButtonState .DISABLED
255+ // enabled: actionHeader.selectedNode ? !actionHeader.nodeLocked : false
213256 background: Rectangle {
214257 color: {
258+ if (actionHeader .submittedExternally )
259+ return Qt .darker (Colors .statusColors [" SUBMITTED" ], 1.2 )
215260 if (! submitButton .enabled ) return activePalette .button
216- if (actionHeader .runningExternally ) return Colors .statusColors [" SUBMITTED" ]
217261 if (submitButton .hovered ) return activePalette .highlight
218262 return activePalette .button
219263 }
@@ -228,36 +272,6 @@ Item {
228272 }
229273 }
230274 }
231-
232- // Re-submit button : stop everything and relaunch on farm
233- // TODO : disabled for now because we can't stop jobs submitted on farm
234- MaterialToolButton {
235- id: reSubmitButton
236- font .pointSize : 16
237- text: MaterialIcons .double_arrow
238- padding: 6
239- ToolTip .text : " Re-submit on Render Farm"
240- ToolTip .visible : hovered
241- ToolTip .delay : 1000
242- visible: false // root.uigraph ? root.uigraph.canSubmit : false
243- enabled: actionHeader .selectedNode !== null
244- background: Rectangle {
245- color: {
246- if (! actionHeader .selectedNode ) return activePalette .button
247- if (reSubmitButton .hovered ) return activePalette .highlight
248- return activePalette .button
249- }
250- opacity: reSubmitButton .hovered ? 1 : root ._opacity
251- border .color : reSubmitButton .hovered ? activePalette .highlight : Qt .darker (activePalette .window , 1.3 )
252- border .width : 1
253- radius: 3
254- }
255- onClicked: {
256- if (actionHeader .selectedNode ) {
257- root .reSubmitRequest (actionHeader .selectedNode )
258- }
259- }
260- }
261275 }
262276 }
263277}
0 commit comments