Visualizer: gray-mode color slider + mode persists across launches

- New prefs: visualizer_mode (on/dim/off, saved on every click) and
  color_visualizer_gray (None = keep the derived alternateBase look).
- VisualizerWidget takes prefs (optional, so existing call sites/tests
  keep working); restores its mode at startup and validates junk values.
- New "Visualizer (gray mode):" row in the Preferences color sliders;
  theme.default_gray mirrors the widget's 0.88-lightness derivation so
  an untouched slider shows the current appearance.
- TransportBar.refresh_theme() repaints the visualizer so slider drags
  preview live.
This commit is contained in:
2026-07-02 16:52:59 -04:00
parent 08d3058edb
commit a1eb8aec8b
6 changed files with 129 additions and 4 deletions
+1
View File
@@ -19,6 +19,7 @@ _COLOR_ROWS = [
("color_now_playing_bg", "Now-playing panel:"),
("color_now_playing_text", "Now-playing text:"),
("color_stripe", "Stripes:"),
("color_visualizer_gray", "Visualizer (gray mode):"),
]
+2 -1
View File
@@ -255,7 +255,7 @@ class TransportBar(QWidget):
layout.addWidget(shuffle_box)
layout.addSpacing(10)
self._visualizer = VisualizerWidget(player)
self._visualizer = VisualizerWidget(player, prefs)
self._visualizer.setFixedHeight(CONTROL_HEIGHT)
layout.addWidget(self._visualizer)
layout.addSpacing(10)
@@ -359,6 +359,7 @@ class TransportBar(QWidget):
box.setStyleSheet(_box_style(box_bg))
self._apply_now_playing_bg()
self._apply_now_playing_font()
self._visualizer.update() # dim-mode bar color may have changed
def _apply_now_playing_bg(self):
bg = theme.gray(theme.gray_value(self._prefs, "color_now_playing_bg"))
+12 -2
View File
@@ -11,6 +11,8 @@ from PyQt6.QtCore import Qt, QTimer, QRectF
from PyQt6.QtGui import QPainter, QColor, QPainterPath, QPen
from PyQt6.QtMultimedia import QAudioFormat
from lintunes import theme
BANDS = 20
STEPS = 20 # vertical granularity per bar
@@ -41,10 +43,12 @@ class VisualizerWidget(QWidget):
panel; off = blank.
"""
def __init__(self, player, parent=None):
def __init__(self, player, prefs=None, parent=None):
super().__init__(parent)
self._player = player
self._mode = MODE_ON
self._prefs = prefs
saved = prefs.get("visualizer_mode") if prefs is not None else None
self._mode = saved if saved in _MODE_CYCLE else MODE_ON
self._levels = np.zeros(BANDS)
self._bars = [0] * BANDS # quantized 0..STEPS
self._samples = np.zeros(FFT_SIZE, dtype=np.float32)
@@ -113,6 +117,8 @@ class VisualizerWidget(QWidget):
# Cycle on -> dim -> off -> on.
idx = _MODE_CYCLE.index(self._mode)
self._mode = _MODE_CYCLE[(idx + 1) % len(_MODE_CYCLE)]
if self._prefs is not None:
self._prefs.set("visualizer_mode", self._mode)
if self._mode == MODE_OFF:
self._timer.stop()
self._clear() # off = blank, not the last frame held in place
@@ -150,6 +156,10 @@ class VisualizerWidget(QWidget):
def _bar_color(self):
if self._mode == MODE_DIM:
if self._prefs is not None:
saved = self._prefs.get("color_visualizer_gray")
if saved is not None:
return theme.gray(saved)
# Light gray just darker than the panel: take alternateBase and
# drop its lightness ~12% so it tracks theme/scale changes.
base = QColor(self.palette().alternateBase().color())