132 lines
4.1 KiB
C++
132 lines
4.1 KiB
C++
// SPDX-FileCopyrightText: 2026 Gary Wang <opensource@blumia.net>
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "lyricswidget.h"
|
|
#include "lyricsmanager.h"
|
|
|
|
#include <QListWidget>
|
|
#include <QVBoxLayout>
|
|
#include <QListWidgetItem>
|
|
#include <QListWidgetItem>
|
|
#include <QFont>
|
|
#include <QPropertyAnimation>
|
|
#include <QScrollBar>
|
|
#include <QEasingCurve>
|
|
|
|
LyricsWidget::LyricsWidget(QWidget *parent)
|
|
: QWidget(parent)
|
|
, m_listWidget(new QListWidget(this))
|
|
{
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
layout->addWidget(m_listWidget);
|
|
|
|
m_listWidget->setFrameShape(QFrame::NoFrame);
|
|
m_listWidget->setStyleSheet("background: transparent;");
|
|
m_listWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
m_listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
m_listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Hide scrollbar for cleaner look? Or Keep it? User didn't specify. Hiding it looks more like "Lyrics Mode"
|
|
// Enable word wrap
|
|
m_listWidget->setWordWrap(true);
|
|
m_listWidget->setTextElideMode(Qt::ElideNone);
|
|
m_listWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
|
m_listWidget->setFocusPolicy(Qt::NoFocus);
|
|
}
|
|
|
|
void LyricsWidget::setLyricsManager(LyricsManager *mgr)
|
|
{
|
|
if (m_lyricsManager) {
|
|
disconnect(m_lyricsManager, nullptr, this, nullptr);
|
|
}
|
|
m_lyricsManager = mgr;
|
|
if (m_lyricsManager) {
|
|
connect(m_lyricsManager, &LyricsManager::lyricsLoaded, this, &LyricsWidget::onLyricsLoaded);
|
|
// Load initial state if any
|
|
onLyricsLoaded(m_lyricsManager->hasLyrics());
|
|
}
|
|
}
|
|
|
|
void LyricsWidget::updatePosition(qint64 position)
|
|
{
|
|
if (!m_lyricsManager || !m_lyricsManager->hasLyrics() || !isVisible()) return;
|
|
|
|
// Note: rely on LyricsManager::updateCurrentTimeMs()
|
|
int index = m_lyricsManager->currentLineIndex();
|
|
|
|
if (index != m_lastHighlightIndex) {
|
|
highlightCurrentLine(index);
|
|
}
|
|
}
|
|
|
|
void LyricsWidget::onLyricsLoaded(bool success)
|
|
{
|
|
m_listWidget->clear();
|
|
m_lastHighlightIndex = -1;
|
|
|
|
if (!success || !m_lyricsManager) return;
|
|
|
|
const QList<int>& timestamps = m_lyricsManager->timestamps();
|
|
const QHash<int, QString>& lyricsMap = m_lyricsManager->lyricsMap();
|
|
|
|
for (int timestamp : timestamps) {
|
|
QListWidgetItem *item = new QListWidgetItem(lyricsMap.value(timestamp));
|
|
item->setTextAlignment(Qt::AlignCenter);
|
|
|
|
// Default style
|
|
QFont font = item->font();
|
|
font.setPointSize(10);
|
|
item->setFont(font);
|
|
item->setForeground(QColor(255, 255, 255, 150)); // Dimmed
|
|
|
|
m_listWidget->addItem(item);
|
|
}
|
|
}
|
|
|
|
void LyricsWidget::highlightCurrentLine(int index)
|
|
{
|
|
if (index < 0 || index >= m_listWidget->count()) return;
|
|
|
|
// Reset old highlight
|
|
if (m_lastHighlightIndex >= 0 && m_lastHighlightIndex < m_listWidget->count()) {
|
|
QListWidgetItem *oldItem = m_listWidget->item(m_lastHighlightIndex);
|
|
QFont font = oldItem->font();
|
|
font.setPointSize(10);
|
|
font.setBold(false);
|
|
oldItem->setFont(font);
|
|
oldItem->setForeground(QColor(255, 255, 255, 150));
|
|
}
|
|
|
|
// Set new highlight
|
|
QListWidgetItem *newItem = m_listWidget->item(index);
|
|
QFont font = newItem->font();
|
|
font.setPointSize(14);
|
|
font.setBold(true);
|
|
newItem->setFont(font);
|
|
newItem->setForeground(QColor(255, 255, 255, 255));
|
|
|
|
// Smooth scroll
|
|
QScrollBar *vBar = m_listWidget->verticalScrollBar();
|
|
int startScroll = vBar->value();
|
|
|
|
m_listWidget->scrollToItem(newItem, QAbstractItemView::PositionAtCenter);
|
|
int endScroll = vBar->value();
|
|
|
|
// Restore and animate
|
|
if (startScroll != endScroll) {
|
|
vBar->setValue(startScroll);
|
|
|
|
if (!m_scrollAnimation) {
|
|
m_scrollAnimation = new QPropertyAnimation(vBar, "value", this);
|
|
m_scrollAnimation->setDuration(400);
|
|
m_scrollAnimation->setEasingCurve(QEasingCurve::OutCubic);
|
|
}
|
|
m_scrollAnimation->stop();
|
|
m_scrollAnimation->setStartValue(startScroll);
|
|
m_scrollAnimation->setEndValue(endScroll);
|
|
m_scrollAnimation->start();
|
|
}
|
|
|
|
m_lastHighlightIndex = index;
|
|
}
|