示例#1
0
	def __init__( self, scriptNode, **kw ) :

		self.__gadgetWidget = GafferUI.GadgetWidget(
			bufferOptions = set( (
				GafferUI.GLWidget.BufferOptions.Depth,
				GafferUI.GLWidget.BufferOptions.Double )
			),
		)

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

		with GafferUI.ListContainer( borderWidth = 2, spacing = 2 ) as toolbarColumn :
			self.__nodeToolbarFrame = GafferUI.Frame( borderWidth = 0, borderStyle=GafferUI.Frame.BorderStyle.None )
			with GafferUI.ListContainer( borderWidth = 0, spacing = 2, orientation = GafferUI.ListContainer.Orientation.Horizontal ) :
				with GafferUI.Frame( borderWidth = 1, borderStyle=GafferUI.Frame.BorderStyle.None ) :
					self.__toolMenuButton = GafferUI.MenuButton( menu = GafferUI.Menu( Gaffer.WeakMethod( self.__toolMenuDefinition ) ), hasFrame=False )
				self.__toolbarFrame = GafferUI.Frame( borderWidth = 0, borderStyle=GafferUI.Frame.BorderStyle.None )
		self.__gadgetWidget.addOverlay( toolbarColumn )

		self.__views = []
		# The following two variables are indexed by view
		# instance. We would prefer to simply store toolbars
		# and tools as python attributes on the view instances
		# themselves, but we can't because that would create
		# circular references.
		self.__viewToolbars = {}
		self.__viewTools = {}
		self.__currentView = None

		self._updateFromSet()
示例#2
0
	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 )

		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.__gadgetWidget.dragEnterSignal().connect( Gaffer.WeakMethod( self.__dragEnter ), scoped = False )
		self.__gadgetWidget.dropSignal().connect( Gaffer.WeakMethod( self.__drop ), scoped = False )
		self.__gadgetWidget.getViewportGadget().preRenderSignal().connect( Gaffer.WeakMethod( self.__preRender ), scoped = False )

		self.__nodeMenu = None
示例#3
0
	def testObjectVisibility( self ) :

		s = Gaffer.ScriptNode()
		s["s"] = GafferScene.Sphere()
		s["g"] = GafferScene.Group()
		s["g"]["in"][0].setInput( s["s"]["out"] )
		s["a"] = GafferScene.StandardAttributes()
		s["a"]["in"].setInput( s["g"]["out"] )

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

		with GafferUI.Window() as w :
			gw = GafferUI.GadgetWidget( sg )

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

		sg.waitForCompletion()
		gw.getViewportGadget().frame( sg.bound() )

		self.assertObjectAt( sg, imath.V2f( 0.5 ), IECore.InternedStringVectorData( [ "group", "sphere" ] ) )

		s["a"]["attributes"]["visibility"]["enabled"].setValue( True )
		s["a"]["attributes"]["visibility"]["value"].setValue( False )

		sg.waitForCompletion()
		self.assertObjectAt( sg, imath.V2f( 0.5 ), None )

		s["a"]["attributes"]["visibility"]["enabled"].setValue( True )
		s["a"]["attributes"]["visibility"]["value"].setValue( True )

		sg.waitForCompletion()
		self.assertObjectAt( sg, imath.V2f( 0.5 ), IECore.InternedStringVectorData( [ "group", "sphere" ] ) )
示例#4
0
    def testDestroyWhileProcessing(self):

        s = Gaffer.ScriptNode()
        s["c"] = GafferImage.Constant()
        s["c"]["format"].setValue(GafferImage.Format(2000, 2000))

        s["b"] = GafferImage.Blur()
        s["b"]["in"].setInput(s["c"]["out"])
        s["b"]["radius"].setValue(imath.V2f(400))

        g = GafferImageUI.ImageGadget()
        g.setImage(s["b"]["out"])

        with GafferUI.Window() as w:
            GafferUI.GadgetWidget(g)

        w.setVisible(True)

        # If this computer doesn't support floating point textures, the ImageGadget will warn about
        # this the first time it tries to render.  Don't fail because of this
        with IECore.CapturingMessageHandler() as mh:
            self.waitForIdle(1000)

        if len(mh.messages):
            self.assertEqual(len(mh.messages), 1)
            self.assertEqual(mh.messages[0].context, "ImageGadget")
            self.assertEqual(
                mh.messages[0].message,
                "Could not find supported floating point texture format in OpenGL.  GPU image viewer path will be low quality, recommend switching to CPU display transform, or resolving graphics driver issue."
            )

        del g, w
        del s
示例#5
0
    def __init__(self, scriptNode, **kw):

        self.__column = GafferUI.ListContainer(
            GafferUI.ListContainer.Orientation.Vertical)

        GafferUI.EditorWidget.__init__(self, self.__column, scriptNode, **kw)

        self.__splineGadget = GafferUI.SplinePlugGadget()
        self.__selectionAddedConnection = self.__splineGadget.selection(
        ).memberAddedSignal().connect(
            Gaffer.WeakMethod(self.__selectionChanged))
        self.__selectionRemovedConnection = self.__splineGadget.selection(
        ).memberRemovedSignal().connect(
            Gaffer.WeakMethod(self.__selectionChanged))

        self.__gadgetWidget = GafferUI.GadgetWidget(
            self.__splineGadget,
            cameraMode=GafferUI.GadgetWidget.CameraMode.Mode2D)
        self.__gadgetWidget.setBackgroundColor(IECore.Color3f(0.07))

        self.__column.append(self.__gadgetWidget, expand=True)

        self.__plugWidgetRow = GafferUI.ListContainer(
            GafferUI.ListContainer.Orientation.Horizontal)
        self.__xPlugWidget = GafferUI.NumericPlugValueWidget(plug=None)
        self.__plugWidgetRow.append(self.__xPlugWidget, expand=True)
        self.__yPlugWidget = GafferUI.NumericPlugValueWidget(plug=None)
        self.__plugWidgetRow.append(self.__yPlugWidget, expand=True)

        self.__column.append(self.__plugWidgetRow)
示例#6
0
    def __init__(self, scriptNode, **kw):

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

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

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

        self.__gadgetWidget.getViewportGadget().setChild(graphGadget)
        self.__gadgetWidget.getViewportGadget().setDragTracking(True)
        self.__frame(scriptNode.selection())

        self.__buttonPressConnection = self.buttonPressSignal().connect(
            Gaffer.WeakMethod(self.__buttonPress))
        self.__keyPressConnection = self.keyPressSignal().connect(
            Gaffer.WeakMethod(self.__keyPress))
        self.__buttonDoubleClickConnection = self.buttonDoubleClickSignal(
        ).connect(Gaffer.WeakMethod(self.__buttonDoubleClick))

        self.__gadgetWidget._qtWidget().installEventFilter(_eventFilter)

        self.__nodeMenu = None
示例#7
0
    def __init__(self, scriptNode, **kw):

        column = GafferUI.ListContainer()

        GafferUI.NodeSetEditor.__init__(self, column, scriptNode, **kw)

        self.__uvView = GafferSceneUI.UVView()

        with column:

            with GafferUI.Frame(borderWidth=4,
                                borderStyle=GafferUI.Frame.BorderStyle.None):
                toolbar = GafferUI.NodeToolbar.create(self.__uvView)

            self.__gadgetWidget = GafferUI.GadgetWidget(bufferOptions={
                GafferUI.GLWidget.BufferOptions.Double,
                GafferUI.GLWidget.BufferOptions.AntiAlias
            }, )

            Gaffer.NodeAlgo.applyUserDefaults(self.__uvView)
            self.__uvView.setContext(self.getContext())

            self.__gadgetWidget.setViewportGadget(
                self.__uvView.viewportGadget())
            self.__gadgetWidget.getViewportGadget().frame(
                imath.Box3f(imath.V3f(0, 0, 0), imath.V3f(1, 1, 0)))

        self.keyPressSignal().connect(Gaffer.WeakMethod(self.__keyPress),
                                      scoped=False)

        self._updateFromSet()
示例#8
0
	def testExpansion( self ) :

		s = Gaffer.ScriptNode()
		s["s"] = GafferScene.Sphere()
		s["g"] = GafferScene.Group()
		s["g"]["in"][0].setInput( s["s"]["out"] )
		s["a"] = GafferScene.StandardAttributes()
		s["a"]["in"].setInput( s["g"]["out"] )

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

		with GafferUI.Window() as w :
			gw = GafferUI.GadgetWidget( sg )

		w.setVisible( True )
		self.waitForIdle( 10000 )

		gw.getViewportGadget().frame( sg.bound() )
		self.waitForIdle( 10000 )

		self.assertObjectAt( sg, imath.V2f( 0.5 ), None )
		self.assertObjectsAt( sg, imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ), [ "/group" ] )

		sg.setExpandedPaths( IECore.PathMatcher( [ "/group" ] ) )

		self.assertObjectAt( sg, imath.V2f( 0.5 ), IECore.InternedStringVectorData( [ "group", "sphere" ] ) )
		self.assertObjectsAt( sg, imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ), [ "/group/sphere" ] )

		sg.setExpandedPaths( IECore.PathMatcher( [] ) )

		self.assertObjectAt( sg, imath.V2f( 0.5 ), None )
		self.assertObjectsAt( sg, imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ), [ "/group" ] )
示例#9
0
    def testGLResourceDestruction(self):

        s = Gaffer.ScriptNode()
        s["p"] = GafferScene.Plane()
        s["g"] = GafferScene.Group()
        s["g"]["in"][0].setInput(s["p"]["out"])
        s["g"]["in"][1].setInput(s["p"]["out"])
        s["g"]["in"][2].setInput(s["p"]["out"])
        s["g"]["in"][3].setInput(s["p"]["out"])

        sg = GafferSceneUI.SceneGadget()
        sg.setScene(s["g"]["out"])
        sg.setMinimumExpansionDepth(2)

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

        # Reduce the GL cache size so that not everything will fit, and we'll
        # need to dispose of some objects. We can't dispose of objects on any
        # old thread, just the main GL thread, so it's important that we test
        # that we're doing that appropriately.
        IECoreGL.CachedConverter.defaultCachedConverter().setMaxMemory(100)

        for i in range(1, 1000):
            s["p"]["dimensions"]["x"].setValue(i)
            self.waitForIdle(10)
示例#10
0
    def __init__(self, scriptNode, **kw):

        self.__gadgetWidget = GafferUI.GadgetWidget(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.__buttonPressConnection = self.__gadgetWidget.buttonPressSignal(
        ).connect(Gaffer.WeakMethod(self.__buttonPress))
        self.__keyPressConnection = self.__gadgetWidget.keyPressSignal(
        ).connect(Gaffer.WeakMethod(self.__keyPress))
        self.__buttonDoubleClickConnection = self.__gadgetWidget.buttonDoubleClickSignal(
        ).connect(Gaffer.WeakMethod(self.__buttonDoubleClick))
        self.__dragEnterConnection = self.__gadgetWidget.dragEnterSignal(
        ).connect(Gaffer.WeakMethod(self.__dragEnter))
        self.__dropConnection = self.__gadgetWidget.dropSignal().connect(
            Gaffer.WeakMethod(self.__drop))
        self.__preRenderConnection = self.__gadgetWidget.getViewportGadget(
        ).preRenderSignal().connect(Gaffer.WeakMethod(self.__preRender))

        self.__nodeMenu = None
示例#11
0
    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
示例#12
0
	def testObjectsAt( self ) :

		plane = GafferScene.Plane()

		sphere = GafferScene.Sphere()
		sphere["radius"].setValue( 0.25 )

		instancer = GafferScene.Instancer()
		instancer["in"].setInput( plane["out"] )
		instancer["instances"].setInput( sphere["out"] )
		instancer["parent"].setValue( "/plane" )

		subTree = GafferScene.SubTree()
		subTree["in"].setInput( instancer["out"] )
		subTree["root"].setValue( "/plane" )

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

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

		gw.getViewportGadget().frame( sg.bound() )
		self.waitForIdle( 10000 )

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ),
			[ "/instances/sphere/{}".format( i ) for i in range( 0, 4 ) ]
		)

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0 ), imath.V2f( 0.5 ) ),
			[ "/instances/sphere/2" ]
		)

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0.5, 0 ), imath.V2f( 1, 0.5 ) ),
			[ "/instances/sphere/3" ]
		)

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0, 0.5 ), imath.V2f( 0.5, 1 ) ),
			[ "/instances/sphere/0" ]
		)

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0.5 ), imath.V2f( 1 ) ),
			[ "/instances/sphere/1" ]
		)
示例#13
0
    def testImageViewStatus(self):

        script = Gaffer.ScriptNode()
        script["image"] = GafferImage.ImageReader()

        view = GafferUI.View.create(script["image"]["out"])

        tool = GafferSceneUI.CropWindowTool(view)
        tool["active"].setValue(True)

        # Presently, crop window tool updates are coupled to `preRender`, so we
        # need to actually show the View before we can verify our behaviour.

        with GafferUI.Window() as window:
            GafferUI.GadgetWidget(view.viewportGadget())
        window.setVisible(True)

        # Check process exceptions

        script["image"]["fileName"].setValue("/i/do/not/exist.exr")

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Error: image.__oiioReader.out.format : OpenImageIOReader : Could not create ImageInput : Could not open file \"/i/do/not/exist.exr\""
        )

        # Missing metadata

        script["image"]["fileName"].setValue(
            "${GAFFER_ROOT}/resources/images/macaw.exr")

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Error: No <b>gaffer:sourceScene</b> metadata in image")

        script["meta"] = GafferImage.ImageMetadata()
        script["meta"]["metadata"].addChild(
            Gaffer.NameValuePlug("gaffer:sourceScene", "options.out", True,
                                 "member1"))
        script["meta"]["in"].setInput(script["image"]["out"])

        script["options"] = GafferScene.StandardOptions()

        view["in"].setInput(script["meta"]["out"])

        # Valid options path

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Info: Editing <b>options.options.renderCropWindow.value</b>")
示例#14
0
	def __init__( self, scriptNode=None ) :
	
		GafferUI.NodeSetEditor.__init__( self, gtk.EventBox(), scriptNode )

		self.__renderableGadget = GafferUI.RenderableGadget( None )
		self.__gadgetWidget = GafferUI.GadgetWidget( self.__renderableGadget, bufferOptions=set( ( GafferUI.GLWidget.BufferOptions.Depth, ) ), cameraMode=GafferUI.GadgetWidget.CameraMode.Mode3D )
		self.__gadgetWidget.gtkWidget().connect( "button-press-event", self.__buttonPress )
		self.__gadgetWidget.baseState().add( IECoreGL.Primitive.DrawWireframe( True ) )
		
		self.gtkWidget().add( self.__gadgetWidget.gtkWidget() )
		
		self._updateFromSet()
示例#15
0
    def __init__(self, path):

        self.__renderableGadget = GafferUI.RenderableGadget(None)
        self.__gadgetWidget = GafferUI.GadgetWidget(
            self.__renderableGadget,
            bufferOptions=set((
                GafferUI.GLWidget.BufferOptions.Depth,
                GafferUI.GLWidget.BufferOptions.Double,
            )),
        )

        GafferUI.DeferredPathPreview.__init__(self, self.__gadgetWidget, path)

        self._updateFromPath()
示例#16
0
	def __init__( self, scriptNode, **kw ) :
	
		self.__gadgetWidget = GafferUI.GadgetWidget(
			bufferOptions = set( (
				GafferUI.GLWidget.BufferOptions.Depth,
				GafferUI.GLWidget.BufferOptions.Double )
			),					
		)
		
		GafferUI.NodeSetEditor.__init__( self, self.__gadgetWidget, scriptNode, **kw )

		self.__views = []
		self.__currentView = None

		self._updateFromSet()
示例#17
0
	def testSelectionMask( self ) :

		plane = GafferScene.Plane()
		plane["dimensions"].setValue( imath.V2f( 10 ) )
		plane["transform"]["translate"]["z"].setValue( 4 )

		camera = GafferScene.Camera()
		group = GafferScene.Group()
		group["in"][0].setInput( plane["out"] )
		group["in"][1].setInput( camera["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 )

		sg.waitForCompletion()
		gw.getViewportGadget().frame( sg.bound(), imath.V3f( 0, 0, -1 ) )
		self.waitForIdle( 10000 )

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ),
			[ "/group/plane", "/group/camera" ]
		)

		sg.setSelectionMask( IECore.StringVectorData( [ "MeshPrimitive" ] ) )

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ),
			[ "/group/plane" ]
		)

		sg.setSelectionMask( IECore.StringVectorData( [ "Camera" ] ) )

		self.assertObjectsAt(
			sg,
			imath.Box2f( imath.V2f( 0 ), imath.V2f( 1 ) ),
			[ "/group/camera" ]
		)
示例#18
0
    def doRun(self, args):

        if len(args["files"]) < 1 or len(args["files"]) > 2:

            raise Exception("Must view exactly one file.")

        o = IECore.Reader.create(args["files"][0]).read()

        window = GafferUI.Window(title="Gaffer Viewer")
        ## \todo Remove gtk from the interface.
        window.gtkWidget().connect("delete_event", gtk.main_quit)
        viewer = GafferUI.GadgetWidget(GafferUI.RenderableGadget(o))
        window.setChild(viewer)

        window.show()

        GafferUI.EventLoop.start()
        return 0
示例#19
0
    def __init__(self, scriptNode, **kw):

        self.__gadgetWidget = GafferUI.GadgetWidget(bufferOptions=set(
            (GafferUI.GLWidget.BufferOptions.Depth,
             GafferUI.GLWidget.BufferOptions.Double)), )

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

        with GafferUI.ListContainer(borderWidth=2, spacing=2) as toolbarColumn:
            self.__nodeToolbarFrame = GafferUI.Frame(
                borderWidth=0, borderStyle=GafferUI.Frame.BorderStyle.None)
            self.__toolbarFrame = GafferUI.Frame(
                borderWidth=0, borderStyle=GafferUI.Frame.BorderStyle.None)
        self.__gadgetWidget.addOverlay(toolbarColumn)

        self.__views = []
        self.__currentView = None

        self._updateFromSet()
示例#20
0
	def testDestroyWhileProcessing( self ) :

		s = Gaffer.ScriptNode()
		s["c"] = GafferImage.Constant()
		s["c"]["format"].setValue( GafferImage.Format( 2000, 2000 ) )

		s["b"] = GafferImage.Blur()
		s["b"]["in"].setInput( s["c"]["out"] )
		s["b"]["radius"].setValue( imath.V2f( 400 ) )

		g = GafferImageUI.ImageGadget()
		g.setImage( s["b"]["out"] )

		with GafferUI.Window() as w :
			GafferUI.GadgetWidget( g )

		w.setVisible( True )

		self.waitForIdle( 1000 )

		del g, w
		del s
示例#21
0
    def testDerivationInPython(self):
        class MyGadget(GafferUI.Gadget):
            def __init__(self):

                GafferUI.Gadget.__init__(self)

                self.layersRendered = set()

            def bound(self):

                return IECore.Box3f(IECore.V3f(-20, 10, 2),
                                    IECore.V3f(10, 15, 5))

            def doRenderLayer(self, layer, style):

                self.layersRendered.add(layer)

        mg = MyGadget()

        # we can't call the methods of the gadget directly in python to test the
        # bindings, as that doesn't prove anything (we're no exercising the virtual
        # method override code in the wrapper). instead cause c++ to call through
        # for us by adding our gadget to a parent and making calls to the parent.

        c = GafferUI.IndividualContainer()
        c.addChild(mg)

        self.assertEqual(c.bound().size(), mg.bound().size())

        with GafferUI.Window() as w:
            GafferUI.GadgetWidget(c)

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

        self.assertEqual(mg.layersRendered,
                         set(GafferUI.Gadget.Layer.values.values()))
示例#22
0
	def testViewportVisibility( self ) :

		with GafferUI.Window() as w :
			gw = GafferUI.GadgetWidget()

		vg1 = gw.getViewportGadget()

		self.assertFalse( gw.visible() )
		self.assertFalse( vg1.visible() )

		w.setVisible( True )
		self.assertTrue( gw.visible() )
		self.assertTrue( vg1.visible() )

		vg2 = GafferUI.ViewportGadget()
		self.assertFalse( vg2.visible() )

		gw.setViewportGadget( vg2 )
		self.assertTrue( vg2.visible() )
		self.assertFalse( vg1.visible() )

		w.setVisible( False )
		self.assertFalse( vg1.visible() )
		self.assertFalse( vg2.visible() )
示例#23
0
    def __init__(self, scriptNode, **kw):

        self.__gadgetWidget = GafferUI.GadgetWidget(bufferOptions=set(
            (GafferUI.GLWidget.BufferOptions.Depth,
             GafferUI.GLWidget.BufferOptions.Double)), )

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

        self.__nodeToolbars = []
        self.__viewToolbars = []

        with GafferUI.GridContainer(borderWidth=2, spacing=0) as overlay:

            with GafferUI.ListContainer(
                    orientation=GafferUI.ListContainer.Orientation.Horizontal,
                    parenting={
                        "index": (slice(0, 5), 0),
                        "alignment": (GafferUI.HorizontalAlignment.None,
                                      GafferUI.VerticalAlignment.Top)
                    }):

                self.__toolMenuButton = GafferUI.MenuButton(
                    menu=GafferUI.Menu(
                        Gaffer.WeakMethod(self.__toolMenuDefinition)),
                    hasFrame=False,
                )

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

                self.__viewToolbars.append(
                    _Toolbar(GafferUI.Edge.Top,
                             parenting={
                                 "verticalAlignment":
                                 GafferUI.VerticalAlignment.Top
                             }))

            self.__nodeToolbars.append(
                _Toolbar(GafferUI.Edge.Top,
                         parenting={
                             "index": (slice(0, 5), 1),
                             "alignment": (GafferUI.HorizontalAlignment.Center,
                                           GafferUI.VerticalAlignment.Top),
                         }))

            self.__viewToolbars.append(
                _Toolbar(GafferUI.Edge.Left,
                         parenting={
                             "index": (0, 2),
                             "alignment": (GafferUI.HorizontalAlignment.Left,
                                           GafferUI.VerticalAlignment.Center),
                         }))

            self.__nodeToolbars.append(
                _Toolbar(GafferUI.Edge.Left,
                         parenting={
                             "index": (1, 2),
                             "alignment": (GafferUI.HorizontalAlignment.Left,
                                           GafferUI.VerticalAlignment.Center),
                         }))

            self.__nodeToolbars.append(
                _Toolbar(GafferUI.Edge.Right,
                         parenting={
                             "index": (3, 2),
                             "alignment": (GafferUI.HorizontalAlignment.Right,
                                           GafferUI.VerticalAlignment.Center),
                         }))

            self.__viewToolbars.append(
                _Toolbar(GafferUI.Edge.Right,
                         parenting={
                             "index": (4, 2),
                             "alignment": (GafferUI.HorizontalAlignment.Right,
                                           GafferUI.VerticalAlignment.Center),
                         }))

            self.__nodeToolbars.append(
                _Toolbar(GafferUI.Edge.Bottom,
                         parenting={
                             "index": (slice(0, 5), 3),
                             "alignment": (GafferUI.HorizontalAlignment.Center,
                                           GafferUI.VerticalAlignment.Bottom),
                         }))

            self.__viewToolbars.append(
                _Toolbar(GafferUI.Edge.Bottom,
                         parenting={
                             "index": (slice(0, 5), 4),
                             "alignment": (GafferUI.HorizontalAlignment.Center,
                                           GafferUI.VerticalAlignment.Bottom),
                         }))
示例#24
0
    def __init__(self, scriptNode, **kw):

        mainRow = GafferUI.ListContainer(
            GafferUI.ListContainer.Orientation.Horizontal,
            borderWidth=5,
            spacing=5)

        GafferUI.NodeSetEditor.__init__(self, mainRow, scriptNode, **kw)

        # Set up widget for curve names on the left
        self.__curveList = GafferUI.PathListingWidget(
            Gaffer.DictPath(
                {}, "/"),  # placeholder, updated in `_updateFromSet()`.
            columns=(GafferUI.PathListingWidget.defaultNameColumn, ),
            displayMode=GafferUI.PathListingWidget.DisplayMode.Tree,
            allowMultipleSelection=True)

        self.__curveList._qtWidget().setMinimumSize(160, 0)
        self.__curveList._qtWidget().setSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Ignored)
        self.__curveList.expansionChangedSignal().connect(Gaffer.WeakMethod(
            self.__updateGadgetSets),
                                                          scoped=False)
        self.__selectionChangedConnection = self.__curveList.selectionChangedSignal(
        ).connect(Gaffer.WeakMethod(self.__updateGadgetSets), scoped=False)

        # Set up the widget responsible for actual curve drawing
        self.__animationGadget = GafferUI.AnimationGadget()

        # Set up signals needed to update selection state in PathListingWidget
        editable = self.__animationGadget.editablePlugs()
        self.__editablePlugsConnections = [
            editable.memberAddedSignal().connect(Gaffer.WeakMethod(
                self.__editablePlugAdded),
                                                 scoped=False),
            editable.memberRemovedSignal().connect(Gaffer.WeakMethod(
                self.__editablePlugRemoved),
                                                   scoped=False)
        ]

        self.__gadgetWidget = GafferUI.GadgetWidget(
            bufferOptions={
                GafferUI.GLWidget.BufferOptions.Depth,
                GafferUI.GLWidget.BufferOptions.Double
            })

        self.__gadgetWidget.getViewportGadget().setPrimaryChild(
            self.__animationGadget)
        self.__gadgetWidget.getViewportGadget().setVariableAspectZoom(True)

        # Set up the widget responsible for curve editing
        self.__curveEditor = _CurveEditor(self.__animationGadget)

        # Assemble UI
        self.__splitMain = GafferUI.SplitContainer(
            orientation=GafferUI.SplitContainer.Orientation.Horizontal)
        self.__splitSide = GafferUI.SplitContainer(
            orientation=GafferUI.SplitContainer.Orientation.Vertical)
        mainRow.addChild(self.__splitMain)

        self.__splitSide.append(self.__curveList)
        self.__splitSide.append(self.__curveEditor)
        self.__splitMain.append(self.__splitSide)
        self.__splitMain.append(self.__gadgetWidget)

        # Initial allocation of screen space:
        #   If there's enough space for the list to get 160 pixels give the rest to the AnimationGadget.
        #   If that's not the case, divide the space 50/50
        # \todo: do we want to preserve that ratio when maximizing the window as being done currently?
        self.__splitMain.setSizes((1, 1))
        currentSizes = self.__splitMain.getSizes()
        if currentSizes[0] > 160:
            total = sum(currentSizes)
            betterSize = [float(x) / total for x in [160, total - 160]]
            self.__splitMain.setSizes(betterSize)

        # set initial state
        self._updateFromSet()
        self._updateFromContext(["frame"])
        self.__curveList._qtWidget().adjustSize()

        # \todo: is this a reasonable initial framing?
        bound = imath.Box3f(imath.V3f(-1, -1, 0), imath.V3f(10, 10, 0))
        self.__gadgetWidget.getViewportGadget().frame(bound)

        # connect context menu for animation gadget
        self.__gadgetWidget.contextMenuSignal().connect(Gaffer.WeakMethod(
            self.__animationGadgetContextMenu),
                                                        scoped=False)
示例#25
0
    def testSceneViewStatus(self):

        camera = GafferScene.Camera()

        view = GafferUI.View.create(camera["out"])

        tool = GafferSceneUI.CropWindowTool(view)
        tool["active"].setValue(True)

        # Presently, crop window tool updates are coupled to `preRender`, so we
        # need to actually show the View before we can verify our behaviour.

        with GafferUI.Window() as window:
            GafferUI.GadgetWidget(view.viewportGadget())
        window.setVisible(True)

        # View camera isn't a real camera

        self.waitForIdle(1000)
        self.assertEqual(tool.status(),
                         "Error: No applicable crop window for this view")

        # Working camera, no node to edit

        view["camera"]["lookThroughCamera"].setValue("/camera")
        view["camera"]["lookThroughEnabled"].setValue(True)

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Error: No crop window found. Insert a <b>StandardOptions</b> node."
        )

        # Editable

        options = GafferScene.StandardOptions()
        options["in"].setInput(camera["out"])
        view["in"].setInput(options["out"])

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Info: Editing <b>StandardOptions.options.renderCropWindow.value</b>"
        )

        # Locked value plug

        Gaffer.MetadataAlgo.setReadOnly(
            options["options"]["renderCropWindow"]["value"], True)

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Warning: <b>StandardOptions.options.renderCropWindow.value</b> is locked"
        )

        # Locked/off enabled plug

        Gaffer.MetadataAlgo.setReadOnly(
            options["options"]["renderCropWindow"]["value"], False)
        options["options"]["renderCropWindow"]["enabled"].setValue(False)
        Gaffer.MetadataAlgo.setReadOnly(
            options["options"]["renderCropWindow"]["enabled"], True)

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Warning: <b>StandardOptions.options.renderCropWindow.value</b> isn't editable"
        )

        # Check status across visible/invisible overlay transitions (this is
        # really testing one of the gnarly parts of the status implementation
        # that has caused trouble before, until we can properly refactor the tool).

        view["camera"]["lookThroughEnabled"].setValue(False)

        self.waitForIdle(1000)
        self.assertEqual(tool.status(),
                         "Error: No applicable crop window for this view")

        view["camera"]["lookThroughEnabled"].setValue(True)

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Warning: <b>StandardOptions.options.renderCropWindow.value</b> isn't editable"
        )
示例#26
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"]["child"].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)
示例#27
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()
示例#28
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)
import IECore
import Gaffer
import GafferUI
import IECore
import gtk

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

s = IECore.Reader.create("test/data/sphere.cob").read()

e = GafferUI.GadgetWidget(GafferUI.RenderableGadget(s))
window.setChild(e)

window.show()

GafferUI.EventLoop.start()
示例#30
0
    def __init__(self, scriptNode, **kw):

        self.__gadgetWidget = GafferUI.GadgetWidget(bufferOptions=set(
            (GafferUI.GLWidget.BufferOptions.Depth,
             GafferUI.GLWidget.BufferOptions.Double,
             GafferUI.GLWidget.BufferOptions.AntiAlias)), )

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

        self.__nodeToolbars = []
        self.__viewToolbars = []
        self.__toolToolbars = []

        with GafferUI.ListContainer(borderWidth=2,
                                    spacing=0) as horizontalToolbars:

            # Top toolbars

            with GafferUI.ListContainer(
                    orientation=GafferUI.ListContainer.Orientation.Vertical,
                    parenting={
                        "verticalAlignment": GafferUI.VerticalAlignment.Top,
                    }):

                for toolbarContainer in [
                        self.__viewToolbars, self.__nodeToolbars,
                        self.__toolToolbars
                ]:
                    toolbarContainer.append(
                        _Toolbar(GafferUI.Edge.Top, self.getContext()))

            # Bottom toolbars

            with GafferUI.ListContainer(
                    spacing=0,
                    orientation=GafferUI.ListContainer.Orientation.Vertical,
                    parenting={
                        "verticalAlignment": GafferUI.VerticalAlignment.Bottom,
                    }):

                for toolbarContainer in [
                        self.__toolToolbars, self.__nodeToolbars,
                        self.__viewToolbars
                ]:
                    toolbarContainer.append(
                        _Toolbar(GafferUI.Edge.Bottom, self.getContext()))

        with GafferUI.ListContainer(
                borderWidth=2,
                spacing=0,
                orientation=GafferUI.ListContainer.Orientation.Horizontal
        ) as verticalToolbars:

            # Left toolbars

            with GafferUI.ListContainer(
                    orientation=GafferUI.ListContainer.Orientation.Horizontal,
                    parenting={
                        "horizontalAlignment":
                        GafferUI.HorizontalAlignment.Left,
                        "verticalAlignment": GafferUI.VerticalAlignment.Center,
                    }):

                self.__toolChooser = _ToolChooser()
                self.__primaryToolChangedConnection = self.__toolChooser.primaryToolChangedSignal(
                ).connect(Gaffer.WeakMethod(self.__primaryToolChanged))

                for toolbarContainer in [
                        self.__viewToolbars, self.__nodeToolbars,
                        self.__toolToolbars
                ]:
                    toolbarContainer.append(
                        _Toolbar(GafferUI.Edge.Left, self.getContext()))

            # Right toolbars

            with GafferUI.ListContainer(
                    orientation=GafferUI.ListContainer.Orientation.Horizontal,
                    parenting={
                        "horizontalAlignment":
                        GafferUI.HorizontalAlignment.Right,
                        "verticalAlignment": GafferUI.VerticalAlignment.Center,
                    }):

                for toolbarContainer in [
                        self.__toolToolbars, self.__nodeToolbars,
                        self.__viewToolbars
                ]:
                    toolbarContainer.append(
                        _Toolbar(GafferUI.Edge.Right, self.getContext()))

        self.__gadgetWidget.addOverlay(horizontalToolbars)
        self.__gadgetWidget.addOverlay(verticalToolbars)

        self.__views = []
        # Indexed by view instance. We would prefer to simply
        # store tools as python attributes on the view instances
        # themselves, but we can't because that would create
        # circular references. Maybe it makes sense to be able to
        # query tools from a view anyway?
        self.__currentView = None

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

        self._updateFromSet()