Coverage for openhcs/pyqt_gui/shared/style_generator.py: 0.0%
46 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"""
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: 1px solid {cs.to_hex(cs.border_color)};
58 border-radius: 5px;
59 margin-top: 10px;
60 padding-top: 10px;
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: 1px solid {cs.to_hex(cs.border_color)};
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-bottom: 1px solid {cs.to_hex(cs.separator_color)};
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: 1px solid {cs.to_hex(cs.border_light)};
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: 1px solid {cs.to_hex(cs.border_color)};
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: 1px solid {cs.to_hex(cs.border_color)};
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: 1px solid {cs.to_hex(cs.border_color)};
276 border-radius: 5px;
277 margin-top: 10px;
278 padding-top: 10px;
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: 1px solid {cs.to_hex(cs.input_border)};
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 QCheckBox {{
302 color: {cs.to_hex(cs.text_primary)};
303 }}
304 QFrame {{
305 background-color: {cs.to_hex(cs.panel_bg)};
306 border: 1px solid {cs.to_hex(cs.border_color)};
307 border-radius: 3px;
308 padding: 10px;
309 }}
310 """
312 def generate_config_button_styles(self) -> dict:
313 """
314 Generate individual button styles for config window buttons.
316 Returns:
317 dict: Dictionary with button styles for reset, cancel, save
318 """
319 cs = self.color_scheme
321 return {
322 "reset": f"""
323 QPushButton {{
324 background-color: {cs.to_hex(cs.button_normal_bg)};
325 color: {cs.to_hex(cs.button_text)};
326 border: 1px solid {cs.to_hex(cs.border_light)};
327 border-radius: 3px;
328 padding: 8px;
329 }}
330 QPushButton:hover {{
331 background-color: {cs.to_hex(cs.button_hover_bg)};
332 }}
333 """,
334 "cancel": f"""
335 QPushButton {{
336 background-color: {cs.to_hex(cs.status_error)};
337 color: {cs.to_hex(cs.text_primary)};
338 border: 1px solid {cs.to_hex(cs.status_error)};
339 border-radius: 3px;
340 padding: 8px;
341 }}
342 QPushButton:hover {{
343 background-color: rgba({cs.status_error[0]}, {cs.status_error[1]}, {cs.status_error[2]}, 0.8);
344 }}
345 """,
346 "save": f"""
347 QPushButton {{
348 background-color: {cs.to_hex(cs.selection_bg)};
349 color: {cs.to_hex(cs.selection_text)};
350 border: 1px solid {cs.to_hex(cs.selection_bg)};
351 border-radius: 3px;
352 padding: 8px;
353 }}
354 QPushButton:hover {{
355 background-color: rgba({cs.selection_bg[0]}, {cs.selection_bg[1]}, {cs.selection_bg[2]}, 0.8);
356 }}
357 """
358 }
360 def generate_plate_manager_style(self) -> str:
361 """
362 Generate QStyleSheet for plate manager widget with all components.
364 Returns:
365 str: Complete QStyleSheet for plate manager styling
366 """
367 cs = self.color_scheme
368 return f"""
369 QListWidget {{
370 background-color: {cs.to_hex(cs.panel_bg)};
371 color: {cs.to_hex(cs.text_primary)};
372 border: 1px solid {cs.to_hex(cs.border_color)};
373 border-radius: 3px;
374 padding: 5px;
375 }}
376 QListWidget::item {{
377 padding: 5px;
378 border-bottom: 1px solid {cs.to_hex(cs.separator_color)};
379 }}
380 QListWidget::item:selected {{
381 background-color: {cs.to_hex(cs.selection_bg)};
382 color: {cs.to_hex(cs.selection_text)};
383 }}
384 QListWidget::item:hover {{
385 background-color: {cs.to_hex(cs.hover_bg)};
386 }}
387 QFrame {{
388 background-color: {cs.to_hex(cs.window_bg)};
389 border: 1px solid {cs.to_hex(cs.border_color)};
390 border-radius: 3px;
391 padding: 5px;
392 }}
393 QPushButton {{
394 background-color: {cs.to_hex(cs.button_normal_bg)};
395 color: {cs.to_hex(cs.button_text)};
396 border: 1px solid {cs.to_hex(cs.border_light)};
397 border-radius: 3px;
398 padding: 5px;
399 }}
400 QPushButton:hover {{
401 background-color: {cs.to_hex(cs.button_hover_bg)};
402 }}
403 QPushButton:pressed {{
404 background-color: {cs.to_hex(cs.button_pressed_bg)};
405 }}
406 QPushButton:disabled {{
407 background-color: {cs.to_hex(cs.button_disabled_bg)};
408 color: {cs.to_hex(cs.button_disabled_text)};
409 }}
410 QProgressBar {{
411 border: 1px solid {cs.to_hex(cs.border_color)};
412 border-radius: 3px;
413 background-color: {cs.to_hex(cs.progress_bg)};
414 color: {cs.to_hex(cs.text_primary)};
415 text-align: center;
416 }}
417 QProgressBar::chunk {{
418 background-color: {cs.to_hex(cs.progress_fill)};
419 border-radius: 2px;
420 }}
421 """
423 def get_status_color_hex(self, status_type: str) -> str:
424 """
425 Get hex color string for status type.
427 Args:
428 status_type: Status type (success, warning, error, info)
430 Returns:
431 str: Hex color string for the status type
432 """
433 cs = self.color_scheme
434 status_colors = {
435 "success": cs.status_success,
436 "warning": cs.status_warning,
437 "error": cs.status_error,
438 "info": cs.status_info,
439 }
441 color = status_colors.get(status_type, cs.status_info)
442 return cs.to_hex(color)