From 11aa7cfdc3f69c3c94c540445745ac94779678df Mon Sep 17 00:00:00 2001 From: jchan Date: Wed, 22 Mar 2023 07:52:06 +1300 Subject: [PATCH] node/port visibility support #310 --- NodeGraphQt/base/commands.py | 76 +++++++++++++++++++++++++----- NodeGraphQt/base/port.py | 19 ++++---- NodeGraphQt/nodes/base_node.py | 29 ++++++++++++ NodeGraphQt/qgraphics/node_base.py | 6 ++- NodeGraphQt/qgraphics/pipe.py | 15 ++++++ 5 files changed, 119 insertions(+), 26 deletions(-) diff --git a/NodeGraphQt/base/commands.py b/NodeGraphQt/base/commands.py index db282f47..e86d7c3a 100644 --- a/NodeGraphQt/base/commands.py +++ b/NodeGraphQt/base/commands.py @@ -22,7 +22,7 @@ def __init__(self, node, name, value): self.old_val = node.get_property(name) self.new_val = value - def set_node_prop(self, name, value): + def set_node_property(self, name, value): """ updates the node view and model. """ @@ -47,21 +47,60 @@ def set_node_prop(self, name, value): name = 'xy_pos' setattr(view, name, value) + # emit property changed signal. + graph = self.node.graph + graph.property_changed.emit(self.node, self.name, value) + def undo(self): if self.old_val != self.new_val: - self.set_node_prop(self.name, self.old_val) - - # emit property changed signal. - graph = self.node.graph - graph.property_changed.emit(self.node, self.name, self.old_val) + self.set_node_property(self.name, self.old_val) def redo(self): if self.old_val != self.new_val: - self.set_node_prop(self.name, self.new_val) + self.set_node_property(self.name, self.new_val) - # emit property changed signal. - graph = self.node.graph - graph.property_changed.emit(self.node, self.name, self.new_val) + +class NodeVisibleCmd(QtWidgets.QUndoCommand): + """ + Node visibility changed command. + + Args: + node (NodeGraphQt.NodeObject): node. + visible (bool): node visible value. + """ + + def __init__(self, node, visible): + QtWidgets.QUndoCommand.__init__(self) + self.node = node + self.visible = visible + self.selected = self.node.selected() + + def set_node_visible(self, visible): + model = self.node.model + model.set_property('visible', visible) + + node_view = self.node.view + node_view.setVisible(visible) + + # redraw the connected pipes in the scene. + ports = node_view.inputs + node_view.outputs + for port in ports: + for pipe in port.connected_pipes: + pipe.update() + + # restore the node selected state. + if self.selected != node_view.isSelected(): + node_view.setSelected(model.selected) + + # emit property changed signal. + graph = self.node.graph + graph.property_changed.emit(self.node, 'visible', visible) + + def undo(self): + self.set_node_visible(not self.visible) + + def redo(self): + self.set_node_visible(self.visible) class NodeMovedCmd(QtWidgets.QUndoCommand): @@ -347,10 +386,14 @@ class PortVisibleCmd(QtWidgets.QUndoCommand): port (NodeGraphQt.Port): node port. """ - def __init__(self, port): + def __init__(self, port, visible): QtWidgets.QUndoCommand.__init__(self) self.port = port - self.visible = port.visible() + self.visible = visible + if visible: + self.setText('show port {}'.format(self.port.name())) + else: + self.setText('hide port {}'.format(self.port.name())) def set_visible(self, visible): self.port.model.visible = visible @@ -363,7 +406,14 @@ def set_visible(self, visible): text_item = node_view.get_output_text_item(self.port.view) if text_item: text_item.setVisible(visible) - node_view.post_init() + + node_view.draw_node() + + # redraw the connected pipes in the scene. + ports = node_view.inputs + node_view.outputs + for port in node_view.inputs + node_view.outputs: + for pipe in port.connected_pipes: + pipe.update() def undo(self): self.set_visible(not self.visible) diff --git a/NodeGraphQt/base/port.py b/NodeGraphQt/base/port.py index 15896b5a..1623ab8e 100644 --- a/NodeGraphQt/base/port.py +++ b/NodeGraphQt/base/port.py @@ -107,23 +107,20 @@ def visible(self): """ return self.model.visible - def set_visible(self, visible=True): + def set_visible(self, visible=True, push_undo=True): """ Sets weather the port should be visible or not. Args: visible (bool): true if visible. + push_undo (bool): register the command to the undo stack. (default: True) """ - self.model.visible = visible - label = 'show' if visible else 'hide' - undo_stack = self.node().graph.undo_stack() - undo_stack.beginMacro('{} port {}'.format(label, self.name())) - - for port in self.connected_ports(): - undo_stack.push(PortDisconnectedCmd(self, port)) - - undo_stack.push(PortVisibleCmd(self)) - undo_stack.endMacro() + undo_cmd = PortVisibleCmd(self, visible) + if push_undo: + undo_stack = self.node().graph.undo_stack() + undo_stack.push(undo_cmd) + else: + undo_cmd.redo() def locked(self): """ diff --git a/NodeGraphQt/nodes/base_node.py b/NodeGraphQt/nodes/base_node.py index c5d29357..c932153b 100644 --- a/NodeGraphQt/nodes/base_node.py +++ b/NodeGraphQt/nodes/base_node.py @@ -1,6 +1,7 @@ #!/usr/bin/python from collections import OrderedDict +from NodeGraphQt.base.commands import NodeVisibleCmd from NodeGraphQt.base.node import NodeObject from NodeGraphQt.base.port import Port from NodeGraphQt.constants import NodePropWidgetEnum, PortTypeEnum @@ -68,6 +69,34 @@ def update_model(self): for name, widget in self.view.widgets.items(): self.model.set_property(name, widget.get_value()) + def set_property(self, name, value, push_undo=True): + """ + Set the value on the node custom property. + + Note: + When setting the `"visible"` property to `False` all node + connections will be disconnected. + + Args: + name (str): name of the property. + value (object): property data (python built in types). + push_undo (bool): register the command to the undo stack. (default: True) + """ + # prevent signals from causing a infinite loop. + if self.get_property(name) == value: + return + + if name == 'visible': + if self.graph: + undo_cmd = NodeVisibleCmd(self, value) + if push_undo: + undo_stack = self.graph.undo_stack() + undo_stack.push(undo_cmd) + else: + undo_cmd.redo() + return + super(BaseNode, self).set_property(name, value, push_undo) + def set_layout_direction(self, value=0): """ Sets the node layout direction to either horizontal or vertical on diff --git a/NodeGraphQt/qgraphics/node_base.py b/NodeGraphQt/qgraphics/node_base.py index c09c5082..9886f67f 100644 --- a/NodeGraphQt/qgraphics/node_base.py +++ b/NodeGraphQt/qgraphics/node_base.py @@ -640,9 +640,11 @@ def _draw_node_horizontal(self): # update port text items in visibility. for port, text in self._input_items.items(): - text.setVisible(port.display_name) + if port.isVisible(): + text.setVisible(port.display_name) for port, text in self._output_items.items(): - text.setVisible(port.display_name) + if port.isVisible(): + text.setVisible(port.display_name) # setup initial base size. self._set_base_size(add_h=height) diff --git a/NodeGraphQt/qgraphics/pipe.py b/NodeGraphQt/qgraphics/pipe.py index 2795210b..ec5e7b48 100644 --- a/NodeGraphQt/qgraphics/pipe.py +++ b/NodeGraphQt/qgraphics/pipe.py @@ -73,6 +73,21 @@ def paint(self, painter, option, widget): used to describe the parameters needed to draw. widget (QtWidgets.QWidget): not used. """ + + # only draw if a port or node is visible. + is_visible = all([ + self._input_port.isVisible(), + self._output_port.isVisible(), + self._input_port.node.isVisible(), + self._output_port.node.isVisible() + ]) + if not is_visible: + painter.save() + painter.setBrush(QtCore.Qt.NoBrush) + painter.setPen(QtCore.Qt.NoPen) + painter.restore() + return + color = QtGui.QColor(*self._color) pen_style = PIPE_STYLES.get(self.style) pen_width = PipeEnum.WIDTH.value