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)])
To that, you may have to go with PySide/PyQt. Find the pointer of the graph editor and find how the elements are layouted.
Here is a sample about changing stylesheet of maya menu :
from maya.OpenMayaUI import MQtUtil as omui
import sip
from PyQt4 import QtGui
def changeMayaMenuColors(fontStyle='italic', fontWeight='bold', fontColor='cyan'):
# Get the widget
widgetStr = mel.eval( 'string $tempString = $gMainCreateMenu' )
ptr = omui.findControl( widgetStr )
widget = sip.wrapinstance(long(ptr), QtGui.QWidget)
widget.setStyleSheet('font-style:%s;'%fontStyle +'font-weight:%s;'%fontWeight + 'color:%s;'%fontColor)
And here sonme experiments about channelBox :
from PySide import QtGui, QtCore
from shiboken import wrapInstance
from maya.OpenMayaUI import MQtUtil
channelbox = wrapInstance(long(MQtUtil.findControl('mainChannelBox')), QtGui.QWidget)
channelbox_children = channelbox.children()
first_widget = channelbox_children[0] # EDIT
first_widget.hide()
#first_widget.show()
#---------------------------------------------------------------------------------------------------------------
mySubWdget = first_widget.children()
new_button = QtGui.QPushButton()
new_layout = QtGui.QVBoxLayout()
first_widget.setLayout(new_layout)
new_layout.addWidget(new_button)
def print_hodor():
print 'HODOR'
new_button.clicked.connect(print_hodor)
You can do this kingd of experiments with all maya widget (find the pointer and then use wrapInstance to get the QT pointer, then iterate throught children to find the layout you may want)
hope it helps