Adds a menu item to the end of the menu and attaches a callback function. The callback is fired when the menu item is selected.

The callback function must be implemented in the plug-in file as described in Definition Callbacks for Menus. If your menu is attached to a contextual menu, the currently selected objects are passed in to your callback. The target object under the cursor is also passed in as part of the selected objects. However if no objects are selected, then only the target is passed in. The objects can be retrieved through the Context.GetAttribute method with "Target" specified as the value for the AttributeName parameter. The selected/target objects are not passed in to the callback of a custom menu item attached to a regular menu.

Note: It is a bit easier to use this method to write script code as a menu callback rather than using Menu.AddCommandItem and implementing a custom Command. However the advantage of using a custom command is that it can also be invoked, without user involvement, from scripting.

Tip: See any of the examples for creating a Simple Menu plug-in to see this method in action.

Note: This method could return an invalid object in python, use Menu.AddCallbackItem2 instead.

C# Syntax

MenuItem Menu.AddCallbackItem( String in_pLabel, String in_pszCallback );

Scripting Syntax

oReturn = Menu.AddCallbackItem( Label, Callback );

Return Value

The newly created MenuItem object.


Parameter Type Description
Label String The menu item label.
Callback String The name of the callback function.

Important: The function must be implemented in the self-installed menu plug-in file.


1. JScript Example

// This example shows how to implement a menu for accessing
// the target of an anchor hook. Run the example from the
// Softimage Script Editor and then follow the MANUAL STEPS.
// Start by building the plug-in on disk
// Then create a mesh and activate vertex selection
CreatePrim("Torus", "MeshSurface");
	Now right-click on the torus and select 'Get Target Info' from the
	pop-up menu. Something like the following will log:
	// Menu Target torus contains 1 item(s):
	//    Target item torus is a X3DObject
	//    Target contains 4 NestedObject(s):
	//       torus.Name (Parameter)
	//       torus.primitive (Parameter)
	//       torus.nodecurrent (Parameter)
	//       torus.Children (Parameter)
	// MenuItem Callback: LogTargetInfo
	// MenuItem Name: Get Target Info
	// MenuItem Origin: siUnknownPath
// Utility function to create the demo plug-in on disk
function BuildDemoPlugin()
	var sPluginFile = XSIUtils.BuildPath(
		"Application", "Plugins", "MenuDemo.js"
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	if (!fso.FileExists(sPluginFile)) {
		var ts = fso.CreateTextFile(sPluginFile);
			XSILoadPlugin.toString() +
			DemoContextMenu_Init.toString() +
			LogTargetInfo.toString() +
			MakeInstallPathReadable.toString() +
// Registration callback
function XSILoadPlugin( in_reg )
	in_reg.Author = "Softimage";
	in_reg.Name   = "MyContextMenu";
	in_reg.Major  = 1;
	in_reg.Minor  = 0;
	in_reg.RegisterMenu(siMenu3DViewObjectSelectContextID, "DemoContextMenu", false, false);
// Init callback
function DemoContextMenu_Init(in_ctxt)
	in_ctxt.Source.AddCallbackItem('Get Target Info', "LogTargetInfo");
	return true;
// AddCallbackItem handler
function LogTargetInfo(in_ctxt)
	// Context.GetAttribute("Target") allows you to access the target of the 
	// anchor point by returning an XSICollection containing the target(s)
	var oTargetColl = in_ctxt.GetAttribute("Target");
	Log("Menu Target contains "+oTargetColl.Count+" item(s):");
	for ( var i=0; i<oTargetColl.Count; i++ ) {
		var oTarget = oTargetColl.Item(i);
		Log("   Target item "+oTarget+" is a "+Application.ClassName(oTarget));
		Log("   Target contains "+oTarget.NestedObjects.Count+" NestedObject(s):");
		for ( var j=0; j<oTarget.NestedObjects.Count; j++ ) {
			var oNested = oTarget.NestedObjects.Item(j);
			Log("      "+oNested+" ("+Application.ClassName(oNested)+")");
	var oMenuItem = in_ctxt.Source;
	Log("\nMenuItem Callback: "+oMenuItem.Callback);
	Log("MenuItem Name: "+oMenuItem.Name);
	Log("MenuItem Origin: "+MakeInstallPathReadable(oMenuItem.Origin));
// Workhorse functions
function MakeInstallPathReadable(in_path)
	switch (in_path) {
		case siProjectPath :		return "siProjectPath";
		case siUserPath :			return "siUserPath";
		case siWorkgroupPath :		return "siWorkgroupPath";
		case siFactoryPath :		return "siFactoryPath";
		case siAddonPath :			return "siAddonPath";
		case siUserAddonPath :		return "siUserAddonPath";
		case siWorkgroupAddonPath :	return "siWorkgroupAddonPath";
		case siUnknownPath :		return "siUnknownPath";
		case siCustomPath :			return "siCustomPath";
function Log(in_msg)
	Application.LogMessage(in_msg, siComment);

2. JScript Example

// This example shows how to implement a menu for calling 
// commands with and without hardcoded arguments through a 
// callback function.
// README: Copy and paste the example into the script editor 
// and run (F5).
// The menu will install itself into the application's main menubar
function XSILoadPlugin( in_reg )
	in_reg.Author = "Softimage Co.";
	in_reg.Name = "Menu.AddCallbackItem Example";
	// Sdd a custom menu under the Application menu in the main menu bar
	in_reg.RegisterMenu( siMenuMainApplicationID, "ApplyOp_Menu" );
	LogMessage( in_reg.Name + " has been loaded." );
	return true;
function ApplyOp_Menu_Init( in_ctxt )
	var menu = in_ctxt.source;
	menu.Name = "Apply Deform operators";
	menu.AddCallbackItem( "Twist", "OnApplyOp" );
	menu.AddCallbackItem( "Bend", "OnApplyOp" );
	menu.AddCallbackItem( "Bulge", "OnApplyOp" );
	menu.AddCallbackItem( "Shear", "OnApplyOp" );
	menu.AddCallbackItem( "Taper", "OnApplyOp" );
	menu.AddCallbackItem( "Push", "OnApplyOp" );
	menu.AddCallbackItem( "Relax", "OnApplyOp" );
	menu.AddCallbackItem( "Smooth", "OnApplyOp" );
	menu.AddCallbackItem( "QStretch", "OnApplyOp" );
	menu.AddCallbackItem( "Randomize", "OnApplyOp" );
	return true;
function OnApplyOp( in_ctxt )
	var item = in_ctxt.Source;
	switch( item.Name )
		case "QStretch":
			ApplyKinematicOp( "QStretch", null, siBranch );
		case "Randomize":
			ApplyOp( "Randomize", null, siBranch );
			ApplyOp( item.Name );
	return true;
// Code to bootstrap example into system
function ExampleSourceCode()
	return "// XSISDK Doc Example\n" +	
		ApplyOp_Menu_Init.toString() + "\n" + 
		OnApplyOp.toString() + "\n" + 
// If we are running from script editor save code to 
// examples addon folder in the user's directory.
if (GetUserPref("ScriptingSessionActive"))
	var ex_name 	= "ExMenuAddCallbackItem";
	var ex_subfolder 	= "Plugins";
	var ex_folder 	= "XSISDKDocExamples";
	var ex_langsuffix	= ".js";
	CreateAddonDirectories( InstallationPath(siUserPath), ex_folder );
	var fso = XSIFactory.CreateActiveXObject("Scripting.FileSystemObject");
	var filename = XSIUtils.BuildPath( 
		ex_name+ex_langsuffix );
	if (!fso.FileExists(filename))
		var f = fso.CreateTextFile ( filename );
		f.write( ExampleSourceCode() );

See Also

MenuItem MenuItem.Callback Definition Callbacks for Menus Simple Menu plug-in example