diff --git a/Changes.md b/Changes.md index 7f580b9157f..b60854da2f1 100644 --- a/Changes.md +++ b/Changes.md @@ -6,9 +6,12 @@ Breaking Changes - StandardNodule : Removed deprecated `setCompatibleLabelsVisible()`. +1.5.x.x (relative to 1.5.2.0) +======= + -1.5.x.x (relative to 1.5.1.0) +1.5.2.0 (relative to 1.5.1.0) ======= > Caution : The GafferML features introduced in this release are considered experimental, and are not subject to the usual backwards compatibility guarantees that apply to the rest of Gaffer. @@ -16,9 +19,9 @@ Breaking Changes Features -------- -- GafferML : Added a new module with the following nodes for running maching learning models via ONNX Runtime : +- GafferML : Added a new module with the following nodes for running machine learning models via ONNX Runtime : - DataToTensor : Converts Gaffer data to tensors. - - Inference : Loads ONNX models and performance inference using an array of input tensors. + - Inference : Loads ONNX models and performs inference using an array of input tensors. - ImageToTensor : Converts images to tensors for use with the Inference node. - TensorToImage : Converts tensors back to images following inference. - VisualiserTool : Added tool to 3D viewer for visualising primitive variables on meshes. @@ -42,6 +45,8 @@ Fixes - Widget : Fixed `event.sourceWidget` for DragDropEvents generated from a Qt native drag within the same Gaffer process. This will now reference the `GafferUI.Widget` that the Qt source widget belongs to, if any. - Catalogue : Fixed bug which "stole" drags that crossed the image listing but which were destined elsewhere, for instance a drag from the HierarchyView to a PathFilter in the GraphEditor. - GadgetWidget : Fixed signal handling bug in `setViewportGadget()`. This could cause the widget to attempt to redraw unnecessarily when the _old_ viewport requested a redraw. +- EditScope : Fixed error updating the Global Edit Target in read-only files. +- RandomChoice : Fixed errors right-clicking on non-value plugs in the NodeEditor. API --- @@ -358,16 +363,23 @@ Build - Zstandard : Added version 1.5.0. - Windows : Updated compiler to Visual Studio 2022 / MSVC 17.8 / Runtime library 14.3. -1.4.15.x (relative to 1.4.15.2) +1.4.15.x (relative to 1.4.15.3) +======== + + + +1.4.15.3 (relative to 1.4.15.2) ======== Fixes ----- +- ArrayPlug : Fixed loading of promoted plugs saved from Gaffer 1.5+. - GraphEditor : Fixed errors when dragging an unknown file type into the GraphEditor. - Widget : Fixed `event.sourceWidget` for DragDropEvents generated from a Qt native drag within the same Gaffer process. This will now reference the `GafferUI.Widget` that the Qt source widget belongs to, if any. - Catalogue : Fixed bug which "stole" drags that crossed the image listing but which were destined elsewhere, for instance a drag from the HierarchyView to a PathFilter in the GraphEditor. - GadgetWidget : Fixed signal handling bug in `setViewportGadget()`. This could cause the widget to attempt to redraw unnecessarily when the _old_ viewport requested a redraw. +- RandomChoice : Fixed errors right-clicking on non-value plugs in the NodeEditor. 1.4.15.2 (relative to 1.4.15.1) ======== diff --git a/python/GafferSceneTest/ParentTest.py b/python/GafferSceneTest/ParentTest.py index eb46adb1b64..bb5fedb54c0 100644 --- a/python/GafferSceneTest/ParentTest.py +++ b/python/GafferSceneTest/ParentTest.py @@ -490,6 +490,19 @@ def testLoadPromotedChildrenPlug( self ) : s2["b2"]["p"]["children"].getInput().fullName() ) + def testLoadPromotedChildrenPlugFrom1_5( self ) : + + script = Gaffer.ScriptNode() + script["fileName"].setValue( pathlib.Path( __file__ ).parent / "scripts" / "promotedArrayPlug-1.5.1.0.gfr" ) + script.load() + + self.assertEqual( script["Box"]["children"][0].getInput(), script["Cube"]["out"] ) + self.assertEqual( script["Box"]["Parent"]["children"].source(), script["Box"]["children"] ) + self.assertEqual( script["Box"]["Parent"]["children"][0].source(), script["Cube"]["out"] ) + + self.assertSceneValid( script["Box"]["out"] ) + self.assertEqual( script["Box"]["out"].childNames( "/" ), IECore.InternedStringVectorData( [ "sphere", "cube" ] ) ) + def testSetPassThroughWhenNoParent( self ) : sphere = GafferScene.Sphere() diff --git a/python/GafferSceneTest/scripts/promotedArrayPlug-1.5.1.0.gfr b/python/GafferSceneTest/scripts/promotedArrayPlug-1.5.1.0.gfr new file mode 100644 index 00000000000..e0845ab730e --- /dev/null +++ b/python/GafferSceneTest/scripts/promotedArrayPlug-1.5.1.0.gfr @@ -0,0 +1,76 @@ +import Gaffer +import GafferImage +import GafferScene +import imath + +Gaffer.Metadata.registerValue( parent, "serialiser:milestoneVersion", 1, persistent=False ) +Gaffer.Metadata.registerValue( parent, "serialiser:majorVersion", 5, persistent=False ) +Gaffer.Metadata.registerValue( parent, "serialiser:minorVersion", 1, persistent=False ) +Gaffer.Metadata.registerValue( parent, "serialiser:patchVersion", 0, persistent=False ) + +__children = {} + +parent["variables"].addChild( Gaffer.NameValuePlug( "image:catalogue:port", Gaffer.IntPlug( "value", defaultValue = 0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "imageCataloguePort", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) ) +parent["variables"].addChild( Gaffer.NameValuePlug( "project:name", Gaffer.StringPlug( "value", defaultValue = 'default', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "projectName", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) ) +parent["variables"].addChild( Gaffer.NameValuePlug( "project:rootDirectory", Gaffer.StringPlug( "value", defaultValue = '$HOME/gaffer/projects/${project:name}', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "projectRootDirectory", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) ) +__children["openColorIO"] = GafferImage.OpenColorIOConfigPlug( "openColorIO", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) +parent.addChild( __children["openColorIO"] ) +__children["defaultFormat"] = GafferImage.FormatPlug( "defaultFormat", defaultValue = GafferImage.Format( 1920, 1080, 1.000 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) +parent.addChild( __children["defaultFormat"] ) +__children["Box"] = Gaffer.Box( "Box" ) +parent.addChild( __children["Box"] ) +__children["Box"].addChild( GafferScene.Parent( "Parent" ) ) +__children["Box"]["Parent"]["children"].resize( 2 ) +__children["Box"]["Parent"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Box"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Box"].addChild( Gaffer.BoxIn( "BoxIn" ) ) +__children["Box"]["BoxIn"].setup( Gaffer.ArrayPlug( "out", elementPrototype = GafferScene.ScenePlug( "child0", ), ) ) +__children["Box"]["BoxIn"]["__in"].resize( 2 ) +__children["Box"]["BoxIn"]["out"].resize( 2 ) +__children["Box"]["BoxIn"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Box"].addChild( Gaffer.ArrayPlug( "children", elementPrototype = GafferScene.ScenePlug( "child0", ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Box"]["children"].resize( 2 ) +__children["Box"].addChild( GafferScene.Sphere( "Sphere" ) ) +__children["Box"]["Sphere"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Box"].addChild( Gaffer.BoxOut( "BoxOut" ) ) +__children["Box"]["BoxOut"].setup( GafferScene.ScenePlug( "in", ) ) +__children["Box"]["BoxOut"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Box"].addChild( GafferScene.ScenePlug( "out", direction = Gaffer.Plug.Direction.Out, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Cube"] = GafferScene.Cube( "Cube" ) +parent.addChild( __children["Cube"] ) +__children["Cube"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +parent["variables"]["imageCataloguePort"]["value"].setValue( 39173 ) +Gaffer.Metadata.registerValue( parent["variables"]["imageCataloguePort"], 'readOnly', True ) +Gaffer.Metadata.registerValue( parent["variables"]["projectName"]["name"], 'readOnly', True ) +Gaffer.Metadata.registerValue( parent["variables"]["projectRootDirectory"]["name"], 'readOnly', True ) +__children["Box"]["Parent"]["in"].setInput( __children["Box"]["Sphere"]["out"] ) +__children["Box"]["Parent"]["parent"].setValue( '/' ) +__children["Box"]["Parent"]["children"].setInput( __children["Box"]["BoxIn"]["out"] ) +Gaffer.Metadata.registerValue( __children["Box"]["Parent"]["children"], 'nodule:type', 'GafferUI::StandardNodule' ) +__children["Box"]["Parent"]["__uiPosition"].setValue( imath.V2f( -9.90000057, 4.5 ) ) +__children["Box"]["__uiPosition"].setValue( imath.V2f( -16.6000023, 1.09999955 ) ) +__children["Box"]["BoxIn"]["name"].setValue( 'children' ) +__children["Box"]["BoxIn"]["__in"].setInput( __children["Box"]["children"] ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxIn"]["__in"], 'nodule:type', 'GafferUI::CompoundNodule' ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxIn"]["__in"], 'description', 'The child hierarchies to be parented.' ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxIn"]["__in"], 'plugValueWidget:type', '' ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxIn"]["__in"], 'noduleLayout:spacing', 0.5 ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxIn"]["out"], 'nodule:type', 'GafferUI::StandardNodule' ) +__children["Box"]["BoxIn"]["__uiPosition"].setValue( imath.V2f( -8.40068531, 12.8320312 ) ) +Gaffer.Metadata.registerValue( __children["Box"]["children"], 'nodule:type', 'GafferUI::CompoundNodule' ) +Gaffer.Metadata.registerValue( __children["Box"]["children"], 'description', 'The child hierarchies to be parented.' ) +Gaffer.Metadata.registerValue( __children["Box"]["children"], 'plugValueWidget:type', '' ) +Gaffer.Metadata.registerValue( __children["Box"]["children"], 'noduleLayout:spacing', 0.5 ) +__children["Box"]["children"][0].setInput( __children["Cube"]["out"] ) +__children["Box"]["Sphere"]["__uiPosition"].setValue( imath.V2f( -24.5000019, 11.3000002 ) ) +__children["Box"]["BoxOut"]["in"].setInput( __children["Box"]["Parent"]["out"] ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxOut"]["__out"], 'description', 'The processed output scene.' ) +Gaffer.Metadata.registerValue( __children["Box"]["BoxOut"]["__out"], 'nodule:type', 'GafferUI::StandardNodule' ) +__children["Box"]["BoxOut"]["__uiPosition"].setValue( imath.V2f( -8.40068531, -3.83203101 ) ) +__children["Box"]["out"].setInput( __children["Box"]["BoxOut"]["__out"] ) +Gaffer.Metadata.registerValue( __children["Box"]["out"], 'description', 'The processed output scene.' ) +Gaffer.Metadata.registerValue( __children["Box"]["out"], 'nodule:type', 'GafferUI::StandardNodule' ) +__children["Cube"]["__uiPosition"].setValue( imath.V2f( -18.8500023, 9.43203068 ) ) + + +del __children diff --git a/python/GafferTest/ArrayPlugTest.py b/python/GafferTest/ArrayPlugTest.py index e60133f7f60..ed2a140d918 100644 --- a/python/GafferTest/ArrayPlugTest.py +++ b/python/GafferTest/ArrayPlugTest.py @@ -34,8 +34,8 @@ # ########################################################################## -import unittest import pathlib +import unittest import imath import IECore @@ -628,5 +628,16 @@ def testResizeWithoutElementPrototype( self ) : with self.assertRaisesRegex( RuntimeError, "ArrayPlug `p` was constructed without the required `elementPrototype`" ) : p.resize( 1 ) + def testLoadOutputPrototypeFrom1_5( self ) : + + script = Gaffer.ScriptNode() + script["fileName"].setValue( pathlib.Path( __file__ ).parent / "scripts" / "arrayPlugWithOutputPrototype-1.5.1.0.gfr" ) + script.load() + + self.assertIsInstance( script["Node"]["user"]["array"], Gaffer.ArrayPlug ) + self.assertEqual( script["Node"]["user"]["array"].direction(), Gaffer.Plug.Direction.In ) + self.assertEqual( len( script["Node"]["user"]["array"] ), 1 ) + self.assertIsInstance( script["Node"]["user"]["array"][0], Gaffer.IntPlug ) + if __name__ == "__main__": unittest.main() diff --git a/python/GafferTest/scripts/arrayPlugWithOutputPrototype-1.5.1.0.gfr b/python/GafferTest/scripts/arrayPlugWithOutputPrototype-1.5.1.0.gfr new file mode 100644 index 00000000000..23ebf99f5cd --- /dev/null +++ b/python/GafferTest/scripts/arrayPlugWithOutputPrototype-1.5.1.0.gfr @@ -0,0 +1,31 @@ +import Gaffer +import GafferImage +import imath + +Gaffer.Metadata.registerValue( parent, "serialiser:milestoneVersion", 1, persistent=False ) +Gaffer.Metadata.registerValue( parent, "serialiser:majorVersion", 5, persistent=False ) +Gaffer.Metadata.registerValue( parent, "serialiser:minorVersion", 1, persistent=False ) +Gaffer.Metadata.registerValue( parent, "serialiser:patchVersion", 0, persistent=False ) + +__children = {} + +parent["variables"].addChild( Gaffer.NameValuePlug( "image:catalogue:port", Gaffer.IntPlug( "value", defaultValue = 0, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "imageCataloguePort", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) ) +parent["variables"].addChild( Gaffer.NameValuePlug( "project:name", Gaffer.StringPlug( "value", defaultValue = 'default', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "projectName", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) ) +parent["variables"].addChild( Gaffer.NameValuePlug( "project:rootDirectory", Gaffer.StringPlug( "value", defaultValue = '$HOME/gaffer/projects/${project:name}', flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ), "projectRootDirectory", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) ) +__children["openColorIO"] = GafferImage.OpenColorIOConfigPlug( "openColorIO", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) +parent.addChild( __children["openColorIO"] ) +__children["defaultFormat"] = GafferImage.FormatPlug( "defaultFormat", defaultValue = GafferImage.Format( 1920, 1080, 1.000 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) +parent.addChild( __children["defaultFormat"] ) +__children["Node"] = Gaffer.Node( "Node" ) +parent.addChild( __children["Node"] ) +__children["Node"]["user"].addChild( Gaffer.ArrayPlug( "array", elementPrototype = Gaffer.IntPlug( "IntPlug", direction = Gaffer.Plug.Direction.Out, defaultValue = 0, ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +__children["Node"].addChild( Gaffer.V2fPlug( "__uiPosition", defaultValue = imath.V2f( 0, 0 ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, ) ) +parent["frame"].setValue( 100.0 ) +parent["variables"]["imageCataloguePort"]["value"].setValue( 41733 ) +Gaffer.Metadata.registerValue( parent["variables"]["imageCataloguePort"], 'readOnly', True ) +Gaffer.Metadata.registerValue( parent["variables"]["projectName"]["name"], 'readOnly', True ) +Gaffer.Metadata.registerValue( parent["variables"]["projectRootDirectory"]["name"], 'readOnly', True ) +__children["Node"]["__uiPosition"].setValue( imath.V2f( -9.40000057, 0.100000001 ) ) + + +del __children diff --git a/python/GafferUI/EditScopeUI.py b/python/GafferUI/EditScopeUI.py index 256160b29c6..f9043797309 100644 --- a/python/GafferUI/EditScopeUI.py +++ b/python/GafferUI/EditScopeUI.py @@ -600,9 +600,11 @@ def __unusableReason( self, editScope ) : def __readOnlyReason( self, editScope ) : - if Gaffer.MetadataAlgo.readOnly( editScope ) : + readOnlyReason = Gaffer.MetadataAlgo.readOnlyReason( editScope ) + if readOnlyReason is not None : return "{} is locked.".format( - Gaffer.MetadataAlgo.readOnlyReason( editScope ).relativeName( editScope.scriptNode() ) + "File" if isinstance( readOnlyReason, Gaffer.ScriptNode ) + else readOnlyReason.relativeName( readOnlyReason.scriptNode() ) ) return None diff --git a/python/GafferUI/RandomChoiceUI.py b/python/GafferUI/RandomChoiceUI.py index a364c24b8eb..81cbad819bf 100644 --- a/python/GafferUI/RandomChoiceUI.py +++ b/python/GafferUI/RandomChoiceUI.py @@ -240,6 +240,8 @@ def __popupMenu( menuDefinition, plugValueWidget ) : return for plug in plugValueWidget.getPlugs() : + if not isinstance( plug, Gaffer.ValuePlug ) : + return if plug.getInput() is not None or Gaffer.MetadataAlgo.readOnly( plug ) : return if not Gaffer.RandomChoice.canSetup( plug ) :