diff --git a/README.md b/README.md index 16799b93..6a7a6216 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You can install `napari-spatialdata` via [pip]: pip install napari-spatialdata[all] -The `all` command will install the qt bindings `PyQt5`. +The `all` extra also installs the Qt bindings `PyQt6` (via `napari[pyqt6]`). Napari now also includes multiple triangulation backends. These improve the speed by which a napari 'Shapes' layer gets loaded (this does not improve the speed of editing large numbers of shapes yet!). See also the napari diff --git a/setup.cfg b/setup.cfg index 5ff2f17e..61787483 100644 --- a/setup.cfg +++ b/setup.cfg @@ -102,7 +102,7 @@ pre = spatialdata>=0.7.3a1 all = - napari[pyqt5] + napari[pyqt6] [options.packages.find] where = src diff --git a/src/napari_spatialdata/_scatterwidgets.py b/src/napari_spatialdata/_scatterwidgets.py index 42bbb58b..8caf894f 100644 --- a/src/napari_spatialdata/_scatterwidgets.py +++ b/src/napari_spatialdata/_scatterwidgets.py @@ -923,11 +923,11 @@ def mousePressEvent(self, event: Any) -> None: logger.debug("Left press detected") # Get the position of the click in the scene - scene_pos = event.pos() + scene_pos = self.mapToScene(event.pos()) # Check if the click is within the scatter plot view box if not self.scatter_plot.vb.sceneBoundingRect().contains(scene_pos): - logger.debug("Click outside scatter plot view box, scene position: {scene_pos}") + logger.debug(f"Click outside scatter plot view box, scene position: {scene_pos}") return pen = pg.mkPen(color="gray", width=2) @@ -938,7 +938,7 @@ def mousePressEvent(self, event: Any) -> None: if self.drawing: - plot_pos = self.scatter_plot.vb.mapSceneToView(event.pos()) + plot_pos = self.scatter_plot.vb.mapSceneToView(scene_pos) self.current_roi = pg.PolyLineROI( [], closed=True, removable=True, pen=pen, handlePen=handlePen, hoverPen=hoverPen @@ -946,7 +946,7 @@ def mousePressEvent(self, event: Any) -> None: self.scatter_plot.addItem(self.current_roi) self.current_points = [(plot_pos.x(), plot_pos.y())] - self.last_pos = (event.pos().x(), event.pos().y()) + self.last_pos = (scene_pos.x(), scene_pos.y()) event.accept() @@ -954,7 +954,7 @@ def mousePressEvent(self, event: Any) -> None: logger.info("Rectangle") - plot_pos = self.scatter_plot.vb.mapSceneToView(event.pos()) + plot_pos = self.scatter_plot.vb.mapSceneToView(scene_pos) self.current_roi = pg.RectROI( pos=(plot_pos.x(), plot_pos.y()), size=(0, 0), @@ -979,16 +979,17 @@ def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: if self.drawing and self.current_roi is not None: if self.last_pos is not None: - dist = np.sqrt((event.pos().x() - self.last_pos[0]) ** 2 + (event.pos().y() - self.last_pos[1]) ** 2) + scene_pos = self.mapToScene(event.pos()) + dist = np.sqrt((scene_pos.x() - self.last_pos[0]) ** 2 + (scene_pos.y() - self.last_pos[1]) ** 2) if dist > self.vertex_add_threshold: - plot_pos = self.scatter_plot.vb.mapSceneToView(event.pos()) + plot_pos = self.scatter_plot.vb.mapSceneToView(scene_pos) self.current_points.append((plot_pos.x(), plot_pos.y())) self.current_roi.setPoints(self.current_points) - self.last_pos = (event.pos().x(), event.pos().y()) + self.last_pos = (scene_pos.x(), scene_pos.y()) logger.debug(f"Updated points for PolyLineROI: {self.current_points}") @@ -996,7 +997,7 @@ def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: elif self.rectangle and self.current_roi is not None and self.initial_pos is not None: - plot_pos = self.scatter_plot.vb.mapSceneToView(event.pos()) + plot_pos = self.scatter_plot.vb.mapSceneToView(self.mapToScene(event.pos())) width = plot_pos.x() - self.initial_pos.x() # type: ignore[attr-defined] height = plot_pos.y() - self.initial_pos.y() # type: ignore[attr-defined] self.current_roi.setSize([width, height]) @@ -1010,7 +1011,7 @@ def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: super().mouseMoveEvent(event) # Get cursor position - scene_pos = event.pos() + scene_pos = self.mapToScene(event.pos()) plot_pos = self.scatter_plot.vb.mapSceneToView(scene_pos) # Update the cursor position label @@ -1021,7 +1022,10 @@ def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None: def mouseReleaseEvent(self, event: Any) -> None: - logger.debug(f"Mouse release event detected at {self.scatter_plot.vb.mapSceneToView(event.pos())}") + # also called by scene().sigMouseClicked with a pyqtgraph MouseClickEvent, whose pos() mapToScene can't take + if isinstance(event, QtGui.QMouseEvent): + scene_pos = self.mapToScene(event.pos()) + logger.debug(f"Mouse release event detected at {self.scatter_plot.vb.mapSceneToView(scene_pos)}") if self.drawing and event.button() == Qt.LeftButton: @@ -1049,7 +1053,7 @@ def mouseReleaseEvent(self, event: Any) -> None: def mouseDoubleClickEvent(self, event: Any) -> None: if event.button() == Qt.LeftButton: - plot_pos = self.scatter_plot.vb.mapSceneToView(event.pos()) + plot_pos = self.scatter_plot.vb.mapSceneToView(self.mapToScene(event.pos())) point = Point(plot_pos.x(), plot_pos.y()) self.remove_roi(point=point) diff --git a/tests/test_scatterwidgets.py b/tests/test_scatterwidgets.py index df18566e..4a1704e9 100644 --- a/tests/test_scatterwidgets.py +++ b/tests/test_scatterwidgets.py @@ -182,8 +182,8 @@ def plot_coords_to_viewport(plot_widget, x, y): def send_mouse_event(event_type, widget, pos, button=QtCore.Qt.LeftButton): """Send a mouse event to a widget.""" - # necessary because of https://bugreports.qt.io/browse/QTBUG-5232 - event = QtGui.QMouseEvent(event_type, pos, button, button, QtCore.Qt.NoModifier) + # necessary because of https://bugreports.qt.io/browse/QTBUG-5232; Qt6 bindings need a QPointF position + event = QtGui.QMouseEvent(event_type, QtCore.QPointF(pos), button, button, QtCore.Qt.NoModifier) QtWidgets.QApplication.sendEvent(widget, event) diff --git a/tests/test_widgets.py b/tests/test_widgets.py index ede04bb5..f0db306e 100644 --- a/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -316,7 +316,7 @@ def test_old_annotation(adata_labels, annotation_values, mocker): col_name = scatter_widget.model.adata.obs.columns[0] mocker.patch.object(scatter_widget, "open_annotation_dialog", return_value=col_name) mocker.patch.object(scatter_widget.plot_widget, "get_selection", return_value=annotation_values) - mocker.patch("PyQt5.QtWidgets.QMessageBox.question", return_value=QtWidgets.QMessageBox.Yes) + mocker.patch.object(QtWidgets.QMessageBox, "question", return_value=QtWidgets.QMessageBox.Yes) scatter_widget.export() diff --git a/tox.ini b/tox.ini index b62b2031..f1cffd50 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,6 @@ deps = pytest-cov pytest-qt pytest-mock - PyQt5 passenv = CI GITHUB_ACTIONS