Skip to content

Commit

Permalink
Merge pull request GafferHQ#5980 from johnhaddon/hierarchyViewContext…
Browse files Browse the repository at this point in the history
…MenuSignal

PathListingWidget : Add column context menu signal
  • Loading branch information
johnhaddon authored Aug 1, 2024
2 parents 73bf2b3 + 1ed69bf commit baac3f1
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 10 deletions.
6 changes: 6 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ Fixes
- WidgetAlgo : Fixed issue preventing `grab()` from capturing popup menus on Windows.
- ShowURL : Fixed opening of "file://" URLs on Windows (#5861).

API
---

- PathListingWidget : Added `columnContextMenuSignal()`, allowing multiple clients to collaborate on the creation of a column-specific context menu.
- HierarchyView : Added `sceneListing()` method, to allow the context menu to be customised.

Documentation
-------------

Expand Down
24 changes: 14 additions & 10 deletions python/GafferSceneUI/HierarchyView.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def __init__( self, scriptNode, **kw ) :
self.__selectionChangedConnection = self.__pathListing.selectionChangedSignal().connect( Gaffer.WeakMethod( self.__selectionChanged ), scoped = False )
self.__expansionChangedConnection = self.__pathListing.expansionChangedSignal().connect( Gaffer.WeakMethod( self.__expansionChanged ), scoped = False )

self.__pathListing.contextMenuSignal().connect( Gaffer.WeakMethod( self.__contextMenuSignal ), scoped = False )
self.__pathListing.columnContextMenuSignal().connect( Gaffer.WeakMethod( self.__columnContextMenuSignal ), scoped = False )
self.keyPressSignal().connect( Gaffer.WeakMethod( self.__keyPressSignal ), scoped = False )

self.__plug = None
Expand All @@ -100,6 +100,17 @@ def scene( self ) :

return self.__plug

## Returns the widget used for showing the main scene listing, with the
# intention that clients can add custom context menu items via
# `sceneListing.columnContextMenuSignal()`.
#
# > Caution : This currently returns a PathListingWidget, but in future
# > will probably return a more specialised widget with fewer privileges.
# > Please limit usage to `columnContextMenuSignal()`.
def sceneListing( self ) :

return self.__pathListing

def __repr__( self ) :

return "GafferSceneUI.HierarchyView( scriptNode )"
Expand Down Expand Up @@ -209,11 +220,9 @@ def __keyPressSignal( self, widget, event ) :

return False

def __contextMenuSignal( self, widget ) :

menuDefinition = IECore.MenuDefinition()
def __columnContextMenuSignal( self, column, pathListing, menuDefinition ) :

selection = self.__pathListing.getSelection()
selection = pathListing.getSelection()
menuDefinition.append(
"Copy Path%s" % ( "" if selection.size() == 1 else "s" ),
{
Expand All @@ -231,11 +240,6 @@ def __contextMenuSignal( self, widget ) :
}
)

self.__contextMenu = GafferUI.Menu( menuDefinition )
self.__contextMenu.popup( widget )

return True

def __copySelectedPaths( self, *unused ) :

if self.__plug is None :
Expand Down
56 changes: 56 additions & 0 deletions python/GafferUI/PathListingWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def __init__(
self.__displayModeChangedSignal = GafferUI.WidgetSignal()
self.__expansionChangedSignal = GafferUI.WidgetSignal()
self.__updateFinishedSignal = GafferUI.WidgetSignal()
self.__columnContextMenuSignal = Gaffer.Signal3()

# Connections for implementing selection and drag and drop.
self.keyPressSignal().connect( Gaffer.WeakMethod( self.__keyPress ), scoped = False )
Expand All @@ -157,6 +158,7 @@ def __init__(
self.mouseMoveSignal().connect( Gaffer.WeakMethod( self.__mouseMove ), scoped = False )
self.dragBeginSignal().connect( Gaffer.WeakMethod( self.__dragBegin ), scoped = False )
self.dragEndSignal().connect( Gaffer.WeakMethod( self.__dragEnd ), scoped = False )
self.contextMenuSignal().connect( Gaffer.WeakMethod( self.__contextMenu ), scoped = False )
self.__dragPointer = "paths"

self.__path = None
Expand Down Expand Up @@ -423,6 +425,19 @@ def pathSelectedSignal( self ) :

return self.__pathSelectedSignal

## Signal emitted to generate a context menu for a column. This allows
# multiple clients to collaborate in the construction of a menu, with each
# providing different items. It should be preferred to the generic
# `Widget.contextMenuSignal()`.
#
# Slots must have the following signature, with the `menuDefinition` being
# edited directly in place :
#
# `slot( column, pathListingWidget, menuDefinition )`
def columnContextMenuSignal( self ) :

return self.__columnContextMenuSignal

def setDragPointer( self, dragPointer ) :

self.__dragPointer = dragPointer
Expand Down Expand Up @@ -749,6 +764,47 @@ def __dragEnd( self, widget, event ) :

GafferUI.Pointer.setCurrent( None )

def __contextMenu( self, widget ) :

if not self.columnContextMenuSignal().numSlots() :
# Allow legacy clients connected to `Widget.contextMenuSignal()` to
# do their own thing instead.
return False

# Select the path under the mouse, if it's not already selected.
# The user will expect to be operating on the thing under the mouse.

mousePosition = GafferUI.Widget.mousePosition( relativeTo = self )
column = self.columnAt( mousePosition )

path = self.pathAt( mousePosition )
if path is not None :
path = str( path )
selection = self.getSelection()
if isinstance( selection, IECore.PathMatcher ) :
# Row or Rows mode.
if not selection.match( path ) & IECore.PathMatcher.Result.ExactMatch :
selection = IECore.PathMatcher( [ path ] )
self.setSelection( selection )
else :
# Cell or Cells mode.
columnIndex = self.getColumns().index( column )
if not selection[columnIndex].match( path ) & IECore.PathMatcher.Result.ExactMatch :
for i in range( 0, len( selection ) ) :
selection[i] = IECore.PathMatcher() if columnIndex != i else IECore.PathMatcher( [ path ] )
self.setSelection( selection )

# Use signals to build menu and display it.

menuDefinition = IECore.MenuDefinition()
self.columnContextMenuSignal()( column, self, menuDefinition )

if menuDefinition.size() :
self.__columnContextMenu = GafferUI.Menu( menuDefinition )
self.__columnContextMenu.popup( self )

return True

def __indexAt( self, position ) :

point = self._qtWidget().viewport().mapFrom(
Expand Down

0 comments on commit baac3f1

Please sign in to comment.