Skip to content

Commit

Permalink
Lots of usability updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mottosso committed Jun 7, 2021
1 parent d32d8b3 commit d1b39a1
Showing 1 changed file with 116 additions and 14 deletions.
130 changes: 116 additions & 14 deletions cmdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,36 @@ def dumps(self, indent=4, sort_keys=True, preserve_order=False):
sort_keys=sort_keys
)

def index(self, plug):
""" Find index of `attr` in its owning node
_____________
| |
| Friction o -> 126
| Mass o -> 127
| Color R o -> 128
| Color G o -> 129
| Color B o -> 130
| |
|_____________|
# TODO: This is really slow
"""

assert isinstance(plug, Plug), "%r was not a cmdx.Plug" % plug

node = plug.node()

for i in range(node._fn.attributeCount()):
attr = node._fn.attribute(i)
fn = om.MFnAttribute(attr)

if fn.shortName == plug.name(long=False):
return i

# Can happen if asking for an index of a plug from another node
raise ValueError("Index of '%s' not found" % plug.name())

def type(self):
"""Return type name
Expand Down Expand Up @@ -1680,7 +1710,7 @@ def mapTo(self, other, time=None):
# Alias
root = assembly

def parent(self, type=None):
def parent(self, type=None, filter=None):
"""Return parent of node
Arguments:
Expand All @@ -1694,6 +1724,13 @@ def parent(self, type=None):
>>> not child.parent(type="camera")
True
>>> parent.parent()
>>> child.parent(filter=om.MFn.kTransform) == parent
True
>>> child.parent(filter=om.MFn.kJoint) is None
True
Returns:
parent (Node): If any, else None
"""

Expand All @@ -1704,11 +1741,14 @@ def parent(self, type=None):

cls = self.__class__

if filter is not None and not mobject.hasFn(filter):
return None

if not type or type == self._fn.__class__(mobject).typeName:
return cls(mobject)

@protected
def lineage(self, type=None):
def lineage(self, type=None, filter=None):
"""Yield parents all the way up a hierarchy
Example:
Expand All @@ -1730,7 +1770,10 @@ def lineage(self, type=None):
parent = self.parent(type)
while parent is not None:
yield parent
parent = parent.parent(type)
parent = parent.parent(type, filter)

# Alias
parenthood = lineage

@protected
def children(self,
Expand Down Expand Up @@ -2740,7 +2783,10 @@ def clone(self, name, shortName=None, niceName=None):
if self.isCompound:
raise TypeError("Compound plugs are unsupported")

niceName = niceName or self.niceName
if niceName is False:
niceName = None
else:
niceName = niceName or self.niceName

# There is no way to tell whether the niceName of
# a plug is automatically generated by Maya or if
Expand Down Expand Up @@ -2864,6 +2910,10 @@ def nextAvailableIndex(self, startIndex=0):
# No connections means the first index is available
return 0

def pull(self):
"""Pull on a plug, without seriasing any value. For performance"""
self._mplug.asMObject()

def append(self, value, autofill=False):
"""Add `value` to end of self, which is an array
Expand Down Expand Up @@ -3005,7 +3055,7 @@ def asTransformationMatrix(self, time=None):

def asEulerRotation(self, order=kXYZ, time=None):
value = self.read(time=time)
return om.MEulerRotation(value, order)
return Euler(om.MEulerRotation(value, order))

asEuler = asEulerRotation

Expand All @@ -3018,6 +3068,10 @@ def asVector(self, time=None):
assert self.isArray or self.isCompound, "'%s' not an array" % self
return Vector(self.read(time=time))

def asPoint(self, time=None):
assert self.isArray or self.isCompound, "'%s' not an array" % self
return Point(self.read(time=time))

def asTime(self, time=None):
attr = self._mplug.attribute()
type = attr.apiType()
Expand Down Expand Up @@ -3050,6 +3104,30 @@ def connected(self):

return self.connection(destination=False) is not None

def animated(self, recursive=True):
"""Return whether this attribute is connected to an animCurve
Arguments:
recursive (bool, optional): Should I travel to connected
attributes in search of an animCurve, or only look to
the immediate connection?
"""

other = self.connection(destination=False, plug=True)
while other is not None:

node = other.node()
if node.object().hasFn(om.MFn.kAnimCurve):
return True

if not recursive:
break

other = other.connection(destination=False, plug=True)

return False

def lock(self):
"""Convenience function for plug.locked = True
Expand Down Expand Up @@ -3326,6 +3404,12 @@ def fn(self):
elif typ == om.MFn.kUnitAttribute:
fn = om.MFnUnitAttribute(attr)

elif typ in (om.MFn.kDoubleLinearAttribute,
om.MFn.kFloatLinearAttribute,
om.MFn.kDoubleAngleAttribute,
om.MFn.kFloatAngleAttribute):
return om.MFnUnitAttribute(attr)

elif typ == om.MFn.kTypedAttribute:
fn = om.MFnTypedAttribute(attr)

Expand All @@ -3338,7 +3422,9 @@ def fn(self):

else:
raise TypeError(
"Couldn't figure out function set for %s" % self
"Couldn't figure out function set for '%s.%s'" % (
self.path(), attr.apiTypeStr
)
)

return fn
Expand Down Expand Up @@ -3805,6 +3891,7 @@ def node(self):
as_euler = asEuler
as_quaternion = asQuaternion
as_vector = asVector
as_point = asPoint
as_time = asTime
channel_box = channelBox
lock_and_hide = lockAndHide
Expand Down Expand Up @@ -4148,7 +4235,7 @@ def __add__(self, value):
self.z + value,
)

return super(Vector, self).__add__(value)
return Vector(super(Vector, self).__add__(value))

def __iadd__(self, value):
if isinstance(value, (int, float)):
Expand All @@ -4158,13 +4245,13 @@ def __iadd__(self, value):
self.z + value,
)

return super(Vector, self).__iadd__(value)
return Vector(super(Vector, self).__iadd__(value))

def dot(self, value):
return super(Vector, self).__mul__(value)
return Vector(super(Vector, self).__mul__(value))

def cross(self, value):
return super(Vector, self).__xor__(value)
return Vector(super(Vector, self).__xor__(value))


# Alias, it can't take anything other than values
Expand Down Expand Up @@ -4824,6 +4911,9 @@ def _python_to_mod(value, plug, mod):
value = om.MAngle(value, om.MAngle.kRadians)
_python_to_mod(value, plug[index], mod)

elif isinstance(value, om.MQuaternion):
_python_to_mod(value.asEulerRotation(), plug, mod)

else:
raise TypeError(
"Unsupported plug type for modifier: %s" % type(value)
Expand Down Expand Up @@ -5209,7 +5299,6 @@ def setNiceName(self, plug, value=True):
plug = Plug(Node(plug.node()), plug)

assert isinstance(plug, Plug), "%s was not a plug" % plug
assert plug._mplug.isDynamic, "%s was not a dynamic attribute" % plug
self._niceNames.append((plug, value))

@record_history
Expand Down Expand Up @@ -6132,8 +6221,11 @@ def createNode(self, type, name=None, parent=None):

try:
mobj = self._modifier.createNode(type, parent)
except TypeError:
raise TypeError("'%s' is not a valid node type" % type)
except TypeError as e:
if e.message == "parent is not a transform type":
raise TypeError("'%s' is not a transform type," % parent)
else:
raise TypeError("'%s' is not a valid node type," % type)

template = self._opts["template"]
if name or template:
Expand All @@ -6156,6 +6248,9 @@ def parent(self, node, parent=None):
if SAFE_MODE:
self._modifier.doIt()

reparent = parent
reparentNode = parent

if ENABLE_PEP8:
create_node = createNode

Expand Down Expand Up @@ -7083,8 +7178,12 @@ def __init__(self, label, **kwargs):
kwargs.pop("fields", None)
kwargs.pop("label", None)

# Account for spaces in label
# E.g. "Hard Pin" -> "hardPin"
name = label[0].lower() + label[1:].replace(" ", "")

super(Divider, self).__init__(
label, fields=(label,), label=" ", **kwargs
name, fields=(label,), label=" ", **kwargs
)


Expand Down Expand Up @@ -7557,6 +7656,9 @@ def __init__(self, *args, **kwargs):
super(_apiUndo, self).__init__(*args, **kwargs)
_apiUndo._aliveCount += 1

self.undoId = None
self.redoId = None

def __del__(self):
_apiUndo._aliveCount -= 1

Expand Down

0 comments on commit d1b39a1

Please sign in to comment.