class SceneItem(object): """Kraken base object type for any 3D object.""" __kType__ = "SceneItem" def __init__(self, name, parent=None): super(SceneItem, self).__init__() self.name = name self.parent = None self.component = None self.children = [] self.flags = {} self.attributeGroups = [] self.constraints = [] self.xfo = Xfo() self.color = None self.visibility = True self.shapeVisibility = True if parent is not None: parent.addChild(self) defaultAttrGroup = AttributeGroup("") self.addAttributeGroup(defaultAttrGroup) # ============= # Name methods # ============= def getName(self): """Returns the name of the object as a string. Return: String of the object's name. """ return self.name def getFullName(self): """Returns the full hierarchical path to this object. Return: String, full name of the object. """ if self.parent is not None: return self.parent.getFullName() + '.' + self.getName() return self.getName() def getBuildName(self): """Returns the name used when building the node in the target application. Return: String, build name of the object. """ if self.component is not None: return self.component.getComponentName() + '_' + self.getName() return self.getName() # =============== # Parent Methods # =============== def getParent(self): """Returns the parent of the object as an object. Return: Parent of this object. """ return self.parent def setParent(self, parent): """Sets the parent attribute of this object. Arguments: parent -- Object, object that is the parent of this one. Return: True if successful. """ self.parent = parent return True # =============== # Hierarchy Methods # =============== def getLayer(self): """Returns the Layer of the object as an object. Return: Layer of this object. """ layer = self while (layer.__class__.__name__ != 'Layer'): layer = layer.parent return layer def getContainer(self): """Returns the Layer of the object as an object. Return: Layer of this object. """ container = self while (container.__class__.__name__ != 'Container'): container = container.parent return container # ================== # Component Methods # ================== def getComponent(self): """Returns the component of the object as an object. Return: Component of this object. """ return self.component def setComponent(self, component): """Sets the component attribute of this object. Arguments: component -- Object, object that is the component of this one. Return: True if successful. """ self.component = component return True # ============== # Child Methods # ============== def checkChildIndex(self, index): """Checks the supplied index is valid. Arguments: index -- Integer, child index to check. """ if index > len(self.children): raise IndexError("'" + str(index) + "' is out of the range of the 'children' array.") return True def addChild(self, child): """Adds a child to this object. Arguments: child -- Object, object that will be a child of this object. Return: True if successful. """ # TODO: WE NEED UNIQUE NAMES BUT WE HAVE A RESTRICTION CURRENTLY WHEN TWO OBJECTS OF DIFFERENT TYPES # NEED THE SAME NAME. i.e.: 'bicep' control and 'bicep' srtBuffer # if child.getName() in [x.getName() for x in self.children]: # raise IndexError("Child with name '" + child.getName() + "'' already exists as a child.") if child.getParent() is not None: parent = child.getParent() if child in parent.children: parent.children.remove(child) self.children.append(child) child.setParent(self) # Assign the child the same component. if self.component is not None: child.setComponent(self.component) return True def removeChildByIndex(self, index): """Removes a child from this object by index. Arguments: index -- Integer, index of child to remove. Return: True if successful. """ if self.checkChildIndex(index) is not True: return False del self.children[index] return True def removeChildByName(self, name): """Removes a child from this object by name. Arguments: name -- String, name of child to remove. Return: True if successful. """ removeIndex = None for i, eachChild in enumerate(self.children): if eachChild.getName() == name: removeIndex = i if removeIndex is None: raise ValueError("'" + name + "' is not a valid child of this object.") self.removeChildByIndex(removeIndex) return True def getNumChildren(self): """Returns the number of children this object has. Return: Integer, number of children of this object. """ return len(self.children) def getChildByIndex(self, index): """Returns the child object at specified index. Arguments: index -- Integer, index of the child to find. Return: Child object at specified index. """ if self.checkChildIndex(index) is not True: return False return self.children[index] def getChildByName(self, name): """Returns the child object with the specified name. Return: Object if found. None if not found. """ for eachChild in self.children: if eachChild.getName() == name: return eachChild return None def getChildrenByType(self, childType): """Returns all children that are of the specified type. Arguments: childType -- Class, type of children to find. Return: Array of child objects of the specified type. None if no objects of specified type are found. """ childrenOfType = [] for eachChild in self.children: if type(eachChild) is childType: childrenOfType.append(eachChild) return childrenOfType def findChild(self, name, targetObj=None): """Finds a child by recursively searching the hierarhcy for a child with the given name. Arguments: name -- String, name of the child to find. targetObj -- Object, object to search under. Used for recursive searching. Return: Object, child if found. """ foundChild = None if targetObj == None: targetObj = self # Build children for i in xrange(targetObj.getNumChildren()): child = targetObj.getChildByIndex(i) if child.getName() == name: foundChild = child else: foundChild = self.findChild(name, child) if foundChild is not None: break return foundChild def findChildrenByType(self, objectType, targetObj=None): """Finds a child by recursively searching the hierarhcy for a child with the given name. Arguments: objectType -- Class, type of children to find. targetObj -- Object, object to search under. Used for recursive searching. Return: List, children of the searched type if found. """ childrenOfType = [] self._findChildByType(objectType, childrenOfType) return childrenOfType def _findChildByType(self, objectType, foundArray, targetObj=None): """Protected find child by type method. Arguments: objectType -- Class, type of children to find. foundArray -- List, list of found children to append to. targetObj -- Object, object to search under. Used for recursive searching. Return: True if successful. """ if targetObj == None: targetObj = self # Build children for i in xrange(targetObj.getNumChildren()): child = targetObj.getChildByIndex(i) if type(child) is objectType: foundArray.append(child) newFoundChildren = self._findChildByType(objectType, foundArray, child) return # ============= # Flag Methods # ============= def setFlag(self, name): """Sets the flag of the specified name. Return: True if successful. """ self.flags[name] = True return True def testFlag(self, name): """Tests if the specified flag is set. Arguments: name -- String, name of the flag to test. Return: True if flag is set, false otherwise. """ if name in self.flags: return True return False def clearFlag(self, name): """Clears the flag of the specified name. Arguments: name -- String, name of the flag to clear. Return: True if successful. """ if name in self.flags: del self.flags[name] return True return False # ======================== # Attribute Group Methods # ======================== def checkAttributeGroupIndex(self, index): """Checks the supplied index is valid. Arguments: index -- Integer, attribute index to check. Return: True if successful. """ if index > len(self.attributeGroups): raise IndexError("'" + str(index) + "' is out of the range of 'attributeGroups' array.") return True def addAttributeGroup(self, attributeGroup): """Adds an attributeGroup to this object. Arguments: attributeGroup -- Object, Attribute Group object to add to this object. Return: True if successful. """ if attributeGroup.getName() in [x.getName() for x in self.attributeGroups]: raise IndexError("Child with " + attributeGroup.getName() + " already exists as a attributeGroup.") self.attributeGroups.append(attributeGroup) attributeGroup.setParent(self) return True def removeAttributeGroupByIndex(self, index): """Removes attribute at specified index. Arguments: index -- Integer, index of attribute to remove. Return: True if successful. """ if self.checkAttributeGroupIndex(index) is not True: return False del self.attributeGroups[index] return True def removeAttributeGroupByName(self, name): """Removes the attribute with the specified name. Arguments: name -- String, name of the attribute to remove. Return: True if successful. """ removeIndex = None for i, eachAttributeGroup in enumerate(self.attributeGroups): if eachAttributeGroup.getName() == name: removeIndex = i if removeIndex is None: return False self.removeAttributeGroupByIndex(removeIndex) return True def getNumAttributeGroups(self): """Returns the number of attributeGroups as an integer. Return: Integer of the number of attributeGroups on this object. """ return len(self.attributeGroups) def getAttributeGroupByIndex(self, index): """Returns the attribute at the specified index. Arguments: index -- Integer, index of the attribute to return. Return: AttributeGroup at the specified index. False if not a valid index. """ if self.checkAttributeGroupIndex(index) is not True: return False return self.attributeGroups[index] def getAttributeGroupByName(self, name): """Return the attribute group with the specified name. Arguments: name -- String, name of the attribute group to return. Return: Attribute with the specified name. None if not found. """ for eachAttributeGroup in self.attributeGroups: if eachAttributeGroup.getName() == name: return eachAttributeGroup return None # =================== # Constraint Methods # =================== def checkConstraintIndex(self, index): """Checks the supplied index is valid. Arguments: index -- Integer, constraint index to check. Return: True if successful. """ if index > len(self.constraints): raise IndexError("'" + str(index) + "' is out of the range of 'constraints' array.") return True def addConstraint(self, constraint): """Adds an constraint to this object. Arguments: constraint -- Object, Constraint object to add to this object. Return: True if successful. """ if constraint.getName() in [x.getName() for x in self.constraints]: raise IndexError("Constraint with name '" + constraint.getName() + "'' already exists as a constraint.") self.constraints.append(constraint) constraint.setParent(self) constraint.setConstrainee(self) return True def removeConstraintByIndex(self, index): """Removes constraint at specified index. Arguments: index -- Integer, index of constraint to remove. Return: True if successful. """ if self.checkConstraintIndex(index) is not True: return False del self.constraints[index] return True def removeConstraintByName(self, name): """Removes the constraint with the specified name. Arguments: name -- String, name of the constraint to remove. Return: True if successful. """ removeIndex = None for i, eachConstraint in enumerate(self.constraints): if eachConstraint.getName() == name: removeIndex = i if removeIndex is None: return False self.removeConstraintByIndex(removeIndex) return True def getNumConstraints(self): """Returns the number of constraints as an integer. Return: Integer of the number of constraints on this object. """ return len(self.constraints) def getConstraintByIndex(self, index): """Returns the constraint at the specified index. Arguments: index -- Integer, index of the constraint to return. Return: Constraint at the specified index. False if not a valid index. """ if self.checkConstraintIndex(index) is not True: return False return self.constraints[index] def getConstraintByName(self, name): """Return the constraint group with the specified name. Arguments: name -- String, name of the constraint group to return. Return: Attribute with the specified name. None if not found. """ for eachConstraint in self.constraints: if eachConstraint.getName() == name: return eachConstraint return None # ============== # kType Methods # ============== def getKType(self): """Returns the kType of this object. Return: True if successful. """ return self.__kType__ # =================== # Visibility Methods # =================== def getVisibility(self): """Returns the visibility status of the scene item. Return: Boolean, visible or not. """ return self.visibility def setVisibility(self, value): """Sets the visibility of the scene object. Arguments: value -- Boolean, value of the visibility of the object. Return: True if successful. """ self.visibility = value return True def getShapeVisibility(self): """Returns the shape visibility status of the scene item. Return: Boolean, visible or not. """ return self.shapeVisibility def setShapeVisibility(self, value): """Sets the shape visibility of the scene object. Arguments: value -- Boolean, value of the visibility of the object. Return: True if successful. """ self.shapeVisibility = value return True # ================ # Display Methods # ================ def setColor(self, color): """Sets the color of this object. Arguments: color -- String, name of the color you wish to set. Return: True if successful. """ self.color = color return True def getColor(self): """Returns the color of the object. Return: String, color of the object. """ return self.color # ================== # Transform Methods # ================== def lockAttribute(self, attributeName): pass def unlockAttribute(self, attributeName): pass def hideAttribute(self, attributeName): pass def unhideAttribute(self, attributeName): pass # ==================== # Persistence Methods # ==================== def jsonEncode(self, saver): """Returns the data for this object encoded as a JSON hierarchy. Arguments: Return: A JSON structure containing the data for this SceneItem. """ classHierarchy = [] for cls in type.mro(type(self)): if cls == object: break; classHierarchy.append(cls.__name__) jsonData = { '__typeHierarchy__': classHierarchy, 'name': self.name, 'parent': None, 'children': [], 'flags': self.flags, 'attributeGroups': [], 'constraints': [], 'xfo': self.xfo.jsonEncode(), 'color': self.color, 'visibility': self.visibility, 'shapeVisibility': self.shapeVisibility, } if self.parent is not None: jsonData['parent'] = self.parent.getName() if self.color is not None: jsonData['color'] = saver.encodeValue(self.color) for child in self.children: jsonData['children'].append(child.jsonEncode(saver)) for attrGroup in self.attributeGroups: jsonData['attributeGroups'].append(attrGroup.jsonEncode(saver)) for constr in self.constraints: jsonData['constraints'].append(constr.jsonEncode(saver)) return jsonData def jsonDecode(self, loader, jsonData): """Returns the color of the object. Return: True if decoding was successful """ self.parent = loader.getParentItem() self.flags = jsonData['flags'] self.xfo = loader.decodeValue(jsonData['xfo']) if 'color' in jsonData and jsonData['color'] is not None: self.color = loader.decodeValue(jsonData['color']) self.visibility = jsonData['visibility'] self.shapeVisibility = jsonData['shapeVisibility'] for child in jsonData['children']: self.addChild(loader.construct(child)) for attrGroup in jsonData['attributeGroups']: # There is one default attribute group assigned to each scene item. # Load data into the existing item instead of constructing a new one. if attrGroup['name'] == '': loader.registerItem(self.attributeGroups[0]) self.attributeGroups[0].jsonDecode(loader, attrGroup) else: self.addAttributeGroup(loader.construct(attrGroup)) for constr in jsonData['constraints']: self.addConstraint(loader.construct(constr)) return True