Coverage for openhcs/pyqt_gui/windows/help_window.py: 0.0%
97 statements
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-14 05:57 +0000
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-14 05:57 +0000
1"""
2Help Window for PyQt6
4Help display dialog with OpenHCS documentation and usage information.
5Uses hybrid approach: extracted business logic + clean PyQt6 UI.
6"""
8import logging
9from typing import Optional
11from PyQt6.QtWidgets import (
12 QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,
13 QScrollArea, QTextEdit, QFrame, QWidget
14)
15from PyQt6.QtCore import Qt
16from PyQt6.QtGui import QFont
18from openhcs.pyqt_gui.shared.style_generator import StyleSheetGenerator
19from openhcs.pyqt_gui.shared.color_scheme import PyQt6ColorScheme
21logger = logging.getLogger(__name__)
24class HelpWindow(QDialog):
25 """
26 PyQt6 Help Window.
28 Help display dialog with OpenHCS documentation and usage information.
29 Preserves all business logic from Textual version with clean PyQt6 UI.
30 """
32 # Help content (extracted from Textual version)
33 HELP_TEXT = """OpenHCS - Open High-Content Screening
35🔬 Visual Programming for Cell Biology Research
37Key Features:
38• GPU-accelerated image processing
39• Visual pipeline building
40• Multi-backend storage support
41• Real-time parameter editing
43Workflow:
441. Add Plate → Select microscopy data
452. Edit Step → Visual function selection
463. Compile → Create execution plan
474. Run → Process images
49Navigation:
50• Use the Plate Manager to add and manage your microscopy plates
51• Build processing pipelines in the Pipeline Editor
52• Configure functions in the Function Library
53• Monitor system performance in real-time
55Keyboard Shortcuts:
56• Ctrl+N: New pipeline
57• Ctrl+O: Open pipeline
58• Ctrl+S: Save pipeline
59• F1: Show this help
60• Esc: Close current dialog
62Tips:
63• Right-click on widgets for context menus
64• Use drag-and-drop to reorder pipeline steps
65• Parameters are validated in real-time
66• GPU acceleration is automatic when available
68For detailed documentation, see the Nature Methods publication
69and the online documentation at https://openhcs.org
71Version: PyQt6 GUI 1.0.0
72"""
74 def __init__(self, content: Optional[str] = None,
75 color_scheme: Optional[PyQt6ColorScheme] = None, parent=None):
76 """
77 Initialize the help window.
79 Args:
80 content: Custom help content (uses default if None)
81 color_scheme: Color scheme for styling (optional, uses default if None)
82 parent: Parent widget
83 """
84 super().__init__(parent)
86 # Initialize color scheme and style generator
87 self.color_scheme = color_scheme or PyQt6ColorScheme()
88 self.style_generator = StyleSheetGenerator(self.color_scheme)
90 # Business logic state
91 self.content = content or self.HELP_TEXT
93 # Setup UI
94 self.setup_ui()
95 self.setup_connections()
97 logger.debug("Help window initialized")
99 def setup_ui(self):
100 """Setup the user interface."""
101 self.setWindowTitle("OpenHCS Help")
102 self.setModal(True)
103 self.setMinimumSize(600, 500)
104 self.resize(800, 700)
106 layout = QVBoxLayout(self)
107 layout.setSpacing(10)
109 # Header with OpenHCS logo/title
110 header_frame = self.create_header()
111 layout.addWidget(header_frame)
113 # Scrollable content area
114 content_area = self.create_content_area()
115 layout.addWidget(content_area)
117 # Button panel
118 button_panel = self.create_button_panel()
119 layout.addWidget(button_panel)
121 # Apply centralized styling
122 self.setStyleSheet(self.style_generator.generate_dialog_style() + f"""
123 QTextEdit {{
124 background-color: {self.color_scheme.to_hex(self.color_scheme.panel_bg)};
125 color: {self.color_scheme.to_hex(self.color_scheme.text_primary)};
126 border: 1px solid {self.color_scheme.to_hex(self.color_scheme.border_color)};
127 border-radius: 5px;
128 padding: 10px;
129 font-family: 'Courier New', monospace;
130 font-size: 11px;
131 line-height: 1.4;
132 }}
133 """)
135 def create_header(self) -> QWidget:
136 """
137 Create the header section with title and version.
139 Returns:
140 Widget containing header information
141 """
142 frame = QFrame()
143 frame.setFrameStyle(QFrame.Shape.Box)
144 frame.setStyleSheet(f"""
145 QFrame {{
146 background-color: {self.color_scheme.to_hex(self.color_scheme.panel_bg)};
147 border: 1px solid {self.color_scheme.to_hex(self.color_scheme.border_color)};
148 border-radius: 5px;
149 padding: 15px;
150 }}
151 """)
153 layout = QVBoxLayout(frame)
155 # ASCII art title
156 title_label = QLabel(self.get_ascii_title())
157 title_label.setFont(QFont("Courier New", 10, QFont.Weight.Bold))
158 title_label.setStyleSheet(f"color: {self.color_scheme.to_hex(self.color_scheme.text_accent)};")
159 title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
160 layout.addWidget(title_label)
162 # Subtitle
163 subtitle_label = QLabel("Visual Programming for Cell Biology Research")
164 subtitle_label.setFont(QFont("Arial", 12))
165 subtitle_label.setStyleSheet(f"color: {self.color_scheme.to_hex(self.color_scheme.text_secondary)};")
166 subtitle_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
167 layout.addWidget(subtitle_label)
169 return frame
171 def create_content_area(self) -> QWidget:
172 """
173 Create the scrollable content area.
175 Returns:
176 Widget containing help content
177 """
178 # Text edit for help content
179 self.content_text = QTextEdit()
180 self.content_text.setPlainText(self.content)
181 self.content_text.setReadOnly(True)
183 # Enable rich text formatting
184 self.content_text.setHtml(self.format_help_content(self.content))
186 return self.content_text
188 def create_button_panel(self) -> QWidget:
189 """
190 Create the button panel.
192 Returns:
193 Widget containing action buttons
194 """
195 panel = QFrame()
196 panel.setFrameStyle(QFrame.Shape.Box)
197 panel.setStyleSheet(f"""
198 QFrame {{
199 background-color: {self.color_scheme.to_hex(self.color_scheme.panel_bg)};
200 border: 1px solid {self.color_scheme.to_hex(self.color_scheme.border_color)};
201 border-radius: 3px;
202 padding: 10px;
203 }}
204 """)
206 layout = QHBoxLayout(panel)
207 layout.addStretch()
209 # Close button
210 close_button = QPushButton("Close")
211 close_button.setMinimumWidth(100)
212 close_button.setMinimumHeight(35)
213 close_button.clicked.connect(self.accept)
214 close_button.setStyleSheet("""
215 QPushButton {
216 background-color: #0078d4;
217 color: white;
218 border: 1px solid #106ebe;
219 border-radius: 5px;
220 padding: 8px;
221 font-weight: bold;
222 }
223 QPushButton:hover {
224 background-color: #106ebe;
225 }
226 QPushButton:pressed {
227 background-color: #005a9e;
228 }
229 """)
230 layout.addWidget(close_button)
232 return panel
234 def setup_connections(self):
235 """Setup signal/slot connections."""
236 pass # No additional connections needed
238 def get_ascii_title(self) -> str:
239 """
240 Get ASCII art title.
242 Returns:
243 ASCII art title string
244 """
245 return """
246 ██████╗ ██████╗ ███████╗███╗ ██╗██╗ ██╗ ██████╗███████╗
247██╔═══██╗██╔══██╗██╔════╝████╗ ██║██║ ██║██╔════╝██╔════╝
248██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████║██║ ███████╗
249██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██║██║ ╚════██║
250╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║╚██████╗███████║
251 ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝╚══════╝
252 """
254 def format_help_content(self, content: str) -> str:
255 """
256 Format help content with HTML for better display.
258 Args:
259 content: Raw help content
261 Returns:
262 HTML formatted content
263 """
264 # Convert plain text to HTML with basic formatting
265 html_content = content.replace('\n', '<br>')
267 # Format headers (lines starting with uppercase words followed by colon)
268 import re
269 accent_color = self.color_scheme.to_hex(self.color_scheme.text_accent)
270 html_content = re.sub(
271 r'^([A-Z][A-Za-z\s]+:)$',
272 rf'<h3 style="color: {accent_color}; margin-top: 20px; margin-bottom: 10px;">\1</h3>',
273 html_content,
274 flags=re.MULTILINE
275 )
277 # Format bullet points
278 secondary_color = self.color_scheme.to_hex(self.color_scheme.text_secondary)
279 html_content = re.sub(
280 r'^• (.+)$',
281 rf'<li style="margin-left: 20px; color: {secondary_color};">\1</li>',
282 html_content,
283 flags=re.MULTILINE
284 )
286 # Format numbered lists
287 html_content = re.sub(
288 r'^(\d+\.) (.+)$',
289 rf'<div style="margin-left: 20px; color: {secondary_color};"><strong style="color: {accent_color};">\1</strong> \2</div>',
290 html_content,
291 flags=re.MULTILINE
292 )
294 # Format keyboard shortcuts
295 input_bg_color = self.color_scheme.to_hex(self.color_scheme.input_bg)
296 text_accent_color = self.color_scheme.to_hex(self.color_scheme.text_accent)
297 html_content = re.sub(
298 r'(Ctrl\+[A-Z]|F\d+|Esc)',
299 rf'<code style="background-color: {input_bg_color}; padding: 2px 4px; border-radius: 3px; color: {text_accent_color};">\1</code>',
300 html_content
301 )
303 # Wrap in HTML structure
304 primary_text_color = self.color_scheme.to_hex(self.color_scheme.text_primary)
305 html_content = f"""
306 <html>
307 <body style="font-family: Arial, sans-serif; font-size: 12px; line-height: 1.6; color: {primary_text_color};">
308 {html_content}
309 </body>
310 </html>
311 """
313 return html_content
315 def set_content(self, content: str):
316 """
317 Set new help content.
319 Args:
320 content: New help content
321 """
322 self.content = content
323 if hasattr(self, 'content_text'):
324 self.content_text.setHtml(self.format_help_content(content))
326 def show_section(self, section_name: str):
327 """
328 Show specific help section.
330 Args:
331 section_name: Name of the section to show
332 """
333 # This could be extended to show specific sections
334 # For now, just show the full help
335 self.show()
337 @staticmethod
338 def show_help(parent=None, content: Optional[str] = None):
339 """
340 Static method to show help window.
342 Args:
343 parent: Parent widget
344 content: Custom help content
346 Returns:
347 Dialog result
348 """
349 help_window = HelpWindow(content, parent)
350 return help_window.exec()
353# Convenience function for showing help
354def show_help_dialog(parent=None, content: Optional[str] = None):
355 """
356 Show help dialog.
358 Args:
359 parent: Parent widget
360 content: Custom help content
362 Returns:
363 Dialog result
364 """
365 return HelpWindow.show_help(parent, content)