#include <stdio.h>
#include <stdlib.h>
#include <maya/M3dView.h>
#include <maya/MArgList.h>
#include <maya/MCursor.h>
#include <maya/MDagPath.h>
#include <maya/MEventMessage.h>
#include <maya/MFn.h>
#include <maya/MFnCamera.h>
#include <maya/MFnDistanceManip.h> 
#include <maya/MFnPlugin.h>
#include <maya/MFnTransform.h>
#include <maya/MGlobal.h>
#include <maya/MIOStream.h>
#include <maya/MItSelectionList.h>
#include <maya/MModelMessage.h>
#include <maya/MPxContext.h>
#include <maya/MPxContextCommand.h>
#include <maya/MPxManipContainer.h> 
#include <maya/MPxNode.h>
#include <maya/MPxSelectionContext.h>
#include <maya/MPxToolCommand.h>
#include <maya/MPlug.h>
#include <maya/MPoint.h>
#include <maya/MQuaternion.h>
#include <maya/MSelectionList.h>
#include <maya/MVector.h>
#include "rockingTransform2.h"
#include "customTriadManip.h"
#define     customAttributeString   "rockx"
MCallbackId cid1 = 0;
MCallbackId cid2 = 0;
static bool     isSetting = false;
static double       scaleFactor = 0.01;
static void eventCB(void * data);
#define     ATTR_CMD_NAME "customAttrToolCmd"
#define     DOIT        0
#define     UNDOIT      1
#define     REDOIT      2
{
public:
    customAttrCmd();
    virtual ~customAttrCmd(); 
    
public:
    static void* creator();
    void        setDelta(double d);
    void        setDragX() {dragX = true;}
private:
    double      delta;
    bool        dragX;
    void        parseDrag(int axis);
};
customAttrCmd::customAttrCmd( )
{
    setCommandString( ATTR_CMD_NAME );
    dragX = false;
}
customAttrCmd::~customAttrCmd()
{}
void* customAttrCmd::creator()
{
    return new customAttrCmd;
}
bool customAttrCmd::isUndoable() const
{
    return true;
}
void customAttrCmd::setDelta(double d)
{
    delta = d * scaleFactor;
}
{
    command.
addArg( commandString() );
    
    
    
}
{
    return action( DOIT );
}
{
    return action( UNDOIT );
}
{
    return action( REDOIT );
}
MStatus customAttrCmd::action( 
int flag )
 
{
    double d = delta;
    switch( flag )
    {
        case UNDOIT:    
            d = -d;
            break;
        case REDOIT:    
            break;
        case DOIT:      
            break;
        default:
            break;
    }
    
    
        
        
        for ( ; !iter.isDone(); iter.next() ) 
        {
            
            
            iter.getDagPath( mdagPath, mComponent );
                
                
                
                if (transFn.typeId() == rockingTransformNode::id)
                {
                    MPlug plg = transFn.findPlug(customAttributeString);
 
                    double val;
                }
                continue;
            }
        } 
    }
    else {
        cerr << "Error creating selection list iterator" << endl;
    }
}
{
public:
    customAttrManip();
    virtual ~customAttrManip();
    
    static void *   creator();
    void            updateManipLocations();
public:
};
MTypeId customAttrManip::id( 0x80025 );
 
customAttrManip::customAttrManip() 
{ 
    
    
}
customAttrManip::~customAttrManip() 
{
}
void *customAttrManip::creator()
{
     return new customAttrManip();
}
MStatus customAttrManip::initialize()
 
{ 
    return stat;
}
MStatus customAttrManip::createChildren()
 
{
    fManip = addDistanceManip("customtManip", "customPoint");
}
{
    return q;
}
MVector customAttrManip::nodeTranslation() const
 
{
}
void customAttrManip::updateManipLocations()
{
    freePointManipFn.setDirection(vecX);
    freePointManipFn.rotateBy(q);
}
{
    
    
    dagNodeFn.getPath(fNodePath);
    
    MPlug cPlug = nodeFn.findPlug(customAttributeString, &stat);
 
        distManipFn.connectToDistancePlug(cPlug);
    finishAddingManips();
    updateManipLocations();
    return stat;
}
#define MOVEHELPSTR     "Drag the distance manips to change values on custom attributes"
#define MOVETITLESTR    "customAttrManip"
{
public:
    customAttrCtx();
    customAttrManip * caManip;
private:
    short           startPos_x, endPos_x;
    short           startPos_y, endPos_y;
    double          delta;
    customAttrCmd * cmd;
};
void updateManipulators(void * data);
MCallbackId id1;
customAttrCtx::customAttrCtx()
{
    setTitleString(str);
}
void customAttrCtx::toolOnSetup(
MEvent &)
 
{
    setHelpString(str);
    updateManipulators(this);
                                     updateManipulators, 
                                     this, &status);
    if (!status) {
        cerr << "Model addCallback failed\n";
    }
}
void customAttrCtx::toolOffCleanup()
{
    if (!status) {
        cerr << "Model remove callback failed\n";
    }
}
{
    
    
    
    
    if ( !isSelecting() ) {
        {
            
            
            
            
            cmd = (customAttrCmd *)newToolCommand();
            cmd->setDelta(0.0);
            event.getPosition( startPos_x, startPos_y );
            
            
            unsigned int i;
                    "channelBox -q -selectedMainAttributes $gChannelBoxName", result);
            for (i=0; i<result.
length(); i++)
 
            {
                if (result[i] == customAttributeString)
                {
                    cmd->setDragX();
                    break;
                }
            }
        }
    }
    return stat;
}
{
    
    
        event.getPosition( endPos_x, endPos_y );
        
        
        
        cmd->undoIt();
        cmd->setDelta(endPos_x - startPos_x);
        stat = cmd->redoIt();
        view.refresh( true );
    }
    else
    return stat;
}
{
    
    
    
    if ( !isSelecting() ) {
        {
            event.getPosition( endPos_x, endPos_y );
            
            
            
            
            if ( abs(startPos_x - endPos_x) < 2 ) {
                delete cmd;
                view.refresh( true );
            }
            else {
                stat = cmd->finalize();
                view.refresh( true );
            }
        }
    }
    return stat;
}
void updateManipulators(void * data)
{
    
    
    customAttrCtx * ctxPtr = (customAttrCtx *) data;
    ctxPtr->deleteManipulators(); 
    
    
        for (; !iter.isDone(); iter.next()) {
            
            
            MString manipName (
"customAttrManip");
 
            ctxPtr->caManip = (customAttrManip *) customAttrManip::newManipulator(manipName, manipObject);
            if (NULL != ctxPtr->caManip) {
                iter.getDependNode(dependNode);
                ctxPtr->addManipulator(manipObject);
                dependNodeFn.findPlug(customAttributeString, &stat);
                    ctxPtr->deleteManipulators(); 
                    return;
                }
                ctxPtr->caManip->connectToDependNode(dependNode);
            } 
        }
    }
}
{
    return setHelpString(str);
}
#define CREATE_CTX_NAME "customAttrManipContext"
{
public:
    customAttrCtxCommand() {};
public:
    static void* creator();
};
{
    customAttrCtx *newC = new customAttrCtx();
    return newC;
}
void *customAttrCtxCommand::creator()
{
    return new customAttrCtxCommand;
}
{
    MFnPlugin plugin(obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    status = plugin.registerContextCommand(
            CREATE_CTX_NAME, &customAttrCtxCommand::creator,
            ATTR_CMD_NAME, &customAttrCmd::creator);
    if (!status) 
    {
        status.
perror(
"registerContextCommand");
        return status;
    }
    status = plugin.registerContextCommand(
            CREATE_TRIAD_CTX_NAME, &customTriadCtxCommand::creator);
    if (!status) 
    {
        status.
perror(
"registerContextCommand");
        return status;
    }
    
    
    
    const MString classification = 
"drawdb/geometry/transform/rockingTransform2";
 
    status = plugin.registerTransform(  "rockingTransform", 
                                        rockingTransformNode::id, 
                                        &rockingTransformNode::creator, 
                                        &rockingTransformNode::initialize,
                                        &rockingTransformMatrix::creator,
                                        rockingTransformMatrix::id,
                                        &classification);
    if (!status) {
        status.
perror(
"registerNode");
        return status;
    }
    status = plugin.registerNode("customAttrManip", customAttrManip::id, 
                                 &customAttrManip::creator, &customAttrManip::initialize,
    if (!status) 
    {
        status.
perror(
"registerManip");
        return status;
    }
    status = plugin.registerNode("customTriadManip", customTriadManip::id, 
                                 &customTriadManip::creator, &customTriadManip::initialize,
    if (!status) 
    {
        status.
perror(
"registerManip");
        return status;
    }
    
    return status;
}
{
    
    status = plugin.deregisterContextCommand(CREATE_CTX_NAME, ATTR_CMD_NAME);
    if (!status) {
        status.
perror(
"deregisterContextCommand");
        return status;
    }
    status = plugin.deregisterContextCommand(CREATE_TRIAD_CTX_NAME);
    if (!status) {
        status.
perror(
"deregisterContextCommand");
        return status;
    }
    status = plugin.deregisterNode(customAttrManip::id);
    if (!status) {
        status.
perror(
"deregisterManip");
        return status;
    }
    status = plugin.deregisterNode(customTriadManip::id);
    if (!status) {
        status.
perror(
"deregisterManip");
        return status;
    }
    status = plugin.deregisterNode( rockingTransformNode::id );
    if (!status) {
        status.
perror(
"deregisterNode");
        return status;
    }
    return status;
}
static void eventCB(void * data)
{
    
    if (isSetting)
        return;
    for (
unsigned int i=0; i<selList.
length(); i++)
 
    {
        {
            else
                continue;
            if (node.
typeId() == rockingTransformNode::id)
 
            {
                
                
                
                if ((curCtx == "dragAttrContext") || (curCtx == ""))
                {
                    
                    
                    unsigned int c;
                            "channelBox -q -selectedMainAttributes $gChannelBoxName", cboxAttrs);
                    for (c=0; c<cboxAttrs.
length(); c++)
 
                    {
                        if (cboxAttrs[c] == customAttributeString)
                        {
                            isSetting = true;
                            isSetting = false;
                            return;
                        }
                    }
                }
                if ((curCtx == "moveSuperContext") || (curCtx == "manipMoveContext") ||
                    (curCtx == ""))
                {
                    isSetting = true;
                    isSetting = false;
                    return;
                }
            }
        }
    }
}