Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NodeGraphQt/base/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ def redo(self):
self.model.nodes[self.node.id] = self.node
self.viewer.add_node(self.node.view, self.pos)

# node width & height is calculated when its added to the scene
# so we have to update the node model here.
self.node.model.width = self.node.view.width
self.node.model.height = self.node.view.height


class NodeRemovedCmd(QtWidgets.QUndoCommand):
"""
Expand Down
105 changes: 92 additions & 13 deletions NodeGraphQt/base/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
from NodeGraphQt.base.node import NodeObject
from NodeGraphQt.base.port import Port
from NodeGraphQt.constants import (
NODE_LAYOUT_DIRECTION, NODE_LAYOUT_HORIZONTAL, NODE_LAYOUT_VERTICAL,
URI_SCHEME,
URN_SCHEME,
LayoutDirectionEnum,
PipeLayoutEnum,
URI_SCHEME, URN_SCHEME,
PortTypeEnum,
ViewerEnum
)
Expand Down Expand Up @@ -125,6 +126,15 @@ def __init__(self, parent=None, **kwargs):
self.setObjectName('NodeGraph')
self._model = (
kwargs.get('model') or NodeGraphModel())

layout_direction = kwargs.get('layout_direction')
if layout_direction:
if layout_direction not in [e.value for e in LayoutDirectionEnum]:
layout_direction = LayoutDirectionEnum.HORIZONTAL.value
self._model.layout_direction = layout_direction
else:
layout_direction = self._model.layout_direction

self._node_factory = (
kwargs.get('node_factory') or NodeFactory())

Expand All @@ -138,6 +148,7 @@ def __init__(self, parent=None, **kwargs):

self._viewer = (
kwargs.get('viewer') or NodeViewer(undo_stack=self._undo_stack))
self._viewer.set_layout_direction(layout_direction)

self._build_context_menu()
self._register_builtin_nodes()
Expand Down Expand Up @@ -786,6 +797,52 @@ def set_pipe_style(self, style=PipeLayoutEnum.CURVED.value):
style = style if 0 <= style <= pipe_max else PipeLayoutEnum.CURVED.value
self._viewer.set_pipe_layout(style)

def layout_direction(self):
"""
Return the current node graph layout direction.

`Implemented in` ``v0.3.0``

See Also:
:meth:`NodeGraph.set_layout_direction`

Returns:
int: layout direction.
"""
return self.model.layout_direction

def set_layout_direction(self, direction):
"""
Sets the node graph layout direction to horizontal or vertical.
This function will also override the layout direction on all
nodes in the current node graph.

`Implemented in` ``v0.3.0``

See Also:
:meth:`NodeGraph.layout_direction`,
:meth:`NodeObject.set_layout_direction`

Note:
Node Graph Layout Types:

* :attr:`NodeGraphQt.constants.LayoutDirectionEnum.HORIZONTAL`
* :attr:`NodeGraphQt.constants.LayoutDirectionEnum.VERTICAL`

Warnings:
This function does not register to the undo stack.

Args:
direction (int): layout direction.
"""
direction_types = [e.value for e in LayoutDirectionEnum]
if direction not in direction_types:
direction = LayoutDirectionEnum.HORIZONTAL.value
self._model.layout_direction = direction
for node in self.all_nodes():
node.set_layout_direction(direction)
self._viewer.set_layout_direction(direction)

def fit_to_selection(self):
"""
Sets the zoom level to fit selected nodes.
Expand Down Expand Up @@ -853,7 +910,7 @@ def register_node(self, node, alias=None):
Register the node to the :meth:`NodeGraph.node_factory`

Args:
node (_NodeGraphQt.NodeObject): node object.
node (NodeGraphQt.NodeObject): node object.
alias (str): custom alias name for the node type.
"""
self._node_factory.register_node(node, alias)
Expand Down Expand Up @@ -922,6 +979,9 @@ def format_color(clr):
if pos:
node.model.pos = [float(pos[0]), float(pos[1])]

# initial node direction layout.
node.model.layout_direction = self.layout_direction()

node.update()

if push_undo:
Expand Down Expand Up @@ -964,6 +1024,11 @@ def add_node(self, node, pos=None, selected=True, push_undo=True):
node.NODE_NAME = self.get_unique_name(node.NODE_NAME)
node.model._graph_model = self.model
node.model.name = node.NODE_NAME

# initial node direction layout.
node.model.layout_direction = self.layout_direction()

# update method must be called before it's been added to the viewer.
node.update()

if push_undo:
Expand Down Expand Up @@ -1672,7 +1737,9 @@ def auto_layout_nodes(self, nodes=None, down_stream=True, start_nodes=None):
else:
rank_map[rank] = [node]

if NODE_LAYOUT_DIRECTION is NODE_LAYOUT_HORIZONTAL:
node_layout_direction = self._viewer.get_layout_direction()

if node_layout_direction is LayoutDirectionEnum.HORIZONTAL.value:
current_x = 0
node_height = 120
for rank in sorted(range(len(rank_map)), reverse=not down_stream):
Expand All @@ -1687,7 +1754,7 @@ def auto_layout_nodes(self, nodes=None, down_stream=True, start_nodes=None):
current_y += dy * 0.5 + 10

current_x += max_width * 0.5 + 100
elif NODE_LAYOUT_DIRECTION is NODE_LAYOUT_VERTICAL:
elif node_layout_direction is LayoutDirectionEnum.VERTICAL.value:
current_y = 0
node_width = 250
for rank in sorted(range(len(rank_map)), reverse=not down_stream):
Expand Down Expand Up @@ -1861,7 +1928,11 @@ def expand_group_node(self, node):

# build new sub graph.
node_factory = copy.deepcopy(self.node_factory)
sub_graph = SubGraph(self, node=node, node_factory=node_factory)
layout_direction = self.layout_direction()
sub_graph = SubGraph(self,
node=node,
node_factory=node_factory,
layout_direction=layout_direction)

# populate the sub graph.
session = node.get_sub_graph_session()
Expand Down Expand Up @@ -1913,14 +1984,17 @@ class SubGraph(NodeGraph):
-
"""

def __init__(self, parent=None, node=None, node_factory=None):
def __init__(self, parent=None, node=None, node_factory=None, **kwargs):
"""
Args:
parent (object): object parent.
node (GroupNode): group node related to this sub graph.
node_factory (NodeFactory): override node factory.
**kwargs (dict): additional kwargs.
"""
super(SubGraph, self).__init__(parent, node_factory=node_factory)
super(SubGraph, self).__init__(
parent, node_factory=node_factory, **kwargs
)

# sub graph attributes.
self._node = node
Expand Down Expand Up @@ -1953,6 +2027,8 @@ def _build_port_nodes(self):
Returns:
tuple(dict, dict): input nodes, output nodes.
"""
node_layout_direction = self._viewer.get_layout_direction()

# build the parent input port nodes.
input_nodes = {n.name(): n for n in
self.get_nodes_by_type(PortInputNode.type_)}
Expand All @@ -1965,9 +2041,9 @@ def _build_port_nodes(self):
input_nodes[port.name()] = input_node
self.add_node(input_node, selected=False, push_undo=False)
x, y = input_node.pos()
if NODE_LAYOUT_DIRECTION is NODE_LAYOUT_HORIZONTAL:
if node_layout_direction is LayoutDirectionEnum.HORIZONTAL.value:
x -= 100
elif NODE_LAYOUT_DIRECTION is NODE_LAYOUT_VERTICAL:
elif node_layout_direction is LayoutDirectionEnum.VERTICAL.value:
y -= 100
input_node.set_property('pos', [x, y], push_undo=False)

Expand All @@ -1983,9 +2059,9 @@ def _build_port_nodes(self):
output_nodes[port.name()] = output_node
self.add_node(output_node, selected=False, push_undo=False)
x, y = output_node.pos()
if NODE_LAYOUT_DIRECTION is NODE_LAYOUT_HORIZONTAL:
if node_layout_direction is LayoutDirectionEnum.HORIZONTAL.value:
x += 100
elif NODE_LAYOUT_DIRECTION is NODE_LAYOUT_VERTICAL:
elif node_layout_direction is LayoutDirectionEnum.VERTICAL.value:
y += 100
output_node.set_property('pos', [x, y], push_undo=False)

Expand Down Expand Up @@ -2282,7 +2358,10 @@ def expand_group_node(self, node):

# build new sub graph.
node_factory = copy.deepcopy(self.node_factory)
sub_graph = SubGraph(self, node=node, node_factory=node_factory)
sub_graph = SubGraph(self,
node=node,
node_factory=node_factory,
layout_direction=self.layout_direction())

# populate the sub graph.
serialized_session = node.get_sub_graph_session()
Expand Down
42 changes: 30 additions & 12 deletions NodeGraphQt/base/graph_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ def build_context_menu(graph):
graph (NodeGraphQt.NodeGraph): node graph controller.
"""
from Qt import QtGui, QtCore
graph_menu = graph.get_context_menu('graph')
context_menu = graph.get_context_menu('graph')

# "File" menu.
# --------------------------------------------------------------------------
file_menu = graph_menu.add_menu('&File')
file_menu = context_menu.add_menu('&File')

file_menu.add_command('Open...', _open_session, QtGui.QKeySequence.Open)
file_menu.add_command('Import...', _import_session)
Expand All @@ -22,7 +22,7 @@ def build_context_menu(graph):

# "Edit" menu.
# --------------------------------------------------------------------------
edit_menu = graph_menu.add_menu('&Edit')
edit_menu = context_menu.add_menu('&Edit')

edit_menu.add_separator()
edit_menu.add_command('Clear Undo History', _clear_undo)
Expand All @@ -49,20 +49,24 @@ def build_context_menu(graph):
edit_menu.add_command('Zoom Out', _zoom_out, '-')
edit_menu.add_command('Reset Zoom', _reset_zoom, 'H')

edit_menu.add_separator()
context_menu.add_separator()

# "Grid Mode" submenu.
# "Node" menu.
# --------------------------------------------------------------------------
bg_menu = edit_menu.add_menu('&Grid Mode')
bg_menu.add_command('None', _bg_grid_none)
bg_menu.add_command('Lines', _bg_grid_lines)
bg_menu.add_command('Dots', _bg_grid_dots)
graph_menu = context_menu.add_menu('&Graph')

edit_menu.add_separator()
bg_menu = graph_menu.add_menu('&Background')
bg_menu.add_command('None', _bg_grid_none, 'Alt+1')
bg_menu.add_command('Lines', _bg_grid_lines, 'Alt+2')
bg_menu.add_command('Dots', _bg_grid_dots, 'Alt+3')

layout_menu = graph_menu.add_menu('&Layout')
layout_menu.add_command('Horizontal', _layout_h_mode, 'Shift+1')
layout_menu.add_command('Vertical', _layout_v_mode, 'Shift+2')

# "Node" menu.
# --------------------------------------------------------------------------
node_menu = graph_menu.add_menu('&Nodes')
node_menu = context_menu.add_menu('&Nodes')
node_menu.add_command('Node Search', _toggle_node_search, 'Tab')
node_menu.add_separator()
node_menu.add_command(
Expand All @@ -76,7 +80,7 @@ def build_context_menu(graph):

# "Pipe" menu.
# --------------------------------------------------------------------------
pipe_menu = graph_menu.add_menu('&Pipes')
pipe_menu = context_menu.add_menu('&Pipes')
pipe_menu.add_command('Curved', _curved_pipe)
pipe_menu.add_command('Straight', _straight_pipe)
pipe_menu.add_command('Angle', _angle_pipe)
Expand Down Expand Up @@ -109,6 +113,20 @@ def _reset_zoom(graph):
graph.reset_zoom()


def _layout_h_mode(graph):
"""
Set node graph layout direction to horizontal.
"""
graph.set_layout_direction(0)


def _layout_v_mode(graph):
"""
Set node graph layout direction to vertical.
"""
graph.set_layout_direction(1)


def _open_session(graph):
"""
Prompts a file open dialog to load a session.
Expand Down
5 changes: 5 additions & 0 deletions NodeGraphQt/base/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections import defaultdict

from NodeGraphQt.constants import (
LayoutDirectionEnum,
NODE_PROP,
NODE_PROP_QLABEL,
NODE_PROP_QLINEEDIT,
Expand Down Expand Up @@ -73,6 +74,7 @@ def __init__(self):
self.width = 100.0
self.height = 80.0
self.pos = [0.0, 0.0]
self.layout_direction = LayoutDirectionEnum.HORIZONTAL.value

# BaseNode attrs.
self.inputs = {}
Expand Down Expand Up @@ -107,6 +109,7 @@ def __init__(self):
'width': NODE_PROP,
'height': NODE_PROP,
'pos': NODE_PROP,
'layout_direction': NODE_PROP,
'inputs': NODE_PROP,
'outputs': NODE_PROP,
}
Expand Down Expand Up @@ -230,6 +233,7 @@ def to_dict(self):
'width': 0.0,
'height: 0.0,
'pos': (0.0, 0.0),
'layout_direction': 0,
'custom': {},
'inputs': {
<port_name>: {<node_id>: [<port_name>, <port_name>]}
Expand Down Expand Up @@ -317,6 +321,7 @@ def __init__(self):
self.session = ''
self.acyclic = True
self.pipe_collision = False
self.layout_direction = LayoutDirectionEnum.HORIZONTAL.value

def common_properties(self):
"""
Expand Down
Loading