Skip to content

Commit b0b4473

Browse files
AttributeQuery : Support inheriting global attributes
1 parent 8e2241c commit b0b4473

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

Changes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Improvements
2929
- PathListingWidget : Improved formatting of Box and Matrix values.
3030
- LocaliseAttributes : Added support for localising global attributes, controlled by the new `includeGlobalAttributes` plug.
3131
- AttributeTweaks : Added support for localising global attributes when `localise` is enabled.
32+
- AttributeQuery : Added support for querying global attributes when `inherit` is enabled.
3233

3334
Fixes
3435
-----
@@ -93,6 +94,7 @@ Breaking Changes
9394
- ContextAlgo : Removed deprecated API. Use ScriptNodeAlgo instead, which has been available from Gaffer 1.4.13.0 onwards.
9495
- ScriptNodeAlgo : Reimplemented using Metadata rather than Context variables for storage. Use the ScriptNodeAlgo API instead of attempting direct access to `ui:*` context variables.
9596
- AttributeTweaks : Tweaks with `localise` enabled and a mode of `CreateIfMissing` will now not create an attribute if it is missing from the scene hierarchy, but exists in the globals.
97+
- AttributeQuery : Queries with `inherit` enabled will now return a result when querying an attribute that does not exist in the scene hierarchy, but does exist in the globals.
9698

9799
Build
98100
-----

python/GafferSceneTest/AttributeQueryTest.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import IECore
4242
import Gaffer
43+
import GafferTest
4344
import GafferScene
4445
import GafferSceneTest
4546

@@ -1337,5 +1338,92 @@ def testQueryDoubleData( self ) :
13371338
self.assertTrue( query["exists"].getValue() )
13381339
self.assertEqual( query["value"].getValue(), 2.5 )
13391340

1341+
def testInheritedGlobalAttribute( self ) :
1342+
1343+
sphere = GafferScene.Sphere()
1344+
1345+
globalAttributes = GafferScene.CustomAttributes()
1346+
globalAttributes["in"].setInput( sphere["out"] )
1347+
globalAttributes["global"].setValue( True )
1348+
globalAttributes["extraAttributes"].setValue( IECore.CompoundObject( { "test" : IECore.DoubleData( 5.0 ) } ) )
1349+
1350+
attributes = GafferScene.CustomAttributes()
1351+
attributes["in"].setInput( globalAttributes["out"] )
1352+
attributes["extraAttributes"].setValue( IECore.CompoundObject( { "test" : IECore.DoubleData( 2.5 ) } ) )
1353+
attributes["enabled"].setValue( False )
1354+
1355+
query = GafferScene.AttributeQuery()
1356+
query.setup( Gaffer.FloatPlug() )
1357+
query["scene"].setInput( attributes["out"] )
1358+
query["location"].setValue( "/sphere" )
1359+
query["attribute"].setValue( "test" )
1360+
1361+
self.assertFalse( query["exists"].getValue() )
1362+
self.assertEqual( query["value"].getValue(), 0.0 )
1363+
1364+
query["inherit"].setValue( True )
1365+
1366+
self.assertTrue( query["exists"].getValue() )
1367+
self.assertEqual( query["value"].getValue(), 5.0 )
1368+
1369+
globalAttributes["extraAttributes"].setValue( IECore.CompoundObject( { "test" : IECore.DoubleData( 10.0 ) } ) )
1370+
1371+
self.assertTrue( query["exists"].getValue() )
1372+
self.assertEqual( query["value"].getValue(), 10.0 )
1373+
1374+
attributes["enabled"].setValue( True )
1375+
1376+
self.assertTrue( query["exists"].getValue() )
1377+
self.assertEqual( query["value"].getValue(), 2.5 )
1378+
1379+
query["inherit"].setValue( False )
1380+
1381+
self.assertTrue( query["exists"].getValue() )
1382+
self.assertEqual( query["value"].getValue(), 2.5 )
1383+
1384+
def testDirtyPropagation( self ) :
1385+
1386+
sphere = GafferScene.Sphere()
1387+
1388+
globalAttributes = GafferScene.StandardAttributes()
1389+
globalAttributes["in"].setInput( sphere["out"] )
1390+
globalAttributes["global"].setValue( True )
1391+
1392+
standardAttributes = GafferScene.StandardAttributes()
1393+
standardAttributes["in"].setInput( globalAttributes["out"] )
1394+
1395+
query = GafferScene.AttributeQuery()
1396+
query.setup( Gaffer.BoolPlug() )
1397+
query["scene"].setInput( standardAttributes["out"] )
1398+
query["location"].setValue( "/sphere" )
1399+
1400+
cs = GafferTest.CapturingSlot( query.plugDirtiedSignal() )
1401+
1402+
standardAttributes["attributes"]["scene:visible"]["enabled"].setValue( True )
1403+
self.assertIn( query["value"], { x[0] for x in cs } )
1404+
1405+
standardAttributes["attributes"]["scene:visible"]["enabled"].setValue( False )
1406+
del cs[:]
1407+
query["default"].setValue( True )
1408+
self.assertIn( query["value"], { x[0] for x in cs } )
1409+
1410+
# modifying the globals with the `inherit` plug disabled
1411+
# should not dirty query["value"]
1412+
del cs[:]
1413+
globalAttributes["attributes"]["scene:visible"]["enabled"].setValue( True )
1414+
self.assertNotIn( query["value"], { x[0] for x in cs } )
1415+
1416+
query["inherit"].setValue( True )
1417+
self.assertIn( query["value"], { x[0] for x in cs } )
1418+
1419+
globalAttributes["attributes"]["scene:visible"]["enabled"].setValue( False )
1420+
del cs[:]
1421+
globalAttributes["attributes"]["scene:visible"]["enabled"].setValue( True )
1422+
self.assertIn( query["value"], { x[0] for x in cs } )
1423+
1424+
del cs[:]
1425+
standardAttributes["attributes"]["scene:visible"]["enabled"].setValue( True )
1426+
self.assertIn( query["value"], { x[0] for x in cs } )
1427+
13401428
if __name__ == "__main__":
13411429
unittest.main()

python/GafferSceneUI/AttributeQueryUI.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ def __updateVisibility( self, *args, **kwargs ) :
132132

133133
"description",
134134
"""
135-
Should inherited attributes or be considered or not.
135+
Should inherited attributes or be considered or not. Attributes are
136+
inherited from ancestors or from the scene globals.
136137
""",
137138

138139
"nodule:type", ""

src/GafferScene/AttributeQuery.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ void AttributeQuery::affects( const Gaffer::Plug* const input, AffectedPlugsCont
259259
( input == locationPlug() ) ||
260260
( input == attributePlug() ) ||
261261
( input == scenePlug()->existsPlug() ) ||
262-
( input == scenePlug()->attributesPlug() ) )
262+
( input == scenePlug()->attributesPlug() ) ||
263+
( input == scenePlug()->globalsPlug() && !inheritPlug()->isSetToDefault() ) )
263264
{
264265
outputs.push_back( internalObjectPlug() );
265266
}
@@ -300,7 +301,7 @@ void AttributeQuery::hash( const Gaffer::ValuePlug* const output, const Gaffer::
300301
if( splug->exists( path ) )
301302
{
302303
h.append( ( inheritPlug()->getValue() )
303-
? splug->fullAttributesHash( path )
304+
? splug->fullAttributesHash( path, /* withGlobalAttributes = */ true )
304305
: splug->attributesHash( path ) );
305306
attributePlug()->hash( h );
306307
}
@@ -347,7 +348,7 @@ void AttributeQuery::compute( Gaffer::ValuePlug* const output, const Gaffer::Con
347348
if( ! name.empty() )
348349
{
349350
const IECore::ConstCompoundObjectPtr cobj = ( inheritPlug()->getValue() )
350-
? boost::static_pointer_cast< const IECore::CompoundObject >( splug->fullAttributes( path ) )
351+
? boost::static_pointer_cast< const IECore::CompoundObject >( splug->fullAttributes( path, /* withGlobalAttributes = */ true ) )
351352
: ( splug->attributes( path ) );
352353
assert( cobj );
353354

0 commit comments

Comments
 (0)