Source code for arthropod_describer.custom_graphics_view

import time
import mouse

from PySide2.QtCore import Signal, QPointF, Qt, QEvent, QPoint
from PySide2.QtGui import QPainter, QWheelEvent, QResizeEvent, QMouseEvent, QKeyEvent, QCursor
from PySide2.QtWidgets import QGraphicsView, QWidget, QSizePolicy

from arthropod_describer.common.state import State
from arthropod_describer.common.tool import Tool


[docs]class CustomGraphicsView(QGraphicsView): view_changed = Signal() rubber_band_started = Signal() mouse_move = Signal(QPointF) view_dragging = Signal(bool, QPoint) double_shift = Signal() escape_pressed = Signal() space_pressed = Signal() tab_pressed = Signal() def __init__(self, state: State, parent: QWidget = None): QGraphicsView.__init__(self, parent) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) self.setRenderHint(QPainter.Antialiasing) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setInteractive(True) self.verticalScrollBar().valueChanged.connect(lambda _: self.view_changed.emit()) self.horizontalScrollBar().valueChanged.connect(lambda _: self.view_changed.emit()) self.time_of_first_shift = -1 self._allow_zoom: bool = True self.state = state #self.setCursor(QCursor(Qt.CursorShape.BlankCursor))
[docs] def wheelEvent(self, event: QWheelEvent) -> None: if event.modifiers() & Qt.ControlModifier > 0: self.state.key_modifier = Qt.Key_Control QGraphicsView.wheelEvent(self, event) return else: self.state.key_modifier = None if event.modifiers() & Qt.ShiftModifier > 0: QGraphicsView.wheelEvent(self, event) return delta = 1 if event.angleDelta().y() < 0: delta = -1 m = self.transform() m11 = m.m11() * (1 + delta * 0.05) m31 = 0 m22 = m.m22() * (1 + delta * 0.05) m32 = 0 m.setMatrix(m11, m.m12(), m.m13(), m.m21(), m22, m.m23(), m.m31() + m31, m.m32() + m32, m.m33()) self.setTransform(m, False) srect = self.sceneRect() rrect = self.mapToScene(self.rect()).boundingRect() if delta < 0 and rrect.height() > srect.height() and rrect.width() > srect.width(): self.fitInView(srect, Qt.KeepAspectRatio) self.scene().update() self.view_changed.emit()
[docs] def resizeEvent(self, event: QResizeEvent): self.view_changed.emit()
[docs] def mousePressEvent(self, event: QMouseEvent): if event.button() == Qt.MidButton: self.setDragMode(QGraphicsView.ScrollHandDrag) self.viewport().setCursor(Qt.ClosedHandCursor) self.original_event = event handmade_event = QMouseEvent(QEvent.MouseButtonPress, QPointF(event.pos()), Qt.LeftButton, event.buttons(), Qt.KeyboardModifiers()) self.view_dragging.emit(True, self.mapToScene(event.pos())) self.mousePressEvent(handmade_event) return None super().mousePressEvent(event)
[docs] def mouseReleaseEvent(self, event: QMouseEvent): if event.button() == Qt.RightButton: pass elif event.button() == Qt.LeftButton: pass elif event.button() == Qt.MidButton: self.viewport().setCursor(Qt.OpenHandCursor) handmade_event = QMouseEvent(QEvent.MouseButtonRelease, QPointF(event.pos()), Qt.LeftButton, event.buttons(), Qt.KeyboardModifiers()) self.mouseReleaseEvent(handmade_event) self.setDragMode(QGraphicsView.NoDrag) self.view_dragging.emit(False, self.mapToScene(event.pos())) super().mouseReleaseEvent(event)
[docs] def mouseMoveEvent(self, event: QMouseEvent): self.mouse_move.emit(self.mapToScene(event.pos())) QGraphicsView.mouseMoveEvent(self, event) # Auto scrolling near viewport edges. if (event.buttons() & Qt.LeftButton) or (self.state.current_tool is not None and self.state.current_tool.should_auto_scroll_with_left_button_released()): auto_scroll_edge_width = min(self.state.current_tool.get_auto_scroll_distance() if self.state.current_tool is not None else Tool.DEFAULT_AUTO_SCROLL_DISTANCE, self.width() / 3, self.height() / 3) # Auto scroll left. displacement = int(auto_scroll_edge_width - event.pos().x()) if self.horizontalScrollBar().value() > 0 and displacement > 0: mouse.move(displacement, 0, False) self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - displacement) # Auto scroll up. displacement = int(auto_scroll_edge_width - event.pos().y()) if self.verticalScrollBar().value() > 0 and displacement > 0: mouse.move(0, displacement, False) self.verticalScrollBar().setValue(self.verticalScrollBar().value() - displacement) # Auto scroll right. displacement = int(self.viewport().width() - auto_scroll_edge_width - event.pos().x()) if self.horizontalScrollBar().value() < self.horizontalScrollBar().maximum() and displacement < 0: mouse.move(displacement, 0, False) self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - displacement) # Auto scroll down. displacement = int(self.viewport().height() - auto_scroll_edge_width - event.pos().y()) if self.verticalScrollBar().value() < self.verticalScrollBar().maximum() and displacement < 0: mouse.move(0, displacement, False) self.verticalScrollBar().setValue(self.verticalScrollBar().value() - displacement)
[docs] def keyPressEvent(self, event: QKeyEvent) -> None: if event.key() == Qt.Key_Control: # self.setDragMode(QGraphicsView.ScrollHandDrag) pass elif event.key() == Qt.Key_Shift: self.rubber_band_started.emit() self.setDragMode(QGraphicsView.RubberBandDrag) self.setRubberBandSelectionMode(Qt.ContainsItemBoundingRect) QGraphicsView.keyPressEvent(self, event)
[docs] def keyReleaseEvent(self, event: QKeyEvent) -> None: if event.key() == Qt.Key_Control or event.key() == Qt.Key_Shift: # self.setDragMode(QGraphicsView.NoDrag) if self.time_of_first_shift < 0: self.time_of_first_shift = time.time() * 1000 else: if 1000 * time.time() - self.time_of_first_shift < 500: self.double_shift.emit() self._allow_zoom = False self.time_of_first_shift = -1 if event.key() == Qt.Key_Escape: self.escape_pressed.emit() self._allow_zoom = True elif event.key() == Qt.Key_Space: self.space_pressed.emit() elif event.key() == Qt.Key_Tab: self.tab_pressed.emit() QGraphicsView.keyReleaseEvent(self, event)
# def allow_zoom(self, allow: bool): # self._allow_zoom = allow # self.horizontalScrollBar().setEnabled(allow) # self.verticalScrollBar().setEnabled(allow)