Package slumMaya :: Module classNode
[hide private]
[frames] | no frames]

Source Code for Module slumMaya.classNode

  1  # 
  2  # classNode - wraps a maya node as if it was a dictionary. Attrs are dictionary keys and 
  3  #                         adding a new key will add and attribute in the node. 
  4  #                         this class makes use of color/vector datatype (color.py and vector.py) to create color/vectors attributes 
  5  # 
  6  #    Copyright (C) 2008 - Roberto Hradec 
  7  # 
  8  # --------------------------------------------------------------------------- 
  9  #        This file is part of SLUM. 
 10  # 
 11  #    SLUM is free software: you can redistribute it and/or modify 
 12  #    it under the terms of the GNU General Public License as published by 
 13  #    the Free Software Foundation, either version 3 of the License, or 
 14  #    (at your option) any later version. 
 15  # 
 16  #    SLUM is distributed in the hope that it will be useful, 
 17  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 18  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 19  #    GNU General Public License for more details. 
 20  # 
 21  #    You should have received a copy of the GNU General Public License 
 22  #    along with SLUM.  If not, see <http://www.gnu.org/licenses/>. 
 23  # --------------------------------------------------------------------------- 
 24   
 25   
 26  import maya, os 
 27  import maya.mel as meval 
 28  import maya.cmds as m 
 29  import maya.OpenMaya as OpenMaya 
 30  from slum import * # color and vector datatypes 
 31   
32 -class classNode(dict):
33 ''' 34 wraps a maya node as if it was a dictionary. Attrs are dictionary keys and 35 adding a new key will add and attribute in the node. 36 this class makes use of color/vector classes (color.py and vector.py) to create color/vectors attributes 37 see slum for more info about color/vector classes 38 39 classNode also have some special methods that wraps some really usefull api methods, like setConnectable and 40 setInternal. 41 Also, some low level api methos to return an MObject of the node, a MFnDependecyNode object of the node and 42 MFnAttribute of the specified key (attribute) 43 '''
44 - def __init__(self, node, data=None):
45 self.node = node 46 if data != None: 47 if type(data) != dict: 48 raise Exception("'%s' can only be initialized with a dict" % self.__class__.__name__) 49 self.update(data)
50
51 - def attr(self, key):
52 return "%s.%s" % (self.node, key)
53
54 - def addAttr(self, key, item, hidden=False):
55 t = eval(item.__class__.__name__) 56 # check the item type and create a proper attr in the node to accomodate the data type 57 if not m.objExists( self.attr(key) ): 58 if t in [int,long]: 59 m.addAttr( self.node, ln=key, at='long', hidden=hidden ) 60 elif t==float: 61 m.addAttr( self.node, ln=key, at='float', hidden=hidden ) 62 elif t==bool: 63 m.addAttr( self.node, ln=key, at='bool', hidden=hidden ) 64 elif t == str: 65 m.addAttr( self.node, ln=key, dt='string', hidden=hidden ) 66 elif t in [vector, normal, color, point]: 67 isColor = False 68 dataTypes={ 69 vector: ['X','Y','Z'], 70 point: ['PX','PY','PZ'], 71 normal: ['NX','NY','NZ'], 72 color: ['R','G','B'], 73 } 74 children=dataTypes[t] 75 maya.cmds.addAttr( self.node, ln=key, at="float3", usedAsColor=t is color, hidden=False ) 76 maya.cmds.addAttr( self.node, ln="%s%s" % (key,children[0]), at="float", dv=int(item[0]), keyable=True, parent=key, hidden=False ) 77 maya.cmds.addAttr( self.node, ln="%s%s" % (key,children[1]), at="float", dv=int(item[1]), keyable=True, parent=key, hidden=False ) 78 maya.cmds.addAttr( self.node, ln="%s%s" % (key,children[2]), at="float", dv=int(item[2]), keyable=True, parent=key, hidden=False ) 79 else: 80 # if a unknown datatype, create a string attr and store as string 81 m.addAttr( self.node, ln=key, dt='string', hidden=True )
82
83 - def setAttr(self, key, item):
84 self.addAttr(key, item) 85 t = item.__class__.__name__ 86 if t=='str': 87 m.setAttr( self.attr(key), item, type="string" ) 88 elif t in ['vector', 'normal', 'color', 'point']: 89 m.setAttr( self.attr(key), item[0], item[1], item[2], type="double3" ) 90 elif t in ['dict','_dict','list','tuple']: #handle dict/list/tuple as special string data that will be retrieve as python dict/list/tuple 91 m.setAttr( self.attr(key), "%s/%s" % (item.__class__.__name__,str(item)), type="string" ) 92 else: 93 m.setAttr( self.attr(key), item )
94
95 - def getAttr(self, key):
96 if not m.objExists( self.attr(key) ): 97 raise Exception( 'Attribute %s does not exist in node.' % self.attr(key) ) 98 value = m.getAttr(self.attr(key)) 99 ret = value 100 t = type(ret) 101 if t in [str, unicode]: 102 ret = str(value) 103 # check if its a python dict, list or tuple. if so, return our wrapper to trigger updates automatically 104 dataType = ret.split('/')[0] 105 if dataType in ['dict','list','tuple']: 106 data = eval(ret.replace('%s/' % dataType,'')) 107 #print '\n\ntttttt:', data, '\n\n' 108 ret = self._dict(self, key) 109 ret.update(data, callingFromClassNode=True) 110 #print '\n\ntttttt:', ret, '\n\n' 111 elif t in [list]: 112 if m.objExists( "%sX" % self.attr(key) ): 113 ret = vector(value[0][0], value[0][1], value[0][2]) 114 elif m.objExists( "%sPX" % self.attr(key) ): 115 ret = point(value[0][0], value[0][1], value[0][2]) 116 elif m.objExists( "%sNX" % self.attr(key) ): 117 ret = normal(value[0][0], value[0][1], value[0][2]) 118 elif m.objExists( "%sR" % self.attr(key) ): 119 ret = color(value[0][0], value[0][1], value[0][2]) 120 else: 121 ret = [value[0][0], value[0][1], value[0][2]] 122 return ret
123
124 - def __setitem__(self, key, item):
125 self.setAttr(key, item)
126
127 - def __getitem__(self, key):
128 return self.getAttr(key)
129
130 - def __repr__(self):
131 name = self.__class__.__name__ 132 list = {} 133 for each in self.keys(): 134 list[each] = self.getAttr(each) 135 return "%s('%s',%s)" % (name, self.node, str(list) )
136 - def __str__(self):
137 return self.__repr__()
138
139 - def __len__(self):
140 return len(m.listAttr(self.node))
141
142 - def keys(self):
143 excluded = ['message'] 144 excludedTypes = ['TdataCompound'] 145 list = [] 146 for each in m.listAttr(self.node): 147 try: 148 if each not in excluded and '.' not in each: 149 if m.getAttr(self.attr(each), type=True) not in excludedTypes : 150 list.append(str(each)) 151 except: 152 pass 153 return list
154
155 - def has_key(self,f):
156 return f in m.listAttr(self.node)
157
158 - def update(self,f):
159 if type(f) != dict: 160 raise Exception('%s.update only accepts dicts' % self.__class__.__name__) 161 for each in f: 162 self.setAttr(each, f[each])
163
164 - def __delitem__(self, key):
165 m.deleteAttr(self.attr(key))
166 167 168 169
170 - def MObject(self):
171 list = OpenMaya.MSelectionList() 172 list.add( self.node ) 173 mobj = OpenMaya.MObject() 174 list.getDependNode( 0, mobj ) 175 return mobj
176
177 - def MFnDependencyNode(self):
178 return OpenMaya.MFnDependencyNode( self.MObject() )
179
180 - def MFnAttribute(self, key):
181 return OpenMaya.MFnAttribute( self.MFnDependencyNode().attribute( key ) )
182
183 - def _setNeededAttributes(self, key):
184 ret=[key] 185 if self.__getitem__(key).__class__.__name__ in ['color']: 186 ret.extend(['%sR' % key,'%sG' % key,'%sB' % key]) 187 elif self.__getitem__(key).__class__.__name__ in ['vector','normal','point']: 188 ret.extend(['%sX' % key,'%sY' % key,'%sZ' % key]) 189 return ret
190
191 - def setInternal(self, key, value=True):
192 for each in self._setNeededAttributes(key): 193 self.MFnAttribute(each).setInternal(value)
194
195 - def setReadable(self, key, value=True):
196 for each in self._setNeededAttributes(key): 197 self.MFnAttribute(each).setReadable(value)
198
199 - def setStorable(self, key, value=True):
200 for each in self._setNeededAttributes(key): 201 self.MFnAttribute(each).setStorable(value)
202
203 - def setWritable(self, key, value=True):
204 for each in self._setNeededAttributes(key): 205 self.MFnAttribute(each).setWritable(value)
206
207 - def setHidden(self, key, value=False):
208 for each in self._setNeededAttributes(key): 209 self.MFnAttribute(each).setHidden(value)
210
211 - def setConnectable(self, key, value=True):
212 for each in self._setNeededAttributes(key): 213 self.MFnAttribute(each).setConnectable(value)
214
215 - class _dict(dict):
216 ''' 217 _classNode = classNode that own this data 218 key = original key(attr) in the classnode 219 index = all the keys that are needed to get to this data from the original classNode attr(list) 220 '''
221 - def ____updateFromClassNode(self):
222 if not self.updatingFrom: 223 self.updatingFrom = True 224 dict.clear(self) 225 data = self._classNode.getAttr(self.key) 226 data.updatingFrom = True 227 index = "['%s']" % ']['.join(self.index) 228 if not self.index: 229 index="" 230 dict.update( self, eval( 'data%s' % index ) ) 231 data.updatingFrom = False 232 self.updatingFrom = False
233
234 - def ____updateToClassNode(self):
235 if not self.updating: 236 self.updating = True 237 data = self._classNode.getAttr(self.key) 238 data.updatingFrom = True 239 index = "['%s']" % ']['.join(self.index) 240 if not self.index: 241 index="" 242 exec( 'data%s=%s' % ( index, dict.__repr__(self) ) ) 243 self._classNode.setAttr(self.key, data) 244 #data.updatingFrom = False 245 self.updating = False
246
247 - def __init__(self, _classNode, key, index=[]):
248 self.updating = False 249 self.updatingFrom = False 250 dict.__init__(self) 251 self.key = key 252 self._classNode = _classNode 253 self.index = index
254 - def __setitem__(self, key, item):
255 t = item.__class__.__name__ 256 if t in ['dict','_dict']: 257 dict.__setitem__( self, key, _dict(self.classNode, self.key, self.index+[key]).update(item) ) 258 else: 259 dict.__setitem__(self, key, item) 260 self.____updateToClassNode()
261 - def update(self, data, callingFromClassNode=False):
262 if not callingFromClassNode: 263 self.____updateFromClassNode() 264 dict.update(self, data) 265 if not callingFromClassNode: 266 self.____updateToClassNode()
267 - def __delitem__(self, key):
268 self.____updateFromClassNode() 269 dict.__delitem__(self, key) 270 self.____updateToClassNode()
271 - def __getitem__(self, key):
272 #self.____updateFromClassNode() 273 return dict.__getitem__(self, key)
274 - def __repr__(self):
275 self.____updateFromClassNode() 276 return dict.__repr__(self)
277 - def __len__(self):
278 self.____updateFromClassNode() 279 return dict.__len__(self)
280 - def keys(self):
281 self.____updateFromClassNode() 282 return dict.keys(self)
283 - def has_key(self,f):
284 self.____updateFromClassNode() 285 return dict.has_key(self,f)
286 287 #need to add API utils to do affectsAttributo, callbacks, etc... 288