feat: queue panel skip-to-track and drag reorder; remove visualizer
Queue panel: - Double-clicking an upcoming track skips to it immediately: drops all tracks before it from the queue and starts playback (skipToUpcoming) - Items can be dragged to reorder; rowsMoved rebuilds the queue via setUpcomingOrder() - Track JSON stored per-item so order survives drag operations - New PlayQueue methods: skipToUpcoming(), setUpcomingOrder() - New QueuePanel signal: skipToTrackRequested(qint64) wired to MainWindow Remove visualizer: - Drop VisualizerWidget, Qt6::OpenGLWidgets, projectM CMake detection - Remove qobuz_backend_read_pcm FFI (Rust + C header + Qt wrapper) - Remove pcm_visualizer from PlayerStatus and PCM tap from AudioOutput Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
static constexpr int UpcomingIndexRole = Qt::UserRole + 1;
|
||||
static constexpr int IsPlayNextRole = Qt::UserRole + 2;
|
||||
static constexpr int TrackJsonRole = Qt::UserRole + 3;
|
||||
|
||||
QueuePanel::QueuePanel(PlayQueue *queue, QWidget *parent)
|
||||
: QDockWidget(tr("Queue"), parent)
|
||||
@@ -32,6 +33,8 @@ QueuePanel::QueuePanel(PlayQueue *queue, QWidget *parent)
|
||||
m_list = new QListWidget(container);
|
||||
m_list->setAlternatingRowColors(true);
|
||||
m_list->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_list->setDragDropMode(QAbstractItemView::InternalMove);
|
||||
m_list->setDefaultDropAction(Qt::MoveAction);
|
||||
layout->addWidget(m_list, 1);
|
||||
|
||||
setWidget(container);
|
||||
@@ -45,12 +48,17 @@ QueuePanel::QueuePanel(PlayQueue *queue, QWidget *parent)
|
||||
this, &QueuePanel::onItemDoubleClicked);
|
||||
connect(m_list, &QListWidget::customContextMenuRequested,
|
||||
this, &QueuePanel::onContextMenu);
|
||||
connect(m_list->model(), &QAbstractItemModel::rowsMoved,
|
||||
this, &QueuePanel::onRowsMoved);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void QueuePanel::refresh()
|
||||
{
|
||||
if (m_refreshing) return;
|
||||
m_refreshing = true;
|
||||
|
||||
m_list->clear();
|
||||
|
||||
const QVector<QJsonObject> upcoming = m_queue->upcomingTracks();
|
||||
@@ -73,6 +81,7 @@ void QueuePanel::refresh()
|
||||
auto *item = new QListWidgetItem(text, m_list);
|
||||
item->setData(UpcomingIndexRole, i);
|
||||
item->setData(IsPlayNextRole, i < playNextCount);
|
||||
item->setData(TrackJsonRole, QVariant::fromValue(t));
|
||||
|
||||
// "Play Next" tracks shown slightly differently
|
||||
if (i < playNextCount) {
|
||||
@@ -81,12 +90,33 @@ void QueuePanel::refresh()
|
||||
item->setFont(f);
|
||||
}
|
||||
}
|
||||
|
||||
m_refreshing = false;
|
||||
}
|
||||
|
||||
void QueuePanel::onItemDoubleClicked(QListWidgetItem *item)
|
||||
{
|
||||
// Double-clicking an upcoming item is not needed for now (could skip to it later)
|
||||
Q_UNUSED(item)
|
||||
const int idx = item->data(UpcomingIndexRole).toInt();
|
||||
const QJsonObject track = m_queue->skipToUpcoming(idx);
|
||||
if (track.isEmpty()) return;
|
||||
const qint64 id = static_cast<qint64>(track["id"].toDouble());
|
||||
emit skipToTrackRequested(id);
|
||||
}
|
||||
|
||||
void QueuePanel::onRowsMoved()
|
||||
{
|
||||
if (m_refreshing) return;
|
||||
|
||||
QVector<QJsonObject> newOrder;
|
||||
newOrder.reserve(m_list->count());
|
||||
for (int i = 0; i < m_list->count(); ++i) {
|
||||
const QVariant v = m_list->item(i)->data(TrackJsonRole);
|
||||
newOrder.append(v.value<QJsonObject>());
|
||||
}
|
||||
|
||||
m_refreshing = true;
|
||||
m_queue->setUpcomingOrder(newOrder);
|
||||
m_refreshing = false;
|
||||
}
|
||||
|
||||
void QueuePanel::onContextMenu(const QPoint &pos)
|
||||
|
||||
Reference in New Issue
Block a user