Search code examples
pythonwindowmayamel

How do I parent new, user-created buttons inside the Graph Editor window?


I'd like to add some new buttons to the Maya Graph editor -- particularly on top of the Channel list with all the attributes in the left of the window. However I'd rather not muck around with the Maya Startup scripts for the Graph Editor itself. Is there a way to "parent" the new buttons I want inside every new Graph Editor window using a separate script?

Ideally this could be all Python.


Solution

  • TL;DR;

    if cmds.window("GE_ui_window", exists=True): #If the window exists
        cmds.deleteUI("GE_ui_window") #Delete it
    cmds.window("GE_ui_window", title="My custom Graph Editor") #Create your custom win
    
    cmds.frameLayout("GE_ui_frameLayout", p="GE_ui_window", lv=False, bv=False ) 
    
    if cmds.scriptedPanel("GE_ui_scriptedPanel", exists=True): #If the scriptel panel already exists
        cmds.deleteUI("GE_ui_scriptedPanel") #Delete it
    cmds.scriptedPanel("GE_ui_scriptedPanel", unParent=True, type="graphEditor")
    cmds.scriptedPanel( "GE_ui_scriptedPanel", e=True, parent="GE_ui_window|GE_ui_frameLayout") #parent the scripted panel to your frame layout
    
    cmds.showWindow("GE_ui_window")
    
    channelLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[0] #Get the channel box's layout
    filterLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[1] #Get the filter's layout
    
    myRowLayout=cmds.rowLayout(numberOfColumns=3, p="GE_ui_scriptedPanelOutlineEdForm") #Create a row layout 
    cmds.button(label="Café", h=100, p=myRowLayout) #Add some buttons
    cmds.button(label="Clope", p=myRowLayout)
    cmds.button(label="Caca", p=myRowLayout)
    
    #This will reorder the content of the left formLayout
    cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", edit=True, af=[ \
                (channelLayout, "bottom", 0), \
                (channelLayout, "right", 0),  \
                (filterLayout, "top", 0),  \
                (myRowLayout, "left", 0),  \
                (myRowLayout, "right", 0)],  \
                ac=[(myRowLayout, "top", 0, filterLayout), \
                (channelLayout, "top", 0, myRowLayout)])
    

    There are two really usefull things to know when it comes to editing Maya's UI.

    First thing is the History -> Echo all commands checkbox in your script editor. This can print out a lot of garbage with usefull pieces of information inside.

    Second thing is the whatIs command (Doc).

    This command takes one string type argument and returns a string indicating whether the argument is a builtin "Command", a "Mel procedure", a "Script", or a variable. If it is a variable, the type of the variable is also given. If the argument is a Mel procedure or a script file, the path to the file containing the script or procedure is included in the return value.

    This combination will allow you to track down how and where the graph editor is created. Now let's do it.

    1: Open the graph editor Window -> Animation Editors -> Graph Editor

    GraphEditor;
    tearOffPanel "Graph Editor" "graphEditor" true;
    // Result: graphEditor1Window // 
    

    GraphEditor; is a Run Time Command which executes tearOffPanel "Graph Editor" "graphEditor" true; when called. That's why it appears in the script editor.

    2: Run whatIs "tearOffPanel"; (mel)

    // Result: Mel procedure found in: C:/Program Files/Autodesk/Maya2014/scripts/startup/tearOffPanel.mel // 
    

    With a little investigation in this file, you can deduce that you can create a whole new Graph Editor using the scriptedPanel command.

    3: Create your own Graph Panel

    The scriptedPanel doc show you how to create a scripted panel and include it in a window. You can now create you custom graph editor using this:

    if cmds.window("GE_ui_window", exists=True):
        cmds.deleteUI("GE_ui_window")
    cmds.window("GE_ui_window", title="My custom Graph Editor")
    
    cmds.frameLayout("GE_ui_frameLayout", p="GE_ui_window", lv=False, bv=False )
    
    if cmds.scriptedPanel("GE_ui_scriptedPanel", exists=True):
        cmds.deleteUI("GE_ui_scriptedPanel")
    cmds.scriptedPanel("GE_ui_scriptedPanel", unParent=True, type="graphEditor", label='Sample')
    cmds.scriptedPanel( "GE_ui_scriptedPanel", e=True, parent="GE_ui_window|GE_ui_frameLayout")
    
    cmds.showWindow("GE_ui_window")
    

    4: Try to understand how the Graph Editor is built

    This script will print out the widget hierarchy of a Graph Editor (create your custom Graph Editor first):

    nbIteration = 0
    def getChildren(uiItem, nbIteration):
        for childItem in cmds.layout(uiItem, query=True, childArray=True):
            try:
                print "|___"*nbIteration + childItem
                getChildren(uiItem + "|" + childItem, nbIteration+1)
            except:
                pass
    getChildren("GE_ui_window|GE_ui_frameLayout|GE_ui_scriptedPanel", nbIteration)
    

    Also, you can check into C:\Program Files\Autodesk\Maya2014\scripts\others\graphEditorPanel.mel, @939: global proc addGraphEditor (string $whichPanel)

    You can now realize that a lot of widgets are not given any name, only default name given by Maya. Hence, we can't add widgets and parent them using a full path because this path will change every time a new Graph Editor is created.

    The item we will try to rely on is GE_ui_scriptedPanelOutlineEdForm which is a formLayout containing an other formLayout and a paneLayout.

    |___|___GE_ui_scriptedPanelOutlineEdForm 
    |___|___|___paneLayout123 #layout containing the two channel boxes
    |___|___|___|___GE_ui_scriptedPanelOutlineEd
    |___|___|___|___GE_ui_scriptedPanelOutlineEdSlave
    |___|___|___formLayout276 #Layout containing the "filter part"
    |___|___|___|___textField63 #It's text
    |___|___|___|___iconTextButton102
    

    5: Create your buttons and reorder the content of GE_ui_scriptedPanelOutlineEdForm

    channelLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[0] #Get the channel box's layout
    filterLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[1] #Get the filter's layout
    
    myRowLayout=cmds.rowLayout(numberOfColumns=3, p="GE_ui_scriptedPanelOutlineEdForm") #Create a row layout 
    cmds.button(label="Café", h=100, p=myRowLayout) #Add some buttons
    cmds.button(label="Clope", p=myRowLayout)
    cmds.button(label="Caca", p=myRowLayout)
    
    #This will reorder the content of the left formLayout
    cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", edit=True, af=[ \
                (channelLayout, "bottom", 0), \
                (channelLayout, "right", 0),  \
                (filterLayout, "top", 0),  \
                (myRowLayout, "left", 0),  \
                (myRowLayout, "right", 0)],  \
                ac=[(myRowLayout, "top", 0, filterLayout), \
                (channelLayout, "top", 0, myRowLayout)])