Start
This commit is contained in:
96
linedance-app/ui/vu_meter.py
Normal file
96
linedance-app/ui/vu_meter.py
Normal file
@@ -0,0 +1,96 @@
|
||||
"""
|
||||
vu_meter.py — VU-meter widget der tegner L og R kanaler.
|
||||
Opdateres via set_levels(left, right) med værdier 0.0–1.0.
|
||||
"""
|
||||
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
from PyQt6.QtCore import Qt, QTimer
|
||||
from PyQt6.QtGui import QPainter, QColor
|
||||
import random
|
||||
|
||||
|
||||
NUM_BARS = 14
|
||||
BAR_W = 14
|
||||
BAR_H = 4
|
||||
BAR_GAP = 2
|
||||
CHAN_GAP = 6
|
||||
PADDING = 4
|
||||
|
||||
COLOR_OFF = QColor("#1a2218")
|
||||
COLOR_GREEN = QColor("#28a050")
|
||||
COLOR_YELLOW = QColor("#c8a020")
|
||||
COLOR_RED = QColor("#c83020")
|
||||
|
||||
# Grænser for farver (bar-indeks fra bunden)
|
||||
YELLOW_FROM = NUM_BARS - 4
|
||||
RED_FROM = NUM_BARS - 2
|
||||
|
||||
|
||||
class VUMeter(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._left = 0.0
|
||||
self._right = 0.0
|
||||
self._peak_l = 0.0
|
||||
self._peak_r = 0.0
|
||||
self._dark = True
|
||||
|
||||
total_h = NUM_BARS * (BAR_H + BAR_GAP) + PADDING * 2 + 16 # +16 til label
|
||||
total_w = (BAR_W + CHAN_GAP) * 2 + PADDING * 2
|
||||
self.setFixedSize(total_w, total_h)
|
||||
|
||||
def set_dark(self, dark: bool):
|
||||
self._dark = dark
|
||||
self.update()
|
||||
|
||||
def set_levels(self, left: float, right: float):
|
||||
"""Sæt niveauer 0.0–1.0. Kaldes fra afspiller-tråden via signal."""
|
||||
self._left = max(0.0, min(1.0, left))
|
||||
self._right = max(0.0, min(1.0, right))
|
||||
self._peak_l = max(self._peak_l * 0.92, self._left)
|
||||
self._peak_r = max(self._peak_r * 0.92, self._right)
|
||||
self.update()
|
||||
|
||||
def reset(self):
|
||||
self._left = self._right = self._peak_l = self._peak_r = 0.0
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||
|
||||
off_color = QColor("#d0d8cc") if not self._dark else COLOR_OFF
|
||||
|
||||
for ch_idx, level in enumerate([self._left, self._right]):
|
||||
x = PADDING + ch_idx * (BAR_W + CHAN_GAP)
|
||||
active_bars = int(level * NUM_BARS)
|
||||
|
||||
for bar_idx in range(NUM_BARS):
|
||||
y = PADDING + (NUM_BARS - 1 - bar_idx) * (BAR_H + BAR_GAP)
|
||||
|
||||
if bar_idx < active_bars:
|
||||
if bar_idx >= RED_FROM:
|
||||
color = COLOR_RED
|
||||
elif bar_idx >= YELLOW_FROM:
|
||||
color = COLOR_YELLOW
|
||||
else:
|
||||
color = COLOR_GREEN
|
||||
else:
|
||||
color = off_color
|
||||
|
||||
painter.fillRect(x, y, BAR_W, BAR_H,
|
||||
QColor(color.red(), color.green(), color.blue(), 220))
|
||||
|
||||
# Kanal-labels
|
||||
label_y = PADDING + NUM_BARS * (BAR_H + BAR_GAP) + 4
|
||||
painter.setPen(QColor("#5a6070"))
|
||||
font = painter.font()
|
||||
font.setPointSize(8)
|
||||
font.setFamily("Courier New")
|
||||
painter.setFont(font)
|
||||
|
||||
for ch_idx, label in enumerate(["L", "R"]):
|
||||
x = PADDING + ch_idx * (BAR_W + CHAN_GAP) + BAR_W // 2
|
||||
painter.drawText(x - 4, label_y + 10, label)
|
||||
|
||||
painter.end()
|
||||
Reference in New Issue
Block a user