API Guide > Manipulators >

# Manipulator Containers

You can create a manipulator container programmatically and add one or more base manipulators to the container. This approach involves the following steps:

1. Create a manipulator container class derived from MPxManipContainer.
2. Add the base manipulators to the manipulator container class.
3. Define associations between the manipulator and the attribute on the nodes.

The parent class of user-defined container manipulators is MPxManipContainer. There are a number of methods in MPxManipContainer that allow you to add a variety of base manipulators to the container. You also need to implement a number of methods in the custom manipulator.

The necessary methods are:

- creator method
- initialize method
- createChildren method
- connectToDependNode method.

You can also override the draw method to customize the way your container manipulator is drawn.

## creator method

The creator method needs to return a new instance of the manipulator, and it is registered in the initializePlugin() function with a call to the MFnPlugin::registerNode() method.

Note Because this method is static and registered, and not derived, the name of the method does not need to be creator, although by convention the name creator is typically used.

## initialize method

The initialize method performs any necessary initializations for the manipulator as well as calling the method in the parent class MPxManipContainer::initialize(). Similar to the creator method, the initialize method is static and registered rather than derived.

## createChildren method

The base manipulators are added to the manipulator container classes using the MPxManipContainer::createChildren() method.

For example, in the moveManip::createChildren() method:

    MStatus moveManip::createChildren()
    {
        ...

        fDistanceManip = addDistanceManip(manipName,
        distanceName);
        fFreePointManip = addFreePointTriadManip(pointManipName,
        pointName);

        ...

    }

This method is usually called after the custom manipulator container class is set up. The MPxManipContainer class provides a set of member functions to add individual base manipulators, most of them are named as addXYZManip, where XYZ represents the manipulator name. The function returns an MDagPath object representing the created base manipulator. Following is an example from the footPrintManip plug-in for adding distance manipulator to a custom manipulator container.

    MStatus footPrintLocatorManip::createChildren() {
        MStatus stat =MStatus::kSuccess;

        MString manipName("distanceManip");
        MString distanceName("distance");

        MPoint startPoint (0.0, 0.0, 0.0);
        MVector direction (0.0, 1.0, 0.0);
        fDistanceManip =addDistanceManip(manipName,distanceName);

        MFnDistanceManip distanceManipFn(fDistanceManip);
        distanceManipFn.setStartPoint(startPoint);
        distanceManipFn.setDirection(direction);

        return(stat);
    }

## connectToDependNode method

The connectToDependNode() method is where the association is made between the manipulator and the plug with which it will communicate. All the operations to set up communication between manipulators and plugs (including one-on-one association and conversion functions) must be put in this method. After mapping relationships between manipulators and plugs are set, there are two additional methods to be called. These methods are MPxManipContainer::finishAddingManips() and MPxManipContainer::connectToDependNode(), and must be called in that order. It is important to note that MPxManipContainer::finishAddingManips() must be called after all calls to connect to plugs have been made. Furthermore, finishAddingManips() must be called only once.

For example, in the moveManip::connectToDependNode() method:

    MStatus moveManip::connectToDependNode(const MObject &node)
    {
        ...
        distanceManipFn.connectToDistancePlug(syPlug);
        ...
        freePointTriadManipFn.connectToPointPlug(tPlug);
        ...
        finishAddingManips();
        ...
        MPxManipContainer::connectToDependNode(node);
        ...
    }

Note Although connectToDependNode() is a virtual method, you will usually be responsible for calling this method yourself when you are using the manipulator within a custom context. For more information, see Connect Manipulators to the Show Manipulator Tool.

The footPrintManip plug-in example demonstrates the following operations: creating a distance manipulator, applying MFnDistanceManip function set class on the created distance manipulator, setting up one-on-one association between plug and distance manipulator value, and setting up plugToManip conversion to set the manipulator start point position.

    MStatus footPrintLocatorManip::connectToDependNode (const MObject &node) {
        MStatus stat;

        // Get the DAG path
        MFnDagNode dagNodeFn(node);
        dagNodeFn.getPath(fNodePath);

        // Connect the plugs

        MFnDistanceManip distanceManipFn(fDistanceManip);
        MFnDependencyNode nodeFn(node);

        MPlug sizePlug =nodeFn.findPlug("size", &stat);
        if ( stat != MStatus::kFailure ) {
           distanceManipFn.connectToDistancePlug (sizePlug);
           unsigned startPointIndex =distanceManipFn.startPointIndex();
           addPlugToManipConversionCallback (startPointIndex,
           (plugToManipConversionCallback)&footPrintLocatorManip::startPointCallback);
           finishAddingManips();
           MPxManipContainer::connectToDependNode(node);
        }
        return(stat);
    }

## draw method

The draw method is an optional method which can be used to customize the drawing of a container manipulator. If you are overriding the draw method, you must first call MPxManipContainer::draw() to draw all the children.

For example, the moveManip::draw() method draws a label in addition to the base manipulators.

    void moveManip::draw(M3dView &view,
                         const MDagPath &path,
                         M3dView::DisplayStyle style,
                         M3dView::DispalyStatus status)
    {
        MPxManipContainer::draw(view, path, style, status);
        view.beginGL();
        MPoint textPos(0, 0, 0);
        char str[100];
        sprintf(str, "Stretch Me!");
        MString distanceText(str);
        view.drawText(distanceText, textPos, M3dView::kLeft);
        view.endGL();
    }

The shape and drawing of custom manipulators is restricted to base manipulators because the MPxManipContainer::draw() method only provides a M3dView parameter to add supplementary drawing to the manipulator. The custom manipulator’s shape is already decided by the combination of base manipulator shapes that are added to the current manipulator container. However, there are situations where you want to have more control over different perspectives of a manipulator. The MPxManipulatorNode class, which was introduced in Maya 2009, provides a new way to implement custom manipulators with custom OpenGL drawing code. It offers options for selecting components (activating different handles) in custom manipulators. This class can either work alone or work with the MPxManipContainer class.

The MPxManipulatorNode::draw() method is overridden to implement custom drawing. In OpenGL, drawing and picking are done together. There are several important methods like the following:

- glFirstHandle() – When drawing an OpenGL pickable component, a name uniquely representing the OpenGL component must be set. This method returns the unsigned integer value that represents the first available OpenGL handle to use. When one OpenGL component drawing is finished, the integer value can be incremented by one to represent the next OpenGL component.
- colorAndName() – This method is used to set the color of the OpenGL component that is being drawn next. It is also used to set the OpenGL name of the component so that picking is supported.

    void triadScaleManip::draw (M3dView &view, const MDagPath &path, M3dView::DisplayStyle style,
             M3dView::DisplayStatus status) {
        ……

        // Begin the drawing
        view.beginGL();

        // Place before you draw the manipulator component that can
        // be pickable.
        MGLuint glPickableItem;
        glFirstHandle(glPickableItem);

        // Top
        topName =glPickableItem;
        colorAndName(view, glPickableItem, true, mainColor());
        gGLFT->glBegin(GL_LINES);
        gGLFT->glVertex3fv(tl);
        gGLFT->glVertex3fv(tr);
        gGLFT->glEnd();

        // Right
        glPickableItem++;
        rightName =glPickableItem;
        colorAndName(view, glPickableItem, true, mainColor());
        gGLFT->glBegin(GL_LINES);
        gGLFT->glVertex3fv(tr);
        gGLFT->glVertex3fv(br);
        gGLFT->glEnd();

        // ...

        // End the drawing
        view.endGL();
    }

## Updating Plug Values on Nodes

You can use MPxManipulatorNode to update the plug values in the following ways:

- Implement Methods Related to Mouse Movement Event – There are three methods for mouse movement events: MPxManipulatorNode::doPress(), MPxManipulatorNode::doDrag(), and MPxManipulatorNode::doRelease(). These methods are called when the manipulator receives a corresponding mouse event such as mouse down, mouse drag, or mouse release. Algorithms can be implemented to update the plug values when these methods are called. For example, when doPress() is called, you can record the mouse position as the original position or when doDrag() is called, you can record the mouse movement (direction and distance).
- Connect to a Dependent Node – Follow these steps to connect to a dependent node.
  1. Call add*Value() in the postConstructor() of the manipulator node.
  2. Call conectPlugToValue() in connectToDependNode().
  3. Call set*Value() in one of the do*() functions.

  To connect plugs directly to manipulator values, the manipulator values must be first created on the manipulator. There are several add*Value() methods to add manipulator values of different types. The one-on-one association can be achieved by calling connectPlugToValue() method within MPxManipulatorNode::connectToDependNode(). In one of the do*() functions, which is triggered when the manipulator is receiving the corresponding mouse event, calling set*Value() sets the corresponding manipulator value that consequently sets the plug value.

## Registration/Deregistration

Because manipulator containers are derived from nodes, user-defined manipulators can be registered and deregistered like any other node, with the exception that the MPxNode::Type argument in MFnPlugin::registerNode() is set to MPxNode::kManipContainer instead of the default MPxNode::kDependNode.

For example, in moveToolManip.cpp:

    MStatus initializePlugin(MObject obj)
    {
            ...
            plugin.registerNode("moveManip",
            moveManip::id,
            &moveManip::creator,
            &moveManip::initialize,
            MPxNode::kManipContainer);
            ...
    }
    MStatus uninitializePlugin(MObject obj)
    {
        ...
        plugin.deregisterNode(moveManip::id);
        ...
    }