def setKey(insert=True, useSelectedCurves=True):
    """Sets clever keys.  Hohoho.

    If the mouse is over the graph editor, it keys the attributes selected
    there.  Otherwise it keys the attributes selected in the channel box. If
    the channelBox is closed it will key all the attributes on the selected
    node.  It attempts to use the "Insert Key" function which makes keys match
    the curvature of the surrounding keys whenever possible.  Set insert
    parameter to false to disable this behavior."""

    # Get Attributes
    attributes = selectedAttributes.get(detectionType="cursor", useSelectedCurves=useSelectedCurves)
    currentFrame = cmd.currentTime(q=1)

    # Make extra sure attributes are unique (they should already be)
    attributes = list(set(attributes))

    if cmd.optionVar(ex="animBlendingOpt") and cmd.optionVar(q="animBlendingOpt") == 0:
        # PairBlend creation is disabled.  All incomming connections on
        # attributes will spit out warnings if we try to key them.
        removeConnectedAttributes(attributes)

    attrCount = 0
    for attr in attributes:
        # Test if we can use insert
        # canInsert returns 2 if something errored out in it.
        insertAttr = insert
        canInsert = canInsertKey(attr)
        if canInsert != 2:
            if not (insert and canInsert):
                insertAttr = False

            # Key it
            try:
                performSelect = selectNewKeyframe(attr)
                cmd.setKeyframe(attr, i=insertAttr)
                attrCount += 1

                # Select it if in between selected keys, or if adding
                # new keys and the last one was selected.
                if performSelect:
                    cmd.selectKey(attr, add=1, k=1, t=(currentFrame, currentFrame))

            except RuntimeError as err:
                print err
                om.MGlobal.displayError("Could not not set a key on %s." % attr)
    if attrCount:
        om.MGlobal.displayInfo("Set %d keys." % attrCount)
    else:
        om.MGlobal.displayInfo("No keys were set.")
def zeroSelection():
    '''Reset the selected channels to their default values.'''

    # Get Attributes
    attributes = selectedAttributes.get(detectionType='cursor', animatableOnly=False)

    # Make extra sure attributes are unique (they should already be)
    attributes = list(set(attributes))

    for attr in attributes:
        try:
            # Get default values
            default = cmd.attributeQuery(attr.split('.')[-1], node=attr.split('.')[0], listDefault=1)
            if isinstance(default, collections.Iterable) and len(default):
                try:
                    cmd.setAttr(attr, default[0])
                except RuntimeError:
                    # Maybe a compound?
                    om.MGlobal.displayError("Sorry, but I couldn't reset the attribute: %s" % attr)
            else:
                # Probably a string or something weird.  Actually, I'm
                # curious.  So I want to know what would fail..
                om.MGlobal.displayError("Sorry, but I don't know how to deal with the attribute: %s" % attr)
        except RuntimeError:
            # Print out error so I can debug any further problems if
            # they appear...
            om.MGlobal.displayError("Sorry, what is this? %s" % attr)
Example #3
0
def loadKeys(reload=0):
    # This function loads the currently selected keys.  It can be called
    # explicitly with reload = 1 or implicitly from other functions.  It
    # also tests if these new keys are the same as the old ones and
    # compares their values against the old ones.  If they have changed
    # it updates the keys, making things seamless and automatic for the
    # user.  This is so the user doesn't manually have to press a
    # "Reload Keys" button.

    # If the user is in the middle of sliding the slider or if there is
    # a manual reload button and it has NOT been pushed then skip
    # everything.
    global settings
    if settings.manualReload and not reload or settings.sliding:
        return

    newKeys = {}
    consecutive = True

    # Get keys for each attribute.
    keys = {}
    allKeys = {}
    selectedKeys = True
    attrs = []

    # Find selected keyframes if graph editor is open.
    if selectedAttributes.isGraphEditorVisible():
        attrs = cmd.keyframe(q=1, n=1, sl=1)

    # If none are selected, get any keys on the current frame that are
    # selected in the graph editor.  If the graph editor isn't open, get
    # what is selected in the channel box
    if attrs:
        for attr in attrs:
            keys[attr] = cmd.keyframe(attr, q=1, iv=1, sl=1)
            allKeys[attr] = cmd.keyframe(attr, q=1, iv=1)
    elif settings.findCurrentKeys:
        # Get selected
        attributes = selectedAttributes.get(detectionType='panel')
        # Get keyframe attrs from selected (Basically turns . to _ and
        # expands single objects to object attributes)
        attrs = []
        for att in attributes:
            att = cmd.keyframe(att, q=1, n=1)
            # Attributes can sometimes be None for some reason... So
            # check that.
            if att:
                attrs.extend(att)
        attrs = list(set(attrs))

        if attrs:
            # Find keyframes on current time.  If there are, add them to
            # keys
            time = cmd.currentTime(q=1)
            for attr in attrs:
                ky = cmd.keyframe(attr, q=1, iv=1, t=(time, time))
                if ky:
                    keys[attr] = ky
                    allKeys[attr] = cmd.keyframe(attr, q=1, iv=1)
            attrs = keys.keys()
            selectedKeys = False

    if not attrs:
        # No keys selected, and none under the current frame. Clear keys
        # so we don't operate later on them when nothing is selected.
        settings.keys = {}

    if attrs:
        changed = 0
        gKeys = settings.keys
        for attr in attrs:
            if keys[attr]:
                keys[attr].sort()
                allKeys[attr].sort()
                if not isConsecutive(keys[attr]):
                    consecutive = False
                # elif keys[attr][0] > allKeys[attr][0] or keys[attr][-1] < allKeys[attr][-1]:
                else:
                    first = 1
                    last = 1
                    if keys[attr][0] == allKeys[attr][0]:
                        first = 0
                    if keys[attr][-1] == allKeys[attr][-1]:
                        last = 0
                    keys[attr].insert(0, keys[attr][0] - first)
                    keys[attr].append(keys[attr][-1] + last)

                    newKeys[attr] = []

                    # Get default value
                    realNode = cmd.listConnections('%s.output' % attr, d=1, s=0, scn=1, p=1)[0].split('.')
                    default = cmd.attributeQuery(realNode[1], node=realNode[0], listDefault=1)[0]

                    # Test if keys are the same.  The test is in this
                    # section for efficiency.  Sorry it's less readable.
                    keyExisted = attr in gKeys.keys()
                    if not keyExisted or len(keys[attr]) != len(gKeys[attr]):
                        changed = 1

                    for x, key in enumerate(keys[attr]):
                        newKeys[attr].append({})
                        newKeys[attr][x]['key'] = key
                        newKeys[attr][x]['value'] = cmd.keyframe(attr, index=(key, key), q = 1, valueChange = 1)[0]
                        newKeys[attr][x]['time'] = cmd.keyframe(attr, index=(key, key), q = 1, timeChange = 1)[0]
                        newKeys[attr][x]['default'] = default
                        newKeys[attr][x]['endKey'] = (x == 0 and len(keys[attr]) > 1 and keys[attr][x + 1] == key) or (x == len(keys[attr]) - 1 and keys[attr][x - 1] == key)
                        newKeys[attr][x]['lastValue'] = newKeys[attr][x]['value']

                        if not changed and not reload:
                            # If keys are not on the same frame they have changed
                            if gKeys[attr][x]['key'] != key:
                                changed = 1
                            # If key is a start or end key and matches
                            # the next or previous key, it is a
                            # duplicate made on purpose.  lastValue will
                            # be changed on the real key in the middle.
                            # So the value check needs to be avoided for
                            # these duplicates.  These duplicates are
                            # made so that start and end keys can still
                            # be manipulated.
                            if not newKeys[attr][x]['endKey']:
                                # If keys do not have the same value, they have changed.
                                if round(gKeys[attr][x]['lastValue'], 5) != round(newKeys[attr][x]['value'], 5):
                                    changed = 1


    # Test if keys have changed.  If they have, reload them and set their defaults.
    if newKeys and not reload:
        if gKeys and not changed:
            if sorted(gKeys.keys()) != sorted(newKeys.keys()):
                changed = 1
            if not changed:
                # Don't do anything else, these are the same keys and
                # the user hasn't touched them.
                return

    # Keys will get reloaded beyond this point!
    settings.shrinkWarning = False

    # Find additional information needed for Shrink and Level function
    if newKeys:

        # Find Level Value and set the linear goals
        level = 0
        count = 0
        for attr in newKeys:
            startKey = newKeys[attr][0]
            endKey = newKeys[attr][-1]
            for key in range(1, len(newKeys[attr]) - 1):
                # Sum levels
                level += newKeys[attr][key]['value']
                count += 1

                # Linear goal
                # Find the value that is the linear interpolation of the
                # start key to the end key at the current frame
                totalTime = float(endKey['time'] - startKey['time'])
                try:
                    t = (newKeys[attr][key]['time'] - startKey['time']) / totalTime
                except ZeroDivisionError:
                    t = 0.0
                goal = (t * (endKey['value'] - startKey['value'])) + startKey['value']
                newKeys[attr][key]['linear'] = goal

        if count > 0:
            level /= count

        # Find out how many keys per attribute for shrink, and add level
        # to each key (it's the same value, but it doesn't make sense to
        # put it on a lower level)
        keys = []
        for attr in newKeys.keys():
            keys.append(len(newKeys[attr]))
            for key in newKeys[attr]:
                key['level'] = level

        center = []
        if len(set(keys)) == 1:
            count = []
            for attr in newKeys.keys():
                for x in range(len(newKeys[attr]) - 2):
                    if len(center) <= x:
                        center.append(0)
                        count.append(0)
                    center[x] += newKeys[attr][x + 1]['value']
                    count[x] += 1
            for x in range(len(center)):
                center[x] /= count[x]

        # Add shrink to newKeys
        for attr in newKeys.keys():
            for x in range(len(newKeys[attr]) - 2):
                if center:
                    newKeys[attr][x + 1]['shrink'] = center[x]
                else:
                    newKeys[attr][x + 1]['shrink'] = None

        # Let user know that shrink won't work.
        if not center:
            om.MGlobal.displayInfo('Shrink will not work for this selection.  Select the same number of keys for every attribute for shrink to work.')

        settings.keys = newKeys

        # Reset the GUI if appropriate.
        if reload and settings.absolute:
            updateSliderGui(0)

    # Update GUI or print warnings/errors
    if settings.keys:
        if not selectedKeys:
            om.MGlobal.displayInfo('Grabbed keys from current frame.')
    if not consecutive:
        om.MGlobal.displayWarning('All selected keys must be consecutive.')
    elif not settings.keys:
        om.MGlobal.displayError('You must select at least one key!')