""" Image Preview Dialog Dialog for displaying enlarged view of images/spectrograms with zoom functionality. """ from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QPushButton, QHBoxLayout, QScrollArea from PyQt5.QtCore import Qt from PyQt5.QtGui import QPixmap, QFont class ImagePreviewDialog(QDialog): """ Dialog for displaying enlarged image previews with zoom functionality. Features: - Enlarged view of spectrograms/images - Zoom in/out with buttons or keyboard (+/- or scroll wheel) - Click anywhere or press ESC to close - Clean, professional appearance """ def __init__(self, pixmap: QPixmap, title: str = "Preview", parent=None): """ Initialize the preview dialog. Args: pixmap: QPixmap to display title: Dialog title parent: Parent widget """ super().__init__(parent) self.original_pixmap = pixmap self.setWindowTitle(title) self.setModal(True) self.zoom_level = 1.0 self.min_zoom = 0.25 self.max_zoom = 4.0 self.init_ui() def init_ui(self): """Initialize the dialog UI.""" layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # Header header = QLabel(self.windowTitle()) header.setAlignment(Qt.AlignCenter) header.setStyleSheet(""" QLabel { background-color: #2c3e50; color: white; font-weight: bold; font-size: 12px; padding: 10px; } """) layout.addWidget(header) # Scroll area for image with zoom scroll_area = QScrollArea() scroll_area.setStyleSheet(""" QScrollArea { background-color: #2c3e50; border: none; } """) scroll_area.setWidgetResizable(True) # Image display label self.image_label = QLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setStyleSheet(""" QLabel { background-color: #2c3e50; padding: 20px; } """) # Initial scaling to fit dialog (max 1200x800) initial_pixmap = self.original_pixmap.scaled( 1200, 800, Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(initial_pixmap) self.zoom_level = 1.0 self.current_display_pixmap = initial_pixmap scroll_area.setWidget(self.image_label) layout.addWidget(scroll_area) # Control buttons and zoom info controls_layout = QHBoxLayout() controls_layout.setContentsMargins(10, 10, 10, 10) controls_layout.setSpacing(10) # Zoom out button zoom_out_button = QPushButton("🔍− Zoom Out") zoom_out_button.setFont(QFont("Arial", 10)) zoom_out_button.setFixedHeight(35) zoom_out_button.setStyleSheet(""" QPushButton { background-color: #34495e; color: white; border: none; font-weight: bold; border-radius: 4px; } QPushButton:hover { background-color: #2c3e50; } QPushButton:pressed { background-color: #1a252f; } """) zoom_out_button.clicked.connect(self.zoom_out) controls_layout.addWidget(zoom_out_button) # Zoom level label self.zoom_label = QLabel("100%") self.zoom_label.setAlignment(Qt.AlignCenter) self.zoom_label.setFont(QFont("Arial", 10, QFont.Bold)) self.zoom_label.setStyleSheet("color: white; min-width: 60px;") controls_layout.addWidget(self.zoom_label) # Zoom in button zoom_in_button = QPushButton("Zoom In 🔍+") zoom_in_button.setFont(QFont("Arial", 10)) zoom_in_button.setFixedHeight(35) zoom_in_button.setStyleSheet(""" QPushButton { background-color: #34495e; color: white; border: none; font-weight: bold; border-radius: 4px; } QPushButton:hover { background-color: #2c3e50; } QPushButton:pressed { background-color: #1a252f; } """) zoom_in_button.clicked.connect(self.zoom_in) controls_layout.addWidget(zoom_in_button) # Reset zoom button reset_button = QPushButton("Reset (R)") reset_button.setFont(QFont("Arial", 10)) reset_button.setFixedHeight(35) reset_button.setStyleSheet(""" QPushButton { background-color: #7f8c8d; color: white; border: none; font-weight: bold; border-radius: 4px; } QPushButton:hover { background-color: #6c7a7d; } QPushButton:pressed { background-color: #5a6667; } """) reset_button.clicked.connect(self.reset_zoom) controls_layout.addWidget(reset_button) # Close button close_button = QPushButton("Close (ESC)") close_button.setFont(QFont("Arial", 10)) close_button.setFixedHeight(35) close_button.setStyleSheet(""" QPushButton { background-color: #e74c3c; color: white; border: none; font-weight: bold; border-radius: 4px; } QPushButton:hover { background-color: #c0392b; } QPushButton:pressed { background-color: #a93226; } """) close_button.clicked.connect(self.accept) controls_layout.addWidget(close_button) layout.addLayout(controls_layout) # Set dialog size self.resize(1280, 900) def zoom_in(self): """Increase zoom level.""" if self.zoom_level < self.max_zoom: self.zoom_level *= 1.25 if self.zoom_level > self.max_zoom: self.zoom_level = self.max_zoom self._update_display() def zoom_out(self): """Decrease zoom level.""" if self.zoom_level > self.min_zoom: self.zoom_level /= 1.25 if self.zoom_level < self.min_zoom: self.zoom_level = self.min_zoom self._update_display() def reset_zoom(self): """Reset to initial zoom level.""" self.zoom_level = 1.0 # Re-scale to fit dialog scaled_pixmap = self.original_pixmap.scaled( 1200, 800, Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(scaled_pixmap) self.current_display_pixmap = scaled_pixmap self._update_zoom_label() def _update_display(self): """Update the displayed image based on current zoom level.""" # Calculate new size based on original pixmap and zoom level new_width = int(self.original_pixmap.width() * self.zoom_level) new_height = int(self.original_pixmap.height() * self.zoom_level) # Scale the image scaled_pixmap = self.original_pixmap.scaled( new_width, new_height, Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(scaled_pixmap) self.current_display_pixmap = scaled_pixmap self._update_zoom_label() def _update_zoom_label(self): """Update zoom percentage label.""" zoom_percentage = int(self.zoom_level * 100) self.zoom_label.setText(f"{zoom_percentage}%") def mousePressEvent(self, event): """Close dialog on mouse click outside the scroll area.""" # Only close if clicking on dialog background, not on scroll area if not self.image_label.geometry().contains(self.mapFromGlobal(event.globalPos())): self.accept() def wheelEvent(self, event): """Handle mouse wheel for zooming.""" if event.angleDelta().y() > 0: self.zoom_in() else: self.zoom_out() def keyPressEvent(self, event): """Handle keyboard shortcuts for zooming.""" if event.key() == Qt.Key_Escape: self.accept() elif event.key() == Qt.Key_Plus or event.key() == Qt.Key_Equal: self.zoom_in() elif event.key() == Qt.Key_Minus: self.zoom_out() elif event.key() == Qt.Key_R: self.reset_zoom() else: super().keyPressEvent(event)