""" Multispectral Analysis Panel Panel for displaying multispectral camera analysis (coming soon feature). """ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy from PyQt5.QtCore import Qt from PyQt5.QtGui import QFont, QPixmap, QImage, QCursor from ui.widgets.panel_header import PanelHeader from ui.widgets.coming_soon_overlay import ComingSoonOverlay from ui.dialogs.image_preview_dialog import ImagePreviewDialog class MultispectralPanel(QWidget): """ Panel for multispectral camera analysis. Currently shows "COMING SOON" placeholder for future camera integration. """ def __init__(self, parent=None): super().__init__(parent) 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: #8e44ad;") header_layout = QHBoxLayout(header) header_layout.setContentsMargins(10, 0, 10, 0) header_layout.setSpacing(0) title = QLabel("Multispectral Analysis") 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) # Content area self.content = QWidget() self.content.setMinimumSize(250, 250) # content.setMaximumSize(400, 400) self.content.setStyleSheet(""" background-color: #8e44ad; border: 1px solid #9b59b6; border-top: none; """) content_layout = QVBoxLayout(self.content) content_layout.setAlignment(Qt.AlignCenter) content_layout.setSpacing(5) # Image display label (initially hidden) self.image_label = QLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setScaledContents(False) # We'll scale manually for better control self.image_label.setMinimumSize(250, 250) self.image_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.image_label.setStyleSheet(""" QLabel { background-color: #2c3e50; border: 2px solid #34495e; } """) self.image_label.hide() self.image_label.setCursor(QCursor(Qt.PointingHandCursor)) self.image_label.mousePressEvent = self._on_image_clicked self.current_pixmap = None # Store the original pixmap for dialog content_layout.addWidget(self.image_label, 1) # Give it stretch factor # Main text container (shown by default) self.text_container = QWidget() text_layout = QVBoxLayout(self.text_container) text_layout.setAlignment(Qt.AlignCenter) text_layout.setSpacing(2) # Spectral data text data_label = QLabel("8-Band Spectral Data") data_label.setFont(QFont("Arial", 12)) data_label.setStyleSheet("color: #e8daef;") data_label.setAlignment(Qt.AlignCenter) text_layout.addWidget(data_label) # NIR enhancement text enhancement_label = QLabel("NIR Enhancement Active\n(Coming soon)") enhancement_label.setFont(QFont("Arial", 10)) enhancement_label.setStyleSheet("color: #d5a6df;") enhancement_label.setAlignment(Qt.AlignCenter) text_layout.addWidget(enhancement_label) content_layout.addWidget(self.text_container) # Band selection area bands_frame = QWidget() bands_frame.setMaximumHeight(40) bands_layout = QHBoxLayout(bands_frame) bands_layout.setContentsMargins(10, 5, 10, 5) bands_label = QLabel("Active Bands:") bands_label.setStyleSheet("font-weight: bold; font-size: 12px;") bands_layout.addWidget(bands_label) bands_data = [ ("680nm", "#e74c3c"), ("750nm", "#f39c12"), ("850nm", "#27ae60"), ("950nm", "#3498db") ] for band_name, color in bands_data: band_frame = QWidget() band_layout = QHBoxLayout(band_frame) band_layout.setContentsMargins(0, 0, 0, 0) band_layout.setSpacing(5) color_box = QWidget() color_box.setFixedSize(20, 12) color_box.setStyleSheet(f"background-color: {color};") name_label = QLabel(band_name) name_label.setStyleSheet("font-size: 12px;") band_layout.addWidget(color_box) band_layout.addWidget(name_label) bands_layout.addWidget(band_frame) bands_layout.addStretch() layout.addWidget(header) layout.addWidget(self.content, 1) layout.addWidget(bands_frame, 0) # Tooltip self.setToolTip("Multispectral camera analysis - Coming with hardware integration") def set_image(self, pixmap: QPixmap): """Display an image in the panel.""" if pixmap and not pixmap.isNull(): # Store the original pixmap for dialog display self.current_pixmap = pixmap # Show the image label self.image_label.show() self.text_container.hide() # Update the pixmap - use a timer to ensure layout is complete from PyQt5.QtCore import QTimer QTimer.singleShot(50, self._update_image_display) # Also try immediate update in case widget is already sized self._update_image_display() # Update tooltip to indicate clickability self.image_label.setToolTip("Click to view full-size image") def _update_image_display(self): """Update the image display with proper scaling.""" if self.current_pixmap and not self.current_pixmap.isNull() and self.image_label.isVisible(): # Get the current size of the label label_size = self.image_label.size() if label_size.width() <= 0 or label_size.height() <= 0: # If not yet sized, use minimum size label_size = self.image_label.minimumSize() # Calculate scaled size maintaining aspect ratio scaled_pixmap = self.current_pixmap.scaled( label_size.width(), label_size.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(scaled_pixmap) def resizeEvent(self, event): """Handle resize events to update image scaling.""" super().resizeEvent(event) if self.current_pixmap and not self.current_pixmap.isNull(): # Use QTimer to update after layout is complete from PyQt5.QtCore import QTimer QTimer.singleShot(10, self._update_image_display) def update_image(self, pixmap: QPixmap): """Update the displayed image (alias for set_image).""" self.set_image(pixmap) def clear(self): """Clear the image display and show default text.""" self.image_label.clear() self.image_label.hide() self.text_container.show() self.current_pixmap = None def _on_image_clicked(self, event): """Handle click on image to show full-size dialog.""" if self.current_pixmap and not self.current_pixmap.isNull(): dialog = ImagePreviewDialog( self.current_pixmap, title="Multispectral Analysis - Grad-CAM Visualization", parent=self ) dialog.exec_() def _create_band_indicator(self, wavelength: str, color: str) -> QWidget: """Create a band indicator widget.""" widget = QWidget() layout = QHBoxLayout(widget) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) # Color box color_box = QLabel() color_box.setFixedSize(20, 12) color_box.setStyleSheet(f"background-color: {color}; border: 1px solid #2c3e50;") layout.addWidget(color_box) # Wavelength label wavelength_label = QLabel(wavelength) wavelength_label.setFont(QFont("Arial", 8)) wavelength_label.setStyleSheet("color: #2c3e50;") layout.addWidget(wavelength_label) return widget