Skip to content

Commit ac96930

Browse files
authored
Merge pull request #6015 from johnhaddon/arrayPlugElements
ArrayPlug improvements
2 parents 82e1e9c + cd70463 commit ac96930

37 files changed

+561
-125
lines changed

Changes.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ Fixes
3535
- Fixed update of custom context-sensitive labels on Dot nodes.
3636
- GafferCortexUI : Removed usage of legacy PlugValueWidget API.
3737
- Dispatcher : Fixed crashes caused by a dispatcher's `SetupPlugsFn` attempting to access the TaskNode it was being called for. Dispatchers may now introspect the TaskNode and add different plugs based on type (#915).
38+
- ArrayPlug :
39+
- Fixed error when `resize()` removed plugs with input connections.
40+
- Fixed error when `resize()` was used on an output plug.
41+
- CreateViews : Fixed redundant serialisation of internal connections.
3842

3943
API
4044
---
@@ -51,6 +55,9 @@ API
5155
- PathColumn :
5256
- Added `contextMenuSignal()`, allowing the creation of custom context menus.
5357
- Added `instanceCreatedSignal()`, providing an opportunity to connect to the signals on _any_ column, no matter how it is created.
58+
- ArrayPlug :
59+
- It is now legal to construct an ArrayPlug with a minimum size of 0. Previously the minimum size was 1.
60+
- Added `elementPrototype()` method.
5461

5562
Breaking Changes
5663
----------------
@@ -69,6 +76,9 @@ Breaking Changes
6976
- Deprecated `getContext()` methods. Use `context()` instead.
7077
- Loop : Removed `nextIterationContext()` method.
7178
- NodeGadget, ConnectionGadget : Removed `activeForFocusNode()` virtual methods. Override `updateFromContextTracker()` instead.
79+
- ArrayPlug :
80+
- Renamed `element` constructor argument to `elementPrototype`.
81+
- Deprecated the passing of `element = nullptr` to the constructor.
7282

7383
1.4.x.x (relative to 1.4.11.0)
7484
=======

include/Gaffer/ArrayPlug.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,17 @@ class GAFFER_API ArrayPlug : public Plug
4949

5050
public :
5151

52-
/// The element plug is used as the first array element,
53-
/// and all new array elements are created by calling
54-
/// element->createCounterpart(). Currently the element
55-
/// names are derived from the name of the first element,
56-
/// but this may change in the future. It is strongly
57-
/// recommended that ArrayPlug children are only accessed
58-
/// through numeric indexing and never via names.
52+
/// All array elements are created by calling
53+
/// `elementPrototype->createCounterpart()`. Currently the element names
54+
/// are derived from the name of the prototype, but this may change in
55+
/// the future. It is strongly recommended that ArrayPlug children are
56+
/// only accessed through numeric indexing and never via names.
5957
explicit ArrayPlug(
6058
const std::string &name = defaultName<ArrayPlug>(),
6159
Direction direction = In,
62-
PlugPtr element = nullptr,
60+
/// > Caution : `elementPrototype` should not be null. It only defaults
61+
/// > that way to support the loading of legacy serialisations.
62+
ConstPlugPtr elementPrototype = nullptr,
6363
size_t minSize = 1,
6464
size_t maxSize = std::numeric_limits<size_t>::max(),
6565
unsigned flags = Default,
@@ -75,8 +75,10 @@ class GAFFER_API ArrayPlug : public Plug
7575
void setInput( PlugPtr input ) override;
7676
PlugPtr createCounterpart( const std::string &name, Direction direction ) const override;
7777

78+
const Plug *elementPrototype() const;
7879
size_t minSize() const;
7980
size_t maxSize() const;
81+
/// Resizes the array. This should be preferred to `addChild()`.
8082
void resize( size_t size );
8183
bool resizeWhenInputsChange() const;
8284
/// Returns an unconnected element at the end of the array, adding one
@@ -91,7 +93,9 @@ class GAFFER_API ArrayPlug : public Plug
9193
private :
9294

9395
void inputChanged( Gaffer::Plug *plug );
96+
void childAdded();
9497

98+
ConstPlugPtr m_elementPrototype;
9599
size_t m_minSize;
96100
size_t m_maxSize;
97101
bool m_resizeWhenInputsChange;

python/GafferDispatchTest/DebugDispatcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def __createNode( name ) :
111111
node = Gaffer.Node()
112112
node.setName( name.replace( ".", "_" ) )
113113

114-
node["preTasks"] = Gaffer.ArrayPlug( element = Gaffer.Plug( "preTask0" ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
114+
node["preTasks"] = Gaffer.ArrayPlug( elementPrototype = Gaffer.Plug( "preTask0" ), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
115115
node["task"] = Gaffer.Plug( direction = Gaffer.Plug.Direction.Out, flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
116116
node["node"] = Gaffer.StringPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
117117
node["frames"] = Gaffer.StringPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )

python/GafferImageTest/AnaglyphTest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ def test( self ) :
6767
right['transform']['translate'].setValue( imath.V2f( 10, 0 ) )
6868

6969
createViews = GafferImage.CreateViews()
70-
createViews["views"].addChild( Gaffer.NameValuePlug( "left", GafferImage.ImagePlug(), True, "view0", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
71-
createViews["views"].addChild( Gaffer.NameValuePlug( "right", GafferImage.ImagePlug(), True, "view1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
70+
createViews["views"].resize( 2 )
7271
createViews["views"][0]["value"].setInput( left["out"] )
72+
createViews["views"][0]["name"].setValue( "left" )
7373
createViews["views"][1]["value"].setInput( right["out"] )
74+
createViews["views"][1]["name"].setValue( "right" )
7475

7576
anaglyph = GafferImage.Anaglyph()
7677
anaglyph["in"].setInput( createViews["out"] )

python/GafferImageTest/CatalogueTest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -917,10 +917,11 @@ def testGenerateFileName( self ):
917917

918918
# Check that two multi-view images match only if all views are identical
919919
createViews = GafferImage.CreateViews()
920-
createViews["views"].addChild( Gaffer.NameValuePlug( "left", GafferImage.ImagePlug(), True, "view0", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
921-
createViews["views"].addChild( Gaffer.NameValuePlug( "right", GafferImage.ImagePlug(), True, "view1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
920+
createViews["views"].resize( 2 )
922921
createViews["views"][0]["value"].setInput( constant1["out"] )
922+
createViews["views"][0]["name"].setValue( "left" )
923923
createViews["views"][1]["value"].setInput( constant2["out"] )
924+
createViews["views"][1]["name"].setValue( "right" )
924925

925926
f3 = catalogue.generateFileName( createViews["out"] )
926927
self.assertNotIn( f3, [f1, f2] )

python/GafferImageTest/ContactSheetCoreTest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@ def testNoInvalidViewAccesses( self ) :
124124

125125
checker = GafferImage.Checkerboard()
126126
createViews = GafferImage.CreateViews()
127-
createViews["views"].addChild( Gaffer.NameValuePlug( "left", GafferImage.ImagePlug(), True, "left", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
127+
createViews["views"].resize( 1 )
128128
createViews["views"][0]["value"].setInput( checker["out"] )
129+
createViews["views"][0]["name"].setValue( "left" )
129130
self.assertEqual( createViews["out"].viewNames(), IECore.StringVectorData( [ "left" ] ) )
130131

131132
contactSheet = GafferImage.ContactSheetCore()

python/GafferImageTest/CopyViewsTest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ def test( self ) :
6666
name = "source%iview%i" % ( i, j )
6767

6868
createViews[i].addChild( constant )
69-
createViews[i]["views"].addChild( Gaffer.NameValuePlug( name, GafferImage.ImagePlug(), True, "view0", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
70-
createViews[i]["views"][-1]["value"].setInput( constant["out"] )
69+
view = createViews[i]["views"].next()
70+
view["name"].setValue( name )
71+
view["value"].setInput( constant["out"] )
7172

7273
copyViews = GafferImage.CopyViews()
7374
copyViews["in"][0].setInput( createViews[0]["out"] )

python/GafferImageTest/CreateViewsTest.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,11 @@
3737
import unittest
3838
import imath
3939
import inspect
40-
import os
40+
import pathlib
4141

4242
import IECore
4343

4444
import Gaffer
45-
import GafferTest
4645
import GafferImage
4746
import GafferImageTest
4847

@@ -58,8 +57,9 @@ def test( self ) :
5857
script.addChild( createViews )
5958

6059
# Default views added by the UI
61-
createViews["views"].addChild( Gaffer.NameValuePlug( "left", GafferImage.ImagePlug(), True, "view0", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
62-
createViews["views"].addChild( Gaffer.NameValuePlug( "right", GafferImage.ImagePlug(), True, "view1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
60+
createViews["views"].resize( 2 )
61+
createViews["views"][0]["name"].setValue( "left" )
62+
createViews["views"][1]["name"].setValue( "right" )
6363

6464
reader = GafferImage.ImageReader()
6565
script.addChild( reader )
@@ -93,9 +93,9 @@ def test( self ) :
9393
self.assertImagesEqual( createViews["out"], deserialise["CreateViews"]["out"] )
9494

9595

96-
createViews["views"].addChild( Gaffer.NameValuePlug( "custom", GafferImage.ImagePlug(), True, "view1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
97-
createViews["views"]["view2"]["name"].setValue( "blah" )
98-
createViews["views"]["view2"]["value"].setInput( constant2["out"] )
96+
createViews["views"].resize( 3 )
97+
createViews["views"][2]["name"].setValue( "blah" )
98+
createViews["views"][2]["value"].setInput( constant2["out"] )
9999

100100
self.assertEqual( createViews["out"].viewNames(), IECore.StringVectorData( [ "left", "right", "blah" ] ) )
101101
self.assertEqual(
@@ -194,8 +194,9 @@ def testInputToExpressionDrivingEnabledPlug( self ) :
194194

195195
# `default` view with RGBA channels, and `notDefault` view with no channels
196196
script["createViews"] = GafferImage.CreateViews()
197-
script["createViews"]["views"].addChild( Gaffer.NameValuePlug( "default", GafferImage.ImagePlug(), True, "view0", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
198-
script["createViews"]["views"].addChild( Gaffer.NameValuePlug( "notDefault", GafferImage.ImagePlug(), True, "view1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
197+
script["createViews"]["views"].resize( 2 )
198+
script["createViews"]["views"][0]["name"].setValue( "default" )
199+
script["createViews"]["views"][1]["name"].setValue( "notDefault" )
199200
script["createViews"]["views"][0]["value"].setInput( script["checkerboard"]["out"] )
200201
self.assertEqual( script["createViews"]["out"].channelNames( "default" ), IECore.StringVectorData( [ "R", "G", "B", "A" ] ) )
201202
self.assertEqual( script["createViews"]["out"].channelNames( "notDefault" ), IECore.StringVectorData() )
@@ -224,5 +225,32 @@ def testInputToExpressionDrivingEnabledPlug( self ) :
224225
# for this particular view.
225226
self.assertFalse( script["constant"]["enabled"].getValue() )
226227

228+
def testNoRedundantSerialisation( self ) :
229+
230+
script = Gaffer.ScriptNode()
231+
script["createViews"] = GafferImage.CreateViews()
232+
self.assertNotIn( "setInput", script.serialise() )
233+
234+
def testLoadFromVersion1_4( self ) :
235+
236+
script = Gaffer.ScriptNode()
237+
script["fileName"].setValue( pathlib.Path( __file__ ).parent / "scripts" / "createViews-1.4.10.0.gfr" )
238+
script.load()
239+
240+
def assertLoadedOK( script ) :
241+
242+
self.assertEqual( len( script["CreateViews"]["views"] ), 2 )
243+
self.assertEqual( script["CreateViews"]["views"][0]["name"].getValue(), "left" )
244+
self.assertEqual( script["CreateViews"]["views"][1]["name"].getValue(), "right" )
245+
self.assertEqual( script["CreateViews"]["views"][0]["value"].getInput(), script["CheckerboardLeft"]["out"] )
246+
self.assertEqual( script["CreateViews"]["views"][1]["value"].getInput(), script["CheckerboardRight"]["out"] )
247+
248+
assertLoadedOK( script )
249+
250+
script2 = Gaffer.ScriptNode()
251+
script2.execute( script.serialise() )
252+
253+
assertLoadedOK( script2 )
254+
227255
if __name__ == "__main__":
228256
unittest.main()

python/GafferImageTest/DeleteViewsTest.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ def test( self ) :
6363

6464
createViews = GafferImage.CreateViews()
6565

66-
createViews["views"].addChild( Gaffer.NameValuePlug( "left", GafferImage.ImagePlug(), True, "view0", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
67-
createViews["views"].addChild( Gaffer.NameValuePlug( "right", GafferImage.ImagePlug(), True, "view1", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
68-
createViews["views"].addChild( Gaffer.NameValuePlug( "default", GafferImage.ImagePlug(), True, "view2", Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
66+
createViews["views"].resize( 3 )
67+
createViews["views"][0]["name"].setValue( "left" )
68+
createViews["views"][1]["name"].setValue( "right" )
69+
createViews["views"][2]["name"].setValue( "default" )
6970

7071
createViews["views"]["view0"]["value"].setInput( reader["out"] )
7172
createViews["views"]["view1"]["value"].setInput( constant1["out"] )

python/GafferImageTest/FormatQueryTest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ def testView( self ) :
9999
reader["fileName"].setValue( self.imagesPath() / "checkerboard.100x100.exr" )
100100

101101
views = GafferImage.CreateViews()
102-
views["views"].addChild( Gaffer.NameValuePlug( "left", GafferImage.ImagePlug(), True ) )
103-
views["views"].addChild( Gaffer.NameValuePlug( "right", GafferImage.ImagePlug(), True ) )
102+
views["views"].resize( 2 )
103+
views["views"][0]["name"].setValue( "left" )
104+
views["views"][1]["name"].setValue( "right" )
104105
views["views"][0]["value"].setInput( constantSource["out"] )
105106
views["views"][1]["value"].setInput( reader["out"] )
106107

0 commit comments

Comments
 (0)