Coverage for openhcs/pyqt_gui/shared/style_generator.py: 0.0%
46 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-01 18:33 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-01 18:33 +0000
1"""
2QStyleSheet Generator for OpenHCS PyQt6 GUI
4Generates dynamic QStyleSheet strings from PyQt6ColorScheme objects, enabling
5centralized styling with theme support. Replaces hardcoded color strings with
6semantic color scheme references.
7"""
9import logging
10from typing import Dict, Optional
11from openhcs.pyqt_gui.shared.color_scheme import PyQt6ColorScheme
13logger = logging.getLogger(__name__)
16class StyleSheetGenerator:
17 """
18 Generates QStyleSheet strings from PyQt6ColorScheme objects.
20 Provides methods to generate complete stylesheets for different widget types,
21 replacing hardcoded colors with centralized color scheme references.
22 """
24 def __init__(self, color_scheme: PyQt6ColorScheme):
25 """
26 Initialize the style generator with a color scheme.
28 Args:
29 color_scheme: PyQt6ColorScheme instance to use for styling
30 """
31 self.color_scheme = color_scheme
33 def update_color_scheme(self, color_scheme: PyQt6ColorScheme):
34 """
35 Update the color scheme used for style generation.
37 Args:
38 color_scheme: New PyQt6ColorScheme instance
39 """
40 self.color_scheme = color_scheme
42 def generate_dialog_style(self) -> str:
43 """
44 Generate QStyleSheet for dialog windows.
46 Returns:
47 str: Complete QStyleSheet for dialog styling
48 """
49 cs = self.color_scheme
50 return f"""
51 QDialog {{
52 background-color: {cs.to_hex(cs.window_bg)};
53 color: {cs.to_hex(cs.text_primary)};
54 }}
55 QGroupBox {{
56 font-weight: bold;
57 border: none;
58 border-radius: 5px;
59 margin-top: 5px;
60 padding-top: 5px;
61 background-color: {cs.to_hex(cs.panel_bg)};
62 color: {cs.to_hex(cs.text_primary)};
63 }}
64 QGroupBox::title {{
65 subcontrol-origin: margin;
66 left: 10px;
67 padding: 0 5px 0 5px;
68 color: {cs.to_hex(cs.text_accent)};
69 }}
70 QLabel {{
71 color: {cs.to_hex(cs.text_secondary)};
72 }}
73 QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox {{
74 background-color: {cs.to_hex(cs.input_bg)};
75 color: {cs.to_hex(cs.input_text)};
76 border: 1px solid {cs.to_hex(cs.input_border)};
77 border-radius: 3px;
78 padding: 5px;
79 }}
80 QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QComboBox:focus {{
81 border: 1px solid {cs.to_hex(cs.input_focus_border)};
82 }}
83 QCheckBox {{
84 color: {cs.to_hex(cs.text_primary)};
85 }}
86 """
88 def generate_tree_widget_style(self) -> str:
89 """
90 Generate QStyleSheet for tree widgets and list widgets.
92 Returns:
93 str: Complete QStyleSheet for tree/list widget styling
94 """
95 cs = self.color_scheme
96 return f"""
97 QTreeWidget, QListWidget {{
98 background-color: {cs.to_hex(cs.panel_bg)};
99 color: {cs.to_hex(cs.text_primary)};
100 border: none;
101 border-radius: 3px;
102 selection-background-color: {cs.to_hex(cs.selection_bg)};
103 }}
104 QTreeWidget::item, QListWidget::item {{
105 padding: 4px;
106 border: none;
107 }}
108 QTreeWidget::item:hover, QListWidget::item:hover {{
109 background-color: {cs.to_hex(cs.hover_bg)};
110 }}
111 QTreeWidget::item:selected, QListWidget::item:selected {{
112 background-color: {cs.to_hex(cs.selection_bg)};
113 color: {cs.to_hex(cs.selection_text)};
114 }}
115 """
117 def generate_button_style(self) -> str:
118 """
119 Generate QStyleSheet for buttons with all states.
121 Returns:
122 str: Complete QStyleSheet for button styling
123 """
124 cs = self.color_scheme
125 return f"""
126 QPushButton {{
127 background-color: {cs.to_hex(cs.button_normal_bg)};
128 color: {cs.to_hex(cs.button_text)};
129 border: none;
130 border-radius: 3px;
131 padding: 5px;
132 }}
133 QPushButton:hover {{
134 background-color: {cs.to_hex(cs.button_hover_bg)};
135 }}
136 QPushButton:pressed {{
137 background-color: {cs.to_hex(cs.button_pressed_bg)};
138 }}
139 QPushButton:disabled {{
140 background-color: {cs.to_hex(cs.button_disabled_bg)};
141 color: {cs.to_hex(cs.button_disabled_text)};
142 }}
143 """
145 def generate_combobox_style(self) -> str:
146 """
147 Generate QStyleSheet for combo boxes with dropdown styling.
149 Returns:
150 str: Complete QStyleSheet for combo box styling
151 """
152 cs = self.color_scheme
153 return f"""
154 QComboBox {{
155 background-color: {cs.to_hex(cs.input_bg)};
156 color: {cs.to_hex(cs.input_text)};
157 border: 1px solid {cs.to_hex(cs.input_border)};
158 border-radius: 3px;
159 padding: 5px;
160 }}
161 QComboBox::drop-down {{
162 border: none;
163 background-color: {cs.to_hex(cs.button_normal_bg)};
164 }}
165 QComboBox::down-arrow {{
166 border: none;
167 }}
168 QComboBox QAbstractItemView {{
169 background-color: {cs.to_hex(cs.input_bg)};
170 color: {cs.to_hex(cs.input_text)};
171 selection-background-color: {cs.to_hex(cs.selection_bg)};
172 }}
173 """
175 def generate_progress_bar_style(self) -> str:
176 """
177 Generate QStyleSheet for progress bars.
179 Returns:
180 str: Complete QStyleSheet for progress bar styling
181 """
182 cs = self.color_scheme
183 return f"""
184 QProgressBar {{
185 border: none;
186 border-radius: 3px;
187 background-color: {cs.to_hex(cs.progress_bg)};
188 color: {cs.to_hex(cs.text_primary)};
189 text-align: center;
190 }}
191 QProgressBar::chunk {{
192 background-color: {cs.to_hex(cs.progress_fill)};
193 border-radius: 2px;
194 }}
195 """
197 def generate_frame_style(self) -> str:
198 """
199 Generate QStyleSheet for frames and panels.
201 Returns:
202 str: Complete QStyleSheet for frame styling
203 """
204 cs = self.color_scheme
205 return f"""
206 QFrame {{
207 background-color: {cs.to_hex(cs.frame_bg)};
208 border: none;
209 border-radius: 3px;
210 padding: 5px;
211 }}
212 """
214 def generate_system_monitor_style(self) -> str:
215 """
216 Generate QStyleSheet for system monitor widget.
218 Returns:
219 str: Complete QStyleSheet for system monitor styling
220 """
221 cs = self.color_scheme
222 return f"""
223 SystemMonitorWidget {{
224 background-color: {cs.to_hex(cs.window_bg)};
225 color: {cs.to_hex(cs.text_primary)};
226 border: 1px solid {cs.to_hex(cs.border_color)};
227 border-radius: 5px;
228 }}
229 QLabel {{
230 color: {cs.to_hex(cs.text_primary)};
231 }}
232 #header_label {{
233 color: {cs.to_hex(cs.text_accent)};
234 font-weight: bold;
235 font-size: 14px;
236 }}
237 #info_label {{
238 color: {cs.to_hex(cs.text_secondary)};
239 font-size: 10px;
240 }}
241 """
243 def generate_complete_application_style(self) -> str:
244 """
245 Generate complete application-wide QStyleSheet.
247 Returns:
248 str: Complete QStyleSheet for entire application
249 """
250 return (
251 self.generate_dialog_style() + "\n" +
252 self.generate_tree_widget_style() + "\n" +
253 self.generate_button_style() + "\n" +
254 self.generate_combobox_style() + "\n" +
255 self.generate_progress_bar_style() + "\n" +
256 self.generate_frame_style() + "\n" +
257 self.generate_system_monitor_style()
258 )
260 def generate_config_window_style(self) -> str:
261 """
262 Generate QStyleSheet for configuration windows with button panel.
264 Returns:
265 str: Complete QStyleSheet for config window styling
266 """
267 cs = self.color_scheme
268 return f"""
269 QDialog {{
270 background-color: {cs.to_hex(cs.window_bg)};
271 color: {cs.to_hex(cs.text_primary)};
272 }}
273 QGroupBox {{
274 font-weight: bold;
275 border: none;
276 border-radius: 5px;
277 margin-top: 5px;
278 padding-top: 5px;
279 background-color: {cs.to_hex(cs.panel_bg)};
280 color: {cs.to_hex(cs.text_primary)};
281 }}
282 QGroupBox::title {{
283 subcontrol-origin: margin;
284 left: 10px;
285 padding: 0 5px 0 5px;
286 color: {cs.to_hex(cs.text_accent)};
287 }}
288 QLabel {{
289 color: {cs.to_hex(cs.text_secondary)};
290 }}
291 QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox {{
292 background-color: {cs.to_hex(cs.input_bg)};
293 color: {cs.to_hex(cs.input_text)};
294 border: none;
295 border-radius: 3px;
296 padding: 5px;
297 }}
298 QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QComboBox:focus {{
299 border: 1px solid {cs.to_hex(cs.input_focus_border)};
300 }}
301 QPushButton {{
302 background-color: {cs.to_hex(cs.button_normal_bg)};
303 color: {cs.to_hex(cs.button_text)};
304 border: none;
305 border-radius: 3px;
306 padding: 5px;
307 }}
308 QPushButton:hover {{
309 background-color: {cs.to_hex(cs.button_hover_bg)};
310 }}
311 QPushButton:pressed {{
312 background-color: {cs.to_hex(cs.button_pressed_bg)};
313 }}
314 QPushButton:disabled {{
315 background-color: {cs.to_hex(cs.button_disabled_bg)};
316 color: {cs.to_hex(cs.button_disabled_text)};
317 }}
318 QCheckBox {{
319 color: {cs.to_hex(cs.text_primary)};
320 }}
321 QFrame {{
322 background-color: {cs.to_hex(cs.panel_bg)};
323 border: none;
324 border-radius: 3px;
325 padding: 5px;
326 }}
327 """
329 def generate_config_button_styles(self) -> dict:
330 """
331 Generate individual button styles for config window buttons.
333 Returns:
334 dict: Dictionary with button styles for reset, cancel, save
335 """
336 cs = self.color_scheme
338 return {
339 "reset": f"""
340 QPushButton {{
341 background-color: {cs.to_hex(cs.button_normal_bg)};
342 color: {cs.to_hex(cs.button_text)};
343 border: 1px solid {cs.to_hex(cs.border_light)};
344 border-radius: 3px;
345 padding: 8px;
346 }}
347 QPushButton:hover {{
348 background-color: {cs.to_hex(cs.button_hover_bg)};
349 }}
350 """,
351 "cancel": f"""
352 QPushButton {{
353 background-color: {cs.to_hex(cs.status_error)};
354 color: {cs.to_hex(cs.text_primary)};
355 border: 1px solid {cs.to_hex(cs.status_error)};
356 border-radius: 3px;
357 padding: 8px;
358 }}
359 QPushButton:hover {{
360 background-color: rgba({cs.status_error[0]}, {cs.status_error[1]}, {cs.status_error[2]}, 0.8);
361 }}
362 """,
363 "save": f"""
364 QPushButton {{
365 background-color: {cs.to_hex(cs.selection_bg)};
366 color: {cs.to_hex(cs.selection_text)};
367 border: 1px solid {cs.to_hex(cs.selection_bg)};
368 border-radius: 3px;
369 padding: 8px;
370 }}
371 QPushButton:hover {{
372 background-color: rgba({cs.selection_bg[0]}, {cs.selection_bg[1]}, {cs.selection_bg[2]}, 0.8);
373 }}
374 """
375 }
377 def generate_plate_manager_style(self) -> str:
378 """
379 Generate QStyleSheet for plate manager widget with all components.
381 Returns:
382 str: Complete QStyleSheet for plate manager styling
383 """
384 cs = self.color_scheme
385 return f"""
386 QListWidget {{
387 background-color: {cs.to_hex(cs.panel_bg)};
388 color: {cs.to_hex(cs.text_primary)};
389 border: none;
390 border-radius: 3px;
391 padding: 5px;
392 }}
393 QListWidget::item {{
394 padding: 5px;
395 border: none;
396 }}
397 QListWidget::item:selected {{
398 background-color: {cs.to_hex(cs.selection_bg)};
399 color: {cs.to_hex(cs.selection_text)};
400 }}
401 QListWidget::item:hover {{
402 background-color: {cs.to_hex(cs.hover_bg)};
403 }}
404 QFrame {{
405 background-color: {cs.to_hex(cs.window_bg)};
406 border: none;
407 border-radius: 3px;
408 padding: 5px;
409 }}
410 QPushButton {{
411 background-color: {cs.to_hex(cs.button_normal_bg)};
412 color: {cs.to_hex(cs.button_text)};
413 border: none;
414 border-radius: 3px;
415 padding: 5px;
416 }}
417 QPushButton:hover {{
418 background-color: {cs.to_hex(cs.button_hover_bg)};
419 }}
420 QPushButton:pressed {{
421 background-color: {cs.to_hex(cs.button_pressed_bg)};
422 }}
423 QPushButton:disabled {{
424 background-color: {cs.to_hex(cs.button_disabled_bg)};
425 color: {cs.to_hex(cs.button_disabled_text)};
426 }}
427 QProgressBar {{
428 border: none;
429 border-radius: 3px;
430 background-color: {cs.to_hex(cs.progress_bg)};
431 color: {cs.to_hex(cs.text_primary)};
432 text-align: center;
433 }}
434 QProgressBar::chunk {{
435 background-color: {cs.to_hex(cs.progress_fill)};
436 border-radius: 2px;
437 }}
438 """
440 def get_status_color_hex(self, status_type: str) -> str:
441 """
442 Get hex color string for status type.
444 Args:
445 status_type: Status type (success, warning, error, info)
447 Returns:
448 str: Hex color string for the status type
449 """
450 cs = self.color_scheme
451 status_colors = {
452 "success": cs.status_success,
453 "warning": cs.status_warning,
454 "error": cs.status_error,
455 "info": cs.status_info,
456 }
458 color = status_colors.get(status_type, cs.status_info)
459 return cs.to_hex(color)