diff --git a/src/view/maintoolbar.cpp b/src/view/maintoolbar.cpp index 998e4bf..604d760 100644 --- a/src/view/maintoolbar.cpp +++ b/src/view/maintoolbar.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include MainToolBar::MainToolBar(QobuzBackend *backend, PlayQueue *queue, QWidget *parent) @@ -19,87 +21,151 @@ MainToolBar::MainToolBar(QobuzBackend *backend, PlayQueue *queue, QWidget *paren m_nam = new QNetworkAccessManager(this); connect(m_nam, &QNetworkAccessManager::finished, this, &MainToolBar::onAlbumArtReady); - // --- Album art thumbnail --- - m_artLabel = new QLabel(this); - m_artLabel->setFixedSize(36, 36); + // ---------------------------------------------------------------- + // Root container — three equal-stretch columns + // ---------------------------------------------------------------- + auto *root = new QWidget(this); + auto *rootLo = new QHBoxLayout(root); + rootLo->setContentsMargins(6, 2, 6, 2); + rootLo->setSpacing(0); + + // ---- LEFT: album art + track info ---- + auto *leftWidget = new QWidget(root); + auto *leftLo = new QHBoxLayout(leftWidget); + leftLo->setContentsMargins(0, 0, 0, 0); + leftLo->setSpacing(8); + + m_artLabel = new QLabel(leftWidget); + m_artLabel->setFixedSize(44, 44); m_artLabel->setScaledContents(true); - m_artLabel->setStyleSheet("border: 1px solid #444; background: #1a1a1a;"); - m_artLabel->setPixmap(QIcon(":/res/icons/view-media-album-cover.svg") - .pixmap(32, 32)); - addWidget(m_artLabel); - addSeparator(); + m_artLabel->setStyleSheet("border: 1px solid #444; background: #1a1a1a; border-radius: 3px;"); + m_artLabel->setPixmap(QIcon(":/res/icons/view-media-album-cover.svg").pixmap(40, 40)); - // --- Playback controls --- - m_previous = addAction(Icon::previous(), tr("Previous")); - connect(m_previous, &QAction::triggered, this, &MainToolBar::onPrevious); - - m_playPause = addAction(Icon::play(), tr("Play")); - connect(m_playPause, &QAction::triggered, this, &MainToolBar::onPlayPause); - - m_next = addAction(Icon::next(), tr("Next")); - connect(m_next, &QAction::triggered, this, &MainToolBar::onNext); - - addSeparator(); - - // --- Track info label --- - m_trackLabel = new QLabel(tr("Not playing"), this); - m_trackLabel->setMinimumWidth(180); - m_trackLabel->setMaximumWidth(340); + m_trackLabel = new QLabel(tr("Not playing"), leftWidget); + m_trackLabel->setMinimumWidth(120); + m_trackLabel->setMaximumWidth(280); m_trackLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); - addWidget(m_trackLabel); + m_trackLabel->setWordWrap(false); - addSeparator(); + leftLo->addWidget(m_artLabel); + leftLo->addWidget(m_trackLabel); + leftLo->addStretch(1); - // --- Progress slider --- - m_progress = new ClickableSlider(Qt::Horizontal, this); + // ---- CENTER: controls + progress ---- + auto *centerWidget = new QWidget(root); + auto *centerLo = new QVBoxLayout(centerWidget); + centerLo->setContentsMargins(0, 0, 0, 0); + centerLo->setSpacing(2); + + // Controls row: prev / play-pause / next + auto *ctrlRow = new QHBoxLayout; + ctrlRow->setSpacing(4); + ctrlRow->setContentsMargins(0, 0, 0, 0); + + auto makeBtn = [&](const QIcon &icon, const QString &tip) -> QToolButton * { + auto *btn = new QToolButton(centerWidget); + btn->setIcon(icon); + btn->setToolTip(tip); + btn->setAutoRaise(true); + btn->setIconSize(QSize(22, 22)); + return btn; + }; + + m_prevBtn = makeBtn(Icon::previous(), tr("Previous")); + m_playBtn = makeBtn(Icon::play(), tr("Play")); + m_playBtn->setIconSize(QSize(28, 28)); + m_nextBtn = makeBtn(Icon::next(), tr("Next")); + + connect(m_prevBtn, &QToolButton::clicked, this, &MainToolBar::onPrevious); + connect(m_playBtn, &QToolButton::clicked, this, &MainToolBar::onPlayPause); + connect(m_nextBtn, &QToolButton::clicked, this, &MainToolBar::onNext); + + ctrlRow->addStretch(1); + ctrlRow->addWidget(m_prevBtn); + ctrlRow->addWidget(m_playBtn); + ctrlRow->addWidget(m_nextBtn); + ctrlRow->addStretch(1); + + // Progress row: elapsed / slider / total + auto *progRow = new QHBoxLayout; + progRow->setSpacing(6); + progRow->setContentsMargins(0, 0, 0, 0); + + m_elapsedLabel = new QLabel(QStringLiteral("0:00"), centerWidget); + m_elapsedLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + m_elapsedLabel->setMinimumWidth(36); + + m_progress = new ClickableSlider(Qt::Horizontal, centerWidget); m_progress->setRange(0, 1000); m_progress->setValue(0); - m_progress->setMinimumWidth(160); - m_progress->setMaximumWidth(380); - addWidget(m_progress); + m_progress->setMinimumWidth(200); + m_progress->setMaximumWidth(500); + + m_totalLabel = new QLabel(QStringLiteral("0:00"), centerWidget); + m_totalLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + m_totalLabel->setMinimumWidth(36); connect(m_progress, &QSlider::sliderPressed, this, [this] { m_seeking = true; }); connect(m_progress, &QSlider::sliderReleased, this, &MainToolBar::onProgressReleased); - m_timeLabel = new QLabel("0:00 / 0:00", this); - addWidget(m_timeLabel); + progRow->addWidget(m_elapsedLabel); + progRow->addWidget(m_progress, 1); + progRow->addWidget(m_totalLabel); - addSeparator(); + centerLo->addLayout(ctrlRow); + centerLo->addLayout(progRow); - // --- Volume --- - m_volume = new VolumeButton(this); + // ---- RIGHT: volume + shuffle + queue + search ---- + auto *rightWidget = new QWidget(root); + auto *rightLo = new QHBoxLayout(rightWidget); + rightLo->setContentsMargins(0, 0, 0, 0); + rightLo->setSpacing(4); + + m_volume = new VolumeButton(rightWidget); m_volume->setValue(AppSettings::instance().volume()); - addWidget(m_volume); connect(m_volume, &VolumeButton::volumeChanged, this, &MainToolBar::onVolumeChanged); - addSeparator(); + auto makeToggle = [&](const QIcon &icon, const QString &tip) -> QToolButton * { + auto *btn = new QToolButton(rightWidget); + btn->setIcon(icon); + btn->setToolTip(tip); + btn->setCheckable(true); + btn->setAutoRaise(true); + btn->setIconSize(QSize(22, 22)); + return btn; + }; - // --- Shuffle --- - m_shuffle = addAction(Icon::get(QStringLiteral("media-playlist-shuffle")), tr("Shuffle")); - m_shuffle->setCheckable(true); - connect(m_shuffle, &QAction::toggled, this, &MainToolBar::onShuffleToggled); + m_shuffleBtn = makeToggle(Icon::get(QStringLiteral("media-playlist-shuffle")), tr("Shuffle")); + m_queueBtn = makeToggle(Icon::queue(), tr("Queue")); + m_searchBtn = makeToggle(Icon::search(), tr("Search")); - addSeparator(); + connect(m_shuffleBtn, &QToolButton::toggled, this, &MainToolBar::onShuffleToggled); + connect(m_queueBtn, &QToolButton::toggled, this, &MainToolBar::queueToggled); + connect(m_searchBtn, &QToolButton::toggled, this, &MainToolBar::searchToggled); - // --- Queue toggle --- - m_queueBtn = addAction(Icon::queue(), tr("Queue")); - m_queueBtn->setCheckable(true); - connect(m_queueBtn, &QAction::toggled, this, &MainToolBar::queueToggled); + rightLo->addStretch(1); + rightLo->addWidget(m_volume); + rightLo->addWidget(m_shuffleBtn); + rightLo->addWidget(m_queueBtn); + rightLo->addWidget(m_searchBtn); - // --- Search toggle --- - m_search = addAction(Icon::search(), tr("Search")); - m_search->setCheckable(true); - connect(m_search, &QAction::toggled, this, &MainToolBar::searchToggled); + // ---- Assemble root: equal stretch on left + right keeps center centred ---- + rootLo->addWidget(leftWidget, 1); + rootLo->addWidget(centerWidget, 0, Qt::AlignCenter); + rootLo->addWidget(rightWidget, 1); - // --- Backend signals --- + root->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + addWidget(root); + + // ---- Backend signals ---- connect(m_backend, &QobuzBackend::stateChanged, this, &MainToolBar::onBackendStateChanged); connect(m_backend, &QobuzBackend::trackChanged, this, &MainToolBar::onTrackChanged); connect(m_backend, &QobuzBackend::positionChanged, this, &MainToolBar::onPositionChanged); connect(m_backend, &QobuzBackend::trackFinished, this, &MainToolBar::onTrackFinished); - // --- Queue signals --- + // ---- Queue signals ---- connect(m_queue, &PlayQueue::queueChanged, this, &MainToolBar::onQueueChanged); - onQueueChanged(); // initialise button states + onQueueChanged(); } // ---- public ---- @@ -107,14 +173,14 @@ MainToolBar::MainToolBar(QobuzBackend *backend, PlayQueue *queue, QWidget *paren void MainToolBar::setPlaying(bool playing) { m_playing = playing; - m_playPause->setIcon(playing ? Icon::pause() : Icon::play()); - m_playPause->setText(playing ? tr("Pause") : tr("Play")); + m_playBtn->setIcon(playing ? Icon::pause() : Icon::play()); + m_playBtn->setToolTip(playing ? tr("Pause") : tr("Play")); } void MainToolBar::setCurrentTrack(const QJsonObject &track) { - const QString title = track["title"].toString(); - const QString artist = track["performer"].toObject()["name"].toString().isEmpty() + const QString title = track["title"].toString(); + const QString artist = track["performer"].toObject()["name"].toString().isEmpty() ? track["album"].toObject()["artist"].toObject()["name"].toString() : track["performer"].toObject()["name"].toString(); @@ -123,10 +189,9 @@ void MainToolBar::setCurrentTrack(const QJsonObject &track) } else if (artist.isEmpty()) { m_trackLabel->setText(title); } else { - m_trackLabel->setText(QStringLiteral("%1 — %2").arg(artist, title)); + m_trackLabel->setText(QStringLiteral("%1\n%2").arg(title, artist)); } - // Album art const QString artUrl = track["album"].toObject()["image"].toObject()["small"].toString(); if (!artUrl.isEmpty() && artUrl != m_currentArtUrl) { m_currentArtUrl = artUrl; @@ -142,10 +207,8 @@ void MainToolBar::updateProgress(quint64 position, quint64 duration) m_progress->blockSignals(true); m_progress->setValue(sliderPos); m_progress->blockSignals(false); - m_timeLabel->setText( - QStringLiteral("%1 / %2") - .arg(TrackListModel::formatDuration(static_cast(position)), - TrackListModel::formatDuration(static_cast(duration)))); + m_elapsedLabel->setText(TrackListModel::formatDuration(static_cast(position))); + m_totalLabel->setText(TrackListModel::formatDuration(static_cast(duration))); } // ---- private slots ---- @@ -207,20 +270,20 @@ void MainToolBar::onPositionChanged(quint64 position, quint64 duration) void MainToolBar::onTrackFinished() { - // Auto-advance queue if (m_queue->canGoNext()) { onNext(); } else { setPlaying(false); m_progress->setValue(0); - m_timeLabel->setText("0:00 / 0:00"); + m_elapsedLabel->setText(QStringLiteral("0:00")); + m_totalLabel->setText(QStringLiteral("0:00")); } } void MainToolBar::onQueueChanged() { - m_previous->setEnabled(m_queue->canGoPrev()); - m_next->setEnabled(m_queue->canGoNext()); + m_prevBtn->setEnabled(m_queue->canGoPrev()); + m_nextBtn->setEnabled(m_queue->canGoNext()); } void MainToolBar::onShuffleToggled(bool checked) diff --git a/src/view/maintoolbar.hpp b/src/view/maintoolbar.hpp index 29efae6..77492db 100644 --- a/src/view/maintoolbar.hpp +++ b/src/view/maintoolbar.hpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -50,18 +49,23 @@ private: QobuzBackend *m_backend = nullptr; PlayQueue *m_queue = nullptr; - QLabel *m_artLabel = nullptr; - QLabel *m_trackLabel = nullptr; - ClickableSlider *m_progress = nullptr; - QLabel *m_timeLabel = nullptr; - VolumeButton *m_volume = nullptr; + // Left + QLabel *m_artLabel = nullptr; + QLabel *m_trackLabel = nullptr; - QAction *m_previous = nullptr; - QAction *m_playPause = nullptr; - QAction *m_next = nullptr; - QAction *m_shuffle = nullptr; - QAction *m_queueBtn = nullptr; - QAction *m_search = nullptr; + // Center + QToolButton *m_prevBtn = nullptr; + QToolButton *m_playBtn = nullptr; + QToolButton *m_nextBtn = nullptr; + ClickableSlider *m_progress = nullptr; + QLabel *m_elapsedLabel = nullptr; + QLabel *m_totalLabel = nullptr; + + // Right + VolumeButton *m_volume = nullptr; + QToolButton *m_shuffleBtn = nullptr; + QToolButton *m_queueBtn = nullptr; + QToolButton *m_searchBtn = nullptr; QNetworkAccessManager *m_nam = nullptr; QString m_currentArtUrl;