feat: rename themes to sunrise/sunset, add bluebird theme with Catppuccin-Latte light palette
Sunrise/sunset replace the original/portrait tokens (QSettings values migrate on restore); bluebird is sunrise with a flat sky. The light palette is repainted with Catppuccin Latte across alerts, chips, cards, log, splash, inputs, and status flags, plus button/input height caps and hover rules in the QSS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+27
-10
@@ -98,9 +98,10 @@ from aare.gui.styles import (
|
||||
DARK_TEXT,
|
||||
DOCK_CONTENT_LEFT_PAD,
|
||||
SEPARATOR_HINT_DELAY_MS,
|
||||
THEME_BLUEBIRD,
|
||||
THEME_FADE_MS,
|
||||
THEME_ORIGINAL,
|
||||
THEME_PORTRAIT,
|
||||
THEME_SUNRISE,
|
||||
THEME_SUNSET,
|
||||
build_app_stylesheet,
|
||||
qcolor,
|
||||
)
|
||||
@@ -179,7 +180,7 @@ class MainWindow(QMainWindow):
|
||||
# default) so the mutable list is per-instance (RUF012).
|
||||
self._pre_vacancy_open_banners: list[TitleLabel] = []
|
||||
|
||||
self._theme_mode = THEME_ORIGINAL
|
||||
self._theme_mode = THEME_SUNRISE
|
||||
self._theme_action_group = None
|
||||
self._use_legacy_theme_action = None
|
||||
self._use_portrait_theme_action = None
|
||||
@@ -1754,7 +1755,7 @@ class MainWindow(QMainWindow):
|
||||
assert isinstance(app, QApplication) # palette() lives on QApplication
|
||||
if not hasattr(self, "_default_palette"):
|
||||
self._default_palette = app.palette()
|
||||
if self._theme_mode == THEME_PORTRAIT:
|
||||
if self._theme_mode == THEME_SUNSET:
|
||||
palette = QPalette(self._default_palette)
|
||||
for role in (
|
||||
QPalette.ColorRole.ButtonText,
|
||||
@@ -1788,7 +1789,11 @@ class MainWindow(QMainWindow):
|
||||
def _restore_theme_settings(self) -> None:
|
||||
settings = QSettings("PSI", "AareGUI")
|
||||
# str() wrap: settings.value is typed object even with type=str.
|
||||
self._theme_mode = str(settings.value("appearance/theme", THEME_ORIGINAL, type=str))
|
||||
saved = str(settings.value("appearance/theme", THEME_SUNRISE, type=str))
|
||||
# Migrate the pre-rename tokens so a saved theme survives the value
|
||||
# change (styles.py: "original"->"sunrise", "portrait"->"sunset").
|
||||
saved = {"original": THEME_SUNRISE, "portrait": THEME_SUNSET}.get(saved, saved)
|
||||
self._theme_mode = saved
|
||||
|
||||
def _save_theme_settings(self) -> None:
|
||||
settings = QSettings("PSI", "AareGUI")
|
||||
@@ -1796,12 +1801,17 @@ class MainWindow(QMainWindow):
|
||||
|
||||
@Slot()
|
||||
def use_legacy_theme(self) -> None:
|
||||
self._theme_mode = THEME_ORIGINAL
|
||||
self._theme_mode = THEME_SUNRISE
|
||||
self._apply_theme()
|
||||
|
||||
@Slot()
|
||||
def use_portrait_theme(self) -> None:
|
||||
self._theme_mode = THEME_PORTRAIT
|
||||
self._theme_mode = THEME_SUNSET
|
||||
self._apply_theme()
|
||||
|
||||
@Slot()
|
||||
def use_bluebird_theme(self) -> None:
|
||||
self._theme_mode = THEME_BLUEBIRD
|
||||
self._apply_theme()
|
||||
|
||||
def create_menu_bar(self):
|
||||
@@ -1839,17 +1849,24 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self._use_legacy_theme_action = QAction("Sunrise Theme (default)", self)
|
||||
self._use_legacy_theme_action.setCheckable(True)
|
||||
self._use_legacy_theme_action.setChecked(self._theme_mode == THEME_ORIGINAL)
|
||||
self._use_legacy_theme_action.setChecked(self._theme_mode == THEME_SUNRISE)
|
||||
self._use_legacy_theme_action.triggered.connect(self.use_legacy_theme)
|
||||
self._theme_action_group.addAction(self._use_legacy_theme_action)
|
||||
|
||||
self._use_portrait_theme_action = QAction("Sunset Theme", self)
|
||||
self._use_portrait_theme_action = QAction("Sunset Theme (work in progress)", self)
|
||||
self._use_portrait_theme_action.setCheckable(True)
|
||||
self._use_portrait_theme_action.setChecked(self._theme_mode == THEME_PORTRAIT)
|
||||
self._use_portrait_theme_action.setChecked(self._theme_mode == THEME_SUNSET)
|
||||
self._use_portrait_theme_action.triggered.connect(self.use_portrait_theme)
|
||||
self._theme_action_group.addAction(self._use_portrait_theme_action)
|
||||
|
||||
self._use_bluebird_theme_action = QAction("Bluebird Theme", self)
|
||||
self._use_bluebird_theme_action.setCheckable(True)
|
||||
self._use_bluebird_theme_action.setChecked(self._theme_mode == THEME_BLUEBIRD)
|
||||
self._use_bluebird_theme_action.triggered.connect(self.use_bluebird_theme)
|
||||
self._theme_action_group.addAction(self._use_bluebird_theme_action)
|
||||
|
||||
view_menu.addAction(self._use_legacy_theme_action)
|
||||
view_menu.addAction(self._use_bluebird_theme_action)
|
||||
view_menu.addAction(self._use_portrait_theme_action)
|
||||
view_menu.addSeparator()
|
||||
view_menu.addAction(self._portrait_mode_action)
|
||||
|
||||
@@ -5,7 +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, THEME_ORIGINAL, state_colors
|
||||
from aare.gui.styles import FONT_VALUE, THEME_SUNRISE, 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
|
||||
@@ -141,7 +141,7 @@ class BeamlineStatePanel(QFrame):
|
||||
self._hover_hint_timer.timeout.connect(self._show_hover_hint)
|
||||
|
||||
# Per-theme colors (MainWindow._apply_theme calls set_theme).
|
||||
self._colors = state_colors(THEME_ORIGINAL)
|
||||
self._colors = state_colors(THEME_SUNRISE)
|
||||
self._separators: list[QLabel] = []
|
||||
|
||||
layout = QHBoxLayout(self)
|
||||
|
||||
+281
-185
@@ -3,8 +3,14 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
from string import Template
|
||||
|
||||
THEME_ORIGINAL = "original"
|
||||
THEME_PORTRAIT = "portrait"
|
||||
# These string values are the tokens persisted in QSettings("appearance/theme").
|
||||
# They were renamed from "original"/"portrait"; MainWindow._restore_theme_settings
|
||||
# migrates the old tokens so a user's saved theme survives the rename.
|
||||
THEME_SUNRISE = "sunrise"
|
||||
THEME_SUNSET = "sunset"
|
||||
# Sunrise with the sky gradient flattened to its top color — for consoles
|
||||
# where the gradient banding distracts, and as a plain-background baseline.
|
||||
THEME_BLUEBIRD = "bluebird"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Color palette. Change values HERE to try a different look — the QSS below
|
||||
@@ -16,16 +22,16 @@ THEME_PORTRAIT = "portrait"
|
||||
|
||||
# -- Light theme ------------------------------------------------------------
|
||||
BACKGROUND = "#e2e7ee"
|
||||
# App-wide dusk-sky gradient (sampled from the reference photo): slate blue
|
||||
# fading through pale grey-lavender into warm cream. Painted once per
|
||||
# top-level window (QMainWindow/QDialog) while plain child widgets stay
|
||||
# transparent, so the window reads as ONE continuous sky instead of every
|
||||
# widget restarting the gradient. Tune the stops here; set all three stops
|
||||
# to BACKGROUND to get the old flat look back.
|
||||
# App-wide sunrise-sky gradient (sampled from the reference photo taken at dawn
|
||||
# near Dawn's house at Windisch: slate blue fading through pale grey-lavender
|
||||
# into warm cream. Painted once per top-level window (QMainWindow/QDialog)
|
||||
# while plain child widgets stay transparent, so the window reads as ONE
|
||||
# continuous sky instead of every widget restarting the gradient.
|
||||
# Tune the transition point here:
|
||||
BACKGROUND_GRADIENT_TOP = "#84abd9" # RHEL9 window-frame blue (sampled from screenshot)
|
||||
BACKGROUND_GRADIENT_MID = "#c6cad6"
|
||||
BACKGROUND_GRADIENT_MID_POS = "0.55" # 0..1 — where the mid stop sits
|
||||
BACKGROUND_GRADIENT_BOTTOM = "#f6e9dd"
|
||||
BACKGROUND_GRADIENT_MID = "#bbd6f6"
|
||||
BACKGROUND_GRADIENT_MID_POS = "0.65" # 0..1 — where the mid stop sits
|
||||
BACKGROUND_GRADIENT_BOTTOM = "#dbe9f9"
|
||||
APP_BACKGROUND = (
|
||||
"qlineargradient(x1:0, y1:0, x2:0, y2:1,"
|
||||
f" stop:0 {BACKGROUND_GRADIENT_TOP},"
|
||||
@@ -52,7 +58,12 @@ SURFACE = "#f2f2f2" # input fields, cards, group boxes
|
||||
|
||||
# Buttons: flat + hairline like the dark theme (the explicit border is what
|
||||
# switches Qt from bulky native chrome to compact QSS box rendering).
|
||||
BUTTON_BG = "#f7f9fc"
|
||||
# Half-transparent so the sky gradient shimmers through, same glass idea as
|
||||
# INPUT_BG — slightly more solid so clickables read as raised faces.
|
||||
BUTTON_BG = "rgba(255, 255, 255, 50%)"
|
||||
# Hover: a dark ink tint instead of more white — darkens whatever sky shade
|
||||
# is behind the button (the dark theme hovers LIGHTER, see DARK_ELEVATED_HOVER).
|
||||
BUTTON_BG_HOVER = "rgba(76, 79, 105, 18%)"
|
||||
BUTTON_BORDER = "#c9cfd8" # same tone as FRAME_L3_COLOR, separate knob
|
||||
|
||||
# Spin/combo arrow glyphs: tiny PNGs — this Qt draws neither native glyphs
|
||||
@@ -102,7 +113,7 @@ BANNER_TAB_GAP = 6
|
||||
# one for SEPARATOR_HINT_DELAY_MS (or a drag starts) — then only the exact
|
||||
# separator under the cursor fills with SEPARATOR_HINT. The rest/drag gate
|
||||
# lives in MainWindow.event(); the QSS :hover part picks the one separator.
|
||||
SEPARATOR_HINT = "rgba(168, 178, 192, 50%)" # scrollbar-track grey @50%
|
||||
SEPARATOR_HINT = "rgba(168, 178, 192, 20%)" # scrollbar-track grey @50%
|
||||
SEPARATOR_HINT_DELAY_MS = 888 # int, used in code, not QSS
|
||||
|
||||
# Theme-switch screenshot cross-fade duration (int ms, used in code).
|
||||
@@ -133,15 +144,17 @@ SECONDARY_BG = "#dfe9fb"
|
||||
SECONDARY_BG_HOVER = "#d3e1f8"
|
||||
|
||||
# Alert banners (alertKind: error / success / waiting=warning):
|
||||
ERROR_BG = "#fbe4e6"
|
||||
ERROR_BORDER = "#d97a84"
|
||||
ERROR_TEXT = "#8f1d2c"
|
||||
SUCCESS_BG = "#e7f6ea"
|
||||
SUCCESS_BORDER = "#7bbf8e"
|
||||
SUCCESS_TEXT = "#1f6a3a"
|
||||
WARNING_BG = "#fff8e1"
|
||||
WARNING_BORDER = "#ffb300"
|
||||
WARNING_TEXT = "#e65100"
|
||||
# Catppuccin Latte: BG = 15% accent over base, border = 50%, text = 65% over
|
||||
# Latte text — same recipe as the chips/cards/log blocks below.
|
||||
ERROR_BG = "#ebcfd9" # red wash
|
||||
ERROR_BORDER = "#e08097"
|
||||
ERROR_TEXT = "#a3254a"
|
||||
SUCCESS_BG = "#d5e5d7" # green wash
|
||||
SUCCESS_BORDER = "#98c890"
|
||||
SUCCESS_TEXT = "#448441"
|
||||
WARNING_BG = "#f1dcd2" # peach wash
|
||||
WARNING_BORDER = "#f6aa80"
|
||||
WARNING_TEXT = "#c05d2c"
|
||||
|
||||
# Axis video status + beamline state bar:
|
||||
STATUS_IDLE_BG = "#d9e2f2"
|
||||
@@ -181,6 +194,7 @@ DARK_APP_BACKGROUND = (
|
||||
DARK_PANEL2 = "#0e1728" # panel2 — deepest opaque: menus, popups, tooltips
|
||||
DARK_SURFACE = "#1c2b4a" # panel — cards, state panel, scrollbar track
|
||||
DARK_ELEVATED = "#253148" # glass2 (7% white) flattened — buttons, banners
|
||||
DARK_ELEVATED_HOVER = "#32405c" # one glass step lighter — button hover
|
||||
# Solid, not transparent: scroll-area viewports don't composite the window
|
||||
# gradient on the container's X11 and render BLACK instead. Lighter sky-navy
|
||||
# so tables don't read near-black against the backdrop.
|
||||
@@ -238,108 +252,106 @@ WHITE = "#ffffff"
|
||||
# ONLY for theme-independent light surfaces (tutorial callout). To "reset" a
|
||||
# themed label, clear its stylesheet ("") so the theme color applies — a
|
||||
# hardcoded black reset is invisible in the dark theme.
|
||||
DEFAULT_TEXT = "#000000"
|
||||
NOTE_TEXT = "#555555" # tutorial hints, TELL sample details
|
||||
DIM_TEXT = "#666666" # baton dialog timers
|
||||
HINT_TEXT = "#999999" # baton dialog fine print
|
||||
HEADING_TEXT = "#1e293b" # card headings (slate-800)
|
||||
SUBTLE_TEXT = "#334155" # card body text (slate-700)
|
||||
MUTED_TEXT = "#475569" # neutral chip / idle step text (slate-600)
|
||||
FAINT_TEXT = "#64748b" # pending/skipped step text (slate-500)
|
||||
DEFAULT_TEXT = "#4c4f69" # latte text
|
||||
NOTE_TEXT = "#5c5f77" # tutorial hints, TELL sample details (latte subtext1)
|
||||
DIM_TEXT = "#6c6f85" # baton dialog timers (latte subtext0)
|
||||
HINT_TEXT = "#9ca0b0" # baton dialog fine print (latte overlay0)
|
||||
HEADING_TEXT = "#4c4f69" # card headings (latte text)
|
||||
SUBTLE_TEXT = "#5c5f77" # card body text (latte subtext1)
|
||||
MUTED_TEXT = "#6c6f85" # neutral chip / idle step text (latte subtext0)
|
||||
FAINT_TEXT = "#8c8fa1" # pending/skipped step text (latte overlay1)
|
||||
SHADOW = "#000000" # drop shadows & tutorial scrim; alpha stays at call site
|
||||
|
||||
# -- Semantic action colors -------------------------------------------------
|
||||
GO_TEXT = "#4e9a06" # green start/run/measure button text
|
||||
ABORT_TEXT = "#a40000" # abort button text
|
||||
ALERT_TEXT = "#ff0000" # out-of-range motor labels
|
||||
PATH_WARN_TEXT = "#c80000" # file-exists warning in path panel
|
||||
DANGER_ACCENT = "#d9534f" # invalid p-group border + message text
|
||||
GO_TEXT = "#40a02b" # green start/run/measure button text
|
||||
ABORT_TEXT = "#d20f39" # abort button text (red)
|
||||
ALERT_TEXT = "#d20f39" # out-of-range motor labels (red)
|
||||
PATH_WARN_TEXT = "#e64553" # file-exists warning in path panel (maroon)
|
||||
DANGER_ACCENT = "#e64553" # invalid p-group border + message text (maroon)
|
||||
|
||||
# -- Status chips (local contact status) — "good" reuses SUCCESS_BG/TEXT ----
|
||||
CHIP_WARN_BG = "#fff3cd"
|
||||
CHIP_WARN_TEXT = "#7a4b00"
|
||||
CHIP_BAD_BG = "#fdeaea"
|
||||
CHIP_BAD_TEXT = "#8b1e1e"
|
||||
CHIP_NEUTRAL_BG = "#e9eef5" # text uses MUTED_TEXT
|
||||
CHIP_INFO_BG = "#e8f1ff"
|
||||
CHIP_INFO_TEXT = "#12406a"
|
||||
CHIP_WARN_BG = "#ede2d5" # yellow wash
|
||||
CHIP_WARN_TEXT = "#ac7838"
|
||||
CHIP_BAD_BG = "#ebcfd9" # red wash
|
||||
CHIP_BAD_TEXT = "#a3254a"
|
||||
CHIP_NEUTRAL_BG = "#e6e9ef" # latte mantle; text uses MUTED_TEXT
|
||||
CHIP_INFO_BG = "#d0dcf5" # blue wash
|
||||
CHIP_INFO_TEXT = "#2e5ec4"
|
||||
|
||||
# -- Status cards (beamline recovery, local contact error frame) ------------
|
||||
# TODO: recovery-card colors are inherited from the old ad-hoc design and
|
||||
# stand out against the app palette — retheme them here when ready.
|
||||
WARN_CARD_BORDER = "#f0c36d"
|
||||
BAD_CARD_BORDER = "#e6a8a8"
|
||||
INFO_CARD_BG = "#eef6ff"
|
||||
INFO_CARD_BORDER = "#a8c7e6"
|
||||
PENDING_CARD_BG = "#fff7db"
|
||||
PENDING_CARD_BORDER = "#e7cb73"
|
||||
WARN_CARD_BORDER = "#e9cea9" # yellow border
|
||||
BAD_CARD_BORDER = "#e5a2b3" # red border
|
||||
INFO_CARD_BG = "#d0dcf5" # blue wash
|
||||
INFO_CARD_BORDER = "#a6c0f5"
|
||||
PENDING_CARD_BG = "#ede2d5" # yellow wash
|
||||
PENDING_CARD_BORDER = "#e9cea9"
|
||||
|
||||
# -- Log panel --------------------------------------------------------------
|
||||
# TODO: console-log notification colors are inherited from the old ad-hoc
|
||||
# design and stand out against the app palette — retheme them here when ready.
|
||||
LOG_BORDER = "#8a8a8a"
|
||||
LOG_PANEL_BG = "#fff4f4"
|
||||
LOG_ERROR_BG = "#fff1f1"
|
||||
LOG_ERROR_BORDER = "#dd6666"
|
||||
LOG_WARN_BG = "#fff8e8"
|
||||
LOG_WARN_BORDER = "#d7aa42"
|
||||
LOG_SUCCESS_BG = "#eefaf0"
|
||||
LOG_SUCCESS_BORDER = "#6cb37a"
|
||||
LOG_INFO_BG = "#eef5ff"
|
||||
LOG_INFO_BORDER = "#6b9bd6"
|
||||
LOG_BORDER = "#8c8fa1" # latte overlay1
|
||||
LOG_PANEL_BG = "#ecdae2" # faint red wash
|
||||
LOG_ERROR_BG = "#ebcfd9"
|
||||
LOG_ERROR_BORDER = "#e08097"
|
||||
LOG_WARN_BG = "#ede2d5"
|
||||
LOG_WARN_BORDER = "#e7c089"
|
||||
LOG_SUCCESS_BG = "#d5e5d7"
|
||||
LOG_SUCCESS_BORDER = "#98c890"
|
||||
LOG_INFO_BG = "#d0dcf5"
|
||||
LOG_INFO_BORDER = "#86acf5"
|
||||
|
||||
# -- Automation panel + progress steps --------------------------------------
|
||||
AUTOMATION_TITLE_TEXT = "#1f2937"
|
||||
AUTOMATION_HINT_TEXT = "#374151"
|
||||
STEP_RUNNING_TEXT = "#2563eb" # same blue as PRIMARY, separate knob
|
||||
STEP_SUCCESS_TEXT = "#15803d"
|
||||
STEP_FAILED_TEXT = "#b91c1c"
|
||||
STEP_PAUSED_TEXT = "#c2410c"
|
||||
STEP_DONE_BG = "#ecfdf3"
|
||||
STEP_DONE_TEXT = "#166534"
|
||||
STEP_DONE_BORDER = "#a7f3d0"
|
||||
STEP_ACTIVE_BG = "#eff6ff"
|
||||
STEP_ACTIVE_TEXT = "#1d4ed8"
|
||||
STEP_ACTIVE_BORDER = "#bfdbfe"
|
||||
STEP_FAILED_BG = "#fef2f2"
|
||||
STEP_FAILED_BORDER = "#fecaca"
|
||||
STEP_PAUSED_BG = "#fff7ed"
|
||||
STEP_PAUSED_BORDER = "#fed7aa"
|
||||
STEP_IDLE_BG = "#f8fafc"
|
||||
STEP_IDLE_BORDER = "#e2e8f0"
|
||||
AUTOMATION_TITLE_TEXT = "#4c4f69" # latte text
|
||||
AUTOMATION_HINT_TEXT = "#5c5f77" # latte subtext1
|
||||
STEP_RUNNING_TEXT = "#1e66f5" # latte blue — same as PRIMARY, separate knob
|
||||
STEP_SUCCESS_TEXT = "#40a02b" # green
|
||||
STEP_FAILED_TEXT = "#d20f39" # red
|
||||
STEP_PAUSED_TEXT = "#c05d2c" # peach ink
|
||||
STEP_DONE_BG = "#d5e5d7" # green wash
|
||||
STEP_DONE_TEXT = "#448441"
|
||||
STEP_DONE_BORDER = "#b2d5ae"
|
||||
STEP_ACTIVE_BG = "#d0dcf5" # blue wash
|
||||
STEP_ACTIVE_TEXT = "#2e5ec4"
|
||||
STEP_ACTIVE_BORDER = "#a6c0f5"
|
||||
STEP_FAILED_BG = "#ebcfd9" # red wash
|
||||
STEP_FAILED_BORDER = "#e5a2b3"
|
||||
STEP_PAUSED_BG = "#f1dcd2" # peach wash
|
||||
STEP_PAUSED_BORDER = "#f4c0a3"
|
||||
STEP_IDLE_BG = "#eff1f5" # latte base
|
||||
STEP_IDLE_BORDER = "#dce0e8" # latte crust
|
||||
|
||||
# -- Baton request dialog ---------------------------------------------------
|
||||
BATON_OK_BG = "#4caf50"
|
||||
BATON_OK_HOVER = "#45a049"
|
||||
BATON_OK_PRESSED = "#3d8b40"
|
||||
BATON_DANGER_BG = "#f44336"
|
||||
BATON_DANGER_HOVER = "#da190b"
|
||||
BATON_DANGER_PRESSED = "#c41000"
|
||||
BATON_WARN = "#ff9800"
|
||||
BATON_INFO = "#2196f3"
|
||||
LIGHT_BORDER = "#cccccc"
|
||||
PROGRESS_TRACK_BG = "#f0f0f0"
|
||||
# Hover/pressed are the accent mixed 12%/24% toward Latte text.
|
||||
BATON_OK_BG = "#40a02b" # green
|
||||
BATON_OK_HOVER = "#419632"
|
||||
BATON_OK_PRESSED = "#438d3a"
|
||||
BATON_DANGER_BG = "#d20f39" # red
|
||||
BATON_DANGER_HOVER = "#c2173f"
|
||||
BATON_DANGER_PRESSED = "#b21e45"
|
||||
BATON_WARN = "#fe640b" # peach
|
||||
BATON_INFO = "#1e66f5" # blue
|
||||
LIGHT_BORDER = "#bcc0cc" # latte surface1
|
||||
PROGRESS_TRACK_BG = "#e6e9ef" # latte mantle
|
||||
|
||||
# -- Splash screen ----------------------------------------------------------
|
||||
SPLASH_BG = "#222222"
|
||||
SPLASH_BORDER = "#444444"
|
||||
SPLASH_ACCENT = "#0078d7"
|
||||
SPLASH_BG = "#dce0e8" # latte crust (progress-bar track)
|
||||
SPLASH_BORDER = "#bcc0cc" # latte surface1
|
||||
SPLASH_ACCENT = "#1e66f5" # latte blue
|
||||
SPLASH_TEXT = "#4c4f69" # latte text — bar % and loading message
|
||||
|
||||
# -- Numeric inputs ---------------------------------------------------------
|
||||
# Translucent, not solid white: the sky gradient shimmers through the field
|
||||
# while text stays on a light ground. Raise the % for a more solid face.
|
||||
INPUT_BG = "rgba(255, 255, 255, 33%)"
|
||||
INPUT_INVALID_BG = "#ffd5d5"
|
||||
INPUT_DISABLED_BG = "#f0f0f0"
|
||||
INPUT_DISABLED_INVALID_BG = "#f0e1e1"
|
||||
INPUT_INVALID_BG = "#e9c4cf" # red 20% over latte base
|
||||
INPUT_DISABLED_BG = "#e6e9ef" # latte mantle
|
||||
INPUT_DISABLED_INVALID_BG = "#ecdae2" # faint red wash
|
||||
|
||||
# -- Status bar flags (hex equivalents of the old CSS named colors) ---------
|
||||
STATUS_OK = "#008000" # closed / idle / owned / tell ok (was "green")
|
||||
STATUS_ALERT = "#ff0000" # open / busy / other-owner / hot cryo (was "red")
|
||||
STATUS_WARN = "#ffa500" # baton waiting / warming cryo / tell busy (was "orange")
|
||||
STATUS_INFO = "#0000ff" # cold cryo (was "blue")
|
||||
STATUS_VACANT = "#ffff00" # baton vacant (was "yellow")
|
||||
STATUS_REQUEST = "#00ffff" # baton request (was "cyan")
|
||||
# -- Status bar flags (Catppuccin Latte) ------------------------------------
|
||||
STATUS_OK = "#40a02b" # closed / idle / owned / tell ok (green)
|
||||
STATUS_ALERT = "#d20f39" # open / busy / other-owner / hot cryo (red)
|
||||
STATUS_WARN = "#fe640b" # baton waiting / warming cryo / tell busy (peach)
|
||||
STATUS_INFO = "#1e66f5" # cold cryo (blue)
|
||||
STATUS_VACANT = "#df8e1d" # baton vacant (yellow)
|
||||
STATUS_REQUEST = "#04a5e5" # baton request (sky)
|
||||
|
||||
# -- Beamline state panel ---------------------------------------------------
|
||||
# The panel paints these in code per DAQ tick (data-driven), so it asks
|
||||
@@ -357,7 +369,7 @@ 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:
|
||||
if theme == THEME_SUNSET:
|
||||
return {
|
||||
"available": DARK_STATE_AVAILABLE,
|
||||
"unavailable": DARK_STATE_UNAVAILABLE,
|
||||
@@ -393,86 +405,89 @@ SAMPLE_STATUS_SELECTED_BG = "#d8e8fd" # pale blue — table selection highlight
|
||||
SAMPLE_STATUS_TEXT = "#263043"
|
||||
|
||||
# -- Camera / video overlay (painter colors, alpha at call site) ------------
|
||||
BEAM_OPEN = "#00ff00" # beam marker: shutter open
|
||||
BEAM_IDLE = "#f57900" # beam marker: idle
|
||||
BEAM_BUSY = "#ff0000" # beam marker: busy
|
||||
BEAM_MARKING = "#663399" # beam marker: marking mode
|
||||
MARKER_GREEN = "#32cd32" # loop-centering click marker
|
||||
PATH_START = "#008000" # raster path gradient start + start circle
|
||||
PATH_END = "#ff0000" # raster path gradient end + end circle
|
||||
LEGEND_BG = "#141414"
|
||||
LEGEND_TEXT = "#f0f0f0"
|
||||
TOOLTIP_TEXT = "#e6e6e6" # camera coords tooltip pen — NOT the QToolTip popup
|
||||
MARK_TOOLTIP_GOLD = "#ffd700"
|
||||
MARK_TOOLTIP_ORANGE = "#ffa500"
|
||||
MARK_TOOLTIP_RED = "#ff0000"
|
||||
MARK_BADGE_BG = "#b43c00"
|
||||
# Palette: Catppuccin Latte (light flavor) — softer than the old pure-RGB set.
|
||||
BEAM_OPEN = "#40a02b" # beam marker: shutter open (green)
|
||||
BEAM_IDLE = "#fe640b" # beam marker: idle (peach)
|
||||
BEAM_BUSY = "#d20f39" # beam marker: busy (red)
|
||||
BEAM_MARKING = "#8839ef" # beam marker: marking mode (mauve)
|
||||
MARKER_GREEN = "#40a02b" # loop-centering click marker (green)
|
||||
PATH_START = "#40a02b" # raster path gradient start + start circle (green)
|
||||
PATH_END = "#d20f39" # raster path gradient end + end circle (red)
|
||||
LEGEND_BG = "#eff1f5" # base
|
||||
LEGEND_TEXT = "#4c4f69" # text
|
||||
TOOLTIP_TEXT = "#4c4f69" # camera coords tooltip pen — NOT the QToolTip popup
|
||||
MARK_TOOLTIP_GOLD = "#df8e1d" # yellow
|
||||
MARK_TOOLTIP_ORANGE = "#fe640b" # peach
|
||||
MARK_TOOLTIP_RED = "#d20f39" # red
|
||||
MARK_BADGE_BG = "#fe640b" # peach
|
||||
|
||||
# Prediction class overlay colors. The chart variant historically used pure
|
||||
# green (#00ff00) while the overlay used CSS green (#008000) — both kept.
|
||||
# Prediction class overlay colors. The old pure-green vs CSS-green split
|
||||
# between chart and overlay collapses to the single Latte green.
|
||||
CLASS_COLORS = {
|
||||
"pin": "#ff0000",
|
||||
"loop_all": "#008000",
|
||||
"loop_face": "#ffff00",
|
||||
"crystal": "#0000ff",
|
||||
"needle": "#ff00ff",
|
||||
"ice": "#00ffff",
|
||||
"pin": "#d20f39", # red
|
||||
"loop_all": "#40a02b", # green
|
||||
"loop_face": "#df8e1d", # yellow
|
||||
"crystal": "#1e66f5", # blue
|
||||
"needle": "#ea76cb", # pink
|
||||
"ice": "#04a5e5", # sky
|
||||
}
|
||||
CHART_CLASS_COLORS = {
|
||||
"Pin": "#ff0000",
|
||||
"Loop_all": "#00ff00",
|
||||
"Loop_face": "#ffff00",
|
||||
"Crystal": "#0000ff",
|
||||
"Needle": "#ff00ff",
|
||||
"Ice": "#00ffff",
|
||||
"Pin": "#d20f39",
|
||||
"Loop_all": "#40a02b",
|
||||
"Loop_face": "#df8e1d",
|
||||
"Crystal": "#1e66f5",
|
||||
"Needle": "#ea76cb",
|
||||
"Ice": "#04a5e5",
|
||||
}
|
||||
TARGET_COLORS = {"Cyan": "#00ffff", "Dark Blue": "#0046a0", "Dark Red": "#8c1919"}
|
||||
TARGET_COLORS = {"Cyan": "#04a5e5", "Dark Blue": "#1e66f5", "Dark Red": "#e64553"}
|
||||
BOOKMARK_COLORS = {
|
||||
"red": "#ff0000",
|
||||
"green": "#008000",
|
||||
"blue": "#0000ff",
|
||||
"indigo": "#4b0082",
|
||||
"lime": "#00ff00",
|
||||
"red": "#d20f39",
|
||||
"green": "#40a02b",
|
||||
"blue": "#1e66f5",
|
||||
"indigo": "#8839ef", # mauve
|
||||
"lime": "#179299", # teal — Latte has one green; teal keeps the pair distinct
|
||||
}
|
||||
|
||||
# -- Busy overlay (per-source color coding) ---------------------------------
|
||||
BUSY_YELLOW = "#f1c40f"
|
||||
BUSY_YELLOW_BORDER = "#fff8d2"
|
||||
BUSY_YELLOW_DOT = "#fff6bf"
|
||||
BUSY_YELLOW_TEXT_DARK = "#3b2f00"
|
||||
BUSY_PURPLE = "#8e44ad"
|
||||
BUSY_PURPLE_BORDER = "#ebdcf5"
|
||||
BUSY_PURPLE_DOT = "#f0dfff"
|
||||
BUSY_RED_BADGE = "#d64545"
|
||||
BUSY_RED_FILL = "#be2828"
|
||||
BUSY_RED_BORDER = "#ffdcdc"
|
||||
BUSY_RED_DOT = "#ffdddd"
|
||||
BUSY_ORANGE = "#e67e22"
|
||||
BUSY_ORANGE_BORDER = "#ffead6"
|
||||
BUSY_ORANGE_DOT = "#fff0db"
|
||||
BUSY_BLUE = "#3498db"
|
||||
BUSY_BLUE_BORDER = "#dcf0ff"
|
||||
BUSY_BLUE_DOT = "#dff2ff"
|
||||
BUSY_PSI_RED = "#e04f39"
|
||||
BUSY_PSI_RED_BORDER = "#ffe1dc"
|
||||
BUSY_PSI_RED_DOT = "#ffd8d1"
|
||||
# Catppuccin Latte accents; BORDER/DOT are 25%/20% mixes toward Latte base.
|
||||
BUSY_YELLOW = "#df8e1d" # yellow
|
||||
BUSY_YELLOW_BORDER = "#ebd8bf"
|
||||
BUSY_YELLOW_DOT = "#ecddca"
|
||||
BUSY_YELLOW_TEXT_DARK = "#4c4f69" # text
|
||||
BUSY_PURPLE = "#8839ef" # mauve
|
||||
BUSY_PURPLE_BORDER = "#d5c3f4"
|
||||
BUSY_PURPLE_DOT = "#daccf4"
|
||||
BUSY_RED_BADGE = "#d20f39" # red
|
||||
BUSY_RED_FILL = "#d20f39" # red
|
||||
BUSY_RED_BORDER = "#e8b8c6"
|
||||
BUSY_RED_DOT = "#e9c4cf"
|
||||
BUSY_ORANGE = "#fe640b" # peach
|
||||
BUSY_ORANGE_BORDER = "#f3ceba"
|
||||
BUSY_ORANGE_DOT = "#f2d5c6"
|
||||
BUSY_BLUE = "#1e66f5" # blue
|
||||
BUSY_BLUE_BORDER = "#bbcef5"
|
||||
BUSY_BLUE_DOT = "#c5d5f5"
|
||||
BUSY_PSI_RED = "#e64553" # maroon — closest Latte to the PSI brand red
|
||||
BUSY_PSI_RED_BORDER = "#edc6cc"
|
||||
BUSY_PSI_RED_DOT = "#edcfd5"
|
||||
|
||||
# -- Charts (prediction metrics, target stability, fluorescence) ------------
|
||||
CHART_BLUE = "#1f77b4"
|
||||
CHART_BLUE_LIGHT = "#6baed6"
|
||||
CHART_BLUE_PALE = "#9ecae1"
|
||||
CHART_RED = "#d62728"
|
||||
CHART_RED_LIGHT = "#ff9896"
|
||||
CHART_RED_DARK = "#c43c39"
|
||||
CHART_ORANGE = "#ff7f0e"
|
||||
CHART_ORANGE_PALE = "#ffbb78"
|
||||
CHART_GREEN = "#2ca02c"
|
||||
CHART_GREEN_PALE = "#98df8a"
|
||||
CHART_CYAN = "#17becf"
|
||||
CHART_PURPLE = "#9467bd"
|
||||
CHART_MUTED = "#888888"
|
||||
# Catppuccin Latte; PALE variants are 35% mixes toward Latte base.
|
||||
CHART_BLUE = "#1e66f5" # blue
|
||||
CHART_BLUE_LIGHT = "#04a5e5" # sky
|
||||
CHART_BLUE_PALE = "#a6c0f5"
|
||||
CHART_RED = "#d20f39" # red
|
||||
CHART_RED_LIGHT = "#dd7878" # flamingo
|
||||
CHART_RED_DARK = "#e64553" # maroon
|
||||
CHART_ORANGE = "#fe640b" # peach
|
||||
CHART_ORANGE_PALE = "#f4c0a3"
|
||||
CHART_GREEN = "#40a02b" # green
|
||||
CHART_GREEN_PALE = "#b2d5ae"
|
||||
CHART_CYAN = "#179299" # teal
|
||||
CHART_PURPLE = "#8839ef" # mauve
|
||||
CHART_MUTED = "#8c8fa1" # overlay1
|
||||
CONFIDENCE_BIN_COLORS = [CHART_RED, CHART_ORANGE, CHART_ORANGE_PALE, CHART_GREEN_PALE, CHART_GREEN]
|
||||
SPECTRUM_LINE = "#cc0000"
|
||||
SPECTRUM_LINE = "#d20f39" # red
|
||||
|
||||
# -- Generic panels (developer help, raster table) --------------------------
|
||||
PANEL_BG_SOFT = "#f6f6f6"
|
||||
@@ -508,9 +523,9 @@ SLIDER_FILL = "#8ba3c7"
|
||||
# -- Scrollbars (rounded, no arrows) ----------------------------------------
|
||||
# Flipped on request: the track is now the darker grey and the draggable
|
||||
# handle the light one; hover therefore lightens further instead of darkening.
|
||||
SCROLLBAR_TRACK = "#a8b2c0"
|
||||
SCROLLBAR_HANDLE = "#d8dde5"
|
||||
SCROLLBAR_HANDLE_HOVER = "#eef1f6"
|
||||
SCROLLBAR_TRACK = "#E4E4E4"
|
||||
SCROLLBAR_HANDLE = "#D4D4D4"
|
||||
SCROLLBAR_HANDLE_HOVER = "#C4C4C4"
|
||||
|
||||
# Disabled-input fill and the slider colors used to borrow the scrollbar
|
||||
# knobs; own knobs so the scrollbar flip above doesn't drag them along.
|
||||
@@ -567,14 +582,20 @@ def card_style(
|
||||
|
||||
|
||||
def build_app_stylesheet(theme: str) -> str:
|
||||
if theme == THEME_PORTRAIT:
|
||||
return _portrait_stylesheet()
|
||||
return _original_stylesheet()
|
||||
if theme == THEME_SUNSET:
|
||||
return _sunset_stylesheet()
|
||||
if theme == THEME_BLUEBIRD:
|
||||
# Same sheet as Sunrise, sky flattened to the solid top color.
|
||||
return _sunrise_stylesheet({"app_background": BACKGROUND_GRADIENT_MID})
|
||||
return _sunrise_stylesheet()
|
||||
|
||||
|
||||
def _original_stylesheet() -> str:
|
||||
def _sunrise_stylesheet(overrides: dict[str, str] | None = None) -> str:
|
||||
mapping = _palette()
|
||||
if overrides:
|
||||
mapping.update(overrides)
|
||||
return Template("""
|
||||
/* Dusk-sky gradient: only top-level windows paint it (rule order
|
||||
/* Sunrise-sky gradient: only top-level windows paint it (rule order
|
||||
matters — this must come AFTER the transparent QWidget rule so it
|
||||
wins the specificity tie). Knobs: BACKGROUND_GRADIENT_* above. */
|
||||
QWidget {
|
||||
@@ -603,10 +624,31 @@ def _original_stylesheet() -> str:
|
||||
}
|
||||
|
||||
/* Flat compact buttons, mirroring the dark theme's elevated+hairline
|
||||
look — the explicit border drops the padded native chrome. */
|
||||
look — the explicit border drops the padded native chrome.
|
||||
min/max-height + vertical padding pinned to the SAME values as
|
||||
the inputs below: without them each widget derives its own height
|
||||
from sizeHint and buttons end up taller than the entry boxes.
|
||||
|
||||
CAUTION: this cap hits EVERY QPushButton/QToolButton/QComboBox.
|
||||
Icon buttons with a fixed size (dock title-bar popout/close) or
|
||||
multi-line buttons (beamline state strip) get squashed: the padding
|
||||
shrinks their content box and Qt scales the icon/text down. Any such
|
||||
widget must opt out with a more specific rule or its own widget-level
|
||||
stylesheet setting padding: 0 / min-height: 0 / its real max-height —
|
||||
see popout_window._titlebar_button and the beamlineStatePanel rule
|
||||
below for the two existing patterns. */
|
||||
QPushButton, QToolButton, QComboBox {
|
||||
background-color: $button_bg;
|
||||
border: 1px solid $button_border;
|
||||
min-height: 16px;
|
||||
max-height: 16px;
|
||||
padding: 1px 8px;
|
||||
}
|
||||
|
||||
/* Hover darkens in the light theme (ink tint over the sky); the dark
|
||||
theme lightens instead — direction always moves toward contrast. */
|
||||
QPushButton:hover, QToolButton:hover, QComboBox:hover {
|
||||
background-color: $button_bg_hover;
|
||||
}
|
||||
|
||||
/* Inputs — centralized (was per-widget INPUT_BG stylesheets, which
|
||||
@@ -617,6 +659,18 @@ def _original_stylesheet() -> str:
|
||||
QLineEdit, QAbstractSpinBox {
|
||||
background-color: $input_bg;
|
||||
border: 1px solid $button_border;
|
||||
min-height: 16px;
|
||||
max-height: 16px;
|
||||
padding: 1px 6px;
|
||||
}
|
||||
|
||||
/* Beamline state strip: exempt from the global control-height cap.
|
||||
Its entries are QPushButtons that wrap to two lines when the window
|
||||
is narrow (see BeamlineStatePanel._update_label_mode) — the 16px cap
|
||||
would clip the second line. */
|
||||
QFrame#beamlineStatePanel QPushButton {
|
||||
min-height: 0px;
|
||||
max-height: 64px;
|
||||
}
|
||||
|
||||
QLineEdit:read-only, QAbstractSpinBox:read-only {
|
||||
@@ -875,6 +929,18 @@ def _original_stylesheet() -> str:
|
||||
image: url($check_mark);
|
||||
}
|
||||
|
||||
/* Radios stay ROUND — single-choice groups must read as radios, not
|
||||
checkboxes. Checked = accent dot (a check mark in a circle reads
|
||||
as a squashed checkbox). */
|
||||
QRadioButton::indicator {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked {
|
||||
image: none;
|
||||
background: $primary;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
||||
background: $disabled_input_bg;
|
||||
}
|
||||
@@ -1191,10 +1257,10 @@ def _original_stylesheet() -> str:
|
||||
QWidget#portraitRoot QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
""").substitute(_palette())
|
||||
""").substitute(mapping)
|
||||
|
||||
|
||||
def _portrait_stylesheet() -> str:
|
||||
def _sunset_stylesheet() -> str:
|
||||
return Template("""
|
||||
/* Sunset-sky gradient — same transparent-children scheme as the light
|
||||
theme: only top-level windows paint the sky (rule order matters, see
|
||||
@@ -1214,11 +1280,29 @@ def _portrait_stylesheet() -> str:
|
||||
}
|
||||
|
||||
/* Interactive faces sit one step above the backdrop (site: glass2)
|
||||
with the faint gold hairline. */
|
||||
with the faint gold hairline. Same pinned height as the light sheet
|
||||
so buttons and entry boxes match in both themes. */
|
||||
QPushButton, QToolButton, QComboBox,
|
||||
QLineEdit, QAbstractSpinBox {
|
||||
background-color: $dark_elevated;
|
||||
border: 1px solid $dark_border_faint;
|
||||
min-height: 16px;
|
||||
max-height: 16px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
/* Hover lightens in the dark theme (one glass step up); the light
|
||||
theme darkens instead — direction always moves toward contrast. */
|
||||
QPushButton:hover, QToolButton:hover, QComboBox:hover {
|
||||
background-color: $dark_elevated_hover;
|
||||
}
|
||||
|
||||
/* Beamline state strip: exempt from the height cap — two-line labels
|
||||
(see the light sheet's matching rule). */
|
||||
QFrame#beamlineStatePanel QPushButton {
|
||||
min-height: 0px;
|
||||
max-height: 64px;
|
||||
}
|
||||
|
||||
/* Text views (console log) read fine straight on the sky. */
|
||||
@@ -1251,6 +1335,16 @@ def _portrait_stylesheet() -> str:
|
||||
image: url($dark_check_mark);
|
||||
}
|
||||
|
||||
/* Radios stay ROUND (see the light-theme note). Checked = gold dot. */
|
||||
QRadioButton::indicator {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:checked {
|
||||
image: none;
|
||||
background: $dark_accent;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
||||
background: $dark_disabled;
|
||||
}
|
||||
@@ -1767,6 +1861,8 @@ def _portrait_stylesheet() -> str:
|
||||
|
||||
if __name__ == "__main__":
|
||||
# ponytail: smallest check that fails if a $name has no matching constant
|
||||
for _theme in (THEME_ORIGINAL, THEME_PORTRAIT):
|
||||
for _theme in (THEME_SUNRISE, THEME_SUNSET, THEME_BLUEBIRD):
|
||||
assert "$" not in build_app_stylesheet(_theme)
|
||||
assert APP_BACKGROUND not in build_app_stylesheet(THEME_BLUEBIRD)
|
||||
# This line was added by Claude. But I would do the same. So all gude.
|
||||
print("gude")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QApplication, QProgressBar, QSplashScreen
|
||||
|
||||
from aare.gui.styles import SPLASH_ACCENT, SPLASH_BG, SPLASH_BORDER, WHITE, qcolor
|
||||
from aare.gui.styles import SPLASH_ACCENT, SPLASH_BG, SPLASH_BORDER, SPLASH_TEXT, qcolor
|
||||
|
||||
|
||||
class LoadingSplashScreen(QSplashScreen):
|
||||
@@ -17,7 +17,7 @@ class LoadingSplashScreen(QSplashScreen):
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
background-color: {SPLASH_BG};
|
||||
color: {WHITE};
|
||||
color: {SPLASH_TEXT};
|
||||
}}
|
||||
QProgressBar::chunk {{
|
||||
background-color: {SPLASH_ACCENT};
|
||||
@@ -28,6 +28,8 @@ class LoadingSplashScreen(QSplashScreen):
|
||||
self.progress.setValue(value)
|
||||
if message:
|
||||
self.showMessage(
|
||||
message, Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignCenter, qcolor(WHITE)
|
||||
message,
|
||||
Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignCenter,
|
||||
qcolor(SPLASH_TEXT),
|
||||
)
|
||||
QApplication.processEvents()
|
||||
|
||||
@@ -2,7 +2,7 @@ from PySide6.QtCore import QSettings, Qt, QTimer
|
||||
from PySide6.QtGui import QPainter, QPalette
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QLayout, QPushButton, QStyle, QStyleOption
|
||||
|
||||
from aare.gui.styles import BANNER_TEXT, BANNER_TEXT_SHADOW, FONT_BODY, qcolor
|
||||
from aare.gui.styles import BANNER_TEXT, BANNER_TEXT_SHADOW, FONT_VALUE, qcolor
|
||||
|
||||
# Universal vertical rhythm between stacked panels: each panel contributes
|
||||
# PANEL_VMARGIN top and bottom, the column adds PANEL_VSPACING between them,
|
||||
@@ -65,9 +65,11 @@ class TitleLabel(QLabel):
|
||||
self.toggle_button = QPushButton("−", self)
|
||||
# Bare glyph, no pill: the shared beamlineStateToggleButton QSS paints
|
||||
# a translucent white background, which is unwanted on these banners.
|
||||
# FONT_VALUE (18px), not FONT_BODY: a bare +/- glyph reads smaller than
|
||||
# the 16px banner title beside it; the big-glyph size evens them out.
|
||||
self.toggle_button.setStyleSheet(
|
||||
f"QPushButton {{ background: transparent; border: none;"
|
||||
f" color: {BANNER_TEXT}; font-size: {FONT_BODY}; font-weight: 700; }}"
|
||||
f" color: {BANNER_TEXT}; font-size: {FONT_VALUE}; font-weight: 700; }}"
|
||||
)
|
||||
self.toggle_button.setToolTip("Minimise panel")
|
||||
self.toggle_button.setFixedSize(21, 21)
|
||||
|
||||
Reference in New Issue
Block a user