/**@file naTangentTypeCmd.cpp

@brief v1.0.0 naTangentTypeCmd -step;   //make all the selected animation curves' keys stepped or smoothed  -smooth

@author Nathaniel O. Anozie (ogbonnawork at gmail dot com)

@bug no undo, limited error checking

@note modify at your own risk

@note goes over class declaration for maya command, initialize, unitialize,

@note I think studying the Maya docs is an excellent way to get familiar with the api

@note I looked at Maya's included api examples to understand parsing of user arguments,

initialize, unitialize, in        animInfoCmd.cpp

@note --fixed parameter bug, renamed file

*/

//Flags:

//

// -step <string>: whether to use step tangent

//

// -smooth <string>: whether to use smooth tangent

//

//

//before using MSimple.h

//now to use external functions we'll use MPxCommand

//but we also need something else for the intialization stuff MFnPlugin

#include <maya/MPxCommand.h>

#include <maya/MFnPlugin.h>

#include <maya/MGlobal.h>

//for parameter stuff we need this one

#include <maya/MArgList.h>

#include <maya/MItSelectionList.h>

//look in docs what library needed to link to

#include <maya/MItKeyframe.h>                

//this is a little tricky this is kindof like a MEL global variable but not visible everywhere

//notice no equal is needed

//define replaces anywhere we see na_Cmd with this name

#define na_Cmd "naTangentTypeCmd"

#define na_Author "Nathaniel Anozie"

/**this is very different from MEL

before I used DeclareSimpleCommand( naTangentTypeCmd, "Autodesk", "8.0");

to take care of all the class stuff, now i'm writing the stuff out.

Check out Maya's included animInfoCmd.cpp for a great example

*/

//public stuff

//

//constructor

//destructor

//do it

//creator

//

//private stuff

/*this slightly similar to MEL using proc, instead of global proc

*/

//here i'm just making something to parse arguments we need for

//setting tangent of keys

//

//parseArg

//

class naTangentTypeCmd : public MPxCommand

{

public:

                             naTangentTypeCmd();

        virtual            ~naTangentTypeCmd();

        virtual MStatus doIt ( const MArgList& args );

        static void* creator();

private:

        //notice the stat isnt const so we can edit it in our function

        int getTangentTypeIndexFromArg(const MArgList& args, MStatus& stat );

//this semicolon is a little tricky because functions

//in MEL or if's etc don't have them after parenthesis

};

///////////////////////////////////

//

//after doing the class declaration need to make sure

//

//constructor

//destructor

//creator

//before with declareSimple command didn't need to worry about these

//

void * naTangentTypeCmd::creator() { return new naTangentTypeCmd(); }

//pretty easy just write the command object twice kindof that

//tilde symbol

naTangentTypeCmd::~naTangentTypeCmd() {}

//if had some private variables -- coulbe be anything like doubles int whatever

//could set them to something in here

naTangentTypeCmd::naTangentTypeCmd() {}

//

//also need

//initializePlugin

//uninitializePlugin

MStatus initializePlugin( MObject obj )

{

        MFnPlugin plugin( obj, na_Author, "8.0", "Any");

        MStatus status = plugin.registerCommand(na_Cmd,

                                                                                    naTangentTypeCmd::creator );

    //heres another cool way to check error

    //like MEL's error( )

    //the MStatus class has this function perror

    if (!status) status.perror("registerCommand");

        return status;

}

MStatus uninitializePlugin( MObject obj )

{

        MFnPlugin plugin( obj );

        MStatus status = plugin.deregisterCommand(na_Cmd);

    if (!status) status.perror("deregisterCommand");

        return status;

}

///////////////////////////////////

//experimenting with a new function

//this i think is tricky because not using a variable but reference,

//i look at some of the example api files Maya came with to see how

//to parse argument list the animInfoCmd.cpp one

//

/**get the tangent type index to use given user arguments, basically I want rest of script

to know what the user selection was while keeping it separate from doIt

@param reference to user parameter (const MargList& arg)

@param reference to status code        (MStatus& stat)

@result 1 -- step, 2 -- smooth

*/

int naTangentTypeCmd::getTangentTypeIndexFromArg( const MArgList& arg, MStatus& stat)

{

        CHECK_MSTATUS(stat);

        int result = 1;

        stat = MS::kSuccess;

   

        //like MEL string

        MString parameterMessage = "Required single argument: -smooth ; - step; ";

   

        //like MEL's size using length

        if(arg.length() != 1){

            MGlobal::displayInfo( parameterMessage );

            stat.perror(parameterMessage);

            stat = MS::kFailure; }

        else{

            //like MEL, param = array[0]

            //

            MString param;

            param = arg.asString(0,&stat);

            MGlobal::displayInfo( param );

            //like MEL's strcmp but we'll use ==

            //dash needed

            if(param == "-smooth"){ result = 2;}

            else if(param == "-step"){ result = 1;  }

            else{

                //tell callee that something went wrong

                //by looking in docs for MStatus could find out these

                stat = MS::kFailure;

                stat.perror(parameterMessage);

            }

           

        }

   

        //neat were returning something similar to MEL's usual

        //int

        return result;

}

/**            

before with declareSimpleCommand wasn't using argument so i didn't have

arg in parameter, i need it here so i can pass it as a parameter to another

function

*/

MStatus naTangentTypeCmd::doIt( const MArgList& arg)

{

   

        MStatus stat = MS::kSuccess;

   

        //don't need anything before parseArg

        //because by writing out the class and putting this there

        //it can be found

        //neat how we can verify the function we wrote does what is needed

        //by checking

        int tangentTypeChoice = getTangentTypeIndexFromArg( arg, stat );

        CHECK_MSTATUS(stat);

   

   

   

        MSelectionList selList;

   

        MGlobal::getActiveSelectionList(selList);

   

        MItSelectionList curveIt(selList,MFn::kAnimCurve); //not in MGlobal

   

        while( !curveIt.isDone() )

        {

            MObject myCurve;

            curveIt.getDependNode(myCurve);

                     

            if(!myCurve.isNull())

            {

                //going from animator curve like animCurveTA to its keyframe

                MItKeyframe itKey(myCurve,&stat);

                //i'm not surre 100 percent whether this will make sure

                //we have ability to work on keys

                CHECK_MSTATUS(stat);

               

                if(stat == MS::kSuccess)

                {

                    while( !itKey.isDone() )

                    {

                        //trying to use MItKeyframe's method to make

                        //key stepped, looked in manual for this and found

                        //one that changes tangent type.

                        //

                        //In a way similar to MEL's global variables

                        //we can use an public variables

                        //here using a public variable stored somewhere else

                        //in MItKeyframe, the kTangentStep enum (similar to mel int)

                        //I needed to look in manual though because sometimes

                        //like for the MSelectionList the filter variable wasnt in that

                        //header it was somewhere else in a MFn place

                        //

                       

                        if( tangentTypeChoice == 1 ){

                            stat = itKey.setInTangentType(MItKeyframe::kTangentStep);

                            stat = itKey.setOutTangentType(MItKeyframe::kTangentStep);

                        }

                        else if( tangentTypeChoice == 2 ){

                           

                            stat = itKey.setInTangentType(MItKeyframe::kTangentSmooth);

                            stat = itKey.setOutTangentType(MItKeyframe::kTangentSmooth);

                            stat = itKey.setTangentsLocked(false);

                        }

                        else

                        {

                            stat.perror("Skipping");

                        }

                       

                        CHECK_MSTATUS(stat);

                       

                        itKey.next();

                    }

                   

                    //end is keyframe check  

                }

            }

           

            //increment selected

            curveIt.next();

           

        }

   

   

    return MS::kSuccess;

}