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:

  1. Context. The first selected transform is tested against the registered contexts, from the highest priority to the lowest. The first context whose detector returns True builds the menu. If no context matches, Maya’s default menu is shown.

  2. Prepare. The context’s optional prepare function runs. The built-in "control" context uses it to load the items of Shifter components.

  3. Sections. The context’s sections are built in ascending order. A section whose poll function returns False is skipped. A divider is added between sections automatically.

Built-in contexts:

Context

Priority

Detects

control

100

mGear rig controls (isCtl attribute)

guide

90

Shifter guide nodes (rig_name or isGearGuide attribute)

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),
)

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=True its 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 icons folder, 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 the XBMLANGPATH environment variable in Maya.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

node

The right-clicked node (full path)

selection

The selected nodes

ui_host

The control holding the IK/FK and space switch attributes

ikfk_attrs

(attribute, suffix) IK/FK blend and switch attributes

space_attrs

(node, attribute) space switch enum attributes

child_controls

Controls below the selected controls, and the node

all_controls

All the controls of the rig

rig_root

The rig top node

comp_type

The Shifter component type of the control, i.e. arm_2jnt_01

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__.py is 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_type attribute. 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.

API reference

See mgear.core.dagmenu package.