""" Audio Spectrogram Panel Panel for displaying audio spectrogram visualization. """ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QSizePolicy from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtGui import QFont, QPixmap, QCursor from ui.widgets.panel_header import PanelHeader class ClickableLabel(QLabel): """Label that emits a signal when clicked.""" clicked = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.setCursor(QCursor(Qt.PointingHandCursor)) def mousePressEvent(self, event): """Emit clicked signal on mouse press.""" self.clicked.emit() super().mousePressEvent(event) class AudioSpectrogramPanel(QWidget): """ Panel for audio spectrogram display and settings. Signals: spectrogram_clicked: Emitted when spectrogram is clicked for enlarged view """ spectrogram_clicked = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.current_pixmap = None self.current_audio_path = None self.init_ui() def init_ui(self): """Initialize the panel UI.""" # Set size policy to expand equally self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # Main panel container with card styling self.setStyleSheet(""" QWidget { background-color: white; border: 1px solid #ddd; } """) # Header header = QWidget() header.setFixedHeight(25) header.setStyleSheet("background-color: #16a085;") header_layout = QHBoxLayout(header) header_layout.setContentsMargins(10, 0, 10, 0) header_layout.setSpacing(0) title = QLabel("Audio Spectrogram") title.setStyleSheet("color: white; font-weight: bold; font-size: 16px;") status_indicator = QWidget() status_indicator.setFixedSize(10, 10) status_indicator.setStyleSheet("background-color: #27ae60; border-radius: 5px;") header_layout.addWidget(title) header_layout.addStretch() header_layout.addWidget(status_indicator) # Visualization area visualization = QWidget() visualization.setMinimumSize(250, 250) # visualization.setMaximumSize(500, 500) visualization.setStyleSheet(""" background-color: #2c3e50; border: 1px solid #34495e; border-top: none; """) visualization_layout = QVBoxLayout(visualization) visualization_layout.setContentsMargins(0, 0, 0, 0) visualization_layout.setSpacing(0) # Frequency range label range_label = QLabel("0-8kHz Range") range_label.setStyleSheet("color: #bdc3c7; font-size: 12px;") range_label.setAlignment(Qt.AlignCenter) # range_label.setFixedHeight(15) visualization_layout.addWidget(range_label) # Spectrogram display (clickable) self.spectrogram_label = ClickableLabel() self.spectrogram_label.setAlignment(Qt.AlignCenter) self.spectrogram_label.setMinimumHeight(200) self.spectrogram_label.setScaledContents(False) self.spectrogram_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.spectrogram_label.setStyleSheet(""" QLabel { background-color: #2c3e50; border: none; color: #bdc3c7; } QLabel:hover { background-color: #34495e; } """) self.spectrogram_label.setText("No audio loaded\n\nClick to view details") self.spectrogram_label.setToolTip("Click to enlarge and view audio details") self.spectrogram_label.clicked.connect(self._on_spectrogram_clicked) visualization_layout.addWidget(self.spectrogram_label, 1) layout.addWidget(header) layout.addWidget(visualization, 1) def update_spectrogram(self, pixmap: QPixmap, sample_rate: float = 44100, duration: float = 0, audio_path: str = None): """ Update the spectrogram display. Args: pixmap: Spectrogram image as QPixmap sample_rate: Audio sample rate in Hz duration: Audio duration in seconds audio_path: Path to the audio file for playback """ # Store original pixmap and audio path for enlargement self.current_pixmap = pixmap self.current_audio_path = audio_path # Force widget to update geometry first self.spectrogram_label.updateGeometry() # Get actual dimensions, with better fallbacks label_width = self.spectrogram_label.width() label_height = self.spectrogram_label.height() # Use parent widget size if label size not yet determined if label_width < 100: parent_width = self.width() if self.width() > 100 else 380 label_width = parent_width - 20 if label_height < 100: label_height = 220 # Scale to fit width while preserving aspect ratio scaled_pixmap = pixmap.scaledToWidth( int(label_width), Qt.SmoothTransformation ) self.spectrogram_label.setPixmap(scaled_pixmap) def clear_spectrogram(self): """Clear the spectrogram display.""" self.current_pixmap = None self.current_audio_path = None self.spectrogram_label.clear() self.spectrogram_label.setText("No audio loaded\n\nClick to view details") def _on_spectrogram_clicked(self): """Handle spectrogram click to show enlarged view with waveform and playback.""" if self.current_pixmap is not None: from ui.dialogs.spectrogram_preview_dialog import SpectrogramPreviewDialog dialog = SpectrogramPreviewDialog( self.current_pixmap, self.current_audio_path, self ) dialog.exec_()