Custom Menu Examples

The following custom menu examples are provided:

• JScript Example: Nesting SubMenus within SubMenus—demonstrates how to use the AddItem method to create submenus that cascade down through three or four levels.

• JScript Example: Simulating Command Instances with Menu Callback Items—demonstrates how you can define a number of callback menu items in a self-installing plug-in that implement different flavors (instances) of standard Softimage commands.

| In addition, there is a Simple Menu plug-in example (versions written in VBScript, JScript and C++) included with the Softimage SDK installation: check the following location:
       %XSI_ROOT%/XSISDK/examples/menus

JScript Example: Nesting SubMenus within SubMenus

This self-installing menu plug-in demonstrates how to nest submenus deeply. he entries used are just blank entries to demonstrate the mechanism.

    /* ------------------------------------------------------------------

           This self-installing menu plug-in demonstrates how to
           nest submenus deeply. The entries used are just blank
           entries to demonstrate the mechanism.

    */

    /* ------------------------------------------------------------------

       ### REGISTRATION ###

    */
    function XSILoadPlugin( in_reg )
    {
       // Set up some basic information for the whole plug-in
       in_reg.Name = "Nested Demo";
       in_reg.Author = "Softimage SDK Education";
       in_reg.Email = "editors@softimage.com";
       in_reg.URL = "http://www.softimage.com/education";
       in_reg.Major = 1;
       in_reg.Minor = 0;

       // Register a single Menu entry point on the Help menu
       in_reg.RegisterMenu( siMenuMainHelpID, "NestedMenus" );

       // Only the first level is flat; the submenus still cascade on
       // the Window menu
       in_reg.RegisterMenu( siMenuMainWindowID, "NestedMenus", false );

       // This one will stick all submenus on the same level on the Layers
       // contextual menu
       in_reg.RegisterMenu( siMenuSELayersContextID, "FlatMenus" );

       // You can also log a message about this plug-in's installation
       Application.LogMessage( "The 'Nested Demo' plug-in has been "
           + "successfully installed." );

       // Finish with success notification
       return true;
    }

    /* ------------------------------------------------------------------

       ### DEFINITION ###

       This menu definition creates a cascading menu effect
       with several submenus nested inside the next one.

    */
    function NestedMenus_Init( in_context )
    {
       // Get the menu object from the Context input
       var oTopMnu = in_context.Source;

       // Add some regular menu items
       oTopMnu.AddItem( "Regular Item1", siMenuItem );
       oTopMnu.AddItem( "Regular Item2", siMenuItem );

       // Add the submenu item
       var oSubLevel1 = oTopMnu.AddItem( "SubMenu Demo Level1",
           siMenuItemSubmenu )
       oSubLevel1.AddItem( "SubLevel1 ItemA", siMenuItem );
       oSubLevel1.AddItem( "SubLevel1 ItemB", siMenuItem );

       // Nest another submenu item
       var oSubLevel2 = oSubLevel1.AddItem( "SubMenu Demo Level2",
           siMenuItemSubmenu )
       oSubLevel2.AddItem( "SubLevel2 ItemA", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemB", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemC", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemD", siMenuItem );

       // ...and another ...
       var oSubLevel3 = oSubLevel2.AddItem( "SubMenu Demo Level3",
           siMenuItemSubmenu )
       oSubLevel3.AddItem( "SubLevel3 ItemA", siMenuItem );
       oSubLevel3.AddItem( "SubLevel3 ItemB", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemC", siMenuItem );

       // ,,, etc.

       // Finish with success notification
       return true;
    }

    /* ------------------------------------------------------------------

       ### DEFINITION ###

       This menu definition creates a several submenus
       appearing as siblings.

    */
    function FlatMenus_Init( in_context )
    {
       // Get the menu object from the Context input
       var oTopMnu = in_context.Source;

       // Add some regular menu items
       oTopMnu.AddItem( "Regular Item1", siMenuItem );
       oTopMnu.AddItem( "Regular Item2", siMenuItem );

       // Add a submenu item
       var oSubLevel1 = oTopMnu.AddItem( "SubMenu Demo Level1",
           siMenuItemSubmenu )
       oSubLevel1.AddItem( "SubLevel1 ItemA", siMenuItem );
       oSubLevel1.AddItem( "SubLevel1 ItemB", siMenuItem );

       // And another submenu item
       var oSubLevel2 = oTopMnu.AddItem( "SubMenu Demo Level2",
           siMenuItemSubmenu )
       oSubLevel2.AddItem( "SubLevel2 ItemA", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemB", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemC", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemD", siMenuItem );

       // ...and another ...
       var oSubLevel3 = oTopMnu.AddItem( "SubMenu Demo Level3",
           siMenuItemSubmenu )
       oSubLevel3.AddItem( "SubLevel3 ItemA", siMenuItem );
       oSubLevel3.AddItem( "SubLevel3 ItemB", siMenuItem );
       oSubLevel2.AddItem( "SubLevel2 ItemC", siMenuItem );

       // ,,, etc.

       // Finish with success notification
       return true;
    }

JScript Example: Simulating Command Instances with Menu Callback Items

This example demonstrates how you can define a number of callback menu items in a self-installing plug-in that implement different flavors (instances) of standard Softimage commands:

1. Create a script file in the $user/Application/Plugins folder and name it OpMenuInstances.js. This will contain the JScript implementation of the new custom menu.

2. Set up the registration callback containing two custom menus to appear in the Application menu: one containing Deform operator instances and another containing Generator operator instances:

    function XSILoadPlugin( in_reg )
    {
       // Register the plug-in information
       in_reg.Author = "Softimage Corp.";
       in_reg.Name = "Submenu command example";

       // Set the version number of this plugin
       in_reg.Major = 1;
       in_reg.Minor = 0 ;

       // Register the Deform menu in the Application menu
       in_reg.RegisterMenu( siMenuMainApplicationID, "ApplyDeformOp_Menu" );

       // Register the Generator menu in the Application menu
       in_reg.RegisterMenu( siMenuMainApplicationID, "ApplyGenOp_Menu" );

       LogMessage( in_reg.Name + " has been loaded." );

       return true;
    }

3. Define the Apply Deform Operators menu using the Init callback. This menu’s items will always appear, regardless of what is currently selected. It contains three sections separated by menu separator bars:

    function ApplyDeformOp_Menu_Init( in_ctxt )
    {
       var menu = in_ctxt.source;

       menu.Name = "Apply Deform Operators";
       menu.AddCallbackItem( "Twist", "OnApplyDeformOp" );
       menu.AddCallbackItem( "Bend", "OnApplyDeformOp" );
       menu.AddCallbackItem( "Bulge", "OnApplyDeformOp" );
       menu.AddCallbackItem( "Shear", "OnApplyDeformOp" );
       menu.AddCallbackItem( "Taper", "OnApplyDeformOp" );

       menu.AddSeparatorItem();

       menu.AddCallbackItem( "Expand", "OnApplyDeformOp2" );
       menu.AddCallbackItem( "Contract", "OnApplyDeformOp2" );

       menu.AddSeparatorItem();

       menu.AddCallbackItem( "Randomize", "OnApplyDeformOp2" );
       menu.AddCallbackItem( "Relax", "OnApplyDeformOp2" );
       menu.AddCallbackItem( "Smooth", "OnApplyDeformOp2" );
       menu.AddCallbackItem( "QStretch", "OnApplyDeformOp2" );

       return true;
    }

This menu uses two callbacks:

- OnApplyDeformOp—simple implementation that takes the name of the operator (used as the name of the menu item) and calls the ApplyOp command with all default values.

- OnApplyDeformOp2—more complex implementation that uses a switch statement to test the name of the menu item. Based on the name, either ApplyOp or ApplyKinematicOp is called with specific parameter values and, in some cases, extra tasks are performed after the operator is applied.

4. Write the simple implementation for the OnApplyDeformOp callback:

    function OnApplyDeformOp( in_ctxt )
    {
       // Get the menu item name
       var mnu_itm = in_ctxt.Source;

       ApplyOp( mnu_itm.Name );
       return true;
    }

5. Write the more complex implementation for the OnApplyDeformOp2 callback:

    function OnApplyDeformOp2( in_ctxt )
    {
       // Get the menu item name
       var mnu_itm = in_ctxt.Source;

       switch (mnu_itm.Name) {
           case "Randomize" :
              // You can specify extra arguments
              ApplyOp( "Randomize", null, siBranch );
              break;
           case "Expand" :
              // You could run extra commands to tweak the result...
              var op = ApplyOp( "Push" )(0);
              op.ampl.Value = 2;
              break;
           case "Contract" :
              // ...and make slight changes
              var op = ApplyOp( "Push" )(0);
              op.ampl.Value = -2;
              break;
           case "QStretch" :
              // You can call a different command
              ApplyKinematicOp( "QStretch", null, siBranch );
              break;
           case "Punch Out Shape" :
              ApplyOp( "QStretch", null, siBranch );
              break;
           default :
              // This will catch "Relax" and "Smooth"
              ApplyOp( mnu_itm.Name );
       }

       return true;
    }

6. Define the Apply Generator Operators menu using the Init callback. This menu’s items appear only under certain circumstances related to what is currently selected:

- When the selected items have different primitive types, no items are added to the menu.

- When two or more surface meshes are selected, only the Fit and Fillet Intersection operators are added to the menu.

- When only one polygon mesh is selected, only the Subdivide operator is added to the menu.

- When two or more polygon meshes are selected, the three Boolean, Blend and Subdivide operators are added to the menu.

| This conditional menu contruction only works when the menu is dynamic (that is, when the RegisterMenu (PluginRegistrar) method uses the default value, true, for the Dynamic argument—see Are the Contents of My Menu Fixed? for more information).

    function ApplyGenOp_Menu_Init( in_ctxt )
    {
       var menu = in_ctxt.source;

       menu.Name = "Apply Generator Operators";

       // Make all selected objects are the same type
       var primtype = "";
       for ( var i=0; i<Selection.Count; i++ ) {
           if ( primtype == "" ) {
              primtype = Selection(i).Type;
           } else {
              if ( primtype != Selection(i).Type ) {
                  return false;
              }
           }
       }

       // Build the menu items according to the primitive type of the
       // selected objects
       switch (primtype) {
           case siSrfMeshPrimType :
              // Only display operator types that can be applied to surfmeshes
              if ( Selection.Count > 1 ) {
                  // Make sure at least two items are selected
                  menu.AddCallbackItem( "Fit to Shape", "OnApplyGenOp" );
                  menu.AddCallbackItem( "Fillet Intersection", "OnApplyGenOp" );
              }
              break;

           case siPolyMeshType :
              // Only display operator types that can be applied to polymeshes
              if ( Selection.Count > 1 ) {
                  // Make sure at least two items are selected for boolean operations
                  menu.AddCallbackItem( "Punch Out Shape (Difference)",
                     "OnApplyGenOp" );
                  menu.AddCallbackItem( "Leave Remainder Shape (Intersection)",
                     "OnApplyGenOp" );
                  menu.AddCallbackItem( "Bind Shapes Together (Union)",
                     "OnApplyGenOp" );
                  menu.AddCallbackItem( "Blend Shapes (Mesh)", "OnApplyGenOp" );
              }

              menu.AddCallbackItem( "Subdivide Selection", "OnApplyGenOp" );
              break;
       }

       return true;
    }

7. Write the implementation for the OnApplyGenOp callback. Since the Init callback performed all the tests on the selection before enabling certain callbacks, this callback doesn't need to check that the selected types are appropriate for the input objects, since any commands that didn't fit the selection were filtered out:

    function OnApplyGenOp( in_ctxt )
    {
       // Get the menu item name
       var mnu_itm = in_ctxt.Source;

       switch (mnu_itm.Name) {
           case "Punch Out Shape (Difference)" :
              ApplyGenOp( "BooleanGenDifference", "", "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           case "Leave Remainder Shape (Intersection)" :
              ApplyGenOp( "BooleanGenIntersection", "", "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           case "Bind Shapes Together (Union)" :
              ApplyGenOp( "BooleanGenUnion", "", "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           case "Subdivide Selection" :
              MeshSubdivideWithCenter( null, "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           case "Fit to Shape" :
              ApplyGenOp( "SrfFit", "", "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           case "Fillet Intersection" :
              ApplyGenOp( null, "", "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           case "Blend Shapes (Mesh)" :
              ApplyGenOp( "MeshBlend", "", "", null,
                  siImmediateOperation, siDeleteGenOpInputs );
              break;
           default :
       }

       return true;
    }

8. Save the file and launch Softimage. If Softimage is already running, you can explicitly load this plug-in by opening the Plug-in Manager (select Plug-ins > Manager from the File menu) and clicking the Update button.

9. To test the menus, create and select some primitives and open the Application menu. At the bottom you will see the new menus:

- Apply Deform Operators [u]

- Apply Generator Operators [u]

Autodesk Softimage v7.5