From 468dd1b20d2cf00babf3c3904344d4dccda8ea5a Mon Sep 17 00:00:00 2001 From: Paul-George Roberts Date: Tue, 12 Nov 2024 10:27:28 -0500 Subject: [PATCH] Visualisers : Contribute UI --- .../visualisers/CsVisualiseOrientToolUI.py | 191 ++++++++++++++++ contrib/visualisers/CsVisualiseValueToolUI.py | 195 +++++++++++++++++ .../visualisers/CsVisualiseVectorToolUI.py | 203 ++++++++++++++++++ .../visualisers/CsVisualiseVertexIdToolUI.py | 179 +++++++++++++++ 4 files changed, 768 insertions(+) create mode 100644 contrib/visualisers/CsVisualiseOrientToolUI.py create mode 100644 contrib/visualisers/CsVisualiseValueToolUI.py create mode 100644 contrib/visualisers/CsVisualiseVectorToolUI.py create mode 100644 contrib/visualisers/CsVisualiseVertexIdToolUI.py diff --git a/contrib/visualisers/CsVisualiseOrientToolUI.py b/contrib/visualisers/CsVisualiseOrientToolUI.py new file mode 100644 index 00000000000..61c8a0ff2a4 --- /dev/null +++ b/contrib/visualisers/CsVisualiseOrientToolUI.py @@ -0,0 +1,191 @@ +########################################################################## +# +# 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. +# +########################################################################## + +import Gaffer +import GafferUI + +from csgaffer.nodes import CsVisualiseOrientTool + +if CsVisualiseOrientTool is not None: + Gaffer.Metadata.registerNode( + CsVisualiseOrientTool, + "description", + """ + Tool for displaying named primitive variables of type Quatf as coordinate frame. + + Use keys (+/-) to change the scale of the displayed coordinate frame. + """, + "viewer:shortCut", + "O", + "viewer:shouldAutoActivate", + False, + "order", + 1003, + "tool:exclusive", + False, + "layout:activator:activatorFalse", + lambda node: False, + plugs={ + "active": ( + "boolPlugValueWidget:image", + "node_icons/tools/visualise_orient_data.png", + "layout:visibilityActivator", + "activatorFalse", + ), + "name": ( + "description", + """ + Specifies the name of the primitive variable to visualise. The data should + be of type Imath::Quatf. + """, + "layout:index", + 0, + "layout:section", + "Settings", + "label", + "Name", + ), + "scale": ( + "description", + """ + Scale factor applied to the orientation data visualisation. + """, + "layout:index", + 1, + "layout:section", + "Settings", + "label", + "Scale", + ), + "colourX": ( + "description", + """ + Colour applied to the orientation X axis visualisation. + """, + "layout:index", + 2, + "layout:section", + "Settings", + "label", + "Colour X", + ), + "colourY": ( + "description", + """ + Colour applied to the orientation Y axis visualisation. + """, + "layout:index", + 3, + "layout:section", + "Settings", + "label", + "Colour Y", + ), + "colourZ": ( + "description", + """ + Colour applied to the orientation Z axis visualisation. + """, + "layout:index", + 4, + "layout:section", + "Settings", + "label", + "Colour Z", + ), + }, + ) + + class _SettingsNodeUI(GafferUI.NodeUI): + def __init__(self, node, **kw): + self.__mainColumn = GafferUI.ListContainer( + GafferUI.ListContainer.Orientation.Vertical, spacing=4, borderWidth=4 + ) + + GafferUI.NodeUI.__init__(self, node, self.__mainColumn, **kw) + + with self.__mainColumn: + self.__plugLayout = GafferUI.PlugLayout(node, rootSection="Settings") + + def plugValueWidget(self, plug): + hierarchy = [] + while not plug.isSame(self.node()): + hierarchy.insert(0, plug) + plug = plug.parent() + + widget = self.__plugLayout.plugValueWidget(hierarchy[0]) + if widget is None: + return None + + for i in range(1, len(hierarchy)): + widget = widget.childPlugValueWidget(hierarchy[i]) + if widget is None: + return None + + return widget + + def setReadOnly(self, readOnly): + if readOnly == Gaffer.MetadataAlgo.getReadOnly(self.node()): + return + + Gaffer.NodeUI.setReadOnly(self, readOnly) + + self.__plugLayout.setReadOnly(readOnly) + + def __launchToolSettings(node, plugValueWidget): + w = GafferUI.Window(sizeMode=GafferUI.Window.SizeMode.Automatic) + w.setTitle("Tool Settings (%s)" % (CsVisualiseOrientTool.staticTypeName())) + w.setChild(GafferUI.NodeUI.create(node)) + plugValueWidget.ancestor(GafferUI.Window).addChildWindow(w, removeOnClose=True) + w.setVisible(True) + + def __plugPopupMenu(menuDefinition, plugValueWidget): + try: + plug = plugValueWidget.getPlug() + except: + pass + else: + node = plug.node() + if plug.getName() == "active" and isinstance(node, CsVisualiseOrientTool): + import functools + + menuDefinition.append("/Tool Settings Divider", {"divider": True}) + menuDefinition.append( + "/Tool Settings", {"command": functools.partial(__launchToolSettings, node, plugValueWidget)} + ) + + GafferUI.NodeUI.registerNodeUI(CsVisualiseOrientTool, _SettingsNodeUI) + GafferUI.PlugValueWidget.popupMenuSignal().connect(__plugPopupMenu, scoped=False) diff --git a/contrib/visualisers/CsVisualiseValueToolUI.py b/contrib/visualisers/CsVisualiseValueToolUI.py new file mode 100644 index 00000000000..e289dc37d30 --- /dev/null +++ b/contrib/visualisers/CsVisualiseValueToolUI.py @@ -0,0 +1,195 @@ +########################################################################## +# +# 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. +# +########################################################################## + +import Gaffer +import GafferUI + +from csgaffer.nodes import CsVisualiseValueTool + +if CsVisualiseValueTool is not None: + Gaffer.Metadata.registerNode( + CsVisualiseValueTool, + "description", + """ + Tool for displaying named primitive variables of type float, V2f or V3f as a coloured overlay. + """, + "viewer:shortCut", + "S", + "viewer:shouldAutoActivate", + False, + "order", + 1001, + "tool:exclusive", + False, + "layout:activator:activatorFalse", + lambda node: False, + plugs={ + "active": ( + "boolPlugValueWidget:image", + "node_icons/tools/visualise_value_data.png", + "layout:visibilityActivator", + "activatorFalse", + ), + "name": ( + "description", + """ + Specifies the name of the primitive variable to visualise. The data should + be of type float, V2f or V3f. + """, + "layout:index", + 0, + "layout:section", + "Settings", + "label", + "Name", + ), + "valueMin": ( + "description", + """ + The minimum data channel value that will be mapped to 0. + + For float data only the first channel is used. For V2f data only the first + and second channels are used. For V3f data all three channels are used. + """, + "layout:index", + 1, + "layout:section", + "Settings", + "label", + "Min Value", + ), + "valueMax": ( + "description", + """ + The maximum data channel value that will be mapped to 1. + + For float data only the first channel is used. For V2f data only the first + and second channels are used. For V3f data all three channels are used. + """, + "layout:index", + 2, + "layout:section", + "Settings", + "label", + "Max Value", + ), + "size": ( + "description", + """ + Specifies the size of the displayed text. + """, + "layout:index", + 3, + "layout:section", + "Settings", + "label", + "Size", + ), + "colour": ( + "description", + """ + Specifies the colour of the displayed text. + """, + "layout:index", + 4, + "layout:section", + "Settings", + "label", + "Colour", + ), + }, + ) + + class _SettingsNodeUI(GafferUI.NodeUI): + def __init__(self, node, **kw): + self.__mainColumn = GafferUI.ListContainer( + GafferUI.ListContainer.Orientation.Vertical, spacing=4, borderWidth=4 + ) + + GafferUI.NodeUI.__init__(self, node, self.__mainColumn, **kw) + + with self.__mainColumn: + self.__plugLayout = GafferUI.PlugLayout(node, rootSection="Settings") + + def plugValueWidget(self, plug): + hierarchy = [] + while not plug.isSame(self.node()): + hierarchy.insert(0, plug) + plug = plug.parent() + + widget = self.__plugLayout.plugValueWidget(hierarchy[0]) + if widget is None: + return None + + for i in range(1, len(hierarchy)): + widget = widget.childPlugValueWidget(hierarchy[i]) + if widget is None: + return None + + return widget + + def setReadOnly(self, readOnly): + if readOnly == Gaffer.MetadataAlgo.getReadOnly(self.node()): + return + + Gaffer.NodeUI.setReadOnly(self, readOnly) + + self.__plugLayout.setReadOnly(readOnly) + + def __launchToolSettings(node, plugValueWidget): + w = GafferUI.Window(sizeMode=GafferUI.Window.SizeMode.Automatic) + w.setTitle("Tool Settings (%s)" % (CsVisualiseValueTool.staticTypeName())) + w.setChild(GafferUI.NodeUI.create(node)) + plugValueWidget.ancestor(GafferUI.Window).addChildWindow(w, removeOnClose=True) + w.setVisible(True) + + def __plugPopupMenu(menuDefinition, plugValueWidget): + try: + plug = plugValueWidget.getPlug() + except: + pass + else: + node = plug.node() + if plug.getName() == "active" and isinstance(node, CsVisualiseValueTool): + import functools + + menuDefinition.append("/Tool Settings Divider", {"divider": True}) + menuDefinition.append( + "/Tool Settings", {"command": functools.partial(__launchToolSettings, node, plugValueWidget)} + ) + + GafferUI.NodeUI.registerNodeUI(CsVisualiseValueTool, _SettingsNodeUI) + GafferUI.PlugValueWidget.popupMenuSignal().connect(__plugPopupMenu, scoped=False) diff --git a/contrib/visualisers/CsVisualiseVectorToolUI.py b/contrib/visualisers/CsVisualiseVectorToolUI.py new file mode 100644 index 00000000000..027c4488c7d --- /dev/null +++ b/contrib/visualisers/CsVisualiseVectorToolUI.py @@ -0,0 +1,203 @@ +########################################################################## +# +# 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. +# +########################################################################## + +import Gaffer +import GafferUI + +from csgaffer.nodes import CsVisualiseVectorTool + +if CsVisualiseVectorTool is not None: + Gaffer.Metadata.registerNode( + CsVisualiseVectorTool, + "description", + """ + Tool for displaying named primitive variables of type V3f as line vectors. + + Use keys (+/-) to change the scale of the displayed line vectors. + """, + "viewer:shortCut", + "V", + "viewer:shouldAutoActivate", + False, + "order", + 1002, + "tool:exclusive", + False, + "layout:activator:activatorFalse", + lambda node: False, + "layout:activator:activatorScale", + lambda node: node["format"].getValue() != CsVisualiseVectorTool.Format.Point, + plugs={ + "active": ( + "boolPlugValueWidget:image", + "node_icons/tools/visualise_vector_data.png", + "layout:visibilityActivator", + "activatorFalse", + ), + "name": ( + "description", + """ + Specifies the name of the primitive variable to visualise. The data should + be of type Imath::V3f. + """, + "layout:index", + 0, + "layout:section", + "Settings", + "label", + "Name", + ), + "format": ( + "description", + """ + Format of data : + + Point - Interpret data as points. + + Vector - Interpret data as vectors. + + Bivector - Interpret data as bivectors (e.g. surface normals) so they remain + orthogonal to the plane containing the vectors whose cross product + they are the result of, under all affine transformations. + """, + "preset:Point", + CsVisualiseVectorTool.Format.Point, + "preset:Vector", + CsVisualiseVectorTool.Format.Vector, + "preset:Bivector", + CsVisualiseVectorTool.Format.Bivector, + "plugValueWidget:type", + "GafferUI.PresetsPlugValueWidget", + "layout:index", + 0, + "layout:accessory", + True, + "layout:width", + 100, + "layout:section", + "Settings", + "label", + "Format", + ), + "scale": ( + "description", + """ + Scale factor applied to the vector data visualisation. + """, + "layout:index", + 1, + "layout:section", + "Settings", + "layout:activator", + "activatorScale", + "label", + "Scale", + ), + "colour": ( + "description", + """ + Colour applied to the vector data visualisation. + """, + "layout:index", + 2, + "layout:section", + "Settings", + "label", + "Colour", + ), + }, + ) + + class _SettingsNodeUI(GafferUI.NodeUI): + def __init__(self, node, **kw): + self.__mainColumn = GafferUI.ListContainer( + GafferUI.ListContainer.Orientation.Vertical, spacing=4, borderWidth=4 + ) + + GafferUI.NodeUI.__init__(self, node, self.__mainColumn, **kw) + + with self.__mainColumn: + self.__plugLayout = GafferUI.PlugLayout(node, rootSection="Settings") + + def plugValueWidget(self, plug): + hierarchy = [] + while not plug.isSame(self.node()): + hierarchy.insert(0, plug) + plug = plug.parent() + + widget = self.__plugLayout.plugValueWidget(hierarchy[0]) + if widget is None: + return None + + for i in range(1, len(hierarchy)): + widget = widget.childPlugValueWidget(hierarchy[i]) + if widget is None: + return None + + return widget + + def setReadOnly(self, readOnly): + if readOnly == Gaffer.MetadataAlgo.getReadOnly(self.node()): + return + + Gaffer.NodeUI.setReadOnly(self, readOnly) + + self.__plugLayout.setReadOnly(readOnly) + + def __launchToolSettings(node, plugValueWidget): + w = GafferUI.Window(sizeMode=GafferUI.Window.SizeMode.Automatic) + w.setTitle("Tool Settings (%s)" % (CsVisualiseVectorTool.staticTypeName())) + w.setChild(GafferUI.NodeUI.create(node)) + plugValueWidget.ancestor(GafferUI.Window).addChildWindow(w, removeOnClose=True) + w.setVisible(True) + + def __plugPopupMenu(menuDefinition, plugValueWidget): + try: + plug = plugValueWidget.getPlug() + except: + pass + else: + node = plug.node() + if plug.getName() == "active" and isinstance(node, CsVisualiseVectorTool): + import functools + + menuDefinition.append("/Tool Settings Divider", {"divider": True}) + menuDefinition.append( + "/Tool Settings", {"command": functools.partial(__launchToolSettings, node, plugValueWidget)} + ) + + GafferUI.NodeUI.registerNodeUI(CsVisualiseVectorTool, _SettingsNodeUI) + GafferUI.PlugValueWidget.popupMenuSignal().connect(__plugPopupMenu, scoped=False) diff --git a/contrib/visualisers/CsVisualiseVertexIdToolUI.py b/contrib/visualisers/CsVisualiseVertexIdToolUI.py new file mode 100644 index 00000000000..7783882f99f --- /dev/null +++ b/contrib/visualisers/CsVisualiseVertexIdToolUI.py @@ -0,0 +1,179 @@ +########################################################################## +# +# 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. +# +########################################################################## + +import Gaffer +import GafferUI + +from csgaffer.nodes import CsVisualiseVertexIdTool + +if CsVisualiseVertexIdTool is not None: + Gaffer.Metadata.registerNode( + CsVisualiseVertexIdTool, + "description", + """ + Tool for displaying the vertex ids of a primitive with a "P" primitive variable. + + Use keys (+/-) to change the size of the displayed text. + """, + "viewer:shortCut", + "U", + "viewer:shouldAutoActivate", + False, + "order", + 1004, + "tool:exclusive", + False, + "layout:activator:activatorFalse", + lambda node: False, + plugs={ + "active": ( + "boolPlugValueWidget:image", + "node_icons/tools/visualise_vertex_ids.png", + "layout:visibilityActivator", + "activatorFalse", + ), + "size": ( + "description", + """ + Specifies the size of the displayed text labels. + """, + "layout:index", + 0, + "layout:section", + "Settings", + "label", + "Text Size", + ), + "colour": ( + "description", + """ + Specifies the colour of the displayed text labels. + """, + "layout:index", + 1, + "layout:section", + "Settings", + "label", + "Text Colour", + ), + "cursorColour": ( + "description", + """ + Specifies the colour of the displayed cursor text label. + """, + "layout:index", + 2, + "layout:section", + "Settings", + "label", + "Cursor Text Colour", + ), + "cursorRadius": ( + "description", + """ + Specifies the search radius distance used to find the nearest vertex id to the cursor. + Set to zero to disable cursor vertex id search. + """, + "layout:index", + 3, + "layout:section", + "Settings", + "label", + "Cursor Search Radius", + ), + }, + ) + + class _SettingsNodeUI(GafferUI.NodeUI): + def __init__(self, node, **kw): + self.__mainColumn = GafferUI.ListContainer( + GafferUI.ListContainer.Orientation.Vertical, spacing=4, borderWidth=4 + ) + + GafferUI.NodeUI.__init__(self, node, self.__mainColumn, **kw) + + with self.__mainColumn: + self.__plugLayout = GafferUI.PlugLayout(node, rootSection="Settings") + + def plugValueWidget(self, plug): + hierarchy = [] + while not plug.isSame(self.node()): + hierarchy.insert(0, plug) + plug = plug.parent() + + widget = self.__plugLayout.plugValueWidget(hierarchy[0]) + if widget is None: + return None + + for i in range(1, len(hierarchy)): + widget = widget.childPlugValueWidget(hierarchy[i]) + if widget is None: + return None + + return widget + + def setReadOnly(self, readOnly): + if readOnly == Gaffer.MetadataAlgo.getReadOnly(self.node()): + return + + Gaffer.NodeUI.setReadOnly(readOnly) + + self.__plugLayout.setReadOnly(readOnly) + + def __launchToolSettings(node, plugValueWidget): + w = GafferUI.Window(sizeMode=GafferUI.Window.SizeMode.Automatic) + w.setTitle("Tool Settings (%s)" % (CsVisualiseVertexIdTool.staticTypeName())) + w.setChild(GafferUI.NodeUI.create(node)) + plugValueWidget.ancestor(GafferUI.Window).addChildWindow(w, removeOnClose=True) + w.setVisible(True) + + def __plugPopupMenu(menuDefinition, plugValueWidget): + try: + plug = plugValueWidget.getPlug() + except: + pass + else: + node = plug.node() + if plug.getName() == "active" and isinstance(node, CsVisualiseVertexIdTool): + import functools + + menuDefinition.append("/Tool Settings Divider", {"divider": True}) + menuDefinition.append( + "/Tool Settings", {"command": functools.partial(__launchToolSettings, node, plugValueWidget)} + ) + + GafferUI.NodeUI.registerNodeUI(CsVisualiseVertexIdTool, _SettingsNodeUI) + GafferUI.PlugValueWidget.popupMenuSignal().connect(__plugPopupMenu, scoped=False)