def __propagateExpanded( self, index, expanded ) :

		numLevels = 0
		if self.__currentEventModifiers & QtCore.Qt.ShiftModifier :
			numLevels = 10000
		elif self.__currentEventModifiers & QtCore.Qt.ControlModifier :
			numLevels = 1

		if numLevels :

			self.collapsed.disconnect( self.__collapsed )
			self.expanded.disconnect( self.__expanded )

			# This call is critical for performance. Without it,
			# QTreeView will start doing relayout for every single
			# call to setExpanded() that we make inside
			# _pathListingWidgetPropagateExpanded(). With it, it
			# waits nicely till the end and does it all at once.
			self.scheduleDelayedItemsLayout()

			# Defer to C++ to do the heavy lifting.
			_GafferUI._pathListingWidgetPropagateExpanded(
				GafferUI._qtAddress( self ),
				GafferUI._qtAddress( index ),
				expanded,
				numLevels
			)

			self.collapsed.connect( self.__collapsed )
			self.expanded.connect( self.__expanded )
Beispiel #2
0
	def testAddressAndObject( self ) :

		button = GafferUI.Button()
		address = GafferUI._qtAddress( button._qtWidget() )
		self.assertTrue( isinstance( address, int ) )
		widget = GafferUI._qtObject( address, QtGui.QPushButton )
		self.assertTrue( isinstance( widget, QtGui.QPushButton ) )
	def __init__(
		self,
		path,
		columns = defaultFileSystemColumns,
		allowMultipleSelection = False,
		displayMode = DisplayMode.List,
		**kw
	) :

		GafferUI.Widget.__init__( self, _TreeView(), **kw )

		self._qtWidget().setAlternatingRowColors( True )
		self._qtWidget().setUniformRowHeights( True )
		self._qtWidget().setEditTriggers( QtWidgets.QTreeView.NoEditTriggers )
		self._qtWidget().activated.connect( Gaffer.WeakMethod( self.__activated ) )

		if Qt.__binding__ in ( "PySide2", "PyQt5" ) :
			self._qtWidget().header().setSectionsMovable( False )
		else :
			self._qtWidget().header().setMovable( False )

		self._qtWidget().header().setSortIndicator( 0, QtCore.Qt.AscendingOrder )
		self._qtWidget().setSortingEnabled( True )

		self._qtWidget().expansionChanged.connect( Gaffer.WeakMethod( self.__expansionChanged ) )

		# install an empty model, so we an construct our selection model
		# around it. we'll update the model contents shortly in setPath().
		_GafferUI._pathListingWidgetUpdateModel( GafferUI._qtAddress( self._qtWidget() ), None )
		_GafferUI._pathListingWidgetSetColumns( GafferUI._qtAddress( self._qtWidget() ), columns )

		self.__selectionModel = QtCore.QItemSelectionModel( self._qtWidget().model() )
		self._qtWidget().setSelectionModel( self.__selectionModel )
		self.__selectionChangedSlot = Gaffer.WeakMethod( self.__selectionChanged )
		self._qtWidget().selectionModel().selectionChanged.connect( self.__selectionChangedSlot )
		if allowMultipleSelection :
			self._qtWidget().setSelectionMode( QtWidgets.QAbstractItemView.ExtendedSelection )

		self.__pathSelectedSignal = GafferUI.WidgetSignal()
		self.__selectionChangedSignal = GafferUI.WidgetSignal()
		self.__displayModeChangedSignal = GafferUI.WidgetSignal()
		self.__expansionChangedSignal = GafferUI.WidgetSignal()

		# members for implementing drag and drop
		self.__emittingButtonPress = False
		self.__borrowedButtonPress = None
		self.__buttonPressConnection = self.buttonPressSignal().connect( Gaffer.WeakMethod( self.__buttonPress ) )
		self.__buttonReleaseConnection = self.buttonReleaseSignal().connect( Gaffer.WeakMethod( self.__buttonRelease ) )
		self.__mouseMoveConnection = self.mouseMoveSignal().connect( Gaffer.WeakMethod( self.__mouseMove ) )
		self.__dragBeginConnection = self.dragBeginSignal().connect( Gaffer.WeakMethod( self.__dragBegin ) )
		self.__dragEndConnection = self.dragEndSignal().connect( Gaffer.WeakMethod( self.__dragEnd ) )
		self.__dragPointer = "paths"

		self.__path = None

		self.setDisplayMode( displayMode )
		self.setPath( path )
	def __indexForPath( self, path ) :

		result = QtCore.QModelIndex()
		_GafferUI._pathListingWidgetIndexForPath(
			GafferUI._qtAddress( self._qtWidget() ),
			path,
			GafferUI._qtAddress( result ),
		)

		return result
Beispiel #5
0
	def __createHostedQGLWidget( cls, format ) :

		# When running Gaffer embedded in a host application such as Maya
		# or Houdini, we want to be able to share OpenGL resources between
		# gaffer uis and host viewport uis, because IECoreGL will be used
		# in both. So we implement our own QGLContext class which creates a
		# context which shares with the host. The custom QGLContext is
		# implemented in GLWidgetBinding.cpp, and automatically shares with
		# the context which is current at the time of its creation. The host
		# context should therefore be made current before calling this
		# method.

		result = QtOpenGL.QGLWidget()
		_GafferUI._glWidgetSetHostedContext( GafferUI._qtAddress( result ), GafferUI._qtAddress( format ) )
		return result
Beispiel #6
0
	def _updateFromSet( self ) :

		GafferUI.NodeSetEditor._updateFromSet( self )

		del self.__column[:]
		self.__nodeUI = None
		self.__nameWidget = None

		node = self._lastAddedNode()
		if not node :
			with self.__column :
				GafferUI.Spacer( imath.V2i( 0 ) )
			return

		with self.__column :
			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, borderWidth=8, spacing=4 ) :

				GafferUI.Label( "<h4>Node Name</h4>" )
				self.__nameWidget = GafferUI.NameWidget( node )
				## \todo Make NameWidget support the readOnly metadata internally itself.
				# We can't do that easily right now, because it would need to be managing
				# the exact same `setEditable()` call that we're using here to propagate
				# our Widget readonlyness. Really our Widget readonlyness mechanism is a
				# bit lacking, and it should really be inherited automatically so we don't
				# have to propagate it like this.
				self.__nameWidget.setEditable( not self.getReadOnly() and not Gaffer.MetadataAlgo.readOnly( node ) )

				with GafferUI.ListContainer(
					GafferUI.ListContainer.Orientation.Horizontal,
					spacing=4,
					parenting = { "horizontalAlignment" : GafferUI.HorizontalAlignment.Right },
				) as infoSection :

					GafferUI.Label( "<h4>" + node.typeName().rpartition( ":" )[-1] + "</h4>" )

					button = GafferUI.Button( image = "info.png", hasFrame = False )
					url = Gaffer.Metadata.value( node, "documentation:url" )
					if url :
						button.clickedSignal().connect(
							lambda button : GafferUI.showURL( url ),
							scoped = False
						)

				toolTip = "<h3>" + node.typeName().rpartition( ":" )[2] + "</h3>"
				description = Gaffer.Metadata.nodeDescription( node )
				if description :
					toolTip += "\n\n" + description
				infoSection.setToolTip( toolTip )

				GafferUI.MenuButton(
					image = "gear.png",
					hasFrame = False,
					menu = GafferUI.Menu( Gaffer.WeakMethod( self.__menuDefinition ) )
				)

		frame = GafferUI.Frame( borderStyle=GafferUI.Frame.BorderStyle.None, borderWidth=0 )
		self.__column.append( frame, expand=True )
		self.__nodeUI = GafferUI.NodeUI.create( node )
		self.__nodeUI.setReadOnly( self.getReadOnly() )
		frame.setChild( self.__nodeUI )
	def __update( self ) :

		# update the listing if necessary. when the path itself changes, we only
		# want to update if the directory being viewed has changed. if the path
		# hasn't changed at all then we assume that the filter has changed and
		# we therefore have to update the listing anyway.
		# \todo Add an argument to Path.pathChangedSignal() to specify whether it
		# is the path or the filtering that has changed, and remove self.__currentPath.
		# Also consider whether it might be easier for the C++ PathModel to be
		# doing the signal handling at that point.

		dirPath = self.__dirPath()
		if self.__currentDir!=dirPath or str( self.__path )==self.__currentPath :

			selectedPaths = self.getSelectedPaths()
			expandedPaths = None
			if str( self.__path ) == self.__currentPath :
				# the path location itself hasn't changed so we are assuming that just the filter has.
				# if we're in the tree view mode, the user would probably be very happy
				# if we didn't forget what was expanded.
				if self.getDisplayMode() == self.DisplayMode.Tree :
					expandedPaths = self.getExpandedPaths()

			_GafferUI._pathListingWidgetUpdateModel( GafferUI._qtAddress( self._qtWidget() ), dirPath.copy() )

			if expandedPaths is not None :
				self.setExpandedPaths( expandedPaths )

			self.setSelectedPaths( selectedPaths, scrollToFirst = False, expandNonLeaf = False )

			self.__currentDir = dirPath

		self.__currentPath = str( self.__path )
Beispiel #8
0
	def __qtClipboardContentsChanged( self ) :
	
		if self.__ignoreQtClipboardContentsChanged :
			return
	
		QtGui = GafferUI._qtImport( "QtGui" )
		
		text = str( QtGui.QApplication.clipboard().text() )
		if text :
			with Gaffer.BlockedConnection( self.__clipboardContentsChangedConnection ) :
				self.root().setClipboardContents( IECore.StringData( text ) )
Beispiel #9
0
	def __clipboardContentsChanged( self, applicationRoot ) :
	
		assert( applicationRoot.isSame( self.root() ) )

		data = applicationRoot.getClipboardContents()

		QtGui = GafferUI._qtImport( "QtGui" )
		clipboard = QtGui.QApplication.clipboard()
		try :
			self.__ignoreQtClipboardContentsChanged = True # avoid triggering an unecessary copy back in __qtClipboardContentsChanged
			clipboard.setText( str( data ) )
		finally :
			self.__ignoreQtClipboardContentsChanged = False
Beispiel #10
0
    def __clipboardContentsChanged(self, applicationRoot):

        assert applicationRoot.isSame(self.root())

        data = applicationRoot.getClipboardContents()
        if isinstance(data, IECore.StringData):
            QtGui = GafferUI._qtImport("QtGui")
            clipboard = QtGui.QApplication.clipboard()
            try:
                self.__ignoreQtClipboardContentsChanged = (
                    True
                )  # avoid triggering an unecessary copy back in __qtClipboardContentsChanged
                clipboard.setText(data.value)
            finally:
                self.__ignoreQtClipboardContentsChanged = False
Beispiel #11
0
	def _updateFromSet( self ) :

		GafferUI.NodeSetEditor._updateFromSet( self )

		del self.__column[:]
		self.__nodeUI = None
		self.__nameWidget = None

		node = self._lastAddedNode()
		if not node :
			return

		with self.__column :
			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, borderWidth=8, spacing=4 ) :

				GafferUI.Label( "<h4>Node Name</h4>" )
				self.__nameWidget = GafferUI.NameWidget( node )
				self.__nameWidget.setEditable( not self.getReadOnly() )

				with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing=4 ) as infoSection :

					GafferUI.Label( "<h4>" + node.typeName().rpartition( ":" )[-1] + "</h4>" )

					button = GafferUI.Button( image = "info.png", hasFrame = False )
					url = Gaffer.Metadata.nodeValue( node, "documentation:url" )
					if url :
						button.clickedSignal().connect(
							lambda button : GafferUI.showURL( url ),
							scoped = False
						)

				toolTip = "<h3>" + node.typeName().rpartition( ":" )[2] + "</h3>"
				description = Gaffer.Metadata.nodeDescription( node )
				if description :
					toolTip += "\n\n" + description
				infoSection.setToolTip( toolTip )

				GafferUI.MenuButton(
					image = "gear.png",
					hasFrame = False,
					menu = GafferUI.Menu( Gaffer.WeakMethod( self.__menuDefinition ) )
				)

		frame = GafferUI.Frame( borderStyle=GafferUI.Frame.BorderStyle.None, borderWidth=0 )
		self.__column.append( frame, expand=True )
		self.__nodeUI = GafferUI.NodeUI.create( node )
		self.__nodeUI.setReadOnly( self.getReadOnly() )
		frame.setChild( self.__nodeUI )
	def setExpansion( self, paths ) :

		self.collapsed.disconnect( self.__collapsed )
		self.expanded.disconnect( self.__expanded )

		self.collapseAll()
		# This call is critical to performance - without
		# it an update is triggered for every call to
		# setExpanded().
		self.scheduleDelayedItemsLayout()

		_GafferUI._pathListingWidgetSetExpansion( GafferUI._qtAddress( self ), paths )

		self.collapsed.connect( self.__collapsed )
		self.expanded.connect( self.__expanded )

		self.__recalculateColumnSizes()

		self.expansionChanged.emit()
Beispiel #13
0
	def __setupClipboardSync( self ) :
	
		## This function sets up two way syncing between the clipboard held in the Gaffer::ApplicationRoot
		# and the global QtGui.QClipboard which is shared with external applications, and used by the cut and paste
		# operations in GafferUI's underlying QWidgets. This is very useful, as it allows nodes to be copied from
		# the graph and pasted into emails/chats etc, and then copied out of emails/chats and pasted into the node graph.
		#
		## \todo I don't think this is the ideal place for this functionality. Firstly, we need it in all apps
		# rather than just the gui app. Secondly, we want a way of using the global clipboard using GafferUI
		# public functions without needing an ApplicationRoot. Thirdly, it's questionable that ApplicationRoot should
		# have a clipboard anyway - it seems like a violation of separation between the gui and non-gui libraries.
		# Perhaps we should abolish the ApplicationRoot clipboard and the ScriptNode cut/copy/paste routines, relegating
		# them all to GafferUI functionality?
		
		QtGui = GafferUI._qtImport( "QtGui" )
		
		self.__clipboardContentsChangedConnection = self.root().clipboardContentsChangedSignal().connect( Gaffer.WeakMethod( self.__clipboardContentsChanged ) )
		QtGui.QApplication.clipboard().dataChanged.connect( Gaffer.WeakMethod( self.__qtClipboardContentsChanged ) )
		self.__ignoreQtClipboardContentsChanged = False
Beispiel #14
0
	def __createHoudiniQGLWidget( cls, format ) :

		try :
			import hou
		except ImportError :
			# we're not in houdini - createQGLWidget() will just make a
			# normal widget.
			return None

		import IECoreHoudini
		
		# Prior to Houdini 14 we are running embedded on the hou.ui idle loop,
		# so we needed to force the Houdini GL context to be current, and share
		# it, similar to how we do this in Maya.
		if hou.applicationVersion()[0] < 14 :
			return cls.__createHostedQGLWidget( format, IECoreHoudini.makeMainGLContextCurrent )
		
		# In Houdini 14 and beyond, Qt is the native UI, and we can access
		# Houdini's shared QGLWidget directly, provided we are using a recent
		# Cortex version.		
		return QtOpenGL.QGLWidget( format, shareWidget = GafferUI._qtObject( IECoreHoudini.sharedGLWidget(), QtOpenGL.QGLWidget ) )
Beispiel #15
0
	def __createHoudiniQGLWidget( cls, format ) :

		try :
			import hou
		except ImportError :
			# we're not in houdini - createQGLWidget() will just make a
			# normal widget.
			return None

		import IECoreHoudini

		if hasattr( IECoreHoudini, "sharedGLWidget" ) :
			# In Houdini 14 and 15, Qt is the native UI, and we can access
			# Houdini's shared QGLWidget directly.
			return QtOpenGL.QGLWidget( format, shareWidget = GafferUI._qtObject( IECoreHoudini.sharedGLWidget(), QtOpenGL.QGLWidget ) )

		# While Qt is the native UI in Houdini 16.0, they have moved away
		# from QGLWidgets for their Qt5 builds, so we need to force the
		# Houdini GL context to be current, and share it.
		IECoreHoudini.makeMainGLContextCurrent()
		return cls.__createHostedQGLWidget( format )
	def setDisplayMode( self, displayMode ) :

		if displayMode == self.getDisplayMode() :
			return

		# It is possible to implement list mode as follows :
		#
		# ```
		# self._qtWidget().setItemsExpandable( False )
		# self._qtWidget().setRootIsDecorated( False )
		# ```
		#
		# However, even when doing this QTreeView will call
		# QModel::hasChildren() anyway, causing our model to
		# recurse one level deeper than strictly necessary.
		# This can be costly, so instead we implement list
		# view by making the model flat.

		_GafferUI._pathListingWidgetSetFlat( GafferUI._qtAddress( self._qtWidget() ), displayMode == self.DisplayMode.List )

		self.__displayModeChangedSignal( self )
	def setSelection( self, paths, scrollToFirst=True, expandNonLeaf=True ) :

		assert( isinstance( paths, IECore.PathMatcher ) )

		# If there are pending changes to our path model, we must perform
		# them now, so that the model is valid with respect to the paths
		# we're trying to select.
		self.__updateLazily.flush( self )

		assert( isinstance( paths, IECore.PathMatcher ) )

		selectionModel = self._qtWidget().selectionModel()
		selectionModel.selectionChanged.disconnect( self.__selectionChangedSlot )

		selectionModel.clear()

		_GafferUI._pathListingWidgetSetSelection(
			GafferUI._qtAddress( self._qtWidget() ),
			paths, scrollToFirst, expandNonLeaf
		)

		selectionModel.selectionChanged.connect( self.__selectionChangedSlot )

		self.selectionChangedSignal()( self )
	def setColumns( self, columns ) :

		if columns == self.getColumns() :
			return

		_GafferUI._pathListingWidgetSetColumns( GafferUI._qtAddress( self._qtWidget() ), columns )
Beispiel #19
0

IECore.registerRunTimeTyped(_Camera)

GafferUI.NodeToolbar.registerCreator(_Camera.staticTypeId(),
                                     GafferUI.StandardNodeToolbar)
GafferUI.PlugValueWidget.registerCreator(_Camera.staticTypeId(), "in", None)
GafferUI.PlugValueWidget.registerCreator(_Camera.staticTypeId(), "out", None)
GafferUI.PlugValueWidget.registerCreator(_Camera.staticTypeId(), "user", None)

GafferUI.PlugValueWidget.registerCreator(
    _Camera.staticTypeId(),
    "lookAt",
    lambda plug: GafferUI.PathPlugValueWidget(
        plug,
        path=GafferScene.ScenePath(plug.node()["in"],
                                   plug.node().scriptNode().context(), "/"),
    ),
)


def __fixedWidthNumericPlugValueWidget(plug):

    result = GafferUI.NumericPlugValueWidget(plug)
    result.numericWidget().setFixedCharacterWidth(5)

    return result


GafferUI.PlugValueWidget.registerCreator(_Camera.staticTypeId(), "depth",
                                         __fixedWidthNumericPlugValueWidget)
	def getDisplayMode( self ) :

		if _GafferUI._pathListingWidgetGetFlat( GafferUI._qtAddress( self._qtWidget() ) ) :
			return self.DisplayMode.List
		else :
			return self.DisplayMode.Tree
Beispiel #21
0
	def __linkActivated( self, label, url ) :

		GafferUI.showURL( url )
Beispiel #22
0
def __fixedWidthNumericPlugValueWidget(plug):

    result = GafferUI.NumericPlugValueWidget(plug)
    result.numericWidget().setFixedCharacterWidth(5)

    return result
Beispiel #23
0
    def testExceptionsDuringCompute(self):

        # Make this scene
        #
        # - bigSphere
        #	- littleSphere (with exception in attributes expression)

        s = Gaffer.ScriptNode()

        s["s1"] = GafferScene.Sphere()
        s["s1"]["name"].setValue("bigSphere")

        s["s2"] = GafferScene.Sphere()
        s["s2"]["name"].setValue("littleSphere")
        s["s2"]["radius"].setValue(0.1)

        s["p"] = GafferScene.Parent()
        s["p"]["in"].setInput(s["s1"]["out"])
        s["p"]["children"][0].setInput(s["s2"]["out"])
        s["p"]["parent"].setValue("/bigSphere")

        s["a"] = GafferScene.StandardAttributes()
        s["a"]["in"].setInput(s["p"]["out"])
        s["a"]["attributes"]["doubleSided"]["enabled"].setValue(True)

        s["e"] = Gaffer.Expression()
        s["e"].setExpression(
            'parent["a"]["attributes"]["doubleSided"]["value"] = context["nonexistent"]'
        )

        s["f"] = GafferScene.PathFilter()
        s["f"]["paths"].setValue(
            IECore.StringVectorData(["/bigSphere/littleSphere"]))

        s["a"]["filter"].setInput(s["f"]["out"])

        # Try to view it

        sg = GafferSceneUI.SceneGadget()
        sg.setScene(s["a"]["out"])
        sg.setMinimumExpansionDepth(4)

        with GafferUI.Window() as w:
            gw = GafferUI.GadgetWidget(sg)
            gw.getViewportGadget().setPlanarMovement(False)
            gw.getViewportGadget().setCamera(
                IECoreScene.Camera(parameters={
                    "projection": "perspective",
                }))

        originalMessageHandler = IECore.MessageHandler.getDefaultHandler()
        mh = IECore.CapturingMessageHandler()
        IECore.MessageHandler.setDefaultHandler(
            IECore.LevelFilteredMessageHandler(
                mh, IECore.LevelFilteredMessageHandler.defaultLevel()))

        try:

            w.setVisible(True)
            self.waitForIdle(1000)
            sg.waitForCompletion()

            # Check we were told about the problem

            self.assertEqual(len(mh.messages), 1)
            self.assertEqual(mh.messages[0].level, mh.Level.Error)
            self.assertTrue("nonexistent" in mh.messages[0].message)

            # And that there isn't some half-assed partial scene
            # being displayed.

            self.assertTrue(sg.bound().isEmpty())
            gw.getViewportGadget().frame(
                imath.Box3f(imath.V3f(-1), imath.V3f(1)))
            self.assertObjectAt(sg, imath.V2f(0.5), None)

            # And that redraws don't cause more fruitless attempts
            # to compute the scene.

            gw.getViewportGadget().frame(
                imath.Box3f(imath.V3f(-1.1), imath.V3f(1.1)))
            self.waitForIdle(1000)

            self.assertEqual(len(mh.messages), 1)
            self.assertObjectAt(sg, imath.V2f(0.5), None)
            self.assertTrue(sg.bound().isEmpty())

            # Fix the problem with the scene, and check that we can see something now

            s["f"]["enabled"].setValue(False)
            sg.waitForCompletion()

            self.assertEqual(len(mh.messages), 1)
            self.assertFalse(sg.bound().isEmpty())
            self.assertObjectAt(sg, imath.V2f(0.5),
                                IECore.InternedStringVectorData(["bigSphere"]))

        finally:

            IECore.MessageHandler.setDefaultHandler(originalMessageHandler)
			),
		},
		{
			"label" : "Alpha Map",
			"summary" : __alphaMapSummary,
			"namesAndLabels" : (
				( "as:alpha_map", "Alpha Map" ),
			),
		},
		{
			"label" : "Photons",
			"summary" : __photonsSummary,
			"namesAndLabels" : (
				( "as:photon_target", "Photon Target" ),
			),
		},
	),
)

GafferUI.PlugValueWidget.registerCreator(
	GafferAppleseed.AppleseedAttributes,
	"attributes.alphaMap.value",
	lambda plug : GafferUI.PathPlugValueWidget( plug,
		path = Gaffer.FileSystemPath( "/", filter = Gaffer.FileSystemPath.createStandardFilter() ),
		pathChooserDialogueKeywords = {
			"bookmarks" : GafferUI.Bookmarks.acquire( plug, category = "appleseed" ),
			"leaf" : True,
		},
	),
)
            def __init__(self):

                GafferUI.TabbedContainer.__init__(self)

                self.signal = GafferUI.WidgetSignal()
Beispiel #26
0
    "sets",
    "Specifies a list of tags to be loaded and converted into gaffer sets.",
)

##########################################################################
# Widgets
##########################################################################

GafferUI.PlugValueWidget.registerCreator(
    GafferScene.SceneReader, "fileName",
    lambda plug: GafferUI.PathPlugValueWidget(
        plug,
        path=Gaffer.FileSystemPath(
            "/",
            filter=Gaffer.FileSystemPath.createStandardFilter(
                extensions=IECore.SceneInterface.supportedExtensions())),
        pathChooserDialogueKeywords={
            "bookmarks": GafferUI.Bookmarks.acquire(plug,
                                                    category="sceneCache"),
            "leaf": True,
        },
    ))

##########################################################################
# Right click menu for tags
##########################################################################


def __toggleTag(plug, tag, checked):

    tags = plug.getValue().split()
    if checked:
Beispiel #27
0
class bundleListWidget(GafferUI.EditorWidget):

    __pathSelectedSignal = GafferUI.WidgetSignal()
    __selectionChangedSignal = GafferUI.WidgetSignal()
    __displayModeChangedSignal = GafferUI.WidgetSignal()
    __expansionChangedSignal = GafferUI.WidgetSignal()
    _selectionChangedSignal = GafferUI.WidgetSignal()

    def __init__(self, scriptNode=None, **kw):
        from GafferUI.PathListingWidget import _TreeView

        __toolTip__ = '''Light Icons:
            off\t= asset not present in the scene
            green\t= asset present in the scene, and up-to-date
            red\t= asset present in the scene, but its an older/not current version
            edit\t= EDIT MODE - the scene has the source nodes for publishing a new version, and NOT the actual asset.
                   \t  If this is a render scene, please make sure to remove the original nodes and import the asset!
                   \t  (Unless renderSettings assets, since they are allways available for publishing)
        '''
        __toolTip__ += '''\nBackground:
            blue\t= shot specific asset
            yellow\t= same as edit icon
        '''

        self._script = scriptNode
        super(bundleListWidget, self).__init__(_TreeView(),
                                               scriptNode,
                                               toolTip=__toolTip__,
                                               **kw)

        # GafferUI.EditorWidget.__init__( self, QtGui.QTreeView(), scriptNode, **kw )
        self._lastLS = None

        # self._model = TreeModel(populateAssets()[0])
        # self._qtWidget().setModel(self._model)
        # self._qtWidget().expandToDepth(1)
        self.setTreeModel()
        self._mayaNodeDeleted()

        self._qtWidget().resizeColumnToContents(0)
        self._qtWidget().setColumnWidth(0, 100)
        self._qtWidget().setIndentation(10)

        self._qtWidget().setAlternatingRowColors(True)
        self._qtWidget().setUniformRowHeights(True)
        self._qtWidget().setEditTriggers(QtGui.QTreeView.NoEditTriggers)
        self._qtWidget().activated.connect(Gaffer.WeakMethod(self.__activated))
        self._qtWidget().header().setMovable(False)
        self._qtWidget().header().setSortIndicator(0, QtCore.Qt.AscendingOrder)
        self._qtWidget().setSortingEnabled(True)

        # members for implementing drag and drop
        self.__emittingButtonPress = False
        self.__borrowedButtonPress = None
        self.__buttonPressConnection = self.buttonPressSignal().connect(
            Gaffer.WeakMethod(self.__buttonPress))
        self.__buttonReleaseConnection = self.buttonReleaseSignal().connect(
            Gaffer.WeakMethod(self.__buttonRelease))
        self.__mouseMoveConnection = self.mouseMoveSignal().connect(
            Gaffer.WeakMethod(self.__mouseMove))
        self.__dragBeginConnection = self.dragBeginSignal().connect(
            Gaffer.WeakMethod(self.__dragBegin))
        self.__dragEndConnection = self.dragEndSignal().connect(
            Gaffer.WeakMethod(self.__dragEnd))
        self.__dragPointer = "paths"

        self.__contextMenuConnection = self.contextMenuSignal().connect(
            Gaffer.WeakMethod(self.__contextMenu))

        self.__hostApp = None
        # self.__dragEnterConnection = self.dragEnterSignal().connect( Gaffer.WeakMethod( self.__dragEnter ) )

        self.__path = None
        self._nodeGraph = None
        self._script = scriptNode

        self.timer = QtCore.QTimer()

        def forceRefresh():
            # import threading
            # threading.Thread( target = ).start()
            self._mayaNodeDeleted(force=True)
            self.timer.singleShot(60 * 1000, forceRefresh)

        # self.timer.singleShot( 60*1000,forceRefresh)

    def _mayaNodeDeleted(self, force=False):
        ls = []
        if assetUtils.m:
            ls = assetUtils.m.ls("|SAM*")
        # print ls
        if ls != self._lastLS or force:
            self.refresh(ls)

        def __SAM_assetList_mayaNodeDeleted__():
            def __SAM_assetList_mayaNodeDeleted_IDLE__():
                import genericAsset
                genericAsset.maya.cleanUnusedShadingNodes()
                genericAsset.maya.attachShadersLazy()
                # genericAsset.maya.setRenderSettings()
                self._mayaNodeDeleted(True)

            assetUtils.mayaLazyScriptJob(
                runOnce=True, idleEvent=__SAM_assetList_mayaNodeDeleted_IDLE__)

        assetUtils.mayaLazyScriptJob(
            runOnce=False, deleteEvent=__SAM_assetList_mayaNodeDeleted__)
        assetUtils.mayaLazyScriptJob(
            runOnce=False,
            event=['deleteAll', __SAM_assetList_mayaNodeDeleted__])
        assetUtils.mayaLazyScriptJob(
            runOnce=False,
            event=['NewSceneOpened', __SAM_assetList_mayaNodeDeleted__])
        assetUtils.mayaLazyScriptJob(
            runOnce=False,
            event=['SceneOpened', __SAM_assetList_mayaNodeDeleted__])

        # def __SAM_assetList_mayaSelectSam__():
        #     print m.ls(sl=1)
        # assetUtils.mayaLazyScriptJob( runOnce=False,  event=['SomethingSelected',__SAM_assetList_mayaSelectSam__] )

    def hostApp(self, hostAppName):
        self.__hostApp = hostAppName

    def __contextMenu(self, pathListing):
        return self._menu(pathListing)

    def _menu(self, pathListing):
        # asset=0
        # assetData=1
        # assetFullPath=2
        # assetOP=3
        # assetOPSourceExistsInHost=4

        menuDefinition = IECore.MenuDefinition()
        selectedData = pathListing.getSelectedColumns()
        selectedPaths = selectedData['assetFullPath']
        selectedPathsOP = selectedData['assetOP']
        selectedPathsExistInHost = selectedData['assetOPSourceExistsInHost']
        # for path in selectedPaths:

        selected_source_exists_in_host = False if [
            x for x in selectedPathsExistInHost if x
        ] else True

        isAssetMenu = [x for x in selectedPaths if len(x.split('/')) > 2]
        isPublishMenu = [x for x in selectedPaths if len(x.split('/')) <= 2]

        if isAssetMenu:

            def checkout(paths):
                def __SAM_assetList_doImport__():
                    import genericAsset
                    pb = genericAsset.progressBar(
                        len(paths) + 1, "Importing assets...")
                    for path in paths:
                        pb.step()
                        print path
                        op = assetUtils.assetOP(path)
                        op.doImport()
                    pb.step()
                    pb.close()
                    self._mayaNodeDeleted()
                    # print op, path

                __SAM_assetList_doImport__()
                # assetUtils.mayaLazyScriptJob( runOnce=True,  idleEvent=__SAM_assetList_doImport__)

            canImport = selected_source_exists_in_host
            if len(selectedPaths) == 1:
                if 'renderSettings/' in selectedPaths[0]:
                    canImport = True
            menuDefinition.append(
                "/Import selected", {
                    "command": IECore.curry(checkout, selectedPaths),
                    "active": canImport
                })

            if len(selectedPaths) == 1:
                menuDefinition.append("/  ", {})
                menuDefinition.append("/ ", {})

                def updateAsset(asset):
                    op = assetUtils.assetOP(asset[0])
                    op.updatePublish()

                menuDefinition.append(
                    "/Publish an UPDATE to the selected asset", {
                        "command": IECore.curry(updateAsset, selectedPaths),
                        "active": not selected_source_exists_in_host
                    })
                menuDefinition.append("/", {})

                def mayaImportDependency(paths):
                    def __SAM_assetList_mayaImportDependency__():
                        # print paths
                        for path in paths:
                            # print path
                            op = assetUtils.assetOP(path)
                            op.mayaImportDependency()

                    if assetUtils.m:
                        assetUtils.mayaLazyScriptJob(
                            runOnce=True,
                            idleEvent=__SAM_assetList_mayaImportDependency__)
                    else:
                        __SAM_assetList_mayaImportDependency__()

                def mayaOpenDependency(paths):
                    def __SAM_assetList_mayaOpenDependency__():
                        # print paths
                        for path in paths:
                            # print path
                            op = assetUtils.assetOP(path)
                            op.mayaOpenDependency()

                    if assetUtils.m:
                        assetUtils.mayaLazyScriptJob(
                            runOnce=True,
                            idleEvent=__SAM_assetList_mayaOpenDependency__)
                    else:
                        __SAM_assetList_mayaOpenDependency__()

                if assetUtils.m:
                    menuDefinition.append(
                        "/open original scene in this maya session ", {
                            "command":
                            IECore.curry(mayaImportDependency, selectedPaths)
                        })
                menuDefinition.append(
                    "/open original scene in a new maya session ", {
                        "command": IECore.curry(mayaOpenDependency,
                                                selectedPaths)
                    })

        elif isPublishMenu and len(selectedPaths) == 1:
            from pprint import pprint
            types = assetUtils.Asset.types(refresh=True)
            atype = selectedPaths[0].split('/')[0]

            def createNewAsset(paths, assetType):
                op = assetUtils.assetOP(assetType)
                op.newPublish()

            for t in [x for x in types if atype in x.split('/')]:
                if 'render/' in t:
                    if assetUtils.m and 'render/maya' not in t:
                        continue

                menuDefinition.append(
                    "/publish new asset of type %s" % t.replace('/', '_'), {
                        "command": IECore.curry(createNewAsset, selectedPaths,
                                                t)
                    })

        self.__menu = GafferUI.Menu(menuDefinition)
        if len(menuDefinition.items()):
            self.__menu.popup(parent=pathListing.ancestor(GafferUI.Window))

        return True

    def refresh(self, lastLS=None):
        self.setTreeModel()
        if self._lastLS != lastLS:
            self._lastLS = lastLS
            self._model.refresh(self._lastLS)

    def setTreeModel(self):
        self._model = TreeModel(populateAssets()[0])
        self._qtWidget().setModel(self._model)
        self._qtWidget().expandToDepth(1)
        self._qtWidget().setSelectionMode(
            QtGui.QAbstractItemView.ExtendedSelection)
        self.__selectionChangedSlot = Gaffer.WeakMethod(
            self.__selectionChanged)
        self._qtWidget().selectionModel().selectionChanged.connect(
            self.__selectionChangedSlot)
        self._qtWidget().setSelectionMode(
            QtGui.QAbstractItemView.ExtendedSelection)

    def getTitle(self):
        return 'SAM Bundle List'

    def __repr__(self):

        return "GafferUI.SAMbundleListWidget( scriptNode )"

    def setNodeGraph(self, nodeGraph):
        self._nodeGraph = nodeGraph

    def setScript(self, script):
        self._script = script

    def getSelectedPaths(self):
        selectedRows = self._qtWidget().selectionModel().selectedRows()
        # print [ index.internalPointer().data(TreeItem.assetFullPath) for index in selectedRows ]
        return [
            index.internalPointer().data(TreeItem.assetFullPath)
            for index in selectedRows
        ]

    def getSelectedColumns(self):
        selectedRows = self._qtWidget().selectionModel().selectedRows()
        # print [ index.internalPointer().data(TreeItem.assetFullPath) for index in selectedRows ]
        ret = {}
        for column in [x for x in dir(TreeItem) if 'asset' in x]:
            ret[column] = []
            for index in selectedRows:
                ret[column] += [
                    index.internalPointer().data(eval('TreeItem.%s' % column))
                ]
        return ret

    # def setSelectedPaths( self, paths, scrollToFirst=True, expandNonLeaf=True ) :
    #
    #     # If there are pending changes to our path model, we must perform
    #     # them now, so that the model is valid with respect to the paths
    #     # we're trying to select.
    #     self.__updateLazily.flush( self )
    #     selectionModel = self._qtWidget().selectionModel()
    #     selectionModel.selectionChanged.disconnect( self.__selectionChangedSlot )
    #
    #     selectionModel.clear()
    #
    #     for path in paths :
    #
    #         indexToSelect = self.__indexForPath( path )
    #         if indexToSelect.isValid() :
    #             selectionModel.select( indexToSelect, selectionModel.Select | selectionModel.Rows )
    #             if scrollToFirst :
    #                 self._qtWidget().scrollTo( indexToSelect, self._qtWidget().EnsureVisible )
    #                 selectionModel.setCurrentIndex( indexToSelect, selectionModel.Current )
    #                 scrollToFirst = False
    #             if expandNonLeaf and not path.isLeaf() :
    #                 self._qtWidget().setExpanded( indexToSelect, True )
    #
    #     selectionModel.selectionChanged.connect( self.__selectionChangedSlot )
    #
    #     self.selectionChangedSignal()( self )

    def __selectionChanged(self, selected, deselected):
        self.selectionChangedSignal()(self)
        return True

    def selectionChangedSignal(self):
        if assetUtils.m:
            assetUtils.m.select(cl=1)
            selectedData = self.getSelectedColumns()
            # print selectedData
            for n in range(len(selectedData['assetFullPath'])):
                path, op = selectedData['assetFullPath'][n], selectedData[
                    'assetOP'][n]
                # print path
                # op = assetUtils.assetOP( path )
                if op:
                    nodes = op.assetSourceExistsInHost()
                    if nodes and 'renderSettings' not in path:
                        if assetUtils.m:
                            assetUtils.m.select(nodes)
                    else:
                        op.mayaSelectNodes()
                # self.refresh(op.mayaLastLs())

        self.parent()._qtWidget().emit(
            QtCore.SIGNAL("selectionChangedSignal(PyQt_PyObject)"),
            {"self": self})

        return self.__selectionChangedSignal

    def __pathForIndex(self, modelIndex):
        if type(modelIndex) == list:
            return [
                Gaffer.Path(index.internalPointer().data(
                    TreeItem.assetFullPath)) for index in modelIndex
            ]
        else:
            return Gaffer.Path(modelIndex.internalPointer().data(
                TreeItem.assetFullPath))

    def __activated(self, modelIndex):

        activatedPath = self.__pathForIndex(modelIndex)

        self.__path = activatedPath
        if type(activatedPath) == list:
            self.__path[:] = activatedPath[:]

        if activatedPath.isLeaf():
            self.pathSelectedSignal()(self)
            return True

        return False

    ## This signal is emitted when the user double clicks on a leaf path.
    def pathSelectedSignal(self):

        return self.__pathSelectedSignal

    def __buttonPress(self, widget, event):

        if self.__emittingButtonPress:
            return False

        self.__borrowedButtonPress = None
        if event.buttons == event.Buttons.Left and event.modifiers == event.Modifiers.None:

            # We want to implement drag and drop of the selected items, which means borrowing
            # mouse press events that the QTreeView needs to perform selection and expansion.
            # This makes things a little tricky. There are are two cases :
            #
            #  1) There is an existing selection, and it's been clicked on. We borrow the event
            #     so we can get a dragBeginSignal(), and to prevent the QTreeView reducing a current
            #     multi-selection down to the single clicked item. If a drag doesn't materialise we'll
            #     re-emit the event straight to the QTreeView in __buttonRelease so the QTreeView can
            #     do its thing.
            #
            #  2) There is no existing selection. We pass the event to the QTreeView
            #     to see if it will select something which we can subsequently drag.
            #
            # This is further complicated by the fact that the button presses we simulate for Qt
            # will end up back in this function, so we have to be careful to ignore those.

            index = self._qtWidget().indexAt(
                QtCore.QPoint(event.line.p0.x, event.line.p0.y))
            if self._qtWidget().selectionModel().isSelected(index):
                # case 1 : existing selection.
                self.__borrowedButtonPress = event
                return True
            else:
                # case 2 : no existing selection.
                # allow qt to update the selection first.
                self.__emitButtonPress(event)
                # we must always return True to prevent the event getting passed
                # to the QTreeView again, and so we get a chance to start a drag.
                return True

        return False

    def __buttonRelease(self, widget, event):

        if self.__borrowedButtonPress is not None:
            self.__emitButtonPress(self.__borrowedButtonPress)
            self.__borrowedButtonPress = None

        return False

    def __mouseMove(self, widget, event):

        if event.buttons:
            # take the event so that the underlying QTreeView doesn't
            # try to do drag-selection, which would ruin our own upcoming drag.
            return True

        return False

    def __dragBegin(self, widget, event):

        self.__borrowedButtonPress = None
        selectedPaths = self.getSelectedPaths()
        if len(selectedPaths):
            GafferUI.Pointer.setCurrent(self.__dragPointer)
            each = str(selectedPaths[0])
            print each
            node = Gaffer.Node('_'.join(each.split('/')[:-1]))
            node['in'] = Gaffer.Plug()
            node['out'] = Gaffer.Plug(direction=Gaffer.Plug.Direction.Out)
            return node

            return IECore.StringVectorData([str(p) for p in selectedPaths], )
        return None

    def __dragEnter(self, widget, event):
        print widget
        print event.destinationGadget
        print event.destinationWidget
        sys.stdout.flush()

    def __dragEnd(self, widget, event):
        import sys
        for each in event.data:
            # node =  Gaffer.Node( '_'.join(each.split('/')[:-1]) )
            # node['in']= Gaffer.Plug(  )
            # node['out']= Gaffer.Plug( direction = Gaffer.Plug.Direction.Out )
            if event.destinationGadget:
                event.destinationGadget.ScriptNode.addChild(node)
        # print dir(event)
        print widget
        print event.destinationGadget
        print event.destinationWidget
        sys.stdout.flush()

        # self.__viewportGadget.dragEndSignal()( self.__viewportGadget, event )

        # if self._nodeGraph:
        #     graph = self._nodeGraph.graphGadget()
        #     graph.getLayout().layoutNodes( graph )
        GafferUI.Pointer.setCurrent(None)

    def __emitButtonPress(self, event):

        qEvent = QtGui.QMouseEvent(
            QtCore.QEvent.MouseButtonPress,
            QtCore.QPoint(event.line.p0.x, event.line.p0.y),
            QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)

        try:
            self.__emittingButtonPress = True
            # really i think we should be using QApplication::sendEvent()
            # here, but it doesn't seem to be working. it works with the qObject
            # in the Widget event filter, but for some reason that differs from
            # Widget._owner( qObject )._qtWidget() which is what we have here.
            self._qtWidget().mousePressEvent(qEvent)
        finally:
            self.__emittingButtonPress = False
Beispiel #28
0
class GraphEditor( GafferUI.Editor ) :

	def __init__( self, scriptNode, **kw ) :

		# We want to disable precise navigation motions as they interfere
		# with our keyboard shortcuts and aren't that useful in the graph
		viewportGadget = GafferUI.ViewportGadget()
		viewportGadget.setPreciseMotionAllowed( False )
		viewportGadget.setMaxPlanarZoom( imath.V2f( 25 ) )

		self.__gadgetWidget = GafferUI.GadgetWidget(
			gadget = viewportGadget,
			bufferOptions = set( [
				GafferUI.GLWidget.BufferOptions.Double,
			] ),
		)

		GafferUI.Editor.__init__( self, self.__gadgetWidget, scriptNode, **kw )

		graphGadget = GafferUI.GraphGadget( self.scriptNode() )
		self.__rootChangedConnection = graphGadget.rootChangedSignal().connect( Gaffer.WeakMethod( self.__rootChanged ) )

		self.__gadgetWidget.getViewportGadget().setPrimaryChild( graphGadget )
		self.__gadgetWidget.getViewportGadget().setDragTracking( GafferUI.ViewportGadget.DragTracking.XDragTracking | GafferUI.ViewportGadget.DragTracking.YDragTracking )
		self.__frame( scriptNode.selection() )

		self.__gadgetWidget.buttonPressSignal().connect( Gaffer.WeakMethod( self.__buttonPress ), scoped = False )
		self.__gadgetWidget.keyPressSignal().connect( Gaffer.WeakMethod( self.__keyPress ), scoped = False )
		self.__gadgetWidget.buttonDoubleClickSignal().connect( Gaffer.WeakMethod( self.__buttonDoubleClick ), scoped = False )
		self.dragEnterSignal().connect( Gaffer.WeakMethod( self.__dragEnter ), scoped = False )
		self.dragLeaveSignal().connect( Gaffer.WeakMethod( self.__dragLeave ), scoped = False )
		self.dropSignal().connect( Gaffer.WeakMethod( self.__drop ), scoped = False )
		self.__gadgetWidget.getViewportGadget().preRenderSignal().connect( Gaffer.WeakMethod( self.__preRender ), scoped = False )

		with GafferUI.ListContainer( borderWidth = 8, spacing = 0 ) as overlay :
			with GafferUI.ListContainer(
				GafferUI.ListContainer.Orientation.Horizontal,
				parenting = {
					"verticalAlignment" : GafferUI.VerticalAlignment.Top,
				}
			) :
				GafferUI.Spacer( imath.V2i( 1 ) )
				GafferUI.MenuButton(
					image = "annotations.png", hasFrame = False,
					menu = GafferUI.Menu(
						Gaffer.WeakMethod( self.__annotationsMenu ),
						title = "Annotations"
					)
				)

		self.__gadgetWidget.addOverlay( overlay )

		self.__nodeMenu = None

	## Returns the internal GadgetWidget holding the GraphGadget.
	def graphGadgetWidget( self ) :

		return self.__gadgetWidget

	## Returns the internal Gadget used to draw the graph. This may be
	# modified directly to set up appropriate filters etc. This is just
	# a convenience method returning graphGadgetWidget().getViewportGadget().getPrimaryChild().
	def graphGadget( self ) :

		return self.graphGadgetWidget().getViewportGadget().getPrimaryChild()

	## Frames the specified nodes in the viewport. If extend is True
	# then the current framing will be extended to include the specified
	# nodes, if False then the framing will be reset to frame only the
	# nodes specified.
	def frame( self, nodes, extend=False ) :

		self.__frame( nodes, extend )

	def getTitle( self ) :

		title = super( GraphEditor, self ).getTitle()
		if title:
			return title

		result = IECore.CamelCase.toSpaced( self.__class__.__name__ )

		root = self.graphGadget().getRoot()
		if not root.isSame( self.scriptNode() ) :
			result += " : " + root.relativeName( self.scriptNode() ).replace( ".", " / " )

		return result

	__plugContextMenuSignal = Gaffer.Signal3()
	## Returns a signal which is emitted to create a context menu for a
	# plug in the graph. Slots may connect to this signal to edit the
	# menu definition on the fly - the signature for the signal is
	# ( graphEditor, plug, menuDefinition ) and the menu definition should just be
	# edited in place.
	@classmethod
	def plugContextMenuSignal( cls ) :

		return cls.__plugContextMenuSignal

	__connectionContextMenuSignal = Gaffer.Signal3()
	## Returns a signal which is emitted to create a context menu for a
	# connection in the graph. Slots may connect to this signal to edit the
	# menu definition on the fly - the signature for the signal is
	# ( graphEditor, destinationPlug, menuDefinition ) and the menu definition
	# should just be edited in place.
	@classmethod
	def connectionContextMenuSignal( cls ) :

		return cls.__connectionContextMenuSignal

	@classmethod
	def appendConnectionNavigationMenuDefinitions( cls, graphEditor, destinationPlug, menuDefinition ) :

		def __append( plug, label ) :

			node = plug.node()
			nodeGadget = graphEditor.graphGadget().nodeGadget( node ) if node is not None else None

			menuDefinition.append(
				"/Navigate/Go to " + label,
				{
					"active" : nodeGadget is not None,
					"command" : functools.partial(
						Gaffer.WeakMethod( graphEditor.frame ), [ node ]
					)
				}
			)

			menuDefinition.append(
				"/Navigate/Select " + label,
				{
					"active" : node is not None,
					"command" : functools.partial(
						cls.__select, node
					)
				}
			)

		__append( destinationPlug.getInput(), "Source Node" )
		__append( destinationPlug, "Destination Node" )

	__nodeContextMenuSignal = Gaffer.Signal3()
	## Returns a signal which is emitted to create a context menu for a
	# node in the graph. Slots may connect to this signal to edit the
	# menu definition on the fly - the signature for the signal is
	# ( graphEditor, node, menuDefinition ) and the menu definition should just be
	# edited in place. Typically you would add slots to this signal
	# as part of a startup script.
	@classmethod
	def nodeContextMenuSignal( cls ) :

		return cls.__nodeContextMenuSignal

	## May be used from a slot attached to nodeContextMenuSignal() to install some
	# standard menu items for modifying the connection visibility for a node.
	@classmethod
	def appendConnectionVisibilityMenuDefinitions( cls, graphEditor, node, menuDefinition ) :

		def plugDirectionsWalk( gadget ) :

			result = set()
			if isinstance( gadget, GafferUI.Nodule ) :
				result.add( gadget.plug().direction() )

			for c in gadget.children() :
				result |= plugDirectionsWalk( c )

			return result

		plugDirections = plugDirectionsWalk( graphEditor.graphGadget().nodeGadget( node ) )
		if not plugDirections :
			return

		readOnly = Gaffer.MetadataAlgo.readOnly( node )

		menuDefinition.append( "/ConnectionVisibilityDivider", { "divider" : True } )

		if Gaffer.Plug.Direction.In in plugDirections :
			menuDefinition.append(
				"/Show Input Connections",
				{
					"checkBox" : functools.partial( cls.__getNodeInputConnectionsVisible, graphEditor.graphGadget(), node ),
					"command" : functools.partial( cls.__setNodeInputConnectionsVisible, graphEditor.graphGadget(), node ),
					"active" : not readOnly,
				}
			)

		if Gaffer.Plug.Direction.Out in plugDirections :
			menuDefinition.append(
				"/Show Output Connections",
				{
					"checkBox" : functools.partial( cls.__getNodeOutputConnectionsVisible, graphEditor.graphGadget(), node ),
					"command" : functools.partial( cls.__setNodeOutputConnectionsVisible, graphEditor.graphGadget(), node ),
					"active" : not readOnly
				}
			)

	## May be used from a slot attached to nodeContextMenuSignal() to install a
	# standard menu item for modifying the enabled state of a node.
	@classmethod
	def appendEnabledPlugMenuDefinitions( cls, graphEditor, node, menuDefinition ) :

		enabledPlug = node.enabledPlug() if isinstance( node, Gaffer.DependencyNode ) else None
		if enabledPlug is not None :
			menuDefinition.append( "/EnabledDivider", { "divider" : True } )
			menuDefinition.append(
				"/Enabled",
				{
					"command" : functools.partial( cls.__setEnabled, node ),
					"checkBox" : enabledPlug.getValue(),
					"active" : enabledPlug.settable() and not Gaffer.MetadataAlgo.readOnly( enabledPlug )
				}
			)

	@classmethod
	def appendContentsMenuDefinitions( cls, graphEditor, node, menuDefinition ) :

		menuDefinition.append( "/FocusDivider", { "divider" : True } )
		menuDefinition.append( "/Focus", {
			"command" : functools.partial( graphEditor.scriptNode().setFocus, node ),
			"active" : not node.isSame( graphEditor.scriptNode().getFocus() ),
			"shortCut" : "Ctrl+`"
		} )

		if not GraphEditor.__childrenViewable( node ) :
			return

		menuDefinition.append( "/ContentsDivider", { "divider" : True } )
		menuDefinition.append( "/Show Contents...", { "command" : functools.partial( cls.acquire, node ) } )

	__nodeDoubleClickSignal = GafferUI.WidgetEventSignal()
	## Returns a signal which is emitted whenever a node is double clicked.
	# Slots should have the signature ( graphEditor, node ).
	@classmethod
	def nodeDoubleClickSignal( cls ) :

		return cls.__nodeDoubleClickSignal

	## Ensures that the specified node has a visible GraphEditor viewing
	# it, and returns that editor.
	## \todo Consider how this relates to the todo items in NodeSetEditor.acquire().
	@classmethod
	def acquire( cls, rootNode ) :

		if isinstance( rootNode, Gaffer.ScriptNode ) :
			script = rootNode
		else :
			script = rootNode.scriptNode()

		scriptWindow = GafferUI.ScriptWindow.acquire( script )
		tabbedContainer = None
		for editor in scriptWindow.getLayout().editors( type = GafferUI.GraphEditor ) :
			if rootNode.isSame( editor.graphGadget().getRoot() ) :
				editor.parent().setCurrent( editor )
				return editor

		editor = GraphEditor( script )
		editor.graphGadget().setRoot( rootNode )
		scriptWindow.getLayout().addEditor( editor )

		return editor

	def __repr__( self ) :

		return "GafferUI.GraphEditor( scriptNode )"

	def _nodeMenu( self ) :

		if self.__nodeMenu is None :
			self.__nodeMenu = GafferUI.Menu( GafferUI.NodeMenu.acquire( self.scriptNode().applicationRoot() ).definition(), searchable=True )
			self.__nodeMenu.visibilityChangedSignal().connect( Gaffer.WeakMethod( self.__nodeMenuVisibilityChanged ), scoped = False )

		return self.__nodeMenu

	def __nodeMenuVisibilityChanged( self, widget ) :

		assert( widget is self.__nodeMenu )

		if not self.__nodeMenu.visible() :
			# generally we steal focus on mouse enter (implemented in GadgetWidget),
			# but when the node menu closes we may not get an enter event, so we have to steal
			# the focus back here.
			self.__gadgetWidget._qtWidget().setFocus()

	def __buttonPress( self, widget, event ) :

		if event.buttons & GafferUI.ButtonEvent.Buttons.Right :

			# right click - display either the node creation popup menu
			# or a menu specific to the node/plug/connection under the
			# mouse if possible.

			viewport = self.__gadgetWidget.getViewportGadget()
			gadgets = viewport.gadgetsAt( imath.V2f( event.line.p1.x, event.line.p1.y ) )
			if len( gadgets ) :

				overrideMenuDefinition = IECore.MenuDefinition()
				overrideMenuTitle = None

				if isinstance( gadgets[0], GafferUI.Nodule ) :
					self.plugContextMenuSignal()( self, gadgets[0].plug(), overrideMenuDefinition )
					overrideMenuTitle = gadgets[0].plug().relativeName( self.graphGadget().getRoot() )
				elif isinstance( gadgets[0], GafferUI.ConnectionGadget ) :
					self.connectionContextMenuSignal()( self, gadgets[0].dstNodule().plug(), overrideMenuDefinition )
					overrideMenuTitle = "-> " + gadgets[0].dstNodule().plug().relativeName( self.graphGadget().getRoot() )
				else :
					nodeGadget = gadgets[0]
					if not isinstance( nodeGadget, GafferUI.NodeGadget ) :
						nodeGadget = nodeGadget.ancestor( GafferUI.NodeGadget )
					if nodeGadget is not None :
						self.nodeContextMenuSignal()( self, nodeGadget.node(), overrideMenuDefinition )
						overrideMenuTitle = nodeGadget.node().getName()

				if len( overrideMenuDefinition.items() ) :
					menuDefinition = overrideMenuDefinition
					self._m = GafferUI.Menu( menuDefinition, title=overrideMenuTitle )
					self._m.popup( self )
					return True

			if not (
				Gaffer.MetadataAlgo.getChildNodesAreReadOnly( self.graphGadget().getRoot() ) or
				Gaffer.MetadataAlgo.readOnly( self.graphGadget().getRoot() )
			):
				self._nodeMenu().popup( self )
				return True

		return False

	def __nodeGadgetAt( self, position ) :

		viewport = self.__gadgetWidget.getViewportGadget()
		line = viewport.rasterToGadgetSpace( imath.V2f( position.x, position.y ), gadget = self.graphGadget() )
		return self.graphGadget().nodeGadgetAt( line )

	def __keyPress( self, widget, event ) :

		if event.key == "F" and not event.modifiers :
			self.__frame( self.scriptNode().selection() )
			return True
		elif event.key == "QuoteLeft" and not event.modifiers :
			self.__frame( [ self.scriptNode().getFocus() ] )
			return True
		elif event.key == "QuoteLeft" and event.modifiers == event.modifiers.Control :
			selection = self.scriptNode().selection()
			if len( selection ) > 0 :
				self.scriptNode().setFocus( selection[0] )
		elif event.key == "Down" :
			selection = self.scriptNode().selection()
			if selection.size() == 1 and selection[0].parent() == self.graphGadget().getRoot() :
				needsModifiers = not GraphEditor.__childrenViewable( selection[0] )
				if (
					( needsModifiers and event.modifiers == event.modifiers.Shift | event.modifiers.Control ) or
					( not needsModifiers and event.modifiers == event.modifiers.None_ )
				) :
					self.graphGadget().setRoot( selection[0] )
					return True
		elif event.key == "Up" :
			root = self.graphGadget().getRoot()
			if not isinstance( root, Gaffer.ScriptNode ) :
				self.graphGadget().setRoot( root.parent() )
				return True
		elif event.key == "Tab" :
			if not (
				Gaffer.MetadataAlgo.getChildNodesAreReadOnly( self.graphGadget().getRoot() ) or
				Gaffer.MetadataAlgo.readOnly( self.graphGadget().getRoot() )
			):
				self._nodeMenu().popup( self )
				return True

		return False

	def __frame( self, nodes, extend = False, at = None ) :

		graphGadget = self.graphGadget()

		# get the bounds of the nodes
		bound = imath.Box3f()
		for node in nodes :
			nodeGadget = graphGadget.nodeGadget( node )
			if nodeGadget :
				bound.extendBy( nodeGadget.transformedBound( graphGadget ) )

		# if there were no nodes then use the bound of the whole
		# graph.
		if bound.isEmpty() :
			bound = graphGadget.bound()

		# if there's still nothing then an arbitrary area in the centre of the world
		if bound.isEmpty() :
			bound = imath.Box3f( imath.V3f( -10, -10, 0 ), imath.V3f( 10, 10, 0 ) )

		# pad it a little bit so
		# it sits nicer in the frame
		bound.setMin( bound.min() - imath.V3f( 1, 1, 0 ) )
		bound.setMax( bound.max() + imath.V3f( 1, 1, 0 ) )

		if extend :
			# we're extending the existing framing, which we assume the
			# user was happy with other than it not showing the nodes in question.
			# so we just take the union of the existing frame and the one for the nodes.
			cb = self.__currentFrame()
			bound.extendBy( imath.Box3f( imath.V3f( cb.min().x, cb.min().y, 0 ), imath.V3f( cb.max().x, cb.max().y, 0 ) ) )
		else :
			# we're reframing from scratch, so the frame for the nodes is all we need.
			# we do however want to make sure that we don't zoom in too far if the node
			# bounds are small, as having a single node filling the screen is of little use -
			# it's better to see some context around it.
			boundSize = bound.size()
			widgetSize = imath.V3f( self._qtWidget().width(), self._qtWidget().height(), 0 )

			pixelsPerUnit = min( widgetSize.x / boundSize.x, widgetSize.y / boundSize.y )
			adjustedPixelsPerUnit = min( pixelsPerUnit, 10 )

			newBoundSize = widgetSize / adjustedPixelsPerUnit
			boundCenter = bound.center()
			bound.setMin( boundCenter - newBoundSize / 2.0 )
			bound.setMax( boundCenter + newBoundSize / 2.0 )

		self.__gadgetWidget.getViewportGadget().frame( bound )

		if at is not None :
			# Offset the bound and reframe so that the centre of the bound moves
			# to `at`, which is specified in raster space. We have to do this
			# _after_ the initial call to `frame()` because
			# `rasterToGadgetSpace()` is affected by the zoom calculated by
			# `frame()`. Because we are not changing the size of the bound, the
			# second call to `frame()` will use the same zoom.
			viewport = self.graphGadgetWidget().getViewportGadget()
			offset = viewport.rasterToGadgetSpace( imath.V2f( self.bound().size() / 2 ), graphGadget ).p0 - viewport.rasterToGadgetSpace( at, graphGadget ).p0
			bound.setMin( bound.min() + offset )
			bound.setMax( bound.max() + offset )
			self.__gadgetWidget.getViewportGadget().frame( bound )

	def __buttonDoubleClick( self, widget, event ) :

		nodeGadget = self.__nodeGadgetAt( event.line.p1 )
		if nodeGadget is not None :
			return self.nodeDoubleClickSignal()( self, nodeGadget.node() )

	def __dragEnter( self, widget, event ) :

		if event.sourceWidget is self.__gadgetWidget :
			return False

		if self.__dropNodes( event.data ) :
			self.__dragEnterPointer = GafferUI.Pointer.getCurrent()
			GafferUI.Pointer.setCurrent( "target" )
			return True

		return False

	def __dragLeave( self, widget, event ) :

		GafferUI.Pointer.setCurrent( self.__dragEnterPointer )
		return True

	def __drop( self, widget, event ) :

		if event.sourceWidget is self.__gadgetWidget :
			return False

		dropNodes = self.__dropNodes( event.data )
		if dropNodes :
			self.graphGadget().setRoot( dropNodes[0].parent() )
			self.__frame( dropNodes, at = imath.V2f( event.line.p0.x, event.line.p0.y ) )
			return True

		return False

	def __dropNodes( self, dragData ) :

		if isinstance( dragData, Gaffer.Node ) :
			return [ dragData ]
		elif isinstance( dragData, Gaffer.Set ) :
			nodes = [ x for x in dragData if isinstance( x, Gaffer.Node ) ]
			if len( set( n.parent() for n in nodes ) ) == 1 :
				# Can only frame nodes if they all share the same parent.
				return nodes

		return []

	def __currentFrame( self ) :
		viewportGadget = self.graphGadgetWidget().getViewportGadget()

		rasterMin = viewportGadget.rasterToWorldSpace( imath.V2f( 0 ) ).p0
		rasterMax = viewportGadget.rasterToWorldSpace( imath.V2f( viewportGadget.getViewport() ) ).p0

		frame = imath.Box2f()
		frame.extendBy( imath.V2f( rasterMin[0], rasterMin[1] ) )
		frame.extendBy( imath.V2f( rasterMax[0], rasterMax[1] ) )

		return frame

	def __rootChanged( self, graphGadget, previousRoot ) :

		# save/restore the current framing so jumping in
		# and out of Boxes isn't a confusing experience.

		Gaffer.Metadata.registerValue( previousRoot, "ui:graphEditor:framing", self.__currentFrame(), persistent = False )

		frame = Gaffer.Metadata.value( self.graphGadget().getRoot(), "ui:graphEditor:framing" )
		if frame is not None :
			self.graphGadgetWidget().getViewportGadget().frame(
				imath.Box3f( imath.V3f( frame.min().x, frame.min().y, 0 ), imath.V3f( frame.max().x, frame.max().y, 0 ) )
			)
		else :
			self.__frame( self.graphGadget().getRoot().children( Gaffer.Node ) )

		# do what we need to do to keep our title up to date.

		self.__changeConnections = []

		if not graphGadget.getRoot().isSame( self.scriptNode() ) :
			# We have to track the root _and_ its ancestors
			node = graphGadget.getRoot()
			while node and not isinstance( node, Gaffer.ScriptNode ) :
				self.__changeConnections.append( node.nameChangedSignal().connect( Gaffer.WeakMethod( self.__rootNameChanged ) ) )
				self.__changeConnections.append( node.parentChangedSignal().connect( Gaffer.WeakMethod( self.__rootParentChanged ) ) )
				node = node.parent()

		self.titleChangedSignal()( self )

	def __rootNameChanged( self, root ) :

		self.titleChangedSignal()( self )

	def __rootParentChanged( self, node, oldParent ) :

		# This may be called for our root, or any of its parents
		if node.parent() == None :
			self.graphGadget().setRoot( self.scriptNode() )

	def __preRender( self, viewportGadget ) :

		# Find all unpositioned nodes.

		graphGadget = self.graphGadget()
		nodes = [ g.node() for g in graphGadget.unpositionedNodeGadgets() ]
		if not nodes :
			return

		nodes = Gaffer.StandardSet( nodes )

		# Lay them out somewhere near the centre of frame.

		gadgetWidget = self.graphGadgetWidget()
		fallbackPosition = gadgetWidget.getViewportGadget().rasterToGadgetSpace(
			imath.V2f( gadgetWidget.size() ) / 2.0,
			gadget = graphGadget
		).p0
		fallbackPosition = imath.V2f( fallbackPosition.x, fallbackPosition.y )

		graphGadget.getLayout().positionNodes( graphGadget, nodes, fallbackPosition )
		graphGadget.getLayout().layoutNodes( graphGadget, nodes )

		# And then extend the frame to include them, in case the
		# layout has gone off screen.

		self.frame( nodes, extend = True )

	def __annotationsMenu( self ) :

		graphGadget = self.graphGadget()
		annotationsGadget = graphGadget["__annotations"]

		annotations = Gaffer.MetadataAlgo.annotationTemplates() + [ "user", annotationsGadget.untemplatedAnnotations ]
		visiblePattern = annotationsGadget.getVisibleAnnotations()
		visibleAnnotations = { a for a in annotations if IECore.StringAlgo.matchMultiple( a, visiblePattern ) }

		result = IECore.MenuDefinition()

		result.append(
			"All",
			{
				"checkBox" : len( visibleAnnotations ) == len( annotations ),
				"command" : functools.partial( Gaffer.WeakMethod( self.__setVisibleAnnotations ), annotations = { "*" } )
			}
		)

		result.append(
			"None",
			{
				"checkBox" : len( visibleAnnotations ) == 0,
				"command" : functools.partial( Gaffer.WeakMethod( self.__setVisibleAnnotations ), annotations = set() )
			}
		)

		result.append( "__annotationsDivider__", { "divider" : True } )

		def appendMenuItem( annotation, label = None ) :

			if label is None :
				# Support snake_case and CamelCase for conversion of name to label,
				# since not all extensions use the Gaffer convention.
				labelParts = annotation.split( ":" )
				label = "/".join(
					( " ".join( x.title() for x in p.split( "_" ) ) )
					if "_" in p
					else IECore.CamelCase.toSpaced( p )
					for p in labelParts
				)

			if annotation in visibleAnnotations :
				toggled = visibleAnnotations - { annotation }
			else :
				toggled = visibleAnnotations | { annotation }

			result.append(
				"/" + label,
				{
					"checkBox" : annotation in visibleAnnotations,
					"command" : functools.partial( Gaffer.WeakMethod( self.__setVisibleAnnotations ), annotations = toggled )
				}
			)

		userAnnotations = set( Gaffer.MetadataAlgo.annotationTemplates( userOnly = True ) )
		for annotation in sorted( userAnnotations ) :
			appendMenuItem( annotation )

		if len( userAnnotations ) :
			result.append( "__userDivider__", { "divider" : True } )
		appendMenuItem( "user" )

		result.append( "__nonUserDivider__", { "divider" : True } )

		for annotation in sorted( Gaffer.MetadataAlgo.annotationTemplates() ) :
			if annotation not in userAnnotations :
				appendMenuItem( annotation )

		result.append( "__otherDivider__", { "divider" : True } )
		appendMenuItem( annotationsGadget.untemplatedAnnotations, label = "Other" )

		return result

	def __setVisibleAnnotations( self, unused, annotations ) :

		annotationsGadget = self.graphGadget()["__annotations"]
		pattern = " ".join( a.replace( " ", r"\ " ) for a in annotations )
		annotationsGadget.setVisibleAnnotations( pattern )

	@classmethod
	def __getNodeInputConnectionsVisible( cls, graphGadget, node ) :

		return not graphGadget.getNodeInputConnectionsMinimised( node )

	@classmethod
	def __setNodeInputConnectionsVisible( cls, graphGadget, node, value ) :

		with Gaffer.UndoScope( node.ancestor( Gaffer.ScriptNode ) ) :
			graphGadget.setNodeInputConnectionsMinimised( node, not value )

	@classmethod
	def __getNodeOutputConnectionsVisible( cls, graphGadget, node ) :

		return not graphGadget.getNodeOutputConnectionsMinimised( node )

	@classmethod
	def __setNodeOutputConnectionsVisible( cls, graphGadget, node, value ) :

		with Gaffer.UndoScope( node.ancestor( Gaffer.ScriptNode ) ) :
			graphGadget.setNodeOutputConnectionsMinimised( node, not value )

	@classmethod
	def __setEnabled( cls, node, value ) :

		with Gaffer.UndoScope( node.ancestor( Gaffer.ScriptNode ) ) :
			node.enabledPlug().setValue( value )

	@staticmethod
	def __childrenViewable( node ) :

		viewable = Gaffer.Metadata.value( node, "graphEditor:childrenViewable" )
		if viewable is not None :
			return viewable

		## \todo: Remove nodeGraph fallback when all client code has been updated
		return Gaffer.Metadata.value( node, "nodeGraph:childrenViewable" )

	@staticmethod
	def __select( node ) :

		node.scriptNode().selection().clear()
		node.scriptNode().selection().add( node )
Beispiel #29
0
    def _menu(self, pathListing):
        # asset=0
        # assetData=1
        # assetFullPath=2
        # assetOP=3
        # assetOPSourceExistsInHost=4

        menuDefinition = IECore.MenuDefinition()
        selectedData = pathListing.getSelectedColumns()
        selectedPaths = selectedData['assetFullPath']
        selectedPathsOP = selectedData['assetOP']
        selectedPathsExistInHost = selectedData['assetOPSourceExistsInHost']
        # for path in selectedPaths:

        selected_source_exists_in_host = False if [
            x for x in selectedPathsExistInHost if x
        ] else True

        isAssetMenu = [x for x in selectedPaths if len(x.split('/')) > 2]
        isPublishMenu = [x for x in selectedPaths if len(x.split('/')) <= 2]

        if isAssetMenu:

            def checkout(paths):
                def __SAM_assetList_doImport__():
                    import genericAsset
                    pb = genericAsset.progressBar(
                        len(paths) + 1, "Importing assets...")
                    for path in paths:
                        pb.step()
                        print path
                        op = assetUtils.assetOP(path)
                        op.doImport()
                    pb.step()
                    pb.close()
                    self._mayaNodeDeleted()
                    # print op, path

                __SAM_assetList_doImport__()
                # assetUtils.mayaLazyScriptJob( runOnce=True,  idleEvent=__SAM_assetList_doImport__)

            canImport = selected_source_exists_in_host
            if len(selectedPaths) == 1:
                if 'renderSettings/' in selectedPaths[0]:
                    canImport = True
            menuDefinition.append(
                "/Import selected", {
                    "command": IECore.curry(checkout, selectedPaths),
                    "active": canImport
                })

            if len(selectedPaths) == 1:
                menuDefinition.append("/  ", {})
                menuDefinition.append("/ ", {})

                def updateAsset(asset):
                    op = assetUtils.assetOP(asset[0])
                    op.updatePublish()

                menuDefinition.append(
                    "/Publish an UPDATE to the selected asset", {
                        "command": IECore.curry(updateAsset, selectedPaths),
                        "active": not selected_source_exists_in_host
                    })
                menuDefinition.append("/", {})

                def mayaImportDependency(paths):
                    def __SAM_assetList_mayaImportDependency__():
                        # print paths
                        for path in paths:
                            # print path
                            op = assetUtils.assetOP(path)
                            op.mayaImportDependency()

                    if assetUtils.m:
                        assetUtils.mayaLazyScriptJob(
                            runOnce=True,
                            idleEvent=__SAM_assetList_mayaImportDependency__)
                    else:
                        __SAM_assetList_mayaImportDependency__()

                def mayaOpenDependency(paths):
                    def __SAM_assetList_mayaOpenDependency__():
                        # print paths
                        for path in paths:
                            # print path
                            op = assetUtils.assetOP(path)
                            op.mayaOpenDependency()

                    if assetUtils.m:
                        assetUtils.mayaLazyScriptJob(
                            runOnce=True,
                            idleEvent=__SAM_assetList_mayaOpenDependency__)
                    else:
                        __SAM_assetList_mayaOpenDependency__()

                if assetUtils.m:
                    menuDefinition.append(
                        "/open original scene in this maya session ", {
                            "command":
                            IECore.curry(mayaImportDependency, selectedPaths)
                        })
                menuDefinition.append(
                    "/open original scene in a new maya session ", {
                        "command": IECore.curry(mayaOpenDependency,
                                                selectedPaths)
                    })

        elif isPublishMenu and len(selectedPaths) == 1:
            from pprint import pprint
            types = assetUtils.Asset.types(refresh=True)
            atype = selectedPaths[0].split('/')[0]

            def createNewAsset(paths, assetType):
                op = assetUtils.assetOP(assetType)
                op.newPublish()

            for t in [x for x in types if atype in x.split('/')]:
                if 'render/' in t:
                    if assetUtils.m and 'render/maya' not in t:
                        continue

                menuDefinition.append(
                    "/publish new asset of type %s" % t.replace('/', '_'), {
                        "command": IECore.curry(createNewAsset, selectedPaths,
                                                t)
                    })

        self.__menu = GafferUI.Menu(menuDefinition)
        if len(menuDefinition.items()):
            self.__menu.popup(parent=pathListing.ancestor(GafferUI.Window))

        return True
Beispiel #30
0
def __nodeGadget(pathFilter):

    nodeGadget = GafferUI.StandardNodeGadget(pathFilter)
    addObjectDropTarget(nodeGadget)

    return nodeGadget
Beispiel #31
0
			which the `paths` are relative to. This can be useful when working
			on a single asset in isolation, and then placing it into multiple
			locations within a layout. When no filter is connected, all `paths`
			are treated as being relative to `/`, the true scene root.
			""",
                                     "plugValueWidget:type",
                                     "",
                                 ],
                             })

##########################################################################
# NodeGadget drop handler
##########################################################################

GafferUI.Pointer.registerPointer(
    "addObjects", GafferUI.Pointer("addObjects.png", imath.V2i(36, 18)))
GafferUI.Pointer.registerPointer(
    "removeObjects", GafferUI.Pointer("removeObjects.png", imath.V2i(36, 18)))
GafferUI.Pointer.registerPointer(
    "replaceObjects", GafferUI.Pointer("replaceObjects.png", imath.V2i(36,
                                                                       18)))

__DropMode = IECore.Enum.create("None", "Add", "Remove", "Replace")

__originalDragPointer = None


def __pathsPlug(node):

    for plug in node.children(Gaffer.Plug):
        if Gaffer.Metadata.value(plug, "ui:scene:acceptsPaths"):
Beispiel #32
0
	def __init__( self, plug, **kw ) :

		column = GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Vertical, spacing = 4 )

		GafferUI.PlugValueWidget.__init__( self, column, plug, **kw )

		with column :
			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 4 ) :
				GafferUI.Label( "Display Mode" )
				drawModeWidget = GafferUI.MultiSelectionMenu( allowMultipleSelection = False, allowEmptySelection = False )
				drawModeWidget.append( "Ramp" )
				drawModeWidget.append( "Curves" )
				drawModeWidget.setSelection( "Ramp" )
				drawModeWidget.selectionChangedSignal().connect( Gaffer.WeakMethod( self.__drawModeChanged ), scoped = False )

				GafferUI.Spacer( imath.V2i( 0 ), parenting = { "expand" : True } )

				# TODO: Since we don't have a good way to register metadata on child plugs, we just write the
				# metadata on this child plug right before constructing a widget for it.  There should probably
				# be some way to do this genericly during initialization
				Gaffer.Metadata.registerValue( plug['interpolation'],
					"plugValueWidget:type", "GafferUI.PresetsPlugValueWidget", persistent=False )
				for name, value in sorted( Gaffer.SplineDefinitionInterpolation.names.items() ):
					Gaffer.Metadata.registerValue( plug['interpolation'], "preset:" + name, value, persistent=False )

				GafferUI.PlugWidget( GafferUI.PlugValueWidget.create( plug["interpolation"] ) )

			self.__splineWidget = GafferUI.SplineWidget()
			if isinstance( plug, ( Gaffer.SplinefColor3fPlug, Gaffer.SplinefColor4fPlug ) ) :
				self.__splineWidget.setDrawMode( self.__splineWidget.DrawMode.Ramp )
			else:
				self.__splineWidget.setDrawMode( self.__splineWidget.DrawMode.Splines )
			self.__splineWidget._qtWidget().setMinimumHeight( 50 )

			self.__slider = GafferUI.Slider()
			self.__slider.setMinimumSize( 2 )
			self.__positionsChangedConnection = self.__slider.positionChangedSignal().connect( Gaffer.WeakMethod( self.__positionsChanged ), scoped = False )
			self.__slider.indexRemovedSignal().connect( Gaffer.WeakMethod( self.__indexRemoved ), scoped = False )
			self.__slider.selectedIndexChangedSignal().connect( Gaffer.WeakMethod( self.__selectedIndexChanged ), scoped = False )

			self.__lastPositionChangedReason = None
			self.__positionsMergeGroupId = 0

			with GafferUI.ListContainer( GafferUI.ListContainer.Orientation.Horizontal, spacing = 4 ) :

				self.__positionLabel = GafferUI.LabelPlugValueWidget( plug.pointXPlug( 0 ) )
				self.__positionField = GafferUI.NumericPlugValueWidget( plug.pointXPlug( 0 ) )

				self.__valueLabel = GafferUI.LabelPlugValueWidget( plug.pointYPlug( 0 ) )
				if isinstance( plug.pointYPlug( 0 ), Gaffer.FloatPlug ):
					self.__valueField = GafferUI.NumericPlugValueWidget( plug.pointYPlug( 0 ) )
				else:
					self.__valueField = GafferUI.ColorPlugValueWidget( plug.pointYPlug( 0 ) )

		self.setPlug( plug )
Beispiel #33
0
import Gaffer
import GafferUI

GafferUI.Nodule.registerNodule(Gaffer.ObjectReader.staticTypeId(),
                               fnmatch.translate("*"), lambda plug: None)
GafferUI.Nodule.registerNodule(Gaffer.ObjectReader.staticTypeId(), "out",
                               GafferUI.StandardNodule)

GafferUI.PlugValueWidget.registerCreator(
    Gaffer.ObjectReader.staticTypeId(),
    "fileName",
    lambda plug: GafferUI.PathPlugValueWidget(
        plug,
        path=Gaffer.FileSystemPath(
            "/",
            filter=Gaffer.FileSystemPath.createStandardFilter(
                extensions=IECore.Reader.supportedExtensions(),
                extensionsLabel="Show only supported files",
            ),
        ),
    ),
)


def __createParameterWidget(plug):

    return GafferUI.CompoundParameterValueWidget(
        plug.node().parameterHandler(), collapsible=False)


GafferUI.PlugValueWidget.registerCreator(Gaffer.ObjectReader.staticTypeId(),
                                         "parameters", __createParameterWidget)
import IECore
import GafferUI
import GafferScene
import GafferSceneUI
import os

scriptNode = script
scriptWindow = GafferUI.ScriptWindow.acquire( script )
ea = GafferUI.NodeGraph( scriptNode )
eb = GafferUI.NodeGraph( scriptNode )
layout = eval( "GafferUI.CompoundEditor( scriptNode, children = ( GafferUI.SplitContainer.Orientation.Horizontal, 0.65, ( {'tabs': (ea,), 'tabsVisible': True, 'currentTab': 0, 'pinned': [True]}, {'tabs': (eb,), 'tabsVisible': True, 'currentTab': 0, 'pinned': [True]} ) ) )" )



script.selection().add( script["ThisIsABox"] )
eb.graphGadget().setRoot( script["ThisIsABox"] )

scriptWindow.setLayout( layout )
scriptWindow._Widget__qtWidget.resize(925,450)

ea.frame([script["Backdrop"],script["ThisIsABox"]])
eb.frame([ script["ThisIsABox"]["Cube3"], script["ThisIsABox"]["Cube2"], script["ThisIsABox"]["Sphere5"], script["ThisIsABox"]["PathFilter1"] ])
Beispiel #35
0
    def __init__(self, plug, **kw):

        self.__column = GafferUI.ListContainer(spacing=4)

        GafferUI.PlugValueWidget.__init__(self, self.__column, plug, **kw)

        with self.__column:

            columns = self.__listingColumns()

            self.__pathListing = GafferUI.PathListingWidget(
                _ImagesPath(self.__images(), []),
                columns=columns,
                allowMultipleSelection=True,
                sortable=False,
                horizontalScrollMode=GafferUI.ScrollMode.Automatic)
            self.__pathListing.setDragPointer("")
            self.__pathListing.setHeaderVisible(True)
            self.__pathListing.selectionChangedSignal().connect(
                Gaffer.WeakMethod(self.__pathListingSelectionChanged),
                scoped=False)
            self.__pathListing.dragEnterSignal().connect(Gaffer.WeakMethod(
                self.__pathListingDragEnter),
                                                         scoped=False)
            self.__pathListing.dragLeaveSignal().connect(Gaffer.WeakMethod(
                self.__pathListingDragLeave),
                                                         scoped=False)
            self.__pathListing.dragMoveSignal().connect(Gaffer.WeakMethod(
                self.__pathListingDragMove),
                                                        scoped=False)
            self.__pathListing.dropSignal().connect(Gaffer.WeakMethod(
                self.__pathListingDrop),
                                                    scoped=False)
            self.keyPressSignal().connect(Gaffer.WeakMethod(self.__keyPress),
                                          scoped=False)

            with GafferUI.ListContainer(
                    GafferUI.ListContainer.Orientation.Horizontal, spacing=4):

                addButton = GafferUI.Button(image="pathChooser.png",
                                            hasFrame=False,
                                            toolTip="Load image")
                addButton.clickedSignal().connect(Gaffer.WeakMethod(
                    self.__addClicked),
                                                  scoped=False)

                self.__duplicateButton = GafferUI.Button(
                    image="duplicate.png",
                    hasFrame=False,
                    toolTip=
                    "Duplicate selected image, hold <kbd>alt</kbd> to view copy. [<kbd>Ctrl-D</kbd>]"
                )
                self.__duplicateButton.setEnabled(False)
                self.__duplicateButton.clickedSignal().connect(
                    Gaffer.WeakMethod(self.__duplicateClicked), scoped=False)

                self.__exportButton = GafferUI.Button(
                    image="export.png",
                    hasFrame=False,
                    toolTip="Export selected image")
                self.__exportButton.setEnabled(False)
                self.__exportButton.clickedSignal().connect(Gaffer.WeakMethod(
                    self.__exportClicked),
                                                            scoped=False)

                self.__extractButton = GafferUI.Button(
                    image="extract.png",
                    hasFrame=False,
                    toolTip="Create CatalogueSelect node for selected image")
                self.__extractButton.setEnabled(False)
                self.__extractButton.clickedSignal().connect(Gaffer.WeakMethod(
                    self.__extractClicked),
                                                             scoped=False)

                GafferUI.Spacer(imath.V2i(0), parenting={"expand": True})

                self.__removeButton = GafferUI.Button(
                    image="delete.png",
                    hasFrame=False,
                    toolTip="Remove selected image [<kbd>Delete</kbd>]")
                self.__removeButton.setEnabled(False)
                self.__removeButton.clickedSignal().connect(Gaffer.WeakMethod(
                    self.__removeClicked),
                                                            scoped=False)

            GafferUI.Divider()

            with GafferUI.Collapsible(label="Image Properties",
                                      collapsed=False):

                with GafferUI.ListContainer(
                        GafferUI.ListContainer.Orientation.Vertical,
                        spacing=4):

                    with GafferUI.ListContainer(
                            GafferUI.ListContainer.Orientation.Horizontal,
                            spacing=4):
                        GafferUI.Label("Name")
                        self.__nameWidget = GafferUI.NameWidget(
                            graphComponent=None)

                    GafferUI.Label("Description")
                    self.__descriptionWidget = GafferUI.MultiLineStringPlugValueWidget(
                        plug=None)

        Gaffer.Metadata.plugValueChangedSignal().connect(Gaffer.WeakMethod(
            self.__plugMetadataValueChanged),
                                                         scoped=False)

        self.contextMenuSignal().connect(Gaffer.WeakMethod(self.__contextMenu),
                                         scoped=False)

        self._updateFromPlug()
Beispiel #36
0
    def testObjectAtLine(self):

        cubes = []
        names = ("left", "center", "right")
        for i in range(3):
            cube = GafferScene.Cube()
            cube["transform"]["translate"].setValue(
                imath.V3f((i - 1) * 2.0, 0.0, -2.5))
            cube["name"].setValue(names[i])
            cubes.append(cube)

        group = GafferScene.Group()
        for i, cube in enumerate(cubes):
            group["in"][i].setInput(cube["out"])

        sg = GafferSceneUI.SceneGadget()
        sg.setScene(group["out"])
        sg.setMinimumExpansionDepth(100)

        with GafferUI.Window() as w:
            gw = GafferUI.GadgetWidget(sg)
        w.setVisible(True)
        self.waitForIdle(10000)

        vp = gw.getViewportGadget()

        # This is the single most important line in this test. If you don't set
        # this to false, you get an orthographic camera, even if you set a
        # perspective projection.
        vp.setPlanarMovement(False)

        c = IECoreScene.Camera()
        c.setProjection("perspective")
        c.setFocalLength(35)
        c.setAperture(imath.V2f(36, 24))
        vp.setCamera(c)

        cameraTransform = imath.M44f()
        cameraTransform.translate(imath.V3f(0, 0, 2))
        vp.setCameraTransform(cameraTransform)

        self.waitForIdle(10000)

        # We assume in this case, that gadget space is world space

        leftCubeDir = IECore.LineSegment3f(imath.V3f(0, 0, 2),
                                           imath.V3f(-2, 0, -2))
        pathA = sg.objectAt(leftCubeDir)
        pathB, hitPoint = sg.objectAndIntersectionAt(leftCubeDir)
        self.assertIsNotNone(pathA)
        self.assertEqual(pathA,
                         IECore.InternedStringVectorData(["group", "left"]))
        self.assertEqual(pathA, pathB)
        self.assertAlmostEqual(hitPoint.x, -2, delta=0.01)
        self.assertAlmostEqual(hitPoint.y, 0, delta=0.01)
        self.assertAlmostEqual(hitPoint.z, -2, delta=0.01)

        centerCubeDir = IECore.LineSegment3f(imath.V3f(0, 0, 1),
                                             imath.V3f(0, 0, -1))
        pathA = sg.objectAt(centerCubeDir)
        pathB, hitPoint = sg.objectAndIntersectionAt(centerCubeDir)
        self.assertIsNotNone(pathA)
        self.assertEqual(pathA,
                         IECore.InternedStringVectorData(["group", "center"]))
        self.assertEqual(pathA, pathB)
        self.assertAlmostEqual(hitPoint.x, 0, delta=0.01)
        self.assertAlmostEqual(hitPoint.y, 0, delta=0.01)
        self.assertAlmostEqual(hitPoint.z, -2, delta=0.01)

        rightCubeDir = IECore.LineSegment3f(imath.V3f(0, 0, 2),
                                            imath.V3f(2, 0, -2))
        pathA = sg.objectAt(rightCubeDir)
        pathB, hitPoint = sg.objectAndIntersectionAt(rightCubeDir)
        self.assertIsNotNone(pathA)
        self.assertEqual(pathA,
                         IECore.InternedStringVectorData(["group", "right"]))
        self.assertEqual(pathA, pathB)
        self.assertAlmostEqual(hitPoint.x, 2, delta=0.01)
        self.assertAlmostEqual(hitPoint.y, 0, delta=0.01)
        self.assertAlmostEqual(hitPoint.z, -2, delta=0.01)

        missDir = IECore.LineSegment3f(imath.V3f(0, 0, 2),
                                       imath.V3f(0, 10, -2))
        pathA = sg.objectAt(missDir)
        pathB, hitPoint = sg.objectAndIntersectionAt(missDir)
        self.assertIsNone(pathA)
        self.assertIsNone(pathB)
Beispiel #37
0
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import fnmatch
import weakref

import IECore

import Gaffer
import GafferUI

QtCore = GafferUI._qtImport( "QtCore" )

##########################################################################
# Public functions
##########################################################################

def appendMenuDefinitions( menuDefinition, prefix="" ) :

	menuDefinition.append( prefix + "/Execute Selected", { "command" : executeSelected, "shortCut" : "Ctrl+E", "active" : selectionAvailable } )
	menuDefinition.append( prefix + "/Repeat Previous", { "command" : repeatPrevious, "shortCut" : "Ctrl+R", "active" : previousAvailable } )

def appendNodeContextMenuDefinitions( nodeGraph, node, menuDefinition ) :

	if not hasattr( node, "execute" ) :
		return
Beispiel #38
0
    def __init__(self, scriptNode, **kw):

        self.__row = GafferUI.ListContainer(
            GafferUI.ListContainer.Orientation.Horizontal,
            borderWidth=4,
            spacing=2)

        GafferUI.Editor.__init__(self, self.__row, scriptNode, **kw)

        with self.__row:

            self.__visibilityButton = GafferUI.Button(image="timeline3.png",
                                                      hasFrame=False)
            self.__visibilityButtonClickedConnection = self.__visibilityButton.clickedSignal(
            ).connect(Gaffer.WeakMethod(self.__visibilityButtonClicked))

            self.__scriptRangeStart = GafferUI.NumericPlugValueWidget(
                scriptNode["frameRange"]["start"])
            self.__scriptRangeStart.numericWidget().setFixedCharacterWidth(4)
            self.__scriptRangeStart.setToolTip(
                self.__scriptRangeStart.getPlug().fullName())

            self.__sliderRangeStart = GafferUI.NumericWidget(
                scriptNode["frameRange"]["start"].getValue())
            self.__sliderRangeStart.setFixedCharacterWidth(4)
            self.__sliderRangeStart.setToolTip("Slider minimum")
            self.__sliderRangeStartChangedConnection = self.__sliderRangeStart.editingFinishedSignal(
            ).connect(Gaffer.WeakMethod(self.__sliderRangeChanged))

            self.__slider = GafferUI.NumericSlider(
                value=self.getContext().getFrame(),
                min=float(scriptNode["frameRange"]["start"].getValue()),
                max=float(scriptNode["frameRange"]["end"].getValue()),
                parenting={"expand": True},
            )
            self.__slider.setPositionIncrement(
                0
            )  # disable so the slider doesn't mask our global frame increment shortcut
            self.__sliderValueChangedConnection = self.__slider.valueChangedSignal(
            ).connect(Gaffer.WeakMethod(self.__valueChanged))

            self.__startButton = GafferUI.Button(image="timelineStart.png",
                                                 hasFrame=False)
            self.__startButtonClickedConnection = self.__startButton.clickedSignal(
            ).connect(Gaffer.WeakMethod(self.__startOrEndButtonClicked))

            self.__playPause = GafferUI.Button(image="timelinePlay.png",
                                               hasFrame=False)
            self.__playPauseClickedConnection = self.__playPause.clickedSignal(
            ).connect(Gaffer.WeakMethod(self.__playPauseClicked))

            self.__endButton = GafferUI.Button(image="timelineEnd.png",
                                               hasFrame=False)
            self.__endButtonClickedConnection = self.__endButton.clickedSignal(
            ).connect(Gaffer.WeakMethod(self.__startOrEndButtonClicked))

            self.__frame = GafferUI.NumericWidget(self.getContext().getFrame())
            self.__frame.setFixedCharacterWidth(5)
            self.__frame.setToolTip("Current frame")
            self.__frameChangedConnection = self.__frame.valueChangedSignal(
            ).connect(Gaffer.WeakMethod(self.__valueChanged))

            self.__sliderRangeEnd = GafferUI.NumericWidget(
                scriptNode["frameRange"]["end"].getValue())
            self.__sliderRangeEnd.setFixedCharacterWidth(4)
            self.__sliderRangeEnd.setToolTip("Slider maximum")
            self.__sliderRangeEndChangedConnection = self.__sliderRangeEnd.editingFinishedSignal(
            ).connect(Gaffer.WeakMethod(self.__sliderRangeChanged))

            self.__scriptRangeEnd = GafferUI.NumericPlugValueWidget(
                scriptNode["frameRange"]["end"])
            self.__scriptRangeEnd.numericWidget().setFixedCharacterWidth(4)
            self.__scriptRangeEnd.setToolTip(
                self.__scriptRangeEnd.getPlug().fullName())

        self.__scriptNodePlugSetConnection = scriptNode.plugSetSignal(
        ).connect(Gaffer.WeakMethod(self.__scriptNodePlugSet))

        frameIncrementShortcut = QtWidgets.QShortcut(
            QtGui.QKeySequence("Right"), self._qtWidget())
        frameIncrementShortcut.activated.connect(
            Gaffer.WeakMethod(self.__incrementFrame))

        frameDecrementShortcut = QtWidgets.QShortcut(
            QtGui.QKeySequence("Left"), self._qtWidget())
        frameDecrementShortcut.activated.connect(
            functools.partial(Gaffer.WeakMethod(self.__incrementFrame), -1))

        self.__playback = None
        self._updateFromContext(set())
	def getSelectedPaths( self ) :

		return _GafferUI._pathListingWidgetPathsForPathMatcher(
			GafferUI._qtAddress( self._qtWidget() ),
			self.getSelection()
		)
Beispiel #40
0
    def _updateFromSet(self):

        GafferUI.NodeSetEditor._updateFromSet(self)

        del self.__column[:]
        self.__nodeUI = None
        self.__nameWidget = None

        node = self._lastAddedNode()
        if not node:
            return

        with self.__column:
            with GafferUI.ListContainer(
                    GafferUI.ListContainer.Orientation.Horizontal,
                    borderWidth=8,
                    spacing=4):

                GafferUI.Label("<h4>Node Name</h4>")
                self.__nameWidget = GafferUI.NameWidget(node)
                ## \todo Make NameWidget support the readOnly metadata internally itself.
                # We can't do that easily right now, because it would need to be managing
                # the exact same `setEditable()` call that we're using here to propagate
                # our Widget readonlyness. Really our Widget readonlyness mechanism is a
                # bit lacking, and it should really be inherited automatically so we don't
                # have to propagate it like this.
                self.__nameWidget.setEditable(
                    not self.getReadOnly()
                    and not Gaffer.MetadataAlgo.readOnly(node))

                with GafferUI.ListContainer(
                        GafferUI.ListContainer.Orientation.Horizontal,
                        spacing=4) as infoSection:

                    GafferUI.Label("<h4>" +
                                   node.typeName().rpartition(":")[-1] +
                                   "</h4>")

                    button = GafferUI.Button(image="info.png", hasFrame=False)
                    url = Gaffer.Metadata.value(node, "documentation:url")
                    if url:
                        button.clickedSignal().connect(
                            lambda button: GafferUI.showURL(url), scoped=False)

                toolTip = "<h3>" + node.typeName().rpartition(":")[2] + "</h3>"
                description = Gaffer.Metadata.nodeDescription(node)
                if description:
                    toolTip += "\n\n" + description
                infoSection.setToolTip(toolTip)

                GafferUI.MenuButton(image="gear.png",
                                    hasFrame=False,
                                    menu=GafferUI.Menu(
                                        Gaffer.WeakMethod(
                                            self.__menuDefinition)))

        frame = GafferUI.Frame(borderStyle=GafferUI.Frame.BorderStyle.None,
                               borderWidth=0)
        self.__column.append(frame, expand=True)
        self.__nodeUI = GafferUI.NodeUI.create(node)
        self.__nodeUI.setReadOnly(self.getReadOnly())
        frame.setChild(self.__nodeUI)
	def __pathForIndex( self, modelIndex ) :

		return _GafferUI._pathListingWidgetPathForIndex(
			GafferUI._qtAddress( self._qtWidget() ),
			GafferUI._qtAddress( modelIndex ),
		)
Beispiel #42
0
# the OpenGL module loves spewing things into logs, and for some reason
# when running in maya 2012 the default log level allows info messages through.
# so we set a specific log level on the OpenGL logger to keep it quiet.
logging.getLogger("OpenGL").setLevel(logging.WARNING)

import IECore

import Gaffer
import GafferUI

# import lazily to improve startup of apps which don't use GL functionality
GL = Gaffer.lazyImport("OpenGL.GL")
IECoreGL = Gaffer.lazyImport("IECoreGL")

QtCore = GafferUI._qtImport("QtCore")
QtGui = GafferUI._qtImport("QtGui")
QtOpenGL = GafferUI._qtImport("QtOpenGL", lazy=True)

## The GLWidget is a base class for all widgets which wish to draw using OpenGL.
# Derived classes override the _draw() method to achieve this.
class GLWidget(GafferUI.Widget):

    ## This enum defines the optional elements of the GL buffer used
    # for display.
    BufferOptions = IECore.Enum.create("Alpha", "Depth", "Double")

    ## Note that you won't always get the buffer options you ask for - a best fit is found
    # among the available formats. In particular it appears that a depth buffer is often present
    # even when not requested.
    def __init__(self, bufferOptions=set(), **kw):
Beispiel #43
0
    def testConnectedNodeGadgets(self):

        script = Gaffer.ScriptNode()

        # a -> b -> c -> e -> f
        #           |
        #           v
        #			d

        script["a"] = GafferTest.AddNode()
        script["b"] = GafferTest.AddNode()
        script["c"] = GafferTest.AddNode()
        script["d"] = GafferTest.AddNode()
        script["e"] = GafferTest.AddNode()
        script["f"] = GafferTest.AddNode()

        script["b"]["op1"].setInput(script["a"]["sum"])
        script["c"]["op1"].setInput(script["b"]["sum"])
        script["d"]["op1"].setInput(script["c"]["sum"])
        script["e"]["op1"].setInput(script["c"]["sum"])
        script["f"]["op1"].setInput(script["e"]["sum"])

        g = GafferUI.GraphGadget(script)

        # test traversing in both directions

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["b"])
        ]
        self.assertEqual(set(u), set(["a", "c", "d", "e", "f"]))

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["e"])
        ]
        self.assertEqual(set(u), set(["a", "b", "c", "d", "f"]))

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["c"], degreesOfSeparation=1)
        ]
        self.assertEqual(set(u), set(["b", "d", "e"]))

        # test traversing upstream

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["c"],
                                            direction=Gaffer.Plug.Direction.In)
        ]
        self.assertEqual(set(u), set(["a", "b"]))

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["c"],
                                            direction=Gaffer.Plug.Direction.In,
                                            degreesOfSeparation=1)
        ]
        self.assertEqual(set(u), set(["b"]))

        # test traversing downstream

        u = [
            x.node().relativeName(script) for x in g.connectedNodeGadgets(
                script["c"], direction=Gaffer.Plug.Direction.Out)
        ]
        self.assertEqual(set(u), set(["d", "e", "f"]))

        u = [
            x.node().relativeName(script) for x in g.connectedNodeGadgets(
                script["c"],
                direction=Gaffer.Plug.Direction.Out,
                degreesOfSeparation=1)
        ]
        self.assertEqual(set(u), set(["d", "e"]))

        # test that invisible nodes are ignored

        g.setFilter(Gaffer.StandardSet([script["f"], script["e"],
                                        script["c"]]))

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["e"])
        ]
        self.assertEqual(set(u), set(["f", "c"]))

        u = [
            x.node().relativeName(script)
            for x in g.connectedNodeGadgets(script["e"],
                                            direction=Gaffer.Plug.Direction.In)
        ]
        self.assertEqual(set(u), set(["c"]))

        u = [
            x.node().relativeName(script) for x in g.connectedNodeGadgets(
                script["e"], direction=Gaffer.Plug.Direction.Out)
        ]
        self.assertEqual(set(u), set(["f"]))
	def getExpandedPaths( self ) :

		return _GafferUI._pathListingWidgetGetExpandedPaths( GafferUI._qtAddress( self._qtWidget() ) )
Beispiel #45
0
    def _addButton(self, label):

        button = GafferUI.Button(label=label)
        self.__buttonRow.append(button)
        return button
Beispiel #46
0
import IECore
import Gaffer
import GafferUI
import IECore
import gtk

window = GafferUI.Window(title="Frame test")
window.gtkWidget().connect("delete_event", gtk.main_quit)

t = GafferUI.TextGadget(IECore.Font("/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf"),
                        "hello")
f = GafferUI.Frame(t)

window.setChild(GafferUI.GadgetWidget(f))

window.show()

GafferUI.EventLoop.start()
Beispiel #47
0
    def testOwner(self):

        t = GafferUI.TabbedContainer()

        self.failUnless(GafferUI.Widget._owner(t._qtWidget()) is t)
	def getColumns( self ) :

		return _GafferUI._pathListingWidgetGetColumns( GafferUI._qtAddress( self._qtWidget() ) )
Beispiel #49
0
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import warnings

import Gaffer
import GafferUI

QtGui = GafferUI._qtImport("QtGui")


## The PlugWidget combines a LabelPlugValueWidget with a second PlugValueWidget
## suitable for editing the plug.
## \todo This could provide functionality for arbitrary Widgets to be placed
## on the right, which combined with the ability to find a
## PlugWidget given a Plug could be quite useful for many things.
## \todo Remove deprecated label and description capabilities.
class PlugWidget(GafferUI.Widget):
    def __init__(self, plugOrWidget, label=None, description=None, **kw):

        GafferUI.Widget.__init__(self, QtGui.QWidget(), **kw)

        layout = QtGui.QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
	def getSelection( self ) :

		return _GafferUI._pathListingWidgetGetSelection( GafferUI._qtAddress( self._qtWidget() ) )
Beispiel #51
0
    def testLookThrough(self):

        script = Gaffer.ScriptNode()

        script["sphere"] = GafferScene.Sphere()
        script["camera"] = GafferScene.Camera()
        script["camera"]["transform"]["translate"].setValue(imath.V3f(1, 0, 0))

        script["group"] = GafferScene.Group()
        script["group"]["in"][0].setInput(script["sphere"]["out"])
        script["group"]["in"][1].setInput(script["camera"]["out"])

        with GafferUI.Window() as window:
            viewer = GafferUI.Viewer(script)

        window.setVisible(True)

        viewer.setNodeSet(Gaffer.StandardSet([script["group"]]))
        view = viewer.view()
        self.assertTrue(isinstance(view, GafferSceneUI.SceneView))

        def setViewCameraTransform(matrix):

            view.viewportGadget().setCameraTransform(matrix)

        def getViewCameraTransform():

            return view.viewportGadget().getCameraTransform()

        # Simulate the user translating the camera.
        setViewCameraTransform(imath.M44f().translate(imath.V3f(100, 0, 0)))
        self.assertEqual(getViewCameraTransform(),
                         imath.M44f().translate(imath.V3f(100, 0, 0)))

        # Set the path for the look-through camera, but don't activate it - nothing should have changed.
        view["camera"]["lookThroughCamera"].setValue("/group/camera")
        self.assertEqual(getViewCameraTransform(),
                         imath.M44f().translate(imath.V3f(100, 0, 0)))

        # Enable the look-through - the camera should update.
        view["camera"]["lookThroughEnabled"].setValue(True)
        self.waitForIdle(100)
        self.assertEqual(getViewCameraTransform(),
                         script["group"]["out"].transform("/group/camera"))

        # Disable the look-through - the camera should revert to its previous position.
        view["camera"]["lookThroughEnabled"].setValue(False)
        self.waitForIdle(100)
        self.assertEqual(getViewCameraTransform(),
                         imath.M44f().translate(imath.V3f(100, 0, 0)))

        # Simulate the user moving the viewport camera, and then move the (now disabled) look-through
        # camera. The user movement should win out.
        setViewCameraTransform(imath.M44f().translate(imath.V3f(200, 0, 0)))
        self.assertEqual(getViewCameraTransform(),
                         imath.M44f().translate(imath.V3f(200, 0, 0)))
        script["camera"]["transform"]["translate"].setValue(imath.V3f(2, 0, 0))
        self.waitForIdle(100)
        self.assertEqual(getViewCameraTransform(),
                         imath.M44f().translate(imath.V3f(200, 0, 0)))

        # Change the viewer context - since look-through is disabled the user camera should not move.
        viewer.getContext().setFrame(10)
        self.waitForIdle(100)
        self.assertEqual(getViewCameraTransform(),
                         imath.M44f().translate(imath.V3f(200, 0, 0)))

        # Work around "Internal C++ object (PySide.QtWidgets.QWidget) already deleted" error. In an
        # ideal world we'll fix this, but it's unrelated to what we're testing here.
        window.removeChild(viewer)
Beispiel #52
0
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#  
##########################################################################

from __future__ import with_statement

import os
import warnings

import IECore

import Gaffer
import GafferUI

QtCore = GafferUI._qtImport( "QtCore" )

class PathWidget( GafferUI.TextWidget ) :

	def __init__( self, path, **kw ) :
	
		GafferUI.TextWidget.__init__( self, str( path ), **kw )
		
		# we can be fairly sure that the average path requires a bit more space
		# than the other things that go in TextWidgets.
		self.setPreferredCharacterWidth( 60 )
		
		self.__keyPressConnection = self.keyPressSignal().connect( Gaffer.WeakMethod( self.__keyPress ) )
		self.__selectingFinishedConnection = self.selectingFinishedSignal().connect( Gaffer.WeakMethod( self.__selectingFinished ) )		
						
		self.__textChangedConnection = self.textChangedSignal().connect( Gaffer.WeakMethod( self.__textChanged ) )
Beispiel #53
0
    def testReveal(self):

        with GafferUI.TabbedContainer() as t1:
            with GafferUI.TabbedContainer() as t2:
                with GafferUI.ListContainer() as c1:
                    l1 = GafferUI.Label("l1")
                with GafferUI.ListContainer() as c2:
                    l2 = GafferUI.Label("l2")
            with GafferUI.TabbedContainer() as t3:
                with GafferUI.ListContainer() as c3:
                    l3 = GafferUI.Label("l3")
                with GafferUI.ListContainer() as c4:
                    l4 = GafferUI.Label("l4")

        l1.reveal()
        self.assertTrue(t1.getCurrent() is t2)
        self.assertTrue(t2.getCurrent() is c1)

        l3.reveal()
        self.assertTrue(t1.getCurrent() is t3)
        self.assertTrue(t3.getCurrent() is c3)
Beispiel #54
0
def __createParameterWidget(plug):

    return GafferUI.CompoundParameterValueWidget(
        plug.node().parameterHandler(), collapsible=False)
		( "Midpoint", "midpoint" ),
	),
)

GafferUI.PlugValueWidget.registerCreator(
	GafferRenderMan.RenderManOptions.staticTypeId(),
	"options.statisticsLevel.value",
	GafferUI.EnumPlugValueWidget,
	labelsAndValues = (
		( "0 (Off)", 0 ),
		( "1", 1 ),
		( "2", 2 ),
		( "3 (Most Verbose)", 3 ),
	),
)

GafferUI.PlugValueWidget.registerCreator(
	GafferRenderMan.RenderManOptions.staticTypeId(),
	"options.statisticsFileName.value",
	lambda plug : GafferUI.PathPlugValueWidget( plug,
		path = Gaffer.FileSystemPath( "/", filter = Gaffer.FileSystemPath.createStandardFilter( extensions = ( "htm", "html", "txt", "stats" ) ) ),
		pathChooserDialogueKeywords = {
			"bookmarks" : GafferUI.Bookmarks.acquire(
				plug.ancestor( Gaffer.ApplicationRoot.staticTypeId() ),
				category = "statistics",
			),
			"leaf" : True,
		},
	)
)
Beispiel #56
0
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import weakref

import IECore

import Gaffer
import GafferUI

QtCore = GafferUI._qtImport( "QtCore" )
QtGui = GafferUI._qtImport( "QtGui" )

Gaffer.Metadata.registerNode(

	Gaffer.LocalDispatcher,

	"description",
	"""
	Schedules execution of task graphs on the local machine. Tasks
	may be dispatched in the background to keep the UI responsive.
	""",

	plugs = {

		"executeInBackground" : (
Beispiel #57
0
    def __init__(self, childPlug):

        column = GafferUI.ListContainer(
            GafferUI.ListContainer.Orientation.Vertical, spacing=4)
        GafferUI.PlugValueWidget.__init__(self, column, childPlug)

        with column:

            with GafferUI.ListContainer(
                    GafferUI.ListContainer.Orientation.Horizontal,
                    spacing=4) as header:

                collapseButton = GafferUI.Button(
                    image="collapsibleArrowRight.png", hasFrame=False)
                collapseButton.__clickedConnection = collapseButton.clickedSignal(
                ).connect(Gaffer.WeakMethod(self.__collapseButtonClicked))

                GafferUI.PlugValueWidget.create(childPlug["active"])
                self.__label = GafferUI.Label(childPlug["label"].getValue())

                GafferUI.Spacer(IECore.V2i(1),
                                maximumSize=IECore.V2i(100000, 1),
                                parenting={"expand": True})

                self.__deleteButton = GafferUI.Button(image="delete.png",
                                                      hasFrame=False)
                self.__deleteButton.__clickedConnection = self.__deleteButton.clickedSignal(
                ).connect(Gaffer.WeakMethod(self.__deleteButtonClicked))
                self.__deleteButton.setVisible(False)

            with GafferUI.ListContainer(
                    GafferUI.ListContainer.Orientation.Vertical,
                    spacing=4) as self.__detailsColumn:

                GafferUI.PlugWidget(childPlug["label"])
                GafferUI.PlugWidget(childPlug["name"])
                GafferUI.PlugWidget(childPlug["type"])
                GafferUI.PlugWidget(childPlug["data"])
                GafferUI.CompoundDataPlugValueWidget(childPlug["parameters"],
                                                     collapsed=None)

                GafferUI.Divider(GafferUI.Divider.Orientation.Horizontal)

            self.__detailsColumn.setVisible(False)

            self.__enterConnection = header.enterSignal().connect(
                Gaffer.WeakMethod(self.__enter))
            self.__leaveConnection = header.leaveSignal().connect(
                Gaffer.WeakMethod(self.__leave))
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#  
##########################################################################

from __future__ import with_statement

import IECore

import Gaffer
import GafferUI

QtGui = GafferUI._qtImport( "QtGui" )

class CompoundPlugValueWidget( GafferUI.PlugValueWidget ) :

	## Possible values for collapsed are :
	#
	#	True  : use Collapsible container which starts off collapsed
	#	False : use Collapsible container which starts off opened
	#	None  : don't use Collapsible container 
	#
	# Note that the True/False values for collapsible just set the initial state -
	# after this the current state is stored for the session on a per-node basis
	# for user convenience.
	#
	# If summary is specified it will be called each time a child plug changes value,
	# and the result used to provide a summary in the collapsible header.
Beispiel #59
0
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import IECore

import Gaffer
import GafferUI

QtCore = GafferUI._qtImport( "QtCore" )
QtGui = GafferUI._qtImport( "QtGui" )

## The ColorSwatch simply displays a flat patch of colour. By default, the colour
# is specified in linear space and GafferUI.DisplayTransform is used to ensure it
# is correctly corrected when displayed. To specify the colour directly in display
# space, pass `useDisplayTransform = False` to the constructor.
class ColorSwatch( GafferUI.Widget ) :

	__linearBackgroundColor0 = IECore.Color3f( 0.1 )
	__linearBackgroundColor1 = IECore.Color3f( 0.2 )

	def __init__( self, color=IECore.Color4f( 1 ), useDisplayTransform = True, **kw ) :

		GafferUI.Widget.__init__( self, _Checker(), **kw )