Viewport Menu
The mGear Viewport Menu replaces Maya’s right-click menu when an mGear control or a Shifter guide is selected. Turn it on or off with the mGear Viewport Menu checkbox in the mGear menu. The items it shows for animators are described in Quick Start.
This page is for TDs and pipeline developers who want to add their own items to the menu, from a tool, a custom step, a userSetup.py or a Shifter component.
How the menu is built
On right-click, the menu goes through three steps:
Context. The first selected transform is tested against the registered contexts, from the highest priority to the lowest. The first context whose detector returns
Truebuilds the menu. If no context matches, Maya’s default menu is shown.Prepare. The context’s optional
preparefunction runs. The built-in"control"context uses it to load the items of Shifter components.Sections. The context’s sections are built in ascending order. A section whose
pollfunction returnsFalseis skipped. A divider is added between sections automatically.
Built-in contexts:
Context |
Priority |
Detects |
|---|---|---|
control |
100 |
mGear rig controls ( |
guide |
90 |
Shifter guide nodes ( |
Built-in sections use orders in steps of 100, so the gaps are free for your own sections.
Order |
Control section |
Order |
Guide section |
|---|---|---|---|
100 |
select_host |
100 |
settings |
200 |
ikfk_switch |
200 |
build |
300 |
select_children |
300 |
duplicate |
400 |
reset |
400 |
guide_manager |
500 |
mirror_flip |
500 |
export |
600 |
rotate_order |
600 |
update |
700 |
spaces |
700 |
xray |
800 |
select_all_keyframe |
||
900 |
xray |
||
1000+ |
Shifter component items |
Adding a section
A section is a function that adds items to the menu. It receives a builder, to add the items, and a ctx, with the right-clicked node and its rig data.
from functools import partial
from mgear.core import dagmenu
def print_control(control):
print(control)
def build(builder, ctx):
builder.item("Print Control", partial(print_control, ctx.node))
dagmenu.register_section("control", "print_control", 650, build)
This adds Print Control between the Rotate Order switch (600) and the Parent spaces (700).
Registering the same context and name again replaces the section, so reloading your tool doesn’t duplicate items.
dagmenu.unregister_section("control", "print_control")removes it. This also works on built-in sections, i.e.dagmenu.unregister_section("control", "xray").If a section raises an error, the error is logged and the rest of the menu is still built.
Use a poll function to show the section only for some controls:
dagmenu.register_section(
"control",
"space_tools",
750,
build_space_tools,
poll=lambda ctx: bool(ctx.space_attrs),
)
Menu commands
Bind the command arguments with functools.partial. Commands are called without arguments; the check state that Maya sends to menu commands is dropped.
Keep the build function light: it runs on every right-click. Query heavy data in the command, when the item is clicked, not when the menu is built.
The builder
builder.item(label, command=None, image=None, **kwargs)Adds a menu item. Extra keyword arguments are passed to
cmds.menuItem, i.e.radioButton=True.builder.divider()Adds a divider before the next item. A menu never starts or ends with a divider, and never has two in a row.
builder.submenu(label, image=None, radio=False)Context manager that adds a submenu and gives its builder. With
radio=Trueits items are grouped as radio buttons.
def build(builder, ctx):
with builder.submenu("My Tools") as sub:
sub.item("Tool A", partial(tool_a, ctx.node))
sub.divider()
sub.item("Tool B", partial(tool_b, ctx.node))
Icons
builder.item and builder.submenu take an image argument. It accepts the same values as the image flag of cmds.menuItem: an icon file name found in Maya’s icon paths, or the full path of an image file (.png or .svg).
def build(builder, ctx):
# Maya icon
builder.item(
"Key Control",
partial(cmds.setKeyframe, ctx.node),
image="setKeyframe.png",
)
# mGear icon
builder.item(
"My Reset",
partial(my_reset, ctx.node),
image="mgear_refresh-cw.svg",
)
# custom icon, by full path
builder.item(
"My Tool",
partial(my_tool, ctx.node),
image="D:/studio/icons/my_tool.svg",
)
with builder.submenu("My Tools", image="mgear_list.svg") as sub:
sub.item("Tool A", partial(tool_a, ctx.node))
Where to find icons:
Maya icons: browse them in Windows > General Editors > Resource Browser, or list them with
cmds.resourceManager(nameFilter="*key*"). Use the name as shown, i.e."setKeyframe.png".mGear icons: the files in the mGear
iconsfolder, i.e."mgear_x.svg","mgear_sliders.svg". The mGear module adds this folder to Maya’s icon paths.Custom icons: use the full file path, or add your icon folder to Maya’s icon paths and use the file name only. Add the folder with an
icons:line in your own Maya module file (.mod), or with theXBMLANGPATHenvironment variable inMaya.env.
Prefer .svg icons, they stay sharp at any display scaling. An icon that can’t be found shows no image, the item still works.
The context
ctx gives the right-clicked node and the data the built-in sections use. Each value is queried the first time it’s used and then cached for that right-click.
Attribute |
Value |
|---|---|
|
The right-clicked node (full path) |
|
The selected nodes |
|
The control holding the IK/FK and space switch attributes |
|
|
|
|
|
Controls below the selected controls, and the node |
|
All the controls of the rig |
|
The rig top node |
|
The Shifter component type of the control, i.e. |
Adding a context
Register a context to show an mGear menu on other kinds of nodes:
from maya import cmds
from mgear.core import dagmenu
def is_joint(ctx):
return cmds.nodeType(ctx.node) == "joint"
dagmenu.register_context("joint", is_joint, priority=10)
dagmenu.register_section("joint", "joint_tools", 100, build_joint_tools)
register_context also accepts a prepare function, called with the context before the sections are built, i.e. to register sections on demand.
Shifter component items
A Shifter component can add items for its own controls with a dagmenu.py file in its folder, next to its __init__.py. This works for built-in components and for custom components found through MGEAR_SHIFTER_COMPONENT_PATH.
# my_component_01/dagmenu.py
from functools import partial
def match_pose(control):
print("match", control)
def build(builder, ctx):
builder.item("Match Pose", partial(match_pose, ctx.node))
def register(registry):
registry.register_section("match_pose", build)
The file is imported the first time a control of that component type is right-clicked, and only once per session. The component
__init__.pyis not imported.registry.register_section(name, build, order=1000, poll=None)adds the section to the"control"context. It only shows for the controls of that component type, after the built-in sections.Use absolute imports in
dagmenu.py, it is not imported as part of the component package.Rigs built with mGear 5.4.0 or later store the component type on each control in the
ctl_comp_typeattribute. Older rigs find it from the guide data stored in the rig.
Where to register
Register your sections once per Maya session, after mGear is loaded. For example, from a userSetup.py:
from maya import cmds
cmds.evalDeferred("import my_studio.dagmenu_items")
where my_studio/dagmenu_items.py calls dagmenu.register_section at import. The menu module itself is light to import: it doesn’t load Shifter.