Add record/vinyl look to now playing screen

This commit is contained in:
2025-11-20 02:09:43 -07:00
parent e709f8978c
commit c41fe4be1b
28 changed files with 150 additions and 31 deletions

View File

@@ -1,16 +1,18 @@
#include "spinningalbumart.h"
#include <QPainter>
#include <QPainterPath>
#include <QMouseEvent>
#include <QRadialGradient>
#include <QLinearGradient>
SpinningAlbumArt::SpinningAlbumArt(const QString& imagePath, int size, QWidget* parent)
: QWidget(parent), size_(size)
{
artLabel_ = new QLabel(this);
artLabel_->setAlignment(Qt::AlignCenter);
setFixedSize(size, size);
// Load and crop square
// Load album art and square-crop it
QPixmap pix(imagePath);
QPixmap scaled = pix.scaled(size, size,
Qt::KeepAspectRatioByExpanding,
@@ -24,33 +26,121 @@ SpinningAlbumArt::SpinningAlbumArt(const QString& imagePath, int size, QWidget*
side
);
// Mask into circle
discArt_ = createCircularDisc(square, size);
artLabel_->setPixmap(discArt_);
// Build full realistic vinyl disc with grooves + sheen + hole + label
disc_ = buildRecord(square, size);
artLabel_->setPixmap(disc_);
// Setup spin timer
timer_ = new QTimer(this);
timer_->setInterval(16);
connect(timer_, &QTimer::timeout, this, &SpinningAlbumArt::updateRotation);
}
QPixmap SpinningAlbumArt::createCircularDisc(const QPixmap& src, int size)
QPixmap SpinningAlbumArt::buildRecord(const QPixmap& src, int size)
{
QPixmap disc(size, size);
disc.fill(Qt::transparent);
QPointF center(size / 2.0, size / 2.0);
QPainter p(&disc);
p.setRenderHint(QPainter::Antialiasing);
p.setRenderHint(QPainter::SmoothPixmapTransform);
QPainterPath path;
path.addEllipse(0, 0, size, size);
p.setClipPath(path);
//
// 1. Base vinyl gradient
//
QRadialGradient vinylGrad(center, size / 2);
vinylGrad.setColorAt(0.0, QColor(55, 55, 55));
vinylGrad.setColorAt(1.0, QColor(10, 10, 10));
p.setBrush(vinylGrad);
p.setPen(Qt::NoPen);
p.drawEllipse(0, 0, size, size);
p.drawPixmap(0, 0, src);
//
// 2. Grooves (2px spacing, soft alpha)
//
p.setPen(QPen(QColor(255, 255, 255, 22), 1));
int labelRadius = size * 0.35;
for (int r = labelRadius; r < size / 2; r += 2)
p.drawEllipse(center, r, r);
//
// 3. Directional sheen (angled elliptical gradient)
//
QPixmap sheen(size, size);
sheen.fill(Qt::transparent);
{
QPainter sp(&sheen);
sp.setRenderHint(QPainter::Antialiasing);
QLinearGradient lg(0, size * 0.25, size, size * 0.75);
lg.setColorAt(0.0, QColor(255, 255, 255, 40));
lg.setColorAt(0.5, QColor(255, 255, 255, 5));
lg.setColorAt(1.0, QColor(0, 0, 0, 0));
sp.setBrush(lg);
sp.setPen(Qt::NoPen);
sp.drawEllipse(0, 0, size, size);
}
p.drawPixmap(0, 0, sheen);
//
// 4. Recessed label shadow
//
QRadialGradient labelGrad(center, size * 0.36);
labelGrad.setColorAt(0.0, QColor(0, 0, 0, 80));
labelGrad.setColorAt(1.0, Qt::transparent);
p.setBrush(labelGrad);
p.drawEllipse(center, size * 0.36, size * 0.36);
//
// 5. Album art masked to label circle
//
QPixmap label = buildLabelMask(src, size);
p.drawPixmap(0, 0, label);
//
// 6. Spindle hole (cutout)
//
int holeDiameter = size * 0.17;
QPainterPath hole;
hole.addEllipse(
(size - holeDiameter) / 2,
(size - holeDiameter) / 2,
holeDiameter,
holeDiameter
);
p.setCompositionMode(QPainter::CompositionMode_Clear);
p.fillPath(hole, Qt::transparent);
return disc;
}
QPixmap SpinningAlbumArt::buildLabelMask(const QPixmap& src, int size)
{
QPixmap label(size, size);
label.fill(Qt::transparent);
QPainter p(&label);
p.setRenderHint(QPainter::Antialiasing);
int labelDiameter = size * 0.70;
QPainterPath mask;
mask.addEllipse(
(size - labelDiameter) / 2,
(size - labelDiameter) / 2,
labelDiameter,
labelDiameter
);
p.setClipPath(mask);
p.drawPixmap(0, 0, src);
return label;
}
void SpinningAlbumArt::start()
{
timer_->start();
@@ -63,7 +153,7 @@ void SpinningAlbumArt::stop()
void SpinningAlbumArt::updateRotation()
{
rotationAngle_ += 0.6;
rotationAngle_ += 0.5;
QPixmap frame(size_, size_);
frame.fill(Qt::transparent);
@@ -76,7 +166,7 @@ void SpinningAlbumArt::updateRotation()
p.rotate(rotationAngle_);
p.translate(-size_ / 2, -size_ / 2);
p.drawPixmap(0, 0, discArt_);
p.drawPixmap(0, 0, disc_);
artLabel_->setPixmap(frame);
}

View File

@@ -4,14 +4,15 @@
#include <QLabel>
#include <QPixmap>
#include <QTimer>
#include <QMouseEvent>
class SpinningAlbumArt : public QWidget
{
Q_OBJECT
public:
explicit SpinningAlbumArt(const QString& imagePath, int size = 250, QWidget* parent = nullptr);
explicit SpinningAlbumArt(const QString& imagePath,
int size = 250,
QWidget* parent = nullptr);
public slots:
void start();
@@ -20,18 +21,20 @@ public slots:
signals:
void artClicked();
private slots:
void updateRotation();
protected:
void mousePressEvent(QMouseEvent* event) override;
private:
QPixmap discArt_; // circular-masked album image
QLabel* artLabel_; // widget that displays the spinning frame
QTimer* timer_; // animation timer
qreal rotationAngle_ = 0;
int size_; // final diameter of the disc
private slots:
void updateRotation();
QPixmap createCircularDisc(const QPixmap& src, int size);
private:
QPixmap buildRecord(const QPixmap& src, int size);
QPixmap buildLabelMask(const QPixmap& src, int size);
QLabel* artLabel_;
QPixmap disc_; // final assembled vinyl-only disc (with grooves + sheen + hole + label)
QTimer* timer_;
qreal rotationAngle_ = 0;
int size_;
};