Skip to content

Commit

Permalink
ColorChooser : Custom layout for color field row
Browse files Browse the repository at this point in the history
The previous approach was causing they layout to often be resized
multiple times because we were resizing the color field widget within
the resize event. This creates a custom widget and custom layout to
achieve the same layout constraints without multiple resize events.
  • Loading branch information
ericmehl committed Sep 24, 2024
1 parent 81b4955 commit dea359b
Showing 1 changed file with 118 additions and 25 deletions.
143 changes: 118 additions & 25 deletions python/GafferUI/ColorChooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,32 +163,11 @@ def _displayTransformChanged( self ) :
GafferUI.Slider._displayTransformChanged( self )
self._qtWidget().update()

class _ColorFieldWidget( QtWidgets.QWidget ) :

def __init__( self, parent = None ) :

QtWidgets.QWidget.__init__( self, parent )

self.__size = 216

def resizeEvent( self, event ) :

w = event.size().width()
h = event.size().height()

if w != h :
self.__size = h
self.setMinimumWidth( h )

def sizeHint( self ) :

return QtCore.QSize( self.__size, self.__size )

class _ColorField( GafferUI.Widget ) :

def __init__( self, color = imath.Color3f( 1.0 ), staticComponent = "s", **kw ) :

GafferUI.Widget.__init__( self, _ColorFieldWidget(), **kw )
GafferUI.Widget.__init__( self, QtWidgets.QWidget(), **kw )

self._qtWidget().paintEvent = Gaffer.WeakMethod( self.__paintEvent )

Expand Down Expand Up @@ -472,6 +451,121 @@ def __paintEvent( self, event ) :

self.__drawValue( painter )

class _ColorFieldRowLayout( QtWidgets.QLayout ) :

def __init__( self ) :

QtWidgets.QLayout.__init__( self, None )

# No spacing between color field and sliders so the active component icons
# line up against the color field. Do add a little space between the sliders
# and the options button.
self.setSpacing( 0 )
self.__buttonSpacing = 4

self.__items = []

def addItem( self, item ) :

self.__items.append( item )

def count( self ) :

return len( self.__items )

def expandingDirections( self ) :

return QtCore.Qt.Orientations( QtCore.Qt.Orientation( 0 ) )

def itemAt( self, index ) :

return self.__items[index] if index >= 0 and index < len( self.__items ) else None

def takeAt( self, index ) :

return self.__items.pop( index ) if index >= 0 and index < len( self.__items ) else None

def minimumSize( self ) :

assert( len( self.__items ) == 3 )

return self.__size( self.__items[1].minimumSize(), self.__items[2].minimumSize() )

def maximumSize( self ) :

return QtCore.QSize( QtWidgets.QLayout.maximumSize( self ).width(), self.sizeHint().height() )

def sizeHint( self ) :

assert( len( self.__items ) == 3 )

return self.__size( self.__items[1].sizeHint(), self.__items[2].sizeHint() )

def setGeometry( self, rect ) :

assert( len( self.__items ) == 3 )

size1 = self.__items[1].sizeHint()
size2 = self.__items[2].sizeHint()

leftSize = 0
if not self.__items[0].isEmpty() :
self.__items[0].setGeometry( QtCore.QRect( rect.left(), rect.top(), size1.height(), size1.height() ) )
leftSize = size1.height()

self.__items[1].setGeometry(
QtCore.QRect(
rect.left() + leftSize,
rect.top(),
rect.width() - leftSize - size2.width() - self.__buttonSpacing,
size1.height()
)
)
self.__items[2].setGeometry(
QtCore.QRect( rect.right() - size2.width(), rect.top(), size2.width(), size2.height() )
)

def __size( self, size1, size2 ) :

return QtCore.QSize(
size1.height() + size1.width() + size2.width() + self.__buttonSpacing,
max( size1.height(), size2.height() )
)

class _ColorFieldRowContainer( GafferUI.ContainerWidget ) :

def __init__( self, **kw ) :

GafferUI.ContainerWidget.__init__( self, QtWidgets.QWidget(), **kw )

self.__qtLayout = _ColorFieldRowLayout()
self.__qtLayout.setSizeConstraint( QtWidgets.QLayout.SetMinAndMaxSize )

self._qtWidget().setLayout( self.__qtLayout )

self.__widgets = []

def addChild( self, child ) :

assert( isinstance( child, GafferUI.Widget ) )
assert( len( self.__widgets ) <=3 )

oldParent = child.parent()
if oldParent is not None :
oldParent.removeChild( child )

self.__widgets.append( child )

self.__qtLayout.addWidget( child._qtWidget() )

child._applyVisibility()

def removeChild( self, child ) :

self.__widgets.remove( child )
child._qtWidget().setParent( None )
child._applyVisibility()

class ColorChooser( GafferUI.Widget ) :

ColorChangedReason = enum.Enum( "ColorChangedReason", [ "Invalid", "SetColor", "Reset" ] )
Expand All @@ -496,7 +590,7 @@ def __init__( self, color=imath.Color3f( 1 ), **kw ) :
self.__componentValueChangedConnections = []

with self.__column :
with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 0 ) :
with _ColorFieldRowContainer() :

self.__colorField = _ColorField( color )
self.__colorValueChangedConnection = self.__colorField.valueChangedSignal().connect( Gaffer.WeakMethod( self.__colorValueChanged ) )
Expand Down Expand Up @@ -563,8 +657,7 @@ def __init__( self, color=imath.Color3f( 1 ), **kw ) :
GafferUI.MenuButton(
image = "gear.png",
menu = GafferUI.Menu( Gaffer.WeakMethod( self.__optionsMenuDefinition ) ),
hasFrame = False,
parenting = { "verticalAlignment": GafferUI.VerticalAlignment.Top }
hasFrame = False
)

# initial and current colour swatches
Expand Down

0 comments on commit dea359b

Please sign in to comment.