I'm hoping someone can help. I've attached the MILA script which is responsibly for most of the UI for the MR layering library; what is missing from the MILA Material Library is the ability to rename the Layering Layers or even add notes to layers or groups of layers, I was hoping someone could help so I can also understand more about Python ?

Christopher

--
You received this message because you are subscribed to the Google Groups "Python 
Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/python_inside_maya/55F903EE.30207%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
import re
from functools import partial
import maya.cmds as cmds
import maya.mel as mel

def get_connection_or_value(node_layer, attribute):
    connection = cmds.connectionInfo('%s.%s' % (node_layer, attribute), 
sourceFromDestination=True)
    if connection:
        return connection
    else:
        attr_value = cmds.getAttr('%s.%s' % (node_layer, attribute))
        if type(attr_value) == list:  # color (eg, tint) is returned in list of 
tuple, [(r,g,b)]
            attr_value = attr_value[0]
        return attr_value

def get_connection(node_layer, attribute):
    connections = cmds.listConnections('%s.%s' % (node_layer, attribute), 
s=True, d=False)
    if connections:
        return connections[0]
    else:
        return ''

def disconnect_layer_attr(node_layer, attribute):
    attr = '%s.%s' % (node_layer, attribute)
    if cmds.objExists(attr):
        connections = cmds.listConnections(attr, s=True, d=False)
        if connections[0]:
            cmds.disconnectAttr(connections[0], attr)

def set_connection_or_value(attr_value, node_layer, attribute):
    attr = str('%s.%s' % (node_layer, attribute))
    connection = cmds.connectionInfo(attr, sourceFromDestination=True)
    if type(attr_value) in (str, unicode) and cmds.objExists(attr):
        if connection:
            cmds.connectAttr(attr_value, attr, f=True)
        else:
            cmds.connectAttr(attr_value, attr)
    else:
        if connection:
            cmds.disconnectAttr(connection, attr)
        attr_type = cmds.attributeQuery(attribute, node=node_layer, 
attributeType=True)
        if attr_type in ('double3', 'float3'): # value returned is a list of 
one tuple, ie [(r,g,b)]
            cmds.setAttr(attr, attr_value[0], attr_value[1], attr_value[2], 
type='double3')
        else:
            cmds.setAttr(attr, attr_value)

def component_attr_index (component_attr):
    match = re.search('.*\[([0-9]*)\]', component_attr)
    if match:
        return int(match.groups()[0])

class mix():
    def __init__(self, node, component_attr):
        self.node = node
        self.attr = component_attr  # indexed mix attr, eg component[0]
        node_mix_component = '%s.%s' % (node, component_attr)
        self.on = get_connection_or_value(node_mix_component, 'on')
        self.background_color = [0.3,0.3,0.3]
                
        self.shader = get_connection(node_mix_component, 'shader')
                
        self.weight = get_connection_or_value(node_mix_component, 'weight')
        self.weight_tint = get_connection_or_value(node_mix_component, 
'weight_tint')

        self.bump = get_connection_or_value(node_mix_component, 'bump')

    def index(self):
        return component_attr_index(self.attr)

    def move_up(self, material_node, *args):
        self.move(True)
        if material_node:
            refresh_material_layout(material_node)
        
    def move_down(self, material_node, *args):
        self.move(False)
        if material_node:
            refresh_material_layout(material_node)
        
    def move(self, up):
        node = self.node
        attr = self.attr
        mixes = collect_mixes(node)
        
        current_mix = None
        swap_mix = None
        for i in range(len(mixes)):
            if mixes[i].attr == self.attr:
                current_mix = mixes[i]
                if up:
                    swap_mix = mixes[i-1]
                else:
                    swap_mix = mixes[i+1]
        
        node_current_mix_attr = '%s.%s' % (node, current_mix.attr)
        node_swap_mix_attr = '%s.%s' % (node, swap_mix.attr)

        cmds.connectAttr ('%s.message' % swap_mix.shader, '%s.shader' % 
node_current_mix_attr, f=True)
        cmds.connectAttr ('%s.message' % current_mix.shader, '%s.shader' % 
node_swap_mix_attr, f=True)
        
        set_connection_or_value(swap_mix.on, node_current_mix_attr, 'on')
        set_connection_or_value(current_mix.on, node_swap_mix_attr, 'on')
        
        set_connection_or_value(swap_mix.weight, node_current_mix_attr, 
'weight')
        set_connection_or_value(current_mix.weight, node_swap_mix_attr, 
'weight')

        set_connection_or_value(swap_mix.weight_tint, node_current_mix_attr, 
'weight_tint')
        set_connection_or_value(current_mix.weight_tint, node_swap_mix_attr, 
'weight_tint')

        set_connection_or_value(swap_mix.bump, node_current_mix_attr, 'bump')
        set_connection_or_value(current_mix.bump, node_swap_mix_attr, 'bump')

    def __str__(self):
        return ('Attr: %s\nEnabled: %s, Shader: %s, Weight: %s, WeightTint: %s' 
% (self.attr, str(self.on), str(self.shader), str(self.weight), 
str(self.weight_tint), str(self.bump)))

def collect_mixes(node):
    mixes = []
    component_attrs = cmds.listAttr(node, m=True, v=True, c=True, 
st='components')
    if component_attrs:
        for component_attr in component_attrs:
            component = mix(node, component_attr)
            mixes.append(component)
    return mixes

class layer():
    def __init__(self, node, layer_attr):
        self.node = node
        self.attr = layer_attr  # indexed layer id, eg layer[0]
        node_layer = '%s.%s' % (node, layer_attr)
        self.on = get_connection_or_value(node_layer, 'on')
        self.background_color = [0.3,0.3,0.3]
                
        self.shader = get_connection(node_layer, 'shader')
                
        self.weight = get_connection_or_value(node_layer, 'weight')
        self.weight_tint = get_connection_or_value(node_layer, 'weight_tint')

        self.bump = get_connection_or_value(node_layer, 'bump')

        self.use_directional_weight = get_connection_or_value(node_layer, 
'use_directional_weight')
        self.directional_weight_mode = get_connection_or_value(node_layer, 
'directional_weight_mode')
        self.ior = get_connection_or_value(node_layer, 'ior')
        self.normal_reflectivity = get_connection_or_value(node_layer, 
'normal_reflectivity')
        self.grazing_reflectivity = get_connection_or_value(node_layer, 
'grazing_reflectivity')
        self.exponent = get_connection_or_value(node_layer, 'exponent')

    def index(self):
        return component_attr_index(self.attr)

    def move_up(self, material_node, *args):
        self.move(True)
        if material_node:
            refresh_material_layout(material_node)
        
    def move_down(self, material_node, *args):
        self.move(False)
        if material_node:
            refresh_material_layout(material_node)
        
    def move(self, up):
        node = self.node
        attr = self.attr
        layers = collect_layers(node)
        
        current_layer = None
        swap_layer = None
        for i in range(len(layers)):
            if layers[i].attr == self.attr:
                current_layer = layers[i]
                if up:
                    swap_layer = layers[i-1]
                else:
                    swap_layer = layers[i+1]
        
        node_current_layer_attr = '%s.%s' % (node, current_layer.attr)
        node_swap_layer_attr = '%s.%s' % (node, swap_layer.attr)

        cmds.connectAttr ('%s.message' % swap_layer.shader, '%s.shader' % 
node_current_layer_attr, f=True)
        cmds.connectAttr ('%s.message' % current_layer.shader, '%s.shader' % 
node_swap_layer_attr, f=True)

        set_connection_or_value(swap_layer.on, node_current_layer_attr, 'on')
        set_connection_or_value(current_layer.on, node_swap_layer_attr, 'on')
        
        set_connection_or_value(swap_layer.weight, node_current_layer_attr, 
'weight')
        set_connection_or_value(current_layer.weight, node_swap_layer_attr, 
'weight')

        set_connection_or_value(swap_layer.weight_tint, 
node_current_layer_attr, 'weight_tint')
        set_connection_or_value(current_layer.weight_tint, 
node_swap_layer_attr, 'weight_tint')

        set_connection_or_value(swap_layer.use_directional_weight, 
node_current_layer_attr, 'use_directional_weight')
        set_connection_or_value(current_layer.use_directional_weight, 
node_swap_layer_attr, 'use_directional_weight')

        set_connection_or_value(swap_layer.directional_weight_mode, 
node_current_layer_attr, 'directional_weight_mode')
        set_connection_or_value(current_layer.directional_weight_mode, 
node_swap_layer_attr, 'directional_weight_mode')
            
        set_connection_or_value(swap_layer.ior, node_current_layer_attr, 'ior')
        set_connection_or_value(current_layer.ior, node_swap_layer_attr, 'ior')

        set_connection_or_value(swap_layer.normal_reflectivity, 
node_current_layer_attr, 'normal_reflectivity')
        set_connection_or_value(current_layer.normal_reflectivity, 
node_swap_layer_attr, 'normal_reflectivity')

        set_connection_or_value(swap_layer.grazing_reflectivity, 
node_current_layer_attr, 'grazing_reflectivity')
        set_connection_or_value(current_layer.grazing_reflectivity, 
node_swap_layer_attr, 'grazing_reflectivity')

        set_connection_or_value(swap_layer.exponent, node_current_layer_attr, 
'exponent')
        set_connection_or_value(current_layer.exponent, node_swap_layer_attr, 
'exponent')

        set_connection_or_value(swap_layer.bump, node_current_layer_attr, 
'bump')
        set_connection_or_value(current_layer.bump, node_swap_layer_attr, 
'bump')

    def __str__(self):
        return ('Attr: %s\nEnabled: %s, Shader: %s, Weight: %s, WeightTint: %s, 
UseDirectionalWeight: %s, DirectionalWeightMode: %s, IOR: %s, 
NormalReflectivity: %s, GrazingReflectivity: %s, Exponent: %s' % (self.attr, 
str(self.on), str(self.shader), str(self.weight), str(self.weight_tint), 
str(self.use_directional_weight), str(self.directional_weight_mode), 
str(self.ior), str(self.normal_reflectivity),  str(self.grazing_reflectivity),  
str(self.exponent), str(self.bump)))

def collect_layers(node):
    layers = []
    component_attrs = cmds.listAttr(node, m=True, v=True, c=True, st='layers')
    if component_attrs:
        for layer_name in component_attrs:
            component = layer(node, layer_name)
            layers.append(component)
    return layers


def create_base_layout(material_node):
    
    cmds.columnLayout('AEmila_material_base', adj=True)
    refresh_base_layout(material_node)
    cmds.setParent('..')


base_component_labels = {'mila_diffuse_reflection':"Diffuse",
                    'mila_mix_subsurface_scatter':"Diffuse (Scatter)",
                    'mila_mix_reflective':"Reflective",
                    'mila_mix_reflective_aniso':"Reflective (Anisotropic)",
                    'mila_layer_reflective':"Reflective (Fresnel)",
                    'mila_layer_reflective_aniso':"Reflective (Anisotropic, 
Fresnel)",
                    'mila_layer_reflective_plastic':"Reflective (Plastic)",
                    'mila_layer_reflective_paint':"Reflective (Paint)",
                    'mila_layer_transmissive':"Transmissive",
                    'mila_layer_transmissive_clear':"Transmissive (Clear)",
                    'mila_layer_transmissive_distance':"Transmissive 
(Distance)",
                    'mila_mix_translucent':"Diffuse (Translucent)",
                    'mila_hair':"Hair",
                    'mila_skin':"Skin"}

def refresh_base_layout(material_node):
    
    to_del = cmds.layout('AEmila_material_base', q=True, childArray=True)
    if to_del:
        for ui in to_del:
            cmds.deleteUI(ui)
    cmds.setParent('AEmila_material_base')
    base_select_control=cmds.optionMenuGrp(l='Base Component', 
changeCommand=partial(change_base_component, material_node))
    cmds.menuItem(label="Diffuse")
    cmds.menuItem(label="Diffuse (Scatter)")
    cmds.menuItem(label="Diffuse (Translucent)")
    cmds.menuItem(label="Reflective")
    cmds.menuItem(label="Reflective (Anisotropic)")
    cmds.menuItem(label="Reflective (Plastic)")
    cmds.menuItem(label="Reflective (Paint)")
    cmds.menuItem(label="Transmissive")
    cmds.menuItem(label="Transmissive (Clear)")
    cmds.menuItem(label="Transmissive (Distance)")
    #ensure the current base component is indicated in the UI
    components = collect_components(get_components_node(material_node, 
create_when_empty=True))
    base_component_node, parent_components = 
get_base_component_node(components)  #recurses through connection hierarchy
    selected_type_label = 
base_component_labels[cmds.nodeType(base_component_node)]
    cmds.optionMenuGrp(base_select_control, edit=True, 
value=selected_type_label)
    refresh_component_layout(material_node, base_component_node, 
collapsable=False)

def refresh_base_layout_after_change(material_node):
    
    to_del = cmds.layout('AEmila_material_base', q=True, childArray=True)
    base_select_control=to_del[0]
    if to_del:
        for ui in to_del:
            if not (ui == base_select_control): # first ui
                cmds.deleteUI(ui)
    
    cmds.setParent('AEmila_material_base')

    #ensure the current base component is indicated in the UI
    components = collect_components(get_components_node(material_node, 
create_when_empty=True))
    base_component_node, parent_components = 
get_base_component_node(components)  #recurses through connection hierarchy

    refresh_component_layout(material_node, base_component_node, 
collapsable=False)

def get_base_component_node (components):
    if len(components) >0:
        last_component_node = get_connection('%s.%s' % (components[-1].node, 
components[-1].attr), 'shader')
        if last_component_node:
            if cmds.nodeType(last_component_node) in ('mila_layer', 'mila_mix'):
                components = collect_components(last_component_node)
                last_component_node, components = 
get_base_component_node(components)
            return (last_component_node, components)

base_component_nodes = {"Diffuse":'mila_diffuse_reflection',
                        "Diffuse (Scatter)":'mila_mix_subsurface_scatter',
                        "Diffuse (Translucent)":'mila_mix_translucent',
                        "Reflective":'mila_mix_reflective',
                        "Reflective (Anisotropic)":'mila_mix_reflective_aniso',
                        "Reflective (Fresnel)":'mila_layer_reflective',
                        "Reflective (Anisotropic, 
Fresnel)":'mila_layer_reflective_aniso',
                        "Reflective (Plastic)":'mila_layer_reflective_plastic',
                        "Reflective (Paint)":'mila_layer_reflective_paint',
                        "Transmissive":'mila_layer_transmissive',
                        "Transmissive (Clear)":'mila_layer_transmissive_clear',
                        "Transmissive 
(Distance)":'mila_layer_transmissive_distance'
                       }

def change_base_component(material_node, value):
    components_node = get_components_node(material_node, 
create_when_empty=False)
    if components_node:
        components = collect_components(components_node)
        current_base_component_node, parent_components = 
get_base_component_node(components)  #recurses through connection hierarchy
        if current_base_component_node:
            current_base_component_node_type = 
cmds.nodeType(current_base_component_node)
            new_node_type = base_component_nodes[value]
            if (new_node_type and (new_node_type != 
current_base_component_node_type)):
                cmds.disconnectAttr("%s.message" % current_base_component_node, 
'%s.%s.shader' % (parent_components[-1].node, parent_components[-1].attr))
                new_shader_node = cmds.createNode(new_node_type, 
skipSelect=True) # skipSelect allows us to stay on this node
                cmds.connectAttr ('%s.message' % new_shader_node, 
'%s.%s.shader' % (parent_components[-1].node, parent_components[-1].attr))
                current_color = 
get_connection_or_value(current_base_component_node, 'tint')
                set_connection_or_value(current_color, new_shader_node, 'tint')
                update_material_swatch(material_node)
                refresh_base_layout_after_change(material_node)
    else:
        print('MILA warning: no components')

def create_material_layout(material_node):
    components_node = get_components_node(material_node, create_when_empty=True)

    cmds.setUITemplate('attributeEditorTemplate', pushTemplate=True)
    
    cmds.columnLayout(adj=True)
    
    cmds.rowLayout(nc=3, cw3=[100, 100, 100], cat=[1, 'left', 20])
    cmds.button('mila_create_new_mix', w=120, rs=False, label='+ Mix', 
command=lambda *args: create_new_mix(components_node, material_node))
    cmds.button('mila_create_new_layer', w=120, rs=False, label='+ Layer', 
command=lambda *args: create_new_layer(components_node, material_node))
    cmds.setParent('..')
    cmds.setParent('..')
    cmds.setUITemplate(popTemplate=True)

    cmds.columnLayout('AEmila_material_components', adj=True)
    refresh_material_layout(material_node)
    cmds.setParent('..')  # matching column layout for initial creation    


def get_components_node(material_node, create_when_empty=True):
    connection = cmds.connectionInfo('%s.shader' % material_node, 
sourceFromDestination=True)
    if ((not connection) and create_when_empty):
        layer_node = cmds.createNode('mila_layer', skipSelect=True) # 
skipSelect allows us to stay on this node
        cmds.connectAttr ('%s.message' % (layer_node), '%s.shader' % 
material_node)
        shader_node = cmds.createNode('mila_diffuse_reflection', 
skipSelect=True) # skipSelect allows us to stay on this node
        cmds.connectAttr ('%s.message' % (shader_node), '%s.layers[0].shader' % 
(layer_node))
        connection = cmds.connectionInfo('%s.shader' % material_node, 
sourceFromDestination=True)  
        cmds.setAttr('%s.tint' % shader_node, 0.7, 0.7, 0.7, type='double3')
    return connection.split(".")[-2]  # not the last which should be "message", 
but the second to last layer or mix

def get_components_node_type(components_node):
    return cmds.nodeType(components_node)

def components_node_is_layer(components_node):
   return cmds.nodeType(components_node) ==  'mila_layer'

def components_node_is_mix(components_node):
   return cmds.nodeType(components_node) ==  'mila_mix'

def collect_components(components_node):
    components_node_type = cmds.nodeType(components_node)
    components_info = []
    if components_node_type == 'mila_layer':
        components_info = collect_layers(components_node)
    elif components_node_type == 'mila_mix':
        components_info = collect_mixes(components_node)
    else:
        print('MILA warning: Unknown components type %s' % components_node_type)
    return components_info

def refresh_material_layout(material_node):
    components_node = get_components_node(material_node)
    cmds.button('mila_create_new_mix', e=True, 
en=len(collect_components(components_node)) > 1, command=lambda *args: 
create_new_mix(components_node, material_node))
    cmds.button('mila_create_new_layer', e=True, command=lambda *args: 
create_new_layer(components_node, material_node))

    to_del = cmds.layout('AEmila_material_components', q=True, childArray=True)
    if to_del:
        for ui in to_del:
            cmds.deleteUI(ui)

    refresh_components_layout(components_node, material_node, 
hierarchy_level=0) #level 0 is top level

component_titles = {'mila_diffuse_reflection':"Diffuse Reflection",
                    'mila_glossy_reflection':"Glossy Reflection",
                    'mila_specular_reflection':"Specular Reflection",
                    'mila_diffuse_transmission':"Diffuse Transmission",
                    'mila_glossy_transmission':"Glossy Transmission",
                    'mila_specular_transmission':"Specular Transmission",
                    'mila_transparency':"Transparency",
                    'mila_scatter':"Scatter",
                    'mila_emission':"Emission",
                    'mila_mix_reflective':"Reflective",
                    'mila_mix_reflective_aniso':"Reflective (Anisotropic)",
                    'mila_layer_reflective':"Reflective (Fresnel)",
                    'mila_layer_reflective_aniso':"Reflective (Anisotropic, 
Fresnel)",
                    'mila_layer_reflective_plastic':"Reflective (Plastic)",
                    'mila_layer_reflective_paint':"Reflective (Paint)",
                    'mila_layer_transmissive':"Transmissive",
                    'mila_layer_transmissive_clear':"Transmissive (Clear)",
                    'mila_layer_transmissive_distance':"Transmissive 
(Distance)",
                    'mila_mix_translucent':"Translucent",
                    'mila_mix_glossy_reflection':"Glossy Reflection Mix",
                    'weighted_layer':"Weighted Layer",
                    'fresnel_layer':"Fresnel Layer",
                    'custom_layer':"Custom Layer",
                    'mila_mix':"Mix",
                    'mila_layer':"Layer"}

def get_component_title(component_node):
    component_node_type = cmds.nodeType(component_node)
    title = component_titles[component_node_type]
    if title:
        return title
    else:
        return component_node_type

level_colors = [[0.38, 0.38, 0.38],[0.32, 0.32, 0.32],[0.26, 0.26, 0.26],[0.20, 
0.20, 0.20],[0.14, 0.14, 0.14]]

def change_bump(material_node, components_node_layer):
    bump = cmds.getAttr('%s.bump' % components_node_layer)
    if get_connection_or_value(components_node_layer, 'bump')[2]==1: # just 
disconnected, defaulting to 0,0,1
        cmds.setAttr('%s.bump' % components_node_layer, 0, 0, 0)
    else:
        update_material_swatch(material_node)

def refresh_components_layout(components_node, material_node, 
hierarchy_level=0):
    components_node_type = get_components_node_type(components_node) 
    components = collect_components(components_node)
    base_component_node, parent_components = 
get_base_component_node(collect_components(get_components_node(material_node)))
    if components:
        length_components_even = len(components) % 2 == 0
        if hierarchy_level == 0:
            cmds.setParent('AEmila_material_components')
        label_title_prefix = "%s" % get_component_title(components_node)
        label_title = ""
        for component in components:
            component.background_color = level_colors[hierarchy_level]

            last_component = (component == components[-1]) # last (base) 
component

            base_component = base_component_node == component.shader

            has_sub_components = (cmds.nodeType(component.shader) in 
('mila_mix','mila_layer'))

            if not base_component:
                if has_sub_components:
                    label_title = "%s: %s Sub-Components" % 
(label_title_prefix, get_component_title(component.shader))
                else:
                    label_title = "%s: %s" % (label_title_prefix, 
get_component_title(component.shader))
                indent_margin = hierarchy_level * 40
                layout = cmds.frameLayout(label='%s' % (label_title), 
labelIndent=indent_margin, collapsable=True, collapse=0, 
backgroundColor=component.background_color)
                cmds.setUITemplate('attributeEditorTemplate', pushTemplate=True)
            
                cmds.columnLayout(rowSpacing=1, adjustableColumn=True, 
backgroundColor=component.background_color, columnOffset=['left', 
indent_margin])
            
                node_component_attr = '%s.%s' % (component.node, component.attr)

                if not (last_component and has_sub_components):
                    cmds.rowLayout(nc=5, cw5=[30, 25, 25, 270,30], cat=[1, 
'left', 5])
            
                    enabled = cmds.checkBox(l='', 
cc=partial(update_material_swatch, material_node))
                    cmds.connectControl(enabled, '%s.on' % node_component_attr)

                    # move up not enabled for first component, nor last
                    up_enabled = not (component == components[0])
                    if last_component:
                        up_enabled = False
                    # move down not enabled for last component, nor for second 
to last
                    down_enabled = not last_component
                    if (len(components) > 1) and (component == components[-2]): 
                        down_enabled = False
            
                    cmds.symbolButton(image='arrowDown.png', vis=down_enabled, 
c=partial(component.move_down, material_node))
                    cmds.symbolButton(image='arrowUp.png', vis=up_enabled, 
c=partial(component.move_up, material_node))
           
                    cmds.attrFieldSliderGrp( l='Weight', min=0, max=1, 
at='%s.weight' % node_component_attr, cw=[1,60], vis=(not last_component))
                    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.weight' % node_component_attr, 
partial(update_material_swatch, material_node)] )

                    cmds.iconTextButton(style='iconOnly', h=25, mw=0, mh=0, 
image='smallTrash.png', c=partial(delete_component, node_component_attr, 
material_node), vis=(not last_component))

                    cmds.setParent('..') # row layout for top row of component 
containing icons and weight slider
                    
                is_layer = components_node_is_layer(components_node)
                directional_enable = is_layer and 
cmds.getAttr('%s.use_directional_weight' % node_component_attr)
                directional_mode = is_layer and 
cmds.getAttr('%s.directional_weight_mode' % node_component_attr)
                fresnel_enable = (directional_mode == 0) and directional_enable
                if is_layer:
                    cmds.attrFieldSliderGrp( l='Fresnel IOR', min=1.0, smx=2.0, 
at='%s.ior' % node_component_attr, vis=fresnel_enable)
                    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.ior' % node_component_attr, 
partial(update_material_swatch, material_node)] )
                    custom_enable = directional_mode == 1
                    cmds.attrFieldSliderGrp( l='Normal Reflectivity', min=0, 
max=1, at='%s.normal_reflectivity' % node_component_attr, 
en=cmds.getAttr('%s.directional_weight_mode' % node_component_attr)==1, 
vis=custom_enable)
                    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.normal_reflectivity' % node_component_attr, 
partial(update_material_swatch, material_node)] )
                    cmds.attrFieldSliderGrp( l='Grazing Reflectivity', min=0, 
max=1, at='%s.grazing_reflectivity' % node_component_attr, 
en=cmds.getAttr('%s.directional_weight_mode' % node_component_attr)==1, 
vis=custom_enable )
                    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.grazing_reflectivity' % node_component_attr, 
partial(update_material_swatch, material_node)] )

                    cmds.attrFieldSliderGrp( l='Exponent', min=0.1, smx=20, 
at='%s.exponent' % node_component_attr, 
en=cmds.getAttr('%s.directional_weight_mode' % node_component_attr)==1, 
vis=custom_enable)
                    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.exponent' % node_component_attr, 
partial(update_material_swatch, material_node)] )

                cmds.attrNavigationControlGrp(label='Bump', attribute='%s.bump' 
% node_component_attr, 
                                              disconnect='cmds.setAttr(%s.bump, 
0, 0, 0)' % node_component_attr)
                cmds.scriptJob( killWithScene=True, attributeChange=['%s.bump' 
% node_component_attr, partial(change_bump, material_node, 
node_component_attr)] )
                cmds.separator()
                refresh_component_layout(material_node, component.shader, 
hierarchy_level=hierarchy_level, background_color=component.background_color, 
collapsable=(not last_component))

                cmds.setParent('..')  # matched with column layout for icons 
and weight controls, ie layer/mix controls
            
                cmds.setUITemplate(popTemplate=True)
                cmds.setParent('..')  # matched with frame layout for this 
component

def refresh_component_layout(material_node, component_node, hierarchy_level=0, 
background_color=[.267,.267,.267], collapsable=True):
    component_node_type = cmds.nodeType(component_node)
    has_sub_components = component_node_type in ('mila_mix', 'mila_layer')
    
    margin = hierarchy_level * 40
    
    if has_sub_components:
        components_node = component_node
        refresh_components_layout(components_node, material_node, 
hierarchy_level=hierarchy_level+1)
    elif component_node_type == 'mila_transparency':
        cmds.attrColorSliderGrp(l='Transparency Color', at='%s.transparency' % 
component_node)
        cmds.scriptJob( killWithScene=True, attributeChange=['%s.transparency' 
% component_node, partial(update_material_swatch, material_node)] )
    elif component_node_type == 'mila_scatter':
        scatter_layout(component_node, material_node, background_color)
    else:
        cmds.attrColorSliderGrp( l='Color', at='%s.tint' % component_node)
        cmds.scriptJob( killWithScene=True, attributeChange=['%s.tint' % 
component_node, partial(update_material_swatch, material_node)] )
        if component_node_type in ('mila_diffuse_reflection', 
'mila_glossy_reflection', 'mila_glossy_transmission', 
'mila_mix_subsurface_scatter', 'mila_mix_translucent'):
            cmds.attrFieldSliderGrp( l='Roughness', min=0, max=1, 
at='%s.roughness' % component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.roughness' 
% component_node, partial(update_material_swatch, material_node)] )
        if component_node_type == 'mila_mix_glossy_reflection':
            cmds.attrFieldSliderGrp( l='Roughness 1', min=0, max=1, 
at='%s.roughness1' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.roughness1' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Weight 1', min=0, max=1, 
at='%s.weight1' % component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.weight1' % 
component_node, partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Roughness 2', min=0, max=1, 
at='%s.roughness2' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.roughness2' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Weight 2', min=0, max=1, 
at='%s.weight2' % component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.weight2' % 
component_node, partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Roughness 3', min=0, max=1, 
at='%s.roughness3' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.roughness3' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Weight 3', min=0, max=1, 
at='%s.weight3' % component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.weight3' % 
component_node, partial(update_material_swatch, material_node)] )
        if component_node_type in ('mila_mix_subsurface_scatter', 
'mila_mix_translucent'):
            cmds.attrFieldSliderGrp( l='Diffuse Weight', min=0, max=1, 
at='%s.diffuse_weight' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.diffuse_weight' % component_node, 
partial(update_material_swatch, material_node)] )
        if component_node_type == 'mila_mix_subsurface_scatter':
            diffuse_scatter_layout(component_node, material_node, 
background_color)
        if component_node_type in ('mila_glossy_transmission', 
'mila_specular_transmission'):
            cmds.attrFieldSliderGrp( l='IOR', min=1, smx=2, fmx=10, at='%s.ior' 
% component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.ior' % 
component_node, partial(update_material_swatch, material_node)] )
        if component_node_type in ('mila_mix_reflective', 
'mila_mix_reflective_aniso', 'mila_layer_reflective', 
'mila_layer_reflective_plastic'):
            cmds.attrFieldSliderGrp( l='Glossy Blend', min=0, max=1, 
at='%s.glossy_weight' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.glossy_weight' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Glossy Roughness', min=0, max=1, 
at='%s.glossy_roughness' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.glossy_roughness' % component_node, 
partial(update_material_swatch, material_node)] )
            if component_node_type in ('mila_mix_reflective_aniso', 
'mila_layer_reflective_aniso'):
                anisotropy_layout(component_node, material_node, 
background_color)
                cmds.attrFieldSliderGrp( l='Diffuse Roughness', min=0, max=1, 
at='%s.diffuse_roughness' % component_node)
                cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.diffuse_roughness' % component_node, 
partial(update_material_swatch, material_node)] )
        if component_node_type in ('mila_layer_reflective', 
'mila_layer_reflective_plastic'):
            cmds.attrFieldSliderGrp( l='Fresnel IOR', min=1, smx=2, fmx=10, 
at='%s.ior' % component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.ior' % 
component_node, partial(update_material_swatch, material_node)] )
        if component_node_type == 'mila_layer_reflective_paint':
            cmds.attrFieldSliderGrp( l='Edge Weight', min=0, max=1, 
at='%s.edge_weight' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.edge_weight' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrColorSliderGrp( l='Edge Color', at='%s.edge_color' % 
component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.edge_color' % component_node, 
partial(update_material_swatch, material_node)] )

            cmds.attrFieldSliderGrp( l='Edge Color Bias', min=1, smx=2, fmx=10, 
at='%s.edge_color_bias' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.edge_color_bias' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Glossy Blend', min=0, max=1, 
at='%s.glossy_weight' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.glossy_weight' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrColorSliderGrp( l='Glossy Color', at='%s.glossy_color' % 
component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.glossy_color' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Glossy Roughness', min=0, max=1, 
at='%s.glossy_roughness' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.glossy_roughness' % component_node, 
partial(update_material_swatch, material_node)] )
            flakes_layout(component_node, material_node, background_color)
        if component_node_type in 
('mila_layer_transmissive','mila_layer_transmissive_clear','mila_layer_transmissive_distance'):
            if (component_node_type == 'mila_layer_transmissive_distance'):
                cmds.attrFieldSliderGrp( l='At Distance', min=0, smx=10, 
at='%s.max_dist' % component_node)
                cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.max_dist' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='Reflective Weight', min=0, max=1, 
at='%s.reflective_weight' % component_node)
            cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.reflective_weight' % component_node, 
partial(update_material_swatch, material_node)] )
            if component_node_type in 
('mila_layer_transmissive','mila_layer_transmissive_distance'):
                cmds.attrFieldSliderGrp( l='Roughness', min=0, max=1, 
at='%s.roughness' % component_node)
                cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.roughness' % component_node, 
partial(update_material_swatch, material_node)] )
            cmds.attrFieldSliderGrp( l='IOR', min=1, smx=2, fmx=10, at='%s.ior' 
% component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.ior' % 
component_node, partial(update_material_swatch, material_node)] )
            if (component_node_type == 'mila_layer_transmissive'):
                anisotropy_layout(component_node, material_node, 
background_color)
        if (component_node_type == 'mila_emission'):
            cmds.attrFieldSliderGrp( l='Intensity', min=0, smx=20, 
at='%s.intensity' % component_node)
            cmds.scriptJob( killWithScene=True, attributeChange=['%s.intensity' 
% component_node, partial(update_material_swatch, material_node)] )
        else:
            contribution_layout(component_node, material_node, background_color)

def scatter_layout(component_node, material_node, background_color):
    cmds.attrColorSliderGrp( l='Front Tint', at='%s.front_tint' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.front_tint' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Front Weight', min=0, max=1, 
at='%s.front_weight' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.front_weight' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldGrp(label='Front Radius', at='%s.front_radius' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.front_radius' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrColorSliderGrp( l='Front Radius Mod', at='%s.front_radius_mod' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.front_radius_mod' 
% component_node, partial(update_material_swatch, material_node)] )
    cmds.separator()
    cmds.attrColorSliderGrp( l='Back Tint', at='%s.back_tint' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_tint' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Back Weight', min=0, max=1, at='%s.back_weight' 
% component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_weight' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldGrp(label='Back Radius', at='%s.back_radius' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_radius' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrColorSliderGrp( l='Back Radius Mod', at='%s.back_radius_mod' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_radius_mod' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Back Depth', min=0, smx=10, ann='Back depth 
distance scale, if 0, uses radius',
                             at='%s.back_depth' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_depth' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.separator()
    cmds.attrFieldSliderGrp( l='Scale Conversion', min=0, smx=10, 
at='%s.scale_conversion' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.scale_conversion' 
% component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Sampling Radius Factor', min=0, smx=10, 
at='%s.sampling_radius_mult' % component_node)
    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.sampling_radius_mult' % component_node, 
partial(update_material_swatch, material_node)] )
    cmds.attrEnumOptionMenuGrp(l='Resolution',
                               at='%s.resolution' % component_node,
                               ei = [(0, "2 x Image"),
                                     (1, "1 x Image"),
                                     (2, "1/2 x Image"),
                                     (3, "1/3 x Image"),
                                     (4, "1/4 x Image"),
                                     (5, "1/5 x Image")])
    cmds.attrFieldSliderGrp( l='Light Storage Gamma', min=0, smx=2, 
at='%s.light_storage_gamma' % component_node)
    cmds.scriptJob( killWithScene=True, 
attributeChange=['%s.light_storage_gamma' % component_node, 
partial(update_material_swatch, material_node)] )

def diffuse_scatter_layout(component_node, material_node, background_color):
    cmds.separator()
    cmds.attrColorSliderGrp( l='Front Scatter Color', at='%s.front_color' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.front_color' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Front Weight', min=0, max=1, 
at='%s.front_weight' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.front_weight' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.separator()
    cmds.attrColorSliderGrp( l='Back Scatter Color', at='%s.back_color' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_color' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Back Weight', min=0, max=1, at='%s.back_weight' 
% component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_weight' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Back Scatter Depth', min=0, smx=10, ann='Back 
depth distance scale, if 0, uses radius',
                             at='%s.back_depth' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.back_depth' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.separator()
    cmds.attrFieldSliderGrp( l='Scale Conversion', min=0, smx=10, 
at='%s.scale_conversion' % component_node,
                             ann='Divide scatter distance of 20 units by this 
conversion factor; higher values scatter less')
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.scale_conversion' 
% component_node, partial(update_material_swatch, material_node)] )

flake_types = {"Distortion 1":0,
               "Distortion 2":1,
               "Distortion 3":2,
               "Cellular 1":3,
               "Cellular 2":4,
               "Cellular 3":5}

def change_flake_type(material_node, paint_node, value):
    set_connection_or_value(flake_types[value], paint_node, 'flake_type')
    cell_enable = flake_types[value] > 2
    cmds.optionMenuGrp("AEmila_flake_cell_style", e=True, en=cell_enable)
    circle_size_enable = cell_enable and (cmds.getAttr('%s.flake_cell_style' % 
paint_node) == 1)
    cmds.attrFieldSliderGrp("AEmila_flake_circle_size", e=True, 
en=circle_size_enable)
    update_material_swatch(material_node)

cell_styles = {"Edgy":0,
               "Circular":1}

def change_cell_style(material_node, paint_node, value):
    set_connection_or_value(cell_styles[value], paint_node, 'flake_cell_style')
    circle_size_enable = cell_styles[value] == 1
    cmds.attrFieldSliderGrp("AEmila_flake_circle_size", e=True, 
en=circle_size_enable)
    update_material_swatch(material_node)

def flakes_layout(component_node, material_node, background_color):
    cmds.frameLayout(collapsable=True, collapse=True, label="Flakes", 
labelIndent=80, font="tinyBoldLabelFont", backgroundColor=background_color)
    cmds.columnLayout(rowSpacing=1, adjustableColumn=True, 
backgroundColor=background_color)
    cmds.attrFieldSliderGrp( l='Flake Weight', min=0, max=1, 
at='%s.flake_weight' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_weight' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrColorSliderGrp( l='Flake Color', at='%s.flake_color' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_color' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Flake Roughness', min=0, max=1, 
at='%s.flake_roughness' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_roughness' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Flake Scale', min=0, smx=2, fmx=10, 
at='%s.flake_scale' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_scale' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Flake Strength', min=0, smx=1, 
at='%s.flake_strength' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_strength' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Flake Density', min=0, smx=2, 
at='%s.flake_density' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_density' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.optionMenuGrp("AEmila_flake_type", l='Flake Type')
    cmds.menuItem("Distortion 1")
    cmds.menuItem("Distortion 2")
    cmds.menuItem("Distortion 3")
    cmds.menuItem("Cellular 1")
    cmds.menuItem("Cellular 2")
    cmds.menuItem("Cellular 3")
    cmds.optionMenuGrp("AEmila_flake_type", e=True, 
select=cmds.getAttr("%s.flake_type"%component_node)+1, 
                       cc=partial(change_flake_type, material_node, 
component_node))
    cell_enable = cmds.getAttr('%s.flake_type' % component_node) > 2
    cmds.optionMenuGrp("AEmila_flake_cell_style", l='Cell Style', 
en=cell_enable)
    cmds.menuItem("Edgy")
    cmds.menuItem("Circular")
    flake_cell_style = cmds.getAttr('%s.flake_cell_style' % component_node)
    cmds.optionMenuGrp("AEmila_flake_cell_style", e=True, select = 
flake_cell_style + 1,
                       cc=partial(change_cell_style, material_node, 
component_node))              
    circle_size_enable = cell_enable and (flake_cell_style == 1)
    cmds.attrFieldSliderGrp("AEmila_flake_circle_size",
                             l='Circle Size', min=0, smx=2, fmx=10,
                             at='%s.flake_circle_size' % component_node,
                             en=circle_size_enable )
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.flake_circle_size' 
% component_node, partial(update_material_swatch, material_node)] )
    cmds.setParent('..') # matched with column layout
    cmds.setParent('..') # matched with Flakes frame layout

def anisotropy_layout(component_node, material_node, background_color):
    cmds.frameLayout(collapsable=True, collapse=True, label="Anisotropy", 
labelIndent=80, font="tinyBoldLabelFont", backgroundColor=background_color)
    cmds.columnLayout(rowSpacing=1, adjustableColumn=True, 
backgroundColor=background_color)
    cmds.attrFieldSliderGrp( l='Anisotropy', min=0.1, smx=10, 
at='%s.anisotropy' % component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.anisotropy' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Angle', smn=0, smx=1, at='%s.aniso_angle' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.aniso_angle' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrEnumOptionMenuGrp(l='Channel',
                               at='%s.aniso_channel' % component_node,
                               ei = [(-1, "World Point"),
                                     (0, "Texture space 0"),
                                     (1, "Texture space 1"),
                                     (2, "Texture space 2"),
                                     (3, "Texture space 3"),
                                     (4, "Texture space 4"),
                                     (5, "Texture space 5")])
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.aniso_channel' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.setParent('..') # matched with column layout
    cmds.setParent('..') # matched with Anisotropy frame layout
    
def contribution_layout(component_node, material_node, background_color):
    cmds.frameLayout(collapsable=True, collapse=True, label="Contribution", 
labelIndent=80, font="tinyBoldLabelFont", backgroundColor=background_color)
    cmds.columnLayout(rowSpacing=1, adjustableColumn=True, 
backgroundColor=background_color)
    cmds.attrFieldSliderGrp( l='Direct', min=0, smx=1, at='%s.direct' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.direct' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.attrFieldSliderGrp( l='Indirect', min=0, smx=1, at='%s.indirect' % 
component_node)
    cmds.scriptJob( killWithScene=True, attributeChange=['%s.indirect' % 
component_node, partial(update_material_swatch, material_node)] )
    cmds.setParent('..') # matched with column layout
    cmds.setParent('..') # matched with Contribution frame layout


def choose_form_layout(components, title_label="Choose"):
    form = cmds.setParent(q=True)
    cmds.formLayout(form, e=True, width=210) #hardcode width, cause not 
resizable
    title = cmds.text(l=title_label)
    buttons = []
    for component in components:
        if component in component_titles.keys():
            component_title = component_titles[component]
            button = cmds.button(component, label=component_title, width=200, 
command='import maya.cmds\nmaya.cmds.layoutDialog(dismiss="' + component + '")' 
)
            buttons.append(button)
        elif component == 'separator':
            buttons.append(cmds.separator(st='in'))
        else:
            buttons.append(cmds.text(label=component))
    cancel = cmds.button(l='Cancel', c='import 
maya.cmds\ncmds.layoutDialog(dismiss="Cancel")')
    spacer = 4
    top = 8
    edge = 5
    attach_form_arg = [(title, 'top', top), (title, 'left', edge), (title, 
'right', edge), (cancel, 'bottom', edge)]
    attach_none_arg = [(title, 'bottom')]
    attach_control_arg = []
    i = 0
    for button in buttons:
        if i == 0:
            above_button = title
            spacer = 10
        else:
            above_button = buttons[i-1]
            spacer = 4
        attach_form_arg.append((button, 'left', edge))
        attach_form_arg.append((button, 'right', edge))
        attach_none_arg.append((button, 'bottom'))
        attach_control_arg.append((button, 'top', spacer, above_button))
        i += 1
    attach_form_arg.append((cancel, 'left', 65))
    attach_form_arg.append((cancel, 'right', 65))
    attach_control_arg.append((cancel, 'top', 12, buttons[-1]))
    cmds.formLayout(form, edit=True,
                    attachForm=attach_form_arg,
                    attachNone=attach_none_arg,
                    attachControl=attach_control_arg)

def elemental_component_form():
    choose_form_layout(['separator',
                        'Reflection',
                        'mila_specular_reflection',
                        'mila_glossy_reflection',
                        'mila_mix_glossy_reflection',
                        'mila_diffuse_reflection', 
                        'separator',
                        'Transmission',
                        'mila_specular_transmission',
                        'mila_glossy_transmission',
                        'mila_diffuse_transmission',
                        'separator',
                        'mila_transparency',
                        'separator',
                        'Subsurface Scattering',
                        'mila_scatter',
                        'separator',
                        'Emission',
                        'mila_emission'],
                       title_label="Choose elemental component")

def choose_elemental_component():
    component = cmds.layoutDialog(ui=elemental_component_form)
    if component in ('Cancel','dismiss'):
        return 'None'
    else:
        return component

def layer_type_form():
    
choose_form_layout(['weighted_layer','fresnel_layer','custom_layer'],title_label="Choose
 layer type")

def choose_layer_type():
    layer_type = cmds.layoutDialog(ui=layer_type_form)
    if layer_type in ('Cancel','dismiss'):
        return 'None'
    else:
        return layer_type

def create_new_layer(node, material_node):
    index = 0
    component_attrs = []
    if components_node_is_mix(node):
        component_attrs = cmds.listAttr(node, m=True, v=True, c=True, 
st='components')
        if len(component_attrs) > 1:
            bottom_component = node
        elif len(component_attrs) == 0:
            print ("MILA Error: expected mila_mix with 1 layer, got %i instead" 
% len(component_attrs))
        else:
            print ("MILA: Adding layer, single mix component, so replace mix 
with layer")
            bottom_component = collect_mixes(node)[0].shader
        layer_node = cmds.createNode('mila_layer', skipSelect=True)
        cmds.connectAttr ('%s.message' % bottom_component, 
'%s.layers[0].shader' % layer_node, f=True)
        cmds.connectAttr ('%s.message' % layer_node, '%s.shader' % 
material_node, f=True)
        node = layer_node # was mix node
    component_attrs = cmds.listAttr(node, m=True, v=True, c=True, st='layers')
    if component_attrs:
        index = component_attr_index(component_attrs[-1])
        index += 1
    layer_type = choose_layer_type()
    if (layer_type != 'None'):
        shader_name = choose_elemental_component()
        if (shader_name != 'None'):
            shader_node = cmds.createNode(shader_name, skipSelect=True) # 
skipSelect allows us to stay on this node
            cmds.connectAttr ('%s.message' % (shader_node), 
'%s.layers[%i].shader' % (node, index))
            if layer_type in ('fresnel_layer', 'custom_layer'):
                cmds.setAttr('%s.layers[%i].use_directional_weight' % (node, 
index), 1)
                if (layer_type == 'custom_layer'):
                    cmds.setAttr('%s.layers[%i].directional_weight_mode' % 
(node, index), 1)
            layers = collect_layers(node)
            if (len(layers) == index+1):
                while (index > 0):
                    layers = collect_layers(node)
                    layers[index].move_up(material_node)
                    index -= 1
    refresh_material_layout(material_node)
    update_material_swatch(material_node)
   
def mix_over_layers_form():
    choose_form_layout(['Mix into top layer','Mix with all layers'], 
title_label="Choose mix placement")

def mix_with_components_form():
    choose_form_layout(['Mix with all components','Mix'], title_label="Choose 
mix type")

def choose_mix_component_type():
    mix_type = cmds.layoutDialog(ui=mix_over_layers_form)
    if mix_type in ('Cancel','dismiss'):
        return 'None'
    else:
        return mix_type

def create_new_mix(node, material_node):
    index = 0
    component_attrs = []
    shader_name = choose_elemental_component()
    if (shader_name == 'None'):
        return
    node_is_layer = components_node_is_layer(node)
    if node_is_layer:
        mix_into_top_layer = False
        create_new_mix_node = True
        component_attrs = cmds.listAttr(node, m=True, v=True, c=True, 
st='layers')
        if len(component_attrs) > 1:
            mix_into_top_layer = True
            if mix_into_top_layer:
                bottom_component = collect_layers(node)[0].shader
                if components_node_is_mix(bottom_component):
                   create_new_mix_node = False
                print ("MILA: Adding mix to top layer %s" % bottom_component)
            else:
                bottom_component = node # mix with current mila_layer as 
bottom(base)component
        else:
            print ("MILA: Adding mix, single layer component, so replace layer 
with mix")
            bottom_component = collect_layers(node)[0].shader
            if components_node_is_mix(bottom_component):
               create_new_mix_node = False

        if create_new_mix_node:
            mix_node = cmds.createNode('mila_mix', skipSelect=True)
            cmds.connectAttr ('%s.message' % bottom_component, 
'%s.components[0].shader' % mix_node, f=True)
            cmds.setAttr('%s.clamp' % (mix_node), 1)
            if mix_into_top_layer:
                cmds.connectAttr ('%s.message' % mix_node, 
'%s.layers[0].shader' % node, f=True)
            else: # mix into material         
                cmds.connectAttr ('%s.message' % mix_node, '%s.shader' % 
material_node, f=True)
            node = mix_node # node was layer node
        else:
            node = bottom_component # an existing mix node
    # node ensured to be a mix node, ready for adding a top mix component over 
one or more others
    component_attrs = cmds.listAttr(node, m=True, v=True, c=True, 
st='components')
    if component_attrs:
        index = component_attr_index(component_attrs[-1])
        index += 1
        shader_node = cmds.createNode(shader_name, skipSelect=True) # 
skipSelect allows us to stay on this node
        cmds.connectAttr ('%s.message' % (shader_node), 
'%s.components[%i].shader' % (node, index))
        mixes = collect_mixes(node)
        # move new last component to component 0 slot by moving it up, index 
from high to low
        if (len(mixes) == index+1):
            while (index > 0):
                mixes = collect_mixes(node)
                mixes[index].move_up(material_node)
                index -= 1
        cmds.setAttr('%s.components[0].weight' % (node), 0.5)
    refresh_material_layout(material_node)
    update_material_swatch(material_node)

def check_component_indices(components):
    i = 0
    for component in components:
        if (i != component.index()):
            return False
        i += 1
    return True

def delete_component(attr, material_node, *args):
    print('MILA: Deleting %s' % attr)
    index = component_attr_index(attr)
    node = attr.partition('.')[0]
    if node:
        components = collect_components(node)
        if check_component_indices(components):
            i = 0
            while (i < len(components)-1): # moving layer-to-delete to bottom, 
last move is second-to-last layer
                if (i == index):
                    components[index].move_down(None) # None is no 
material_node, so refresh doesn't happen til end
                    index += 1
                i += 1
                components = collect_components(node)
            if (components[-1].index() == (len(components) - 1)): # check that 
last layer is correctly numbered
                node_layers_attr='%s.%s' % (components[-1].node, 
components[-1].attr)
                cmds.removeMultiInstance('%s' % node_layers_attr, b=True)
                for job in cmds.scriptJob(listJobs=True):
                    if node_layers_attr in job:
                        cmds.scriptJob(kill=int(job.partition(':')[0]))
            remaining_node = components[-2].shader
            if ((len(components) == 2) and (node == 
get_components_node(material_node))): 
                if cmds.nodeType(remaining_node) in ('mila_mix', 'mila_layer'): 
                    cmds.connectAttr ('%s.message' % (remaining_node), 
'%s.shader' % (material_node), f=True)
            refresh_material_layout(material_node)
            update_material_swatch(material_node)

def update_material_swatch(material_node, *args):
    fb = cmds.getAttr('%s.show_framebuffer' % material_node)
    cmds.setAttr('%s.show_framebuffer' % material_node, fb)

# Copyright (C) 1997-2014 Autodesk, Inc., and/or its licensors.
# All rights reserved.
#
# The coded instructions, statements, computer programs, and/or related
# material (collectively the "Data") in these files contain unpublished
# information proprietary to Autodesk, Inc. ("Autodesk") and/or its licensors,
# which is protected by U.S. and Canadian federal copyright law and by
# international treaties.
#
# The Data is provided for use exclusively by You. You have the right to use,
# modify, and incorporate this Data into other products for purposes authorized 
# by the Autodesk software license agreement, without fee.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. AUTODESK
# DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTIES
# INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF NON-INFRINGEMENT,
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A COURSE 
# OF DEALING, USAGE, OR TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS
# LICENSORS BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
# DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK AND/OR ITS
# LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY OR PROBABILITY OF SUCH DAMAGES.

Reply via email to