1
2 from __future__ import with_statement
3 import nuke
4 import nukescripts
5 import flipbooking
6 from nukescripts import pyAppUtils
7 import os
8 import string
9 import subprocess
10 import uuid
11 import re
12
13 from threading import Thread
14 from nukescripts import utils, sys, os, captureViewer
15 from fnFlipbookRenderer import getFlipbookRenderer
16
17
18
19
20
21
22
26
27 - def get(self, knob, defaultValue = None):
28 """Return the given knob's stored last state value.
29 If none exists, defaultValue is returned.
30 Values are stored in a dict referenced by knob name, so names must be unique!"""
31 return self.getValue(knob.name(), defaultValue)
32
33 - def save(self, knob):
34 """Store the knob's current value as the 'last state' for the next time the dialog is opened.
35 Values are stored in a dict referenced by knob name, so names must be unique!"""
36 self.saveValue(knob.name(), knob.value())
37
38 - def setKnob(self, knob, defaultValue = None):
42 """Stores the value with the given id."""
43 self._state[id] = value
44 - def getValue(self, id, defaultValue = None):
45 """Recalls the value. If it was not set before, it will return the defaultValue."""
46 return self._state.get(id, defaultValue)
47
48 _gRenderDialogState = DialogState()
49 _gFlipbookDialogState = DialogState()
50 _gViewerCaptureDialogState = DialogState()
51
55
57 return "uk.co.thefoundry.ExecuteDialog"
58
60 """Add knobs that must appear before the render knobs."""
61 return
62
63 - def _addPostKnobs(self):
64 """Add knobs that must appear after the render knobs."""
65 return
66
68 """Add knobs that must appear at the very end."""
69 return
70
75
84
89
90 - def __init__(self, dialogState, groupContext, nodeSelection = [], exceptOnError = True):
91 self._state = dialogState
92 self._nodeSelection = nodeSelection
93 self._exceptOnError = exceptOnError
94
95 nukescripts.PythonPanel.__init__(self, self._titleString(), self._idString(), False)
96
97 self._viewers = {}
98 for n in nuke.allNodes("Viewer", groupContext):
99 self._viewers[n.name()] = n
100 self._specialRanges = ["input", "global", "custom"]
101
102 self._addPreKnobs()
103
104
105 self._rangeEnum = nuke.Enumeration_Knob( "frame_range", "Frame range", self._specialRanges + self._viewers.keys() )
106 self._state.setKnob(self._rangeEnum, "input")
107 self.addKnob( self._rangeEnum )
108
109 self._frameRange = nuke.String_Knob( "frame_range_string", "")
110 self._frameRange.clearFlag(nuke.STARTLINE)
111 if self._rangeEnum.value() == "custom":
112 self._state.setKnob(self._frameRange, str(nuke.root().frameRange()))
113 else:
114 self._setFrameRangeFromSource(self._rangeEnum.value())
115
116 self.addKnob(self._frameRange)
117
118
119 self._useProxy = nuke.Boolean_Knob("use_proxy", "Use proxy")
120 self._useProxy.setFlag(nuke.STARTLINE)
121 self._state.setKnob(self._useProxy, nuke.root().proxy())
122 self.addKnob(self._useProxy)
123
124 self._addPostKnobs()
125
126 self._continueOnError = nuke.Boolean_Knob("continue", "Continue on error")
127 self._state.setKnob(self._continueOnError, True)
128 self._continueOnError.setFlag(nuke.STARTLINE)
129 self.addKnob(self._continueOnError)
130
131 self._addViewKnob()
132
133 self._addTrailingKnobs()
134
144
160
162 """Set the framerange knob to have the framerange from the given viewer."""
163 viewerRange = str(self._viewers[viewer].playbackRange())
164 self._frameRange.setValue(viewerRange)
165
172
175
190
192 deprecatedWarningShown = False
193 shouldShowBGRender = False
194 ShowWarning = True
197
198
200 return "uk.co.thefoundry.RenderDialog"
201
202 - def __init__(self,
203 dialogState,
204 groupContext,
205 nodeSelection = [],
206 exceptOnError = True,
207 allowFrameServer = True):
208 self._allowFrameServer = allowFrameServer
209 ExecuteDialog.__init__(self, dialogState, groupContext, nodeSelection, exceptOnError)
210
217
218
223
224
225 - def _addPostKnobs(self):
226
227 bgRenderValue = self._state.getValue("bg_render",False)
228 RenderDialog.shouldShowBGRender = RenderDialog.shouldShowBGRender or bgRenderValue
229
230
231 self._frameserverRender = nuke.Boolean_Knob("frameserver_render", "Render using frame server")
232 if self._allowFrameServer:
233
234
235
236 if bgRenderValue:
237 self._frameserverRender.setValue(False)
238 self._state.save(self._frameserverRender)
239 else:
240 self._state.setKnob(self._frameserverRender,True)
241 self._frameserverRender.setVisible(True)
242 else:
243 self._frameserverRender.setValue(False)
244 self._frameserverRender.setVisible(False)
245 self._frameserverRender.setFlag(nuke.STARTLINE)
246 self.addKnob(self._frameserverRender)
247
248
249 self._bgRender = nuke.Boolean_Knob("bg_render", "Render in background")
250 self._state.setKnob(self._bgRender, bgRenderValue)
251 self._bgRender.setVisible(RenderDialog.shouldShowBGRender)
252 self._bgRender.setFlag(nuke.STARTLINE)
253 self.addKnob(self._bgRender)
254
255 self._numThreads = nuke.Int_Knob("num_threads", "Thread limit")
256 self._numThreads.setVisible(self.isBackgrounded())
257 self._state.setKnob(self._numThreads, max(nuke.NUM_CPUS / 2, 1))
258 self.addKnob(self._numThreads)
259 self._maxMem = nuke.String_Knob("max_memory", "Memory limit")
260 self._state.setKnob(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M")
261 self._maxMem.setVisible(self.isBackgrounded())
262 self.addKnob(self._maxMem)
263 if self.isBackgrounded():
264 self._showDeprecatedWarningMessage()
265
267
268 return {
269 "maxThreads": self._numThreads.value(),
270 "maxCache": self._maxMem.value() }
271
312
313
315 """Return whether the background rendering option is enabled."""
316
317 return self._bgRender.value()
318
319
321 movWriteNodes = []
322 nonMovWriteNodes = []
323
324 for node in nodeSelection:
325 knob = node.knobs().get("file_type",None)
326 if knob:
327 fileType = knob.value()
328 if fileType in ("mov", "mov32", "mov64", "ffmpeg"):
329 movWriteNodes.append(node)
330 else:
331 nonMovWriteNodes.append(node)
332 return (nonMovWriteNodes, movWriteNodes)
333
334
336
337 if not nuke.env['studio']:
338 return False
339
340 if len(self._nodeSelection) > 1 or len(self._nodeSelection) < 1:
341 return False
342
343 write = self._nodeSelection[0]
344
345 if write == nuke.root():
346
347
348
349
350
351 writeNodes = nuke.allNodes( 'Write' )
352 writeNodes.extend( nuke.allNodes( 'WriteGeo') )
353 writeNodes.extend( nuke.allNodes( 'ParticleCache') )
354 writeNodes.extend( nuke.allNodes( 'DiskCache') )
355
356 if len(writeNodes) > 1:
357 return False
358
359 if len(writeNodes) > 0:
360 write = writeNodes[0]
361
362 timelineWriteNode = None
363
364 try:
365 from foundry.frameserver.nuke.workerapplication import GetWriteNode
366 timelineWriteNode = GetWriteNode()
367 except:
368 pass
369
370 if not timelineWriteNode:
371 return False
372
373 if timelineWriteNode.name() != write.name():
374 return False
375
376
377 try:
378 from hiero.ui import isInAnyProject
379 return isInAnyProject( nuke.scriptName() )
380 except:
381 pass
382
383 return False
384
386 import datetime
387 now = datetime.datetime.now()
388 timestamp = now.strftime('%H%M_%S.%f_%d-%m-%Y')
389
390 if nuke.env['nc']:
391 nukeExt = ".nknc"
392 else:
393 nukeExt = ".nk"
394
395 wasSaved = False
396
397 if nuke.Root().name() == 'Root':
398 fileName = "%s.%s%s"%(prefix,timestamp, nukeExt)
399 filePath = "/".join([os.environ["NUKE_TEMP_DIR"], fileName])
400 nuke.scriptSaveToTemp(filePath)
401 wasSaved = True
402 else:
403 originalPath = nuke.scriptName()
404
405 if nuke.Root().modified() == True or forceSaveNew:
406 extensionIndex = originalPath.rfind(nukeExt)
407 noExt = originalPath[:extensionIndex] if extensionIndex>=0 else originalPath
408 head, tail = os.path.split(noExt)
409 fileName = "%s.%s.%s%s"%(prefix,tail,timestamp,nukeExt)
410 filePath = "/".join([head,fileName])
411 try:
412 nuke.scriptSaveToTemp(filePath)
413 wasSaved = True
414 except RuntimeError:
415 nuke.tprint("Exception when saving script to: %s. Saving to NUKE_TEMP_DIR"%filePath)
416 fileName = originalPath.split()[-1]
417 filePath = "/".join([os.environ["NUKE_TEMP_DIR"], fileName])
418 nuke.scriptSaveToTemp(filePath)
419 wasSaved = True
420
421 else:
422 filePath = originalPath
423 return (filePath, wasSaved)
424
425
427
428 nodeSelection = self._nodeSelection
429 nodesToRenderCount= len(nodeSelection)
430 if nodesToRenderCount==1:
431 if nodeSelection[0] == nuke.root():
432 nodeSelection = nuke.allNodes("Write")
433 nodeSelection.extend(nuke.allNodes("DeepWrite"))
434 (nodesToRender, movNodesToRender) = self.extractMovNodes(nodeSelection)
435
436
437 for node in nodeSelection:
438 path = node["file"].getText()
439 needsPadding = frame_ranges.getRange(0).frames()>1
440 hasPadding = nuke.filename( node, nuke.REPLACE ) != path or node["file_type"].value()=="mov"
441 if needsPadding and not hasPadding:
442 nuke.message("%s cannot be executed for multiple frames."%node.name())
443 return
444
445 needsViews = (len(views)!=1 or views[0] != "main" )
446 hasViews = path.find("%v")!=-1 or path.find("%V")!=-1 or node["file_type"].value()=="exr"
447 if needsViews and not hasViews:
448 nuke.message("%s cannot be executed for multiple views."%node.name())
449 return
450
451
452 if movNodesToRender:
453 if RenderDialog.ShowWarning:
454 from PySide2.QtWidgets import (QMessageBox, QCheckBox)
455 message = "It is currently not possible to render container formats using the frame server. Select Continue to render in the current Nuke session.\n\nPlease see the user guide for more information."
456 messageBox = QMessageBox(QMessageBox.Warning, "Warning", message, QMessageBox.Cancel)
457 messageBox.addButton("Continue",QMessageBox.AcceptRole)
458 dontShowCheckBox = QCheckBox("Don't show this message again")
459 dontShowCheckBox.blockSignals(True)
460 messageBox.addButton(dontShowCheckBox, QMessageBox.ResetRole)
461 result = messageBox.exec_()
462 if result != QMessageBox.AcceptRole:
463 return
464 if dontShowCheckBox.isChecked():
465 RenderDialog.ShowWarning = False
466
467 import hiero.ui.nuke_bridge.FnNsFrameServer as FrameServer
468 sortRenderOrder = lambda w : w.knobs()["render_order"].getValue()
469 if nodesToRender:
470 nodesToRender.sort(key = sortRenderOrder)
471 name, wasSaved = self.saveFileToRender("tmp_unsaved",False)
472 try:
473 for node in nodesToRender:
474 FrameServer.renderFrames(
475 name,
476 frame_ranges,
477 node.name(),
478 self._selectedViews())
479 finally:
480 if wasSaved:
481 os.unlink(name)
482
483 if movNodesToRender:
484 movNodesToRender.sort(key = sortRenderOrder)
485 nuke.executeMultiple(movNodesToRender, frame_ranges, views, continueOnError = self._continueOnError.value())
486
487
489
490
491 if self.isTimelineWrite() and self._timelineRender.value():
492 from hiero.ui.nuke_bridge.nukestudio import scriptSaveAndReRender
493 scriptSaveAndReRender()
494 return
495
496 frame_ranges = nuke.FrameRanges(self._frameRange.value().split(','))
497 views = self._selectedViews()
498 rootProxyMode = nuke.root().proxy()
499 try:
500 nuke.Undo().disable()
501 nuke.root().setProxy(self._useProxy.value())
502 if self._frameserverRender.value():
503 self.renderToFrameServer(frame_ranges,views)
504
505 elif (self.isBackgrounded()):
506 nuke.executeBackgroundNuke(nuke.EXE_PATH, self._nodeSelection,
507 frame_ranges, views, self._getBackgroundLimits(), continueOnError = self._continueOnError.value())
508
509 else:
510
511 nuke.executeMultiple(self._nodeSelection, frame_ranges, views, continueOnError = self._continueOnError.value())
512 except RuntimeError, e:
513 if self._exceptOnError or e.args[0][0:9] != "Cancelled":
514 raise
515 finally:
516 nuke.root().setProxy(rootProxyMode)
517 nuke.Undo().enable()
518
522
524 return "uk.co.thefoundry.FlipbookDialog"
525
526 - def __init__(self, dialogState, groupContext, node, takeNodeSettings):
542
544 self._flipbookEnum = nuke.Enumeration_Knob( "flipbook", "Flipbook", flipbooking.gFlipbookFactory.getNames() )
545 self._state.setKnob(self._flipbookEnum, "Default")
546 self.addKnob( self._flipbookEnum )
547 self._viewerForSettings = nuke.Enumeration_Knob("viewer_settings", "Take settings from", ["-"] + self._viewers.keys())
548 if not self._takeNodeSettings:
549 self._viewerForSettings.setValue("-")
550 self.addKnob(self._viewerForSettings)
551
552 self._defaultValues = nuke.PyScript_Knob("default", "Defaults")
553 self.addKnob(self._defaultValues)
554
555
556 self._useRoi = nuke.Boolean_Knob("use_roi", "Enable ROI")
557 self._useRoi.setFlag(nuke.STARTLINE)
558 self._state.setKnob(self._useRoi, False)
559 self.addKnob(self._useRoi)
560 self._roi = nuke.BBox_Knob("roi", "Region of Interest")
561 self._state.setKnob(self._roi, (0, 0, 0, 0))
562 self.addKnob(self._roi)
563 self._roi.setVisible(self._useRoi.value())
564
565
566 self._channels = nuke.Channel_Knob( "channels_knob", "Channels")
567 if self._node.Class() == "Write":
568 self._channels.setValue(self._node.knob("channels").value())
569 else:
570 self._state.setKnob(self._channels, "rgba")
571 self._channels.setFlag(nuke.STARTLINE | nuke.NO_CHECKMARKS)
572 self.addKnob( self._channels )
573
574 - def _addPostKnobs( self ):
575 super(FlipbookDialog, self)._addPostKnobs()
576
577 self._cleanup = nuke.Boolean_Knob("cleanup", "Delete existing temporary files")
578 self._cleanup.setFlag(nuke.STARTLINE)
579 self._state.setKnob(self._cleanup, True)
580 self.addKnob(self._cleanup)
581
582
583 self._luts = nuke.Enumeration_Knob("lut", "LUT", nuke.ViewerProcess.registeredNames())
584 if self._takeNodeSettings:
585 self._state.setKnob(self._luts, self._lutFromViewer(self._viewerForSettings.value()))
586 else:
587 self._state.setKnob(self._luts, self._lutFromViewer())
588 self.addKnob(self._luts)
589
590 self._burnInLUT = nuke.Boolean_Knob("burnin", "Burn in the LUT")
591 self._state.setKnob(self._burnInLUT, False)
592 self.addKnob(self._burnInLUT)
593
594
595 audioList = []
596 audioList.append( "None" )
597 for node in nuke.allNodes("AudioRead"):
598 audioList.append( node.name() )
599 self._audioSource = nuke.Enumeration_Knob( "audio", "Audio", audioList )
600 self._state.setKnob(self._audioSource, audioList[0] )
601 self.addKnob( self._audioSource )
602
605
615
618
642
645
654
656 return knob == self._useRoi or knob == self._roi or knob == self._channels or knob == self._useProxy or knob == self._frameRange or knob == self._rangeEnum or knob == self._luts
657
661
663 RenderDialog.knobChanged(self, knob)
664 if knob == self._defaultValues:
665 self._setKnobAndStore(self._useRoi, False)
666 self._setKnobAndStore(self._roi, (0, 0, 0, 0))
667 self._roi.setVisible(False)
668 self._maxMem.setVisible(False)
669 self._numThreads.setVisible(False)
670 self._setKnobAndStore(self._viewerForSettings, "-")
671 self._setKnobAndStore(self._channels, "rgba")
672 self._setKnobAndStore(self._useProxy, False)
673 self._setKnobAndStore(self._frameRange, str(nuke.root().frameRange()))
674 self._setKnobAndStore(self._rangeEnum, "input")
675 self._setKnobAndStore(self._continueOnError, True)
676 self._setKnobAndStore(self._bgRender, False)
677 self._setKnobAndStore(self._luts, "sRGB")
678 self._setKnobAndStore(self._burnInLUT, False)
679 self._setKnobAndStore(self._cleanup, True)
680 self._setKnobAndStore(self._maxMem, str(max(nuke.memory("max_usage") / 2097152, 16)) + "M")
681 self._setKnobAndStore(self._numThreads, max(nuke.NUM_CPUS / 2, 1))
682 elif (knob == self._viewerForSettings):
683 if self._viewerForSettings.value() != "-":
684 viewer = self._viewers[self._viewerForSettings.value()]
685 self._setKnobAndStore(self._useRoi, viewer.roiEnabled())
686 roi = viewer.roi()
687 if roi != None:
688 self._roi.fromDict(roi)
689 self._state.save(self._roi)
690 self._channels.fromScript(viewer.knob("channels").toScript())
691 self._state.save(self._channels)
692 self._setKnobAndStore(self._useProxy, nuke.root().proxy())
693 self._frameRangeFromViewer(viewer.name())
694 self._state.save(self._frameRange)
695 self._setKnobAndStore(self._rangeEnum, viewer.name())
696 self._roi.setVisible(self._useRoi.value())
697 self._setKnobAndStore(self._luts, self._lutFromViewer(viewer.name()))
698 elif (knob == self._useRoi):
699 self._roi.setVisible(self._useRoi.value())
700 elif self._isViewerSettingKnob(knob):
701 self._viewerForSettings.setValue("-")
702 self._state.save(self._viewerForSettings)
703 elif knob == self._luts:
704 self._burnInLUT.setEnabled(self._luts.value() != "None")
705
706 if knob == self._flipbookEnum:
707 for k in self._customKnobs:
708 self.removeKnob(k)
709 self.removeKnob(self.okButton)
710 self.removeKnob(self.cancelButton)
711 self._customKnobs = []
712 self.flipbookKnobs()
713 self._makeOkCancelButton()
714 elif knob in self._customKnobs:
715 try:
716 flipbookToRun = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value())
717 flipbookToRun.dialogKnobChanged(self, knob)
718 except NotImplementedError:
719 pass
720
722 """Delete all the files in the range to be rendered."""
723 temporariesPath = self._getIntermediatePath()
724 isFilePerView = temporariesPath.find("%V") != -1
725 selectedViews = self._selectedViews()
726 temporariesPath = temporariesPath .replace("%V", "%s")
727 for r in nuke.FrameRanges(self._frameRange.value().split(',')):
728 deleteRange = xrange(r.minFrame(), r.maxFrame() + 1)
729
730 for v in selectedViews:
731 for i in deleteRange:
732 if isFilePerView and (len(selectedViews) > 1):
733 f = temporariesPath % (i, v,)
734 else:
735 f = temporariesPath % i
736
737 if os.access(f, os.F_OK):
738 os.remove(f)
739
742
770
814
816 """Helper function to get the appropriate colorspace to set on the Write node when burning the
817 viewer color transform into the render."""
818
819 writeColorspace = None
820
821 lut = self._getLUT()
822
823
824 usingNukeColorspaces = False
825 rootNode = nuke.root()
826 if rootNode:
827 colorManagementKnob = rootNode.knob("colorManagement")
828 if colorManagementKnob:
829 usingNukeColorspaces = (colorManagementKnob.value() == "Nuke")
830
831 if usingNukeColorspaces:
832
833
834
835
836
837
838
839
840
841 if lut == "rec1886":
842 writeColorspace = "Gamma2.4"
843 elif lut != "None":
844 writeColorspace = lut
845
846 else:
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868 displayName = ""
869 viewName = ""
870
871 NUKE_LUT_FORMAT = '(.*) \((.*)\)$'
872 matchResult = re.match( NUKE_LUT_FORMAT , lut)
873 if matchResult is not None:
874
875 viewName = matchResult.group(1)
876 displayName = matchResult.group(2)
877
878 if rootNode:
879 writeColorspace = rootNode.getOCIOColorspaceFromViewTransform(displayName, viewName)
880
881 return writeColorspace
882
883
944
946 return self._luts.value()
947
955
957 options = {
958 }
959
960 try:
961 options['pixelAspect'] = float(nuke.value(nodeToFlipbook.name()+".pixel_aspect"))
962 except:
963 pass
964
965 try:
966 f = nodeToFlipbook.format()
967 options['dimensions'] = { 'width' : f.width(), 'height' : f.height() }
968 except:
969 pass
970
971
972 if not self._burnInLUT.value():
973 inputColourspace = "linear"
974 outputColourspace = "linear"
975
976 if self._node.Class() == "Read" or self._node.Class() == "Write":
977 lut = self._node.knob("colorspace").value()
978
979 if lut[:7] == "default":
980 lut = lut[9:-1]
981 inputColourspace = lut
982
983
984 lut = self._getLUT()
985 if lut != "None":
986 outputColourspace = lut
987
988 if inputColourspace == outputColourspace:
989 options["lut"] = inputColourspace
990 else:
991 options["lut"] = inputColourspace + "-" + outputColourspace
992
993 audioTrack = self._getAudio()
994 if audioTrack != "":
995 options["audio"] = audioTrack
996
997
998 if self._useRoi.value():
999 roi = self._roi.toDict()
1000 if (roi["r"] - roi["x"] > 0) and (roi["t"] - roi["y"] > 0):
1001 options["roi"] = bboxToTopLeft(int(nuke.value(nodeToFlipbook.name()+".actual_format.height")), roi)
1002
1003
1004 return options
1005
1041
1045
1047 return "uk.co.thefoundry.ViewerCaptureDialog"
1048
1049 - def __init__(self, dialogState, groupContext, node):
1095
1109
1112
1114 """ Return an instance of a CaptureViewer class, which when executed captures the viewer.
1115 """
1116 flipbook = flipbooking.gFlipbookFactory.getApplication(self._flipbookEnum.value())
1117 if flipbook and not os.access(flipbook.path(), os.X_OK):
1118 raise RuntimeError("%s cannot be executed (%s)." % (flipbook.name(), flipbook.path(),) )
1119
1120
1121 frameRange = self._frameRange.value()
1122 viewer = self._node
1123 selectedViews = self._selectedViews()
1124 defaultWritePath = self._getIntermediatePath()
1125 customWritePath = self._file.value() if self._customWrite.value() else ""
1126 doFlipbook = not self._noFlipbook.value()
1127 doCleanup = self._cleanup.value()
1128
1129 return captureViewer.CaptureViewer(flipbook, frameRange, viewer, selectedViews, defaultWritePath, customWritePath, doFlipbook, doCleanup)
1130
1132 """Shows the dialog if dialog.showModalDialog() == True"""
1133 if (dialog.showModalDialog() == True):
1134 dialog.run()
1135
1137 """Present a dialog that executes the given list of nodes."""
1138 groupContext = nuke.root()
1139 d = ExecuteDialog(_gRenderDialogState, groupContext, nodesToExecute, exceptOnError)
1140 _showDialog(d)
1141
1142 -def showRenderDialog(nodesToRender, exceptOnError = True, allowFrameServer = True):
1147
1149 """Returns the flipbook dialog object created when flipbooking node"""
1150 if node is None:
1151 raise RuntimeError("Can't launch flipbook, require a node.");
1152 if node.Class() == "Viewer" and node.inputs() == 0:
1153 raise RuntimeError("Can't launch flipbook, there is nothing connected to the viewed input.");
1154
1155 if not (nuke.canCreateNode("Write")):
1156 nuke.message("Flipbooking is not permitted in Nuke Assist")
1157 return
1158
1159 groupContext = nuke.root()
1160
1161 e = FlipbookDialog(_gFlipbookDialogState, groupContext, node, takeNodeSettings)
1162 return e
1163
1168
1169
1170
1179
1199
1201 """Present a dialog that flipbooks the currently selected node."""
1202 try:
1203 showFlipbookDialog(nuke.selectedNode())
1204 except ValueError, ve:
1205 raise RuntimeError("Can't launch flipbook, %s." % (ve.args[0]))
1206
1208 """Convert the roi passed from a origin at the bottom left to the top left.
1209 Also replaces the r and t keys with w and h keys.
1210 @param height: the height used to determine the top.
1211 @param roi: the roi with a bottom left origin, must have x, y, r & t keys.
1212 @result dict with x, y, w & h keys"""
1213 topLeftRoi = {
1214 "x": roi["x"],
1215 "y": height - roi["y"] - (roi["t"] - roi["y"]),
1216 "w": roi["r"] - roi["x"],
1217 "h": roi["t"] - roi["y"] }
1218 return topLeftRoi
1219
1221 """ Set a particular option to the given value. The type of the value differs per option, giving the wrong value may result in exceptions. The options are read every time the dialog is opened, though not every knob in the dialog has it's value stored."""
1222 _gRenderDialogState.saveValue(name, value)
1223
1225 """ Set a particular option to the given value. The type of the value differs per option, giving the wrong value may result in exceptions. The options are read every time the dialog is opened, though not every knob in the dialog has it's value stored."""
1226 _gFlipbookDialogState.saveValue(name, value)
1227