Handling Mouse Procedures
 
 
 

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 creation procedure 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 is called every time the mouse is moved, giving the plug-in a chance to 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 Widget how-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.