QuickLaunch
dcc/maya/quicklaunch/ — not a separate
window at all, but a small row of icon "stacks" permanently embedded
into Maya's own native ToolBox (the vertical toolbar on the left edge
of the UI, usually holding select/move/rotate/scale), appended after a
separator at the bottom of it. It's meant to look like a native part
of the ToolBox rather than a bolted-on custom panel — it
deliberately does not apply the full
theme.MAIN_STYLE (tooltips and icon chrome stay native Maya
styling on purpose), but it does carry the thin
signature outline
around its own edge, the one piece of shared branding every application
in the suite carries.
Using it
Each configured group ("stack") renders as one icon:
- Left-click the icon — runs that group's first/primary tool. If the group has no tools assigned yet, left-click opens the Configure dialog instead.
- Hover the icon — if the group has more than one tool, a small floating popup of the remaining tools' icons appears beside it, each individually clickable. The popup collapses about 200ms after the mouse leaves both the stack and the popup (unless a context menu is open on it).
- Right-click the icon — Rename Group..., a Presets submenu (see below), Configure QuickLaunch..., Remove Group.
The Configure dialog
Opened via right-click > "Configure QuickLaunch..." (or by clicking an empty placeholder icon).
menu_query.DEFAULT_ICON
(dcc/maya/icons/CF_QuickLaunch.png, CF Clean 256 icon set)
— the same file used as the fallback icon for any menu_tools
launcher with no icon of its own, and as QuickLaunch's own default stack
icon (see Menu discovery),
so there's one canonical asset for all three roles.A drag-and-drop editor with two panes:
- Left ("TOOLS") — every discoverable launcher
tool (same tree
menu_query.pybuilds for the main menu — see Menu discovery), organized by folder, with a live filter box. Drag source only. - Right ("QUICKLAUNCH") — the current groups/stacks tree. Top-level items are groups, children are the tools in that group. Accepts drops from the left pane (adds to the target group, or creates a new group if dropped on empty space), and supports drag-reordering within itself.
Buttons: Add Group, Move Up, Move Down, Remove, Clear All, plus the Presets controls, and a single primary "Done" button.
Dragging a tool out of its group to the top level wraps it into its own new single-tool group rather than losing it — the underlying data model has no way to represent "a bare tool with no group."
The dialog's layout is loaded from a runtime-parsed .ui file
rather than a pre-compiled Python form (an accepted tradeoff since this
isn't a hot path) — the two drag-drop tree widgets can't be declared
in the .ui itself (QUiLoader can't construct custom
Python widget subclasses), so the .ui only holds placeholder
QWidgets that get swapped for the real tree instances after
loading.
Presets
A preset is a whole saved layout — a named snapshot of every configured group at once — not a per-tool bookmark. Save / Load / Delete live in the Configure dialog via a combo box, and Load is also reachable from any single stack's own right-click Presets submenu.
Presets are stored as individual JSON files
(quicklaunch/presets/<name>.json, {"name": ...,
"stacks": [...]}) — plain files you could hand-edit or check
into source control if a team wants to ship a shared default layout.
How it embeds into Maya's UI
toolbar.install() finds Maya's native ToolBox
widget and, inside it, a specific child layout ("flowLayout2",
a Maya-internal flow layout exposed to Python only as a generic
QLayout). It appends a separator plus the QuickLaunch widget
itself.
Two confirmed-live constraints worth knowing if you ever touch this:
- Only append/remove is safe.
addWidget()/removeWidget()onflowLayout2work; mid-layout insertion or reordering does not (a previously confirmed-broken attempt is why this constraint is called out explicitly in the code). remove()is written defensively against dangling Qt wrappers.deleteLater()only schedules destruction — a widget found viafindChild()on a later call may already be a Python wrapper around an already-destroyed C++ object, raising "Internal C++ object already deleted." Every lookup/delete inremove()is wrapped intry/except RuntimeError: passfor exactly this reason.
If ToolBox or flowLayout2 can't be found,
install() warns via cmds.warning() and returns
None rather than raising.
Public API
from CoreTools.dcc.maya.quicklaunch import toolbar
toolbar.install() # embeds the widget - safe to call repeatedly (calls remove() first)
toolbar.remove() # tears it down
install() -> QuickLaunchWidget | Noneremove() -> Nonewidget.load_stacks()/widget.save_stacks(stacks)— the persisted group list, stored as JSON under aQSettingskey (QuickLaunch/Stacks) separate from the general CoreTools config store.QuickLaunchWidget.refresh()— re-pulls tool icons/labels without rebuilding widgets (called after a config change).QuickLaunchWidget.open_config()— opens/raises the (singleton) Configure dialog.
A stack's data shape is
{"label": str, "modules": [dotted_module_name, ...]} — the
first module in the list is the "primary" one shown as the
always-visible icon; the rest populate the hover popup.