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.
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; }
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:
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.
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; }
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; }
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.
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; }
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; }
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; }
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; }
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-insManager from the File menu) and clicking the Update button.
To test the menus, create and select some primitives and open the Application menu. At the bottom you will see the new menus:
Except where otherwise noted, this work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License