nodeCreatedCBCmd/nodeCreatedCBCmd.cpp

nodeCreatedCBCmd/nodeCreatedCBCmd.cpp
//-
// ==========================================================================
// Copyright 2015 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+
// MEL Command: nodeCreatedCB
//
// Description:
// A simple plugin to register a mel proc to be called whenever a node is
// created. Registered Mel procedures should be declared to take a single
// string argument (the name of the added node).
//
// Warning: mel procedures registered with this method will be called
// whenever a node is added to the DG. This may cause problems
// in certain cases. For example: each time a reference is
// reloaded, each of its nodes is re-added to the DG.
//
// Flags:
// -register/-r string: registers a mel callback. There is no limit
// to the number of callbacks that can be registered.
//
// -unregister/-u string: unregister the specified callback.
//
// -filter/-f string: by default all registered callbacks will be called
// whenever any node is created. Using the filter flag
// you can indicate that callbacks should only be
// called when certain node types are created.
// To determine the type of a particular node see the
// 'objectType' and 'nodeType' commands.
//
// Note: only one filter can be in affect at a time,
// and it will be applied to all registered callbacks.
//
// -fullDagPath/-fdp: if this flag is specified when registering a
// callback, any dag node names passed into the mel
// procedure will include the full dag path.
//
// Note:
// The -register, -unregister, and -filter flags are mutually exclusive,
// only one should be used per command invocation.
//
// Important:
// Do not delete the node in your callback.
//
// Example Usage:
//
// // Appends the suffix '_ply' to all created mesh nodes
// //
// global proc myCB( string $node )
// {
// print("calling polyCB " + $node + "\n");
// string $type = `objectType $node`;
// if ( $type == "mesh" ) {
// rename $node ($node+"_ply");
// }
// }
//
// nodeCreatedCB -register "myCB";
//
#include "nodeCreatedCBCmd.h"
#include <maya/MFnPlugin.h>
#include <maya/MObject.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnDagNode.h>
#include <maya/MDGMessage.h>
#include <maya/MArgDatabase.h>
#include <maya/MSyntax.h>
#include <maya/MGlobal.h>
#define kRegisterFlagLong "-register"
#define kRegisterFlag "-r"
#define kUnregisterFlagLong "-unregister"
#define kUnregisterFlag "-u"
#define kFilterFlagLong "-filter"
#define kFilterFlag "-f"
#define kFullDagPathFlagLong "-fullDagPath"
#define kFullDagPathFlag "-fdp"
// The id of the API callback. The API callback must be removed when this
// plug-in is unloaded.
//
MCallbackId nodeCreatedCB::sId;
// The array of all registered Mel procedures.
//
MStringArray nodeCreatedCB::sMelProcs;
// Flags to indicate whether or not a mel procedure should be passed the
// short or long names of dag nodes.
//
MIntArray nodeCreatedCB::sFullDagPath;
MStatus nodeCreatedCB::doIt( const MArgList& args )
//
// Description:
// implements the MEL nodeCreatedCB command.
//
{
MArgDatabase argData( syntax(), args );
// Parse command flags.
//
if ( argData.isFlagSet( kRegisterFlag ) ) {
// Register a new procedure.
//
MString proc;
argData.getFlagArgument( kRegisterFlag, 0, proc );
stat = registerMelProc( proc, argData.isFlagSet( kFullDagPathFlag ) );
} else if ( argData.isFlagSet( kUnregisterFlag ) ) {
// Unregister a procedure.
//
MString proc;
argData.getFlagArgument( kUnregisterFlag, 0, proc );
stat = unregisterMelProc( proc );
} else if ( argData.isFlagSet( kFilterFlag ) ) {
// Change the filter being applied.
//
MString filter;
argData.getFlagArgument( kFilterFlag, 0, filter );
stat = changeFilter( filter );
}
if ( stat.error() ) {
}
return stat;
}
MStatus nodeCreatedCB::registerMelProc( MString melProc, bool fullDagPath )
//
// Register a Mel procedure to be called whenever a node is added.
//
{
if ( melProc.length() == 0 ) {
// Basic error checking. An empty string is not a valid mel procedure
// name
//
stat = MS::kFailure;
stat.perror("invalid mel callback: " + melProc);
return stat;
}
nodeCreatedCB::sMelProcs.append( melProc );
nodeCreatedCB::sFullDagPath.append( fullDagPath );
return stat;
}
MStatus nodeCreatedCB::unregisterMelProc( MString melProc )
//
// Unregister a Mel procedure.
//
{
int numProcs = nodeCreatedCB::sMelProcs.length();
for ( int i = 0; i < numProcs; i++ ) {
// Search the array of registered callbacks for melProc and
// remove it. If melProc exists more than once, only one instance
// of it will be removed.
//
if ( nodeCreatedCB::sMelProcs[i] == melProc ) {
nodeCreatedCB::sMelProcs.remove(i);
nodeCreatedCB::sFullDagPath.remove(i);
stat = MS::kSuccess;
break;
}
}
if ( !stat ) {
// Report an error if melProc was not found.
//
stat.perror(melProc + " is not a registered callback.");
}
return stat;
}
MStatus nodeCreatedCB::changeFilter( MString filter )
//
// Change the node type filter.
//
{
// We don't want to add sCallbackFunc more than once as that will cause
// all registered Mel procs to be called multiple times. So we first
// remove, then re-add the callback.
//
MDGMessage::removeCallback( nodeCreatedCB::sId );
nodeCreatedCB::sId = MDGMessage::addNodeAddedCallback( nodeCreatedCB::sCallbackFunc, filter );
return stat;
}
void nodeCreatedCB::sCallbackFunc( MObject& node, void* clientData )
//
// The API callback called whenever a node is added. This function handles
// calling all registered MEL callbacks and passing them the appropriate
// node name argument.
//
{
int numProcs = nodeCreatedCB::sMelProcs.length();
for ( int i = 0; i < numProcs; i++ ) {
MString melCmd = nodeCreatedCB::sMelProcs[i];
MString nodeName;
if ( nodeCreatedCB::sFullDagPath[i] &&
node.hasFn( MFn::kDagNode ) ) {
MFnDagNode dagObj( node );
nodeName = dagObj.fullPathName();
} else {
MFnDependencyNode dn( node );
nodeName = dn.name();
}
melCmd += " \"" + nodeName + "\"";
}
}
MSyntax nodeCreatedCB::newSyntax()
//
// Create the syntax object for the nodeCreateCB command.
//
{
MSyntax syntax;
syntax.addFlag( kRegisterFlag, kRegisterFlagLong, MSyntax::kString );
syntax.addFlag( kUnregisterFlag, kUnregisterFlagLong, MSyntax::kString );
syntax.addFlag( kFilterFlag, kFilterFlagLong, MSyntax::kString );
syntax.addFlag( kFullDagPathFlag, kFullDagPathFlagLong );
return syntax;
}
void* nodeCreatedCB::creator()
{
return new nodeCreatedCB;
}
MStatus initializePlugin( MObject obj )
{
MFnPlugin plugin( obj, PLUGIN_COMPANY, "6.0" );
MStatus stat;
stat = plugin.registerCommand( "nodeCreatedCB",
nodeCreatedCB::creator,
nodeCreatedCB::newSyntax );
if ( !stat )
stat.perror("registerCommand");
// add the API callback.
//
nodeCreatedCB::sId = MDGMessage::addNodeAddedCallback( nodeCreatedCB::sCallbackFunc );
return stat;
}
MStatus uninitializePlugin( MObject obj )
{
MFnPlugin plugin( obj );
MStatus stat;
stat = plugin.deregisterCommand( "nodeCreatedCB" );
if ( !stat )
stat.perror("deregisterCommand");
// Remove the API callback, necessary to prevent crashes.
//
MDGMessage::removeCallback( nodeCreatedCB::sId );
nodeCreatedCB::sMelProcs.clear();
nodeCreatedCB::sFullDagPath.clear();
return stat;
}