diff --git a/Changes.md b/Changes.md index ea1196b9cf5..41405f2856e 100644 --- a/Changes.md +++ b/Changes.md @@ -13,6 +13,7 @@ Improvements - SceneReader : - Fixed `I/O Exception` errors triggered by closing and reopening the same USD file. - Increased the default limit for the number of open files to 2000 (or 25% of the file handle limit, whichever is lowest). +- ShaderQuery and ShaderTweaks : Added a filter for shader parameter names in the shader browser. Fixes ----- diff --git a/python/GafferSceneUI/ShaderUI.py b/python/GafferSceneUI/ShaderUI.py index 6248cc05bd5..14baea40caf 100644 --- a/python/GafferSceneUI/ShaderUI.py +++ b/python/GafferSceneUI/ShaderUI.py @@ -621,6 +621,89 @@ def __parameterValues( self ) : return None +# A path filter that keeps a path if it, any of its ancestors or any of its descendants have a +# property `propertyName` that matches `patterns`. + +class _PathMatcherPathFilter( Gaffer.PathFilter ) : + + def __init__( self, patterns, paths = [], propertyName = "name", userData = {} ) : + + Gaffer.PathFilter.__init__( self, userData ) + + self.__paths = paths + self.__patterns = patterns + self.__propertyName = propertyName + self.__pathMatcherDirty = True + self.__pathMatcher = IECore.PathMatcher() + + def setPaths( self, paths ) : + + if self.__paths == paths : + return + + self.__paths = paths + self.__pathMatcherDirty = True + self.changedSignal()( self ) + + def getPaths( self ) : + + return self.__paths + + def setMatchPatterns( self, patterns ) : + + if self.__patterns == patterns : + return + + self.__patterns = patterns + self.__pathMatcherDirty = True + self.changedSignal()( self ) + + def getMatchPatterns( self ) : + + return self.__patterns + + def setPropertyName( self, propertyName ) : + + if( self.__propertyName == propertyName ) : + return + + self.__propertyName = propertyName + self.__pathMatcherDirty = True + self.changedSignal()( self ) + + def getPropertyName( self ) : + + return self.__propertyName + + def _filter( self, paths, canceller ) : + + if self.__patterns == "" or len( paths ) == 0 : + return + + self.__updatePathMatcher() + + result = [ p for p in paths if self.__pathMatcher.match( str( p ) ) ] + + return result + + def __updatePathMatcher( self ) : + + if not self.__pathMatcherDirty : + return + + self.__pathMatcher.clear() + + for p in self.__paths : + property = p.property( self.__propertyName ) + if property is None : + continue + + for pattern in self.__patterns : + if IECore.StringAlgo.match( property, pattern ) : + self.__pathMatcher.addPath( str( p ) ) + +GafferUI.PathFilterWidget.registerType( _PathMatcherPathFilter, GafferUI.MatchPatternPathFilterWidget ) + class _ShaderParameterDialogue( GafferUI.Dialogue ) : def __init__( self, shaderNetworks, title = None, **kw ) : @@ -630,27 +713,39 @@ def __init__( self, shaderNetworks, title = None, **kw ) : GafferUI.Dialogue.__init__( self, title, **kw ) + self.__filter = _PathMatcherPathFilter( [ "" ] ) + self.__filter.setEnabled( False ) + self.__filter.userData()["UI"] = { + "editable" : True, + "label" : "Filter", + "propertyFilters" : { "name": "Name", "shader:type": "Type" } + } + self.__shaderNetworks = shaderNetworks self.__path = None tmpPath = Gaffer.DictPath( {}, "/" ) - self.__pathListingWidget = GafferUI.PathListingWidget( - tmpPath, - columns = ( - _DuplicateIconColumn( "Name", "name" ), - GafferUI.PathListingWidget.StandardColumn( "Type", "shader:type" ), - GafferUI.PathListingWidget.StandardColumn( "Value", "shader:value" ), - _ShaderInputColumn( "Input" ), - ), - allowMultipleSelection = True, - displayMode = GafferUI.PathListingWidget.DisplayMode.Tree, - sortable = False, - horizontalScrollMode = GafferUI.ScrollMode.Automatic - ) + + with GafferUI.ListContainer( spacing = 4 ) as self.__column : + self.__pathListingWidget = GafferUI.PathListingWidget( + tmpPath, + columns = ( + _DuplicateIconColumn( "Name", "name" ), + GafferUI.PathListingWidget.StandardColumn( "Type", "shader:type" ), + GafferUI.PathListingWidget.StandardColumn( "Value", "shader:value" ), + _ShaderInputColumn( "Input" ), + ), + allowMultipleSelection = True, + displayMode = GafferUI.PathListingWidget.DisplayMode.Tree, + sortable = False, + horizontalScrollMode = GafferUI.ScrollMode.Automatic + ) + + GafferUI.PathFilterWidget.create( self.__filter ) self.__inputNavigateColumn = self.__pathListingWidget.getColumns()[3] - self._setWidget( self.__pathListingWidget ) + self._setWidget( self.__column ) self.__pathListingWidget.selectionChangedSignal().connect( Gaffer.WeakMethod( self.__updateButtonState ), scoped = False ) self.__pathListingWidget.buttonReleaseSignal().connectFront( Gaffer.WeakMethod( self.__buttonRelease ), scoped = False ) @@ -664,8 +759,19 @@ def __init__( self, shaderNetworks, title = None, **kw ) : self.__updateButtonState() - self.setPath( _ShaderPath( self.__shaderNetworks, path = "/" ) ) + rootPath = _ShaderPath( self.__shaderNetworks, path = "/", filter = self.__filter ) + + def collectPaths( parentPath ) : + result = [] + for p in parentPath.children() : + result.append( p ) + result += collectPaths( p ) + + return result + + self.__filter.setPaths( collectPaths( rootPath ) ) + self.setPath( rootPath ) def getPath( self ) :