From 2907ff695e77e9a9d9ae9b120e1a33332ad86b9f Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:07:03 +0100 Subject: [PATCH 01/10] add missing ] in doku --- NodeGraphQt/base/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index 22d5f202..a09ee0ba 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -431,7 +431,7 @@ def _on_connection_changed(self, disconnected, connected): called when a pipe connection has been changed in the viewer. Args: - disconnected (list[list[widgets.port.PortItem]): + disconnected (list[list[widgets.port.PortItem]]): pair list of port view items. connected (list[list[widgets.port.PortItem]]): pair list of port view items. From 135dc1b0fbb74f3a95d25fac75aefab8b58a380e Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:08:23 +0100 Subject: [PATCH 02/10] fix doku pos is not a list, its a tuple --- NodeGraphQt/base/graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index a09ee0ba..88dafcc2 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -357,7 +357,7 @@ def _on_node_data_dropped(self, mimedata, pos): node_ids = sorted(re.findall(r'node:([\w\.]+)', search_str)) x, y = pos.x(), pos.y() for node_id in node_ids: - self.create_node(node_id, pos=[x, y]) + self.create_node(node_id, pos=(x, y)) x += 80 y += 80 elif mimedata.hasFormat('text/uri-list'): @@ -422,7 +422,7 @@ def _on_search_triggered(self, node_type, pos): Args: node_type (str): node identifier. - pos (tuple or list): x, y position for the node. + pos (tuple[int, int]): x, y position for the node. """ self.create_node(node_type, pos=pos) @@ -1200,7 +1200,7 @@ def create_node(self, node_type, name=None, selected=True, color=None, selected (bool): set created node to be selected. color (tuple or str): node color ``(255, 255, 255)`` or ``"#FFFFFF"``. text_color (tuple or str): text color ``(255, 255, 255)`` or ``"#FFFFFF"``. - pos (list[int, int]): initial x, y position for the node (default: ``(0, 0)``). + pos (tuple[int, int]): initial x, y position for the node (default: ``(0, 0)``). push_undo (bool): register the command to the undo stack. (default: True) Returns: From 578304c5b1d2787eb41b3e6516c7308d0e9cfebd Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:37:50 +0100 Subject: [PATCH 03/10] fix examples to tuples --- docs/examples/ex_menu.rst | 2 +- docs/examples/ex_node.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/ex_menu.rst b/docs/examples/ex_menu.rst index bea0ea05..3673944d 100644 --- a/docs/examples/ex_menu.rst +++ b/docs/examples/ex_menu.rst @@ -100,7 +100,7 @@ can override context menus on a per node type basis. # create some nodes. foo_node = graph.create_node('io.github.jchanvfx.FooNode') - bar_node = graph.create_node('io.github.jchanvfx', pos=[300, 100]) + bar_node = graph.create_node('io.github.jchanvfx', pos=(300, 100)) # show widget. node_graph.widget.show() diff --git a/docs/examples/ex_node.rst b/docs/examples/ex_node.rst index c363fc73..0b97f2c4 100644 --- a/docs/examples/ex_node.rst +++ b/docs/examples/ex_node.rst @@ -35,7 +35,7 @@ Creating Nodes # here we create a couple nodes in the node graph. node_a = node_graph.create_node('io.github.jchanvfx.MyNode', name='node a') - node_b = node_graph.create_node('io.github.jchanvfx.MyNode', name='node b', pos=[300, 100]) + node_b = node_graph.create_node('io.github.jchanvfx.MyNode', name='node b', pos=(300, 100)) app.exec_() From 4e1c937eed523b1914d5a44806fd4746d77577fb Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 14:42:07 +0100 Subject: [PATCH 04/10] feat (Model): add PortDatatypeModel --- NodeGraphQt/base/model.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/NodeGraphQt/base/model.py b/NodeGraphQt/base/model.py index e5896324..f79c4d32 100644 --- a/NodeGraphQt/base/model.py +++ b/NodeGraphQt/base/model.py @@ -10,6 +10,44 @@ from NodeGraphQt.errors import NodePropertyError +class PortDatatypeModel(object): + """ + Data dump for a port datatype object. + """ + + def __init__(self, name="", color=None, painter_func=None): + self._name = name + self._color = color + self._painter_func = painter_func + + @property + def name(self): + """Name of the datatype. + + Returns: + str: name of the Datatype. + """ + return self._name + + @property + def color(self): + """Color of the datatype to override the default color. + + Returns: + tuple: RGB color tuple. + """ + return self._color + + @property + def painter_func(self): + """Painter function for the datatype to override the default painter. + + Returns: + callable: custom painter function. + """ + return self._painter_func + + class PortModel(object): """ Data dump for a port object. From 68c2494ae066e474c3f21215d240bae0225ff562 Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 14:45:54 +0100 Subject: [PATCH 05/10] feat (Model): add PortDatatypeModel to PortModel --- NodeGraphQt/base/model.py | 3 ++- NodeGraphQt/base/port.py | 5 +++-- NodeGraphQt/nodes/base_node.py | 18 ++++++++++++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/NodeGraphQt/base/model.py b/NodeGraphQt/base/model.py index f79c4d32..d77fb9be 100644 --- a/NodeGraphQt/base/model.py +++ b/NodeGraphQt/base/model.py @@ -53,9 +53,10 @@ class PortModel(object): Data dump for a port object. """ - def __init__(self, node): + def __init__(self, node, data_type=None): self.node = node self.type_ = '' + self.data_type = data_type self.name = 'port' self.display_name = True self.multi_connection = False diff --git a/NodeGraphQt/base/port.py b/NodeGraphQt/base/port.py index d38820a6..b8030549 100644 --- a/NodeGraphQt/base/port.py +++ b/NodeGraphQt/base/port.py @@ -29,11 +29,12 @@ class Port(object): Args: node (NodeGraphQt.NodeObject): parent node. port (PortItem): graphic item used for drawing. + data_type (PortDatatypeModel): data type of the port. """ - def __init__(self, node, port): + def __init__(self, node, port, data_type=None): self.__view = port - self.__model = PortModel(node) + self.__model = PortModel(node,data_type) def __repr__(self): port = str(self.__class__.__name__) diff --git a/NodeGraphQt/nodes/base_node.py b/NodeGraphQt/nodes/base_node.py index d9b1f2ca..77ba7190 100644 --- a/NodeGraphQt/nodes/base_node.py +++ b/NodeGraphQt/nodes/base_node.py @@ -375,7 +375,7 @@ def show_widget(self, name, push_undo=True): undo_cmd.redo() def add_input(self, name='input', multi_input=False, display_name=True, - color=None, locked=False, painter_func=None): + color=None, locked=False, painter_func=None, data_type=None): """ Add input :class:`Port` to node. @@ -390,6 +390,7 @@ def add_input(self, name='input', multi_input=False, display_name=True, locked (bool): locked state see :meth:`Port.set_locked` painter_func (function or None): custom function to override the drawing of the port shape see example: :ref:`Creating Custom Shapes` + data_type (PortDatatypeModel): data type for the port. Returns: NodeGraphQt.Port: the created port object. @@ -401,13 +402,17 @@ def add_input(self, name='input', multi_input=False, display_name=True, port_args = [name, multi_input, display_name, locked] if painter_func and callable(painter_func): port_args.append(painter_func) + elif data_type and data_type.painter_func: + port_args.append(data_type.painter_func) view = self.view.add_input(*port_args) if color: view.color = color view.border_color = [min([255, max([0, i + 80])]) for i in color] + elif data_type and data_type.color: + view.color = data_type.color - port = Port(self, view) + port = Port(self, view, data_type) port.model.type_ = PortTypeEnum.IN.value port.model.name = name port.model.display_name = display_name @@ -418,7 +423,7 @@ def add_input(self, name='input', multi_input=False, display_name=True, return port def add_output(self, name='output', multi_output=True, display_name=True, - color=None, locked=False, painter_func=None): + color=None, locked=False, painter_func=None, data_type=None): """ Add output :class:`Port` to node. @@ -433,6 +438,7 @@ def add_output(self, name='output', multi_output=True, display_name=True, locked (bool): locked state see :meth:`Port.set_locked` painter_func (function or None): custom function to override the drawing of the port shape see example: :ref:`Creating Custom Shapes` + data_type (PortDatatypeModel): data type for the port. Returns: NodeGraphQt.Port: the created port object. @@ -444,12 +450,16 @@ def add_output(self, name='output', multi_output=True, display_name=True, port_args = [name, multi_output, display_name, locked] if painter_func and callable(painter_func): port_args.append(painter_func) + elif data_type and data_type.painter_func: + port_args.append(data_type.painter_func) view = self.view.add_output(*port_args) if color: view.color = color view.border_color = [min([255, max([0, i + 80])]) for i in color] - port = Port(self, view) + elif data_type and data_type.color: + view.color = data_type.color + port = Port(self, view, data_type) port.model.type_ = PortTypeEnum.OUT.value port.model.name = name port.model.display_name = display_name From aa94fd2d04ffdd9328bd3bbde82dd6e761b5403e Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 14:46:25 +0100 Subject: [PATCH 06/10] feat (Port): ports only connect if they have the same data type --- NodeGraphQt/base/port.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NodeGraphQt/base/port.py b/NodeGraphQt/base/port.py index b8030549..ba038cec 100644 --- a/NodeGraphQt/base/port.py +++ b/NodeGraphQt/base/port.py @@ -233,6 +233,8 @@ def connect_to(self, port=None, push_undo=True, emit_signal=True): 'Can\'t connect port because "{}" is locked.'.format(name)) # validate accept connection. + if self.model.data_type != port.model.data_type: + return node_type = self.node().type_ accepted_types = port.accepted_port_types().get(node_type) if accepted_types: From e42aac1cc710f078cc1c90dc64c5087c963f0bd2 Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 15:04:23 +0100 Subject: [PATCH 07/10] docs (custom ports node): build a custom node with custom PortDatatypeModel --- examples/nodes/custom_ports_node.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/nodes/custom_ports_node.py b/examples/nodes/custom_ports_node.py index 23befb01..b835e225 100644 --- a/examples/nodes/custom_ports_node.py +++ b/examples/nodes/custom_ports_node.py @@ -2,6 +2,7 @@ from Qt import QtCore, QtGui from NodeGraphQt import BaseNode +from NodeGraphQt.base.model import PortDatatypeModel def draw_triangle_port(painter, rect, info): @@ -110,12 +111,14 @@ class CustomPortsNode(BaseNode): # set the initial default node name. NODE_NAME = 'node' + int_port = PortDatatypeModel("int", (200, 10, 0), draw_triangle_port) def __init__(self): super(CustomPortsNode, self).__init__() # create input and output port. self.add_input('in', color=(200, 10, 0)) + self.add_input('triangel_in', data_type=self.int_port) self.add_output('default') self.add_output('square', painter_func=draw_square_port) - self.add_output('triangle', painter_func=draw_triangle_port) + self.add_output('triangle_out', data_type=self.int_port) From 5b71d8625e517e3a3c7a40f5825582dcdf06e0de Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 15:11:22 +0100 Subject: [PATCH 08/10] Revert "fix examples to tuples" This reverts commit 578304c5b1d2787eb41b3e6516c7308d0e9cfebd. --- docs/examples/ex_menu.rst | 2 +- docs/examples/ex_node.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/ex_menu.rst b/docs/examples/ex_menu.rst index 3673944d..bea0ea05 100644 --- a/docs/examples/ex_menu.rst +++ b/docs/examples/ex_menu.rst @@ -100,7 +100,7 @@ can override context menus on a per node type basis. # create some nodes. foo_node = graph.create_node('io.github.jchanvfx.FooNode') - bar_node = graph.create_node('io.github.jchanvfx', pos=(300, 100)) + bar_node = graph.create_node('io.github.jchanvfx', pos=[300, 100]) # show widget. node_graph.widget.show() diff --git a/docs/examples/ex_node.rst b/docs/examples/ex_node.rst index 0b97f2c4..c363fc73 100644 --- a/docs/examples/ex_node.rst +++ b/docs/examples/ex_node.rst @@ -35,7 +35,7 @@ Creating Nodes # here we create a couple nodes in the node graph. node_a = node_graph.create_node('io.github.jchanvfx.MyNode', name='node a') - node_b = node_graph.create_node('io.github.jchanvfx.MyNode', name='node b', pos=(300, 100)) + node_b = node_graph.create_node('io.github.jchanvfx.MyNode', name='node b', pos=[300, 100]) app.exec_() From ec45377d80d36c536c2a22eb39e5d79182f192c4 Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 15:11:41 +0100 Subject: [PATCH 09/10] Revert "fix doku pos is not a list, its a tuple" This reverts commit 135dc1b0fbb74f3a95d25fac75aefab8b58a380e. --- NodeGraphQt/base/graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index 8a8621a1..c81d43d8 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -357,7 +357,7 @@ def _on_node_data_dropped(self, mimedata, pos): node_ids = sorted(re.findall(r'node:([\w\.]+)', search_str)) x, y = pos.x(), pos.y() for node_id in node_ids: - self.create_node(node_id, pos=(x, y)) + self.create_node(node_id, pos=[x, y]) x += 80 y += 80 elif mimedata.hasFormat('text/uri-list'): @@ -422,7 +422,7 @@ def _on_search_triggered(self, node_type, pos): Args: node_type (str): node identifier. - pos (tuple[int, int]): x, y position for the node. + pos (tuple or list): x, y position for the node. """ self.create_node(node_type, pos=pos) @@ -1200,7 +1200,7 @@ def create_node(self, node_type, name=None, selected=True, color=None, selected (bool): set created node to be selected. color (tuple or str): node color ``(255, 255, 255)`` or ``"#FFFFFF"``. text_color (tuple or str): text color ``(255, 255, 255)`` or ``"#FFFFFF"``. - pos (tuple[int, int]): initial x, y position for the node (default: ``(0, 0)``). + pos (list[int, int]): initial x, y position for the node (default: ``(0, 0)``). push_undo (bool): register the command to the undo stack. (default: True) Returns: From 3f9bda3dd08097d73adb82eafb2f7b8afb91aec9 Mon Sep 17 00:00:00 2001 From: CorsCodini <45790567+CorsCodini@users.noreply.github.com> Date: Sat, 27 Dec 2025 15:11:48 +0100 Subject: [PATCH 10/10] Revert "add missing ] in doku" This reverts commit 2907ff695e77e9a9d9ae9b120e1a33332ad86b9f. --- NodeGraphQt/base/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index c81d43d8..67a44d90 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -431,7 +431,7 @@ def _on_connection_changed(self, disconnected, connected): called when a pipe connection has been changed in the viewer. Args: - disconnected (list[list[widgets.port.PortItem]]): + disconnected (list[list[widgets.port.PortItem]): pair list of port view items. connected (list[list[widgets.port.PortItem]]): pair list of port view items.