Skip to content

Commit

Permalink
Merge branch 'fix/setattr' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
krathjen committed Feb 4, 2017
2 parents e536e8d + 6b7afaa commit a720b4b
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 28 deletions.
4 changes: 2 additions & 2 deletions src/studiolibrary/packages/mutils/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def saveAnim(
)

if not time:
time = mutils.animationFrameRange(objects)
time = mutils.selectedObjectsFrameRange(objects)

start, end = time

Expand Down Expand Up @@ -578,7 +578,7 @@ def save(self, path, time=None, bakeConnected=True, sampleBy=1, fileType=None):
fileType = fileType or DEFAULT_FILE_TYPE

if not time:
time = mutils.animationFrameRange(objects)
time = mutils.selectedObjectsFrameRange(objects)
start, end = time

# Check selected animation layers
Expand Down
154 changes: 128 additions & 26 deletions src/studiolibrary/packages/mutils/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
Example:
import mutils
attr = mutils.Attribute("sphere1", "translateX")
attr.set(100)
"""
import logging

try:
Expand All @@ -26,6 +32,37 @@
logger = logging.getLogger(__name__)


VALID_CONNECTIONS = [
"animCurve",
"animBlend",
"pairBlend",
"character"
]

VALID_BLEND_ATTRIBUTES = [
"int",
"long",
"float",
"short",
"double",
"doubleAngle",
"doubleLinear",
]

VALID_ATTRIBUTE_TYPES = [
"int",
"long",
"enum",
"bool",
"string",
"float",
"short",
"double",
"doubleAngle",
"doubleLinear",
]


class Attribute(object):

def __init__(self, name, attr, value=None, type=None):
Expand All @@ -36,64 +73,88 @@ def __init__(self, name, attr, value=None, type=None):
self._name = name.encode('ascii')
self._attr = attr.encode('ascii')
except UnicodeEncodeError:
raise UnicodeEncodeError('Not a valid ascii name "%s.%s"' % (name, attr))
msg = 'Not a valid ascii name "{0}.{1}"'.format(name, attr)
raise UnicodeEncodeError(msg)

self._type = type
self._value = value
self._fullname = None

def name(self):
"""
Return the Maya object name for the attribute.
:rtype: str
"""
return self._name

def attr(self):
"""
Return the attribute name.
:rtype: str
"""
return self._attr

def update(self):
"""
Make attribute dirty
"""
self._type = None
self._value = None

def fullname(self):
"""
Return the name with the attr name.
:rtype: str
"""
if self._fullname is None:
self._fullname = "%s.%s" % (self.name(), self.attr())
self._fullname = '{0}.{1}'.format(self.name(), self.attr())
return self._fullname

def value(self):
"""
:rtype: float | str | list[]
Return the value of the attribute.
:rtype: float | str | list
"""
if self._value is None:

try:
self._value = maya.cmds.getAttr(self.fullname())
except Exception:
logger.exception("Cannot GET attribute VALUE for {0}:".format(self.fullname()))
msg = 'Cannot GET attribute VALUE for "{0}"'
msg = msg.format(self.fullname())
logger.exception(msg)

return self._value

def type(self):
"""
Return the type of data currently in the attribute.
:rtype: str
"""
if self._type is None:

try:
self._type = maya.cmds.getAttr(self.fullname(), type=True)
self._type = self._type.encode('ascii')
except Exception:
logger.exception("Cannot GET attribute TYPE for %s: {0}:".format(self.fullname()))
msg = 'Cannot GET attribute TYPE for "{0}"'
msg = msg.format(self.fullname())
logger.exception(msg)

return self._type

def set(self, value, blend=100, key=False, **kwargs):
def set(self, value, blend=100, key=False, clamp=True):
"""
:type value: float | str | list[]
Set the value for the attribute.
:type key: bool
:type clamp: bool
:type value: float | str | list
:type blend: float
"""
try:
Expand All @@ -102,27 +163,37 @@ def set(self, value, blend=100, key=False, **kwargs):
else:
_value = (value - self.value()) * (blend/100.00)
value = self.value() + _value
except TypeError, msg:
logger.debug("Cannot BLEND attribute %s: Error: %s" % (self.fullname(), msg))
except TypeError, e:
msg = 'Cannot BLEND attribute {0}: Error: {1}'
msg = msg.format(self.fullname(), e)
logger.debug(msg)

try:
if self.type() in ["string"]:
maya.cmds.setAttr(self.fullname(), value, type=self.type())
elif self.type() in ["list", "matrix"]:
maya.cmds.setAttr(self.fullname(), *value, type=self.type())
else:
maya.cmds.setAttr(self.fullname(), value)
maya.cmds.setAttr(self.fullname(), value, clamp=clamp)

if key:
try:
self.key(value=value, **kwargs)
except TypeError, msg:
logger.debug("Cannot KEY attribute %s: Error: %s" % (self.fullname(), msg))
except (ValueError, RuntimeError), msg:
logger.debug("Cannot SET attribute %s: Error: %s" % (self.fullname(), msg))
self.setKeyframe(value=value)
except TypeError, e:
msg = 'Cannot KEY attribute {0}: Error: {1}'
msg = msg.format(self.fullname(), e)
logger.debug(msg)

except (ValueError, RuntimeError), e:
msg = "Cannot SET attribute {0}: Error: {1}"
msg = msg.format(self.fullname(), e)
logger.debug(msg)

def key(self, value, **kwargs):
def setKeyframe(self, value, **kwargs):
"""
Set a keyframe with the given value.
:rtype: None
"""
if kwargs:
maya.cmds.setKeyframe(self.fullname(), value=value, **kwargs)
Expand All @@ -131,8 +202,11 @@ def key(self, value, **kwargs):

def insertStaticKeyframe(self, value, time):
"""
Insert a static keyframe at the given time with the given value.
:type value: float | str
:type time: (int, int)
:rtype: None
"""
startTime, endTime = time
duration = endTime - startTime
Expand All @@ -142,10 +216,17 @@ def insertStaticKeyframe(self, value, time):
maya.cmds.setKeyframe(self.fullname(), value=value, time=(endTime, endTime), itt='flat', ott='flat')
nextFrame = maya.cmds.findKeyframe(self.fullname(), time=(endTime, endTime), which='next')
maya.cmds.keyTangent(self.fullname(), time=(nextFrame, nextFrame), itt='flat')
except TypeError, msg:
logger.debug("Cannot insert static key frame for attribute %s: Error: %s" % (self.fullname(), msg))
except TypeError, e:
msg = "Cannot insert static key frame for attribute {0}: Error: {1}"
msg = msg.format(self.fullname(), e)
logger.debug(msg)

def animCurve(self):
"""
Return the connected animCurve.
:rtype: str | None
"""
try:
return maya.cmds.listConnections(self.fullname(), destination=False,
type="animCurve")[0]
Expand All @@ -154,6 +235,8 @@ def animCurve(self):

def isConnected(self, ignoreConnections=None):
"""
Return true if the attribute is connected.
:type ignoreConnections: list[str]
:rtype: bool
"""
Expand All @@ -177,18 +260,21 @@ def isConnected(self, ignoreConnections=None):

def isBlendable(self):
"""
Return true if the attribute can be blended.
:rtype: bool
"""
return self.type() in ["float", "doubleLinear", "doubleAngle",
"double", "long", "int", "short"]
return self.type() in VALID_BLEND_ATTRIBUTES

def isSettable(self, validConnections=None):
"""
Return true if the attribute can be set.
:type validConnections: list[str]
:rtype: bool
"""
if validConnections is None:
validConnections = ["animCurve", "animBlend", "pairBlend", "character"]
validConnections = VALID_CONNECTIONS

if not self.exists():
return False
Expand All @@ -208,29 +294,40 @@ def isSettable(self, validConnections=None):

def isLocked(self):
"""
Return true if the attribute is locked.
:rtype: bool
"""
return maya.cmds.getAttr(self.fullname(), lock=True)

def isUnlocked(self):
"""
Return true if the attribute is unlocked.
:rtype: bool
"""
return not self.isLocked()

def toDict(self):
"""
:rtype: dict[]
Return a dictionary of the attribute object.
:rtype: dict
"""
result = {"type": self.type(), "value": self.value(), "fullname": self.fullname()}
result = {
"type": self.type(),
"value": self.value(),
"fullname": self.fullname(),
}
return result

def isValid(self):
"""
Return true if the attribute type is valid.
:rtype: bool
"""
return self.type() in ["string", "enum", "bool", "float", "doubleLinear",
"doubleAngle", "double", "long", "int", "short"]
return self.type() in VALID_ATTRIBUTE_TYPES

def __str__(self):
"""
Expand All @@ -240,11 +337,16 @@ def __str__(self):

def exists(self):
"""
Return true if the object and attribute exists in the scene.
:rtype: bool
"""
return maya.cmds.objExists(self.fullname())

def prettyPrint(self):
"""
Print the command for setting the attribute value
"""
print('maya.cmds.setAttr("%s", %s)' % (self.fullname(), self.value()))
msg = 'maya.cmds.setAttr("{0}", {1})'
msg = msg.format(self.fullname(), self.value())
print(msg)

0 comments on commit a720b4b

Please sign in to comment.