103 lines
3.2 KiB
Python
103 lines
3.2 KiB
Python
import base64
|
|
import json
|
|
import re
|
|
import sys
|
|
|
|
from maya import cmds
|
|
|
|
from .compatibility import ensure_retro_compatibility
|
|
from .namespace import maya_namespace, node_full_namespace
|
|
from .optionvar import USE_BASE64_DATA_ENCODING
|
|
|
|
|
|
PICKER_HOLDER_NODE = '_dwpicker_data'
|
|
PICKER_HOLDER_ATTRIBUTE = '_dwpicker_data'
|
|
LS_EXP = ["*." + PICKER_HOLDER_ATTRIBUTE, "*:*." + PICKER_HOLDER_ATTRIBUTE]
|
|
|
|
|
|
def get_picker_holder_node():
|
|
if cmds.objExists(PICKER_HOLDER_NODE):
|
|
return PICKER_HOLDER_NODE
|
|
return create_picker_holder_node()
|
|
|
|
|
|
def create_picker_holder_node():
|
|
with maya_namespace(":"):
|
|
selection = cmds.ls(selection=True)
|
|
node = cmds.createNode('script', name=PICKER_HOLDER_NODE)
|
|
cmds.select(selection)
|
|
cmds.setAttr(node + '.nodeState', 1)
|
|
cmds.addAttr(node, longName=PICKER_HOLDER_ATTRIBUTE, dataType='string')
|
|
return node
|
|
|
|
|
|
def store_local_picker_data(pickers):
|
|
data = encode_data(pickers)
|
|
node = get_picker_holder_node()
|
|
cmds.setAttr(node + '.' + PICKER_HOLDER_ATTRIBUTE, data, type='string')
|
|
clean_stray_picker_holder_nodes()
|
|
|
|
|
|
def load_local_picker_data():
|
|
nodes = list_picker_holder_nodes()
|
|
pickers = []
|
|
for node in nodes:
|
|
data = cmds.getAttr(node + '.' + PICKER_HOLDER_ATTRIBUTE)
|
|
if not data:
|
|
continue
|
|
data = [ensure_retro_compatibility(p) for p in decode_data(data)]
|
|
namespace = node_full_namespace(node)
|
|
if namespace:
|
|
# holder node would have namespace when it is referenced
|
|
# and we should add it's namespace for items to be selectable
|
|
for p in data:
|
|
for s in p['shapes']:
|
|
s['action.targets'] = [
|
|
re.sub(r'([^|]+)', r'{}:\1'.format(namespace), n)
|
|
for n in s['action.targets']]
|
|
pickers.extend(data)
|
|
return pickers
|
|
|
|
|
|
def encode_data(pickers):
|
|
data = json.dumps(pickers)
|
|
if not cmds.optionVar(query=USE_BASE64_DATA_ENCODING):
|
|
return data
|
|
# Ensure backward compatibility.
|
|
if sys.version_info[0] == 2:
|
|
return base64.b64encode(bytes(data))
|
|
return base64.b64encode(bytes(data, "utf-8"))
|
|
|
|
|
|
def decode_data(data):
|
|
try:
|
|
return json.loads(data)
|
|
except ValueError: # Happe if data encoded is encoded as base 64 string.
|
|
return json.loads(base64.b64decode(data))
|
|
|
|
|
|
def list_picker_holder_nodes():
|
|
"""
|
|
Look up in the scene all the nodes holding an attribute named
|
|
"_dwpicker_holder" which are not set on the "_dwpicker_holder" node.
|
|
This mignt happed if a node node is imported (creating a namespace or a
|
|
incrementation).
|
|
"""
|
|
return [node.split(".")[0] for node in cmds.ls(LS_EXP)]
|
|
|
|
|
|
def clean_stray_picker_holder_nodes():
|
|
"""
|
|
If the scene contains multiple picker holder nodes, we remove them
|
|
automatically to avoid repeated pickers.
|
|
"""
|
|
for node in list_picker_holder_nodes():
|
|
if node == PICKER_HOLDER_NODE:
|
|
continue
|
|
cmds.delete(node)
|
|
if cmds.objExists(node):
|
|
# Node is locked or in reference and cannot be removed.
|
|
# As we cant remove it, we reset his data to avoid double pickers.
|
|
cmds.setAttr(
|
|
node + "." + PICKER_HOLDER_ATTRIBUTE, "", type="string")
|