Skip to content

Commit

Permalink
Merge pull request #5977 from murraystevenson/inspectorColumnPRMain
Browse files Browse the repository at this point in the history
InspectorColumn
  • Loading branch information
johnhaddon authored Aug 7, 2024
2 parents d6d217c + dbf8694 commit aaf1112
Show file tree
Hide file tree
Showing 20 changed files with 688 additions and 378 deletions.
4 changes: 4 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Improvements
- Improved highlighting of active nodes, with more accurate tracking of Loop node iterations.
- Annotation `{plug}` substitutions are now evaluated in a context determined relative to the focus node.
- The strike-through for disabled nodes is now evaluated in a context determined relative to the focus node.
- LightEditor :
- Improved formatting of column headers containing whitespace.
- The "Double-click to toggle" tooltip is no longer displayed while hovering over non-editable cells, and a "Double-click to edit" tooltip is now displayed while hovering over other non-toggleable but editable cells.

Fixes
-----
Expand All @@ -39,6 +42,7 @@ API
- A `DeprecationWarning` is now emitted for any subclasses still implementing the legacy `_updateFromPlug()` or `_updateFromPlugs()` methods. Implement `_updateFromValues()`, `_updateFromMetadata()` and `_updateFromEditable()` instead.
- A `DeprecationWarning` is now emitted by `_plugConnections()`. Use `_blockedUpdateFromValues()` instead.
- NodeGadget, ConnectionGadget : Added `updateFromContextTracker()` virtual methods.
- Path : Added `inspectionContext()` virtual method.

Breaking Changes
----------------
Expand Down
5 changes: 5 additions & 0 deletions include/Gaffer/Path.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#pragma once

#include "Gaffer/Context.h"
#include "Gaffer/Export.h"
#include "Gaffer/Signals.h"
#include "Gaffer/TypeIds.h"
Expand Down Expand Up @@ -190,6 +191,10 @@ class GAFFER_API Path : public IECore::RunTimeTyped
/// made.
virtual const Plug *cancellationSubject() const;

/// May be implemented by Paths to provide a Context useful for inspecting
/// data represented by the Path.
virtual ContextPtr inspectionContext( const IECore::Canceller *canceller = nullptr ) const;

protected :

/// The subclass specific part of children(). This must be implemented
Expand Down
2 changes: 2 additions & 0 deletions include/GafferScene/ScenePath.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class GAFFERSCENE_API ScenePath : public Gaffer::Path

const Gaffer::Plug *cancellationSubject() const override;

Gaffer::ContextPtr inspectionContext( const IECore::Canceller *canceller = nullptr ) const override;

static Gaffer::PathFilterPtr createStandardFilter( const std::vector<std::string> &setNames = std::vector<std::string>(), const std::string &setsLabel = "" );

protected :
Expand Down
86 changes: 86 additions & 0 deletions include/GafferSceneUI/Private/InspectorColumn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2024, Cinesite VFX Ltd. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above
// copyright notice, this list of conditions and the following
// disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided with
// the distribution.
//
// * Neither the name of John Haddon nor the names of
// any other contributors to this software may be used to endorse or
// promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#include "GafferSceneUI/Export.h"
#include "GafferSceneUI/Private/Inspector.h"

#include "GafferUI/PathColumn.h"

#include "Gaffer/Path.h"

using namespace IECore;

namespace GafferSceneUI
{

namespace Private
{

/// Column type which makes use of an Inspector.
class GAFFERSCENEUI_API InspectorColumn : public GafferUI::PathColumn
{

public :

IE_CORE_DECLAREMEMBERPTR( InspectorColumn )

InspectorColumn( GafferSceneUI::Private::InspectorPtr inspector, const std::string &label, const std::string &toolTip = "", PathColumn::SizeMode sizeMode = Default );
InspectorColumn( GafferSceneUI::Private::InspectorPtr inspector, const CellData &headerData, PathColumn::SizeMode sizeMode = Default );

/// Returns the inspector used by this column.
GafferSceneUI::Private::Inspector *inspector() const;

CellData cellData( const Gaffer::Path &path, const IECore::Canceller *canceller ) const override;
CellData headerData( const IECore::Canceller *canceller ) const override;

private :

void inspectorDirtied();

static IECore::ConstStringDataPtr headerValue( const std::string &columnName );

const Private::InspectorPtr m_inspector;
const CellData m_headerData;

};

IE_CORE_DECLAREPTR( InspectorColumn )

} // namespace Private

} // namespace GafferSceneUI
21 changes: 21 additions & 0 deletions python/GafferSceneTest/ScenePathTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,26 @@ def testCancellation( self ) :
with self.assertRaises( IECore.Cancelled ) :
path.isValid( canceller )

def testInspectionContext( self ) :

plane = GafferScene.Plane()
path = GafferScene.ScenePath( plane["out"], Gaffer.Context(), "/plane" )

inspectionContext = path.inspectionContext()
self.assertIsNotNone( inspectionContext )
self.assertIn( "scene:path", inspectionContext )
self.assertEqual( inspectionContext["scene:path"], GafferScene.ScenePlug.stringToPath( "/plane" ) )

context = Gaffer.Context()
context["foo"] = 123
path = GafferScene.ScenePath( plane["out"], context, "/plane/bogus" )

inspectionContext = path.inspectionContext()
self.assertIsNotNone( inspectionContext )
self.assertIn( "scene:path", inspectionContext )
self.assertEqual( inspectionContext["scene:path"], GafferScene.ScenePlug.stringToPath( "/plane/bogus" ) )
self.assertIn( "foo", inspectionContext )
self.assertEqual( inspectionContext["foo"], 123 )

if __name__ == "__main__":
unittest.main()
85 changes: 43 additions & 42 deletions python/GafferSceneUI/LightEditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def registerParameter( cls, rendererKey, parameter, section = None, columnName =
GafferSceneUI.LightEditor.registerColumn(
rendererKey,
".".join( x for x in [ parameter.shader, parameter.name ] if x ),
lambda scene, editScope : _GafferSceneUI._LightEditorInspectorColumn(
lambda scene, editScope : GafferSceneUI.Private.InspectorColumn(
GafferSceneUI.Private.ParameterInspector( scene, editScope, rendererKey, parameter ),
columnName if columnName is not None else ""
),
Expand All @@ -175,7 +175,7 @@ def registerShaderParameter( cls, rendererKey, parameter, shaderAttribute = None
GafferSceneUI.LightEditor.registerColumn(
rendererKey,
".".join( x for x in [ parameter.shader, parameter.name ] if x ),
lambda scene, editScope : _GafferSceneUI._LightEditorInspectorColumn(
lambda scene, editScope : GafferSceneUI.Private.InspectorColumn(
GafferSceneUI.Private.ParameterInspector( scene, editScope, shaderAttribute, parameter ),
columnName if columnName is not None else ""
),
Expand All @@ -189,7 +189,7 @@ def registerAttribute( cls, rendererKey, attributeName, section = None ) :
GafferSceneUI.LightEditor.registerColumn(
rendererKey,
attributeName,
lambda scene, editScope : _GafferSceneUI._LightEditorInspectorColumn(
lambda scene, editScope : GafferSceneUI.Private.InspectorColumn(
GafferSceneUI.Private.AttributeInspector( scene, editScope, attributeName ),
displayName
),
Expand All @@ -199,7 +199,7 @@ def registerAttribute( cls, rendererKey, attributeName, section = None ) :
# Registers a column in the Light Editor.
# `inspectorFunction` is a callable object of the form
# `inspectorFunction( scene, editScope )` returning a
# `GafferSceneUI._LightEditorInspectorColumn` object.
# `GafferSceneUI.Private.InspectorColumn` object.
@classmethod
def registerColumn( cls, rendererKey, columnKey, inspectorFunction, section = None ) :

Expand Down Expand Up @@ -333,19 +333,17 @@ def __editSelectedCells( self, pathListing, quickBoolean = True ) :
inspectors = {}
inspections = []

with Gaffer.Context( self.context() ) as context :

for selection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if not isinstance( column, _GafferSceneUI._LightEditorInspectorColumn ) :
continue
for pathString in selection.paths() :
path = GafferScene.ScenePlug.stringToPath( pathString )

context["scene:path"] = path
path = pathListing.getPath().copy()
for selection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if not isinstance( column, GafferSceneUI.Private.InspectorColumn ) :
continue
for pathString in selection.paths() :
path.setFromString( pathString )
with path.inspectionContext() :
inspection = column.inspector().inspect()

if inspection is not None :
inspectors.setdefault( column.inspector(), {} )[path] = inspection
inspectors.setdefault( column.inspector(), {} )[pathString] = inspection
inspections.append( inspection )

if len( inspectors ) == 0 :
Expand Down Expand Up @@ -439,12 +437,13 @@ def __disablableInspectionTweaks( self, pathListing ) :

tweaks = []

with Gaffer.Context( self.context() ) as context :
for columnSelection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if not isinstance( column, _GafferSceneUI._LightEditorInspectorColumn ) :
continue
for path in columnSelection.paths() :
context["scene:path"] = GafferScene.ScenePlug.stringToPath( path )
path = pathListing.getPath().copy()
for columnSelection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if not isinstance( column, GafferSceneUI.Private.InspectorColumn ) :
continue
for pathString in columnSelection.paths() :
path.setFromString( pathString )
with path.inspectionContext() :
inspection = column.inspector().inspect()
if inspection is not None and inspection.editable() :
source = inspection.source()
Expand All @@ -459,7 +458,7 @@ def __disablableInspectionTweaks( self, pathListing ) :
) and
( editScope is None or editScope.node().isAncestorOf( source ) )
) :
tweaks.append( ( path, column.inspector() ) )
tweaks.append( ( pathString, column.inspector() ) )
else :
return []
else :
Expand All @@ -471,31 +470,33 @@ def __disableEdits( self, pathListing ) :

edits = self.__disablableInspectionTweaks( pathListing )

with Gaffer.UndoScope( self.scriptNode() ), Gaffer.Context( self.context() ) as context :
for path, inspector in edits :
context["scene:path"] = GafferScene.ScenePlug.stringToPath( path )

inspection = inspector.inspect()
if inspection is not None and inspection.editable() :
source = inspection.source()
path = pathListing.getPath().copy()
with Gaffer.UndoScope( self.scriptNode() ) :
for pathString, inspector in edits :
path.setFromString( pathString )
with path.inspectionContext() :
inspection = inspector.inspect()
if inspection is not None and inspection.editable() :
source = inspection.source()

if isinstance( source, ( Gaffer.TweakPlug, Gaffer.NameValuePlug ) ) :
source["enabled"].setValue( False )
elif isinstance( inspector, GafferSceneUI.Private.SetMembershipInspector ) :
inspector.editSetMembership( inspection, path, GafferScene.EditScopeAlgo.SetMembership.Unchanged )
if isinstance( source, ( Gaffer.TweakPlug, Gaffer.NameValuePlug ) ) :
source["enabled"].setValue( False )
elif isinstance( inspector, GafferSceneUI.Private.SetMembershipInspector ) :
inspector.editSetMembership( inspection, pathString, GafferScene.EditScopeAlgo.SetMembership.Unchanged )

def __removableAttributeInspections( self, pathListing ) :

inspections = []

with Gaffer.Context( self.context() ) as context :
for columnSelection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if not isinstance( column, _GafferSceneUI._LightEditorInspectorColumn ) :
continue
elif not columnSelection.isEmpty() and type( column.inspector() ) != GafferSceneUI.Private.AttributeInspector :
return []
for path in columnSelection.paths() :
context["scene:path"] = GafferScene.ScenePlug.stringToPath( path )
path = pathListing.getPath().copy()
for columnSelection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if not isinstance( column, GafferSceneUI.Private.InspectorColumn ) :
continue
elif not columnSelection.isEmpty() and type( column.inspector() ) != GafferSceneUI.Private.AttributeInspector :
return []
for pathString in columnSelection.paths() :
path.setFromString( pathString )
with path.inspectionContext() :
inspection = column.inspector().inspect()
if inspection is not None and inspection.editable() :
source = inspection.source()
Expand Down Expand Up @@ -533,7 +534,7 @@ def __selectedSetExpressions( self, pathListing ) :
for columnSelection, column in zip( pathListing.getSelection(), pathListing.getColumns() ) :
if (
not columnSelection.isEmpty() and (
not isinstance( column, _GafferSceneUI._LightEditorInspectorColumn ) or
not isinstance( column, GafferSceneUI.Private.InspectorColumn ) or
not (
Gaffer.Metadata.value( "attribute:" + column.inspector().name(), "ui:scene:acceptsSetName" ) or
Gaffer.Metadata.value( "attribute:" + column.inspector().name(), "ui:scene:acceptsSetNames" ) or
Expand Down Expand Up @@ -726,7 +727,7 @@ def __showHistory( self, *unused ) :

for i in range( 0, len( columns ) ) :
column = columns[ i ]
if not isinstance( column, _GafferSceneUI._LightEditorInspectorColumn ) :
if not isinstance( column, GafferSceneUI.Private.InspectorColumn ) :
continue

for path in selection[i].paths() :
Expand Down
Loading

0 comments on commit aaf1112

Please sign in to comment.