From 0bfa9dbbeb5f8798fac8506c420d5ccdb33ed514 Mon Sep 17 00:00:00 2001 From: Dawn Date: Fri, 7 Aug 2026 17:08:22 +0200 Subject: [PATCH] style: extend the palette with selection, frame, slider, and sample-status tokens SELECTION_BG/TEXT pin the app-wide selection blue to the banner color (was Qt's undeclared palette default); FRAME_L1/L2/L3 knobs put window, panel, and data-view borders on three tunable levels (panel etching off by default); QTabBar tabs and filter chips go borderless with a hover underline; QSlider matches the scrollbar look; scrollbar tracks turn square with a track-colored corner; SAMPLE_STATUS_* and SAMPLE_ROW_ALT_BG drive the sample-table status tints. Co-Authored-By: Claude Fable 5 --- src/aare/gui/styles.py | 260 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 245 insertions(+), 15 deletions(-) diff --git a/src/aare/gui/styles.py b/src/aare/gui/styles.py index 8a86223b..02241a6d 100644 --- a/src/aare/gui/styles.py +++ b/src/aare/gui/styles.py @@ -26,6 +26,37 @@ BORDER = "transparent" # main dividers, e.g. the beamline state bar top line CARD_BORDER = "transparent" # cards / group boxes (Local Contact, automation) COMPACT_BORDER = "transparent" # compact-automation cards and buttons +# -- Box-frame borders by nesting level ------------------------------------- +# One knob per level so the amount of "boxing" is tunable in one place: +# L1: top-level pop-out window edge (painted by PopoutWindow) +# L2: panel frames inside a dock/tab (TELL sample changer, reference +# tools, sample queue) — transparent by default: banner + table +# already delimit the panel, extra boxes read as clutter +# L3: data views (tables, log text) — a light line so scrollable content +# keeps a visible edge +# (The tab-widget pane is a fourth box, already governed by BORDER above.) +FRAME_L1_WIDTH = "0px" # default off — the pop-out reads as one clean surface +FRAME_L1_COLOR = "#bdbdbd" +FRAME_L2_WIDTH = "0px" +FRAME_L2_COLOR = "transparent" +FRAME_L3_WIDTH = "1px" +FRAME_L3_COLOR = "#c9cfd8" + +# Left inset (px, int — used in code, not QSS) for bottom-dock content so its +# left edge lines up with the left-column panels above (Loop centering). +DOCK_CONTENT_LEFT_PAD = 10 + +# Tab face fill: the selected Dewar/Auxiliary tab AND the unchecked +# All/Queued/Flagged/Measured filter buttons share this background. +TAB_FACE_BG = "#ffffff" + +# Selection highlight (combo popups, menus, list rows, text selections). +# Qt's style palette used to supply its own blue here; now it is the banner +# blue, and THIS is the knob for it. (Table-row selection has its own paler +# knob: SAMPLE_STATUS_SELECTED_BG.) +SELECTION_BG = BANNER +SELECTION_TEXT = "#263043" # same as TEXT — readable on the banner blue + # Compact-automation page: COMPACT_CARD_BG = "#e6eefc" COMPACT_TITLE = "#17324d" # section titles + menu/secondary button text @@ -194,11 +225,20 @@ STATE_MSG_INFO = "#005caa" # -- Sample tables + raster grid -------------------------------------------- SAMPLE_ROW_ACTIVE_BG = "#ff6600" -SAMPLE_ROW_QUEUED_BG = "#729fcf" +SAMPLE_ROW_QUEUED_BG = "#729fcf" # mounted/current-sample row (legacy name) SAMPLE_ROW_HIGHLIGHT_BG = "#d8e4fd" RASTER_GRID_LINE = "#729fcf" TABLE_SHADE_BG = "#e0e0e0" +# -- Sample status row tints (dewar/queue view) ----------------------------- +# Status colors now fill the rounded dot in the table's status column; rows +# themselves alternate WHITE / SAMPLE_ROW_ALT_BG. Tune the palette here. +SAMPLE_ROW_ALT_BG = "#eef1f5" # staggered row grey (alternates with white) +SAMPLE_STATUS_QUEUED_BG = "#ffe4c4" # pale orange — waiting in the automation queue +SAMPLE_STATUS_FLAGGED_BG = "#ffd9d9" # pale red — automation failed on this sample +SAMPLE_STATUS_MEASURED_BG = "#dcf2e0" # pale green — already has collected data +SAMPLE_STATUS_SELECTED_BG = "#d8e8fd" # pale blue — table selection highlight + # -- Camera / video overlay (painter colors, alpha at call site) ------------ BEAM_OPEN = "#00ff00" # beam marker: shutter open BEAM_IDLE = "#f57900" # beam marker: idle @@ -307,6 +347,11 @@ TOOLTIP_FG = "#263043" DARK_TOOLTIP_BG = "#363a4f" # surface0 DARK_TOOLTIP_FG = "#cad3f5" # text +# -- Sliders ---------------------------------------------------------------- +# Own knob instead of PRIMARY: full-saturation button blue was too loud for a +# passive fill (illumination panel). Muted slate-blue, tweak freely. +SLIDER_FILL = "#8ba3c7" + # -- Scrollbars (rounded, no arrows: grey track, darker draggable handle) --- SCROLLBAR_TRACK = "#d8dde5" SCROLLBAR_HANDLE = "#a8b2c0" @@ -542,10 +587,59 @@ def _original_stylesheet() -> str: font-weight: bold; } + /* Disabled = baton-gated ("watch only"): the explicit colors above mask + Qt's native grey, so spell the greyed state out. */ + QPushButton:disabled, QCheckBox:disabled, QRadioButton:disabled, + QLabel:disabled, QComboBox:disabled, QLineEdit:disabled, + QAbstractSpinBox:disabled, QTabBar::tab:disabled { + color: $faint_text; + } + + QLineEdit:disabled, QAbstractSpinBox:disabled, QComboBox:disabled { + background: $scrollbar_track; + } + + QSlider::sub-page:horizontal:disabled { + background: $scrollbar_handle; + } + QTabWidget::pane { border: 1px solid $border; } + /* Exp. Config. pane: hand-rolled QTabBar+QStackedWidget (button row sits + between bar and pages), so it needs the pane border by hand too. */ + #expConfigPane { + border: 1px solid $border; + } + + /* Borderless tabs: the pane isn't outlined, so the native 3-side tab + boxes hung in the air. Selection shows via fill + the raised effect + (unselected tabs sit 3px lower). */ + QTabBar::tab { + background: transparent; + border: none; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + padding: 4px 14px; + margin-top: 3px; + color: $muted_text; + } + + QTabBar::tab:selected { + background: $tab_face_bg; + color: $text; + margin-top: 0px; + padding: 6px 14px 5px 14px; + } + + /* Menu-bar-style hover hint: text-decoration underlines only the text + itself (short, close to the baseline) instead of the full tab box. */ + QTabBar::tab:hover:!selected { + color: $text; + text-decoration: underline; + } + QMainWindow::separator { background: $border; width: 4px; @@ -594,18 +688,78 @@ def _original_stylesheet() -> str: background: transparent; } - /* Plain scroll containers stay frameless; data views (tables, trees, - text/log views) keep their native frame — those borders are wanted. */ + /* Plain scroll containers stay frameless. */ QScrollArea { border: none; } - /* Soft scrollbars: rounded track + draggable handle, no end arrows. */ + /* Box-frame levels — weights/colors are knobs in styles.py. L2: panel + frames (replaces their native StyledPanel etching); L3: data views. */ + TellSamplePanel, ReferenceToolsPanel, SampleQueuePanel { + border: $frame_l2_width solid $frame_l2_color; + } + + QTableView, QPlainTextEdit { + border: $frame_l3_width solid $frame_l3_color; + } + + /* Pale-blue selection with readable dark text in every sample table; + staggered grey/white rows where alternation is enabled. */ + QTableView { + background: $white; + alternate-background-color: $sample_row_alt_bg; + selection-background-color: $sample_status_selected_bg; + selection-color: $text; + } + + /* Selection highlight: the banner blue (SELECTION_BG in styles.py) + instead of the style palette's own blue. Tables keep their paler + selection rule below. */ + QListView, QTreeView, + QComboBox QAbstractItemView { + selection-background-color: $selection_bg; + selection-color: $selection_text; + } + + QMenu::item:selected { + background: $selection_bg; + color: $selection_text; + } + + QLineEdit, QAbstractSpinBox, QTextEdit, QPlainTextEdit { + selection-background-color: $selection_bg; + selection-color: $selection_text; + } + + /* Sliders: rounded groove ends (like the scrollbar handles) + round + handle. Wheel adjustment needs the right mouse button held — see + WheelValueGuard. */ + QSlider::groove:horizontal { + height: 6px; + background: $scrollbar_track; + border-radius: 3px; + } + + QSlider::sub-page:horizontal { + background: $slider_fill; + border-radius: 3px; + } + + QSlider::handle:horizontal { + background: $white; + border: 1px solid $scrollbar_handle; + width: 14px; + margin: -5px 0; + border-radius: 7px; + } + + /* Soft scrollbars: square track band (runs flush to the widget edges — + rounded ends left corner notches in the tables) + rounded draggable + handle, no end arrows. */ QScrollBar:vertical { background: $scrollbar_track; width: 10px; border: none; - border-radius: 5px; margin: 0px; } @@ -613,7 +767,6 @@ def _original_stylesheet() -> str: background: $scrollbar_track; height: 10px; border: none; - border-radius: 5px; margin: 0px; } @@ -645,9 +798,10 @@ def _original_stylesheet() -> str: background: transparent; } - /* Kill the square filler where the two scrollbars meet. */ + /* The two scrollbar bands meet in a track-colored corner — no white + square, the bands read as one continuous edge. */ QAbstractScrollArea::corner { - background: transparent; + background: $scrollbar_track; border: none; } @@ -705,6 +859,30 @@ def _portrait_stylesheet() -> str: color: $dark_text; } + /* Borderless tabs, dark flavor — see the light-theme note. */ + QTabBar::tab { + background: transparent; + border: none; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + padding: 4px 14px; + margin-top: 3px; + color: $dark_muted; + } + + QTabBar::tab:selected { + background: $dark_elevated; + color: $dark_text; + margin-top: 0px; + padding: 6px 14px 5px 14px; + } + + /* Menu-bar-style hover hint — see the light-theme note. */ + QTabBar::tab:hover:!selected { + color: $dark_text; + text-decoration: underline; + } + /* Borderless hover hints. The transparent border is required — QToolTip only honours the stylesheet background once a border is set. */ QToolTip { @@ -901,18 +1079,71 @@ def _portrait_stylesheet() -> str: background: transparent; } - /* Plain scroll containers stay frameless; data views (tables, trees, - text/log views) keep their native frame — those borders are wanted. */ + /* Plain scroll containers stay frameless. */ QScrollArea { border: none; } - /* Soft scrollbars: rounded track + draggable handle, no end arrows. */ + /* Box-frame levels — weights/colors are knobs in styles.py. */ + TellSamplePanel, ReferenceToolsPanel, SampleQueuePanel { + border: $frame_l2_width solid $frame_l2_color; + } + + QTableView, QPlainTextEdit { + border: $frame_l3_width solid $frame_l3_color; + } + + /* Selection + staggered rows, dark flavor. */ + QTableView { + background: $dark_bg; + alternate-background-color: $dark_surface; + selection-background-color: $sample_status_selected_bg; + selection-color: $text; + } + + /* Selection highlight — same banner-blue knob as the light theme. */ + QListView, QTreeView, + QComboBox QAbstractItemView { + selection-background-color: $selection_bg; + selection-color: $selection_text; + } + + QMenu::item:selected { + background: $selection_bg; + color: $selection_text; + } + + QLineEdit, QAbstractSpinBox, QTextEdit, QPlainTextEdit { + selection-background-color: $selection_bg; + selection-color: $selection_text; + } + + /* Sliders, dark flavor — see the light-theme note. */ + QSlider::groove:horizontal { + height: 6px; + background: $dark_border; + border-radius: 3px; + } + + QSlider::sub-page:horizontal { + background: $dark_accent; + border-radius: 3px; + } + + QSlider::handle:horizontal { + background: $dark_elevated; + border: 1px solid $dark_muted; + width: 14px; + margin: -5px 0; + border-radius: 7px; + } + + /* Soft scrollbars: square track band + rounded handle, no end arrows + (see light-theme note on the corner notches). */ QScrollBar:vertical { background: $dark_surface; width: 10px; border: none; - border-radius: 5px; margin: 0px; } @@ -920,7 +1151,6 @@ def _portrait_stylesheet() -> str: background: $dark_surface; height: 10px; border: none; - border-radius: 5px; margin: 0px; } @@ -952,9 +1182,9 @@ def _portrait_stylesheet() -> str: background: transparent; } - /* Kill the square filler where the two scrollbars meet. */ + /* The two scrollbar bands meet in a track-colored corner. */ QAbstractScrollArea::corner { - background: transparent; + background: $dark_surface; border: none; }