Esempio n. 1
0
 def saveCharacter( self ):
     '''
     Save the character into an XML file for re-use.
     '''        
     charNode = self.characterDict[self.SAVE_SELECTED_CHARACTER]
     charBitName = Components.CharacterRootComponent( charNode ).parentNode[0]
     XMLUtility.writeModuleXML( charBitName, 'characters', self.SAVE_SELECTED_CHARACTER )
Esempio n. 2
0
 def saveModule( self ):
     '''
     Save the module into an XML file for re-use.
     We assume that the root node of the module is the one with the module root meta node.
     This means it and all of it's children will be saved in the XML.
     '''
     # Get the selected module
     item = cmds.ls( long=True, selection=True )[0]
     
     # Try to get the module meta component.
     moduleComp = Components.searchModule( item, 'ModuleRootComponent' )
     
     if moduleComp:
         # Get the module info and save it as an XML.
         modulePlug = NodeUtility.getPlug( moduleComp[1], 'moduleName' )
         moduleName = NodeUtility.getPlugValue( modulePlug )
         XMLUtility.writeModuleXML( moduleComp[0], self.SELECTED_ITEM, moduleName )
Esempio n. 3
0
    def updateCards( self ):
        '''
        Updates the character cards.
        '''
        # Clear the lattice list first.
        clearLayout( self.scrollLayout )

        presetsPath = '{0}{1}/'.format( XMLUtility.FRAME_PRESETS_PATH, 'characters' )
        latticePresets = XMLUtility.getXMLInFolder( presetsPath )
        for lattice in latticePresets:
            description = 'From here you can search these documents. Enter your search words into the box below and click /"search/".'
            self.scrollLayout.addWidget( QTWidgets.latticeCard( 'characters', lattice, description, parent=self.scrollLayout ) )
Esempio n. 4
0
 def updateCards( self ):
     # Clear the lattice list first.
     clearLayout( self.scrollLayout )
     
     # Get all the active toggle buttons.
     for index in xrange( self.togLayout.count() ):
         button = self.togLayout.itemAt( index ).widget()
         if isinstance( button, QtGui.QToolButton ):
             if button.isChecked():
                 buttonType = button.text()
                 presetsPath = '{0}{1}/'.format( XMLUtility.FRAME_PRESETS_PATH, buttonType )
                 latticePresets = XMLUtility.getXMLInFolder( presetsPath )
                 for lattice in latticePresets:
                     description = 'From here you can search these documents. Enter your search words into the box below and click /"search/".'
                     self.scrollLayout.addWidget( latticeCard( buttonType, lattice, description, parent=self.scrollLayout ) )
Esempio n. 5
0
def getAttrXML( presets=False ):    
    presetPath = XMLUtility.getPresetPath( '' )
    fullPath = '{0}frames/bits/bitAttributes.xml'.format( presetPath )
    returnList = []
    xmlDoc = ET.parse( fullPath )
    xmlRoot = xmlDoc.getroot()
    
    if presets:
        presetList = xmlRoot.find( 'presets' )
        for preset in presetList.findall( 'preset' ):
            tempList = { 'presetName':preset.get('name') }
            tempList['attrs'] = []
            for attr in preset.findall( 'attr' ):
                tempList['attrs'].append( attr.get('name') )
            returnList.append( tempList )
    else:
        attrList = xmlRoot.find( 'attributes' )
        for attr in attrList.findall( 'attr' ):
            returnList.append( { 'name':attr.get('name'), 'attrType':attr.get('attrType'), 'attrDataType':attr.get('attrDataType') } )    
    return returnList
Esempio n. 6
0
 def fillButtons( self, *args ):
     # This fills gridLayout with the appropriate buttons.        
     # Check if buttons already exist. If they do, delete them.
     gridChildren = cmds.gridLayout( self.frameGrid, query=True, childArray=True )
     if gridChildren is not None:
         for c in gridChildren:
             cmds.deleteUI( c )
     
     # Get the children of toggle buttons column.
     checkBoxChildren = cmds.rowColumnLayout( self.toggleColumn, query=True, childArray=True )
     for checkBox in checkBoxChildren:
         # Loop through the children to see if they are active.
         boxValue = cmds.symbolCheckBox( checkBox, query=True, value=True )
         if boxValue == True:
             # If the button is active then we need to make the appropriate frame
             # buttons in the grid layout.
             boxAnno = cmds.symbolCheckBox( checkBox, query=True, annotation=True )
             frameFiles = XMLUtility.getXMLInFolder( XMLUtility.FRAME_PRESETS_PATH+boxAnno+'/' )   
             for frame in frameFiles:
                 # Make the grid layout buttons. The label is the file name, while
                 # the annotation is the folder name.
                 cmds.button( parent=self.frameGrid, label=frame, annotation=boxAnno, command=lambda v, a1=frame, a2=boxAnno: buttonTest(v, a1, a2) )
Esempio n. 7
0
def buildFrameModule( inDir=None, inXMLFile=None ):
    from marigold.meta.metaNode import MetaNode
    
    # Get the XML settings for the frame module.
    dirPath = XMLUtility.getPresetPath( XMLUtility.FRAME_PRESETS_PATH+inDir )
    fullPath = dirPath+'/'+inXMLFile+'.xml'
    xmlDict = readFrameModuleXML( fullPath )
    
    # Get the metanode.
    metanode = xmlDict['metanode']
    meta = metanode['name']
    metaPlugs = metanode['plugs']
    metaType = metanode['metaType']
    metaClass = metanode['metaClass']
    
    metanode = MetaNode( inNodeName=meta, inNodeMetaType=metaType )
    metanode = cmds.ls( selection=True )[0]
    
    metaPlugs = xmlDict['metanode']['plugs']
    for plug in metaPlugs:
        if not NodeUtility.attributeCheck( metanode, plug['name'] ):
            addPlug( metanode, plug['name'], plug['attrType'], plug['attrDataType'] )
        if plug['connected'] == 'False':
            setPlug( metanode, plug['name'], plug['value'], inAttrDataType=plug['attrDataType'] )
    
    # Get the bits.
    bits = xmlDict['bits']
    
    # Make a group for the module.
    for bit in bits:
        if bit['name'] == 'frame_root':
            for plug in bit['plugs']:
                if plug['name'] == 'prefix':
                    modulePrefix = plug['value']
                    break
                
    moduleGroup = '|{0}'.format( cmds.group( em=True, name=modulePrefix+'_'+metaClass ) )

    # Make each bit.
    tick = 0
    storeBitConnections = []

    while tick < len(bits):
        bitName = bits[0]['name']
        if bits[0]['parent'] == 'None':
            # This is the root bit. The | is there to represent this. We don't need it now.
            # Plus it causes problems with the full path name stuff (double ||). So we
            # remove it.
            bitParent = moduleGroup
        else:
            bitParent = moduleGroup+bits[0]['parent']
        bitPlugs = bits[0]['plugs']
        bitShape = bits[0]['shape']
        
        # Make the bit.
        if cmds.objExists( bitParent ):
            newBit = cmds.makeGLBit( name=bitName, objecttype=bits[0]['shapeType'] )            
            cmds.parent( newBit, bitParent )
            
            # From this point we use the long name for the bit. This avoids any
            # name clashes.
            fullBitName = '{0}{1}'.format( bitParent, newBit )
            # Get the frame_root for the module. We want to return this at the very end.
            if bitName == 'frame_root':
                rootFullName = fullBitName
            
            # Setup plugs for transform and custom attributes.
            for plug in bitPlugs:
                if not NodeUtility.attributeCheck( fullBitName, plug['name'] ):
                    addPlug( fullBitName, plug['name'], plug['attrType'], plug['attrDataType'] )
                    if plug['value'] is not None:
                        setPlug( fullBitName, plug['name'], plug['value'], inAttrDataType=plug['attrDataType'] )
                else:          
                    # Setup position and rotation.
                    setPlug( fullBitName, plug['name'], plug['value'] )
            
                # Connect plug to meta node.
                for mplug in metaPlugs:
                    if '{0}.{1}'.format(bitName, plug['name']) == mplug['value']:
                        inSourcePlug = fullBitName+'.'+plug['name']
                        inDestinationPlug = metanode+'.'+mplug['name']
                        NodeUtility.connectPlugs( inSourcePlug, inDestinationPlug )
                        
            # Setup plugs for shape attributes.
            shapeName = cmds.listRelatives( fullBitName, shapes=True )
            fullShapeName = '{0}|{1}'.format( fullBitName, shapeName[0] )
            for plug in bitShape:
                if plug['attrDataType'] == 'TdataCompound':
                    # We skip compound nodes at this stage. They are for the child arrow drawing and must be
                    # hooked up after all the objects are created.
                    connectionChild = '{0}{1}'.format( moduleGroup, plug['value'] )
                    storeBitConnections.append( { 'parent':fullBitName, 'child':connectionChild } )
                else:
                    setPlug( fullShapeName, plug['name'], plug['value'], inAttrDataType=plug['attrDataType'] )
                           
            bits.remove( bits[0] )
        else:
            tick = tick+1
            pass
    
    # Now do the hook ups for the child arrows.
    for i in storeBitConnections:
        setBitChild( i['parent'], i['child'] )
    
    return rootFullName
Esempio n. 8
0
def readFrameModuleXML( inFile=None, inCallScript=False ):
    '''
    Processes an XML file to get the parts/settings for the module.
    
    @param inFullPath: Full directory path + filename + extension of the XML file.
    @return: A dictionary.
    '''
    import xml.etree.ElementTree as ET
    
    if inFile is None:
        # Browse for file to replace or new file to make.
        moduleFilter = "*.xml"
        dialogResults = cmds.fileDialog2( fileFilter=moduleFilter, dialogStyle=2, startingDirectory=XMLUtility.getPresetPath( XMLUtility.FRAME_PRESETS_PATH ) )
    else:
        dialogResults = [ inFile ]
    
    returnDict = {}
    xmlDoc = ET.parse( dialogResults[0] )
    xmlRoot = xmlDoc.getroot()

    # Process meta nodes.
    for metanode in xmlRoot.findall( 'metanode' ):
        metaType = metanode.get( 'metaType' )
        returnDict[ 'metanode' ] = { 'name':metanode.get('name'), 'metaType':metanode.get('metaType'), 'metaClass':metanode.get('metaClass') }
        
        plugList = []
        for plug in metanode.findall( 'plug' ):
            plugList.append( { 'name':plug.get('name'), 'connected':plug.get('connected'), 'attrType':plug.get('attrType'), 'attrDataType':plug.get('attrDataType'), 'value':plug.text } )
        returnDict[ 'metanode' ].update( { 'plugs':plugList } )
        
    # Process bit nodes.
    bitList = []
    for bit in xmlRoot.findall( 'bit' ):
        # Get shape type.
        shape = bit.findall( 'shape' )
        shapeType = shape[0].get('name')
        
        bitDict = { 'name':bit.get('name'), 'parent':bit.get('parent'), 'shapeType':shapeType }
        
        plugList = []
        for plug in bit.findall( 'plug' ):
            plugList.append( { 'name':plug.get('name'), 'attrType':plug.get('attrType'), 'attrDataType':plug.get('attrDataType'), 'value':plug.text } )
        bitDict[ 'plugs' ] = plugList
        
        shapePlugList = []
        for plug in shape[0].findall( 'plug' ):
            shapePlugList.append( { 'name':plug.get('name'), 'attrType':plug.get('attrType'), 'attrDataType':plug.get('attrDataType'), 'value':plug.text } )
        bitDict[ 'shape' ] = shapePlugList
        
        bitList.append( bitDict )
        
        returnDict[ 'bits' ] = bitList
    
    # Call the script.
    if inCallScript:
        pass
    else:    
        # Or just return the list.
        return returnDict
Esempio n. 9
0
def createFrameModuleXML():
    # Browse for file to replace or new file to make.
    moduleFilter = "*.xml"
    dialogResults = cmds.fileDialog2( fileFilter=moduleFilter, dialogStyle=2, startingDirectory=XMLUtility.getPresetPath( XMLUtility.FRAME_PRESETS_PATH ) )
    tempPath = dialogResults[0].split( '/' )
    fullFileName = tempPath[ len( tempPath )-1 ]
    filePath = dialogResults[0].rstrip( fullFileName )
    fileName = fullFileName.split( '.' )[0]
    
    # Get the name of the selected node and it's plugs.
    selList = cmds.ls( selection=True )
    node = selList[0]
    nodeAttrs = getFrameBitSettings( node )
    
    # Build a list with each entry representing a line in the XML file.
    xmlList = []
    xmlList.append( '<data>' ) # Set the first line
    
    # Meta node.
    xmlList.append( '\t<metanode name=\"{0}\" metaType=\"{1}\" metaClass=\"{2}\">'.format( node, nodeAttrs['metaType'], nodeAttrs['metaClass'] ) )
    
    # Loop through the attributes.
    for attr in nodeAttrs:
        plug = NodeUtility.getPlug( node, attr )
        if plug.isConnected():
            connection = NodeUtility.getNodeAttrSource( node, attr )
            types = getAttrTypes( node, attr )
            xmlList.append( '\t\t<plug name=\"{0}\" connected=\"{1}\" attrType=\"{2}\" attrDataType=\"{3}\">{4}</plug>'.format( attr,
                                                                                                                                True,
                                                                                                                                types[0],
                                                                                                                                types[1],
                                                                                                                                connection[0]+'.'+connection[1] ) )
        else:
            types = getAttrTypes( node, attr )
            xmlList.append( '\t\t<plug name=\"{0}\" connected=\"{1}\" attrType=\"{2}\" attrDataType=\"{3}\">{4}</plug>'.format( attr,
                                                                                                                                False,
                                                                                                                                types[0],
                                                                                                                                types[1],
                                                                                                                                NodeUtility.getPlugValue( plug ) ) )
    xmlList.append( '\t</metanode>' )
    
    # Get the root bit of the frame module.
    rootBit = NodeUtility.getNodeAttrSource( node, 'rootBit' )
    if not rootBit:
        raise ValueError( 'The meta node\'s ({0}) ROOT BIT attribute is not connected.'.format(node) )

    # Get the parent's full path. We need to remove the group name from the beginning as well.
    parent = cleanParentFullName( rootBit[0] )

    
    xmlList.append( '\t<bit name=\"{0}\" parent=\"{1}\">'.format( rootBit[0], parent ) )
    rootAttrs = getFrameBitSettings( rootBit[0] )
    for attr in rootAttrs:
        types = getAttrTypes( rootBit[0], attr )
        plug = NodeUtility.getPlug( rootBit[0], attr )
        xmlList.append( '\t\t<plug name=\"{0}\" attrType=\"{1}\" attrDataType=\"{2}\">{3}</plug>'.format( attr,
                                                                                                          types[0],
                                                                                                          types[1],
                                                                                                          NodeUtility.getPlugValue( plug ) ) )
    
    wmRootBit = TransformUtility.getMatrix( rootBit[0], 'matrix' )
    pos = TransformUtility.getMatrixTranslation( wmRootBit, OpenMaya.MFn.kWorld )
    rot = TransformUtility.getMatrixRotation( wmRootBit, 'eulerVector' )
    xmlList.append( '\t\t<plug name=\"translateX\">{0}</plug>'.format( pos.x ) )
    xmlList.append( '\t\t<plug name=\"translateY\">{0}</plug>'.format( pos.y ) )
    xmlList.append( '\t\t<plug name=\"translateZ\">{0}</plug>'.format( pos.z ) )
        
    xmlList.append( '\t\t<plug name=\"rotateX\">{0}</plug>'.format( math.degrees(rot.x) ) )
    xmlList.append( '\t\t<plug name=\"rotateY\">{0}</plug>'.format( math.degrees(rot.y) ) )
    xmlList.append( '\t\t<plug name=\"rotateZ\">{0}</plug>'.format( math.degrees(rot.z) ) )
    
    # Shape nodes attributes.
    rootShape = NodeUtility.getDagPath( rootBit[0] ).child( 0 )
    depFn = OpenMaya.MFnDependencyNode( rootShape )
    shapeName = cmds.listRelatives( rootBit[0], shapes=True, fullPath=True )[0]
    shapeType = depFn.typeName()
    xmlList.append( '\t\t<shape name=\"{0}\">'.format( shapeType ) )
    
    # Get the shape's local position and scale.
    for attr in cmds.listAttr( shapeName, channelBox=True ):
        types = getAttrTypes( shapeName, attr )
        aPlug = NodeUtility.getPlug( shapeName, attr )
        xmlList.append( '\t\t\t<plug name=\"{0}\" attrType=\"{1}\" attrDataType=\"{2}\">{3}</plug>'.format( attr,
                                                                                                            types[0],
                                                                                                            types[1],
                                                                                                            NodeUtility.getPlugValue(aPlug) ) )
        
    # Get the shape's custom attributes.
    for attr in cmds.listAttr( shapeName, multi=True, keyable=True ):
        if attr.find( '[' ) is not -1:
            # Special case handle array attributes. The [] needs to be removed so we can get
            # the base name for the attribute. From there we can then loop through it's children.
            # First we get the connection since these plugs won't return a value, but rather a
            # connected node.
            connection = NodeUtility.getNodeAttrSource( shapeName, attr )
            bitChildren = cmds.listRelatives( rootBit[0], type='transform', children=True, fullPath=True )
            for child in bitChildren:
                if child.find( connection[0] ):
                    plugValue = child
            
            # Now we get the compound attribute's name by removing the index brackets.
            attrSplit = attr.split('[')
            attr = attrSplit[0]
        else:
            aPlug = NodeUtility.getPlug( shapeName, attr )
            plugValue = NodeUtility.getPlugValue( aPlug )
            
        types = getAttrTypes( shapeName, attr )
        if types[0] is not False:
            xmlList.append( '\t\t\t<plug name=\"{0}\" attrType=\"{1}\" attrDataType=\"{2}\">{3}</plug>'.format( attr,
                                                                                                                types[0],
                                                                                                                types[1],
                                                                                                                plugValue ) )
    xmlList.append( '\t\t</shape>' )
    xmlList.append( '\t</bit>')

    # Get all of the root's children.
    children = getFrameRootAllChildren( rootBit[0] )
    for child in children:
        # Bit name.
        bitName = child
        parent = cleanParentFullName( child )
        childFrameAttrs = getFrameBitSettings( child )
        xmlList.append( '\t<bit name=\"{0}\" parent=\"{1}\">'.format( bitName, parent ) )
    
        # Transform nodes attributes.
        if childFrameAttrs is not None:
            for attr in childFrameAttrs:
                types = getAttrTypes( child, attr )
                plug = NodeUtility.getPlug( child, attr )
                xmlList.append( '\t\t<plug name=\"{0}\" attrType=\"{1}\" attrDataType=\"{2}\">{3}</plug>'.format( attr,
                                                                                                                  types[0],
                                                                                                                  types[1],
                                                                                                                  NodeUtility.getPlugValue( plug ) ) )
        
        # Get the position and rotation.
        wmBit = TransformUtility.getMatrix( child, 'matrix' )
        pos = TransformUtility.getMatrixTranslation( wmBit, OpenMaya.MFn.kWorld )
        rot = TransformUtility.getMatrixRotation( wmBit, 'eulerVector' )
        
        xmlList.append( '\t\t<plug name=\"translateX\">{0}</plug>'.format( pos.x ) )
        xmlList.append( '\t\t<plug name=\"translateY\">{0}</plug>'.format( pos.y ) )
        xmlList.append( '\t\t<plug name=\"translateZ\">{0}</plug>'.format( pos.z ) )
        xmlList.append( '\t\t<plug name=\"rotateX\">{0}</plug>'.format( math.degrees(rot.x) ) )
        xmlList.append( '\t\t<plug name=\"rotateY\">{0}</plug>'.format( math.degrees(rot.y) ) )
        xmlList.append( '\t\t<plug name=\"rotateZ\">{0}</plug>'.format( math.degrees(rot.z) ) )
        
        # Shape nodes attributes.
        childShape = NodeUtility.getDagPath( child ).child( 0 )
        depFn = OpenMaya.MFnDependencyNode( childShape )
        shapeName = cmds.listRelatives( child, shapes=True, fullPath=True )[0]
        shapeType = depFn.typeName() 
        xmlList.append( '\t\t<shape name=\"{0}\">'.format( shapeType ) )
        
        # Get the shape's local position and scale.
        for attr in cmds.listAttr( shapeName, channelBox=True ):
            types = getAttrTypes( shapeName, attr )
            aPlug = NodeUtility.getPlug( shapeName, attr )
            xmlList.append( '\t\t\t<plug name=\"{0}\" attrType=\"{1}\" attrDataType=\"{2}\">{3}</plug>'.format( attr,
                                                                                                                types[0],
                                                                                                                types[1],
                                                                                                                NodeUtility.getPlugValue(aPlug) ) )
            
        # Get the shape's custom attributes.
        for attr in cmds.listAttr( shapeName, multi=True, keyable=True ):
            if attr.find( '[' ) is not -1:
                # Special case handle array attributes. The [] needs to be removed so we can get
                # the base name for the attribute. From there we can then loop through it's children.
                # First we get the connection since these plugs won't return a value, but rather a
                # connected node.
                connection = NodeUtility.getNodeAttrSource( shapeName, attr )
                bitChildren = cmds.listRelatives( child, type='transform', children=True, fullPath=True )
                for c in bitChildren:
                    if c.find( connection[0] ):
                        plugValue = c
                
                # Now we get the compound attribute's name by removing the index brackets.
                attrSplit = attr.split('[')
                attr = attrSplit[0]
            else:
                aPlug = NodeUtility.getPlug( shapeName, attr )
                plugValue = NodeUtility.getPlugValue( aPlug )
                
            types = getAttrTypes( shapeName, attr )
            if types[0] is not False:
                xmlList.append( '\t\t\t<plug name=\"{0}\" attrType=\"{1}\" attrDataType=\"{2}\">{3}</plug>'.format( attr,
                                                                                                                    types[0],
                                                                                                                    types[1],
                                                                                                                    plugValue ) )
        xmlList.append( '\t\t</shape>' )  
        
        # Close the bit.
        xmlList.append( '\t</bit>' )
            
    # Close the data tag.
    xmlList.append( '</data>' )
    
    # Create the new file.
    newfile = file( os.path.join( filePath, fullFileName ), 'w')      
    for i in xmlList:
        newfile.write( i+'\n' )
    newfile.close()
Esempio n. 10
0
 def upVec( self, inControlName ):
     print 'UP VEC'
     XMLUtility.createControlFromXML( 'glBox', self.subType, inControlName )
Esempio n. 11
0
 def hand( self, inControlName ):
     print 'BOX HAND'
     XMLUtility.createControlFromXML( 'glBox', self.subType, inControlName )
Esempio n. 12
0
 def elbow( self, inControlName ):
     print 'BOX ELBOW'
     XMLUtility.createControlFromXML( 'glBox', self.subType, inControlName )
Esempio n. 13
0
 def shoulder( self, inControlName ):
     print 'BOX SHOULDER'
     XMLUtility.createControlFromXML( 'glBox', self.subType, inControlName )
Esempio n. 14
0
def latticeCard( inLatticeType, inLattice, inLatticeDescription, parent=None ):
    nameLabelHeight = 14
    cardHeight = 64
    cardBackgroundColor = {'roots':'383232',
                           'spines':'383832',
                           'arms':'323834',
                           'legs':'323638',
                           'hands':'343238',
                           'feet':'383237',
                           'heads':'383232'}
        
    cardLabelColor = {'roots':'5d5353',
                      'spines':'5d5d53',
                      'arms':'535d56',
                      'legs':'53595d',
                      'hands':'57535d',
                      'feet':'5d535b',
                      'heads':'5d5353'}
    
    cardButtonColor = {'roots':'4b4141',
                      'spines':'4b4b43',
                      'arms':'434b45',
                      'legs':'42474a',
                      'hands':'45424a',
                      'feet':'4a4249',
                      'heads':'4a4242'}
    
    latticeName = QtGui.QLabel()
    latticeName.setIndent( 10 )
    latticeName.setText( str.upper( str( inLattice ) ) )
    latticeName.setAlignment( QtCore.Qt.AlignLeft )
    latticeName.setMaximumHeight( nameLabelHeight )
    latticeName.setStyleSheet( 'font:{0}; font-size:{1}px; color:{2}; background-color:#{3}'.format( 'bold',
                                                                                                     10,
                                                                                                     'white',
                                                                                                     cardLabelColor[ inLatticeType ] ) )
    
    latticeDescription = QtGui.QLabel()
    latticeDescription.setMinimumHeight( 45 )
    latticeDescription.setMaximumHeight( 45 )
    latticeDescription.setWordWrap( True )
    latticeDescription.setText( inLatticeDescription )
    
    latticeButton = QTWidgets.imageTextButton( None, ':/riggingUI/icons/icon_plus32.png', [32,32] )
    latticeButton.setMaximumSize( QtCore.QSize( 40, 40 ) )
    latticeButton.setStyleSheet( 'background-color:#{0}'.format( cardButtonColor[ inLatticeType ]) )
    latticeButton.clicked.connect( lambda a=inLatticeType, b=inLattice:XMLUtility.loadModule( a, b ) )
    
    latticeGrid = QtGui.QGridLayout()
    latticeGrid.setAlignment( QtCore.Qt.AlignTop )
    latticeGrid.setContentsMargins( 0, 0, 0, 0 )
    latticeGrid.setHorizontalSpacing( 0 )
    
    latticeGrid.addWidget( latticeDescription, 0, 0 )
    latticeGrid.addWidget( latticeButton, 0, 1 )
    latticeGrid.setColumnMinimumWidth( 1, 40 )
    
    latticeRow = QtGui.QVBoxLayout()
    latticeRow.setSpacing( 0 )
    latticeRow.setContentsMargins( 0,0,0,0 )
    latticeRow.addWidget( latticeName )
    latticeRow.addLayout( latticeGrid )

    frame = QtGui.QFrame()
    frame.setFrameShadow( QtGui.QFrame.Sunken )
    frame.setFrameShape( QtGui.QFrame.StyledPanel )
    frame.setLineWidth( 2 )
    frame.setStyleSheet( 'padding:1px; background-color:#{0}'.format( cardBackgroundColor[ inLatticeType ] ) )
    frame.setMinimumHeight( cardHeight )
    frame.setLayout( latticeRow )
    
    return frame