The <tool_body> of a mouse tool definition is made up of a sequence of tool clauses as follows:
Tool clauses define the components of a tool and can be one of two basic things:
Local variables, functions or structure definitions are variables, functions, and structures whose scope is the tool. The <tool_body> is compiled in its own local scope and the locals are only visible inside the scope of the tool. Tool locals are heap-based locals, which are slightly different from normal (stack-based) locals. Normal locals are visible in the current scope and have a lifetime of one execution of that scope. Heap-based locals are also visible only in the current scope, but have a lifetime equal to the lifetime of the top-level expression where they are defined. A tool’s locals are created the first time you execute the tool and are kept permanently in the heap (unless and until you redefine the tool). This means things like rollouts created in a tool that live beyond the simple execution of the tool can refer to these locals and the locals will still exist. Each time you execute a tool, its local variables are initialized to a value of undefined , or to their specified initialization value. For example, you can create a rollout in a tool, and the rollout’s event handlers can access the locals defined in the tool because the rollout is executing within the scope of the tool. You cannot access the tool’s locals from another utility or from Listener, because they are not executing within the scope of the tool. See Scope of Variables for more information.
Event handlers are special kinds of functions associated with particular events. Event handlers specify the processing you want to occur when a user clicks or moves a mouse, right-clicks, or starts or stops the tool. These actions generate named events and the optional event handler you supply for that event is called when the action occurs.
Formally, the syntax of a <tool_clause> is defined as follows:
<tool_clause> ::= <local_variable_decl> | <local_function_decl> | <local_struct_decl> | <event_handler>
A <local_variable_decl> , <local_function_decl> , and <local_struct_decl> are exactly the same as local variable, function, and structure definitions in MAXScript:
<local_variable_decl> ::= local <decl> { , <decl> }
<decl> ::= <name> [ = <expr> ] -- optional initial value
<local_function_decl> ::= [ mapped ](function | fn ) <name> { <argument> } = <expr>
<local_struct_decl> ::+ struct <name> ( <member> { , <member> } )
<member> ::= ( <name> [ = <expr> ] | <local_function_decl> )
Global variables cannot be declared as a tool clause, however they can be declared within event handler scripts. If you need to ensure a variable name references a global variable, declare the variable name as global immediately before defining the tool in your script.
When writing scripts, it is good programming practice to explicitly declare your local and global variables. Implicit declaration is provided as a short-hand, typically used when working in the Listener interactively or developing short scripts. When developing extended scripts, explicitly declaring variables can reduce errors and improve readability of the code. It is also recommend that you declare as local all variables unless you really want them to be global variables. The reasons for this are described in Scope of Variables.
Within the functions and event handlers of a tool, 13 pre-defined locals variables are always accessible. Each one holds a useful value relating to the mouse action that just occurred:
The current mouse position in viewport pixel coordinates.
The current mouse position projected on the active grid in world coordinates.
The distance in X, Y, and Z from the previous click point to the current click point in world coordinates.
The angles around the world X, Y, and Z axes from the previous click point to the current click point in world coordinates.
The current mouse position projected on the active grid in the coordinate system of the active grid. If the active grid is the home grid, the coordinate system is the home grid plane active in the current viewport (that is, the construction plane). See the discussion of grid versus world values below.
The distance in X, Y, and Z from the previous click point to the current click point in the coordinate system of the active grid. If the active grid is the home grid, the coordinate system is the home grid plane active in the current viewport (that is, the construction plane). See the discussion of grid versus world values below.
The angles around the world X, Y, and Z axes from the previous click point to the current click point in the coordinate system of the active grid. If the active grid is the home grid, the coordinate system is the home grid plane active in the current viewport (that is, the construction plane). See the discussion of grid versus world values below.
true if left mouse button was down.
true if middle mouse button was down.
true if right mouse button was down.
When a create mouse tool is used in a level 5 scripted plug-in, an additional local variable is accessible:
Provides read/write access to the transform of the node currently being created. This value is in the current grid coordinate system.
See Scripted Plug-ins for more information.
When writing SimpleObject scripted plug-ins, you should always use the gridPoint , gridDist , and gridAngle values rather than corresponding world values, as object-creation in SimpleObject scripted plug-ins is managed in the active grid coordinate system.
For gridDist , the .X and .Y components are the delta X and Y between the previous clicked point and the current mouse point in the plane of the current grid. The .Z component is a projection from the current Y screen coordinates onto a Z-vector (in the grid coordinate system) based at the last point clicked on the grid, such that the .Z value is the projected height up the Z-vector. For non-orthogonal viewports this is as expected, but for orthogonal viewports (in which you are always dragging in the XY plane of the grid), this is always the same as gridDist.y . If you are using the gridDist value to build the portion of an object on the grid, or determine the distance on the current grid from the last point, you want to use only the .X and .Y components.
If you are specifying the height off of the current grid, you would typically use the .Z component.
For worldDist , the behavior is similar to that for gridDist , however the projected component is dependent on the construction plane of the viewport. For the Top, Bottom, and non-orthogonal viewports, the projected height is contained in the .Z component. For Left and Right viewports, the projected height is contained in the .X component. For Front and Back viewports, the projected height is contained in the .Y component.
When you create a node in the 3ds Max user-interface, the local Z axis of the node is perpendicular to the construction plane. When you create a node using MAXScript, by default the local Z axis of the node points along the direction of the world Z axis. If you create a node in a tool (other than in a SimpleObject scripted plug-in), you must take into account the construction plane orientation if you want to duplicate 3ds Max’s behavior when creating a node. The easiest way to do this is to create the node in a coordsys grid context and specify the position of the node during creation in grid coordinate space. An example of this is shown in the following script.
An <event_handler> is a special function definition local to a tool that you provide to handle the processing you want to occur when a user clicks in a viewport, right-clicks, or starts or stops the tool. Each user action generates a named event and any event handler you supply for that event is called when the action occurs. The available event handlers are:
Called when the mouse moves prior to the first click.
Called for each mouse click, parameter arg contains the number of the click.
Called when the mouse moves anytime after the first click.
Called when the user right-clicks to cancel or presses the ESC key.
The <arg> parameter on each of the mouse event handlers lets you know which mouse click you are in. Mouse clicks are actually only the mouse click release, except for the initial mouse click. If you do a mouse click, drag, release, move, click, drag, and release, the on mousePoint event handler is called three times: the first click, the first release, and the second release, with <arg> values of 1, 2, and 3, respectively. The mouse click counter is incremented after processing the on mousePoint event handler, so the <arg> parameter for the mouseMove and mouseAbort event handlers specify the click count for the next mouse click. In the previous example, when you drag between the first click and first release, the <arg> value for a mouseMove event handler will have a value of 2. During the following move, click, and drag it will have a value of 3.
In 3ds Max 6 and higher, while running a mouse tool, if you click in a viewport where the construction plane is on edge, the tool will exit with a return value of #abort
The following script simply demonstrates when the various event handlers are called. Simply run this script and drag in the viewports. Right-click or press the ESC key to stop the tool’s execution.
All of the mouse action event handlers may return the special value #stop which causes the tool to stop. In the following mousePoint event handler example, the first click creates the box and the release (second click) terminates the tool.
The following script implements the following functions: on mouse click three spot lights are created at the mouse point. While holding the mouse button down, drag the mouse to position the classical key, back and fill light positions. During this drag, holding down the SHIFT key will flip the fill light side. Release the mouse button and move the mouse to change the elevation of the lights. Click the mouse button when the lights are at the correct height. The back light is raised 1.5 times the key light’s height, and the fill light is raised 0.75 times the key light’s height.
and then drag in one of the viewports.