maturity_control_panel.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. """
  2. Maturity Control Panel
  3. Control panel for multispectral maturity testing with device selection and parameters.
  4. """
  5. from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
  6. QPushButton, QComboBox, QCheckBox)
  7. from PyQt5.QtCore import Qt, pyqtSignal
  8. from PyQt5.QtGui import QFont
  9. from ui.widgets.panel_header import PanelHeader
  10. from ui.widgets.mode_toggle import ModeToggle
  11. from ui.widgets.parameter_slider import ParameterSlider
  12. class MaturityControlPanel(QWidget):
  13. """
  14. Control panel for multispectral maturity testing.
  15. Signals:
  16. run_test_clicked: Emitted when RUN TEST button is clicked (live mode)
  17. open_file_clicked: Emitted when OPEN FILE is clicked (file mode)
  18. stop_clicked: Emitted when STOP button is clicked
  19. reset_clicked: Emitted when RESET button is clicked
  20. mode_changed: Emitted when test mode changes (str: 'live' or 'file')
  21. """
  22. run_test_clicked = pyqtSignal()
  23. open_file_clicked = pyqtSignal()
  24. stop_clicked = pyqtSignal()
  25. reset_clicked = pyqtSignal()
  26. mode_changed = pyqtSignal(str)
  27. def __init__(self, parent=None):
  28. super().__init__(parent)
  29. self.current_mode = "file"
  30. self.init_ui()
  31. def init_ui(self):
  32. """Initialize the control panel UI."""
  33. layout = QVBoxLayout(self)
  34. layout.setContentsMargins(0, 0, 0, 0)
  35. layout.setSpacing(0)
  36. # Main panel container with card styling
  37. self.setStyleSheet("""
  38. QWidget {
  39. background-color: white;
  40. border: 1px solid #ddd;
  41. }
  42. """)
  43. # Header
  44. header = QWidget()
  45. header.setFixedHeight(25)
  46. header.setStyleSheet("background-color: #34495e;")
  47. header_layout = QHBoxLayout(header)
  48. header_layout.setContentsMargins(10, 0, 10, 0)
  49. header_layout.setSpacing(0)
  50. title = QLabel("Control Panel")
  51. title.setStyleSheet("color: white; font-weight: bold; font-size: 16px;")
  52. header_layout.addWidget(title)
  53. # Content area
  54. content = QWidget()
  55. content.setStyleSheet("""
  56. background-color: white;
  57. border: none;
  58. """)
  59. content_layout = QVBoxLayout(content)
  60. content_layout.setSpacing(10)
  61. content_layout.setContentsMargins(10, 10, 10, 10)
  62. # Camera Selection
  63. camera_label = QLabel("Camera Selection:")
  64. camera_label.setFont(QFont("Arial", 9, QFont.Bold))
  65. camera_label.setStyleSheet("color: #2c3e50;")
  66. content_layout.addWidget(camera_label)
  67. self.camera_combo = QComboBox()
  68. self.camera_combo.addItems(["Multispectral Camera (MSC2-NIR8-1-A) ▼"])
  69. self.camera_combo.setFont(QFont("Arial", 9))
  70. self.camera_combo.setFixedHeight(25)
  71. self.camera_combo.setEnabled(False)
  72. self.camera_combo.setToolTip("Multispectral camera selection - Coming with hardware integration")
  73. self.camera_combo.setStyleSheet("""
  74. QComboBox {
  75. background-color: #ecf0f1;
  76. border: 1px solid #bdc3c7;
  77. padding: 3px;
  78. color: #7f8c8d;
  79. }
  80. """)
  81. content_layout.addWidget(self.camera_combo)
  82. # Band Selection (for future use)
  83. band_label = QLabel("Active Bands:")
  84. band_label.setFont(QFont("Arial", 9, QFont.Bold))
  85. band_label.setStyleSheet("color: #2c3e50;")
  86. content_layout.addWidget(band_label)
  87. self.band_combo = QComboBox()
  88. self.band_combo.addItems(["All 8 Bands ▼"])
  89. self.band_combo.setFont(QFont("Arial", 9))
  90. self.band_combo.setFixedHeight(25)
  91. self.band_combo.setEnabled(False)
  92. self.band_combo.setToolTip("Band selection - Coming in future update")
  93. self.band_combo.setStyleSheet("""
  94. QComboBox {
  95. background-color: #ecf0f1;
  96. border: 1px solid #bdc3c7;
  97. padding: 3px;
  98. color: #7f8c8d;
  99. }
  100. """)
  101. content_layout.addWidget(self.band_combo)
  102. # Parameters Section
  103. params_label = QLabel("Parameters:")
  104. params_label.setFont(QFont("Arial", 9, QFont.Bold))
  105. params_label.setStyleSheet("color: #2c3e50; margin-top: 5px;")
  106. content_layout.addWidget(params_label)
  107. # Mask band slider (disabled - coming soon)
  108. self.mask_band_slider = ParameterSlider("Mask Band", 0, 7, 4, "Band {}")
  109. self.mask_band_slider.setEnabled(False)
  110. self.mask_band_slider.setToolTip("Band index for masking (default: 4, 860nm)")
  111. content_layout.addWidget(self.mask_band_slider)
  112. # Preprocessing Options
  113. preproc_label = QLabel("Preprocessing:")
  114. preproc_label.setFont(QFont("Arial", 9, QFont.Bold))
  115. preproc_label.setStyleSheet("color: #2c3e50; margin-top: 5px;")
  116. content_layout.addWidget(preproc_label)
  117. # Checkboxes
  118. self.normalize_checkbox = QCheckBox("Normalize Spectral Data")
  119. self.normalize_checkbox.setFont(QFont("Arial", 9))
  120. self.normalize_checkbox.setChecked(True)
  121. self.normalize_checkbox.setEnabled(False)
  122. self.normalize_checkbox.setToolTip("Spectral data normalization (always enabled)")
  123. content_layout.addWidget(self.normalize_checkbox)
  124. self.bg_subtract_checkbox = QCheckBox("Background Subtraction")
  125. self.bg_subtract_checkbox.setFont(QFont("Arial", 9))
  126. self.bg_subtract_checkbox.setEnabled(False)
  127. self.bg_subtract_checkbox.setToolTip("Background subtraction - Coming soon")
  128. content_layout.addWidget(self.bg_subtract_checkbox)
  129. self.gradcam_checkbox = QCheckBox("Generate Grad-CAM")
  130. self.gradcam_checkbox.setFont(QFont("Arial", 9))
  131. self.gradcam_checkbox.setChecked(True)
  132. self.gradcam_checkbox.setToolTip("Generate Grad-CAM visualization overlay")
  133. content_layout.addWidget(self.gradcam_checkbox)
  134. # Test Mode Toggle
  135. mode_label = QLabel("Test Mode:")
  136. mode_label.setFont(QFont("Arial", 9, QFont.Bold))
  137. mode_label.setStyleSheet("color: #2c3e50; margin-top: 5px;")
  138. content_layout.addWidget(mode_label)
  139. self.mode_toggle = ModeToggle()
  140. self.mode_toggle.mode_changed.connect(self._on_mode_changed)
  141. content_layout.addWidget(self.mode_toggle)
  142. # Control Buttons
  143. # RUN TEST button
  144. self.run_btn = QPushButton("OPEN FILE")
  145. self.run_btn.setFont(QFont("Arial", 11, QFont.Bold))
  146. self.run_btn.setFixedHeight(32)
  147. self.run_btn.setStyleSheet("""
  148. QPushButton {
  149. background-color: #8e44ad;
  150. border: 2px solid #7d3c98;
  151. color: white;
  152. }
  153. QPushButton:hover {
  154. background-color: #7d3c98;
  155. }
  156. QPushButton:pressed {
  157. background-color: #6c3483;
  158. }
  159. """)
  160. self.run_btn.clicked.connect(self._on_primary_action_clicked)
  161. self.run_btn.setToolTip("Select a multispectral TIFF file to analyze maturity")
  162. content_layout.addWidget(self.run_btn)
  163. # STOP and RESET buttons
  164. bottom_buttons = QHBoxLayout()
  165. bottom_buttons.setSpacing(10)
  166. self.stop_btn = QPushButton("STOP")
  167. self.stop_btn.setFont(QFont("Arial", 8, QFont.Bold))
  168. self.stop_btn.setFixedHeight(22)
  169. self.stop_btn.setStyleSheet("""
  170. QPushButton {
  171. background-color: #e74c3c;
  172. border: 1px solid #c0392b;
  173. color: white;
  174. }
  175. QPushButton:hover {
  176. background-color: #c0392b;
  177. }
  178. """)
  179. self.stop_btn.clicked.connect(self.stop_clicked.emit)
  180. self.stop_btn.setEnabled(False)
  181. bottom_buttons.addWidget(self.stop_btn)
  182. self.reset_btn = QPushButton("RESET")
  183. self.reset_btn.setFont(QFont("Arial", 8, QFont.Bold))
  184. self.reset_btn.setFixedHeight(22)
  185. self.reset_btn.setStyleSheet("""
  186. QPushButton {
  187. background-color: #f39c12;
  188. border: 1px solid #e67e22;
  189. color: white;
  190. }
  191. QPushButton:hover {
  192. background-color: #e67e22;
  193. }
  194. """)
  195. self.reset_btn.clicked.connect(self.reset_clicked.emit)
  196. bottom_buttons.addWidget(self.reset_btn)
  197. content_layout.addLayout(bottom_buttons)
  198. content_layout.addStretch()
  199. layout.addWidget(header)
  200. layout.addWidget(content)
  201. # Initialize primary action label based on default mode
  202. self._update_primary_action_label()
  203. def set_processing(self, is_processing: bool):
  204. """
  205. Set the processing state.
  206. Args:
  207. is_processing: Whether processing is active
  208. """
  209. self.run_btn.setEnabled(not is_processing)
  210. self.stop_btn.setEnabled(is_processing)
  211. if is_processing:
  212. self.run_btn.setText("PROCESSING...")
  213. else:
  214. self._update_primary_action_label()
  215. def _on_mode_changed(self, mode: str):
  216. """Handle mode change from the toggle."""
  217. self.current_mode = mode
  218. self.mode_changed.emit(mode)
  219. self._update_primary_action_label()
  220. def _update_primary_action_label(self):
  221. """Update primary action button label and tooltip based on mode."""
  222. if getattr(self, 'current_mode', 'file') == 'file':
  223. self.run_btn.setText("OPEN FILE")
  224. self.run_btn.setToolTip("Open a multispectral TIFF file to analyze maturity")
  225. else:
  226. self.run_btn.setText("RUN TEST")
  227. self.run_btn.setToolTip("Run live maturity test (coming soon)")
  228. def _on_primary_action_clicked(self):
  229. """Emit the appropriate signal based on current mode."""
  230. if getattr(self, 'current_mode', 'file') == 'file':
  231. self.open_file_clicked.emit()
  232. else:
  233. self.run_test_clicked.emit()