//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ //////////////////////////////////////////////////////////////////////// // // moveNumericTool.cc // // Description: // Interactive tool for moving an object. // This tool also accepts numeric input from the numeric input field. // // This plug-in will register the following two commands in Maya: // moveNumericToolCmd // moveNumericToolContext // //////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CHECKRESULT(stat,msg) \ if ( MS::kSuccess != stat ) { \ cerr << msg << endl; \ } #define kVectorEpsilon 1.0e-3 ///////////////////////////////////////////////////////////// // // The move command // // - this is a tool command which can be used in tool // contexts or in the MEL command window. // ///////////////////////////////////////////////////////////// #define MOVENAME "moveNumericToolCmd" #define DOIT 0 #define UNDOIT 1 #define REDOIT 2 class moveCmd : public MPxToolCommand { public: moveCmd(); virtual ~moveCmd(); MStatus doIt( const MArgList& args ); MStatus redoIt(); MStatus undoIt(); bool isUndoable() const; MStatus finalize(); public: static void* creator(); void setVector( double x, double y, double z ); static MStatus getVector( MVector &vec ); private: MVector delta; // the delta vectors MStatus action( int flag ); // do the work here }; moveCmd::moveCmd( ) { setCommandString( MOVENAME ); } moveCmd::~moveCmd() {} void* moveCmd::creator() { return new moveCmd; } bool moveCmd::isUndoable() const // // Description // Set this command to be undoable. // { return true; } void moveCmd::setVector( double x, double y, double z) { delta.x = x; delta.y = y; delta.z = z; } MStatus moveCmd::getVector( MVector &vec ) { MStatus stat; MSelectionList slist; MGlobal::getActiveSelectionList( slist ); MDagPath mDagPath; MObject mComponent; MSpace::Space spc = MSpace::kWorld; // Translate first selected object // if (slist.length() > 0) stat = slist.getDagPath(slist.length()-1, mDagPath, mComponent); else return MS::kFailure; if ( MS::kSuccess != stat ) return MS::kFailure; MFnTransform transFn( mDagPath, &stat ); if ( MS::kSuccess == stat ) { vec = transFn.translation( spc, &stat ); } return stat; } MStatus moveCmd::finalize() // // Description // Command is finished, construct a string for the command // for journalling. // { MArgList command; command.addArg( commandString() ); command.addArg( delta.x ); command.addArg( delta.y ); command.addArg( delta.z ); // This call adds the command to the undo queue and sets // the journal string for the command. // return MPxToolCommand::doFinalize( command ); } MStatus moveCmd::doIt( const MArgList& args ) // // Description // Test MItSelectionList class // { MStatus stat; MVector vector( 1.0, 0.0, 0.0 ); // default delta unsigned i = 0; switch ( args.length() ) // set arguments to vector { case 1: vector.x = args.asDouble( 0, &stat ); break; case 2: vector.x = args.asDouble( 0, &stat ); vector.y = args.asDouble( 1, &stat ); break; case 3: vector = args.asVector(i,3); break; case 0: default: break; } delta = vector; return action( DOIT ); } MStatus moveCmd::undoIt( ) // // Description // Undo last delta translation // { return action( UNDOIT ); } MStatus moveCmd::redoIt( ) // // Description // Redo last delta translation // { return action( REDOIT ); } MStatus moveCmd::action( int flag ) // // Description // Do the actual work here to move the objects by vector // { MStatus stat; MVector vector = delta; switch( flag ) { case UNDOIT: // undo vector.x = -vector.x; vector.y = -vector.y; vector.z = -vector.z; break; case REDOIT: // redo break; case DOIT: // do command break; default: break; } // Create a selection list iterator // MSelectionList slist; MGlobal::getActiveSelectionList( slist ); MDagPath mdagPath; // Item dag path MObject mComponent; // Current component MSpace::Space spc = MSpace::kWorld; // Translate first selected objects // if (slist.length() > 0) stat = slist.getDagPath(slist.length()-1, mdagPath, mComponent); else return MS::kFailure; if ( MS::kSuccess != stat ) return MS::kFailure; MFnTransform transFn( mdagPath, &stat ); if ( MS::kSuccess == stat ) { stat = transFn.translateBy( vector, spc ); CHECKRESULT(stat,"Error doing translate on transform"); } return MS::kSuccess; } ///////////////////////////////////////////////////////////// // // The moveNumericTool Context // // - tool contexts are custom event handlers. The selection // context class defaults to maya's selection mode and // allows you to override press/drag/release events. // ///////////////////////////////////////////////////////////// #define MOVEHELPSTR "drag to move selected object" #define MOVETITLESTR "moveNumericTool" #define TOP 0 #define FRONT 1 #define SIDE 2 #define PERSP 3 class moveNumericContext : public MPxSelectionContext { public: moveNumericContext(); virtual void toolOnSetup( MEvent & event ); virtual MStatus doPress( MEvent & event ); virtual MStatus doDrag( MEvent & event ); virtual MStatus doRelease( MEvent & event ); virtual MStatus doEnterRegion( MEvent & event ); virtual bool processNumericalInput( const MDoubleArray &values, const MIntArray &flags, bool isAbsolute ); virtual bool feedbackNumericalInput() const; virtual MSyntax::MArgType argTypeNumericalInput( unsigned index ) const; private: int currWin; MEvent::MouseButtonType downButton; M3dView view; short startPos_x, endPos_x, start_x, last_x; short startPos_y, endPos_y, start_y, last_y; moveCmd * cmd; }; moveNumericContext::moveNumericContext() { MString str( MOVETITLESTR ); setTitleString( str ); // Tell the context which XPM to use so the tool can properly // be a candidate for the 6th position on the mini-bar. setImage("moveNumericTool.xpm", MPxContext::kImage1 ); } void moveNumericContext::toolOnSetup( MEvent & ) { MString str( MOVEHELPSTR ); setHelpString( str ); } MStatus moveNumericContext::doPress( MEvent & event ) { MStatus stat = MPxSelectionContext::doPress( event ); MSpace::Space spc = MSpace::kWorld; // If we are not in selecting mode (i.e. an object has been selected) // then set up for the translation. // if ( !isSelecting() ) { event.getPosition( startPos_x, startPos_y ); view = M3dView::active3dView(); MDagPath camera; stat = view.getCamera( camera ); if ( stat != MS::kSuccess ) { cerr << "Error: M3dView::getCamera" << endl; return stat; } MFnCamera fnCamera( camera ); MVector upDir = fnCamera.upDirection( spc ); MVector rightDir = fnCamera.rightDirection( spc ); // Determine the camera used in the current view // if ( fnCamera.isOrtho() ) { if ( upDir.isEquivalent(MVector::zNegAxis,kVectorEpsilon) ) { currWin = TOP; } else if (rightDir.isEquivalent(MVector::xAxis,kVectorEpsilon)) { currWin = FRONT; } else { currWin = SIDE; } } else { currWin = PERSP; } // Create an instance of the move tool command. // cmd = (moveCmd*)newToolCommand(); cmd->setVector( 0.0, 0.0, 0.0 ); } feedbackNumericalInput(); return stat; } MStatus moveNumericContext::doDrag( MEvent & event ) { MStatus stat; stat = MPxSelectionContext::doDrag( event ); // If we are not in selecting mode (i.e. an object has been selected) // then do the translation. // if ( !isSelecting() ) { event.getPosition( endPos_x, endPos_y ); MPoint endW, startW; MVector vec; view.viewToWorld( startPos_x, startPos_y, startW, vec ); view.viewToWorld( endPos_x, endPos_y, endW, vec ); downButton = event.mouseButton(); // We reset the the move vector each time a drag event occurs // and then recalculate it based on the start position. // cmd->undoIt(); switch( currWin ) { case TOP: switch ( downButton ) { case MEvent::kMiddleMouse : cmd->setVector( endW.x - startW.x, 0.0, 0.0 ); break; case MEvent::kLeftMouse : default: cmd->setVector( endW.x - startW.x, 0.0, endW.z - startW.z ); break; } break; case FRONT: switch ( downButton ) { case MEvent::kMiddleMouse : cmd->setVector( endW.x - startW.x, 0.0, 0.0 ); break; case MEvent::kLeftMouse : default: cmd->setVector( endW.x - startW.x, endW.y - startW.y, 0.0 ); break; } break; case SIDE: switch ( downButton ) { case MEvent::kMiddleMouse : cmd->setVector( 0.0, 0.0, endW.z - startW.z ); break; case MEvent::kLeftMouse : default: cmd->setVector( 0.0, endW.y - startW.y, endW.z - startW.z ); break; } break; case PERSP: break; } stat = cmd->redoIt(); view.refresh( true ); } feedbackNumericalInput(); return stat; } MStatus moveNumericContext::doRelease( MEvent & event ) { MStatus stat = MPxSelectionContext::doRelease( event ); if ( !isSelecting() ) { event.getPosition( endPos_x, endPos_y ); // Delete the move command if we have moved less then 2 pixels // otherwise call finalize to set up the journal and add the // command to the undo queue. // if (abs(startPos_x - endPos_x) < 2 && abs(startPos_y - endPos_y) < 2) { delete cmd; view.refresh( true ); } else { stat = cmd->finalize(); view.refresh( true ); } } feedbackNumericalInput(); return stat; } MStatus moveNumericContext::doEnterRegion( MEvent & /*event*/ ) // // Print the tool description in the help line. // { MString str( MOVEHELPSTR ); return setHelpString( str ); } bool moveNumericContext::processNumericalInput ( const MDoubleArray &values, const MIntArray &flags, bool isAbsolute ) { unsigned valueLength = values.length(); cmd = (moveCmd *) newToolCommand(); MVector vec; /* MStatus stat = */ moveCmd::getVector(vec); if (isAbsolute) { MVector absoluteDelta; if (ignoreEntry(flags, 0) || (valueLength < 1)) absoluteDelta.x = 0; else absoluteDelta.x = values[0] - vec.x; if (ignoreEntry(flags, 1) || (valueLength < 2)) absoluteDelta.y = 0; else absoluteDelta.y = values[1] - vec.y; if (ignoreEntry(flags, 2) || (valueLength < 3)) absoluteDelta.z = 0; else absoluteDelta.z = values[2] - vec.z; cmd->setVector(absoluteDelta.x, absoluteDelta.y, absoluteDelta.z); } else { MVector relativeDelta; if (ignoreEntry(flags, 0) || (valueLength < 1)) relativeDelta.x = 0; else relativeDelta.x = values[0]; if (ignoreEntry(flags, 1) || (valueLength < 2)) relativeDelta.y = 0; else relativeDelta.y = values[1]; if (ignoreEntry(flags, 2) || (valueLength < 3)) relativeDelta.z = 0; else relativeDelta.z = values[2]; cmd->setVector(relativeDelta.x, relativeDelta.y, relativeDelta.z); } cmd->redoIt(); cmd->finalize(); feedbackNumericalInput(); return true; } bool moveNumericContext::feedbackNumericalInput() const { MFeedbackLine::setTitle("moveNumericTool"); MFeedbackLine::setFormat("^6.3f ^6.3f ^6.3f"); MVector vec; /* MStatus stat = */ moveCmd::getVector(vec); MFeedbackLine::setValue(0, vec.x); MFeedbackLine::setValue(1, vec.y); MFeedbackLine::setValue(2, vec.z); return true; } MSyntax::MArgType moveNumericContext::argTypeNumericalInput(unsigned /*index*/) const { return MSyntax::kDistance; } ///////////////////////////////////////////////////////////// // // Context creation command // // This is the command that will be used to create instances // of our context. // ///////////////////////////////////////////////////////////// #define CREATE_CTX_NAME "moveNumericToolContext" class moveNumericContextCommand : public MPxContextCommand { public: moveNumericContextCommand() {}; virtual MPxContext * makeObj(); public: static void* creator(); }; MPxContext * moveNumericContextCommand::makeObj() { return new moveNumericContext(); } void * moveNumericContextCommand::creator() { return new moveNumericContextCommand; } /////////////////////////////////////////////////////////////////////// // // The following routines are used to register/unregister // the commands we are creating within Maya // /////////////////////////////////////////////////////////////////////// MStatus initializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin( obj, "Alias", "3.0", "Any" ); status = plugin.registerContextCommand(CREATE_CTX_NAME, &moveNumericContextCommand::creator, MOVENAME, &moveCmd::creator); if (!status) { status.perror("registerContextCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterContextCommand( CREATE_CTX_NAME, MOVENAME ); if (!status) { status.perror("deregisterContextCommand"); return status; } return status; }