예제 #1
0
    def __updateKeyFrame(self):

        # if multiple keys selected display "---" unless all selected keys have same value
        # which can only happen when all the keys have different parent curves
        selectedKeys = self.parent().curveGadget().selectedKeys()
        time = sole(key.getTime() for key in selectedKeys)
        if time is not None:
            context = selectedKeys[0].parent().ancestor(
                Gaffer.ScriptNode).context()
            frame = int(round(time * context.getFramesPerSecond()))
            with Gaffer.BlockedConnection(self.__frameConnection):
                self.__frameEditor.setValue(frame)
        else:
            with Gaffer.BlockedConnection(self.__frameConnection):
                self.__frameEditor.setText("")
                self.__frameEditor._qtWidget().setPlaceholderText("---")

        # set enabled when all selected keys have different parent curves
        enabled = bool(selectedKeys)
        curves = set()
        for key in selectedKeys:
            if key.parent() in curves:
                enabled = False
                break
            curves.add(key.parent())
        self.__frameEditor.setEnabled(enabled)
예제 #2
0
	def testReentrant( self ) :
	
		self.numCalls = 0
		def f() :
			self.numCalls += 1
	
		s = Gaffer.Signal0()
		c = s.connect( f )
		
		s()
		self.assertEqual( self.numCalls, 1 )
		
		with Gaffer.BlockedConnection( c ) :
			s()
			self.assertEqual( self.numCalls, 1 )
			with Gaffer.BlockedConnection( c ) :
				s()
		
		self.assertEqual( self.numCalls, 1 )
		
		s()
		self.assertEqual( self.numCalls, 2 )
		
		with Gaffer.BlockedConnection( c ) :
			s()
			self.assertEqual( self.numCalls, 2 )
			with Gaffer.BlockedConnection( c ) :
				s()
		
		self.assertEqual( self.numCalls, 2 )
		
		s()
		self.assertEqual( self.numCalls, 3 )
예제 #3
0
    def _updateFromPlug(self):
        self.__multiSelectionMenu.setEnabled(self._editable())
        if self.getPlug() is not None:
            with self.getContext():

                # Check to see if the format is the default instance. If so then it means we are tracking
                # the default format and therefore do not need to change the UI.
                if self.getPlug().getValue().getDisplayWindow().isEmpty(
                ) and not self.__isDefaultFormatPlug:
                    self.__multiSelectionMenu.setSelection("Default Format")
                    return

                # Otherwise update the UI from the plug.
                plugValue = self.getPlug().getValue()
                for name in self.__formats.keys():
                    format = self.__formats[name]
                    if format == plugValue:
                        with Gaffer.BlockedConnection(
                                self.__currentChangedConnection):
                            self.__multiSelectionMenu.setSelection(name)

                        return

                # The format is new so we should add it to our menu...
                GafferImage.Format.registerFormat(plugValue)
                with Gaffer.BlockedConnection(self.__currentChangedConnection):
                    self.__multiSelectionMenu.setSelection(
                        self.__multiSelectionMenu[-1])
예제 #4
0
	def testContextChangedAndGIL( self ) :

		script = Gaffer.ScriptNode()

		script["plane"] = GafferScene.Plane()
		script["plane"]["divisions"].setValue( imath.V2i( 20 ) )

		script["sphere"] = GafferScene.Sphere()

		script["expression"] = Gaffer.Expression()
		script["expression"].setExpression( "parent['sphere']['radius'] = context.get( 'minRadius', 0.1 ) + context.getFrame()" )

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

		context = Gaffer.Context()
		traverseConnection = Gaffer.ScopedConnection( GafferSceneTest.connectTraverseSceneToContextChangedSignal( script["instancer"]["out"], context ) )
		with context :

			context.setFrame( 10 )
			context.setFramesPerSecond( 50 )
			context.setTime( 1 )

			context.set( "a", 1 )
			context.set( "a", 2.0 )
			context.set( "a", "a" )
			context.set( "a", imath.V2i() )
			context.set( "a", imath.V3i() )
			context.set( "a", imath.V2f() )
			context.set( "a", imath.V3f() )
			context.set( "a", imath.Color3f() )
			context.set( "a", IECore.BoolData( True ) )

			context["b"] = 1
			context["b"] = 2.0
			context["b"] = "b"
			context["b"] = imath.V2i()
			context["b"] = imath.V3i()
			context["b"] = imath.V2f()
			context["b"] = imath.V3f()
			context["b"] = imath.Color3f()
			context["b"] = IECore.BoolData( True )

			with Gaffer.BlockedConnection( traverseConnection ) :
				# Must add it with the connection disabled, otherwise
				# the addition causes a traversal, and then remove() gets
				# all its results from the cache.
				context["minRadius"] = 0.2

			context.remove( "minRadius" )

			with Gaffer.BlockedConnection( traverseConnection ) :
				context["minRadius"] = 0.3

			del context["minRadius"]
예제 #5
0
    def __updateKeyValue(self):

        # if multiple keys selected display "---" unless all selected keys have same value
        selectedKeys = self.parent().curveGadget().selectedKeys()
        value = sole(key.getValue() for key in selectedKeys)
        if value is not None:
            with Gaffer.BlockedConnection(self.__valueConnection):
                self.__valueEditor.setValue(value)
        else:
            with Gaffer.BlockedConnection(self.__valueConnection):
                self.__valueEditor.setText("")
                self.__valueEditor._qtWidget().setPlaceholderText("---")

        # set disabled when no selected keys
        self.__valueEditor.setEnabled(bool(selectedKeys))
예제 #6
0
    def __updateFilter(self):

        newFilter = self.__path.getFilter()
        if self.__filter is not None and self.__filter.isSame(newFilter):
            return

        # update the directory path filter to include
        # the new filter, but with the additional removal
        # of leaf paths. block the signal because otherwise
        # we'd end up truncating the main path in __dirPathChanged.
        with Gaffer.BlockedConnection(self.__dirPathChangedConnection):
            if newFilter is not None:
                self.__dirPath.setFilter(
                    Gaffer.CompoundPathFilter([
                        Gaffer.LeafPathFilter(),
                        newFilter,
                    ]))
            else:
                self.__dirPath.setFilter(Gaffer.LeafPathFilter())

        # update ui for displaying the filter
        newFilterUI = None
        if newFilter is not None:
            newFilterUI = GafferUI.PathFilterWidget.create(newFilter)

        self.__filterFrame.setChild(newFilterUI)
        self.__filterFrame.setVisible(newFilterUI is not None)

        self.__filter = newFilter
예제 #7
0
	def _updateFromPlug( self ) :

		plug = self.getPlug()
		if plug is not None :

			with self.getContext() :
				try :
					value = plug.getValue()
				except :
					value = None

			if value is not None :
				with Gaffer.BlockedConnection( self.__valueChangedConnection ) :
					self.__numericWidget.setValue( value )

			self.__numericWidget.setErrored( value is None )

			## \todo Perhaps this styling should be provided by the NumericWidget itself?
			animated = Gaffer.Animation.isAnimated( plug )
			widgetAnimated = GafferUI._Variant.fromVariant( self.__numericWidget._qtWidget().property( "gafferAnimated" ) ) or False
			if widgetAnimated != animated :
				self.__numericWidget._qtWidget().setProperty( "gafferAnimated", GafferUI._Variant.toVariant( bool( animated ) ) )
				self.__numericWidget._repolish()

		self.__numericWidget.setEditable( self._editable( canEditAnimation = True ) )
예제 #8
0
	def __setPlugValue( self, mergeGroup="" ) :

		with Gaffer.UndoScope( self.getPlug().ancestor( Gaffer.ScriptNode ), mergeGroup=mergeGroup ) :

			with Gaffer.BlockedConnection( self._plugConnections() ) :
				if Gaffer.Animation.isAnimated( self.getPlug() ) :
					curve = Gaffer.Animation.acquire( self.getPlug() )
					if self.__numericWidget.getText() != self.__numericWidget.valueToString( curve.evaluate( self.getContext().getTime() ) ) :
						curve.addKey(
							Gaffer.Animation.Key(
								self.getContext().getTime(),
								self.__numericWidget.getValue(),
								Gaffer.Animation.Type.Linear
							)
						)
				else :
					try :
						self.getPlug().setValue( self.__numericWidget.getValue() )
					except :
						pass

			# now any changes that were made in the numeric widget have been transferred
			# into the global undo queue, we remove the text editing changes from the
			# widget's private text editing undo queue. it will then ignore undo shortcuts,
			# allowing them to fall through to the global undo shortcut.
			self.__numericWidget.clearUndo()

			# we always need to update the ui from the plug after trying to set it,
			# because the plug might clamp the value to something else. furthermore
			# it might not even emit plugSetSignal if it happens to clamp to the same
			# value as it had before. we block calls to _updateFromPlug() while setting
			# the value to avoid having to do the work twice if plugSetSignal is emitted.
			self._updateFromPlug()
예제 #9
0
    def __transferSelectionFromContext(self):

        selection = ContextAlgo.getSelectedPaths(self.getContext())
        with Gaffer.BlockedConnection(self.__selectionChangedConnection):
            self.__pathListing.setSelection(selection,
                                            scrollToFirst=True,
                                            expandNonLeaf=False)
예제 #10
0
    def __selectionChanged(self, pathListing):

        assert (pathListing is self.__pathListing)

        with Gaffer.BlockedConnection(self._contextChangedConnection()):
            ContextAlgo.setSelectedPaths(self.getContext(),
                                         pathListing.getSelection())
    def __pathListingSelectionChanged(self, pathListing):

        selection = pathListing.getSelectedPaths()
        if len(selection):
            with Gaffer.BlockedConnection(
                    self.__attributeCachePathChangedConnection):
                self.__attributeCachePath[:] = selection[0][:]
예제 #12
0
    def appendMessage(self, level, context, message):

        # make sure relevant button is shown
        self.__levelButtons[level].setVisible(True)

        # append message text
        formatted = "<h1 class='%s'>%s : %s </h1><span class='message'>%s</span><br>" % (
            IECore.Msg.levelAsString(level), IECore.Msg.levelAsString(level),
            context, message.replace("\n", "<br>"))

        with Gaffer.BlockedConnection(self.__textChangedConnection):
            self.__text._qtWidget().appendHtml(formatted)

        # Update the gui so messages are output as they occur, rather than all getting queued
        # up till the end. We have to be careful to avoid recursion when doing this - another
        # thread may be queuing up loads of messages using self.messageHandler(), and those
        # will get processed by processEvents(), resulting in a recursive call to appendMessage().
        # If the other thread supplies messages fast enough and we don't guard against recursion
        # then we can end up exceeding Python's stack limit very quickly.
        if not self.__processingEvents:
            try:
                self.__processingEvents = True
                QtGui.QApplication.instance().processEvents(
                    QtCore.QEventLoop.ExcludeUserInputEvents)
            finally:
                self.__processingEvents = False
예제 #13
0
	def __tabMoved( self, fromIndex, toIndex ) :

		with Gaffer.BlockedConnection( self.__plugMetadataChangedConnection ) :
			with Gaffer.UndoScope( self.__rowsPlug.ancestor( Gaffer.ScriptNode ) ) :
				for i in range( 0, self._qtWidget().count() ) :
					sectionName = self._qtWidget().tabText( i )
					Gaffer.Metadata.registerValue( self.__rowsPlug, "spreadsheet:section:{}:index".format( sectionName ), i )
예제 #14
0
    def __pathListingSelectionChanged(self, pathListing):

        selection = pathListing.getSelection()
        if not selection.isEmpty():
            with Gaffer.BlockedConnection(
                    self.__indexedIOPathChangedConnection):
                self.__indexedIOPath.setFromString(selection.paths()[0])
    def __setPlugValues(self, mergeGroup=""):

        with Gaffer.UndoScope(next(iter(self.getPlugs())).ancestor(
                Gaffer.ScriptNode),
                              mergeGroup=mergeGroup):

            with Gaffer.BlockedConnection(self._plugConnections()):

                for plug in self.getPlugs():

                    if Gaffer.Animation.isAnimated(plug):
                        curve = Gaffer.Animation.acquire(plug)
                        if self.__numericWidget.getText(
                        ) != self.__numericWidget.valueToString(
                                curve.evaluate(self.getContext().getTime())):
                            curve.addKey(
                                Gaffer.Animation.Key(
                                    self.getContext().getTime(),
                                    self.__numericWidget.getValue(),
                                    Gaffer.Animation.Type.Linear))
                    else:
                        try:
                            plug.setValue(self.__sliders.getColor())
                        except Exception as e:
                            print(e)
                            pass

        # We always need to update the UI from the plugs after trying to set them,
        # because the plugs might clamp the value to something else. Furthermore
        # they might not even emit `plugDirtiedSignal() if they happens to clamp to the same
        # value as before. We block calls to `_updateFromPlugs()` while setting
        # the value to avoid having to do the work twice if `plugDirtiedSignal()` _is_ emitted.
        self._updateFromPlugs()
예제 #16
0
    def __pathChanged(self, path):

        self.__updateFilter()

        # update the directory path and the listing path, but only if we're
        # in list mode rather than tree mode.
        if self.__directoryListing.getDisplayMode(
        ) == GafferUI.PathListingWidget.DisplayMode.List:
            pathCopy = path.copy()
            if pathCopy.isLeaf():
                del pathCopy[-1]
            pathCopy.truncateUntilValid()
            with Gaffer.BlockedConnection(
                (self.__dirPathChangedConnection,
                 self.__listingPathChangedConnection)):
                self.__dirPath.setFromPath(pathCopy)
                self.__listingPath.setFromPath(pathCopy)
        else:
            # if we're in tree mode then we instead scroll to display the new path
            self.__directoryListing.scrollToPath(path)

        # and update the selection in the listing
        if path.isLeaf():
            self.__directoryListing.setSelection(
                IECore.PathMatcher([str(path)]))
        else:
            self.__directoryListing.setSelection(IECore.PathMatcher())
예제 #17
0
	def __setPlugValues( self, mergeGroup="" ) :

		with Gaffer.UndoScope( next( iter( self.getPlugs() ) ).ancestor( Gaffer.ScriptNode ), mergeGroup=mergeGroup ) :

			with Gaffer.BlockedConnection( self._plugConnections() ) :

				for plug in self.getPlugs() :

					if Gaffer.Animation.isAnimated( plug ) :
						curve = Gaffer.Animation.acquire( plug )
						if self.__numericWidget.getText() != self.__numericWidget.valueToString( curve.evaluate( self.getContext().getTime() ) ) :
							curve.insertKey( self.getContext().getTime(), self.__numericWidget.getValue() )
					else :
						try :
							plug.setValue( self.__numericWidget.getValue() )
						except :
							pass

		# Now any changes that were made in the numeric widget have been transferred
		# into the global undo queue, we remove the text editing changes from the
		# widget's private text editing undo queue. It will then ignore undo shortcuts,
		# allowing them to fall through to the global undo shortcut.
		self.__numericWidget.clearUndo()

		# We always need to update the UI from the plugs after trying to set them,
		# because the plugs might clamp the value to something else. Furthermore
		# they might not even emit `plugDirtiedSignal() if they happens to clamp to the same
		# value as before. We block calls to `_updateFromPlugs()` while setting
		# the value to avoid having to do the work twice if `plugDirtiedSignal()` _is_ emitted.
		self._updateFromPlugs()
예제 #18
0
    def _updateFromPlug(self):

        if self.getPlug() is not None:

            value = None
            with self.getContext():
                # Since BoolWidget doesn't yet have a way of
                # displaying errors, we just ignore exceptions
                # and leave UI components like GraphGadget to
                # display them via Node.errorSignal().
                with IECore.IgnoredExceptions(Exception):
                    value = self.getPlug().getValue()

            if value is not None:
                with Gaffer.BlockedConnection(self.__stateChangedConnection):
                    self.__boolWidget.setState(value)

            displayMode = Gaffer.Metadata.plugValue(
                self.getPlug(), "boolPlugValueWidget:displayMode")
            if displayMode is not None:
                self.__boolWidget.setDisplayMode(
                    self.__boolWidget.DisplayMode.Switch if displayMode ==
                    "switch" else self.__boolWidget.DisplayMode.CheckBox)

        self.__boolWidget.setEnabled(self._editable(canEditAnimation=True))
예제 #19
0
    def __setScale(self, direction, widget, reason):

        # check for invalid edit
        if reason == GafferUI.NumericWidget.ValueChangedReason.InvalidEdit:
            self.__updateTangentScale(direction)
            return

        # handle undo queue
        if not widget.changesShouldBeMerged(
                self.__lastChangedReasonScale[direction], reason):
            self.__mergeGroupIdScale[direction] += 1
        self.__lastChangedReasonScale[direction] = reason

        # set scale for all selected keys in specified direction
        selectedKeys = self.parent().curveGadget().selectedKeys()
        if selectedKeys:
            try:
                value = max(widget.getValue(), float(0))
            except ValueError:
                return
            with Gaffer.UndoScope(
                    selectedKeys[0].parent().ancestor(Gaffer.ScriptNode),
                    mergeGroup=str(self.__mergeGroupIdScale[direction])):
                for key in selectedKeys:
                    with Gaffer.BlockedConnection(
                            self.__connections[key.parent()].tangent):
                        key.tangent(direction).setScale(value)
            widget.clearUndo()

        # ensure editors are up to date
        for direction in Gaffer.Animation.Direction.names.values():
            self.__updateTangentScale(direction)
예제 #20
0
	def __dataChanged( self, widget ) :

		assert( widget is self.__dataWidget )

		with Gaffer.UndoContext( self.getPlug().ancestor( Gaffer.ScriptNode ) ) :
			with Gaffer.BlockedConnection( self._plugConnections() ) :
				self.getPlug().setValue( self.__dataWidget.getData()[0] )
예제 #21
0
    def __setValue(self, widget, reason):

        # check for invalid edit
        if reason == GafferUI.NumericWidget.ValueChangedReason.InvalidEdit:
            self.__updateKeyValue()
            return

        # handle undo queue
        if not widget.changesShouldBeMerged(self.__lastChangedReasonValue,
                                            reason):
            self.__mergeGroupIdValue += 1
        self.__lastChangedReasonValue = reason

        # set value for all selected keys
        selectedKeys = self.parent().curveGadget().selectedKeys()
        if selectedKeys:
            try:
                value = widget.getValue()
            except ValueError:
                return
            with Gaffer.UndoScope(selectedKeys[0].parent().ancestor(
                    Gaffer.ScriptNode),
                                  mergeGroup=str(self.__mergeGroupIdValue)):
                for key in selectedKeys:
                    with Gaffer.BlockedConnection(
                            self.__connections[key.parent()].value):
                        key.setValue(value)
            widget.clearUndo()
예제 #22
0
    def __selectionChanged(self, pathListing):

        assert (pathListing is self.__curveList)

        paths = pathListing.getSelectedPaths()

        plugList = []

        for path in paths:
            graphComponent = path.property("graphComponent:graphComponent")

            if isinstance(graphComponent, Gaffer.ValuePlug
                          ) and Gaffer.Animation.isAnimated(graphComponent):
                plugList.append(graphComponent)

            for child in graphComponent.children():
                if isinstance(child, Gaffer.ValuePlug
                              ) and Gaffer.Animation.isAnimated(child):
                    plugList.append(child)

        self.__editablePlugs = set(plugList)

        editable = self.__animationGadget.editablePlugs()

        with Gaffer.BlockedConnection(self.__editablePlugsConnections):

            editable.clear()
            for plug in plugList:
                editable.add(self.__sourceCurvePlug(plug))
예제 #23
0
    def __expansionChanged(self, pathListing):

        assert (pathListing is self.__curveList)

        paths = pathListing.getExpandedPaths()

        visiblePlugs = set()
        for path in paths:
            for childPath in path.children():
                child = childPath.property("graphComponent:graphComponent")
                if isinstance(child, Gaffer.ValuePlug
                              ) and Gaffer.Animation.isAnimated(child):
                    visiblePlugs.add(child)

        visible = self.__animationGadget.visiblePlugs()
        editable = self.__animationGadget.editablePlugs()

        visible.clear()
        for plug in visiblePlugs:
            visible.add(self.__sourceCurvePlug(plug))

        with Gaffer.BlockedConnection(self.__editablePlugsConnections):

            editable.clear()
            for plug in (self.__editablePlugs or set()) & visiblePlugs:
                editable.add(self.__sourceCurvePlug(plug))
예제 #24
0
    def __selectionChanged(self, pathListing):

        assert (pathListing is self.__curveList)

        paths = pathListing.getSelectedPaths()

        plugList = []

        for path in paths:
            graphComponent = self.__scriptNode.descendant(
                str(path).replace('/', '.'))

            if isinstance(graphComponent, Gaffer.ValuePlug
                          ) and Gaffer.Animation.isAnimated(graphComponent):
                plugList.append(graphComponent)

            for child in graphComponent.children():
                if isinstance(child, Gaffer.ValuePlug
                              ) and Gaffer.Animation.isAnimated(child):
                    plugList.append(child)

        self.__editablePlugs = set(plugList)

        editable = self.__animationGadget.editablePlugs()

        with Gaffer.BlockedConnection(self.__editablePlugAddedConnection):

            editable.clear()
            for plug in plugList:
                if plug in editable:
                    continue

                curvePlug = self.connectedCurvePlug(plug)
                if curvePlug:
                    editable.add(curvePlug)
예제 #25
0
	def __dirPathChanged( self, dirPath ) :
	
		# update the main path and the listing path
		dirPathCopy = dirPath.copy()
		dirPathCopy.truncateUntilValid()
		with Gaffer.BlockedConnection( ( self.__pathChangedConnection, self.__listingPathChangedConnection ) ) :
			self.__path[:] = dirPathCopy[:]
			self.__listingPath[:] = dirPathCopy[:]
예제 #26
0
	def __selectionChanged( self, pathListing ) :

		assert( pathListing is self.__pathListing )

		paths = pathListing.getSelectedPaths()
		paths = IECore.StringVectorData( [ str( path ) for path in paths ] )
		with Gaffer.BlockedConnection( self._contextChangedConnection() ) :
			self.getContext().set( "ui:scene:selectedPaths", paths )
예제 #27
0
	def __listingPathChanged( self, listingPath ) :
	
		assert( listingPath is self.__listingPath )
	
		# update the directory path and the main path
		with Gaffer.BlockedConnection( ( self.__pathChangedConnection, self.__dirPathChangedConnection ) ) :
			self.__dirPath[:] = listingPath[:]
			self.__path[:] = listingPath[:]
예제 #28
0
    def __playbackFrameRangeChanged( self, playback ) :

        minValue, maxValue = playback.getFrameRange()

        with Gaffer.BlockedConnection( ( self.__sliderRangeStartChangedConnection, self.__sliderRangeEndChangedConnection ) ) :
            self.__slider.setRange( minValue, maxValue )
            self.__sliderRangeStart.setValue( minValue )
            self.__sliderRangeEnd.setValue( maxValue )
예제 #29
0
    def _updateFromPlug(self):

        if self.getPlug() is not None:
            with self.getContext():
                with Gaffer.BlockedConnection(self.__stateChangedConnection):
                    self.__checkBox.setState(self.getPlug().getValue())

        self.__checkBox.setEnabled(self._editable())
예제 #30
0
	def __transferExpansionFromContext( self ) :

		expandedPaths = ContextAlgo.getExpandedPaths( self.getContext() )
		if expandedPaths is None :
			return

		with Gaffer.BlockedConnection( self.__expansionChangedConnection ) :
			self.__pathListing.setExpansion( expandedPaths )