diff --git a/src/aare/gui/main_window.py b/src/aare/gui/main_window.py index de2755eb..2b15e032 100644 --- a/src/aare/gui/main_window.py +++ b/src/aare/gui/main_window.py @@ -1683,6 +1683,8 @@ class MainWindow(QMainWindow): def _apply_theme(self) -> None: self.setStyleSheet(build_app_stylesheet(self._theme_mode)) + # State colors are painted in code per DAQ tick — QSS can't reach them. + self.beamline_state_panel.set_theme(self._theme_mode) def _restore_theme_settings(self) -> None: settings = QSettings("PSI", "AareGUI") diff --git a/src/aare/gui/panels/beamline_state_panel.py b/src/aare/gui/panels/beamline_state_panel.py index db372118..c3aa89aa 100644 --- a/src/aare/gui/panels/beamline_state_panel.py +++ b/src/aare/gui/panels/beamline_state_panel.py @@ -5,13 +5,7 @@ from PySide6.QtCore import Qt, QTimer, Signal, Slot from PySide6.QtGui import QCursor, QFont, QFontMetrics from PySide6.QtWidgets import QFrame, QHBoxLayout, QLabel, QMenu, QPushButton, QSizePolicy, QToolTip -from aare.gui.styles import ( - FONT_VALUE, - STATE_AVAILABLE, - STATE_MSG_ERROR, - STATE_MSG_INFO, - STATE_UNAVAILABLE, -) +from aare.gui.styles import FONT_VALUE, THEME_ORIGINAL, state_colors # Shortcut transitions from the "Available transitions" menu in # widgets/status_bar.py show_state_menu — these come ON TOP of the one-hop @@ -146,8 +140,9 @@ class BeamlineStatePanel(QFrame): self._hover_hint_timer.setInterval(3000) self._hover_hint_timer.timeout.connect(self._show_hover_hint) - self._available_color = STATE_AVAILABLE - self._unavailable_color = STATE_UNAVAILABLE + # Per-theme colors (MainWindow._apply_theme calls set_theme). + self._colors = state_colors(THEME_ORIGINAL) + self._separators: list[QLabel] = [] layout = QHBoxLayout(self) layout.setContentsMargins(10, 2, 10, 2) @@ -159,9 +154,8 @@ class BeamlineStatePanel(QFrame): for index, (state, label) in enumerate(self._ENTRIES): if index: separator = QLabel("–", self) - separator.setStyleSheet( - f"color: {STATE_UNAVAILABLE}; background: transparent; border: none; font-size: {FONT_VALUE};" - ) + self._style_separator(separator) + self._separators.append(separator) layout.addWidget(separator) button = HoverableButton(label, self) button.setFlat(True) @@ -310,6 +304,21 @@ class BeamlineStatePanel(QFrame): elif state == BeamlineStateEnum.XrayFluorescence: self.xray_fluorescence.emit() + def _style_separator(self, separator: QLabel) -> None: + separator.setStyleSheet( + f"color: {self._colors['unavailable']};" + f" background: transparent; border: none; font-size: {FONT_VALUE};" + ) + + def set_theme(self, theme: str) -> None: + """Adopt the theme's state colors (MainWindow._apply_theme calls this + on every switch — the colors are painted in code, so the app QSS + alone cannot restyle them).""" + self._colors = state_colors(theme) + for separator in self._separators: + self._style_separator(separator) + self._apply_highlight() + def _apply_highlight(self) -> None: available = self._available_targets() for state, button in self._buttons.items(): @@ -325,14 +334,16 @@ class BeamlineStatePanel(QFrame): # No backgrounds, no rounded corners. if is_current or is_pending: color = ( - STATE_MSG_ERROR if state == BeamlineStateEnum.Maintenance else STATE_MSG_INFO + self._colors["error"] + if state == BeamlineStateEnum.Maintenance + else self._colors["info"] ) bold = True elif is_available: - color = self._available_color + color = self._colors["available"] bold = False else: - color = self._unavailable_color + color = self._colors["unavailable"] bold = False # Font set in code (not QSS) so _update_label_mode can measure diff --git a/src/aare/gui/styles.py b/src/aare/gui/styles.py index 0e0dd335..405cebf2 100644 --- a/src/aare/gui/styles.py +++ b/src/aare/gui/styles.py @@ -333,11 +333,35 @@ STATUS_VACANT = "#ffff00" # baton vacant (was "yellow") STATUS_REQUEST = "#00ffff" # baton request (was "cyan") # -- Beamline state panel --------------------------------------------------- -# The panel paints these in code per DAQ tick (data-driven), not via QSS. +# The panel paints these in code per DAQ tick (data-driven), so it asks +# state_colors(theme) below instead of QSS. Light values unchanged; dark +# values are Catppuccin Mocha so they stay readable on the sunset sky. STATE_AVAILABLE = "#ed8936" STATE_UNAVAILABLE = "#8c96a5" STATE_MSG_ERROR = "#c81e1e" STATE_MSG_INFO = "#005caa" +DARK_STATE_AVAILABLE = "#fab387" # mocha peach +DARK_STATE_UNAVAILABLE = "#7f849c" # mocha overlay1 +DARK_STATE_MSG_ERROR = "#f38ba8" # mocha red +DARK_STATE_MSG_INFO = "#89b4fa" # mocha blue + + +def state_colors(theme: str) -> dict[str, str]: + """Beamline-state text colors for the given theme.""" + if theme == THEME_PORTRAIT: + return { + "available": DARK_STATE_AVAILABLE, + "unavailable": DARK_STATE_UNAVAILABLE, + "error": DARK_STATE_MSG_ERROR, + "info": DARK_STATE_MSG_INFO, + } + return { + "available": STATE_AVAILABLE, + "unavailable": STATE_UNAVAILABLE, + "error": STATE_MSG_ERROR, + "info": STATE_MSG_INFO, + } + # -- Sample tables + raster grid -------------------------------------------- SAMPLE_ROW_ACTIVE_BG = "#ff6600"