Skip to content

Instantly share code, notes, and snippets.

@Pakmanv
Created May 2, 2025 20:09
Show Gist options
  • Select an option

  • Save Pakmanv/93e4a2ec10c38c6b3e7efa0a18aa430e to your computer and use it in GitHub Desktop.

Select an option

Save Pakmanv/93e4a2ec10c38c6b3e7efa0a18aa430e to your computer and use it in GitHub Desktop.
Cluster Namer VV 1.0
import maya.cmds as cmds
import pymel.core as pm
class VVCLrenamer(object):
def __init__(self):
self.window = "VVCLrenamer"
self.current_mesh = None
self.clusters = []
self.cluster_colors = {} # Store color status per cluster
self.multi_select_enabled = False # Track multi-selection state
self.init_ui()
self.load_preferences()
def init_ui(self):
"""Initialize a popup window with default Maya colors and tooltips."""
if pm.window(self.window, exists=True):
pm.deleteUI(self.window)
self.window = pm.window(self.window, title="Cluster Namer VV 1.0", width=300, height=550)
main_layout = pm.columnLayout(adjustableColumn=True, rowSpacing=5)
pm.text(label="Mesh:")
self.mesh_field = pm.textField(editable=True, annotation="Enter or select a mesh")
pm.textField(self.mesh_field, edit=True, enterCommand=self.set_mesh)
pm.button(label="Load Mesh", command=self.set_mesh, backgroundColor=[0.7, 0.8, 0.9],
annotation="Load selected or entered mesh") # Pastel blue
pm.rowLayout(numberOfColumns=2, adjustableColumn=2)
pm.text(label="Sort By: ")
self.sort_menu = pm.optionMenuGrp(changeCommand=self.update_cluster_list,
annotation="Sort clusters by different criteria")
pm.menuItem(label="Alphabetical A")
pm.menuItem(label="Alphabetical Z")
pm.menuItem(label="Creation Order")
pm.menuItem(label="Vertex Influence")
pm.setParent("..")
self.cluster_label = pm.text(label="Clusters (0):")
self.cluster_list = pm.textScrollList(allowMultiSelection=False, height=200,
annotation="List of clusters; double-click to rename")
pm.textScrollList(self.cluster_list, edit=True, selectCommand=self.select_cluster,
doubleClickCommand=self.edit_cluster_name)
self.popup_menu = pm.popupMenu(parent=self.cluster_list)
pm.menuItem(label="Select Deformer Node", command=self.select_deformer_node, parent=self.popup_menu)
pm.menuItem(label="X", command=lambda x: self.set_cluster_color("green"), parent=self.popup_menu)
pm.menuItem(label="O", command=lambda x: self.set_cluster_color("red"), parent=self.popup_menu)
pm.menuItem(label="Set Default", command=lambda x: self.set_cluster_color("default"), parent=self.popup_menu)
self.multi_select_item = pm.menuItem(label="Toggle Multi Selection", command=self.toggle_multi_selection,
parent=self.popup_menu)
pm.menuItem(label="Rename All Clusters", command=self.rename_all_clusters, parent=self.popup_menu)
pm.button(label="Zero Transforms", command=self.zero_transforms,
annotation="Reset transforms of all cluster handles") # Default Maya color
# Renaming fields and buttons
pm.columnLayout(adjustableColumn=True, rowSpacing=3)
self.search_field = pm.textField(placeholderText="Search", width=290, annotation="Text to search for")
self.replace_field = pm.textField(placeholderText="Replace", width=290, annotation="Text to replace with")
pm.button(label="Search Replace", command=self.search_replace,
annotation="Replace text in selected cluster names") # Default Maya color
self.prefix_field = pm.textField(placeholderText="Prefix", annotation="Prefix to add")
pm.rowLayout(numberOfColumns=3, adjustableColumn=1)
pm.button(label="Add Prefix", command=self.add_prefix, annotation="Add prefix to selected clusters")
pm.text(label=" ") # Spacer
self.prefix_after = pm.checkBox(label="After Existing Prefix", value=False,
annotation="Add prefix after lt_/rt_ if present")
pm.setParent("..")
self.suffix_field = pm.textField(placeholderText="Suffix", annotation="Suffix to add")
pm.button(label="Add Suffix", command=self.add_suffix,
annotation="Add suffix to selected clusters") # Default Maya color
pm.rowLayout(numberOfColumns=4, adjustableColumn=1)
pm.button(label="Append Number", command=self.append_number, backgroundColor=[0.8, 0.8, 0.9],
annotation="Append numbered suffix (e.g., _001)") # Pastel blue
pm.text(label=" ") # Spacer
self.number_before_suffix = pm.checkBox(label="Before Suffix", value=False,
annotation="Place number before existing suffix")
self.uppercase_rt_lt = pm.checkBox(label="RT/LT", value=False,
annotation="Use uppercase RT/LT in names")
pm.setParent("..")
pm.rowLayout(numberOfColumns=4, adjustableColumn=1)
pm.button(label="Auto Prefix Lt/Rt", command=self.auto_prefix, backgroundColor=[0.8, 0.9, 0.8],
annotation="Add lt_/rt_ or LT_/RT_ prefix") # Pastel green
pm.text(label=" ") # Spacer
self.side_prefix = pm.optionMenu(changeCommand=lambda x: None, annotation="Choose side prefix")
pm.menuItem(label="lt_")
pm.menuItem(label="rt_")
self.case_prefix = pm.optionMenu(changeCommand=lambda x: None, annotation="Choose case for prefix")
pm.menuItem(label="lt_/rt_")
pm.menuItem(label="LT_/RT_")
pm.setParent("..")
pm.setParent("..") # End renaming columnLayout
pm.button(label="Close", command=lambda x: pm.deleteUI(self.window), annotation="Close the tool")
pm.showWindow(self.window)
def load_preferences(self):
"""Load saved preferences using optionVar without triggering update_cluster_list."""
if pm.optionVar(exists="VVCLrenamer_sort_mode"):
sort_mode = pm.optionVar(query="VVCLrenamer_sort_mode")
pm.optionMenuGrp(self.sort_menu, edit=True, value=sort_mode)
if pm.optionVar(exists="VVCLrenamer_multi_select"):
self.multi_select_enabled = pm.optionVar(query="VVCLrenamer_multi_select")
pm.textScrollList(self.cluster_list, edit=True, allowMultiSelection=self.multi_select_enabled)
pm.menuItem(self.multi_select_item, edit=True,
label="Toggle Multi Selection (%s)" % ("On" if self.multi_select_enabled else "Off"))
# Do not call update_cluster_list here to avoid premature execution
def save_preferences(self):
"""Save preferences using optionVar."""
sort_mode = pm.optionMenuGrp(self.sort_menu, query=True, value=True)
pm.optionVar(stringValue=("VVCLrenamer_sort_mode", sort_mode))
pm.optionVar(intValue=("VVCLrenamer_multi_select", int(self.multi_select_enabled)))
def set_mesh(self, *args):
"""Set the mesh from selection or text field, displaying short name."""
print("set_mesh: args=%s" % str(args))
mesh_name = pm.textField(self.mesh_field, query=True, text=True).strip()
print("set_mesh: mesh_name from text field=%s" % mesh_name)
if not mesh_name:
selected = cmds.ls(selection=True)
print("set_mesh: selected=%s" % selected)
if not selected:
cmds.warning("No object selected or entered.")
return
mesh_name = selected[0]
print("set_mesh: final mesh_name=%s" % mesh_name)
if not cmds.objExists(mesh_name):
cmds.warning("Object %s does not exist in the scene." % mesh_name)
return
mesh = self.get_mesh_from_selection(mesh_name)
print("set_mesh: mesh from get_mesh_from_selection=%s" % mesh)
if mesh:
self.current_mesh = mesh
short_name = mesh.split("|")[-1]
pm.textField(self.mesh_field, edit=True, text=short_name)
self.update_cluster_list()
else:
cmds.warning("%s is not a valid mesh (no mesh shape found)." % mesh_name)
def get_mesh_from_selection(self, obj):
"""Get the mesh transform from a transform or shape node."""
print("get_mesh_from_selection: obj=%s" % obj)
if not obj or not cmds.objExists(obj):
print("get_mesh_from_selection: Invalid or non-existent obj: %s" % str(obj))
return None
try:
if cmds.nodeType(obj) == "transform":
shapes = cmds.listRelatives(obj, shapes=True, type="mesh", fullPath=True)
print("get_mesh_from_selection: transform shapes=%s" % shapes)
if shapes:
return obj
elif cmds.nodeType(obj) == "mesh":
parents = cmds.listRelatives(obj, parent=True, type="transform", fullPath=True)
print("get_mesh_from_selection: shape parents=%s" % parents)
if parents:
return parents[0]
transforms = cmds.listRelatives(obj, parent=True, type="transform", fullPath=True) or []
for transform in transforms:
shapes = cmds.listRelatives(transform, shapes=True, type="mesh", fullPath=True)
print("get_mesh_from_selection: related transform shapes=%s" % shapes)
if shapes:
return transform
print("get_mesh_from_selection: No valid mesh transform found for %s" % obj)
except Exception as e:
print("get_mesh_from_selection: Error: %s" % str(e))
return None
def get_vertex_influence_count(self, cluster, mesh_shape):
"""Count the number of vertices influenced by the cluster."""
try:
weights = cmds.getAttr(cluster + ".weightList[0].weights[*]")
if weights:
non_zero = sum(1 for w in weights if w > 0.0)
print("get_vertex_influence_count: %s influences %d vertices" % (cluster, non_zero))
return non_zero
return 0
except Exception as e:
print("get_vertex_influence_count: Error for %s: %s" % (cluster, str(e)))
return 0
def get_cluster_handle(self, cluster):
"""Find the handle associated with a cluster deformer."""
print("get_cluster_handle: cluster=%s" % cluster)
handle = None
potential_handle = cluster + "Handle"
if cmds.objExists(potential_handle) and cmds.nodeType(potential_handle) == "transform":
handle = [potential_handle]
print("get_cluster_handle: name-based handle=%s" % handle)
if not handle:
handle = cmds.listConnections(cluster + ".matrix", source=False, destination=True, type="transform")
print("get_cluster_handle: .matrix handle=%s" % handle)
if not handle:
history = cmds.listHistory(cluster, future=True)
cluster_handles = [node for node in history if cmds.nodeType(node) == "clusterHandle"]
if cluster_handles:
handle = cmds.listRelatives(cluster_handles[0], parent=True, type="transform")
print("get_cluster_handle: history handle=%s" % handle)
return handle[0] if handle and cmds.objExists(handle[0]) else None
def toggle_multi_selection(self, *args):
"""Toggle multi-selection in the cluster list."""
self.multi_select_enabled = not self.multi_select_enabled
print("toggle_multi_selection: %s" % ("enabled" if self.multi_select_enabled else "disabled"))
pm.textScrollList(self.cluster_list, edit=True, allowMultiSelection=self.multi_select_enabled)
pm.menuItem(self.multi_select_item, edit=True,
label="Toggle Multi Selection (%s)" % ("On" if self.multi_select_enabled else "Off"))
self.save_preferences()
def set_cluster_color(self, color):
"""Set the color indicator for selected cluster(s)."""
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
print("set_cluster_color: selected=%s to %s" % (selected, color))
for item in selected:
cluster = item.split(" ")[-1] if " " in item else item
if not cmds.objExists(cluster):
continue
self.cluster_colors[cluster] = color
self.update_cluster_list()
def update_cluster_list(self, *args):
"""Populate the cluster deformer list with sorting and indicators."""
print("update_cluster_list: called with args=%s" % str(args))
try:
pm.textScrollList(self.cluster_list, edit=True, removeAll=True)
self.clusters = []
if not self.current_mesh or not cmds.objExists(self.current_mesh):
print("update_cluster_list: No current mesh or mesh does not exist")
pm.text(self.cluster_label, edit=True, label="Clusters (0):")
return
if cmds.nodeType(self.current_mesh) != "transform":
print("update_cluster_list: %s is not a transform node" % self.current_mesh)
pm.text(self.cluster_label, edit=True, label="Clusters (0):")
return
shapes = cmds.listRelatives(self.current_mesh, shapes=True, type="mesh", fullPath=True)
if not shapes:
print("update_cluster_list: No mesh shapes found for %s" % self.current_mesh)
pm.text(self.cluster_label, edit=True, label="Clusters (0):")
return
mesh_shape = shapes[0]
print("update_cluster_list: mesh_shape=%s" % mesh_shape)
try:
deformers = cmds.findDeformers(mesh_shape) or []
except Exception as e:
print("update_cluster_list: Failed to find deformers for %s: %s" % (mesh_shape, str(e)))
pm.text(self.cluster_label, edit=True, label="Clusters (0):")
return
print("update_cluster_list: deformers=%s" % deformers)
if not deformers:
pm.text(self.cluster_label, edit=True, label="Clusters (0):")
return
for deformer in deformers:
if cmds.nodeType(deformer) == "cluster":
print("update_cluster_list: cluster=%s" % deformer)
self.clusters.append(deformer)
if not self.clusters:
print("update_cluster_list: No clusters found")
pm.text(self.cluster_label, edit=True, label="Clusters (0):")
return
pm.text(self.cluster_label, edit=True, label="Clusters (%d):" % len(self.clusters))
sort_mode = pm.optionMenuGrp(self.sort_menu, query=True, value=True)
sorted_clusters = self.clusters[:]
if sort_mode == "Alphabetical A":
sorted_clusters.sort(key=lambda x: x.lower())
print("update_cluster_list: Sorted A to Z: %s" % sorted_clusters)
elif sort_mode == "Alphabetical Z":
sorted_clusters.sort(key=lambda x: x.lower(), reverse=True)
print("update_cluster_list: Sorted Z to A: %s" % sorted_clusters)
elif sort_mode == "Vertex Influence":
sorted_clusters.sort(key=lambda x: self.get_vertex_influence_count(x, mesh_shape), reverse=True)
print("update_cluster_list: Sorted by vertex influence: %s" % sorted_clusters)
print("update_cluster_list: final clusters=%s" % sorted_clusters)
for cluster in sorted_clusters:
display_text = cluster
if cluster in self.cluster_colors and self.cluster_colors[cluster]:
color = self.cluster_colors[cluster]
prefix = "X" if color == "green" else "O" if color == "red" else ""
display_text = "{} {}".format(prefix, cluster) if prefix else cluster
pm.textScrollList(self.cluster_list, edit=True, append=display_text)
self.save_preferences()
except Exception as e:
print("update_cluster_list: Failed to update list: %s" % str(e))
cmds.warning("Failed to update cluster list: %s" % str(e))
def select_cluster(self, *args):
"""Select the cluster handle(s) in the viewport."""
print("select_cluster: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
print("select_cluster: No cluster selected")
return
handles = []
for item in selected:
cluster = item.split(" ")[-1] if " " in item else item
print("select_cluster: cluster=%s" % cluster)
if not cmds.objExists(cluster):
cmds.warning("Cluster %s does not exist." % cluster)
continue
handle = self.get_cluster_handle(cluster)
if handle:
handles.append(handle)
print("select_cluster: Highlighted handle %s" % handle)
else:
cmds.warning("No handle found for cluster %s." % cluster)
if handles:
cmds.select(handles, replace=True)
else:
cmds.warning("No valid handles found for selection.")
def select_deformer_node(self, *args):
"""Select the deformer node(s) directly."""
print("select_deformer_node: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
print("select_deformer_node: No cluster selected")
return
clusters = []
for item in selected:
cluster = item.split(" ")[-1] if " " in item else item
print("select_deformer_node: cluster=%s" % cluster)
if cmds.objExists(cluster):
clusters.append(cluster)
print("select_deformer_node: Selected deformer %s" % cluster)
else:
cmds.warning("Cluster %s does not exist." % cluster)
if clusters:
cmds.select(clusters, replace=True)
else:
cmds.warning("No valid clusters found for selection.")
def edit_cluster_name(self, *args):
"""Rename a single cluster node on double-click."""
print("edit_cluster_name: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True)
if not selected or len(selected) > 1:
cmds.warning("Select exactly one cluster to rename.")
return
old_name = selected[0].split(" ")[-1] if " " in selected[0] else selected[0]
if not cmds.objExists(old_name):
cmds.warning("Cluster %s does not exist." % old_name)
return
result = pm.promptDialog(
title="Rename Cluster",
message="Enter new name for %s:" % old_name,
text=old_name,
button=["OK", "Cancel"],
defaultButton="OK",
cancelButton="Cancel",
dismissString="Cancel"
)
if result == "OK":
new_name = pm.promptDialog(query=True, text=True).strip()
if new_name and new_name != old_name:
cmds.undoInfo(openChunk=True)
try:
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
return
handle_new_name = new_name
handle = self.get_cluster_handle(old_name)
print("edit_cluster_name: Renaming deformer %s to %s" % (old_name, new_name))
new_name = cmds.rename(old_name, new_name)
if handle:
print("edit_cluster_name: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if old_name in self.cluster_colors:
color = self.cluster_colors.pop(old_name)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("edit_cluster_name: Failed: %s" % str(e))
cmds.warning("Failed to rename cluster: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def zero_transforms(self, *args):
"""Reset translate and rotate to 0 and scale to 1 for all cluster handles."""
print("zero_transforms: args=%s" % str(args))
if not self.clusters:
cmds.warning("No clusters available to zero transforms.")
return
cmds.undoInfo(openChunk=True)
try:
for cluster in self.clusters:
if not cmds.objExists(cluster):
cmds.warning("Cluster %s does not exist." % cluster)
continue
handle = self.get_cluster_handle(cluster)
if handle:
try:
cmds.setAttr(handle + ".translateX", 0)
cmds.setAttr(handle + ".translateY", 0)
cmds.setAttr(handle + ".translateZ", 0)
cmds.setAttr(handle + ".rotateX", 0)
cmds.setAttr(handle + ".rotateY", 0)
cmds.setAttr(handle + ".rotateZ", 0)
cmds.setAttr(handle + ".scaleX", 1)
cmds.setAttr(handle + ".scaleY", 1)
cmds.setAttr(handle + ".scaleZ", 1)
print("zero_transforms: Reset transforms for %s" % handle)
except Exception as e:
cmds.warning("Failed to zero transforms for %s: %s" % (handle, str(e)))
else:
cmds.warning("No handle found for cluster %s." % cluster)
finally:
cmds.undoInfo(closeChunk=True)
def search_replace(self, *args):
"""Search and replace in selected cluster names."""
print("search_replace: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
cmds.warning("No clusters selected.")
return
search = pm.textField(self.search_field, query=True, text=True).strip()
replace = pm.textField(self.replace_field, query=True, text=True).strip()
if not search:
cmds.warning("Search string cannot be empty.")
return
cmds.undoInfo(openChunk=True)
try:
for item in selected:
old_name = item.split(" ")[-1] if " " in item else item
if not cmds.objExists(old_name):
cmds.warning("Cluster %s does not exist." % old_name)
continue
new_name = old_name.replace(search, replace)
if new_name == old_name:
continue
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
continue
handle_new_name = new_name
handle = self.get_cluster_handle(old_name)
print("search_replace: Renaming deformer %s to %s" % (old_name, new_name))
new_name = cmds.rename(old_name, new_name)
if handle:
print("search_replace: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if old_name in self.cluster_colors:
color = self.cluster_colors.pop(old_name)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("search_replace: Failed: %s" % str(e))
cmds.warning("Failed to search/replace: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def add_prefix(self, *args):
"""Add a prefix to selected cluster(s)."""
print("add_prefix: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
cmds.warning("No clusters selected.")
return
prefix = pm.textField(self.prefix_field, query=True, text=True).strip()
after_prefix = pm.checkBox(self.prefix_after, query=True, value=True)
if not prefix:
cmds.warning("Prefix cannot be empty.")
return
cmds.undoInfo(openChunk=True)
try:
for item in selected:
old_name = item.split(" ")[-1] if " " in item else item
if not cmds.objExists(old_name):
cmds.warning("Cluster %s does not exist." % old_name)
continue
new_name = old_name
if after_prefix:
for existing in ["lt_", "rt_", "LT_", "RT_"]:
if old_name.startswith(existing):
new_name = existing + prefix + old_name[len(existing):]
break
else:
new_name = prefix + old_name
else:
new_name = prefix + old_name
if new_name == old_name:
continue
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
continue
handle_new_name = new_name
handle = self.get_cluster_handle(old_name)
print("add_prefix: Renaming deformer %s to %s" % (old_name, new_name))
new_name = cmds.rename(old_name, new_name)
if handle:
print("add_prefix: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if old_name in self.cluster_colors:
color = self.cluster_colors.pop(old_name)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("add_prefix: Failed: %s" % str(e))
cmds.warning("Failed to add prefix: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def add_suffix(self, *args):
"""Add a suffix to selected cluster(s)."""
print("add_suffix: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
cmds.warning("No clusters selected.")
return
suffix = pm.textField(self.suffix_field, query=True, text=True).strip()
if not suffix:
cmds.warning("Suffix cannot be empty.")
return
cmds.undoInfo(openChunk=True)
try:
for item in selected:
old_name = item.split(" ")[-1] if " " in item else item
if not cmds.objExists(old_name):
cmds.warning("Cluster %s does not exist." % old_name)
continue
new_name = old_name + suffix
if new_name == old_name:
continue
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
continue
handle_new_name = new_name
handle = self.get_cluster_handle(old_name)
print("add_suffix: Renaming deformer %s to %s" % (old_name, new_name))
new_name = cmds.rename(old_name, new_name)
if handle:
print("add_suffix: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if old_name in self.cluster_colors:
color = self.cluster_colors.pop(old_name)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("add_suffix: Failed: %s" % str(e))
cmds.warning("Failed to add suffix: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def append_number(self, *args):
"""Append numbered suffix to selected clusters."""
print("append_number: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
cmds.warning("No clusters selected.")
return
before_suffix = pm.checkBox(self.number_before_suffix, query=True, value=True)
uppercase = pm.checkBox(self.uppercase_rt_lt, query=True, value=True)
print("append_number: before_suffix=%s, uppercase=%s" % (before_suffix, uppercase))
cmds.undoInfo(openChunk=True)
try:
for i, item in enumerate(selected, 1):
old_name = item.split(" ")[-1] if " " in item else item
if not cmds.objExists(old_name):
cmds.warning("Cluster %s does not exist." % old_name)
continue
new_name = old_name
suffix = "_{:03d}".format(i)
if before_suffix:
parts = old_name.rsplit("_", 1)
if len(parts) > 1 and parts[1].lower() in ["grp", "rig", "geo", "cluster"]:
new_name = parts[0] + suffix + "_" + parts[1]
else:
new_name = old_name + suffix
else:
new_name = old_name + suffix
if new_name == old_name:
continue
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
continue
handle_new_name = new_name
handle = self.get_cluster_handle(old_name)
print("append_number: Renaming deformer %s to %s" % (old_name, new_name))
new_name = cmds.rename(old_name, new_name)
if handle:
print("append_number: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if old_name in self.cluster_colors:
color = self.cluster_colors.pop(old_name)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("append_number: Failed: %s" % str(e))
cmds.warning("Failed to append number: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def auto_prefix(self, *args):
"""Add lt_/rt_ or LT_/RT_ prefix based on dropdowns."""
print("auto_prefix: args=%s" % str(args))
selected = pm.textScrollList(self.cluster_list, query=True, selectItem=True) or []
if not selected:
cmds.warning("No clusters selected.")
return
side = pm.optionMenu(self.side_prefix, query=True, value=True)
case = pm.optionMenu(self.case_prefix, query=True, value=True)
print("auto_prefix: side=%s, case=%s" % (side, case))
prefix = side.upper() if case == "LT_/RT_" else side
cmds.undoInfo(openChunk=True)
try:
for item in selected:
old_name = item.split(" ")[-1] if " " in item else item
if not cmds.objExists(old_name):
cmds.warning("Cluster %s does not exist." % old_name)
continue
new_name = prefix + old_name
if new_name == old_name:
continue
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
continue
handle_new_name = new_name
handle = self.get_cluster_handle(old_name)
print("auto_prefix: Renaming deformer %s to %s" % (old_name, new_name))
new_name = cmds.rename(old_name, new_name)
if handle:
print("auto_prefix: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if old_name in self.cluster_colors:
color = self.cluster_colors.pop(old_name)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("auto_prefix: Failed: %s" % str(e))
cmds.warning("Failed to add prefix: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def rename_all_clusters(self, *args):
"""Rename all clusters with a prefix, suffix, or numbering."""
print("rename_all_clusters: args=%s" % str(args))
if not self.clusters:
cmds.warning("No clusters available to rename.")
return
result = pm.promptDialog(
title="Rename All Clusters",
message="Enter prefix (optional), suffix (optional), or leave blank for numbering:",
text="",
button=["OK", "Cancel"],
defaultButton="OK",
cancelButton="Cancel",
dismissString="Cancel"
)
if result == "OK":
input_text = pm.promptDialog(query=True, text=True).strip()
prefix = ""
suffix = ""
if input_text:
parts = input_text.split("*")
prefix = parts[0] if len(parts) > 0 else ""
suffix = parts[1] if len(parts) > 1 else ""
cmds.undoInfo(openChunk=True)
try:
for i, cluster in enumerate(self.clusters, 1):
if not cmds.objExists(cluster):
cmds.warning("Cluster %s does not exist." % cluster)
continue
new_name = cluster
if prefix or suffix:
new_name = prefix + cluster + suffix
else:
new_name = cluster + "_{:03d}".format(i)
if new_name == cluster:
continue
if cmds.objExists(new_name):
cmds.warning("Name %s already exists." % new_name)
continue
handle_new_name = new_name
handle = self.get_cluster_handle(cluster)
print("rename_all_clusters: Renaming deformer %s to %s" % (cluster, new_name))
new_name = cmds.rename(cluster, new_name)
if handle:
print("rename_all_clusters: Renaming handle %s to %s" % (handle, handle_new_name))
cmds.rename(handle, handle_new_name)
if cluster in self.cluster_colors:
color = self.cluster_colors.pop(cluster)
self.cluster_colors[new_name] = color
self.update_cluster_list()
except Exception as e:
print("rename_all_clusters: Failed: %s" % str(e))
cmds.warning("Failed to rename clusters: %s" % str(e))
finally:
cmds.undoInfo(closeChunk=True)
def run_tool():
"""Launch the tool."""
VVCLrenamer()
if __name__ == "__main__":
run_tool()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment