3ds Max uses a callback mechanism to allow objects to be constructed using the mouse. To support mouse construction a plug-in must return an instance of a class derived from CreateMouseCallBack in its implementation of the function: BaseObject::GetCreateMouseCallBack().
In the Widget how-to sample the following call-back class is defined:
class WidgetCreateCallBack : public CreateMouseCallBack { IPoint2 sp0; // First point in screen coordinates Widget *ob; // Pointer to the object Point3 p0; // First point in world coordinates Point3 p1; // Second point in world coordinates. public: int proc(ViewExp *vpt, int msg, int point, int flags, IPoint2 m, Matrix3& mat); };
A plug-in's call-back class must override the CreateMouseCallBack::proc() method. This method will be called by 3ds Max until the creationprocedure is completed (e.g. returns CREATE_STOP)or abandoned (e.g. returns CREATE_ABORT).When the creation procedure starts the point parameter has the value 0. The method iscalled every time the mouse is moved, giving the plug-in a chanceto update itself in the viewport (e.g. through a call to ParamBlockDesc2::InvalidateUI()).Each time a new point is added manually by the user (e.g. byclicking the mouse) the point parameter is increased by one. The following is an example implementation used by the Widgethow-to sample:
int WidgetCreateCallBack::proc(ViewExp *vpt, int msg, int point, intflags, IPoint2 m, Matrix3& mat) { if (msg == MOUSE_POINT || msg == MOUSE_MOVE) { switch(point) { case 0: { // When point == 0 the message should only be a MOUSE_POINT DbgAssert(msg == MOUSE_POINT); // prevent snapping to self ob->suspendSnap = TRUE; // store screen coordinates sp0 = m; // store world coordinates p0 = vpt->SnapPoint(m, m, NULL, SNAP_IN_PLANE); // Update the matrix mat.SetTrans(p0); break; } case 1: { // store screen coordinates ob->suspendSnap = TRUE; // store world coordinates p1 = vpt->SnapPoint(m, m, NULL, SNAP_IN_PLANE); // Compute the size parameter by scaling using a constant float speedFactor = 24.0f; float theSize = (Length(p1 - p0) / speedFactor); // Set the overall size in parameter block ob->pblock2->SetValue(widget_size, ob->ip->GetTime(), theSize); // Invalidate the parameter block's UI // this triggers the mesh to be invalidated widget_param_blk.InvalidateUI(); break; } case 2: { // Indicate creation is complete return CREATE_STOP; } } } else { if (msg == MOUSE_ABORT) { // Indicate creation is abandoned return CREATE_ABORT; } } return TRUE; }
The most common messages that your proc method will handle: MOUSE_MOVE, MOUSE_POINT, and MOUSE_ABORT. A MOUSE_POINT message is generated when the user first starts the drawing process and every time the user releases the left mouse button, until the mouse drawing process is completed (i.e. your function returns TRUE) or the process is aborted (i.e. the user presses escape). A list of more messages can be found here.