diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py
index 932b8247..913a109e 100644
--- a/NodeGraphQt/base/graph.py
+++ b/NodeGraphQt/base/graph.py
@@ -502,7 +502,7 @@ def close(self):
def viewer(self):
"""
- Returns the view interface used by the node graph.
+ Returns the internal view interface used by the node graph.
Warnings:
Methods in the ``NodeViewer`` are used internally
@@ -572,8 +572,17 @@ def set_grid_mode(self, mode=VIEWER_GRID_LINES):
"""
Set node graph grid mode.
+ Note:
+ By default grid mode is set to "VIEWER_GRID_LINES".
+
+ Node graph background types:
+
+ * :attr:`NodeGraphQt.constants.VIEWER_GRID_NONE`
+ * :attr:`NodeGraphQt.constants.VIEWER_GRID_DOTS`
+ * :attr:`NodeGraphQt.constants.VIEWER_GRID_LINES`
+
Args:
- mode: VIEWER_GRID_LINES/VIEWER_GRID_DOTS/VIEWER_GRID_NONE.
+ mode (int): background styles.
"""
self.scene().grid_mode = mode
self._viewer.force_update()
@@ -734,8 +743,11 @@ def set_pipe_style(self, style=PIPE_LAYOUT_CURVED):
"""
Set node graph pipes to be drawn as straight, curved or angled.
+ .. image:: _images/pipe_layout_types.gif
+ :width: 80%
+
Note:
- By default all pipes are set curved.
+ By default pipe layout is set to "PIPE_LAYOUT_CURVED".
Pipe Layout Styles:
@@ -1239,6 +1251,7 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
Args:
data (dict): node data.
relative_pos (bool): position node relative to the cursor.
+ pos (tuple or list): custom x, y position.
set_parent (bool): set node parent to current node space.
Returns:
@@ -1280,7 +1293,10 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
self.add_node(node, n_data.get('pos'), unique_name=set_parent)
if n_data.get('dynamic_port', None):
- node.set_ports({'input_ports': n_data['input_ports'], 'output_ports': n_data['output_ports']})
+ node.set_ports({
+ 'input_ports': n_data['input_ports'],
+ 'output_ports': n_data['output_ports']
+ })
# build the connections.
for connection in data.get('connections', []):
diff --git a/NodeGraphQt/base/port.py b/NodeGraphQt/base/port.py
index 29aaeee3..05122efc 100644
--- a/NodeGraphQt/base/port.py
+++ b/NodeGraphQt/base/port.py
@@ -145,6 +145,9 @@ def connect_to(self, port=None):
if not port:
return
+ if self in port.connected_ports():
+ return
+
graph = self.node().graph
viewer = graph.viewer()
diff --git a/NodeGraphQt/constants.py b/NodeGraphQt/constants.py
index b2ebc962..317ea4a5 100644
--- a/NodeGraphQt/constants.py
+++ b/NodeGraphQt/constants.py
@@ -88,8 +88,11 @@
# === NODE VIEWER ===
+#: Style to render the node graph background with nothing.
VIEWER_GRID_NONE = 0
+#: Style to render the node graph background with dots.
VIEWER_GRID_DOTS = 1
+#: Style to render the node graph background with grid lines.
VIEWER_GRID_LINES = 2
VIEWER_BG_COLOR = (35, 35, 35)
diff --git a/NodeGraphQt/widgets/node_publish_widget.py b/NodeGraphQt/widgets/node_publish_widget.py
index c46a9cb0..4c5ebb9f 100644
--- a/NodeGraphQt/widgets/node_publish_widget.py
+++ b/NodeGraphQt/widgets/node_publish_widget.py
@@ -1,6 +1,7 @@
+import os
+
from .properties import PropFileSavePath
from .. import QtWidgets
-import os
class _element_widget(QtWidgets.QWidget):
diff --git a/NodeGraphQt/widgets/viewer.py b/NodeGraphQt/widgets/viewer.py
index 6fe3708d..e9801ecf 100644
--- a/NodeGraphQt/widgets/viewer.py
+++ b/NodeGraphQt/widgets/viewer.py
@@ -23,7 +23,7 @@ class NodeViewer(QtWidgets.QGraphicsView):
"""
The widget interface used for displaying the scene and nodes.
- functions in this class are called by the
+ functions in this class should mainly be called by the
class:`NodeGraphQt.NodeGraph` class.
"""
@@ -665,6 +665,13 @@ def apply_live_connection(self, event):
self.end_live_connection()
return
+ # end connection if starting port is already connected.
+ if self._start_port.multi_connection and \
+ self._start_port in end_port.connected_ports:
+ self._detached_port = None
+ self.end_live_connection()
+ return
+
# register as disconnected if not acyclic.
if self.acyclic and not self.acyclic_check(self._start_port, end_port):
if self._detached_port:
@@ -814,6 +821,16 @@ def message_dialog(text, title='Node Graph'):
BaseDialog.message_dialog(text, title)
def load_dialog(self, current_dir=None, ext=None):
+ """
+ Prompt node viewer file load dialog widget.
+
+ Args:
+ current_dir (str): directory path starting point. (optional)
+ ext (str): custom file extension filter type. (optional)
+
+ Returns:
+ str: selected file path.
+ """
ext = '*{} '.format(ext) if ext else ''
ext_filter = ';;'.join([
'Node Graph ({}*json)'.format(ext), 'All Files (*)'
@@ -824,6 +841,16 @@ def load_dialog(self, current_dir=None, ext=None):
return file
def save_dialog(self, current_dir=None, ext=None):
+ """
+ Prompt node viewer file save dialog widget.
+
+ Args:
+ current_dir (str): directory path starting point. (optional)
+ ext (str): custom file extension filter type. (optional)
+
+ Returns:
+ str: selected file path.
+ """
ext_label = '*{} '.format(ext) if ext else ''
ext_type = '.{}'.format(ext) if ext else '.json'
ext_map = {'Node Graph ({}*json)'.format(ext_label): ext_type,
@@ -924,6 +951,14 @@ def remove_node(node):
node.delete()
def move_nodes(self, nodes, pos=None, offset=None):
+ """
+ Globally move specified nodes.
+
+ Args:
+ nodes (list[AbstractNodeItem]): node items.
+ pos (tuple or list): custom x, y position.
+ offset (tuple or list): x, y position offset.
+ """
group = self.scene().createItemGroup(nodes)
group_rect = group.boundingRect()
if pos:
diff --git a/README.md b/README.md
index 6a5e8baf..624d515e 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,11 @@ applications that supports PySide2.
#### Vertical Layout
-
+
+
+#### Pipe Layout
+
+
#### Example
diff --git a/docs/_images/menu_hotkeys.png b/docs/_images/menu_hotkeys.png
index 00824e1f..cf3b312a 100644
Binary files a/docs/_images/menu_hotkeys.png and b/docs/_images/menu_hotkeys.png differ
diff --git a/docs/_images/pipe_layout_menu.png b/docs/_images/pipe_layout_menu.png
new file mode 100644
index 00000000..90cc32c6
Binary files /dev/null and b/docs/_images/pipe_layout_menu.png differ
diff --git a/docs/_images/pipe_layout_types.gif b/docs/_images/pipe_layout_types.gif
new file mode 100644
index 00000000..4bd6b54e
Binary files /dev/null and b/docs/_images/pipe_layout_types.gif differ
diff --git a/docs/conf.py b/docs/conf.py
index 434c88ba..b9a4ae05 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -162,7 +162,7 @@
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'NodeGraphQT.tex', 'NodeGraphQt Documentation',
- 'Johnny Chan', 'manual'),
+ author, 'manual'),
]
diff --git a/docs/examples/ex_node.rst b/docs/examples/ex_node.rst
index 710afe8c..0c6e74a9 100644
--- a/docs/examples/ex_node.rst
+++ b/docs/examples/ex_node.rst
@@ -75,6 +75,8 @@ To you update the widget you can call the :meth:`NodeGraphQt.NodeObject.set_prop
- ``QCheckBox``: :meth:`NodeGraphQt.BaseNode.add_checkbox`
- ``QLineEdit``: :meth:`NodeGraphQt.BaseNode.add_text_input`
+See: :ref:`Node Widgets` for more node widget types.
+
Connecting Nodes
****************
diff --git a/docs/examples/ex_pipe.rst b/docs/examples/ex_pipe.rst
new file mode 100644
index 00000000..152bd477
--- /dev/null
+++ b/docs/examples/ex_pipe.rst
@@ -0,0 +1,35 @@
+Pipe Examples
+#############
+
+Example Pipe Layouts
+********************
+
+.. image:: ../_images/pipe_layout_types.gif
+ :width: 650px
+
+The :class:`NodeGraphQt.NodeGraph` class has 3 different pipe layout styles as
+shown above this can be set easily with the :meth:`NodeGraphQt.NodeGraph.set_pipe_style`
+function.
+
+Here's a super simple example snippet for setting the pipe layout style to be angled.
+
+.. code-block:: python
+ :linenos:
+
+ from NodeGraphQt import NodeGraph
+ from NodeGraphQt.constants import PIPE_LAYOUT_ANGLE
+
+ graph = NodeGraph()
+ graph.set_pipe_style(PIPE_LAYOUT_ANGLE)
+
+Constants variables for the 3 different pipe layout styles:
+
+ - ``Curved``: :attr:`NodeGraphQt.constants.PIPE_LAYOUT_CURVED`
+ - ``Straight``: :attr:`NodeGraphQt.constants.PIPE_LAYOUT_STRAIGHT`
+ - ``Angle``: :attr:`NodeGraphQt.constants.PIPE_LAYOUT_ANGLE`
+
+Note: if you've set up your node graph with the ``NodeGraphQt.setup_context_menu``
+is a convenience function then you'll already have the actions to set the pipe
+layout under "Edit>Pipe".
+
+.. image:: ../_images/pipe_layout_menu.png
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
index 409a3abd..4d1e9bbc 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -30,4 +30,5 @@ GitHub Project: https://github.com/jchanvfx/NodeGraphQt
examples/ex_overview
examples/ex_node
examples/ex_port
+ examples/ex_pipe
examples/ex_menu
diff --git a/docs/node_widgets.rst b/docs/node_widgets.rst
index 5e90e77f..a0d957dd 100644
--- a/docs/node_widgets.rst
+++ b/docs/node_widgets.rst
@@ -11,6 +11,13 @@ NodeBaseWidget
:members:
:exclude-members: node, setToolTip, type_, value, widget
+NodeCheckBox
+************
+
+.. autoclass:: NodeGraphQt.widgets.node_widgets.NodeCheckBox
+ :members:
+ :exclude-members: widget, type_
+
NodeComboBox
************
@@ -25,9 +32,23 @@ NodeLineEdit
:members:
:exclude-members: widget, type_
-NodeCheckBox
+NodeFilePath
************
-.. autoclass:: NodeGraphQt.widgets.node_widgets.NodeCheckBox
+.. autoclass:: NodeGraphQt.widgets.node_widgets.NodeFilePath
+ :members:
+ :exclude-members: widget, type_
+
+NodeFloatEdit
+*************
+
+.. autoclass:: NodeGraphQt.widgets.node_widgets.NodeFloatEdit
+ :members:
+ :exclude-members: widget, type_
+
+NodeIntEdit
+***********
+
+.. autoclass:: NodeGraphQt.widgets.node_widgets.NodeIntEdit
:members:
:exclude-members: widget, type_