Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into gh-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jul 23, 2024
2 parents e65b8d0 + 93aba99 commit 89351b1
Show file tree
Hide file tree
Showing 17 changed files with 128 additions and 87 deletions.
47 changes: 30 additions & 17 deletions NodeGraphQt/base/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import json
import os
import re
from pathlib import Path

from Qt import QtCore, QtWidgets

Expand Down Expand Up @@ -519,7 +520,11 @@ def widget(self):
self._widget.addTab(self._viewer, 'Node Graph')
# hide the close button on the first tab.
tab_bar = self._widget.tabBar()
for btn_flag in [tab_bar.RightSide, tab_bar.LeftSide]:
tab_flags = [
QtWidgets.QTabBar.RightSide,
QtWidgets.QTabBar.LeftSide
]
for btn_flag in tab_flags:
tab_btn = tab_bar.tabButton(0, btn_flag)
if tab_btn:
tab_btn.deleteLater()
Expand Down Expand Up @@ -771,14 +776,15 @@ def get_context_menu(self, menu):
"""
return self._context_menu.get(menu)

def _deserialize_context_menu(self, menu, menu_data):
def _deserialize_context_menu(self, menu, menu_data, anchor_path=None):
"""
Populate context menu from a dictionary.
Args:
menu (NodeGraphQt.NodeGraphMenu or NodeGraphQt.NodesMenu):
parent context menu.
menu_data (list[dict] or dict): serialized menu data.
anchor_path (str or None): directory to interpret file paths relative to (optional)
"""
if not menu:
raise ValueError('No context menu named: "{}"'.format(menu))
Expand All @@ -788,6 +794,10 @@ def _deserialize_context_menu(self, menu, menu_data):

nodes_menu = self.get_context_menu('nodes')

anchor = Path(anchor_path).resolve()
if anchor.is_file():
anchor = anchor.parent

def build_menu_command(menu, data):
"""
Create menu command from serialized data.
Expand All @@ -797,14 +807,16 @@ def build_menu_command(menu, data):
menu object.
data (dict): serialized menu command data.
"""
full_path = os.path.abspath(data['file'])
base_dir, file_name = os.path.split(full_path)
base_name = os.path.basename(base_dir)
file_name, _ = file_name.split('.')
func_path = Path(data['file'])
if not func_path.is_absolute():
func_path = anchor.joinpath(func_path)

base_name = func_path.parent.name
file_name = func_path.stem

mod_name = '{}.{}'.format(base_name, file_name)

spec = importlib.util.spec_from_file_location(mod_name, full_path)
spec = importlib.util.spec_from_file_location(mod_name, func_path)
mod = importlib.util.module_from_spec(spec)
sys.modules[mod_name] = mod
spec.loader.exec_module(mod)
Expand All @@ -828,12 +840,12 @@ def build_menu_command(menu, data):
elif item_type == 'menu':
sub_menu = menu.add_menu(menu_data['label'])
items = menu_data.get('items', [])
self._deserialize_context_menu(sub_menu, items)
self._deserialize_context_menu(sub_menu, items, anchor_path)
elif isinstance(menu_data, list):
for item_data in menu_data:
self._deserialize_context_menu(menu, item_data)
self._deserialize_context_menu(menu, item_data, anchor_path)

def set_context_menu(self, menu_name, data):
def set_context_menu(self, menu_name, data, anchor_path=None):
"""
Populate a context menu from serialized data.
Expand Down Expand Up @@ -871,11 +883,12 @@ def run_test(graph):
Args:
menu_name (str): name of the parent context menu to populate under.
data (dict): serialized menu data.
anchor_path (str or None): directory to interpret file paths relative to (optional)
"""
context_menu = self.get_context_menu(menu_name)
self._deserialize_context_menu(context_menu, data)
self._deserialize_context_menu(context_menu, data, anchor_path)

def set_context_menu_from_file(self, file_path, menu=None):
def set_context_menu_from_file(self, file_path, menu='graph'):
"""
Populate a context menu from a serialized json file.
Expand All @@ -888,16 +901,16 @@ def set_context_menu_from_file(self, file_path, menu=None):
menu (str): name of the parent context menu to populate under.
file_path (str): serialized menu commands json file.
"""
file_path = os.path.abspath(file_path)
file = Path(file_path).resolve()

menu = menu or 'graph'
if not os.path.isfile(file_path):
raise IOError('file doesn\'t exists: "{}"'.format(file_path))
if not file.is_file():
raise IOError('file doesn\'t exist: "{}"'.format(file))

with open(file_path) as f:
with file.open() as f:
data = json.load(f)
context_menu = self.get_context_menu(menu)
self._deserialize_context_menu(context_menu, data)
self._deserialize_context_menu(context_menu, data, file)

def disable_context_menu(self, disabled=True, name='all'):
"""
Expand Down
2 changes: 1 addition & 1 deletion NodeGraphQt/base/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def _set_shortcut(action, shortcut):
shortcut = getattr(QtGui.QKeySequence, search.group(1))
elif all([i in ['Alt', 'Enter'] for i in shortcut.split('+')]):
shortcut = QtGui.QKeySequence(
QtCore.Qt.ALT + QtCore.Qt.Key_Return
QtCore.Qt.ALT | QtCore.Qt.Key_Return
)
elif all([i in ['Return', 'Enter'] for i in shortcut.split('+')]):
shortcut = QtCore.Qt.Key_Return
Expand Down
10 changes: 6 additions & 4 deletions NodeGraphQt/base/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,9 +543,10 @@ def add_port_accept_connection_type(
connection_data = connection_data[key]

if accept_ptype not in connection_data:
connection_data[accept_ptype] = [accept_pname]
connection_data[accept_ptype] = set([accept_pname])
else:
connection_data[accept_ptype].append(accept_pname)
# ensure data remains a set instead of list after json de-serialize
connection_data[accept_ptype] = set(connection_data[accept_ptype]) | {accept_pname}

def port_accept_connection_types(self, node_type, port_type, port_name):
"""
Expand Down Expand Up @@ -588,9 +589,10 @@ def add_port_reject_connection_type(
connection_data = connection_data[key]

if reject_ptype not in connection_data:
connection_data[reject_ptype] = [reject_pname]
connection_data[reject_ptype] = set([reject_pname])
else:
connection_data[reject_ptype].append(reject_pname)
# ensure data remains a set instead of list after json de-serialize
connection_data[reject_ptype] = set(connection_data[reject_ptype]) | {reject_pname}

def port_reject_connection_types(self, node_type, port_type, port_name):
"""
Expand Down
8 changes: 4 additions & 4 deletions NodeGraphQt/custom_widgets/nodes_palette.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ class NodesGridView(QtWidgets.QListView):

def __init__(self, parent=None):
super(NodesGridView, self).__init__(parent)
self.setSelectionMode(self.ExtendedSelection)
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.setUniformItemSizes(True)
self.setResizeMode(self.Adjust)
self.setViewMode(self.IconMode)
self.setDragDropMode(self.DragOnly)
self.setResizeMode(QtWidgets.QListView.Adjust)
self.setViewMode(QtWidgets.QListView.IconMode)
self.setDragDropMode(QtWidgets.QListView.DragOnly)
self.setDragEnabled(True)
self.setMinimumSize(300, 100)
self.setSpacing(4)
Expand Down
2 changes: 1 addition & 1 deletion NodeGraphQt/custom_widgets/nodes_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class NodesTreeWidget(QtWidgets.QTreeWidget):
def __init__(self, parent=None, node_graph=None):
super(NodesTreeWidget, self).__init__(parent)
self.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
self.setSelectionMode(self.ExtendedSelection)
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.setHeaderHidden(True)
self.setWindowTitle('Nodes')

Expand Down
4 changes: 4 additions & 0 deletions NodeGraphQt/nodes/base_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ def add_custom_widget(self, widget, widget_type=None, tab=None):
#: redraw node to address calls outside the "__init__" func.
self.view.draw_node()

#: HACK: calling the .parent() function here on the widget as it seems
# to address a seg fault issue when exiting the application.
widget.parent()

def add_combo_menu(self, name, label='', items=None, tooltip=None,
tab=None):
"""
Expand Down
2 changes: 1 addition & 1 deletion NodeGraphQt/pkg_info.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
__version__ = '0.6.36'
__version__ = '0.6.37'
__status__ = 'Work in Progress'
__license__ = 'MIT'

Expand Down
5 changes: 4 additions & 1 deletion NodeGraphQt/qgraphics/node_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ class AbstractNodeItem(QtWidgets.QGraphicsItem):

def __init__(self, name='node', parent=None):
super(AbstractNodeItem, self).__init__(parent)
self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
self.setFlags(
QtWidgets.QGraphicsItem.ItemIsSelectable |
QtWidgets.QGraphicsItem.ItemIsMovable
)
self.setCacheMode(ITEM_CACHE_MODE)
self.setZValue(Z_VAL_NODE)
self._properties = {
Expand Down
8 changes: 4 additions & 4 deletions NodeGraphQt/qgraphics/node_backdrop.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class BackdropSizer(QtWidgets.QGraphicsItem):

def __init__(self, parent=None, size=6.0):
super(BackdropSizer, self).__init__(parent)
self.setFlag(self.ItemIsSelectable, True)
self.setFlag(self.ItemIsMovable, True)
self.setFlag(self.ItemSendsScenePositionChanges, True)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges, True)
self.setCursor(QtGui.QCursor(QtCore.Qt.SizeFDiagCursor))
self.setToolTip('double-click auto resize')
self._size = size
Expand All @@ -38,7 +38,7 @@ def boundingRect(self):
return QtCore.QRectF(0.5, 0.5, self._size, self._size)

def itemChange(self, change, value):
if change == self.ItemPositionChange:
if change == QtWidgets.QGraphicsItem.ItemPositionChange:
item = self.parentItem()
mx, my = item.minimum_size
x = mx if value.x() < mx else value.x()
Expand Down
2 changes: 1 addition & 1 deletion NodeGraphQt/qgraphics/node_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ def itemChange(self, change, value):
change:
value:
"""
if change == self.ItemSelectedChange and self.scene():
if change == QtWidgets.QGraphicsItem.ItemSelectedChange and self.scene():
self.reset_pipes()
if value:
self.highlight_pipes()
Expand Down
2 changes: 1 addition & 1 deletion NodeGraphQt/qgraphics/node_overlay_disabled.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def paint(self, painter, option, widget):

painter.setFont(font)
font_metrics = QtGui.QFontMetrics(font)
font_width = font_metrics.width(self.text)
font_width = font_metrics.horizontalAdvance(self.text)
font_height = font_metrics.height()
txt_w = font_width * 1.25
txt_h = font_height * 2.25
Expand Down
8 changes: 5 additions & 3 deletions NodeGraphQt/qgraphics/pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ def __init__(self, input_port=None, output_port=None):

self._dir_pointer = QtWidgets.QGraphicsPolygonItem(self)
self._dir_pointer.setPolygon(self._poly)
self._dir_pointer.setFlag(self.ItemIsSelectable, False)
self._dir_pointer.setFlag(
QtWidgets.QGraphicsPathItem.ItemIsSelectable, False
)

self.reset()

Expand All @@ -72,7 +74,7 @@ def hoverLeaveEvent(self, event):
self.highlight()

def itemChange(self, change, value):
if change == self.ItemSelectedChange and self.scene():
if change == QtWidgets.QGraphicsPathItem.ItemSelectedChange and self.scene():
if value:
self.highlight()
else:
Expand Down Expand Up @@ -100,7 +102,7 @@ def paint(self, painter, option, widget):

painter.setPen(pen)
painter.setBrush(self.brush())
painter.setRenderHint(painter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.drawPath(self.path())

# QPaintDevice: Cannot destroy paint device that is being painted.
Expand Down
6 changes: 3 additions & 3 deletions NodeGraphQt/qgraphics/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ def __init__(self, parent=None):
super(PortItem, self).__init__(parent)
self.setAcceptHoverEvents(True)
self.setCacheMode(ITEM_CACHE_MODE)
self.setFlag(self.ItemIsSelectable, False)
self.setFlag(self.ItemSendsScenePositionChanges, True)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, False)
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsScenePositionChanges, True)
self.setZValue(Z_VAL_PORT)
self._pipes = []
self._width = PortEnum.SIZE.value
Expand Down Expand Up @@ -114,7 +114,7 @@ def paint(self, painter, option, widget):
painter.restore()

def itemChange(self, change, value):
if change == self.ItemScenePositionHasChanged:
if change == QtWidgets.QGraphicsItem.ItemScenePositionHasChanged:
self.redraw_connected_pipes()
return super(PortItem, self).itemChange(change, value)

Expand Down
4 changes: 3 additions & 1 deletion NodeGraphQt/widgets/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ def __init__(self, parent=None, undo_stack=None):
)))
text_color.setAlpha(50)
self._cursor_text = QtWidgets.QGraphicsTextItem()
self._cursor_text.setFlag(self._cursor_text.ItemIsSelectable, False)
self._cursor_text.setFlag(
QtWidgets.QGraphicsTextItem.ItemIsSelectable, False
)
self._cursor_text.setDefaultTextColor(text_color)
self._cursor_text.setZValue(Z_VAL_PIPE - 1)
font = self._cursor_text.font()
Expand Down
24 changes: 13 additions & 11 deletions examples/basic_example.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import signal
from pathlib import Path

from Qt import QtCore, QtWidgets

Expand All @@ -12,23 +12,23 @@
NodesPaletteWidget
)

# import example nodes from the "example_nodes" package
from nodes import basic_nodes, custom_ports_node, group_node, widget_nodes
# import example nodes from the "nodes" sub-package
from examples.nodes import basic_nodes, custom_ports_node, group_node, widget_nodes

if __name__ == '__main__':
BASE_PATH = Path(__file__).parent.resolve()

def main():
# handle SIGINT to make the app terminate on CTRL+C
signal.signal(signal.SIGINT, signal.SIG_DFL)

QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)

app = QtWidgets.QApplication([])

# create graph controller.
graph = NodeGraph()

# set up context menu for the node graph.
graph.set_context_menu_from_file('../examples/hotkeys/hotkeys.json')
hotkey_path = Path(BASE_PATH, 'hotkeys', 'hotkeys.json')
graph.set_context_menu_from_file(hotkey_path, 'graph')

# registered example nodes.
graph.register_nodes([
Expand All @@ -55,9 +55,7 @@
# create node and set a custom icon.
n_basic_b = graph.create_node(
'nodes.basic.BasicNodeB', name='custom icon')
n_basic_b.set_icon(
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'star.png')
)
n_basic_b.set_icon(Path(BASE_PATH, 'star.png'))

# create node with the custom port shapes.
n_custom_ports = graph.create_node(
Expand Down Expand Up @@ -141,4 +139,8 @@ def display_properties_bin(node):
nodes_palette.set_category_label('nodes.group', 'Group Nodes')
# nodes_palette.show()

app.exec_()
app.exec()


if __name__ == '__main__':
main()
6 changes: 6 additions & 0 deletions examples/hotkeys/hotkey_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ def clear_session(graph):
if graph.question_dialog('Clear Current Session?', 'Clear Session'):
graph.clear_session()

def quit_qt(graph):
"""
Quit the Qt application.
"""
from Qt import QtCore
QtCore.QCoreApplication.quit()

def clear_undo(graph):
"""
Expand Down
Loading

0 comments on commit 89351b1

Please sign in to comment.