"""Large image of the hovered card, with a text fallback while it downloads.""" from __future__ import annotations from PySide6.QtCore import QSize, Qt, Signal from PySide6.QtGui import QMouseEvent, QPixmap, QResizeEvent from PySide6.QtWidgets import QHBoxLayout, QLabel, QSizePolicy, QToolButton, QVBoxLayout, QWidget from ..carddb import CardDB from ..images import ImageCache class CardPreview(QWidget): cleared = Signal() def __init__(self, cards: CardDB, images: ImageCache, parent=None): super().__init__(parent) self.cards = cards self.images = images self.grp_id: int | None = None self._pixmap: QPixmap | None = None self.image = QLabel() self.image.setAlignment(Qt.AlignmentFlag.AlignCenter) self.image.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Ignored) self.image.setMinimumSize(200, 280) self.caption = QLabel() self.caption.setWordWrap(True) self.caption.setAlignment(Qt.AlignmentFlag.AlignCenter) self.close_btn = QToolButton() self.close_btn.setText("✕") self.close_btn.setToolTip("Stop previewing this card (Esc, or click the image)") self.close_btn.clicked.connect(self.clear) top = QHBoxLayout() top.addStretch(1) top.addWidget(self.close_btn) lay = QVBoxLayout(self) lay.setContentsMargins(4, 4, 4, 4) lay.addLayout(top) lay.addWidget(self.image, 1) lay.addWidget(self.caption) images.image_ready.connect(self._on_image_ready) self.clear() def clear(self) -> None: """Back to the empty state.""" was_showing = self.grp_id is not None self.grp_id = None self.caption.setText("") self._show_placeholder("Hover a card to preview it") self.close_btn.setVisible(False) if was_showing: self.cleared.emit() def mousePressEvent(self, event: QMouseEvent) -> None: if event.button() == Qt.MouseButton.LeftButton and self.grp_id is not None: self.clear() return super().mousePressEvent(event) def show_card(self, grp_id: int) -> None: if grp_id == self.grp_id: return self.grp_id = grp_id self.close_btn.setVisible(True) info = self.cards.get(grp_id) details = [info.type_line] if info.power or info.toughness: details.append(f"{info.power}/{info.toughness}") if info.set_code: details.append(f"{info.set_code} #{info.collector_number}") self.caption.setText(f"{info.name}
{' · '.join(d for d in details if d)}") pm = self.images.pixmap(grp_id) if pm is not None: self._pixmap = pm self._rescale() elif self.images.is_failed(grp_id): self._show_placeholder("No image available") else: self._show_placeholder("Loading image…") def _show_placeholder(self, text: str) -> None: self._pixmap = None self.image.setPixmap(QPixmap()) self.image.setText(text) def _on_image_ready(self, grp_id: int) -> None: if grp_id == self.grp_id: self.grp_id = None self.show_card(grp_id) def _rescale(self) -> None: if self._pixmap is None: return self.image.setPixmap( self._pixmap.scaled(self.image.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) ) def resizeEvent(self, event: QResizeEvent) -> None: super().resizeEvent(event) self._rescale() def sizeHint(self) -> QSize: return QSize(320, 600)