Last active
July 11, 2024 06:43
-
-
Save benmorgantd/c3a5d0719b62fcd75aecdd210ab6054b to your computer and use it in GitHub Desktop.
Scene cleanup tools including naming, labeling, and history/node deletion.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# our standard imports when using pySide | |
import maya.OpenMayaUI as omui | |
import maya.cmds as cmds | |
import maya.mel as mel | |
from PySide import QtCore | |
from PySide import QtGui | |
from shiboken import wrapInstance | |
# convenience function to get the main window. Part of the basic pySide Gui framework. | |
def maya_main_window(): | |
main_window_ptr = omui.MQtUtil.mainWindow() | |
return wrapInstance(long(main_window_ptr), QtGui.QWidget) | |
# Cleanup toolbox that includes renaming functions, relabeling functions, and History/Node Cleanup | |
class CleanupToolsUI(QtGui.QDialog): | |
def __init__(self, parent=maya_main_window()): | |
# init the QDialog class to that the child inherits its properties | |
super(CleanupToolsUI, self).__init__(parent) | |
# name the window | |
self.setWindowTitle("bm_cleanupTools") | |
# make the window a "tool" in Maya's eyes so that it stays on top when you click off | |
self.setWindowFlags(QtCore.Qt.Tool) | |
# Makes the object get deleted from memory, not just hidden, when it is closed. | |
self.setAttribute(QtCore.Qt.WA_DeleteOnClose) | |
# call our create_layout function here in the init | |
self.create_layout() | |
# establish our connections | |
self.create_connections() | |
def create_layout(self): | |
# place to put layout code | |
# formatting for labels | |
self.labelFont = QtGui.QFont() | |
self.labelFont.setBold(1) | |
self.labelFont.setPixelSize(12) | |
# History Deleting tools | |
self.delLbl = QtGui.QLabel() | |
self.delLbl.setFont(self.labelFont) | |
self.delLbl.setAlignment(QtCore.Qt.AlignVCenter) | |
self.delLbl.setText(" Delete:") | |
self.delLbl.setStyleSheet("QLabel {color: #b7b7b7;}") | |
self.delHistBtn = QtGui.QPushButton("History") | |
# change our button's text and background color | |
self.delHistBtn.setStyleSheet("QPushButton {background-color: #828282; color: black;}") | |
self.delHistBtn.setToolTip("Delete All By Type: History") | |
self.delNonDefHistBtn = QtGui.QPushButton("Non-Deformer History") | |
self.delNonDefHistBtn.setStyleSheet("QPushButton {background-color: #828282; color: black;}") | |
self.delNonDefHistBtn.setToolTip("Delete All By Type: Non-Deformer History") | |
self.delUnusedNodesBtn = QtGui.QPushButton("Unused Nodes") | |
self.delUnusedNodesBtn.setStyleSheet("QPushButton {background-color: #828282; color: black;}") | |
self.delUnusedNodesBtn.setToolTip("Delete Unused Nodes") | |
# relabel tools | |
self.relabelLbl = QtGui.QLabel() | |
self.relabelLbl.setFont(self.labelFont) | |
self.relabelLbl.setText("Relabel Tools: ") | |
self.relabelLbl.setStyleSheet("QLabel {color: #b7b7b7;}") | |
self.relabelBtn = QtGui.QPushButton("Relabel") | |
self.relabelBtn.setStyleSheet("QPushButton {background-color: #828282; color: black;}") | |
# radio buttons to determine whether the label is a prefix or suffix. It seems like they automatically | |
# act as a group. | |
self.suffixRadio = QtGui.QRadioButton("Suffix") | |
self.prefixRadio = QtGui.QRadioButton("Prefix") | |
self.prefixRadio.setChecked(1) | |
# a dropdown menu with common prefix/suffix choices | |
self.labelBox = QtGui.QComboBox() | |
self.labelBox.addItem("BIND") | |
self.labelBox.addItem("DRIVE") | |
self.labelBox.addItem("FK") | |
self.labelBox.addItem("GRP") | |
self.labelBox.addItem("GEO") | |
self.labelBox.addItem("IK") | |
self.labelBox.addItem("JNT") | |
self.labelBox.addItem("R") | |
self.labelBox.addItem("L") | |
# add a check box that determines if the label is replaced or appended | |
self.labelCheckBox = QtGui.QCheckBox("Append Label") | |
self.labelCheckBox.setChecked(0) | |
self.labelCheckBox.setToolTip("Tip: Append the new label instead of replacing the old one.\n" | |
" Ex: L_head_GEO") | |
# renamer tools | |
self.renamerLbl = QtGui.QLabel() | |
self.renamerLbl.setFont(self.labelFont) | |
self.renamerLbl.setText("Renamer Tools: ") | |
self.renamerLbl.setStyleSheet("QLabel {color: #b7b7b7;}") | |
# QLineEdit is a good object type for standard text input | |
self.renamerTxt = QtGui.QLineEdit() | |
self.renamerTxt.setPlaceholderText("Rename") | |
self.renamerTxt.setToolTip("Tip: Use # to insert a number inside the string.\n" | |
" - Supports up to ####") | |
self.renamerBtn = QtGui.QPushButton("Rename") | |
self.renamerBtn.setStyleSheet("QPushButton {background-color: #828282; color: black;}") | |
# selection tools | |
self.selectionTxt = QtGui.QLineEdit() | |
self.selectionTxt.setToolTip("Tip: Use * to select all objects containing that string.\n" | |
" Ex: *_GEO will select all nodes ending in _GEO") | |
self.selectionTxt.setPlaceholderText("Select") | |
self.selectionBtn = QtGui.QPushButton("Select") | |
self.selectionBtn.setStyleSheet("QPushButton {background-color: #828282; color: black;}") | |
# create a layout | |
main_layout = QtGui.QGridLayout() | |
# change our margins | |
main_layout.setContentsMargins(2, 2, 2, 2) | |
# fix margin spacing | |
main_layout.setSpacing(5) | |
main_layout.setColumnMinimumWidth(0, 50) | |
# add our items to our layout | |
# delete history tools | |
main_layout.addWidget(self.delLbl, 0, 0) | |
main_layout.addWidget(self.delHistBtn, 0, 1) | |
main_layout.addWidget(self.delNonDefHistBtn, 0, 2) | |
main_layout.addWidget(self.delUnusedNodesBtn, 0, 3) | |
# relabel tools | |
main_layout.addWidget(self.relabelBtn, 2, 3, 1, 1) | |
main_layout.addWidget(self.suffixRadio, 2, 1) | |
main_layout.addWidget(self.labelBox, 2, 2) | |
main_layout.addWidget(self.labelCheckBox, 3, 3) | |
# renamer tools | |
# have our text widget span across two columns (row,column,rowSpan,columnSpan) | |
main_layout.addWidget(self.renamerTxt, 4, 0, 1, 3) | |
main_layout.addWidget(self.renamerBtn, 4, 3) | |
main_layout.addWidget(self.selectionBtn, 5, 3, 1, 1) | |
main_layout.addWidget(self.selectionTxt, 5, 0, 1, 3) | |
# set column stretching | |
main_layout.setColumnStretch(0, 1) | |
main_layout.setColumnStretch(1, 1) | |
main_layout.setColumnStretch(2, 1) | |
main_layout.setColumnStretch(3, 1) | |
main_layout.setColumnStretch(4, 1) | |
# fit window to contents | |
self.resize(self.minimumSizeHint()) | |
# set our layout | |
self.setLayout(main_layout) | |
def create_connections(self): | |
# establish our button connections | |
self.delHistBtn.clicked.connect(self.delHist) | |
self.delNonDefHistBtn.clicked.connect(self.delNonDefHist) | |
self.delUnusedNodesBtn.clicked.connect(self.delUnusedNodes) | |
# we can use the returnPressed attribute on our text to run a function | |
self.renamerTxt.returnPressed.connect(self.renamerTxtFctn) | |
self.renamerBtn.clicked.connect(self.renamerTxtFctn) | |
self.relabelBtn.clicked.connect(self.relabelFctn) | |
self.selectionBtn.clicked.connect(self.selectionTxtFctn) | |
self.selectionTxt.returnPressed.connect(self.selectionTxtFctn) | |
# our functions for the button conections. If we just put the cmd in the | |
# clicked.connect function, it would call it when we open the Ui | |
def delHist(self): | |
mel.eval("DeleteAllHistory") | |
print "Cleanup Helper -- Delete All History" | |
def delNonDefHist(self): | |
mel.eval("BakeAllNonDefHistory") | |
print "Cleanup Helper -- Delete All Non-Deformer History" | |
def delUnusedNodes(self): | |
mel.eval('hyperShadePanelMenuCommand("hyperShadePanel1","deleteUnusedNodes")') | |
print "Cleanup Helper -- Delete Unused Nodes" | |
def renamerTxtFctn(self): | |
sel = cmds.ls(sl=1) | |
newName = self.renamerTxt.text().replace(" ", "_") | |
newName = newName.replace("'", "") | |
if "#" in newName: | |
j = newName.index("#") | |
k = newName.count("#") | |
newName = newName.split("#") | |
i = 1 | |
if len(sel) > 0 and len(newName) > 0: | |
for obj in sel: | |
if j == 0: | |
# maya doesn't allow you to lead an object name with a number | |
cmds.rename(obj, newName[1:]) | |
else: | |
if k == 1: | |
cmds.rename(obj, newName[0] + "%01d" % i + newName[1]) | |
if k == 2: | |
cmds.rename(obj, newName[0] + "%02d" % i + newName[1]) | |
if k == 3: | |
cmds.rename(obj, newName[0] + "%03d" % i + newName[1]) | |
if k == 4: | |
cmds.rename(obj, newName[0] + "%04d" % i + newName[1]) | |
i += 1 | |
print "Cleanup Helper -- Rename Object" | |
def relabelFctn(self): | |
sel = cmds.ls(sl=1) | |
newLabel = self.labelBox.currentText() | |
if self.suffixRadio.isChecked(): | |
position = "suffix" | |
else: | |
position = "prefix" | |
# returns a list containing all of the labels in the labelBox | |
labels = [self.labelBox.itemText(i) for i in range(self.labelBox.count())] | |
if len(sel) > 0: | |
for obj in cmds.ls(sl=1): | |
objName = obj | |
# strip off any old labels | |
if self.labelCheckBox.isChecked() == 0: | |
for label in labels: | |
objName = objName.replace("_" + label, "") | |
objName = objName.replace(label + "_", "") | |
if position == "prefix": | |
cmds.rename(obj, newLabel + "_" + objName) | |
else: | |
cmds.rename(obj, objName + "_" + newLabel) | |
print "Cleanup Helper -- Relabel Object" | |
def selectionTxtFctn(self): | |
sceneObjects = cmds.ls(type="transform") | |
selectionQuery = self.selectionTxt.text() | |
if "*" in selectionQuery: | |
if len(selectionQuery) == 1: | |
# if all the user entered was *, return | |
return | |
i = selectionQuery.index("*") | |
if i == 0: | |
for obj in sceneObjects: | |
if selectionQuery[1:-1] in obj: | |
cmds.select(obj, add=1) | |
else: | |
for obj in sceneObjects: | |
if selectionQuery[0:i] in obj and selectionQuery[i + 1:-2] in obj: | |
cmds.select(obj, add=1) | |
else: | |
cmds.select(selectionQuery, add=1) | |
def selectionTxtToolTipFctn(self): | |
QtGui.QToolTip.showText(self.selectionTxt.mapToGlobal(QtCore.QPoint()), "Test Tool Tip") | |
def showUI(): | |
global ui | |
try: | |
ui.close() | |
except: | |
pass | |
ui = CleanupToolsUI() | |
# useful line of code that gets rid of lots of errors during testing | |
ui.setAttribute(QtCore.Qt.WA_DeleteOnClose) | |
ui.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment