Saturday Snippet: Getting the object under the mouse in a context menu callback

For most context menus, the Target attribute contains both the selected objects (if any) and the object under the mouse.

def MyCustomMenu_Init( in_ctxt ):
    oMenu = in_ctxt.Source
    oMenu.Filter = "camera"
    oMenu.AddCallbackitem("Custom Camera Tool","MyCameraTool")
    return true

def MyCameraTool(in_ctxt):
    obj = in_ctxt.GetAttibute("Target")

I’m pretty sure I’m the one who dug up that info and put it in the docs (on the Menu Item Callback page). I did not, however, write this bit, which to my ear does not sound good at all:

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.

I prefer something more like this:

For context menus, the callback gets the currently selected objects and the object under the mouse. You can get these target objects from the Target attribute with Context.GetAttribute.

Scripting – Getting the target in a context menu callback

If you use AddCallbackItem to implement a contextual menu, then you can get the objects to which the context menu applies. A menu item callback gets a Context object from Softimage, and that Context contains a Target context attribute. Target specifies the selected objects, or the object under the mouse:

  • If more than one object is selected, then the Target attribute is a collection of all selected objects.
  • Otherwise, the Target attribute is a collection that contains just the object under the mouse.

Here’s a Python example of a context menu implemented with AddCallbackItem.

import win32com.client
from win32com.client import constants

null = None
false = 0
true = 1

def XSILoadPlugin( in_reg ):
	in_reg.Author = "blairs"
	in_reg.Name = "Test_CommandPlugin"
	in_reg.Major = 1
	in_reg.Minor = 0

	#RegistrationInsertionPoint - do not remove this line

	return true

def XSIUnloadPlugin( in_reg ):
	strPluginName = in_reg.Name
	Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
	return true

def Model_Context_Menu_Init( in_ctxt ):
	oMenu = in_ctxt.Source
	oMenu.AddCallbackItem( "Log target model", "SE_ContextCallback" )
	return true

def Object_Context_Menu_Init( in_ctxt ):
	oMenu = in_ctxt.Source
	oMenu.AddCallbackItem( "Log target object", "SE_ContextCallback" )
	return true
# Menu item callback
def SE_ContextCallback( in_ctxt ):
	target = in_ctxt.GetAttribute("Target")

	# Target attribute returns an XSICollection
	for o in target:
		Application.LogMessage( o.FullName )