The Undo Mechanism and Transform Controllers
 
 
 

The following is a discussion of how a transform controller responds to movement of the mouse when the user is dragging and how the undo mechanism is involved.

When the user first clicks the mouse button down to begin a drag operation, the initial position of a node is stored. As each move takes place a new vector is calculated from the initial position to the new position of the mouse. This new calculation is used to update the position of the node. This is different than accumulating the new position from the previous position. The accumulation approach can introduce error. It may also be a problem for the user to get back to the initial position of the node if they move the mouse back to the initial position.

3ds Max uses the undo mechanism to avoid the problems associated with the accumulation approach. Every time the user moves the mouse 3ds Max re-computes the entire modification. So 3ds Max uses the original point and the current location of the mouse to compute the position. What this means internally is that every time the user moves the mouse the state at initial mouse down must be restored. To do this, when the mouse is initially pressed,theHold.Begin() is called to create a RestoreObj that stores the initial state. When the mouse is moved, theHold.Restore() is called. This restores the state to when theHold.Begin() was called.

As noted above, when the user initially mouses down, theHold.Begin() is called. Then at each mouse move theHold.Restore() is called. In iterative operations such as this it is often useful to set one of the flags of Animatable to indicate that a restore object is being held. In the example above, when the user first clicks down on the mouse the developer checks if theHold is holding and if it is calls theHold.Put() to register a restore object. Then the developer calls athe method Animatable::SetAFlag() with the value A_HELD. This sets the A_HELD bit of the Animatableaflag data member to indicate the restore object is held. Then on each iteration the bit is tested to see if it is set and if so another restore object is not registered. A single restore object can be restored over and other again.

When theHold. Accept() or theHold. Cancel() is called, the system calls a method of the restore object called EndHold(). The developer may then clear the A_HELD bit to indicate the restore object is no longer being held.

For sample code that does this see any of the transform controllers, for example, \MAXSDK\SAMPLES\CONTROLLERS\BOOLCTRL.CPP. Also, see the topics on Undo / Redo.