""" Zentrales Canvas-Widget: zeigt das Logo mit Zoom, Pan und Rasterlinien an. """ from __future__ import annotations from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem from PySide6.QtCore import Qt, Signal, QPointF from PySide6.QtGui import ( QPainter, QPen, QColor, QPixmap, QWheelEvent, QMouseEvent, ) class LogoCanvas(QGraphicsView): zoom_changed = Signal(float) def __init__(self, parent=None): super().__init__(parent) self._scene = QGraphicsScene(self) self.setScene(self._scene) self._pixmap_item: QGraphicsPixmapItem | None = None self._overlay_item: QGraphicsPixmapItem | None = None self._zoom = 1.0 self._pan_active = False self._pan_start = QPointF() self.setRenderHints( QPainter.RenderHint.Antialiasing | QPainter.RenderHint.SmoothPixmapTransform ) self.setDragMode(QGraphicsView.DragMode.NoDrag) self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse) self.setBackgroundBrush(QColor("#2b2b2b")) self.setMinimumSize(400, 300) self._draw_checkerboard() def _draw_checkerboard(self): """Schachbrettmuster als Transparenz-Indikator.""" self.setStyleSheet(""" QGraphicsView { background-color: #2b2b2b; } """) def set_original_image(self, pixmap: QPixmap): """Zeigt das Original-PNG an.""" if self._pixmap_item: self._scene.removeItem(self._pixmap_item) self._pixmap_item = self._scene.addPixmap(pixmap) self._pixmap_item.setZValue(0) self.fitInView(self._pixmap_item, Qt.AspectRatioMode.KeepAspectRatio) self._zoom = self.transform().m11() self.zoom_changed.emit(self._zoom) def set_overlay(self, pixmap: QPixmap): """Zeigt die gerenderten Vektorpfade als Overlay an.""" if self._overlay_item: self._scene.removeItem(self._overlay_item) self._overlay_item = self._scene.addPixmap(pixmap) self._overlay_item.setZValue(1) self._overlay_item.setOpacity(0.85) def clear_overlay(self): if self._overlay_item: self._scene.removeItem(self._overlay_item) self._overlay_item = None # --- Zoom via Mausrad --- def wheelEvent(self, event: QWheelEvent): factor = 1.15 if event.angleDelta().y() > 0 else 1 / 1.15 self._zoom *= factor self.scale(factor, factor) self.zoom_changed.emit(self._zoom) # --- Pan via mittlere Maustaste oder Leertaste + Links --- def mousePressEvent(self, event: QMouseEvent): if event.button() == Qt.MouseButton.MiddleButton: self._pan_active = True self._pan_start = event.position() self.setCursor(Qt.CursorShape.ClosedHandCursor) else: super().mousePressEvent(event) def mouseMoveEvent(self, event: QMouseEvent): if self._pan_active: delta = event.position() - self._pan_start self._pan_start = event.position() self.horizontalScrollBar().setValue( self.horizontalScrollBar().value() - int(delta.x()) ) self.verticalScrollBar().setValue( self.verticalScrollBar().value() - int(delta.y()) ) else: super().mouseMoveEvent(event) def mouseReleaseEvent(self, event: QMouseEvent): if event.button() == Qt.MouseButton.MiddleButton: self._pan_active = False self.setCursor(Qt.CursorShape.ArrowCursor) else: super().mouseReleaseEvent(event) def set_zoom(self, zoom: float): factor = zoom / self._zoom self._zoom = zoom self.scale(factor, factor) self.zoom_changed.emit(self._zoom) def fit_to_view(self): if self._pixmap_item: self.fitInView(self._pixmap_item, Qt.AspectRatioMode.KeepAspectRatio) self._zoom = self.transform().m11() self.zoom_changed.emit(self._zoom)