moveTool.py

#-
# ==========================================================================
# Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
# rights reserved.
#
# The coded instructions, statements, computer programs, and/or related 
# material (collectively the "Data") in these files contain unpublished 
# information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
# licensors, which is protected by U.S. and Canadian federal copyright 
# law and by international treaties.
#
# The Data is provided for use exclusively by You. You have the right 
# to use, modify, and incorporate this Data into other products for 
# purposes authorized by the Autodesk software license agreement, 
# without fee.
#
# The copyright notices in the Software and this entire statement, 
# including the above license grant, this restriction and the 
# following disclaimer, must be included in all copies of the 
# Software, in whole or in part, and all derivative works of 
# the Software, unless such copies or derivative works are solely 
# in the form of machine-executable object code generated by a 
# source language processor.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
# AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
# WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
# NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
# PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
# TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
# BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
# DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
# AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
# OR PROBABILITY OF SUCH DAMAGES.
#
# ==========================================================================
#+

#
#       Creation Date:   2 October 2006
#
#       Description:
# 
#               moveTool.py
#
# Description:
#       Interactive tool for moving objects and components.
#
#       This plug-in will register the following two commands in Maya:
#               maya.cmds.spMoveToolCmd(x, y, z)
#       maya.cmds.spMoveToolContext()
#
#       Usage:
#       import maya
#       maya.cmds.loadPlugin("moveTool.py")
#       maya.cmds.spMoveToolContext("spMoveToolContext1")
#       shelfTopLevel = maya.mel.eval("global string $gShelfTopLevel;$temp = $gShelfTopLevel")
#       maya.cmds.setParent("%s|General" % shelfTopLevel)
#       maya.cmds.toolButton("spMoveTool1", cl="toolCluster", t="spMoveToolContext1", i1="moveTool.xpm") 
#
#       Remove UI objects with
#       maya.cmds.deleteUI("spMoveToolContext1")
#       maya.cmds.deleteUI("spMoveTool1")
#

import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.OpenMayaUI as OpenMayaUI
import sys, math

kPluginCmdName="spMoveToolCmd"
kPluginCtxName="spMoveToolContext"
kVectorEpsilon = 1.0e-3

# keep track of instances of MoveToolCmd to get around script limitation
# with proxy classes of base pointers that actually point to derived
# classes
kTrackingDictionary = {}

# command
class MoveToolCmd(OpenMayaMPx.MPxToolCommand):
        kDoIt, kUndoIt, kRedoIt = 0, 1, 2

        def __init__(self):
                OpenMayaMPx.MPxToolCommand.__init__(self)
                self.setCommandString(kPluginCmdName)
                self.__delta = OpenMaya.MVector()
                kTrackingDictionary[OpenMayaMPx.asHashable(self)] = self

        def __del__(self):
                del kTrackingDictionary[OpenMayaMPx.asHashable(self)]

        def doIt(self, args):
                argData = OpenMaya.MArgDatabase(self.syntax(), args)
                vector = OpenMaya.MVector(1.0, 0.0, 0.0)
                if args.length() == 1:
                        vector.x = args.asDouble(0)
                elif args.length == 2:
                        vector.x = args.asDouble(0)
                        vector.y = args.asDouble(1)
                elif args.length == 3:
                        vector.x = args.asDouble(0)
                        vector.y = args.asDouble(1)
                        vector.y = args.asDouble(2)
                self.__action(MoveToolCmd.kDoIt)

        def redoIt(self):
                self.__action(MoveToolCmd.kRedoIt)

        def undoIt(self):
                self.__action(MoveToolCmd.kUndoIt)

        def isUndoable(self):
                return True

        def finalize(self):
                """
                Command is finished, construct a string for the command
                for journalling.
                """
                command = OpenMaya.MArgList()
                command.addArg(self.commandString())
                command.addArg(self.__delta.x)
                command.addArg(self.__delta.y)
                command.addArg(self.__delta.z)

                # This call adds the command to the undo queue and sets
                # the journal string for the command.
                #
                try:
                        OpenMayaMPx.MPxToolCommand._doFinalize(self, command)
                except:
                        pass

        def setVector(self, x, y, z):
                self.__delta.x = x
                self.__delta.y = y
                self.__delta.z = z

        def __action(self, flag):
                """
                Do the actual work here to move the objects     by vector
                """
                vector = self.__delta
                if flag == MoveToolCmd.kUndoIt:
                        vector.x = -vector.x
                        vector.y = -vector.y
                        vector.z = -vector.z
                else:
                        # all other cases identical
                        pass

                # Create a selection list iterator
                #
                slist = OpenMaya.MSelectionList()
                OpenMaya.MGlobal.getActiveSelectionList(slist)
                sIter = OpenMaya.MItSelectionList(slist)

                mdagPath = OpenMaya.MDagPath()
                mComponent = OpenMaya.MObject()
                spc = OpenMaya.MSpace.kWorld

                # Translate all selected objects
                #
                while not sIter.isDone():
                        # Get path and possibly a component
                        #
                        sIter.getDagPath(mdagPath, mComponent)
                        try:
                                transFn = OpenMaya.MFnTransform(mdagPath)
                        except:
                                pass
                        else:
                                try:
                                        transFn.translateBy(vector, spc)
                                except:
                                        sys.stderr.write("Error doing translate on transform\n")
                                sIter.next()
                                continue

                        try:
                                cvFn = OpenMaya.MItCurveCV(mdagPath, mComponent)
                        except:
                                pass
                        else:
                                while not cvFn.isDone():
                                        cvFn.translateBy(vector, spc)
                                        cvFn.next()
                                cvFn.updateCurve()

                        try:
                                sCvFn = OpenMaya.MItSurfaceCV(mdagPath, mComponent, True)
                        except:
                                pass

                        else:
                                while not sCvFn.isDone():
                                        while not CvFn.isRowDone():
                                                sCvFn.translateBy(vector, spc)
                                                sCvFn.next()
                                        sCvFn.nextRow()
                                sCvFn.updateSurface()

                        try:
                                vtxFn = OpenMaya.MItMeshVertex(mdagPath, mComponent)
                        except:
                                pass
                        else:
                                while not vtxFn.isDone():
                                        vtxFn.translateBy(vector, spc)
                                        vtxFn.next()
                                vtxFn.updateSurface()

                        sIter.next()


class MoveContext(OpenMayaMPx.MPxSelectionContext):
        kTop, kFront, kSide, kPersp = 0, 1, 2, 3
        
        def __init__(self):
                OpenMayaMPx.MPxSelectionContext.__init__(self)
                self._setTitleString("moveTool")
                self.setImage("moveTool.xpm", OpenMayaMPx.MPxContext.kImage1)
                self.__currWin = 0
                self.__view = OpenMayaUI.M3dView()
                self.__startPos_x = 0
                self.__endPos_x = 0
                self.__startPos_y = 0
                self.__endPos_y = 0
                self.__cmd = None

        def toolOnSetup(self, event):
                self._setHelpString("drag to move selected object")

        def doPress(self, event):
                OpenMayaMPx.MPxSelectionContext.doPress(self, event)
                spc = OpenMaya.MSpace.kWorld
                
                # If we are not in selecting mode (i.e. an object has been selected)
                # then set up for the translation.
                #
                if not self._isSelecting():
                        argX = OpenMaya.MScriptUtil()
                        argX.createFromInt(0)
                        argXPtr = argX.asShortPtr()
                        argY = OpenMaya.MScriptUtil()
                        argY.createFromInt(0)
                        argYPtr = argY.asShortPtr()
                        event.getPosition(argXPtr, argYPtr)
                        self.__startPos_x = OpenMaya.MScriptUtil(argXPtr).asShort()
                        self.__startPos_y = OpenMaya.MScriptUtil(argYPtr).asShort()
                        self.__view = OpenMayaUI.M3dView.active3dView()

                        camera = OpenMaya.MDagPath()
                        self.__view.getCamera(camera)
                        fnCamera = OpenMaya.MFnCamera(camera)
                        upDir = fnCamera.upDirection(spc)
                        rightDir = fnCamera.rightDirection(spc)

                        # Determine the camera used in the current view
                        #
                        if fnCamera.isOrtho():
                                if upDir.isEquivalent(OpenMaya.MVector.zNegAxis, kVectorEpsilon):
                                        self.__currWin = MoveContext.kTop
                                elif rightDir.isEquivalent(OpenMaya.MVector.xAxis, kVectorEpsilon):
                                        self.__currWin = MoveContext.kFront
                                else:
                                        self.__currWin = MoveContext.kSide
                        else:
                                self.__currWin = MoveContext.kPersp

                        # Create an instance of the move tool command.
                        #
                        newCmd = self._newToolCommand()
                        self.__cmd = kTrackingDictionary.get(OpenMayaMPx.asHashable(newCmd), None)
                        self.__cmd.setVector(0.0, 0.0, 0.0)

        def doDrag(self, event):
                OpenMayaMPx.MPxSelectionContext.doDrag(self, event)

                # If we are not in selecting mode (i.e. an object has been selected)
                # then do the translation.
                #

                if not self._isSelecting():
                        argX = OpenMaya.MScriptUtil()
                        argX.createFromInt(0)
                        argXPtr = argX.asShortPtr()
                        argY = OpenMaya.MScriptUtil()
                        argY.createFromInt(0)
                        argYPtr = argY.asShortPtr()
                        event.getPosition(argXPtr, argYPtr)
                        self.__endPos_x = OpenMaya.MScriptUtil(argXPtr).asShort()
                        self.__endPos_y = OpenMaya.MScriptUtil(argYPtr).asShort()

                        startW = OpenMaya.MPoint()
                        endW = OpenMaya.MPoint()
                        vec = OpenMaya.MVector()
                        self.__view.viewToWorld(self.__startPos_x, self.__startPos_y, startW, vec)
                        self.__view.viewToWorld(self.__endPos_x, self.__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.
                        #
                        self.__cmd.undoIt()
                        if self.__currWin == MoveContext.kTop:
                                if downButton == OpenMayaUI.MEvent.kMiddleMouse:
                                        self.__cmd.setVector(endW.x - startW.x, 0.0, 0.0)
                                else:
                                        self.__cmd.setVector(endW.x - startW.x, 0.0, endW.z - startW.z)

                        elif self.__currWin == MoveContext.kFront:
                                if downButton == OpenMayaUI.MEvent.kMiddleMouse:

                                        self.__cmd.setVector(endW.x - startW.x, 0.0, 0.0)

                                else:

                                        self.__cmd.setVector(endW.x - startW.x, endW.y - startW.y, 0.0)

                        elif self.__currWin == MoveContext.kSide:
                                if downButton == OpenMayaUI.MEvent.kMiddleMouse:
                                        self.__cmd.setVector(0.0, 0.0, endW.z - startW.z)
                                else:
                                        self.__cmd.setVector(0.0, endW.y - startW.y, endW.z - startW.z)

                        self.__cmd.redoIt()
                        self.__view.refresh(True)

        def doRelease(self, event):
                OpenMayaMPx.MPxSelectionContext.doRelease(self, event)
                if not self._isSelecting():
                        argX = OpenMaya.MScriptUtil()
                        argX.createFromInt(0)
                        argXPtr = argX.asShortPtr()
                        argY = OpenMaya.MScriptUtil()
                        argY.createFromInt(0)
                        argYPtr = argY.asShortPtr()
                        event.getPosition(argXPtr, argYPtr)
                        self.__endPos_x = OpenMaya.MScriptUtil(argXPtr).asShort()
                        self.__endPos_y = OpenMaya.MScriptUtil(argYPtr).asShort()

                        # 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 (math.fabs(self.__startPos_x - self.__endPos_x) < 2 and 
                                        math.fabs(self.__startPos_y - self.__endPos_y) < 2):
                                self.__cmd = None
                                self.__view.refresh(True)
                        else:
                                self.__cmd.finalize()
                                self.__view.refresh(True)

        def doEnterRegion(self, event):
                """
                Print the tool description in the help line.
                """
                self._setHelpString("drag to move selected object")


#############################################################################


class MoveContextCommand(OpenMayaMPx.MPxContextCommand):
        def __init__(self):
                OpenMayaMPx.MPxContextCommand.__init__(self)

        def makeObj(self):
                return OpenMayaMPx.asMPxPtr(MoveContext())

def cmdCreator():
        return OpenMayaMPx.asMPxPtr(MoveToolCmd())

def ctxCmdCreator():
        return OpenMayaMPx.asMPxPtr(MoveContextCommand())

def syntaxCreator():
        syntax = OpenMaya.MSyntax()
        syntax.addArg(OpenMaya.MSyntax.kDouble)
        syntax.addArg(OpenMaya.MSyntax.kDouble)
        syntax.addArg(OpenMaya.MSyntax.kDouble)
        return syntax

# Initialize the script plug-in

def initializePlugin(mobject):
        mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any")
        try:
                mplugin.registerContextCommand(kPluginCtxName, ctxCmdCreator, kPluginCmdName, cmdCreator, syntaxCreator)
        except:
                sys.stderr.write("Failed to register context command: %s\n" % kPluginCtxName)
                raise

# Uninitialize the script plug-in
def uninitializePlugin(mobject):
        mplugin = OpenMayaMPx.MFnPlugin(mobject)
        try:
                mplugin.deregisterContextCommand(kPluginCtxName, kPluginCmdName)
        except:
                sys.stderr.write("Failed to deregister context command: %s\n" % kPluginCtxName)
                raise


Autodesk® Maya® 2009 © 1997-2008 Autodesk, Inc. All rights reserved. Generated with doxygen 1.5.6