diff --git a/.github/workflows/type-checking.yml b/.github/workflows/type-checking.yml index 195838ac..87f97175 100644 --- a/.github/workflows/type-checking.yml +++ b/.github/workflows/type-checking.yml @@ -30,7 +30,7 @@ jobs: run: python -m pip install . --user && python -m pip uninstall ryven --yes working-directory: ./ryven-editor - name: Install type-checking dependencies - run: python -m pip install mypy pyside2 types-Pygments --user + run: python -m pip install mypy pyside2 pyside6 PySide6-stubs types-Pygments --user - name: Typecheck run: mypy working-directory: . diff --git a/debug.py b/debug.py index e085eac2..c6d70b49 100755 --- a/debug.py +++ b/debug.py @@ -25,6 +25,6 @@ f"{RYVEN_PATH}/ryven/example_nodes/std", f"{RYVEN_PATH}/ryven/example_nodes/linalg", ], - qt_api='pyside2', + qt_api='pyside6', show_dialog=False, ) diff --git a/ryven-editor/ryven/example_nodes/std/gui.py b/ryven-editor/ryven/example_nodes/std/gui.py index 9ad118cb..c54e5a24 100644 --- a/ryven-editor/ryven/example_nodes/std/gui.py +++ b/ryven-editor/ryven/example_nodes/std/gui.py @@ -209,7 +209,7 @@ def rebuild_remove_actions(self): {'method': self.remove_output, 'data': i} -class ButtonNode_MainWidget(QPushButton, NodeMainWidget): +class ButtonNode_MainWidget(NodeMainWidget, QPushButton): def __init__(self, params): NodeMainWidget.__init__(self, params) diff --git a/ryven-editor/ryven/gui/flow_ui.py b/ryven-editor/ryven/gui/flow_ui.py index 4cdf09fd..d7aeedab 100644 --- a/ryven-editor/ryven/gui/flow_ui.py +++ b/ryven-editor/ryven/gui/flow_ui.py @@ -103,7 +103,7 @@ def __init__(self, main_window, flow: Flow, flow_view: FlowView): self.ui.inspector_dock.setWidget(self.inspector_widget) #undo history widget - self.undo_widget = QUndoView(stack=self.flow_view._undo_stack) + self.undo_widget = QUndoView(stack=self.flow_view._undo_stack) # type: ignore self.ui.undo_history_dock.setWidget(self.undo_widget) # logs self.ui.logs_scrollArea.setWidget(self.create_loggers_widget()) diff --git a/ryven-editor/ryven/gui/startup_dialog/StartupDialog.py b/ryven-editor/ryven/gui/startup_dialog/StartupDialog.py index b4364aa0..c79025d8 100644 --- a/ryven-editor/ryven/gui/startup_dialog/StartupDialog.py +++ b/ryven-editor/ryven/gui/startup_dialog/StartupDialog.py @@ -71,7 +71,8 @@ def minimumSizeHint(self): def sizeHint(self): hint = self.fontMetrics().boundingRect(self.text()).size() - l, t, r, b = self.getContentsMargins() + c_margins = self.contentsMargins() + l, t, r, b = c_margins.left(), c_margins.top(), c_margins.right(), c_margins.bottom() margin = self.margin() * 2 return QSize( min(100, hint.width()) + l + r + margin, @@ -83,7 +84,8 @@ def paintEvent(self, event): opt = QStyleOptionFrame() self.initStyleOption(opt) self.style().drawControl(QStyle.CE_ShapedFrame, opt, qp, self) - l, t, r, b = self.getContentsMargins() + c_margins = self.contentsMargins() + l, t, r, b = c_margins.left(), c_margins.top(), c_margins.right(), c_margins.bottom() margin = self.margin() try: # since Qt >= 5.11 diff --git a/ryven-editor/ryven/main/Ryven.py b/ryven-editor/ryven/main/Ryven.py index 75472f1f..ff1b9c02 100644 --- a/ryven-editor/ryven/main/Ryven.py +++ b/ryven-editor/ryven/main/Ryven.py @@ -7,6 +7,32 @@ from ryven.main.args_parser import process_args +def check_pyside_available(qt_api: str): + if qt_api == 'pyside2': + try: + import PySide2 + except ImportError: + sys.exit( + 'You are trying to use PySide2 as the Qt API, but it is not available. ' + 'please install it, or use pyside6 as the Qt API. Either of those can ' + 'installed through pip, e.g. `pip install pyside2` or `pip install \'pyside6<6.7\'`. ' + ) + elif qt_api == 'pyside6': + try: + import PySide6 + except ImportError: + sys.exit( + 'You are trying to use PySide6 as the Qt API, but it is not available. ' + 'please install it, or use pyside2 as the Qt API. Either of those can ' + 'installed through pip, e.g. `pip install pyside2` or `pip install \'pyside6<6.7\'`. ' + ) + else: + sys.exit( + f'Error: Illegal Qt API: "{qt_api}". ' + f'Use either "pyside2" or "pyside6". ' + ) + + def run(*args_, qt_app=None, gui_parent=None, use_sysargs: bool = True, **kwargs): @@ -72,6 +98,7 @@ def run(*args_, # # Init environment + check_pyside_available(conf.qt_api) os.environ['RYVEN_MODE'] = 'gui' os.environ['QT_API'] = conf.qt_api from ryven.node_env import init_node_env diff --git a/ryvencore-qt/ryvencore_qt/src/flows/FlowView.py b/ryvencore-qt/ryvencore_qt/src/flows/FlowView.py index bb2ff344..b91d81f6 100644 --- a/ryvencore-qt/ryvencore_qt/src/flows/FlowView.py +++ b/ryvencore-qt/ryvencore_qt/src/flows/FlowView.py @@ -39,12 +39,17 @@ QShortcut, QMenu, QGraphicsItem, - QUndoStack, QPushButton, QHBoxLayout, QWidget, ) +# for compatibility between qt5 and qt6 +try: + from qtpy.QtGui import QUndoStack +except ImportError: + from qtpy.QtWidgets import QUndoStack # type: ignore + from ryvencore.Flow import Flow from ryvencore.Node import Node from ryvencore.NodePort import NodePort, NodeInput, NodeOutput @@ -262,13 +267,11 @@ def init_proxy_widget(widget: QWidget, proxy: FlowViewProxyWidget): menu_layout_widget.layout().addWidget(menu_button) def menu_button_clicked(): - point = self._menu_layout_proxy.scenePos() - view_pos = self.mapFromScene(point.toPoint()) - # apply offset after - global_pos = self.viewport().mapToGlobal( - view_pos) + QPoint(8, self._menu_layout_proxy.widget().height() - ) - self._menu.exec_(global_pos) + # prob not entirely correct, since menu is part of a layout + # but since it's the first item, it's the same + menu_pos = self._menu_button.pos() + menu_pos = self.mapToGlobal(menu_pos) + QPoint(8, self._menu_button.height() + 10) + self._menu.exec_(menu_pos) menu_button.clicked.connect(menu_button_clicked) @@ -514,13 +517,15 @@ def wheelEvent(self, event): if event.modifiers() & Qt.ControlModifier: event.accept() - self._zoom_data['viewport pos'] = event.posF() - self._zoom_data['scene pos'] = pointF_mapped(self.mapToScene(event.pos()), event.posF()) + view_pos = event.position() + self._zoom_data['viewport pos'] = view_pos + self._zoom_data['scene pos'] = self.mapToScene(view_pos.toPoint()) - self._zoom_data['delta'] += event.delta() + y_delta = event.angleDelta().y() + self._zoom_data['delta'] += y_delta - if self._zoom_data['delta'] * event.delta() < 0: - self._zoom_data['delta'] = event.delta() + if self._zoom_data['delta'] * y_delta < 0: + self._zoom_data['delta'] = y_delta() anim = QTimeLine(100, self) anim.setUpdateInterval(10) diff --git a/ryvencore-qt/ryvencore_qt/src/flows/node_list_widget/NodeListWidget.py b/ryvencore-qt/ryvencore_qt/src/flows/node_list_widget/NodeListWidget.py index 0f2b59fc..35a41367 100644 --- a/ryvencore-qt/ryvencore_qt/src/flows/node_list_widget/NodeListWidget.py +++ b/ryvencore-qt/ryvencore_qt/src/flows/node_list_widget/NodeListWidget.py @@ -151,10 +151,10 @@ def search_pkg_tree(self, search: str): # removes whitespace and escapes all special regex chars new_search = escape(search.strip()) # regex that enforces the text starts with - self.pack_proxy_model.setFilterRegExp(f'^{new_search}') + self.pack_proxy_model.setFilterRegularExpression(f'^{new_search}') self.pack_tree.expandAll() else: - self.pack_proxy_model.setFilterRegExp('') + self.pack_proxy_model.setFilterRegularExpression('') self.pack_tree.collapseAll() def make_nodes_current(self, pack_nodes, pkg_name: str): diff --git a/ryvencore-qt/setup.cfg b/ryvencore-qt/setup.cfg index b41ee170..faf786fb 100644 --- a/ryvencore-qt/setup.cfg +++ b/ryvencore-qt/setup.cfg @@ -21,7 +21,6 @@ include_package_data = True python_requires = >=3.6, <3.11 install_requires = ryvencore ==0.4.* - PySide2 QtPy waiting textdistance