nuke.callbacks

Package nuke :: Module callbacks |
[hide private]
[frames] | no frames]

# Source Code for Module nuke.callbacks

      1  # callbacks.py
      2  #
      3  # Callbacks from Nuke to user-defined Python.
      4  # Nuke actually calls "nuke.onCreate()" but users will normally use
      5  # the default versions of these functions and use "nuke.addOnCreate()"
      6  # to add to the list of callbacks that the default calls.
      7
      8  import types
      9  import nuke
     10
     11
     12 -def _addCallback(dict, call, args, kwargs, nodeClass, node=None):
     13    if not callable(call):
     14      raise ValueError("call must be a callable")
     15    if type(args) != types.TupleType:
     16      args = (args,)
     17    if type(kwargs) != types.DictType:
     18      raise ValueError("kwargs must be a dictionary")
     19    if dict.has_key(nodeClass):
     20      list = dict[nodeClass]
     21      # make it appear only once in list
     22      try:
     23        list.remove((call,args,kwargs,node))
     24      except:
     25        pass
     26      list.append((call,args,kwargs,node))
     27    else:
     28      dict[nodeClass] = [(call,args,kwargs,node)]
     29
     30 -def _removeCallback(dict, call, args, kwargs, nodeClass, node=None):
     31    if type(args) != types.TupleType:
     32      args = (args,)
     33    if dict.has_key(nodeClass):
     34      list = dict[nodeClass]
     35      try:
     36        list.remove((call,args,kwargs,node))
     37      except:
     38        pass
     39
     40 -def _doCallbacks(dict, node=None):
     41    list = dict.get(nuke.thisClass())
     42    node = nuke.thisNode()
     43    if list:
     44      for f in list:
     45        if f[3] == None or f[3] is node:
     46          f[0](*f[1],**f[2])
     47    list = dict.get('*')
     48    if list:
     49      for f in list:
     50        if f[3] == None or f[3] is node:
     51          f[0](*f[1],**f[2])
     52
     53  onUserCreates={}
     54 -def addOnUserCreate(call, args=(), kwargs={}, nodeClass='*'):
     55    """Add code to execute when user creates a node"""
     56    _addCallback(onUserCreates, call, args, kwargs, nodeClass)
     57 -def removeOnUserCreate(call, args=(), kwargs={}, nodeClass='*'):
     58    """Remove a previously-added callback with the same arguments."""
     59    _removeCallback(onUserCreates, call, args, kwargs, nodeClass)
     60 -def onUserCreate():
     61    _doCallbacks(onUserCreates)
     62    if not len(onUserCreates): nuke.tcl("OnCreate")
     63
     64  onCreates={}
     65 -def addOnCreate(call, args=(), kwargs={}, nodeClass='*'):
     66    """Add code to execute when a node is created or undeleted"""
     67    _addCallback(onCreates, call, args, kwargs, nodeClass)
     68 -def removeOnCreate(call, args=(), kwargs={}, nodeClass='*'):
     69    """Remove a previously-added callback with the same arguments."""
     70    _removeCallback(onCreates, call, args, kwargs, nodeClass)
     71 -def onCreate():
     72    _doCallbacks(onCreates)
     73
     74  onScriptLoads={}
     75 -def addOnScriptLoad(call, args=(), kwargs={}, nodeClass='Root'):
     76    """Add code to execute when a script is loaded"""
     77    _addCallback(onScriptLoads, call, args, kwargs, nodeClass)
     78 -def removeOnScriptLoad(call, args=(), kwargs={}, nodeClass='Root'):
     79    """Remove a previously-added callback with the same arguments."""
     80    _removeCallback(onScriptLoads, call, args, kwargs, nodeClass)
     81 -def onScriptLoad():
     82    _doCallbacks(onScriptLoads)
     83
     84  onScriptSaves={}
     85 -def addOnScriptSave(call, args=(), kwargs={}, nodeClass='Root'):
     86    """Add code to execute before a script is saved"""
     87    _addCallback(onScriptSaves, call, args, kwargs, nodeClass)
     88 -def removeOnScriptSave(call, args=(), kwargs={}, nodeClass='Root'):
     89    """Remove a previously-added callback with the same arguments."""
     90    _removeCallback(onScriptSaves, call, args, kwargs, nodeClass)
     91 -def onScriptSave():
     92    _doCallbacks(onScriptSaves)
     93
     94  onScriptCloses={}
     95 -def addOnScriptClose(call, args=(), kwargs={}, nodeClass='Root'):
     96    """Add code to execute before a script is closed"""
     97    _addCallback(onScriptCloses, call, args, kwargs, nodeClass)
     98 -def removeOnScriptClose(call, args=(), kwargs={}, nodeClass='Root'):
     99    """Remove a previously-added callback with the same arguments."""
    100    _removeCallback(onScriptCloses, call, args, kwargs, nodeClass)
    101 -def onScriptClose():
    102    _doCallbacks(onScriptCloses)
    103
    104  onDestroys={}
    105 -def addOnDestroy(call, args=(), kwargs={}, nodeClass='*'):
    106    """Add code to execute when a node is destroyed"""
    107    _addCallback(onDestroys, call, args, kwargs, nodeClass)
    108 -def removeOnDestroy(call, args=(), kwargs={}, nodeClass='*'):
    109    """Remove a previously-added callback with the same arguments."""
    110    _removeCallback(onDestroys, call, args, kwargs, nodeClass)
    111 -def onDestroy():
    112    _doCallbacks(onDestroys)
    113
    114  knobChangeds={}
    115 -def addKnobChanged(call, args=(), kwargs={}, nodeClass='*', node=None):
    116    """Add code to execute when the user changes a knob
    117    The knob is availble in nuke.thisKnob() and the node in nuke.thisNode().
    118    This is also called with dummy knobs when the control panel is opened
    119    or when the inputs to the node changes. The purpose is to update other
    120    knobs in the control panel. Use addUpdateUI() for changes that
    121    should happen even when the panel is closed."""
    122    _addCallback(knobChangeds, call, args, kwargs, nodeClass, node)
    123 -def removeKnobChanged(call, args=(), kwargs={}, nodeClass='*', node=None):
    124    """Remove a previously-added callback with the same arguments."""
    125    _removeCallback(knobChangeds, call, args, kwargs, nodeClass, node)
    126 -def knobChanged():
    127    _doCallbacks(knobChangeds)
    128
    129  updateUIs={}
    130 -def addUpdateUI(call, args=(), kwargs={}, nodeClass='*'):
    131    """Add code to execute on every node when things change. This is done
    132    during idle, you cannot rely on it being done before it starts updating
    133    the viewer"""
    134    _addCallback(updateUIs, call, args, kwargs, nodeClass)
    135 -def removeUpdateUI(call, args=(), kwargs={}, nodeClass='*'):
    136    """Remove a previously-added callback with the same arguments."""
    137    _removeCallback(updateUIs, call, args, kwargs, nodeClass)
    138 -def updateUI():
    139    _doCallbacks(updateUIs)
    140
    141  # autolabel is somewhat different due to it returning a string
    142  autolabels={}
    143 -def addAutolabel(call, args=(), kwargs={}, nodeClass='*'):
    144    """Add code to execute on every node to produce the text to draw on it
    145    in the DAG. Any value other than None is converted to a string and used
    146    as the text. None indicates that previously-added functions should
    147    be tried"""
    148    _addCallback(autolabels, call, args, kwargs, nodeClass)
    149 -def removeAutolabel(call, args=(), kwargs={}, nodeClass='*'):
    150    """Remove a previously-added callback with the same arguments."""
    151    _removeCallback(autolabels, call, args, kwargs, nodeClass)
    152 -def autolabel():
    153    list = autolabels.get(nuke.thisClass())
    154    if list:
    155      for f in list[::-1]:
    156        s = f[0](*f[1],**f[2])
    157        if s != None: return s
    158    list = autolabels.get('*')
    159    if list:
    160      for f in list[::-1]:
    161        s = f[0](*f[1],**f[2])
    162        if s != None: return s
    163
    164  # Normal rendering callbacks
    165  beforeRenders={}
    166 -def addBeforeRender(call, args=(), kwargs={}, nodeClass='Write'):
    167    """Add code to execute before starting any renders"""
    168    _addCallback(beforeRenders, call, args, kwargs, nodeClass)
    169 -def removeBeforeRender(call, args=(), kwargs={}, nodeClass='Write'):
    170    """Remove a previously-added callback with the same arguments."""
    171    _removeCallback(beforeRenders, call, args, kwargs, nodeClass)
    172 -def beforeRender():
    173    _doCallbacks(beforeRenders)
    174
    175  beforeFrameRenders={}
    176 -def addBeforeFrameRender(call, args=(), kwargs={}, nodeClass='Write'):
    177    """Add code to execute before each frame of a render"""
    178    _addCallback(beforeFrameRenders, call, args, kwargs, nodeClass)
    179 -def removeBeforeFrameRender(call, args=(), kwargs={}, nodeClass='Write'):
    180    """Remove a previously-added callback with the same arguments."""
    181    _removeCallback(beforeFrameRenders, call, args, kwargs, nodeClass)
    182 -def beforeFrameRender():
    183    _doCallbacks(beforeFrameRenders)
    184
    185  afterFrameRenders={}
    186 -def addAfterFrameRender(call, args=(), kwargs={}, nodeClass='Write'):
    187    """Add code to execute after each frame of a render"""
    188    _addCallback(afterFrameRenders, call, args, kwargs, nodeClass)
    189 -def removeAfterFrameRender(call, args=(), kwargs={}, nodeClass='Write'):
    190    """Remove a previously-added callback with the same arguments."""
    191    _removeCallback(afterFrameRenders, call, args, kwargs, nodeClass)
    192 -def afterFrameRender():
    193    _doCallbacks(afterFrameRenders)
    194
    195  afterRenders={}
    196 -def addAfterRender(call, args=(), kwargs={}, nodeClass='Write'):
    197    """Add code to execute after any renders"""
    198    _addCallback(afterRenders, call, args, kwargs, nodeClass)
    199 -def removeAfterRender(call, args=(), kwargs={}, nodeClass='Write'):
    200    """Remove a previously-added callback with the same arguments."""
    201    _removeCallback(afterRenders, call, args, kwargs, nodeClass)
    202 -def afterRender():
    203    _doCallbacks(afterRenders)
    204
    205  # Special functions to perform background callbacks as these have no node as
    206  # context.
    207 -def _addBackgroundCallback(list, call, args, kwargs):
    208    if not callable(call):
    209      raise ValueError("call must be a callable")
    210    if type(args) != types.TupleType:
    211      args = (args,)
    212    if type(kwargs) != types.DictType:
    213      raise ValueError("kwargs must be a dictionary")
    214    # make it appear only once in list
    215    try:
    216      list.remove((call,args,kwargs))
    217    except:
    218      pass
    219    list.append((call,args,kwargs))
    220
    221 -def _removeBackgroundCallback(list, call, args, kwargs):
    222    if type(args) != types.TupleType:
    223      args = (args,)
    224    try:
    225      list.remove((call,args,kwargs))
    226    except:
    227      pass
    228
    229 -def _doBackgroundCallbacks(list, context):
    230    for f in list:
    231      f[0](context, *f[1],**f[2])
    232
    233  # Background rendering callbacks
    234  beforeBackgroundRenders=[]
    235 -def addBeforeBackgroundRender(call, args=(), kwargs={}):
    236    """Add code to execute before starting any background renders.
    237    The call must be in the form of:
    238    def foo(context):
    239      pass
    240
    241    The context object that will be passed in is a dictionary containing the following elements:
    242    id => The identifier for the task that's about to begin
    243
    244    Please be aware that the current Nuke context will not make sense in the callback (e.g. nuke.thisNode will return a random node).
    245    """
    246    _addBackgroundCallback(beforeBackgroundRenders, call, args, kwargs)
    247 -def removeBeforeBackgroundRender(call, args=(), kwargs={}):
    248    """Remove a previously-added callback with the same arguments."""
    249    _removeBackgroundCallback(beforeBackgroundRenders, call, args, kwargs)
    250 -def beforeBackgroundRender(context):
    251    _doBackgroundCallbacks(beforeBackgroundRenders, context)
    252
    253  # There is no logical place for this to be called at the moment, so don't expose it.
    254  #def addBeforeBackgroundFrameRender(call, args=(), kwargs={}):
    255  #  """Add code to execute before each frame of a background render"""
    256  #  _addBackgroundCallback(beforeBackgroundFrameRenders, call, args, kwargs)
    257  #def removeBeforeBackgroundFrameRender(call, args=(), kwargs={}):
    258  #  """Remove a previously-added callback with the same arguments."""
    259  #  _removeBackgroundCallback(beforeBackgroundFrameRenders, call, args, kwargs)
    260  #def beforeBackgroundFrameRender():
    261  #  _doBackgroundCallbacks(beforeBackgroundFrameRenders)
    262
    263  afterBackgroundFrameRenders=[]
    264 -def addAfterBackgroundFrameRender(call, args=(), kwargs={}):
    265    """Add code to execute after each frame of a background render.
    266    The call must be in the form of:
    267    def foo(context):
    268      pass
    269
    270    The context object that will be passed in is a dictionary containing the following elements:
    271    id => The identifier for the task that's making progress
    272    frame => the current frame number being rendered
    273    numFrames => the total number of frames that is being rendered
    274    frameProgress => the number of frames rendered so far.
    275
    276    Please be aware that the current Nuke context will not make sense in the callback (e.g. nuke.thisNode will return a random node).
    277    """
    278    _addBackgroundCallback(afterBackgroundFrameRenders, call, args, kwargs)
    279 -def removeAfterBackgroundFrameRender(call, args=(), kwargs={}):
    280    """Remove a previously-added callback with the same arguments."""
    281    _removeBackgroundCallback(afterBackgroundFrameRenders, call, args, kwargs)
    282 -def afterBackgroundFrameRender(context):
    283    _doBackgroundCallbacks(afterBackgroundFrameRenders, context)
    284
    285  afterBackgroundRenders=[]
    286 -def addAfterBackgroundRender(call, args=(), kwargs={}):
    287    """Add code to execute after any background renders.
    288    The call must be in the form of:
    289    def foo(context):
    290      pass
    291
    292    The context object that will be passed in is a dictionary containing the following elements:
    293    id => The identifier for the task that's ended
    294
    295    Please be aware that the current Nuke context will not make sense in the callback (e.g. nuke.thisNode will return a random node).
    296    """
    297    _addBackgroundCallback(afterBackgroundRenders, call, args, kwargs)
    298 -def removeAfterBackgroundRender(call, args=(), kwargs={}):
    299    """Remove a previously-added callback with the same arguments."""
    300    _removeBackgroundCallback(afterBackgroundRenders, call, args, kwargs)
    301 -def afterBackgroundRender(context):
    302    _doBackgroundCallbacks(afterBackgroundRenders, context)
    303
    304  # filenameFilter is somewhat different due to it returning a string
    305  filenameFilters={}
    306 -def addFilenameFilter(call, args=(), kwargs={}, nodeClass='*'):
    307    """Add a function to modify filenames before Nuke passes them to
    308    the operating system. The first argument to the function is the
    309    filename, and it should return the new filename. None is the same as
    310    returning the string unchanged. All added functions are called
    311    in backwards order."""
    312    _addCallback(filenameFilters, call, args, kwargs, nodeClass)
    313 -def removeFilenameFilter(call, args=(), kwargs={}, nodeClass='*'):
    314    """Remove a previously-added callback with the same arguments."""
    315    _removeCallback(filenameFilters, call, args, kwargs, nodeClass)
    316
    317 -def filenameFilter(filename):
    318    import __main__
    319    list = filenameFilters.get(nuke.thisClass())
    320    if list:
    321      for f in list[::-1]:
    322        s = f[0](filename,*f[1],**f[2])
    323        if s != None: filename = s
    324    list = filenameFilters.get('*')
    325    if list:
    326      for f in list[::-1]:
    327        s = f[0](filename,*f[1],**f[2])
    328        if s != None: filename = s
    329    if not len(filenameFilters):
    330      # For back-compatibility allow user to define a filenameFix() function:
    331      if __main__.__dict__.has_key('filenameFix'):
    332        return __main__.__dict__['filenameFix'](filename)
    333      # For even further back-compatibility let them define a tcl filename_fix function:
    334      return nuke.tcl("filename_fix",filename)
    335    return filename
    336
    337  validateFilenames={}
    338 -def addValidateFilename(call, args=(), kwargs={}, nodeClass='Write'):
    339    """Add a function to validate a filename in Write nodes. The first argument
    340    is the filename and it should return a Boolean as to whether the filename is valid
    341    or not. If a callback is provided, it will control whether the Render button of Write nodes
    342    and the Execute button of WriteGeo nodes is enabled or not."""
    343    _addCallback(validateFilenames, call, args, kwargs, nodeClass)
    344 -def removeFilenameValidate(call, args=(), kwargs={}, nodeClass='Write'):
    345    """Remove a previously-added callback."""
    346    _removeCallback(validateFilenames, call, args, kwargs, nodeClass)
    347 -def validateFilename(filename):
    348    import __main__
    349    list = validateFilenames.get(nuke.thisClass())
    350    valid = True
    351
    352    if list:
    353      for f in list:
    354        b = f[0](filename)
    355        if b == False: valid = False
    356    list = validateFilenames.get('*')
    357    if list:
    358      for f in list:
    359        b = f[0](filename)
    360        if b == False: valid = False
    361    return valid
    362
    363
    364 -def _doAutoSaveCallbacks( filters, filename ):
    365    import __main__
    366    list = filters.get( 'Root' )
    367    if list:
    368      for f in list:
    369        s = f[0](filename)
    370        filename = s
    371
    372    return filename
    373
    374  autoSaveFilters={}
    375 -def addAutoSaveFilter(filter):
    376    """addAutoSaveFilter(filter) -> None
    377
    378    Add a function to modify the autosave filename before Nuke saves the current script on an autosave timeout.
    379
    380    Look at rollingAutoSave.py in the nukescripts directory for an example of using the auto save filters.
    381
    382    @param filter: A filter function.  The first argument to the filter is the current autosave filename.
    383    The filter should return the filename to save the autosave to."""
    384    _addCallback(autoSaveFilters, filter, (), {}, 'Root')
    385
    386 -def removeAutoSaveFilter(filter):
    387    """Remove a previously-added callback with the same arguments."""
    388    _removeCallback(autoSaveFilters, call, (), {}, 'Root')
    389
    390 -def autoSaveFilter(filename):
    391    """Internal function.  Use addAutoSaveFilter to add a callback"""
    392    return _doAutoSaveCallbacks( autoSaveFilters, filename )
    393
    394
    395  autoSaveRestoreFilters={}
    396 -def addAutoSaveRestoreFilter(filter):
    397    """addAutoSaveRestoreFilter(filter) -> None
    398
    399    Add a function to modify the autosave restore file before Nuke attempts to restores the autosave file.
    400
    401    Look at rollingAutoSave.py in the nukescripts directory for an example of using the auto save filters.
    402
    403    @param filter: A filter function.  The first argument to the filter is the current autosave filename.
    404    This function should return the filename to load autosave from or it should return None if the autosave file should be ignored."""
    405    _addCallback(autoSaveRestoreFilters, filter, (), {}, 'Root')
    406
    407 -def removeAutoSaveRestoreFilter(filter):
    408    """Remove a previously-added callback with the same arguments."""
    409    _removeCallback(autoSaveRestoreFilters, filter, (), {}, 'Root')
    410
    411 -def autoSaveRestoreFilter(filename):
    412    """Internal function.  Use addAutoSaveRestoreFilter to add a callback"""
    413    return _doAutoSaveCallbacks( autoSaveRestoreFilters, filename )
    414
    415  autoSaveDeleteFilters={}
    416 -def addAutoSaveDeleteFilter(filter):
    417    """addAutoSaveDeleteFilter(filter) -> None
    418
    419    Add a function to modify the autosave filename before Nuke attempts delete the autosave file.
    420
    421    Look at rollingAutoSave.py in the nukescripts directory for an example of using the auto save filters.
    422
    423    @param filter: A filter function.  The first argument to the filter is the current autosave filename.
    424    This function should return the filename to delete or return None if no file should be deleted."""
    425    _addCallback(autoSaveDeleteFilters, filter, (), {}, 'Root')
    426
    427 -def removeAutoSaveDeleteFilter(filter):
    428    """Remove a previously-added callback with the same arguments."""
    429    _removeCallback(autoSaveDeleteFilters, filter, (), {}, 'Root')
    430
    431 -def autoSaveDeleteFilter(filename):
    432    """Internal function.  Use addAutoSaveDeleteFilter to add a callback"""
    433    return _doAutoSaveCallbacks( autoSaveDeleteFilters, filename )
    434