diff options
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/main_window.py | 33 | ||||
| -rw-r--r-- | ui/style_dark.qss | 42 |
2 files changed, 73 insertions, 2 deletions
diff --git a/ui/main_window.py b/ui/main_window.py index 07ab0b2..d7c297f 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -13,7 +13,7 @@ from PyQt6.QtWidgets import ( QAbstractSpinBox, QComboBox, QMenu, ) from PyQt6.QtCore import Qt, QTimer, QObject, QEvent, QRect, QByteArray, pyqtSignal, pyqtSlot -from PyQt6.QtGui import QPainter, QColor, QFont, QAction +from PyQt6.QtGui import QPainter, QColor, QFont, QAction, QPalette import logging import base64 import os @@ -822,8 +822,39 @@ class MainWindow(QMainWindow): if os.path.exists(qss_file): with open(qss_file) as f: QApplication.instance().setStyleSheet(f.read()) + self._apply_palette(theme) self._chart.set_theme(theme) + def _apply_palette(self, theme: str): + """QSS alone doesn't reach every Qt-drawn pixel — a splitter/dock + separator's grip-dot decoration, a QMenu's checkmark tick, etc. are + drawn from the app's QPalette, not stylesheet background-color. + Without ever setting one, those stay Qt's default light palette + regardless of the dark stylesheet, showing up as stray white dots/ + slivers on top of otherwise-correctly-dark widgets.""" + app = QApplication.instance() + if theme == "dark": + pal = QPalette() + pal.setColor(QPalette.ColorRole.Window, QColor("#0b0e13")) + pal.setColor(QPalette.ColorRole.WindowText, QColor("#c7d2fe")) + pal.setColor(QPalette.ColorRole.Base, QColor("#111620")) + pal.setColor(QPalette.ColorRole.AlternateBase, QColor("#161d2e")) + pal.setColor(QPalette.ColorRole.Text, QColor("#c7d2fe")) + pal.setColor(QPalette.ColorRole.Button, QColor("#161d2e")) + pal.setColor(QPalette.ColorRole.ButtonText, QColor("#c7d2fe")) + pal.setColor(QPalette.ColorRole.Highlight, QColor("#3b82f6")) + pal.setColor(QPalette.ColorRole.HighlightedText, QColor("#0b0e13")) + pal.setColor(QPalette.ColorRole.ToolTipBase, QColor("#161d2e")) + pal.setColor(QPalette.ColorRole.ToolTipText, QColor("#c7d2fe")) + pal.setColor(QPalette.ColorRole.Light, QColor("#2a3558")) + pal.setColor(QPalette.ColorRole.Midlight, QColor("#2a3558")) + pal.setColor(QPalette.ColorRole.Dark, QColor("#060810")) + pal.setColor(QPalette.ColorRole.Mid, QColor("#1c2540")) + pal.setColor(QPalette.ColorRole.Shadow, QColor("#000000")) + app.setPalette(pal) + else: + app.setPalette(app.style().standardPalette()) + def _apply_settings_on_startup(self): self._apply_theme(self._settings.get("theme", "dark")) self.engine._interval = self._settings.get("poll_ms", 100) / 1000.0 diff --git a/ui/style_dark.qss b/ui/style_dark.qss index 3a20cba..ce43d74 100644 --- a/ui/style_dark.qss +++ b/ui/style_dark.qss @@ -348,6 +348,11 @@ QComboBox#channelPickerCb { font-family: "IBM Plex Mono", monospace; font-size: QComboBox#channelPickerCb:focus { border-color: #3b82f6; } /* ── Tabs ────────────────────────────────────────────────────────── */ +/* The bare QTabWidget/QTabBar containers (not ::pane or ::tab) have no + background of their own otherwise, so the strip beside/above the tab + buttons falls back to the default light palette. */ +QTabWidget { background-color: transparent; } +QTabBar { background-color: transparent; } QTabWidget::pane { background-color: #111620; border: 1px solid #2a3558; border-radius: 4px; } QTabBar::tab { background-color: #0b0e13; color: #8b9dc3; @@ -385,10 +390,18 @@ QScrollBar::handle:horizontal { background: #2a3558; border-radius: 4px; min-wid QScrollBar::handle:horizontal:hover { background: #3b82f6; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; } -/* ── Splitter ─────────────────────────────────────────────────────── */ +/* ── Splitter / dock separator ─────────────────────────────────────── + Qt draws the little grip-dot decoration on a splitter/dock separator + from the app's QPalette (Light/Midlight roles), not from QSS + background-color — see MainWindow._apply_palette() in ui/main_window.py, + which sets those roles dark too. background-color here still matters + for the flat part of the handle. */ QSplitter::handle { background-color: #2a3558; } QSplitter::handle:hover { background-color: #3b82f6; } +QMainWindow::separator { background-color: #2a3558; width: 4px; height: 4px; } +QMainWindow::separator:hover { background-color: #3b82f6; } + /* ── Status bar ───────────────────────────────────────────────────── */ QStatusBar { background-color: #0b0e13; border-top: 1px solid #2a3558; @@ -554,6 +567,33 @@ QFileDialog QComboBox { color: #e2e8f0; } +/* ── Menus (generic — covers the View menu and any other unnamed QMenu, + not just the named ones below) ───────────────────────────────────── */ +QMenu { + background-color: #111620; + border: 1px solid #2a3558; + border-radius: 4px; + padding: 4px 0; + color: #e2e8f0; + font-size: 13px; +} +QMenu::item { padding: 7px 20px 7px 28px; color: #c7d2fe; } +QMenu::item:selected { background-color: #1e3a5f; color: #e0f2fe; } +QMenu::item:disabled { color: #475569; } +QMenu::separator { height: 1px; background: #2a3558; margin: 3px 8px; } +/* Checkable QAction indicator — drawn as a small filled/outline square + rather than relying on the native tick glyph, so it's guaranteed + visible regardless of palette. */ +QMenu::indicator { + width: 13px; height: 13px; margin-left: 6px; +} +QMenu::indicator:checked { + background-color: #3b82f6; border: 1px solid #3b82f6; border-radius: 3px; +} +QMenu::indicator:unchecked { + background-color: transparent; border: 1px solid #2a3558; border-radius: 3px; +} + /* ── Profile / File menu ─────────────────────────────────────────── */ QMenu#profileMenu { background-color: #111620; |
