| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- """
- Maturity Control Panel
- Control panel for multispectral maturity testing with device selection and parameters.
- """
- from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
- QPushButton, QComboBox, QCheckBox)
- from PyQt5.QtCore import Qt, pyqtSignal
- from PyQt5.QtGui import QFont
- from ui.widgets.panel_header import PanelHeader
- from ui.widgets.mode_toggle import ModeToggle
- from ui.widgets.parameter_slider import ParameterSlider
- class MaturityControlPanel(QWidget):
- """
- Control panel for multispectral maturity testing.
-
- Signals:
- run_test_clicked: Emitted when RUN TEST button is clicked (live mode)
- open_file_clicked: Emitted when OPEN FILE is clicked (file mode)
- stop_clicked: Emitted when STOP button is clicked
- reset_clicked: Emitted when RESET button is clicked
- mode_changed: Emitted when test mode changes (str: 'live' or 'file')
- """
-
- run_test_clicked = pyqtSignal()
- open_file_clicked = pyqtSignal()
- stop_clicked = pyqtSignal()
- reset_clicked = pyqtSignal()
- mode_changed = pyqtSignal(str)
-
- def __init__(self, parent=None):
- super().__init__(parent)
- self.current_mode = "file"
- self.init_ui()
-
- def init_ui(self):
- """Initialize the control panel UI."""
- 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: #34495e;")
- header_layout = QHBoxLayout(header)
- header_layout.setContentsMargins(10, 0, 10, 0)
- header_layout.setSpacing(0)
-
- title = QLabel("Control Panel")
- title.setStyleSheet("color: white; font-weight: bold; font-size: 16px;")
-
- header_layout.addWidget(title)
-
- # Content area
- content = QWidget()
- content.setStyleSheet("""
- background-color: white;
- border: none;
- """)
-
- content_layout = QVBoxLayout(content)
- content_layout.setSpacing(10)
- content_layout.setContentsMargins(10, 10, 10, 10)
-
- # Camera Selection
- camera_label = QLabel("Camera Selection:")
- camera_label.setFont(QFont("Arial", 9, QFont.Bold))
- camera_label.setStyleSheet("color: #2c3e50;")
- content_layout.addWidget(camera_label)
-
- self.camera_combo = QComboBox()
- self.camera_combo.addItems(["Multispectral Camera (MSC2-NIR8-1-A) ▼"])
- self.camera_combo.setFont(QFont("Arial", 9))
- self.camera_combo.setFixedHeight(25)
- self.camera_combo.setEnabled(False)
- self.camera_combo.setToolTip("Multispectral camera selection - Coming with hardware integration")
- self.camera_combo.setStyleSheet("""
- QComboBox {
- background-color: #ecf0f1;
- border: 1px solid #bdc3c7;
- padding: 3px;
- color: #7f8c8d;
- }
- """)
- content_layout.addWidget(self.camera_combo)
-
- # Band Selection (for future use)
- band_label = QLabel("Active Bands:")
- band_label.setFont(QFont("Arial", 9, QFont.Bold))
- band_label.setStyleSheet("color: #2c3e50;")
- content_layout.addWidget(band_label)
-
- self.band_combo = QComboBox()
- self.band_combo.addItems(["All 8 Bands ▼"])
- self.band_combo.setFont(QFont("Arial", 9))
- self.band_combo.setFixedHeight(25)
- self.band_combo.setEnabled(False)
- self.band_combo.setToolTip("Band selection - Coming in future update")
- self.band_combo.setStyleSheet("""
- QComboBox {
- background-color: #ecf0f1;
- border: 1px solid #bdc3c7;
- padding: 3px;
- color: #7f8c8d;
- }
- """)
- content_layout.addWidget(self.band_combo)
-
- # Parameters Section
- params_label = QLabel("Parameters:")
- params_label.setFont(QFont("Arial", 9, QFont.Bold))
- params_label.setStyleSheet("color: #2c3e50; margin-top: 5px;")
- content_layout.addWidget(params_label)
-
- # Mask band slider (disabled - coming soon)
- self.mask_band_slider = ParameterSlider("Mask Band", 0, 7, 4, "Band {}")
- self.mask_band_slider.setEnabled(False)
- self.mask_band_slider.setToolTip("Band index for masking (default: 4, 860nm)")
- content_layout.addWidget(self.mask_band_slider)
-
- # Preprocessing Options
- preproc_label = QLabel("Preprocessing:")
- preproc_label.setFont(QFont("Arial", 9, QFont.Bold))
- preproc_label.setStyleSheet("color: #2c3e50; margin-top: 5px;")
- content_layout.addWidget(preproc_label)
-
- # Checkboxes
- self.normalize_checkbox = QCheckBox("Normalize Spectral Data")
- self.normalize_checkbox.setFont(QFont("Arial", 9))
- self.normalize_checkbox.setChecked(True)
- self.normalize_checkbox.setEnabled(False)
- self.normalize_checkbox.setToolTip("Spectral data normalization (always enabled)")
- content_layout.addWidget(self.normalize_checkbox)
-
- self.bg_subtract_checkbox = QCheckBox("Background Subtraction")
- self.bg_subtract_checkbox.setFont(QFont("Arial", 9))
- self.bg_subtract_checkbox.setEnabled(False)
- self.bg_subtract_checkbox.setToolTip("Background subtraction - Coming soon")
- content_layout.addWidget(self.bg_subtract_checkbox)
-
- self.gradcam_checkbox = QCheckBox("Generate Grad-CAM")
- self.gradcam_checkbox.setFont(QFont("Arial", 9))
- self.gradcam_checkbox.setChecked(True)
- self.gradcam_checkbox.setToolTip("Generate Grad-CAM visualization overlay")
- content_layout.addWidget(self.gradcam_checkbox)
-
- # Test Mode Toggle
- mode_label = QLabel("Test Mode:")
- mode_label.setFont(QFont("Arial", 9, QFont.Bold))
- mode_label.setStyleSheet("color: #2c3e50; margin-top: 5px;")
- content_layout.addWidget(mode_label)
-
- self.mode_toggle = ModeToggle()
- self.mode_toggle.mode_changed.connect(self._on_mode_changed)
- content_layout.addWidget(self.mode_toggle)
-
- # Control Buttons
- # RUN TEST button
- self.run_btn = QPushButton("OPEN FILE")
- self.run_btn.setFont(QFont("Arial", 11, QFont.Bold))
- self.run_btn.setFixedHeight(32)
- self.run_btn.setStyleSheet("""
- QPushButton {
- background-color: #8e44ad;
- border: 2px solid #7d3c98;
- color: white;
- }
- QPushButton:hover {
- background-color: #7d3c98;
- }
- QPushButton:pressed {
- background-color: #6c3483;
- }
- """)
- self.run_btn.clicked.connect(self._on_primary_action_clicked)
- self.run_btn.setToolTip("Select a multispectral TIFF file to analyze maturity")
- content_layout.addWidget(self.run_btn)
-
- # STOP and RESET buttons
- bottom_buttons = QHBoxLayout()
- bottom_buttons.setSpacing(10)
-
- self.stop_btn = QPushButton("STOP")
- self.stop_btn.setFont(QFont("Arial", 8, QFont.Bold))
- self.stop_btn.setFixedHeight(22)
- self.stop_btn.setStyleSheet("""
- QPushButton {
- background-color: #e74c3c;
- border: 1px solid #c0392b;
- color: white;
- }
- QPushButton:hover {
- background-color: #c0392b;
- }
- """)
- self.stop_btn.clicked.connect(self.stop_clicked.emit)
- self.stop_btn.setEnabled(False)
- bottom_buttons.addWidget(self.stop_btn)
-
- self.reset_btn = QPushButton("RESET")
- self.reset_btn.setFont(QFont("Arial", 8, QFont.Bold))
- self.reset_btn.setFixedHeight(22)
- self.reset_btn.setStyleSheet("""
- QPushButton {
- background-color: #f39c12;
- border: 1px solid #e67e22;
- color: white;
- }
- QPushButton:hover {
- background-color: #e67e22;
- }
- """)
- self.reset_btn.clicked.connect(self.reset_clicked.emit)
- bottom_buttons.addWidget(self.reset_btn)
-
- content_layout.addLayout(bottom_buttons)
- content_layout.addStretch()
-
- layout.addWidget(header)
- layout.addWidget(content)
-
- # Initialize primary action label based on default mode
- self._update_primary_action_label()
-
- def set_processing(self, is_processing: bool):
- """
- Set the processing state.
-
- Args:
- is_processing: Whether processing is active
- """
- self.run_btn.setEnabled(not is_processing)
- self.stop_btn.setEnabled(is_processing)
-
- if is_processing:
- self.run_btn.setText("PROCESSING...")
- else:
- self._update_primary_action_label()
- def _on_mode_changed(self, mode: str):
- """Handle mode change from the toggle."""
- self.current_mode = mode
- self.mode_changed.emit(mode)
- self._update_primary_action_label()
- def _update_primary_action_label(self):
- """Update primary action button label and tooltip based on mode."""
- if getattr(self, 'current_mode', 'file') == 'file':
- self.run_btn.setText("OPEN FILE")
- self.run_btn.setToolTip("Open a multispectral TIFF file to analyze maturity")
- else:
- self.run_btn.setText("RUN TEST")
- self.run_btn.setToolTip("Run live maturity test (coming soon)")
- def _on_primary_action_clicked(self):
- """Emit the appropriate signal based on current mode."""
- if getattr(self, 'current_mode', 'file') == 'file':
- self.open_file_clicked.emit()
- else:
- self.run_test_clicked.emit()
|