Skip to content

Commit

Permalink
StringPlugValueWidget : Show substitutions with Alt + middle-click
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Sep 26, 2024
1 parent dced4d4 commit 06a2da8
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 6 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Improvements
- Instancer :
- Improved Arnold raytracing performance for encapsulated instancers with many prototypes. All instances are now output in a single top-level procedural rather than a top-level procedural per prototype, resulting in more optimal BVH traversals in Arnold.
- Reduced scene generation time for encapsulated instancers by around 20%.
- NodeEditor : Added <kbd>Alt</kbd> + middle-click action for showing context variable substitutions in strings.

Fixes
-----
Expand Down
15 changes: 9 additions & 6 deletions python/GafferUI/PathPlugValueWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import GafferUI

from .PlugValueWidget import sole
from .StringPlugValueWidget import addSubstitutionsPopup

import os

Expand All @@ -67,13 +68,14 @@ def __init__( self, plug, path=None, pathChooserDialogueKeywords=None, **kw ) :

self.__pathChooserDialogueKeywords = pathChooserDialogueKeywords

pathWidget = GafferUI.PathWidget( self.__path )
self._addPopupMenu( pathWidget )
self.__row.append( pathWidget )
with self.__row :

button = GafferUI.Button( image = "pathChooser.png", hasFrame=False )
button.clickedSignal().connect( Gaffer.WeakMethod( self.__buttonClicked ) )
self.__row.append( button )
pathWidget = GafferUI.PathWidget( self.__path )
self._addPopupMenu( pathWidget )
addSubstitutionsPopup( pathWidget )

button = GafferUI.Button( image = "pathChooser.png", hasFrame=False )
button.clickedSignal().connect( Gaffer.WeakMethod( self.__buttonClicked ) )

pathWidget.editingFinishedSignal().connect( Gaffer.WeakMethod( self.__setPlugValue ) )

Expand Down Expand Up @@ -102,6 +104,7 @@ def getToolTip( self ) :
result += "- <kbd>Tab</kbd> to autocomplete path component\n"
result += "- Select path component (or hit <kbd>&darr;</kbd>) to show path-level contents menu\n"
result += "- Select all to show path hierarchy menu\n"
result += "- <kbd>Alt</kbd> + middle-click to show context variable substitutions\n"

return result

Expand Down
70 changes: 70 additions & 0 deletions python/GafferUI/StringPlugValueWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#
##########################################################################

import functools

import IECore

import Gaffer
Expand All @@ -59,6 +61,7 @@ def __init__( self, plugs, **kw ) :
self._addPopupMenu( self.__textWidget )

self.__textWidget.keyPressSignal().connect( Gaffer.WeakMethod( self.__keyPress ) )
addSubstitutionsPopup( self.__textWidget )
self.__textWidget.editingFinishedSignal().connect( Gaffer.WeakMethod( self.__editingFinished ) )
self.__textChangedConnection = self.__textWidget.textChangedSignal().connect( Gaffer.WeakMethod( self.__textChanged ) )

Expand All @@ -71,6 +74,15 @@ def setHighlighted( self, highlighted ) :
GafferUI.PlugValueWidget.setHighlighted( self, highlighted )
self.textWidget().setHighlighted( highlighted )

def getToolTip( self ) :

result = GafferUI.PlugValueWidget.getToolTip( self )

result += "\n## Actions\n"
result += " - <kbd>Alt</kbd> + middle-click to show context variable substitutions\n"

return result

def _updateFromValues( self, values, exception ) :

value = sole( values )
Expand Down Expand Up @@ -186,3 +198,61 @@ def __setPlugValues( self ) :
self.__textWidget.clearUndo()

GafferUI.PlugValueWidget.registerType( Gaffer.StringPlug, StringPlugValueWidget )

# Substitutions Popup
# ===================

def addSubstitutionsPopup( widget ) :

widget.buttonPressSignal().connect( __substitutionsButtonPress )
widget.buttonReleaseSignal().connect( __substitutionsButtonRelease )

def __substitutionsCopyClicked( widget, text ) :

application = widget.ancestor( GafferUI.PlugValueWidget ).scriptNode().ancestor( Gaffer.ApplicationRoot )
application.setClipboardContents( IECore.StringData( text ) )
widget.ancestor( GafferUI.Window ).close()
return True

def __substitutionsDragBegin( widget, event, text ) :

GafferUI.Pointer.setCurrent( "values" )
return text

def __substitutionsDragEnd( widget, event ) :

GafferUI.Pointer.setCurrent( None )
return True

def __substitutionsButtonPress( widget, event ) :

if event.buttons != event.Buttons.Middle or event.modifiers != event.Modifiers.Alt :
return False

# Alt + Middle click

plugValueWidget = widget.ancestor( GafferUI.PlugValueWidget )
substitutions = sole( p.substitutions() for p in plugValueWidget.getPlugs() )
if substitutions is None :
return True

text = plugValueWidget.context().substitute( widget.getText(), substitutions )
if text == widget.getText() :
return True

with GafferUI.PopupWindow() as widget.__substitutionsPopupWindow :
with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, 4 ) :
label = GafferUI.Label( f"<b>{text}</b>" )
label.buttonPressSignal().connect( lambda widget, event : True )
label.dragBeginSignal().connect( functools.partial( __substitutionsDragBegin, text = text ) )
label.dragEndSignal().connect( __substitutionsDragEnd )
button = GafferUI.Button( image = "duplicate.png", hasFrame = False, toolTip = "Copy Text" )
button.clickedSignal().connect( functools.partial( __substitutionsCopyClicked, text = text ) )

widget.__substitutionsPopupWindow.popup( parent = widget )
return True

def __substitutionsButtonRelease( widget, event ) :

# Take event to stop Alt+Middle from pasting on Linux.
return event.button == event.Buttons.Middle and event.modifiers == event.Modifiers.Alt

0 comments on commit 06a2da8

Please sign in to comment.