diff options
Diffstat (limited to 'Core/Scripts/System/ART_RigModule.py')
| -rw-r--r-- | Core/Scripts/System/ART_RigModule.py | 3012 |
1 files changed, 3012 insertions, 0 deletions
diff --git a/Core/Scripts/System/ART_RigModule.py b/Core/Scripts/System/ART_RigModule.py new file mode 100644 index 0000000..fe0f385 --- /dev/null +++ b/Core/Scripts/System/ART_RigModule.py @@ -0,0 +1,3012 @@ +""" +Author: Jeremy Ernst + + This is the base class from which all modules are created. When creating a new module, + your module class should inherit from this base class. Example: + +| class ART_Head(ART_RigModule) + + In the __init__ of your module class, you will want to also run the base class __init__ + at the end of your module class __init__: + +| ART_RigModule.__init__(self, "ART_Head_Module", "ART_Head", moduleUserName) + + This module has two file attributes set by default. Your module class will need many more + file attributes set. Please see another module as an example. + +######## +Contents +######## + +| **Module Creation Functions:** +| :func:`addAttributes <System.ART_RigModule.ART_RigModule.addAttributes>` +| :func:`buildNetwork <System.ART_RigModule.ART_RigModule.buildNetwork>` +| :func:`createMirrorModule <System.ART_RigModule.ART_RigModule.createMirrorModule>` +| :func:`jointMover_Build <System.ART_RigModule.ART_RigModule.jointMover_Build>` +| :func:`skeletonSettings_UI <System.ART_RigModule.ART_RigModule.skeletonSettings_UI>` +| +| **Module Update Functions:** +| :func:`applyModuleChanges <System.ART_RigModule.ART_RigModule.applyModuleChanges>` +| :func:`checkForDependencies <System.ART_RigModule.ART_RigModule.checkForDependencies>` +| :func:`deleteModule <System.ART_RigModule.ART_RigModule.deleteModule>` +| +| **Module Settings and Interface Functions:** +| :func:`changeModuleName <System.ART_RigModule.ART_RigModule.changeModuleName>` +| :func:`changeModuleParent <System.ART_RigModule.ART_RigModule.changeModuleParent>` +| :func:`copySettings <System.ART_RigModule.ART_RigModule.copySettings>` +| :func:`pasteSettings <System.ART_RigModule.ART_RigModule.pasteSettings>` +| :func:`resetSettings <System.ART_RigModule.ART_RigModule.resetSettings>` +| :func:`createContextMenu <System.ART_RigModule.ART_RigModule.createContextMenu>` +| :func:`createMirrorOfModule_UI <System.ART_RigModule.ART_RigModule.createMirrorOfModule_UI>` +| :func:`createScriptJob <System.ART_RigModule.ART_RigModule.createScriptJob>` +| :func:`mirrorTransformations <System.ART_RigModule.ART_RigModule.mirrorTransformations>` +| :func:`mirrorTransformations_Custom <System.ART_RigModule.ART_RigModule.mirrorTransformations_Custom>` +| :func:`resetTransforms <System.ART_RigModule.ART_RigModule.resetTransforms>` +| :func:`setMirrorModule <System.ART_RigModule.ART_RigModule.setMirrorModule>` +| :func:`updateBoneCount <System.ART_RigModule.ART_RigModule.updateBoneCount>` +| :func:`updatePreview <System.ART_RigModule.ART_RigModule.updatePreview>` +| :func:`updateSettingsUI <System.ART_RigModule.ART_RigModule.updateSettingsUI>` +| +| **Module Joint Mover Functions:** +| :func:`addJointMoverToOutliner <System.ART_RigModule.ART_RigModule.addJointMoverToOutliner>` +| :func:`aimMode <System.ART_RigModule.ART_RigModule.aimMode>` +| :func:`aimMode_Setup <System.ART_RigModule.ART_RigModule.aimMode_Setup>` +| :func:`bakeOffsets <System.ART_RigModule.ART_RigModule.bakeOffsets>` +| :func:`createGlobalMoverButton <System.ART_RigModule.ART_RigModule.createGlobalMoverButton>` +| :func:`createMeshMoverButton <System.ART_RigModule.ART_RigModule.createMeshMoverButton>` +| :func:`createOffsetMoverButton <System.ART_RigModule.ART_RigModule.createOffsetMoverButton>` +| :func:`pinModule <System.ART_RigModule.ART_RigModule.pinModule>` +| :func:`selectMover <System.ART_RigModule.ART_RigModule.selectMover>` +| :func:`selectScriptJob <System.ART_RigModule.ART_RigModule.selectScriptJob>` +| :func:`toggleShapeVis <System.ART_RigModule.ART_RigModule.toggleShapeVis>` +| :func:`updateOutliner <System.ART_RigModule.ART_RigModule.updateOutliner>` +| +| **Module Publish Functions:** +| :func:`cleanUpRigPose <System.ART_RigModule.ART_RigModule.cleanUpRigPose>` +| :func:`createRigPoseSliderForJoint <System.ART_RigModule.ART_RigModule.createRigPoseSliderForJoint>` +| :func:`getReferencePose <System.ART_RigModule.ART_RigModule.getReferencePose>` +| :func:`matchModelPose <System.ART_RigModule.ART_RigModule.matchModelPose>` +| :func:`mirrorTransformations_RigPose <System.ART_RigModule.ART_RigModule.mirrorTransformations_RigPose>` +| :func:`resetRigPose <System.ART_RigModule.ART_RigModule.resetRigPose>` +| :func:`resetRigPose_Part <System.ART_RigModule.ART_RigModule.resetRigPose_Part>` +| :func:`rigPose_UI <System.ART_RigModule.ART_RigModule.rigPose_UI>` +| :func:`setPosePercentage <System.ART_RigModule.ART_RigModule.setPosePercentage>` +| :func:`setPosePercentage_Part <System.ART_RigModule.ART_RigModule.setPosePercentage_Part>` +| :func:`setReferencePose <System.ART_RigModule.ART_RigModule.setReferencePose>` +| :func:`setReferencePoseSlider <System.ART_RigModule.ART_RigModule.setReferencePoseSlider>` +| :func:`setSkeletonPose <System.ART_RigModule.ART_RigModule.setSkeletonPose>` +| :func:`setupForRigPose <System.ART_RigModule.ART_RigModule.setupForRigPose>` +| :func:`setupModelPoseForRig <System.ART_RigModule.ART_RigModule.setupModelPoseForRig>` +| :func:`skinProxyGeo <System.ART_RigModule.ART_RigModule.skinProxyGeo>` +| :func:`updateRigPose <System.ART_RigModule.ART_RigModule.updateRigPose>` +| +| **Module Rig Functions** +| :func:`buildRig <System.ART_RigModule.ART_RigModule.buildRig>` +| :func:`buildRigCustom <System.ART_RigModule.ART_RigModule.buildRigCustom>` +| :func:`deleteRig <System.ART_RigModule.ART_RigModule.deleteRig>` +| :func:`getControls <System.ART_RigModule.ART_RigModule.getControls>` +| :func:`importFBX <System.ART_RigModule.ART_RigModule.importFBX>` +| :func:`importFBX_pre <System.ART_RigModule.ART_RigModule.importFBX_pre>` +| :func:`resetRigControls <System.ART_RigModule.ART_RigModule.resetRigControls>` +| :func:`selectRigControls <System.ART_RigModule.ART_RigModule.selectRigControls>` +| :func:`selectionScriptJob_animUI <System.ART_RigModule.ART_RigModule.selectionScriptJob_animUI>` +| +| **Module Utility Functions** +| :func:`getAllModules <System.ART_RigModule.ART_RigModule.getAllModules>` +| :func:`getModules <System.ART_RigModule.ART_RigModule.getModules>` +| :func:`removeSkeletalConstraints <System.ART_RigModule.ART_RigModule.removeSkeletalConstraints>` +| :func:`returnCreatedJoints <System.ART_RigModule.ART_RigModule.returnCreatedJoints>` +| :func:`returnJointMovers <System.ART_RigModule.ART_RigModule.returnJointMovers>` +| :func:`returnMirrorModuleInst <System.ART_RigModule.ART_RigModule.returnMirrorModuleInst>` +| :func:`returnNetworkNode <System.ART_RigModule.ART_RigModule.returnNetworkNode>` +| :func:`returnPrefixSuffix <System.ART_RigModule.ART_RigModule.returnPrefixSuffix>` +| :func:`returnRigNetworkNode <System.ART_RigModule.ART_RigModule.returnRigNetworkNode>` +| +| +######### +Class +######### +""" + +# file imports +import json +import os +import traceback +from functools import partial + +import System.interfaceUtils as interfaceUtils +import System.riggingUtils as riggingUtils +import System.utils as utils +import System.mathUtils as mathUtils +import maya.cmds as cmds +import maya.mel as mel +from ThirdParty.Qt import QtGui, QtCore, QtWidgets + +# file attributes +fbxImport = ["None", "FK"] +matchData = [False, None] + + +class ART_RigModule(): + def __init__(self, moduleName, moduleType, userCreatedName): + """Initiate the class, taking in the instance to the interface and the user specified name. + + :param moduleName: This is the base name of the module, specified in the rig module. + :param moduleType: This is the name of the module to create (the module class). + :param userCreatedName: This is the name specified by the user on module creation. + + Instantiate the following class variables as well: + * **self.modName:** Take the passed in moduleName and make it a class var + * **self.moduleType:** Take the passed in moduleType and make it a class var + * **self.rootMod:** The network node of the entire character asset + * **self.name:** The user created name (prefix + baseName + suffix) passed in + * **self.originalName:** Also the user created name, but we want to store what the original name + was on creation, as the user can rename the module later. This will allow us to make the link between + what the module's original name was and what the new name is. + * **self.outlinerControls:** A list of the outliner controls created when adding module joint movers to + the outliner. + + Also, read the QSettings to find out where needed paths are. + """ + + # set class variables + self.modName = moduleName + self.moduleType = moduleType + self.rootMod = None + self.name = userCreatedName + self.originalName = userCreatedName + self.outlinerControls = [] + self.controlTypes = [] + + # get the directory path of the tools + settings = QtCore.QSettings("Epic Games", "ARTv2") + self.toolsPath = settings.value("toolsPath") + self.iconsPath = settings.value("iconPath") + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def buildNetwork(self): + """ + Build the network node for the module which will store all information needed by the module. + Then, call on addAttributes to add the required module attributes to the network node. + """ + + # create the network node for our module + self.networkNode = cmds.createNode("network", name=self.modName) + + # create attributes + self.addAttributes() + + return self.networkNode + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def addAttributes(self): + """ + Add attributes to the network node that all modules need. + """ + + if self.moduleType == None: + # add attributes specific to this module + cmds.addAttr(self.networkNode, sn="rigModules", at="message") + + else: + # add a rigging message attribute + cmds.addAttr(self.networkNode, sn="parent", at="message") + + # add a module type attribute + cmds.addAttr(self.networkNode, sn="moduleType", dt="string", keyable=False) + cmds.setAttr(self.networkNode + ".moduleType", self.moduleType, type="string", lock=True) + + # and a module name attribute (used for skeleton settings UI groupbox label) + cmds.addAttr(self.networkNode, sn="moduleName", dt="string", keyable=False) + cmds.setAttr(self.networkNode + ".moduleName", self.name, type="string", lock=True) + + # add attr for parent module that user specfies + cmds.addAttr(self.networkNode, sn="parentModuleBone", dt="string", keyable=False) + + # add attr for mirror module that user specfies + cmds.addAttr(self.networkNode, sn="mirrorModule", dt="string", keyable=False) + + cmds.addAttr(self.networkNode, sn="pinned", at="bool", keyable=False) + cmds.setAttr(self.networkNode + ".pinned", False, lock=True) + + # connect rigModule to root module node + self.rootMod = self.getModules + if self.rootMod != None: + cmds.connectAttr(self.rootMod + ".rigModules", self.networkNode + ".parent") + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def skeletonSettings_UI(self, name, width, height, checkable): + """ + Build the framework for the skeleton settings that all modules need. + + :param name: user given name of module (prefix + base_name + suffix) + :param width: width of the skeleton settings groupBox. 335 usually + :param height: height of the skeleton settings groupBox. + :param checkable: Whether or not the groupBox can be collapsed. + """ + + # add the groupbox for this module with the module name and module settings + self.groupBox = QtWidgets.QGroupBox(name) + self.groupBox.setGeometry(QtCore.QRect(0, 0, width, height)) + self.groupBox.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)) + + if not checkable: + self.groupBox.setMinimumSize(QtCore.QSize(width, height)) + + if checkable: + self.groupBox.setMinimumSize(QtCore.QSize(width, 0)) + + self.groupBox.setMaximumSize(QtCore.QSize(width, height)) + self.groupBox.setFlat(True) + self.groupBox.setCheckable(checkable) + + self.lockButton = QtWidgets.QPushButton() + self.lockButton.setMinimumSize(QtCore.QSize(20, 20)) + self.lockButton.setMaximumSize(QtCore.QSize(20, 20)) + + # load style sheet file + styleSheetFile = utils.returnNicePath(self.toolsPath, + "Core/Scripts/Interfaces/StyleSheets/skeletonSettings.qss") + f = open(styleSheetFile, "r") + style = f.read() + f.close() + + self.groupBox.setStyleSheet(style) + + # set properties for filtering later + self.groupBox.setObjectName(name) + self.groupBox.setProperty("name", name) + + # set context menu policy on groupbox + self.groupBox.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + self.groupBox.customContextMenuRequested.connect(self.createContextMenu) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def changeModuleName(self, baseName, moduleInst, rigUiInst): + """ + Launch the interface that allows users to change the module name. + + :param baseName: The module base name (head, torso, leg, etc) + :param moduleInst: The specific instance of the module + :param rigUiInst: The instance of the rig creator interface. + + This will call on a separate class in Core/Interfaces called ART_ChangeModuleNameUI.py + """ + + # get prefix/suffix + name = self.groupBox.title() + prefix = name.partition(baseName)[0] + suffix = name.partition(baseName)[2] + + # when pressing the change name button on the skeleton settings UI (if it exists): + + # delete the UI if it already exists + mayaWindow = interfaceUtils.getMainWindow() + mayaWindow = mayaWindow.objectName() + if cmds.window(mayaWindow + "|pyArtChangeModuleNameUi", q=True, exists=True): + cmds.deleteUI(mayaWindow + "|pyArtChangeModuleNameUi") + + # launch a UI for prefix/suffix/preview again + import Interfaces.ART_ChangeModuleNameUI as ART_ChangeModuleNameUI + reload(ART_ChangeModuleNameUI) + inst = ART_ChangeModuleNameUI.ART_ChangeModuleName_UI(baseName, moduleInst, rigUiInst, prefix, suffix, + interfaceUtils.getMainWindow()) + inst.show() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def changeModuleParent(self, moduleInst, rigUiInst): + """ + Launch the interface that allows users to change the module's parent bone. + + :param moduleInst: The specific instance of the module + :param rigUiInst: The instance of the rig creator interface. + + This will call on a separate class in Core/Interfaces called ART_ChangeModuleParentUI.py + """ + + # get current parent value + currentParent = self.currentParent.text() + + # when pressing the change parent button on the skeleton settings UI (if it exists): + + # delete the UI if it already exists + mayaWindow = interfaceUtils.getMainWindow() + mayaWindow = mayaWindow.objectName() + if cmds.window(mayaWindow + "|pyArtChangeModuleParentUi", q=True, exists=True): + cmds.deleteUI(mayaWindow + "|pyArtChangeModuleParentUi") + + # launch a UI for prefix/suffix/preview again + import Interfaces.ART_ChangeModuleParentUI as ART_ChangeModuleParentUI + reload(ART_ChangeModuleParentUI) + inst = ART_ChangeModuleParentUI.ART_ChangeModuleParent_UI(currentParent, moduleInst, rigUiInst, + interfaceUtils.getMainWindow()) + inst.show() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setMirrorModule(self, moduleInst, rigUiInst): + """ + Launch the interface that allows users to change the module's mirror module. + Meaning, the module that is linked as a mirror of this module. Only modules of the same + type can be linked as mirrors. + + :param moduleInst: The specific instance of the module + :param rigUiInst: The instance of the rig creator interface. + + This will call on a separate class in Core/Interfaces called ART_SetMirrorModuleUI.py + """ + + # delete the UI if it already exists + mayaWindow = interfaceUtils.getMainWindow() + mayaWindow = mayaWindow.objectName() + if cmds.window(mayaWindow + "|pyArtSetMirrorModuleUi", q=True, exists=True): + cmds.deleteUI(mayaWindow + "|pyArtSetMirrorModuleUi") + + # launch a UI for prefix/suffix/preview again + import Interfaces.ART_SetMirrorModuleUI as ART_SetMirrorModuleUI + reload(ART_SetMirrorModuleUI) + inst = ART_SetMirrorModuleUI.ART_SetMirrorModule_UI(moduleInst, rigUiInst, interfaceUtils.getMainWindow()) + inst.show() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def jointMover_Build(self, path): + """ + Import the joint mover file with the given path. + + After importing the module's joint mover file, rename imported nodes to use module name. + Then, assign existing matching materials to joint mover proxy geometry, deleting the imported + materials if they were duplicates. Then parent into the main JointMover group. Lastly, hook up + global scaling on the joint movers. + + + :param path: Path of joint mover file to import + """ + + # get the full path for the joint mover file + fullPath = os.path.join(self.toolsPath, path) + + # import the file + if os.path.exists(fullPath): + nodes = cmds.file(fullPath, i=True, iv=True, type="mayaAscii", rnn=True) + validTypes = ["transform", "joint", "ikHandle"] + + # loop through returned nodes from import, and find the mover_grp, renaming it and all + # children to have user specified name as prefix + for node in nodes: + if node.find("|mover_grp") == 0: + children = cmds.listRelatives(node, allDescendents=True, type="transform") + moverGrp = node.partition("|")[2] + movers = [moverGrp] + + for child in children: + try: + if cmds.nodeType(child) in validTypes: + movers.append(child) + except Exception, e: + print e + + for mover in movers: + try: + cmds.rename(mover, self.name + "_" + mover) + except Exception, e: + print mover, self.name + "_" + mover + print str(e) + + # exit loop + break + + # assign materials if they exist, removing duplicate materials + materials = [["*_blue_m", "blue_m"], ["*_green_m", "green_m"], ["*_red_m", "red_m"], + ["*_white_m", "white_m"], ["*_proxy_shader_tan", "proxy_shader_tan"], + ["*_proxy_shader_black", "proxy_shader_black"]] + deleteMaterials = [] + for material in materials: + try: + # select materials for the joint mover + cmds.select(material[0]) + foundMaterials = cmds.ls(sl=True) + + # loop through each color material (dupes) + for mat in foundMaterials: + cmds.hyperShade(objects=mat) + assignedGeo = cmds.ls(sl=True) + + # select the geo and the original material, and assign + originalMaterial = material[1] + for geo in assignedGeo: + cmds.select([geo, originalMaterial]) + cmds.hyperShade(assign=originalMaterial) + + # delete the material no longer needed + deleteMaterials.append(mat) + except: + pass + + # delete all deleteMaterials + for mat in deleteMaterials: + cmds.delete(mat) + + # add to JointMover grp + cmds.refresh(force=True) + if not cmds.objExists("JointMover"): + cmds.group(empty=True, name="JointMover") + + try: + cmds.parent("|" + self.name + "_mover_grp", "JointMover") + except Exception, e: + print str(e) + globalMover = utils.findGlobalMoverFromName(self.name) + cmds.select(globalMover) + cmds.setToolTo("moveSuperContext") + + # obey visibility toggles + self.rigUiInst.setMoverVisibility() + + # 1/13/16 Change # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # hook up global scale on joint movers + try: + movers = self.returnJointMovers + + for each in [movers[0], movers[1]]: + for mover in each: + if not cmds.objExists(mover + ".globalScale"): + try: + cmds.aliasAttr("globalScale", mover + ".scaleZ") + cmds.connectAttr(mover + ".globalScale", mover + ".scaleX") + cmds.connectAttr(mover + ".globalScale", mover + ".scaleY") + cmds.setAttr(mover + ".scaleX", keyable=False) + cmds.setAttr(mover + ".scaleY", keyable=False) + except: + pass + # lock movers + for each in movers: + for mover in each: + cmds.lockNode(mover, lock=True) + except: + pass + + # 1/13/16 Change # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + + else: + cmds.confirmDialog(title="Joint Mover", message="Could not find associated joint mover file.", + icon="critical") + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def selectScriptJob(self, info): + """ + Change icon color of the given joint mover's button in the outliner to show selection status. + + :param info: This list contains the button object, the joint mover control, and the original color icon. + + If the control given is selected, the icon is switched to a white icon. If it is not selected, the icon + is set back to the original passed in icon. + """ + + pixmap = QtGui.QPixmap(20, 15) + pixmap.fill(QtGui.QColor(255, 255, 255)) + whiteIcon = QtGui.QIcon(pixmap) + + # for each item in the passed in info [outliner button, mover control, unselected stylesheet],check if + # the control is in the selection, and color the button appropriately + for item in info: + button = item[0] + control = item[1] + icon = item[2] + + selected = cmds.ls(selection=True) + if control not in selected: + self.outlinerWidgets[button].setIcon(icon) + + if control in selected: + self.outlinerWidgets[button].setIcon(whiteIcon) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createGlobalMoverButton(self, name, parent, uiInstance): + """ + Create the button in the outliner for the global mover control of a joint mover. + + :param name: The name of the joint mover control. + :param parent: The outliner widget the created button will be parented to. + :param uiInstance: The Rig Creator interface instance. + """ + + part = name.partition(self.name)[2] + + # create the icon + pixmap = QtGui.QPixmap(20, 15) + pixmap.fill(QtGui.QColor("yellow")) + icon = QtGui.QIcon(pixmap) + + # create the button + self.outlinerWidgets[name + "_globalMoverBtn"] = QtWidgets.QPushButton(icon, "") + self.outlinerWidgets[name + "_globalMoverBtn"].setMinimumSize(QtCore.QSize(20, 15)) + self.outlinerWidgets[name + "_globalMoverBtn"].setMaximumSize(QtCore.QSize(20, 15)) + uiInstance.treeWidget.setItemWidget(parent, 1, self.outlinerWidgets[name + "_globalMoverBtn"]) + + # connect and add to list + self.outlinerWidgets[name + "_globalMoverBtn"].clicked.connect( + partial(self.selectMover, part, True, False, False, self.outlinerWidgets[name + "_globalMoverBtn"])) + self.outlinerControls.append([name + "_globalMoverBtn", name + "_mover", icon]) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createOffsetMoverButton(self, name, parent, uiInstance): + """ + Create the button in the outliner for the offset mover control of a joint mover. + + :param name: The name of the joint mover control. + :param parent: The outliner widget the created button will be parented to. + :param uiInstance: The Rig Creator interface instance. + """ + part = name.partition(self.name)[2] + + # create the icon + pixmap = QtGui.QPixmap(20, 15) + pixmap.fill(QtGui.QColor(100, 200, 255)) + icon = QtGui.QIcon(pixmap) + + # create the button + self.outlinerWidgets[name + "_offsetMoverBtn"] = QtWidgets.QPushButton(icon, "") + self.outlinerWidgets[name + "_offsetMoverBtn"].setMinimumSize(QtCore.QSize(20, 15)) + self.outlinerWidgets[name + "_offsetMoverBtn"].setMaximumSize(QtCore.QSize(20, 15)) + uiInstance.treeWidget.setItemWidget(parent, 2, self.outlinerWidgets[name + "_offsetMoverBtn"]) + + # connect and add to list + self.outlinerWidgets[name + "_offsetMoverBtn"].clicked.connect( + partial(self.selectMover, part, False, True, False, self.outlinerWidgets[name + "_offsetMoverBtn"])) + self.outlinerControls.append([name + "_offsetMoverBtn", name + "_mover_offset", icon]) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createMeshMoverButton(self, name, parent, uiInstance): + """ + Create the button in the outliner for the geometry mover control of a joint mover. + + :param name: The name of the joint mover control. + :param parent: The outliner widget the created button will be parented to. + :param uiInstance: The Rig Creator interface instance. + + Note: The geometry mover is purely for aesthetics and does not affect the rigging. + """ + + part = name.partition(self.name)[2] + + # create the icon + pixmap = QtGui.QPixmap(20, 15) + pixmap.fill(QtGui.QColor(255, 176, 176)) + icon = QtGui.QIcon(pixmap) + + # create the button + self.outlinerWidgets[name + "_geoMoverBtn"] = QtWidgets.QPushButton(icon, "") + self.outlinerWidgets[name + "_geoMoverBtn"].setMinimumSize(QtCore.QSize(20, 15)) + self.outlinerWidgets[name + "_geoMoverBtn"].setMaximumSize(QtCore.QSize(20, 15)) + uiInstance.treeWidget.setItemWidget(parent, 3, self.outlinerWidgets[name + "_geoMoverBtn"]) + + # connect and add to list + self.outlinerWidgets[name + "_geoMoverBtn"].clicked.connect( + partial(self.selectMover, part, False, False, True, self.outlinerWidgets[name + "_geoMoverBtn"])) + self.outlinerControls.append([name + "_geoMoverBtn", name + "_mover_geo", icon]) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createScriptJob(self): + """ + Create the selection script job for the outliner buttons and their associated joint mover controls. + + This function purely creates the script job. The script job function that is run is called self.selectScriptJob. + """ + + self.scriptJob = cmds.scriptJob( + event=["SelectionChanged", partial(self.selectScriptJob, self.outlinerControls)], runOnce=False, + parent="pyArtRigCreatorUi", kws=True, per=False) + self.rigUiInst.scriptJobs.append(self.scriptJob) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def selectMover(self, part, globalMover, offsetMover, geoMover, button): + """ + Select the appropriate joint mover control based on the args passed in. Color the associated button white + to show selection status. + + :param part: The name of the joint mover control. + :param globalMover: Boolean of whether or not given control is a global mover. + :param offsetMover: Boolean of whether or not given control is an offset mover. + :param geoMover: Boolean of whether or not given control is a mesh mover. + :param button: The button in the outliner associated with the given mover. + """ + + # select mover and color button + name = self.name + part + + # get modifiers + toggle = False + mods = cmds.getModifiers() + if (mods & 1) > 0: + toggle = True + + if globalMover: + cmds.select(name + "_mover", tgl=toggle) + + selected = cmds.ls(sl=True) + if name + "_mover" in selected: + button.setStyleSheet('background-color: rgb(255, 255, 255);') + else: + button.setStyleSheet('background-color: rgb(255, 255, 0);') + + if offsetMover: + cmds.select(name + "_mover_offset", tgl=toggle) + + selected = cmds.ls(sl=True) + if name + "_mover_offset" in selected: + self.outlinerWidgets[name + "_offsetMoverBtn"].setStyleSheet('background-color: rgb(255, 255, 255);') + else: + self.outlinerWidgets[name + "_offsetMoverBtn"].setStyleSheet('background-color: rgb(100, 220, 255);') + + if geoMover: + cmds.select(name + "_mover_geo", tgl=toggle) + + selected = cmds.ls(sl=True) + if name + "_mover_geo" in selected: + self.outlinerWidgets[name + "_geoMoverBtn"].setStyleSheet('background-color: rgb(255, 255, 255);') + else: + self.outlinerWidgets[name + "_geoMoverBtn"].setStyleSheet('background-color: rgb(255, 176, 176);') + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createContextMenu(self, point): + """ + Create the right-click menu for the module. + + :param point: Point on monitor to spawn the right-click menu. + + Default menu actions created: + * Copy Settings + * Paste Settings + * Reset Settings + * Delete Module + * Create Mirror of this Module + * Mirror Transformations (only if a mirror is linked) + """ + + networkNode = self.returnNetworkNode + mirror = cmds.getAttr(networkNode + ".mirrorModule") + + # icons + icon_copy = QtGui.QIcon(os.path.join(self.iconsPath, "System/copy.png")) + icon_paste = QtGui.QIcon(os.path.join(self.iconsPath, "System/paste.png")) + icon_reset = QtGui.QIcon(os.path.join(self.iconsPath, "System/reset.png")) + icon_delete = QtGui.QIcon(os.path.join(self.iconsPath, "System/delete.png")) + icon_mirror = QtGui.QIcon(os.path.join(self.iconsPath, "System/mirrorXforms.png")) + icon_createMirror = QtGui.QIcon(os.path.join(self.iconsPath, "System/createMirror.png")) + + # create the context menu + if networkNode != "ART_Root_Module": + self.contextMenu = QtWidgets.QMenu() + self.contextMenu.addAction(icon_copy, "Copy Settings", self.copySettings) + self.contextMenu.addAction(icon_paste, "Paste Settings", self.pasteSettings) + self.contextMenu.addAction(icon_reset, "Reset Settings", self.resetSettings) + + self.contextMenu.addSeparator() + if mirror != None: + self.contextMenu.addAction(icon_mirror, "Mirror Transformations to " + mirror, + self.mirrorTransformations) + + self.contextMenu.addAction(icon_createMirror, "Create Mirror of this Module", self.createMirrorOfModule_UI) + self.contextMenu.addSeparator() + + self.contextMenu.addAction(icon_delete, "Delete Module", self.deleteModule) + self.contextMenu.exec_(self.groupBox.mapToGlobal(point)) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def copySettings(self): + """ + Copy the values from the network node of the module and store them in a temp file on disk. + + This function is used in the right-click menu of the module on the skeleton settings interface. + Occasionally, it is called outside of the menu. For example, when creating a mirror of the module, + the settings are copied for the source module to then be later pasted on the mirror. + """ + + networkNode = self.returnNetworkNode + attrs = cmds.listAttr(networkNode, ud=True, hd=True) + + attrData = [] + for attr in attrs: + value = cmds.getAttr(networkNode + "." + attr) + attrData.append([attr, value]) + + # write out attrData to a temp file + tempDir = cmds.internalVar(userTmpDir=True) + clipboardFile = os.path.normcase(os.path.join(tempDir, "ART_clipboard.txt")) + + f = open(clipboardFile, 'w') + + # dump the data with json + json.dump(attrData, f) + f.close() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def pasteSettings(self): + """ + Paste the settings from the temp file on disk to the module's network node. + + This function is used in the right-click menu of the module on the skeleton settings interface. + Occasionally, it is called outside of the menu. For example, when creating a mirror of the module, + the settings are copied for the source module to then be later pasted on the mirror. + + After settings are pasted, applyModuleChanges is called to update the joint mover in the scene with + the latest values. updateSettingsUI is also called to update the outliner. + """ + + # it does this 4 times because for some reason it would not grab everything one time through. Investigate + for i in range(4): + + tempDir = cmds.internalVar(userTmpDir=True) + clipboardFile = os.path.normcase(os.path.join(tempDir, "ART_clipboard.txt")) + + if os.path.exists(clipboardFile): + # load the data + json_file = open(clipboardFile) + data = json.load(json_file) + json_file.close() + + # attempt to paste data if module type is the same + networkNode = self.returnNetworkNode + moduleType = cmds.getAttr(networkNode + ".moduleType") + if moduleType == data[0][1]: + + for each in data: + attr = each[0] + value = each[1] + + try: + attrType = str(cmds.getAttr(networkNode + "." + attr, type=True)) + + if attrType != "string": + cmds.setAttr(networkNode + "." + attr, lock=False) + cmds.setAttr(networkNode + "." + attr, value, lock=True) + except: + pass + + else: + cmds.warning("No data in clipboard") + + # relaunch the UI + self.updateSettingsUI() + self.applyModuleChanges(self) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def resetSettings(self): + """ + Reset the settings of the module's network node. + + This function is used in the right-click menu of the module on the skeleton settings interface. + Occasionally, it is called outside of the menu. + + After settings are reset, applyModuleChanges is called to update the joint mover in the scene with + the latest values. updateSettingsUI is also called to update the outliner. + """ + + # it does this 4 times because for some reason it would not grab everything one time through. Investigate + for i in range(4): + + networkNode = self.returnNetworkNode + attrs = cmds.listAttr(networkNode, ud=True) + + for attr in attrs: + attrType = str(cmds.getAttr(networkNode + "." + attr, type=True)) + + if attrType == "double": + cmds.setAttr(networkNode + "." + attr, lock=False) + cmds.setAttr(networkNode + "." + attr, 0, lock=True) + + if attrType == "bool": + cmds.setAttr(networkNode + "." + attr, lock=False) + cmds.setAttr(networkNode + "." + attr, True, lock=True) + + if attrType == "enum": + cmds.setAttr(networkNode + "." + attr, lock=False) + cmds.setAttr(networkNode + "." + attr, 0, lock=True) + + # relaunch the UI + self.updateSettingsUI() + self.applyModuleChanges(self) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def resetTransforms(self, translate, rotate, scale, name): + """ + Reset the given attributes of all movers in the module. + + :param translate: Boolean of whether or not to reset translation values. + :param rotate: Boolean of whether or not to reset the rotation values. + :param scale: Boolean of whether or not to reset the scale values. + :param name: The module name. (prefix + basename + suffix) + + This function is mainly called from ART_ResetModeUI. + + """ + + cmds.select(name + "_mover_grp", hi=True) + selection = cmds.ls(sl=True) + + globalMovers = [] + offsetMovers = [] + geoMovers = [] + + for each in selection: + if each.find("_mover") != -1: + if each.partition("_mover")[2] == "": + globalMovers.append(each) + if each.find("_mover_offset") != -1: + if each.partition("_mover_offset")[2] == "": + offsetMovers.append(each) + if each.find("_mover_geo") != -1: + if each.partition("_mover_geo")[2] == "": + geoMovers.append(each) + + cmds.select(clear=True) + + for moverList in [globalMovers, offsetMovers, geoMovers]: + for each in moverList: + if translate: + for attr in [".tx", ".ty", ".tz"]: + try: + cmds.setAttr(each + attr, 0) + except: + pass + if rotate: + for attr in [".rx", ".ry", ".rz"]: + try: + cmds.setAttr(each + attr, 0) + except: + pass + if scale: + for attr in [".sx", ".sy", ".sz"]: + try: + cmds.setAttr(each + attr, 1) + except: + pass + if cmds.window("ART_ResetXformsModeWin", exists=True): + cmds.deleteUI("ART_ResetXformsModeWin", wnd=True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def deleteModule(self): + """ + Delete the module and all associated nodes and interfaces. + + First, this will delete the joint mover, remove the entry from the outliner and the skeleton settings UI. + Then, it has to deal with any connected modules or mirror modules and resolve any issues there. + + """ + + # delete the joint mover + movers = self.returnJointMovers + + for moverGrp in movers: + for mover in moverGrp: + cmds.lockNode(mover, lock=False) + + cmds.delete(self.name + "_mover_grp") + + # remove the entry from the outliner + index = self.rigUiInst.treeWidget.indexOfTopLevelItem(self.outlinerWidgets[self.name + "_treeModule"]) + self.rigUiInst.treeWidget.takeTopLevelItem(index) + + # remove the groupbox + self.groupBox.setParent(None) + + # deal with mirror module + networkNode = self.returnNetworkNode + mirrorModule = cmds.getAttr(networkNode + ".mirrorModule") + if mirrorModule != None: + if mirrorModule != "None": + modules = utils.returnRigModules() + for mod in modules: + modName = cmds.getAttr(mod + ".moduleName") + if modName == mirrorModule: + + # set the mirrored version + cmds.setAttr(mod + ".mirrorModule", lock=False) + cmds.setAttr(mod + ".mirrorModule", "None", type="string", lock=True) + + # get instance of mirror module's class + modType = cmds.getAttr(mod + ".moduleType") + modName = cmds.getAttr(mod + ".moduleName") + module = __import__("RigModules." + modType, {}, {}, [modType]) + + # get the class name from that module file (returns Modules.ART_Root.ART_Root for example) + moduleClass = getattr(module, module.className) + + # find the instance of that module and call on the skeletonSettings_UI function + moduleInst = moduleClass(self.rigUiInst, modName) + + # find the current groupBox for this module + for i in range(self.rigUiInst.moduleSettingsLayout.count()): + if type(self.rigUiInst.moduleSettingsLayout.itemAt(i).widget()) == QtWidgets.QGroupBox: + if self.rigUiInst.moduleSettingsLayout.itemAt(i).widget().title() == modName: + self.rigUiInst.moduleSettingsLayout.itemAt(i).widget().setParent(None) + + # relaunch the skeleton settings UI with new info + moduleInst.skeletonSettings_UI(modName) + + # check for any attached modules + attachedModules = self.checkForDependencies() + elementList = [] + if len(attachedModules) > 0: + + for each in attachedModules: + elementList.append([each[2], " -> parent changed from: ", each[1], " to: ", "root\n"]) + cmds.parent(each[2] + "_mover_grp", "root_mover") + cmds.setAttr(each[0] + ".parentModuleBone", lock=False) + cmds.setAttr(each[0] + ".parentModuleBone", "root", type="string", lock=True) + each[3].currentParent.setText("root") + mover = "root_mover" + + # create the connection geo between the two + childMover = utils.findOffsetMoverFromName(each[2]) + riggingUtils.createBoneConnection(mover, childMover, each[2]) + each[3].applyModuleChanges(each[3]) + cmds.select(clear=True) + + # remove the network node + cmds.delete(networkNode) + + # delete scriptJob + cmds.scriptJob(kill=self.scriptJob, force=True) + self.updateBoneCount() + self.rigUiInst.moduleInstances.remove(self) + + # warn user about changes + if len(attachedModules) > 0: + winParent = interfaceUtils.getMainWindow() + win = interfaceUtils.DialogMessage("Attention!", + "The following modules have had their parent changed\ + due to the change in this module's structure:", + elementList, 5, winParent) + win.show() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def checkForDependencies(self): + """ + This method will check modules for any attached modules or children modules. + + This method is generally called when deleting a module or when changing a module name + so that any connected modules are updated accordingly. + + :return: attached modules + + """ + + # This method will check our module for any attached modules + modules = self.getAllModules + joints = self.returnCreatedJoints + + attachedMods = [] + instances = {} + + for inst in self.rigUiInst.moduleInstances: + networkNode = inst.returnNetworkNode + instances[networkNode] = inst + + for module in modules: + parentJoint = cmds.getAttr(module + ".parentModuleBone") + moduleName = cmds.getAttr(module + ".moduleName") + if parentJoint in joints: + instance = instances.get(module) + attachedMods.append([module, parentJoint, moduleName, instance]) + + return attachedMods + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createMirrorOfModule_UI(self): + """ + This method builds the interface for creating a mirror of a module. + + .. image:: /images/mirrorModule.png + + """ + + # copy the settings of the module + self.copySettings() + + # get basename and classname + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + className = cmds.getAttr(networkNode + ".moduleType") + + # launch a UI to get the name information + self.mirrorWindow = QtWidgets.QMainWindow() + + # load stylesheet + styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss") + f = open(styleSheetFile, "r") + style = f.read() + f.close() + + self.mirrorWindow.setStyleSheet(style) + + # size policies + mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + + # create the main widget + self.mainWidget = QtWidgets.QWidget() + self.mirrorWindow.setCentralWidget(self.mainWidget) + + # set qt object name + self.mirrorWindow.setObjectName("ART_createMirrorModuleUI") + self.mirrorWindow.setWindowTitle("Create Mirror Module") + + # create the mainLayout for the rig creator UI + self.mainLayout = QtWidgets.QVBoxLayout(self.mainWidget) + self.mainLayout.setContentsMargins(0, 0, 0, 0) + + self.mirrorWindow.resize(300, 150) + self.mirrorWindow.setSizePolicy(mainSizePolicy) + self.mirrorWindow.setMinimumSize(QtCore.QSize(300, 150)) + self.mirrorWindow.setMaximumSize(QtCore.QSize(300, 150)) + + # create the background image + self.frame = QtWidgets.QFrame() + self.mainLayout.addWidget(self.frame) + + # create the layout for the widgets + self.widgetLayout = QtWidgets.QVBoxLayout(self.frame) + + # create the prefix pair of fields + self.prefixForm = QtWidgets.QFormLayout() + self.widgetLayout.addLayout(self.prefixForm) + + self.prefixLabel = QtWidgets.QLabel("Prefix: ") + self.prefixForm.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.prefixLabel) + + self.prefix = QtWidgets.QLineEdit() + self.prefixForm.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.prefix) + + # hookup signal/slot connection + self.prefix.textChanged.connect(partial(self.updatePreview, baseName)) + + # create the suffix pair of fields + self.suffixForm = QtWidgets.QFormLayout() + self.widgetLayout.addLayout(self.suffixForm) + + self.suffixLabel = QtWidgets.QLabel("Suffix: ") + self.suffixForm.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.suffixLabel) + + self.suffix = QtWidgets.QLineEdit() + self.suffixForm.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.suffix) + + # hookup signal/slot connection + self.suffix.textChanged.connect(partial(self.updatePreview, baseName)) + + # spacer + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.widgetLayout.addItem(spacerItem) + + # realtime preview of final module name + self.previewForm = QtWidgets.QFormLayout() + self.widgetLayout.addLayout(self.previewForm) + self.previewLabel = QtWidgets.QLabel("Preview: ") + self.previewName = QtWidgets.QLabel(baseName) + self.previewName.setMinimumSize(QtCore.QSize(200, 20)) + self.previewName.setMaximumSize(QtCore.QSize(200, 20)) + self.previewName.setAlignment(QtCore.Qt.AlignHCenter) + self.previewForm.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.previewLabel) + self.previewForm.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.previewName) + + # set preview font + font = QtGui.QFont() + font.setPointSize(12) + self.previewName.setFont(font) + + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.widgetLayout.addItem(spacerItem1) + + # create button + self.createButton = QtWidgets.QPushButton("CREATE") + self.createButton.setObjectName("blueButton") + self.widgetLayout.addWidget(self.createButton) + self.createButton.setMinimumSize(QtCore.QSize(285, 40)) + self.createButton.setMaximumSize(QtCore.QSize(285, 40)) + self.createButton.setSizePolicy(mainSizePolicy) + font = QtGui.QFont() + font.setPointSize(12) + self.createButton.setFont(font) + + # hookup signal/slot on create button + self.createButton.clicked.connect(self.createMirrorModule) + + # show the window + self.mirrorWindow.show() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def updatePreview(self, baseName, *args): + """ + This simple method updates the module preview field(QLineEdit) with the entered prefix and suffix. + + :param baseName: base name of the module (example: arm) + + """ + + prefix = str(self.prefix.text()) + suffix = str(self.suffix.text()) + + string = "" + if len(prefix) > 0: + string += prefix + "_" + + string += baseName + + if len(suffix) > 0: + string += "_" + suffix + + self.previewName.setText(string) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createMirrorModule(self): + """ + This method creates the mirror of a module and is called from createMirrorOfModule_UI. + + To create the mirror of a module, after a few checks are done, a module of the same type is created first. + If that module type has a left/right version of a joint mover file, the opposite version is brought in. + All the normal steps of module creation are then gone through and lastly, mirrorTransformations is called. + + """ + + userSpecName = str(self.previewName.text()) + networkNode = self.returnNetworkNode + parent = cmds.getAttr(networkNode + ".parentModuleBone") + className = cmds.getAttr(networkNode + ".moduleType") + + # check to see if a module already has that name + modules = utils.returnRigModules() + mirrorModule = None + moduleName = None + + for module in modules: + name = cmds.getAttr(module + ".moduleName") + if name == userSpecName: + cmds.confirmDialog(title="Name Exists", + message="A module with that name already exists. Please enter a unique name \ + for the module", + icon="critical") + return + + # now check the modules that contain the parent bone + for module in modules: + bones = cmds.getAttr(module + ".Created_Bones") + splitJoints = bones.split("::") + createdJoints = [] + + # create a list of the created bones + for bone in splitJoints: + if bone != "": + createdJoints.append(bone) + + # see if the parent bone is in that list + if parent in createdJoints: + mirrorModule = cmds.getAttr(module + ".mirrorModule") + moduleName = cmds.getAttr(module + ".moduleName") + + # if our parent bone's module, has a mirror module, we need to create this new mirror module under that + # parent instead (if parent = l_thigh, mirror parent should be r_thigh) + if mirrorModule is not None: + for module in modules: + modName = cmds.getAttr(module + ".moduleName") + if modName == mirrorModule: + + # find the parent's mover (if parent is l_thigh, mover would be l_leg_thigh_mover) + networkNodes = utils.returnRigModules() + mover = utils.findMoverNodeFromJointName(networkNodes, parent, False, True) + + # find mirror mover + mirrorMover = mover.replace(moduleName, mirrorModule) + baseName = cmds.getAttr(module + ".baseName") + boneList = cmds.getAttr(module + ".Created_Bones") + + # now, we need to find the joint from the mirror mover, and once there is a match, the parent\ + # var now becomes that joint + if mirrorMover.find("_mover") != -1: + jointName = mirrorMover.partition("_mover")[0] + + if jointName in boneList: + parent = jointName + + else: + # if removing _mover didn't yield a matching joint name, take out the baseName from\ + # the mover name, and then remove the _mover + jointName = jointName.replace(baseName + "_", "") + + if jointName in boneList: + parent = jointName + + # arms and leg exception + mirrorSide = None + specialCaseModules = ["ART_Leg_Standard", "ART_Arm_Standard"] + if className in specialCaseModules: + side = cmds.getAttr(networkNode + ".side") + if side == "Left": + mirrorSide = "Right" + if side == "Right": + mirrorSide = "Left" + + # create an instance of the module + mod = __import__("RigModules." + className, {}, {}, [className]) + + # get the class name from that module file (returns Modules.ART_Root.ART_Root for example) + moduleClass = getattr(mod, mod.className) + jmPath = mod.jointMover + + # call functions to create network node, skeleton settings UI + moduleInst = moduleClass(self.rigUiInst, userSpecName) + self.rigUiInst.moduleInstances.append(moduleInst) + networkNodeInst = moduleInst.buildNetwork() + + # if mirrorSide exists + if mirrorSide is not None: + jmPath = jmPath.partition(".ma")[0] + "_" + mirrorSide + ".ma" + if mirrorSide == "Left": + cmds.setAttr(networkNodeInst + ".side", lock=False) + cmds.setAttr(networkNodeInst + ".side", "Left", type="string", lock=True) + if mirrorSide == "Right": + cmds.setAttr(networkNodeInst + ".side", lock=False) + cmds.setAttr(networkNodeInst + ".side", "Right", type="string", lock=True) + + # build the settings UI/joint mover/add to outliner + moduleInst.skeletonSettings_UI(userSpecName) + moduleInst.jointMover_Build(jmPath) + moduleInst.addJointMoverToOutliner() + + # update the created joints attribute on the network node with the new names + prefix = str(self.prefix.text()) + suffix = str(self.suffix.text()) + + if len(prefix) > 0: + if prefix.find("_") == -1: + prefix = prefix + "_" + if len(suffix) > 0: + if suffix.find("_") == -1: + suffix = "_" + suffix + + createdBones = cmds.getAttr(networkNodeInst + ".Created_Bones") + createdBones = createdBones.split("::") + + attrString = "" + for bone in createdBones: + if len(bone) > 1: + attrString += prefix + bone + suffix + "::" + + cmds.setAttr(networkNodeInst + ".Created_Bones", lock=False) + cmds.setAttr(networkNodeInst + ".Created_Bones", attrString, type="string", lock=True) + + # update the self.currentParent label and the parentModuleBone attr on the network node + moduleInst.currentParent.setText(parent) + + cmds.setAttr(networkNodeInst + ".parentModuleBone", lock=False) + cmds.setAttr(networkNodeInst + ".parentModuleBone", parent, type="string", lock=True) + + # find the current parent mover and its scale + if parent == "root": + mover = "root_mover" + offsetMover = "root_mover" + + else: + # find the parent mover name to parent to + networkNodes = utils.returnRigModules() + mover = utils.findMoverNodeFromJointName(networkNodes, parent, False, True) + offsetMover = utils.findMoverNodeFromJointName(networkNodes, parent) + + if mover is not None: + cmds.parentConstraint(mover, userSpecName + "_mover_grp", mo=True) + cmds.scaleConstraint(mover, userSpecName + "_mover_grp") + + # create the connection geo between the two + childMover = utils.findOffsetMoverFromName(userSpecName) + riggingUtils.createBoneConnection(offsetMover, childMover, userSpecName) + + globalMover = utils.findGlobalMoverFromName(userSpecName) + cmds.select(globalMover) + cmds.setToolTo("moveSuperContext") + + utils.fitViewAndShade() + cmds.refresh(force=True) + moduleInst.pasteSettings() + moduleInst.aimMode(True) + + # delete UI + cmds.deleteUI("ART_createMirrorModuleUI", wnd=True) + + # update the mirrorModule setting + self.mirrorMod.setText(userSpecName) + name = cmds.getAttr(networkNode + ".moduleName") + moduleInst.mirrorMod.setText(name) + + cmds.setAttr(networkNode + ".mirrorModule", lock=False) + cmds.setAttr(networkNode + ".mirrorModule", userSpecName, type="string", lock=True) + + cmds.setAttr(networkNodeInst + ".mirrorModule", lock=False) + cmds.setAttr(networkNodeInst + ".mirrorModule", name, type="string", lock=True) + + # mirror transformations + self.mirrorTransformations() + + self.rigUiInst.populateNetworkList() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def mirrorTransformations_RigPose(self): + """ + This method is used when creating rig poses for modules. If a module has a mirror, this method will mirror the + rig pose transformations to that mirror module. + + """ + + # reset mirror module's rig pose + mirrorModInst = self.returnMirrorModuleInst + + # ensure the mirrorModInst has a UI and is setup for rig pose creation + mirrorModInst.setupForRigPose() + # if not cmds.objExists(mirrorModInst.name + "_rigPose"): + # mirrorModInst.getReferencePose("rigPose") + + # call on base mirror transformations method + self.mirrorTransformations() + mirrorModInst.getReferencePose("rigPose") + + # update the rig pose of the mirrorModInst + mirrorModInst.updateRigPose(mirrorModInst.overallSlider) + mirrorModInst.cleanUpRigPose() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def mirrorTransformations(self): + """ + This method mirrors transformations for the module's mirror module. + + """ + + currentSelection = cmds.ls(sl=True) + + # get the mirror module + networkNode = self.returnNetworkNode + mirrorModule = cmds.getAttr(networkNode + ".mirrorModule") + moduleName = cmds.getAttr(networkNode + ".moduleName") + parent = cmds.getAttr(networkNode + ".parentModuleBone") + + # get mirror module instance and information + mirrorInst = self.returnMirrorModuleInst + + # turn off aim mode + mirrorInst.aimMode_Setup(False) + + # turn off coplanar mode IF it exists on the module + try: + state = mirrorInst.coplanarBtn.isChecked() + if state: + mirrorInst.coplanarBtn.setChecked(False) + mirrorInst.coplanarMode() + except: + pass + + moverTypes = self.returnJointMovers + for moverType in moverTypes: + for jointMover in moverType: + attrs = cmds.listAttr(jointMover, keyable=True) + + for attr in attrs: + value = cmds.getAttr(jointMover + "." + attr) + + mirrorMover = jointMover.partition(moduleName)[2] + mirrorMover = mirrorModule + mirrorMover + mirrorAttrs = ["translateX", "translateY", "translateZ"] + + if attr in mirrorAttrs: + cmds.setAttr(mirrorMover + "." + attr, value * -1) + else: + cmds.setAttr(mirrorMover + "." + attr, value) + + cmds.select(clear=True) + if len(currentSelection) > 0: + cmds.select(currentSelection) + + # turn aim mode on + mirrorInst.aimMode_Setup(True) + + # extend functionality + self.mirrorTransformations_Custom() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def rigPose_UI(self, parentWidget): + """ + This method creates the UI widget that gets parented into the publish UI that handles rig pose creation. + + A slider gets created for the overall module that goes from current pose to ideal rig pose. Then a slider + gets created for each joint in the module to allow for finer control over the rig pose creation. + + :param parentWidget: the widget the rig pose UI (QFrame) will get parented to + + """ + + # Add a QFrame for the widget + self.rigPoseFrame = QtWidgets.QFrame() + self.rigPoseFrame.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) + self.rigPoseFrame.setMinimumWidth(310) + self.rigPoseFrame.setMaximumWidth(310) + + # load stylesheet + styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss") + f = open(styleSheetFile, "r") + self.style = f.read() + f.close() + + # add the rig pose frame to the stackWidget + parentWidget.addWidget(self.rigPoseFrame) + numWidgetsInStack = parentWidget.count() + parentWidget.setCurrentIndex(numWidgetsInStack - 1) + + # frame styling + backgroundImg = utils.returnFriendlyPath(os.path.join(self.iconsPath, "System/field_background.png")) + self.rigPoseFrame.setStyleSheet("background-image: url(" + backgroundImg + ");") + + # create an overall layout + self.rigPoseLayout = QtWidgets.QVBoxLayout(self.rigPoseFrame) + label = QtWidgets.QLabel(self.name) + self.rigPoseLayout.addWidget(label) + + # create a slider for the overall module rig pose + hboxLayout = QtWidgets.QHBoxLayout() + self.rigPoseLayout.addLayout(hboxLayout) + + image1 = QtWidgets.QFrame() + image1.setMinimumSize(30, 30) + image1.setMaximumSize(30, 30) + modelPoseImg = utils.returnFriendlyPath(os.path.join(self.iconsPath, "System/modelPose.png")) + image1.setStyleSheet("background-image: url(" + modelPoseImg + ");") + hboxLayout.addWidget(image1) + image1.setToolTip("Model Pose") + + self.overallSlider = QtWidgets.QSlider() + self.overallSlider.setProperty("name", self.name) + hboxLayout.addWidget(self.overallSlider) + self.overallSlider.setOrientation(QtCore.Qt.Horizontal) + self.overallSlider.setRange(0, 100) + self.overallSlider.setSingleStep(1) + self.overallSlider.setTracking(False) + + image2 = QtWidgets.QFrame() + image2.setMinimumSize(30, 30) + image2.setMaximumSize(30, 30) + rigPoseImg = utils.returnFriendlyPath(os.path.join(self.iconsPath, "System/rigPose.png")) + image2.setStyleSheet("background-image: url(" + rigPoseImg + ");") + hboxLayout.addWidget(image2) + image2.setToolTip("Rig Pose") + + # create hboxlayout for resetAll and update Rig Pose buttons + buttonLayout = QtWidgets.QHBoxLayout() + self.rigPoseLayout.addLayout(buttonLayout) + + self.rigPoseResetAllBtn = QtWidgets.QPushButton("Reset Rig Pose") + buttonLayout.addWidget(self.rigPoseResetAllBtn) + self.rigPoseResetAllBtn.clicked.connect(self.resetRigPose) + self.rigPoseResetAllBtn.setToolTip("Reset the module to it's initial ideal rig pose.") + self.rigPoseResetAllBtn.setObjectName("blueButton") + self.rigPoseResetAllBtn.setStyleSheet(self.style) + + self.rigPoseUpdateAllBtn = QtWidgets.QPushButton("Update Rig Pose") + self.rigPoseUpdateAllBtn.setStyleSheet(self.style) + buttonLayout.addWidget(self.rigPoseUpdateAllBtn) + self.rigPoseUpdateAllBtn.clicked.connect(partial(self.updateRigPose, self.overallSlider)) + self.rigPoseUpdateAllBtn.setToolTip( + "Update the rig pose if you've done any custom manipulations to the controls.") + self.rigPoseUpdateAllBtn.setObjectName("blueButton") + + # create a frame for the advanced controls + self.rigPose_advancedGroup = QtWidgets.QGroupBox("Advanced") + self.rigPoseLayout.addWidget(self.rigPose_advancedGroup) + self.rigPose_advancedLayout = QtWidgets.QVBoxLayout(self.rigPose_advancedGroup) + + # create a slider for each created joint + joints = self.returnCreatedJoints + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + + for joint in joints: + + if cmds.objExists(joint): + self.createRigPoseSliderForJoint(joint) + + else: + jointBaseName = joint + if self.name != baseName: + nameData = self.name.split(baseName) + + if nameData[0] != "": + jointBaseName = jointBaseName.partition(nameData[0])[2] + if nameData[1] != "": + jointBaseName = jointBaseName.partition(nameData[1])[0] + + if cmds.objExists(self.name + "_" + jointBaseName + "_mover"): + self.createRigPoseSliderForJoint(joint) + + # create mirror button if applicable + if cmds.getAttr(networkNode + ".mirrorModule") != "": + mirrorMod = cmds.getAttr(networkNode + ".mirrorModule") + if mirrorMod != None: + self.rigPoseMirrorBtn = QtWidgets.QPushButton("Mirror to: " + mirrorMod) + self.rigPoseLayout.addWidget(self.rigPoseMirrorBtn) + self.rigPoseMirrorBtn.clicked.connect(self.mirrorTransformations_RigPose) + self.rigPoseMirrorBtn.setObjectName("blueButton") + self.rigPoseMirrorBtn.setStyleSheet(self.style) + + self.rigPoseLayout.addSpacerItem( + QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def buildRig(self, textEdit, uiInst): + """ + This method starts building the rig for a module. It will then call on buildRigCustom, which is implemented + in each derived module class as an override function. + + :param textEdit: The text edit in the buildProgressUI that we output information to. + :param uiInst: passed in instance of the buildProgressUI + + """ + + # get current nodes in scene + currentNodes = cmds.ls("*", long=True) + successfulBuild = True + errorMessage = "" + + # run the instance build function + try: + self.buildRigCustom(textEdit, uiInst) + + except Exception, e: + successfulBuild = False + errorMessage = str(traceback.format_exc()) + + # get all nodes in scene and compare to original list + allNodes = cmds.ls("*", long=True) + + newNodes = list(set(allNodes).difference(currentNodes)) + + for node in newNodes: + if not cmds.objExists(node + ".sourceModule"): + cmds.addAttr(node, ln="sourceModule", dt="string") + + try: + cmds.setAttr(node + ".sourceModule", self.name, type="string") + except: + print node + + if not successfulBuild: + print "Build Rig Failed: " + str(e) + print errorMessage + # self.deleteRig() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def buildRigCustom(self, textEdit, uiInst): + """ + This method is what truly builds the rig for each module. It is implemented in the derived module class. + + :param textEdit: The text edit in the buildProgressUI that we output information to. + :param uiInst: passed in instance of the buildProgressUI + + """ + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def deleteRig(self): + """ + This method deletes all rigging for the module. + + """ + + allNodes = cmds.ls("*") + for node in allNodes: + if cmds.objExists(node + ".sourceModule"): + cmds.lockNode(node, lock=False) + source = cmds.getAttr(node + ".sourceModule") + if source == self.name: + try: + cmds.delete(node) + except: + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def mirrorTransformations_Custom(self): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def updateSettingsUI(self): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def applyModuleChanges(self, moduleInst): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def addJointMoverToOutliner(self): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def updateOutliner(self): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def skinProxyGeo(self): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def aimMode(self, state): + """ + This method toggles the aim mode state if the module can have aim mode. + + It then calls on each derived module's aimMode_Setup which defines how to setup aim mode for the module. + + """ + + networkNode = self.returnNetworkNode + cmds.setAttr(networkNode + ".aimMode", lock=False) + cmds.setAttr(networkNode + ".aimMode", state, lock=True) + + self.aimMode_Setup(state) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def aimMode_Setup(self, state): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setupModelPoseForRig(self): + """ + This method is implemented in the derived module class. + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def matchModelPose(self): + """ + This method is implemented in the derived module class. + + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def pinModule(self, state): + """ + This method is implemented in the derived module class. + + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def bakeOffsets(self): + """ + This method bakes any transforms on the offset movers up to the global movers, and then zeroes out the offset + movers. + + """ + + # get movers + jointMovers = self.returnJointMovers + + # separate mover lists + globalMovers = jointMovers[0] + offsetMovers = jointMovers[1] + constraints = [] + locators = [] + + # create locators for the offsetMovers, then zero out offset mover + for mover in offsetMovers: + locatorName = mover.partition("_offset")[0] + "_loc" + loc = cmds.spaceLocator(name=locatorName)[0] + + # constrain locator + constraint = cmds.parentConstraint(mover, loc)[0] + cmds.delete(constraint) + + # parent locator under a copy of the locatorName + parentLoc = cmds.duplicate(loc)[0] + cmds.parent(loc, parentLoc) + locators.append(parentLoc) + + for mover in offsetMovers: + for attr in [".tx", ".ty", ".tz", ".rx", ".ry", ".rz"]: + try: + cmds.setAttr(mover + attr, 0) + except: + pass + + # snap global movers to locators + for mover in globalMovers: + if cmds.objExists(mover + "_loc"): + constraint = cmds.parentConstraint(mover + "_loc", mover)[0] + constraints.append(constraint) + + # remove locs + for const in constraints: + cmds.delete(const) + + for loc in locators: + cmds.delete(loc) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setupForRigPose(self): + """ + This method unhides the movers and constrains the joints to the movers for creating the rig pose. + + If the user wants to create a custom rig pose (instead of using the sliders), this method sets the module + up for that functionality. + + """ + + # unlock joint movers + cmds.select("JointMover", hi=True) + jmNodes = cmds.ls(sl=True) + for node in jmNodes: + cmds.lockNode(node, lock=False) + + # find the mover shapes and set their visibility + movers = self.returnJointMovers + globalMovers = movers[0] + shapes = [] + + for each in movers: + for mover in each: + child = cmds.listRelatives(mover, children=True, shapes=True) + if len(child) > 0: + shapes.append(mover + "|" + child[0]) + + for shape in shapes: + cmds.setAttr(shape + ".v", lock=False) + cmds.setAttr(shape + ".v", 0, lock=True) + + # show global movers + shapes = [] + for mover in globalMovers: + child = cmds.listRelatives(mover, children=True, shapes=True) + if len(child) > 0: + shapes.append(mover + "|" + child[0]) + + for shape in shapes: + cmds.setAttr(shape + ".v", lock=False) + cmds.setAttr(shape + ".v", 1, lock=True) + + # unlock mover group for this module and make visible + cmds.lockNode(self.name + "_mover_grp", lock=False) + cmds.setAttr(self.name + "_mover_grp.v", lock=False) + cmds.setAttr(self.name + "_mover_grp.v", 1) + + # hide the proxy geo + cmds.select(self.name + "_mover_grp", hi=True) + allNodes = cmds.ls(sl=True) + for node in allNodes: + if node.find("_proxy_geo") != -1: + if cmds.nodeType(node) == "mesh": + parent = cmds.listRelatives(node, parent=True)[0] + cmds.lockNode(parent, lock=False) + cmds.setAttr(parent + ".v", lock=False) + cmds.setAttr(parent + ".v", 0) + cmds.lockNode(parent, lock=True) + + # get the joints created by this module + joints = self.returnCreatedJoints + + # create mover name + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + + for joint in joints: + + if cmds.objExists(joint + "_mover_offset"): + cmds.parentConstraint(joint + "_mover_offset", joint) + else: + jointBaseName = joint + if self.name != baseName: + nameData = self.name.split(baseName) + + if nameData[0] != "": + jointBaseName = jointBaseName.partition(nameData[0])[2] + if nameData[1] != "": + jointBaseName = jointBaseName.partition(nameData[1])[0] + + if cmds.objExists(self.name + "_" + jointBaseName + "_mover_offset"): + cmds.parentConstraint(self.name + "_" + jointBaseName + "_mover_offset", joint) + + # lock joint movers + cmds.select("JointMover", hi=True) + jmNodes = cmds.ls(sl=True) + for node in jmNodes: + cmds.lockNode(node, lock=True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setSkeletonPose(self, poseType): + """ + This method constrains the joints to the movers and then stores that pose data for those joints. + + This could be the model pose or the rig pose. + + :param poseType: whether to set the model pose or rig pose for the joints. + + """ + # get the joints created by this module + joints = self.returnCreatedJoints + + # create mover name + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + + for joint in joints: + if cmds.objExists(joint + "_mover_offset"): + cmds.parentConstraint(joint + "_mover_offset", joint) + + else: + jointBaseName = joint + if self.name != baseName: + nameData = self.name.split(baseName) + + if nameData[0] != "": + jointBaseName = jointBaseName.partition(nameData[0])[2] + if nameData[1] != "": + jointBaseName = jointBaseName.partition(nameData[1])[0] + + if cmds.objExists(self.name + "_" + jointBaseName + "_mover_offset"): + cmds.parentConstraint(self.name + "_" + jointBaseName + "_mover_offset", joint) + + # set pose + self.setReferencePose(poseType) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def removeSkeletalConstraints(self): + """ + This method removes any constraints on the joints. This tends to get called by removing rigging. + + """ + + # get the joints created by this module and remove the constraints + joints = self.returnCreatedJoints + + # create mover name + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + + for joint in joints: + if cmds.objExists(joint + "_mover_offset"): + cmds.select(joint) + cmds.delete(constraints=True) + + else: + jointBaseName = joint + if self.name != baseName: + nameData = self.name.split(baseName) + + if nameData[0] != "": + jointBaseName = jointBaseName.partition(nameData[0])[2] + if nameData[1] != "": + jointBaseName = jointBaseName.partition(nameData[1])[0] + + if cmds.objExists(self.name + "_" + jointBaseName + "_mover_offset"): + cmds.select(joint) + cmds.delete(constraints=True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def cleanUpRigPose(self): + """ + This method hides the joint movers and unconstrains the joints from the movers after setting a rig pose. + + """ + + # show the proxy geo + cmds.select(self.name + "_mover_grp", hi=True) + allNodes = cmds.ls(sl=True) + for node in allNodes: + if node.find("_proxy_geo") != -1: + if cmds.nodeType(node) == "mesh": + parent = cmds.listRelatives(node, parent=True)[0] + cmds.lockNode(parent, lock=False) + cmds.setAttr(parent + ".v", lock=False) + cmds.setAttr(parent + ".v", 1) + cmds.lockNode(parent, lock=True) + + # unlock mover group for this module and make invisible + cmds.lockNode(self.name + "_mover_grp", lock=False) + cmds.setAttr(self.name + "_mover_grp.v", lock=False) + + cmds.setAttr(self.name + "_mover_grp.v", 0) + + cmds.setAttr(self.name + "_mover_grp.v", lock=True) + cmds.lockNode(self.name + "_mover_grp", lock=True) + + # get the joints created by this module and remove the constraints + joints = self.returnCreatedJoints + + # create mover name + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + + for joint in joints: + if cmds.objExists(joint + "_mover_offset"): + cmds.select(joint) + cmds.delete(constraints=True) + + else: + jointBaseName = joint + if self.name != baseName: + nameData = self.name.split(baseName) + + if nameData[0] != "": + jointBaseName = jointBaseName.partition(nameData[0])[2] + if nameData[1] != "": + jointBaseName = jointBaseName.partition(nameData[1])[0] + + if cmds.objExists(self.name + "_" + jointBaseName + "_mover_offset"): + cmds.select(joint) + cmds.delete(constraints=True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def updateRigPose(self, slider): + """ + This method updates what the stored rig pose is for a module. The default rig pose tends to be zeroed out + rotations, but this function can essentially update what the max value on the rig pose slider sets the pose to. + + :param slider: The rig pose slider where the min is the current model pose and the max is the rig pose. + + """ + + # get network node + networkNode = self.returnNetworkNode + + # get pose data off networkNode + originalData = json.loads(cmds.getAttr(networkNode + ".rigPose")) + newPose = [] + + for data in originalData: + moverData = {} + mover = data.get("mover") + moverData["mover"] = mover + + if cmds.objExists(mover): + translate = cmds.getAttr(mover + ".translate")[0] + rotate = cmds.getAttr(mover + ".rotate")[0] + + moverData["translate"] = translate + moverData["rotate"] = rotate + newPose.append(moverData) + + jsonString = json.dumps(newPose) + cmds.setAttr(networkNode + ".rigPose", jsonString, type="string") + slider.setValue(0) + slider.setValue(100) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def resetRigPose(self): + """ + This method resets the module rig pose to be the default (zeroed rotations). + + """ + + # get the network node + networkNode = self.returnNetworkNode + + # remove the rigPose attribute on the networkNode + cmds.deleteAttr(networkNode, at="rigPose") + + # recreate rig pose node with defaults + self.getReferencePose("rigPose") + + # set slider + self.overallSlider.setValue(0) + self.overallSlider.setValue(100) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def resetRigPose_Part(self, part): + """ + This method resets the given joint (part) rig pose to be zeroed rotations. This is for the part slider on + the rig pose UI in the advanced section. + + :param part: The given joint name slider. + + """ + + # get the networkNode + networkNode = self.returnNetworkNode + + # get the poseData + poseData = json.loads(cmds.getAttr(networkNode + ".rigPose")) + + # find our part in the pose data + for data in poseData: + mover = data.get("mover") + if mover == part: + rotate = data.get("rotate") + + try: + cmds.setAttr(mover + ".rotate", 0, 0, 0, type="double3") + data["rotate"] = (0.0, 0.0, 0.0) + except: + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def getReferencePose(self, poseType, zeroPose=True): + """ + This method gets the model pose or the rig pose (depending on poseType) and stores that data for the movers. + + :param poseType: Whether or not to get the model pose or rig pose. + :param zeroPose: Whether or not the default rig pose should be set to zeroed rotations. + + """ + + # get movers + jointMovers = self.returnJointMovers + + # separate mover lists + globalMovers = jointMovers[0] + offsetMovers = jointMovers[1] + + # get the network node + networkNode = self.returnNetworkNode + + # if rigPose already exists, then do not set values + if poseType == "rigPose": + if cmds.objExists(networkNode + "." + poseType): + return + + # create the pose data attr if needed + if not cmds.objExists(networkNode + "." + poseType): + cmds.addAttr(networkNode, sn=poseType, dt="string") + + # create reference pose data dict + poseData = [] + + # loop through each mover, getting the translate and rotate values, creating an attribute on the network node + # to store those values + for moverList in [globalMovers, offsetMovers]: + for mover in moverList: + moverData = {} + moverData["mover"] = mover + + for attr in ["translate", "rotate"]: + value = cmds.getAttr(mover + "." + attr)[0] + + if zeroPose: + if poseType == "rigPose": + if attr == "rotate": + value = (0.0, 0.0, 0.0) + + # add the data to the list + moverData[attr] = value + + # add mover data to the pose data list + poseData.append(moverData) + + # dump the pose data list onto the poseType attribute + jsonString = json.dumps(poseData) + cmds.setAttr(networkNode + "." + poseType, jsonString, type="string") + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setReferencePose(self, poseType): + """ + This method gets the data for the given pose type (rig or model) and sets the movers with those values. + + :param poseType: Whether to set the model pose or the rig pose on the movers. + + """ + + # get the network node + networkNode = self.returnNetworkNode + + # get the pose data from the attribute + if cmds.objExists(networkNode + "." + poseType): + poseData = json.loads(cmds.getAttr(networkNode + "." + poseType)) + + for data in poseData: + mover = data.get("mover") + translate = data.get("translate") + rotate = data.get("rotate") + + # if the mover exists, set the values + if cmds.objExists(mover): + + # set translations + for i in range(len(translate)): + if i == 0: + try: + cmds.setAttr(mover + ".translateX", translate[i]) + except: + pass + if i == 1: + try: + cmds.setAttr(mover + ".translateY", translate[i]) + except: + pass + if i == 2: + try: + cmds.setAttr(mover + ".translateZ", translate[i]) + except: + pass + + # set rotations + for i in range(len(rotate)): + if i == 0: + try: + cmds.setAttr(mover + ".rotateX", rotate[i]) + except: + pass + if i == 1: + try: + cmds.setAttr(mover + ".rotateY", rotate[i]) + except: + pass + if i == 2: + try: + cmds.setAttr(mover + ".rotateZ", rotate[i]) + except: + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setReferencePoseSlider(self, part, *args): + """ + This method takes the slider value of a given part and then calls on setPosePercentage, which will then find + the values of the model pose and the rig pose and figure out based on the slider percentage what values to + set on the mover. + + :param part: the joint mover which the slider is controlling. + :param args: the values from the slider + + """ + + percent = float(args[0]) * .01 + self.setPosePercentage(percent, part) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setPosePercentage(self, percent, part): + """ + This method takes the percent from setReferencePoseSlider, gets the values of the model pose and rig pose + for the given part, then calls on setPosePercentage_Part to find and set the values on the mover that is + the percentage between model and rig pose. + + Example: If the model pose is a value of 10 and the rig pose is a value of 0, and the slider is at .5, then + the value to set is 5. (But this is done and found per attribute) + + :param percent: What percent of model and rig pose to set. + :param part: What joint mover to set the values on. + + """ + + # get network node + networkNode = self.returnNetworkNode + + # get reference pose attributes + modelPoseData = json.loads(cmds.getAttr(networkNode + ".modelPose")) + rigPoseData = json.loads(cmds.getAttr(networkNode + ".rigPose")) + + # get the data for each mover + for poseData in modelPoseData: + + mover = poseData.get("mover") + translate = poseData.get("translate") + rotate = poseData.get("rotate") + + if part != None: + if part == mover: + self.setPosePercentage_Part(percent, mover, modelPoseData, rigPoseData, poseData, translate, rotate) + else: + self.setPosePercentage_Part(percent, mover, modelPoseData, rigPoseData, poseData, translate, rotate) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def setPosePercentage_Part(self, percent, mover, modelPoseData, rigPoseData, poseData, translate, rotate): + """ + This method takes the data from setPosePercentage and figures out what values to set on the given part (mover). + + Example: If the model pose is a value of 10 and the rig pose is a value of 0, and the slider is at .5, then + the value to set is 5. (But this is done and found per attribute) + + :param percent: the percent value of the slider. What percentage of the model and rig pose to use. + :param mover: the mover to set the values on. + :param modelPoseData: all of the data for the model pose for this mover. + :param rigPoseData: all of the data for the rig pose for this mover. + :param poseData: a list which includes the mover and its translate and rotate values. + :param translate: the translate values for the model pose + :param rotate: the rotate values for the model pose + + """ + + # get the index of this entry in the rigPoseData list + index = modelPoseData.index(poseData) + + # get the corresponding rig pose data + rigData = rigPoseData[index] + rigTranslate = rigData.get("translate") + rigRotate = rigData.get("rotate") + + # find percentile between model and rig pose to set on each attribute + for i in range(len(translate)): + valueToSet = mathUtils.returnPercentile([translate[i], rigTranslate[i]], percent) + if i == 0: + cmds.setAttr(mover + ".translateX", valueToSet) + if i == 1: + cmds.setAttr(mover + ".translateY", valueToSet) + if i == 2: + cmds.setAttr(mover + ".translateZ", valueToSet) + + for i in range(len(rotate)): + valueToSet = mathUtils.returnPercentile([rotate[i], rigRotate[i]], percent) + if i == 0: + cmds.setAttr(mover + ".rotateX", valueToSet) + if i == 1: + cmds.setAttr(mover + ".rotateY", valueToSet) + if i == 2: + cmds.setAttr(mover + ".rotateZ", valueToSet) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def createRigPoseSliderForJoint(self, joint): + """ + This method creates the rig pose slider widget for the given joint. (This shows up in the advanced section of + the rig pose UI) + + :param joint: The joint that the slider will control. + + """ + + # load stylesheet + styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss") + f = open(styleSheetFile, "r") + self.style = f.read() + f.close() + + # create mover name + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + + jointName = joint + + if cmds.objExists(joint + "_mover"): + jointName = joint + + else: + + jointBaseName = joint + if self.name != baseName: + nameData = self.name.split(baseName) + + if nameData[0] != "": + jointName = jointBaseName.partition(nameData[0])[2] + if nameData[1] != "": + jointName = jointName.partition(nameData[1])[0] + + jointName = self.name + "_" + jointName + + else: + jointName = self.name + "_" + jointName + + # create a master vertical layout + mainLayout = QtWidgets.QVBoxLayout() + self.rigPose_advancedLayout.addLayout(mainLayout) + + # create a label for the joint + font = QtGui.QFont() + font.setPointSize(10) + font.setBold(True) + jointLabel = QtWidgets.QLabel(joint + ":") + jointLabel.setFont(font) + mainLayout.addWidget(jointLabel) + + # create layout for slider/button + layout = QtWidgets.QHBoxLayout() + mainLayout.addLayout(layout) + + # create slider for joint + slider = QtWidgets.QSlider() + layout.addWidget(slider) + slider.setProperty("name", joint) + slider.setOrientation(QtCore.Qt.Horizontal) + slider.setRange(0, 100) + slider.setSingleStep(1) + slider.valueChanged.connect(partial(self.setReferencePoseSlider, jointName + "_mover")) + slider.setTracking(False) + self.overallSlider.valueChanged.connect(slider.setValue) + + # create reset button + button = QtWidgets.QPushButton("Reset") + button.setMinimumWidth(70) + button.setMaximumWidth(70) + layout.addWidget(button) + button.setObjectName("blueButton") + button.setStyleSheet(self.style) + + button.clicked.connect(partial(self.resetRigPose_Part, jointName + "_mover")) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def updateBoneCount(self): + """ + This method looks at the create bones attribute of the module and gets the number of bones in that list + and appends it onto the total bone count for the bone counter interface. + + """ + + if cmds.window("ART_BoneCounterWin", exists=True): + if self.rigUiInst.boneCounterInst is not None: + self.rigUiInst.boneCounterInst.updateBoneCount() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def toggleShapeVis(self, transform, value): + """ + This method finds the shapes for the passed in transform and toggles the visibility based on the value. + + :param transform: the transform to get the shape nodes from. + :param value: whether to show or hide the shape nodes. + + """ + + if cmds.objExists(transform): + shape = cmds.listRelatives(transform, shapes=True) + if shape is not None: + cmds.setAttr(shape[0] + ".v", lock=False) + cmds.setAttr(shape[0] + ".v", value) + cmds.setAttr(shape[0] + ".v", lock=True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def selectionScriptJob_animUI(self, buttonData): + """ + This method is called from a scriptjob anytime a selection is changed. It's sole purpose it to update the button + color on the anim picker to show if a control is selected or not. + + :param buttonData: pairings of button/control/brush. brush is the original color of the button. + + """ + + selection = mel.eval("ls -sl;") + if selection is None: + selection = [] + + for data in buttonData: + control = data[1] + button = data[0] + brushColor = data[2] + + if control in selection: + button.brush.setColor(QtCore.Qt.white) + button.update() + + else: + button.brush.setColor(brushColor) + button.update() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def importFBX_pre(self, importMethod, character): + """ + This method runs before an fbx is imported onto the control rig. It cuts any keys on the controls and zeroes + the controls out before importing the fbx (which is called in the derived module class) + + :param importMethod: Whether or not the FBX is getting imported as FK, IK, Both, or None + :param character: The namespace of the rig. + + """ + + if importMethod != "None": + controls = self.getControls() + + for control in controls: + cmds.cutKey(character + ":" + control) + + self.resetRigControls(True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def importFBX(self, importMethod, character): + """ + This method is implemented in the derived module class and defines how mocap is imported onto the rig controls. + + :param importMethod: Whether or not the FBX is getting imported as FK, IK, Both, or None + :param character: The namespace of the rig. + + """ + + pass + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def resetRigControls(self, resetAll): + """ + This method zeroes out control attributes. If resetAll is true, then it will zero out all rig controls for + the module. Otherwise, it will only zero out the selected controls of the module. + + :param resetAll: Whether or not to reset only the selected controls or all controls of the module. + + """ + + # get namespace + networkNode = self.returnRigNetworkNode + characterNode = cmds.listConnections(networkNode + ".parent")[0] + namespace = cmds.getAttr(characterNode + ".namespace") + + if resetAll: + + # list any attributes on the network node that contain "controls" + controls = cmds.listAttr(networkNode, st="*Controls") + # get that data on that attr + for control in controls: + data = json.loads(cmds.getAttr(networkNode + "." + control)) + + # reset the attr on each control + nonZeroAttrs = ["scale", "globalScale", "scaleX", "scaleY", "scaleZ"] + + try: + for each in data: + attrs = cmds.listAttr(namespace + ":" + each, keyable=True) + for attr in attrs: + if attr not in nonZeroAttrs: + cmds.setAttr(namespace + ":" + each + "." + attr, 0) + else: + cmds.setAttr(namespace + ":" + each + "." + attr, 1) + except: + cmds.warning("skipped " + str(control) + ". No valid controls found to reset.") + + if not resetAll: + nonZeroAttrs = ["scale", "globalScale", "scaleX", "scaleY", "scaleZ"] + selection = cmds.ls(sl=True) + + for each in selection: + attrs = cmds.listAttr(each, keyable=True) + + for attr in attrs: + if attr not in nonZeroAttrs: + cmds.setAttr(each + "." + attr, 0) + else: + cmds.setAttr(each + "." + attr, 1) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def getControls(self): + """ + This method returns a list of all the rig controls of the module. + + :return: List of all rig controls in the module. + + """ + + # get namespace + networkNode = self.returnRigNetworkNode + if networkNode is None: + winParent = interfaceUtils.getMainWindow() + win = interfaceUtils.DialogMessage("Error", "This function does not work without a namespace.", [], 0, + winParent) + win.show() + return None + + # list any attributes on the network node that contain "controls" + controls = cmds.listAttr(networkNode, st="*Controls") + + returnControls = [] + + # get that data on that attr + for control in controls: + data = json.loads(cmds.getAttr(networkNode + "." + control)) + + # reset the attr on each control + if data is not None: + for each in data: + returnControls.append(each) + + return returnControls + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + def selectRigControls(self): + """ + This method calls on getControls to return a list of the controls and the selects them. + + """ + + controls = self.getControls() + + # get namespace + networkNode = self.returnRigNetworkNode + characterNode = cmds.listConnections(networkNode + ".parent")[0] + namespace = cmds.getAttr(characterNode + ".namespace") + + for control in controls: + cmds.select(namespace + ":" + control, add=True) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # PROPERTIES + @property + def getModules(self): + """ + This method finds the main "character" module that has connections to all of the rig modules + + :return: returns the character node. + + """ + + modules = cmds.ls(type="network") + for module in modules: + attrs = cmds.listAttr(module) + if "rigModules" in attrs: + return module + + @property + def getAllModules(self): + """ + This method finds all connected rig modules to the main character network node. + + :return: returns a list of the rig modules + + """ + + modules = cmds.ls(type="network") + returnMods = [] + for module in modules: + attrs = cmds.listAttr(module) + if "parent" in attrs: + returnMods.append(module) + + return returnMods + + @property + def returnNetworkNode(self): + """ + This method returns the module's own network node. + + :return: the modules network node + + """ + + networkNodes = cmds.ls(type="network") + for node in networkNodes: + attrs = cmds.listAttr(node) + if "moduleName" in attrs: + if cmds.getAttr(node + ".moduleName") == self.name: + networkNode = node + + return networkNode + + @property + def returnRigNetworkNode(self): + """ + This method returns the module's own network node using the namespace on the main character + network node. This is so that if there are multiple characters in a scene, we know which + network node for which character we are trying to return. + + :return: returns this module's network node in a scene with references. + + """ + modules = [] + networkNodes = cmds.ls(type="network") + for node in networkNodes: + attrs = cmds.listAttr(node) + if "moduleName" in attrs: + if cmds.getAttr(node + ".moduleName") == self.name: + characterNode = cmds.listConnections(node + ".parent")[0] + if cmds.objExists(characterNode + ".namespace"): + if cmds.getAttr(characterNode + ".namespace") == self.namespace.partition(":")[0]: + networkNode = node + return networkNode + else: + return None + + @property + def returnClassObject(self): + return self + + @property + def returnCreatedJoints(self): + """ + This method loops through the Created Bones attribute on its network node and returns a list of the + joints it will create given the current module settings. + + :return: A list of the created bones of the module. + + """ + + networkNode = self.returnNetworkNode + joints = cmds.getAttr(networkNode + ".Created_Bones") + + splitJoints = joints.split("::") + createdJoints = [] + + for bone in splitJoints: + if bone != "": + createdJoints.append(bone) + + return createdJoints + + @property + def returnJointMovers(self): + """ + This method finds and returns all joint movers for the module. + + :return: a list of all global movers, offset movers, and geo movers for the module. + + """ + + name = self.groupBox.title() + + # select global movers + cmds.select(name + "*_mover") + globalMovers = cmds.ls(sl=True) + + # select offset movers + cmds.select(name + "*_mover_offset") + offsetMovers = cmds.ls(sl=True) + + # mesh movers + cmds.select(name + "*_mover_geo") + geoMovers = cmds.ls(sl=True) + + return [globalMovers, offsetMovers, geoMovers] + + @property + def returnMirrorModuleInst(self): + """ + This method finds and returns the instance of a module's mirror module. + + :return: a pointer in memory to the instance of the mirror module. + + """ + + # get network node + networkNode = self.returnNetworkNode + mirrorModule = cmds.getAttr(networkNode + ".mirrorModule") + + # find instance through rig UI inst + for inst in self.rigUiInst.moduleInstances: + networkNode = inst.returnNetworkNode + moduleName = cmds.getAttr(networkNode + ".moduleName") + if moduleName == mirrorModule: + return inst + + @property + def returnPrefixSuffix(self): + """ + This method splits our module name by the base name and returns the prefix and suffix. + + :return: the user-defined prefix and suffix found by splitting the module name by the base name. + + """ + + prefix = None + suffix = None + + networkNode = self.returnNetworkNode + baseName = cmds.getAttr(networkNode + ".baseName") + splitName = self.name.split(baseName) + if splitName[0] != '': + prefix = splitName[0] + if splitName[1] != '': + suffix = splitName[1] + return [prefix, suffix] |