| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- """
- Ripeness Control Panel
- Control panel for ripeness 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 RipenessControlPanel(QWidget):
- """
- Control panel for ripeness 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 (Primary) ▼"])
- self.camera_combo.setFont(QFont("Arial", 9))
- self.camera_combo.setFixedHeight(25)
- self.camera_combo.setEnabled(False)
- self.camera_combo.setToolTip("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)
-
- # Microphone Selection
- mic_label = QLabel("Microphone:")
- mic_label.setFont(QFont("Arial", 9, QFont.Bold))
- mic_label.setStyleSheet("color: #2c3e50;")
- content_layout.addWidget(mic_label)
-
- self.mic_combo = QComboBox()
- self.mic_combo.addItems([
- "Piezo Sensor Array ▼",
- "Built-in Microphone",
- "USB Audio Device"
- ])
- self.mic_combo.setFont(QFont("Arial", 9))
- self.mic_combo.setFixedHeight(25)
- self.mic_combo.setStyleSheet("""
- QComboBox {
- background-color: #ecf0f1;
- border: 1px solid #bdc3c7;
- padding: 3px;
- }
- """)
- content_layout.addWidget(self.mic_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)
-
- # Exposure slider (disabled - coming soon)
- self.exposure_slider = ParameterSlider("Exposure", 1, 250, 125, "1/{}s")
- self.exposure_slider.setEnabled(False)
- self.exposure_slider.setToolTip("Exposure control - Coming in future update")
- content_layout.addWidget(self.exposure_slider)
-
- # Gain slider (disabled - coming soon)
- self.gain_slider = ParameterSlider("Gain", 100, 1600, 400, "ISO {}")
- self.gain_slider.setEnabled(False)
- self.gain_slider.setToolTip("Gain control - Coming in future update")
- content_layout.addWidget(self.gain_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.setEnabled(False)
- self.normalize_checkbox.setToolTip("Spectral data normalization - Coming soon")
- content_layout.addWidget(self.normalize_checkbox)
-
- self.denoise_checkbox = QCheckBox("Denoise Audio Signal")
- self.denoise_checkbox.setFont(QFont("Arial", 9))
- self.denoise_checkbox.setChecked(True)
- self.denoise_checkbox.setToolTip("Apply noise reduction to audio signal")
- content_layout.addWidget(self.denoise_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)
-
- # 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("RUN TEST")
- self.run_btn.setFont(QFont("Arial", 11, QFont.Bold))
- self.run_btn.setFixedHeight(32)
- self.run_btn.setStyleSheet("""
- QPushButton {
- background-color: #27ae60;
- border: 2px solid #229954;
- color: white;
- }
- QPushButton:hover {
- background-color: #229954;
- }
- QPushButton:pressed {
- background-color: #1e8449;
- }
- """)
- self.run_btn.clicked.connect(self._on_primary_action_clicked)
- self.run_btn.setToolTip("Select an audio file to analyze ripeness")
- 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 an audio file to analyze ripeness")
- else:
- self.run_btn.setText("RUN TEST")
- self.run_btn.setToolTip("Run live ripeness 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()
|