1919from .attributeCustomControl import cleanAndFormatTooltip
2020from .connectionsCustomControl import ConnectionsCustomControl
2121from .displayCustomControl import DisplayCustomControl
22- from .materialCustomControl import MaterialCustomControl
22+ from .materialCustomControl import MaterialCustomControl , CollectionMaterialCustomControl
2323from .metadataCustomControl import MetadataCustomControl
2424from .assetInfoCustomControl import AssetInfoCustomControl
2525from .relationshipCustomControl import RelationshipCustomControl
@@ -75,7 +75,7 @@ def __init__(self, ufeSceneItem):
7575 # Get the UFE Attributes interface for this scene item.
7676 self .attrs = ufe .Attributes .attributes (self .item )
7777 self .addedAttrs = set ()
78- self .suppressedAttrs = []
78+ self .suppressedAttrs = set ()
7979 self .hasConnectionObserver = False
8080
8181 self .showArrayAttributes = False
@@ -177,9 +177,7 @@ def addControls(self, attrNames, nameMap=None):
177177 for controlCreator in AETemplate ._controlCreators :
178178 # Control can suppress attributes in the creator function
179179 # so we check for supression at each loop
180- if attrName in self .suppressedAttrs :
181- break
182- if attrName in self .addedAttrs :
180+ if self .isAttrAlreadyHandled (attrName ):
183181 break
184182
185183 try :
@@ -194,7 +192,16 @@ def addControls(self, attrNames, nameMap=None):
194192
195193 def suppress (self , attrName ):
196194 cmds .editorTemplate (suppress = attrName )
197- self .suppressedAttrs .append (attrName )
195+ self .suppressedAttrs .add (attrName )
196+
197+ def isSuppressedAttr (self , attrName ):
198+ return attrName in self .suppressedAttrs
199+
200+ def isAddedAttr (self , attrName ):
201+ return attrName in self .addedAttrs
202+
203+ def isAttrAlreadyHandled (self , attrName ):
204+ return self .isSuppressedAttr (attrName ) or self .isAddedAttr (attrName )
198205
199206 def defineCustom (self , customObj , attrs = []):
200207 create = lambda * args : customObj .onCreate (args )
@@ -205,9 +212,7 @@ def createSection(self, layoutName, attrList, schemasAttributes, collapse=False)
205212 # We create the section named "layoutName" if at least one
206213 # of the attributes from the input list exists.
207214 for attr in attrList :
208- if attr in self .suppressedAttrs :
209- continue
210- if attr in self .addedAttrs :
215+ if self .isAttrAlreadyHandled (attr ):
211216 continue
212217 if self .attrs .hasAttribute (attr ):
213218 with ufeAeTemplate .Layout (self , layoutName , collapse ):
@@ -387,7 +392,7 @@ def createCustomExtraAttrs(self, sectionName, attrs, schemasAttributes, collapse
387392 extraAttrs = []
388393 otherSchemaAttrs = {item for values in schemasAttributes .values () for item in values }
389394 for attr in self .attrs .attributeNames :
390- if attr in self .addedAttrs or attr in self . suppressedAttrs or attr in otherSchemaAttrs :
395+ if self .isAttrAlreadyHandled ( attr ) or attr in otherSchemaAttrs :
391396 continue
392397 extraAttrs .append (attr )
393398 sectionName = mel .eval ("uiRes(\" s_TPStemplateStrings.rExtraAttributes\" );" )
@@ -403,6 +408,49 @@ def createAccessibilitySection(self, sectionName, attrs, schemasAttributes, coll
403408 with ufeAeTemplate .Layout (self , sectionName , collapse = collapse ):
404409 self .addControls (attrs , nameMap = nameMap )
405410
411+ def createCollectionSection (self , sectionName , attrs , schemasAttributes , collapse , typeName ):
412+ '''
413+ Create the section for a named CollectionAPI instance, then, if that
414+ collection has a collection-based material binding authored on it, add
415+ a sibling section right underneath to edit that binding.
416+ '''
417+ self .createSection (sectionName , attrs , schemasAttributes , collapse )
418+
419+ collectionApiSuffix = 'CollectionAPI'
420+ if not typeName .endswith (collectionApiSuffix ):
421+ return
422+ instanceName = typeName [:- len (collectionApiSuffix )]
423+ if not instanceName :
424+ return
425+
426+ self .createCollectionMaterialBindingSection (instanceName )
427+
428+ def createCollectionMaterialBindingSection (self , instanceName ):
429+ '''
430+ If the named collection has a collection-based material binding
431+ authored on the prim, create a section to edit it and suppress the
432+ underlying attributes so they do not also appear in Extra Attributes.
433+ '''
434+ if not CollectionMaterialCustomControl .hasCollectionMaterial (self .prim , instanceName ):
435+ return
436+
437+ matAPI = UsdShade .MaterialBindingAPI (self .prim )
438+ authoredRelNames = []
439+ for purpose in [UsdShade .Tokens .allPurpose , UsdShade .Tokens .preview , UsdShade .Tokens .full ]:
440+ bindingRel = matAPI .GetCollectionBindingRel (instanceName , purpose )
441+ if bindingRel :
442+ authoredRelNames .append (bindingRel .GetName ())
443+
444+ layoutName = '%s Collection Material' % instanceName
445+ with ufeAeTemplate .Layout (self , layoutName , collapse = False ):
446+ createdControl = CollectionMaterialCustomControl (self .item , self .prim , instanceName , self .useNiceName )
447+ usdNoticeControl = UsdNoticeListener (self .prim , [createdControl ])
448+ self .defineCustom (createdControl )
449+ self .defineCustom (usdNoticeControl )
450+
451+ for relName in authoredRelNames :
452+ self .suppress (relName )
453+
406454 def findAppliedSchemas (self ):
407455 # loop on all applied schemas and store all those
408456 # schema into a dictionary with the attributes.
@@ -604,6 +652,10 @@ def createSchemasSections(self, schemasOrder, schemasAttributes):
604652 def addMatSection ():
605653 if not self .addedMaterialSection :
606654 self .addedMaterialSection = True
655+ # Note: collection sections are handled first because if there are *only*
656+ # collection-based material bindings, we want to show those only
657+ # and not the material section.
658+ self .createAllCollectionMaterialBindingSections ()
607659 self .createMaterialAttributeSection ()
608660
609661 # Function that determines if a section should be expanded.
@@ -632,6 +684,7 @@ def isUsdRender(prim):
632684 'assetInfo' : self .createAssetInfoSection ,
633685 'metadata' : self .createMetadataSection ,
634686 ".*AccessibilityAPI" : self .createAccessibilitySection ,
687+ ".*CollectionAPI" : self .createCollectionSection ,
635688 }
636689
637690 # We only want the attributes appearing once so if the prim
@@ -647,14 +700,18 @@ def isUsdRender(prim):
647700 attrs = schemasAttributes [typeName ]
648701 sectionName = self .sectionNameFromSchema (typeName )
649702 collapse = not isSectionOpen (sectionName )
703+ creator = self .createSection
704+ isCollectionSchema = False
650705 for pattern , value in customAttributes .items ():
651706 if re .fullmatch (pattern , typeName ):
652707 creator = value
708+ isCollectionSchema = (pattern == ".*CollectionAPI" )
653709 break
654- else :
655- creator = self .createSection
656710
657- creator (sectionName , attrs , schemasAttributes , collapse )
711+ if isCollectionSchema :
712+ creator (sectionName , attrs , schemasAttributes , collapse , typeName )
713+ else :
714+ creator (sectionName , attrs , schemasAttributes , collapse )
658715
659716 if sectionName == primTypeName :
660717 addMatSection ()
@@ -663,7 +720,10 @@ def isUsdRender(prim):
663720 addMatSection ()
664721
665722 def createMaterialAttributeSection (self ):
666- if not MaterialCustomControl .hasMaterial (self .prim ):
723+ for rel in MaterialCustomControl .findMaterialRelationships (self .prim ):
724+ if not self .isAttrAlreadyHandled (rel .GetName ()):
725+ break
726+ else :
667727 return
668728 layoutName = getMayaUsdLibString ('kLabelMaterial' )
669729 with ufeAeTemplate .Layout (self , layoutName , collapse = False ):
@@ -672,6 +732,14 @@ def createMaterialAttributeSection(self):
672732 self .defineCustom (createdControl )
673733 self .defineCustom (usdNoticeControl )
674734
735+ def createAllCollectionMaterialBindingSections (self ):
736+ collectionBindings = CollectionMaterialCustomControl .findCollectionMaterials (self .prim )
737+ for instanceName , rel in collectionBindings .items ():
738+ if self .isAttrAlreadyHandled (rel .GetName ()):
739+ continue
740+ self .createCollectionMaterialBindingSection (instanceName )
741+ self .addedAttrs .add (rel .GetName ())
742+
675743 def suppressArrayAttribute (self ):
676744 # Suppress all array attributes.
677745 if not self .showArrayAttributes :
0 commit comments