1212#####################################################################
1313import logging
1414import os
15-
1615from qtutils import *
17-
1816from blacs .plugins import PLUGINS_DIR
1917
2018name = "GUI Theme"
2119module = "theme" # should be folder name
2220logger = logging .getLogger ('BLACS.plugin.%s' % module )
2321
22+ def load_theme (theme_name ):
23+ theme_path = os .path .join (PLUGINS_DIR , module , "themes" , f"{ theme_name } _theme.qss" )
24+ try :
25+ with open (theme_path , "r" ) as f :
26+ return f .read ()
27+ except Exception as e :
28+ logger .warning (f"Could not load theme '{ theme_name } ': { e } " )
29+ return ""
30+
2431
2532DEFAULT_STYLESHEET = """DigitalOutput {
2633 font-size: 12px;
99106}
100107 """
101108
109+ # DARK_STYLESHEET = """
110+ # # /* ===== Global & Widget Defaults ===== */
111+ # # QWidget {
112+ # # background-color: #0f1115;
113+ # # color: #e6eef3;
114+ # # selection-background-color: #2b6ea3;
115+ # # selection-color: #ffffff;
116+ # # font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
117+ # # }
118+
119+ # # /* ===== Push Buttons ===== */
120+ # # QPushButton {
121+ # # background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
122+ # # stop:0 #2a2e34, stop:1 #212427);
123+ # # border: 1px solid #2e3338;
124+ # # padding: 6px 10px;
125+ # # border-radius: 6px;
126+ # # color: #e6eef3;
127+ # # }
128+ # # QPushButton:hover { border-color: #3a7bd5; }
129+ # # QPushButton:pressed { background-color: #1b1d20; }
130+
131+ # # /* ===== LineEdits, TextEdits ===== */
132+ # # QLineEdit, QPlainTextEdit, QTextEdit {
133+ # # background-color: #0c0d0f;
134+ # # border: 1px solid #26282c;
135+ # # padding: 6px;
136+ # # border-radius: 4px;
137+ # # color: #e6eef3;
138+ # # }
139+ # # QLineEdit:focus, QTextEdit:focus { border-color: #3a7bd5; }
140+
141+ # # /* ===== Tables, Headers ===== */
142+ # # QHeaderView::section {
143+ # # background-color: #131417;
144+ # # color: #cfd8de;
145+ # # padding: 6px;
146+ # # border: 1px solid #232427;
147+ # # }
148+ # # QTableView, QTreeView, QListView {
149+ # # background-color: #0b0c0e;
150+ # # gridline-color: #17181b;
151+ # # alternate-background-color: #0f1013;
152+ # # }
153+ # # QTableView::item:selected, QTreeView::item:selected, QListView::item:selected {
154+ # # background-color: #2b6ea3;
155+ # # color: #fff;
156+ # # }
157+
158+ # # /* ===== Combo & Spin Boxes ===== */
159+ # # QComboBox, QSpinBox, QDoubleSpinBox {
160+ # # background-color: #0c0d0f;
161+ # # border: 1px solid #26282c;
162+ # # padding: 4px;
163+ # # color: #e6eef3;
164+ # # }
165+
166+ # # /* ===== Checkboxes / Radios ===== */
167+ # # QCheckBox, QRadioButton { spacing: 6px; }
168+ # # QCheckBox::indicator, QRadioButton::indicator {
169+ # # background-color: transparent;
170+ # # border: 1px solid #3a3d42;
171+ # # }
172+
173+ # # /* ===== Progress Bar ===== */
174+ # # QProgressBar {
175+ # # border: 1px solid #2b2f34;
176+ # # background: #0c0d0f;
177+ # # text-align: center;
178+ # # border-radius: 6px;
179+ # # }
180+ # # QProgressBar::chunk {
181+ # # background-color: #3a7bd5;
182+ # # border-radius: 6px;
183+ # # }
184+
185+ # # /* ===== Tabs ===== */
186+ # # QTabWidget::pane { border: 1px solid #232427; }
187+ # # QTabBar::tab {
188+ # # background: #0f1115;
189+ # # color: #cfd8de;
190+ # # padding: 8px;
191+ # # border: 1px solid #232427;
192+ # # border-bottom: none;
193+ # # border-top-left-radius: 6px;
194+ # # border-top-right-radius: 6px;
195+ # # }
196+ # # QTabBar::tab:selected { background: #16181c; }
197+
198+ # # /* ===== Dock Widgets ===== */
199+ # # QDockWidget { titlebar-close-icon: url(:/icons/close.png); title: " "; }
200+ # # QDockWidget::title { background: #101215; }
201+
202+ # # /* ===== Menus & Tooltips ===== */
203+ # # QMenuBar, QMenu {
204+ # # background-color: #0f1115;
205+ # # color: #e6eef3;
206+ # # }
207+ # # QMenu::item:selected { background-color: #2b6ea3; color: #fff; }
208+ # # QToolTip {
209+ # # background-color: #1c1f22;
210+ # # color: #e6eef3;
211+ # # border: 1px solid #3a3f45;
212+ # # padding: 6px;
213+ # # }
214+
215+ # # /* ===== Scrollbars & Splitters ===== */
216+ # # QScrollBar:vertical {
217+ # # background: #0f1115;
218+ # # width: 12px;
219+ # # }
220+ # # QScrollBar::handle:vertical {
221+ # # background: #2b2e33;
222+ # # min-height: 20px;
223+ # # border-radius: 6px;
224+ # # }
225+ # # QScrollBar::add-line, QScrollBar::sub-line { height: 0px; }
226+ # # QSplitter::handle { background: #151618; }
227+
228+ # # /* ===== Status Bar ===== */
229+ # # QStatusBar { background: #0f1115; color: #cfd8de; }
230+
231+ # # """
232+
233+ # BLUE_STYLESHEET = """
234+ # /* ===== Global & Widget Defaults ===== */
235+ # QWidget {
236+ # background-color: #0a0f1a;
237+ # color: #e1e8f0;
238+ # selection-background-color: #1e4a72;
239+ # selection-color: #ffffff;
240+ # font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
241+ # }
242+
243+ # /* ===== Push Buttons ===== */
244+ # QPushButton {
245+ # background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
246+ # stop:0 #1a2332, stop:1 #0f1520);
247+ # border: 1px solid #1e2b3d;
248+ # padding: 6px 10px;
249+ # border-radius: 6px;
250+ # color: #e1e8f0;
251+ # }
252+ # QPushButton:hover { border-color: #2563eb; }
253+ # QPushButton:pressed { background-color: #0d1117; }
254+
255+ # /* ===== LineEdits, TextEdits ===== */
256+ # QLineEdit, QPlainTextEdit, QTextEdit {
257+ # background-color: #070b14;
258+ # border: 1px solid #1a2332;
259+ # padding: 6px;
260+ # border-radius: 4px;
261+ # color: #e1e8f0;
262+ # }
263+ # QLineEdit:focus, QTextEdit:focus { border-color: #2563eb; }
264+
265+ # /* ===== Tables, Headers ===== */
266+ # QHeaderView::section {
267+ # background-color: #0d1421;
268+ # color: #b8c5d6;
269+ # padding: 6px;
270+ # border: 1px solid #1a2332;
271+ # }
272+ # QTableView, QTreeView, QListView {
273+ # background-color: #060a12;
274+ # gridline-color: #0f1520;
275+ # alternate-background-color: #080d17;
276+ # }
277+ # QTableView::item:selected, QTreeView::item:selected, QListView::item:selected {
278+ # background-color: #1e4a72;
279+ # color: #fff;
280+ # }
281+
282+ # /* ===== Combo & Spin Boxes ===== */
283+ # QComboBox, QSpinBox, QDoubleSpinBox {
284+ # background-color: #070b14;
285+ # border: 1px solid #1a2332;
286+ # padding: 4px;
287+ # color: #e1e8f0;
288+ # }
289+
290+ # /* ===== Checkboxes / Radios ===== */
291+ # QCheckBox, QRadioButton { spacing: 6px; }
292+ # QCheckBox::indicator, QRadioButton::indicator {
293+ # background-color: transparent;
294+ # border: 1px solid #2c3e50;
295+ # }
296+
297+ # /* ===== Progress Bar ===== */
298+ # QProgressBar {
299+ # border: 1px solid #1a2332;
300+ # background: #070b14;
301+ # text-align: center;
302+ # border-radius: 6px;
303+ # }
304+ # QProgressBar::chunk {
305+ # background-color: #2563eb;
306+ # border-radius: 6px;
307+ # }
308+
309+ # /* ===== Tabs ===== */
310+ # QTabWidget::pane { border: 1px solid #1a2332; }
311+ # QTabBar::tab {
312+ # background: #0a0f1a;
313+ # color: #b8c5d6;
314+ # padding: 8px;
315+ # border: 1px solid #1a2332;
316+ # border-bottom: none;
317+ # border-top-left-radius: 6px;
318+ # border-top-right-radius: 6px;
319+ # }
320+ # QTabBar::tab:selected { background: #0f1520; }
321+
322+ # /* ===== Dock Widgets ===== */
323+ # QDockWidget { titlebar-close-icon: url(:/icons/close.png); title: " "; }
324+ # QDockWidget::title { background: #0a0f1a; }
325+
326+ # /* ===== Menus & Tooltips ===== */
327+ # QMenuBar, QMenu {
328+ # background-color: #0a0f1a;
329+ # color: #e1e8f0;
330+ # }
331+ # QMenu::item:selected { background-color: #1e4a72; color: #fff; }
332+ # QToolTip {
333+ # background-color: #0f1520;
334+ # color: #e1e8f0;
335+ # border: 1px solid #2c3e50;
336+ # padding: 6px;
337+ # }
338+
339+ # /* ===== Scrollbars & Splitters ===== */
340+ # QScrollBar:vertical {
341+ # background: #0a0f1a;
342+ # width: 12px;
343+ # }
344+ # QScrollBar::handle:vertical {
345+ # background: #1a2332;
346+ # min-height: 20px;
347+ # border-radius: 6px;
348+ # }
349+ # QScrollBar::add-line, QScrollBar::sub-line { height: 0px; }
350+ # QSplitter::handle { background: #0f1520; }
351+
352+ # /* ===== Status Bar ===== */
353+ # QStatusBar { background: #0a0f1a; color: #b8c5d6; }
354+ # """
102355
103356def is_default_stylesheet (stylesheet ):
104357 """Return whether a stylesheet is the same as the default stylesheet, modulo whitespace"""
@@ -157,31 +410,49 @@ def close(self):
157410class Setting (object ):
158411 name = name
159412
160- def __init__ (self ,data ):
161- # This is our data store!
413+ def __init__ (self , data ):
162414 self .data = data
163-
164415 if 'stylesheet' not in self .data or not self .data ['stylesheet' ]:
165- # If it's absent or an empty string, use the default stylesheet:
166- self .data ['stylesheet' ] = DEFAULT_STYLESHEET
167-
168- def on_set_green_button_theme (self ):
169- self .widgets ['stylesheet' ].appendPlainText (DEFAULT_STYLESHEET )
416+ self .data ['stylesheet' ] = load_theme ('default' ) or DEFAULT_STYLESHEET
417+
418+ def on_set_default_theme (self ):
419+ self .widgets ['stylesheet' ].setPlainText (load_theme ('default' ))
170420
171- # Create the page, return the page and an icon to use on the label (the class name attribute will be used for the label text)
172- def create_dialog (self ,notebook ):
421+ def on_set_green_button_theme (self ):
422+ self .widgets ['stylesheet' ].setPlainText (DEFAULT_STYLESHEET )
423+
424+ def create_dialog (self , notebook ):
173425 ui = UiLoader ().load (os .path .join (PLUGINS_DIR , module , 'theme.ui' ))
174-
175426 # restore current stylesheet
176427 ui .stylesheet_text .setPlainText (self .data ['stylesheet' ])
428+ # Populate theme_combo with available .qss files
429+ theme_dir = os .path .join (PLUGINS_DIR , module , 'themes' )
430+ themes = [f for f in os .listdir (theme_dir ) if f .endswith ('.qss' )]
431+ theme_names = [os .path .splitext (f )[0 ].replace ('_theme' ,'' ) for f in themes ]
432+ ui .theme_combo .clear ()
433+ ui .theme_combo .addItems (theme_names )
434+ # Select current theme if possible
435+ current_theme = None
436+ for name in theme_names :
437+ if load_theme (name ) == self .data ['stylesheet' ]:
438+ current_theme = name
439+ break
440+ if current_theme :
441+ idx = theme_names .index (current_theme )
442+ ui .theme_combo .setCurrentIndex (idx )
443+ # Handler for theme selection
444+ def on_theme_selected (idx ):
445+ theme_name = theme_names [idx ]
446+ ui .stylesheet_text .setPlainText (load_theme (theme_name ))
447+ ui .theme_combo .currentIndexChanged .connect (on_theme_selected )
177448 ui .example_button .clicked .connect (self .on_set_green_button_theme )
178449
179450 # save reference to widget
180451 self .widgets = {}
181452 self .widgets ['stylesheet' ] = ui .stylesheet_text
182453 self .widgets ['example_button' ] = ui .example_button
183-
184- return ui ,None
454+ self . widgets [ 'theme_combo' ] = ui . theme_combo
455+ return ui , None
185456
186457 def get_value (self ,name ):
187458 if name in self .data :
@@ -206,5 +477,3 @@ def save(self):
206477
207478 def close (self ):
208479 self .widgets ['example_button' ].clicked .disconnect (self .on_set_green_button_theme )
209-
210-
0 commit comments