Move Attribute Script

Ever get annoyed that you can’t re-arrange the attributes in the Channel Box? I certainly do, but there is something you can work with. When you delete an attribute and then undo, the attribute gets put at the bottom of the list and its connections are maintained.

So with this trick in mind, I was curious to see if I could write a script that uses that single trick to fake the act of moving attributes up and down. It took a while, but I figured it out!

Writing it out and doing it manually helped a lot for this problem. So let’s go through it. Let’s say I want to move “A” down one position in attribute list ABCDE so that we’d end with BACDE. With Maya’s delete/undo functionality, we’d get BCDEA. We want A to be after B, so let’s delete the attributes in front of A until that’s so. We get: BCDAE, BCAED, and BAEDC. Notice something? After our attribute is moved to its proper position, the order of the attributes after it get reversed. To get them back to their original order, we delete the attribute in front of the last attribute in the list (C) until it is after the attribute we wanted to move down (A). So we have BAEDC, BAECD, BACDE. Our list is now in the order that we wanted it and we moved A down one position. Hooray!

There’s a little more to it, but that’s essentially what the script does. It works on one attribute at a time, so don’t expect to be able to move whole chunks of attributes at once.

import maya.cmds as cmds


def delAttr(objAttr):
    # moves an attribute to the bottom of a list
    cmds.undo(cmds.deleteAttr(objAttr))


def moveDown(attr):
    # get the selection
    sel = cmds.ls(sl=1, o=1)[0]
    # list the user keyable user defined attributes. we can't reorder default attr
    attrList = cmds.listAttr(sel, keyable=1, userDefined=1)
    # get the list len
    listLen = len(attrList)
    # this checks to see if the attribute we're trying to move down is already at the bottom
    if attrList.index(attr) == listLen - 1:
        return
    attrIndex = attrList.index(attr)

    numBelow = len(attrList[attrIndex + 1:]) - 1
    # moves the attribute above it to the bottom of the list
    delAttr("%s.%s" % (sel, attr))
    a = 0
    while a < numBelow:
        list = cmds.listAttr(sel, k=1, ud=1)
        delAttr("%s.%s" % (sel, list[list.index(attr) - 1]))
        a += 1
    # get our updated list
    list = cmds.listAttr(sel, k=1, ud=1)
    lastAttr = list[-1]
    attrIndex = list.index(attr)

    while cmds.listAttr(sel, k=1, ud=1).index(lastAttr) > attrIndex + 1:
        # reverse the list below our moved attribute
        list = cmds.listAttr(sel, k=1, ud=1)
        delAttr("%s.%s" % (sel, list[list.index(lastAttr) - 1]))


def moveUp(attr):
    # get the selection
    sel = cmds.ls(sl=1, o=1)[0]
    # list the user keyable user defined attributes. we can't reorder default attr
    attrList = cmds.listAttr(sel, keyable=1, userDefined=1)
    # get the list len
    listLen = len(attrList)
    # this checks to see if the attribute we're trying to move down is already at the bottom
    if attrList.index(attr) == 0:
        return
    attrIndex = attrList.index(attr)
    moveDown(attrList[attrIndex - 1])

And the UI:

import maya.cmds as cmds
import bm_moveAttr
reload(bm_moveAttr)
from functools import partial

def buttonComand(direction, *args):
    if not cmds.ls(sl=1, o=1):
        # if nothing is selected in the channel box, do nothing
        return
    if direction == "up":
        # this command gets the currently selected attribute in the channel box
        selAttr = cmds.channelBox("mainChannelBox", q=1, sma=1)[0]
        if len(selAttr) > 1:
            return
        bm_moveAttr.moveUp(selAttr)
    if direction == "down":
        # this command gets the currently selected attribute in the channel box
        selAttr = cmds.channelBox("mainChannelBox", q=1, sma=1)[0]
        if len(selAttr) > 1:
            return
        bm_moveAttr.moveDown(selAttr)

if cmds.window("bm_moveAttrUI", exists=1):
    cmds.deleteUI("bm_moveAttrUI")

cmds.window("bm_moveAttrUI", tlb=1,title="moveAttr")
cmds.columnLayout(columnAlign="center",rowSpacing=2,adjustableColumn=1)
cmds.text("Move Selected \nAttribute")
cmds.button("moveUp", width=45,label=" ^ ", bgc=(.475,.475,.475),command=partial(buttonComand, "up"))
cmds.button("moveDown",width=45, label=" v ",bgc=(.375,.375,.375), command=partial(buttonComand, "down"))

cmds.showWindow("bm_moveAttrUI")
cmds.window("bm_moveAttrUI", e=1, wh=(85, 90),s=1,bgc=(.275,.275,.275))

Advertisements
Image

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s