"""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)