Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I safely add menuItems to an existing menu in Maya MEL

Tags:

menu

maya

mel

I tried adding menu items to an existing menu in Maya using MEL

Example:

menuItem -label "Mylabel" -insertAfter "someEntry" -parent $gMainFileMenu;
menuItem -label "Mylabel2" -insertAfter "someEntry" -parent $gMainFileMenu;

The issue is that the menu doesn't get populated by the normal entries like it should but only by the entries I've added with these 2 lines of code.

For example, the file menu normally contains "New scene", "Open scene", "Save scene", etc., but when I do these 2 lines, it only contains "Mylabel" and "Mylabel2".

Is there a fix or a workaround to make sure the menu gets fully populated? Is there a way to force Maya to build it without the user actually clicking on it?

like image 914
Hugo Dozois Avatar asked Feb 16 '23 01:02

Hugo Dozois


1 Answers

Actually the problem is that Maya first populates the menu the first time the user opens it. It checks if the menu length and if it's greater than 0, it doesn't populate it. Since you've added 2 entries, the menu length is greater than 0 and doesn't get populated with the standard entries.

To fix that problem there is two ways to do it. You can do it by force-building the menu items or by registering your build menuItem. Bot ways are usable in different cases.

By force building the menu :

What you have to do, is find the function that Maya call to build the menu you need. You can find these functions in the folder <MayaInstall>/scripts/startup/*. A good way to find the procedure name is to open the Maya Console, enable "echo all commands" and then to click the menu you want to see the function called to build it.

In your case the function is called buildFileMenu() and can be found in the script FileMenu.mel.

Now that you have that function name, you have to check it's parameters. Sometime it need a menu name as parameters some times not. See the bottom section about how to find a menu name if you need one.

Now let's build it.

global string $gMainFileMenu; // Retrieve the menu name
buildFileMenu(); //  Build it

// Now build your menu
menuItem -divider true -parent $gMainFileMenu SuperMenuDivider;
menuItem -label "MyLabel1" -parent $gMainFileMenu SuperMenuLab1;
menuItem -label "MyLabel2" -parent $gMainFileMenu SuperMenuLab2;

// Create a proc to remove your menu items
global proc RemoveMyMenuItems()
{
    if(`menuItem -ex SuperMenuDivider`) deleteUI -mi SuperMenuDivider;
    if(`menuItem -ex SuperMenuLab1`) deleteUI -mi SuperMenuLab1;
    if(`menuItem -ex SuperMenuLab2`) deleteUI -mi SuperMenuLab2;
}
// You can then call that function when in the unload function of your plugin.

By registering the build menuItem call

What you have to do is use a function called addMenuItemSafe which takes 3 parameters, the menu you want to populate, the name of the function which populates the menu, and a global variable name to hold the callback.

So first thing you have to do is create the function that will populate your menu, then the function to remove it and then call the AddMenuItemSafe method. Note that in the function you have to check if your menu is already created because Maya will call that function every time the menu is shown.

First, the two functions to add and remove our menu entries:

global proc string AddMyMenuItems()
{
    // Global variable to hold the test to see if the menu is populated.
    global int $gMyMenuItemsTest;

    // Menu var needed in our case because we are inserting in the middle of the menu
    global string $gMainFileMenu;

    if( $gMyMenuItemsTest == 0 ) 
    {
        // Actually build your menu.
        // Note that if you don't need to insert it after a specific entry,
        // You can just do `menuItem -label "blep"`. No need of -ia and -p
        // Also, for inserting in the middle you have to put stuff in reverse order.
        // If you are just appending, put it in the normal order.
        menuItem -label "Mylabel2" -insertAfter "someEntry" -parent $gMainFileMenu MyMenuLab2;
        menuItem -label "Mylabel" -insertAfter "someEntry" -parent $gMainFileMenu MyMenuLab;
        menuItem -divider true -parent $gMainFileMenu MyMenuDiv;

        $gMyMenuItemsTest = 1;
    }
    return "RemoveMyMenuItems()"; // Returns the callback
}

global proc RemoveMyMenuItems()
{
    global int $gMyMenuItemsTest;

    if( $gMyMenuItemsTest == 1 ) 
    {
        // Delete your items if they exist (yes we are kind of 
        // doing the check twice, but I find it safe. 
        // The user could have deleted it from Maya in the command
        // line for whatever reason, more robustness is always good.
        if(`menu -ex MyMenuDiv`) deleteUI -mi MyMenuDiv;
        if(`menu -ex MyMenuLab`) deleteUI -mi MyMenuLab;
        if(`menu -ex MyMenuLab2`) deleteUI -mi MyMenuLab2;
    }
}

And then the actual call to the AddMenuItemSafe:

// The menu we want to use ... here it is the File Menu.
global string $gMainFileMenu;

// Our variables needed for the addSafe call
global int $gMyMenuItemsTest;
global string $gMyMenuVariable;
$gMyMenuItemsTest = 0;
$gMyMenuVariable = "";

// The menu creation
addMenuItemSafe($gMainFileMenu, "AddMyMenuItems", "gMyMenuVariable");

You are free to put that function call in a plugin instantiation or where ever it pleases you.

For more information about the function AddMenuItemSafe, you can go in your Maya Scripts Directory it should be there "AddMenuItemSafe.mel".


How to find a menu name

Note for the menu variable names, you can "build" them by using the following convention

"g" + View + Name + "Menu"

Where :

  • View is the view where you can find that menu. Ex: Main, Polygons, Animations, etc.

  • Name is the name of the menu. Ex: File, Edit, Mesh, etc.

Note Autodesk will sometimes rename menus and use old globalVariable names so using this method might not always work

like image 149
Hugo Dozois Avatar answered Mar 24 '23 23:03

Hugo Dozois