Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cover art UX improvements #1207

Merged
merged 14 commits into from
Nov 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 184 additions & 23 deletions src/library/dlgcoverartfullsize.cpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,203 @@
#include <QDesktopWidget>
#include <QWheelEvent>

#include "library/dlgcoverartfullsize.h"
#include "library/coverartutils.h"
#include "library/coverartcache.h"

DlgCoverArtFullSize::DlgCoverArtFullSize(QWidget* parent, BaseTrackPlayer* pPlayer)
: QDialog(parent),
m_pPlayer(pPlayer),
m_pCoverMenu(new WCoverArtMenu(this)) {
CoverArtCache* pCache = CoverArtCache::instance();
if (pCache != nullptr) {
connect(pCache, SIGNAL(coverFound(const QObject*,
const CoverInfo&, QPixmap, bool)),
this, SLOT(slotCoverFound(const QObject*,
const CoverInfo&, QPixmap, bool)));
}

setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotCoverMenu(QPoint)));
connect(m_pCoverMenu, SIGNAL(coverInfoSelected(const CoverInfo&)),
this, SLOT(slotCoverInfoSelected(const CoverInfo&)));
connect(m_pCoverMenu, SIGNAL(reloadCoverArt()),
this, SLOT(slotReloadCoverArt()));

if (m_pPlayer != nullptr) {
connect(pPlayer, SIGNAL(newTrackLoaded(TrackPointer)),
this, SLOT(slotLoadTrack(TrackPointer)));
}

DlgCoverArtFullSize::DlgCoverArtFullSize(QWidget* parent)
: QDialog(parent) {
setupUi(this);
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
}

DlgCoverArtFullSize::~DlgCoverArtFullSize() {
delete m_pCoverMenu;
}

void DlgCoverArtFullSize::init(QPixmap pixmap) {
if (pixmap.isNull()) {
void DlgCoverArtFullSize::init(TrackPointer pTrack) {
if (pTrack == nullptr) {
return;
}
slotLoadTrack(pTrack);

QWidgetList windows = QApplication::topLevelWidgets();
QSize largestWindowSize;
foreach (QWidget* pWidget, windows) {
largestWindowSize = largestWindowSize.expandedTo(pWidget->size());
show();
raise();
activateWindow();
}

void DlgCoverArtFullSize::slotLoadTrack(TrackPointer pTrack) {
if (m_pLoadedTrack != nullptr) {
disconnect(m_pLoadedTrack.get(), SIGNAL(coverArtUpdated()),
this, SLOT(slotTrackCoverArtUpdated()));
}
m_pLoadedTrack = pTrack;
if (m_pLoadedTrack != nullptr) {
QString windowTitle;
const QString albumArtist = m_pLoadedTrack->getAlbumArtist();
const QString artist = m_pLoadedTrack->getArtist();
const QString album = m_pLoadedTrack->getAlbum();
const QString year = m_pLoadedTrack->getYear();
if (!albumArtist.isEmpty()) {
windowTitle = albumArtist;
} else if (!artist.isEmpty()) {
windowTitle += artist;
}
if (!album.isEmpty()) {
if (!windowTitle.isEmpty()) {
windowTitle += " - ";
}
windowTitle += album;
}
if (!year.isEmpty()) {
if (!windowTitle.isEmpty()) {
windowTitle += " ";
}
windowTitle += QString("(%1)").arg(year);
}
setWindowTitle(windowTitle);

// If cover is bigger than Mixxx, it must be resized!
// In this case, it need to do a small adjust to make
// this dlg a bit smaller than the Mixxx window.
QSize mixxxSize = largestWindowSize / qreal(1.2);
if (pixmap.height() > mixxxSize.height()
|| pixmap.width() > mixxxSize.width()) {
pixmap = pixmap.scaled(
mixxxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
connect(m_pLoadedTrack.get(), SIGNAL(coverArtUpdated()),
this, SLOT(slotTrackCoverArtUpdated()));
}
resize(pixmap.size());
coverArt->setPixmap(pixmap);

show();
move(QApplication::desktop()->screenGeometry().center() - rect().center());
raise();
activateWindow();
slotTrackCoverArtUpdated();
}

void DlgCoverArtFullSize::slotTrackCoverArtUpdated() {
if (m_pLoadedTrack != nullptr) {
CoverArtCache::requestCover(*m_pLoadedTrack, this);
}
}

void DlgCoverArtFullSize::slotCoverFound(const QObject* pRequestor,
const CoverInfo& info, QPixmap pixmap,
bool fromCache) {
Q_UNUSED(info);
Q_UNUSED(fromCache);

if (pRequestor == this && m_pLoadedTrack != nullptr &&
m_pLoadedTrack->getCoverHash() == info.hash) {
// qDebug() << "DlgCoverArtFullSize::slotCoverFound" << pRequestor << info
// << pixmap.size();
m_pixmap = pixmap;
if (m_pixmap.isNull()) {
close();
} else {
// Scale down dialog if the pixmap is larger than the screen.
// Use 90% of screen size instead of 100% to prevent an issue with
// whitespace appearing on the side when resizing a window whose
// borders touch the edges of the screen.
QSize dialogSize = m_pixmap.size();
const QSize availableScreenSpace =
QApplication::desktop()->availableGeometry().size() * 0.9;
if (dialogSize.height() > availableScreenSpace.height()) {
dialogSize.scale(dialogSize.width(), availableScreenSpace.height(),
Qt::KeepAspectRatio);
} else if (dialogSize.width() > availableScreenSpace.width()) {
dialogSize.scale(availableScreenSpace.width(), dialogSize.height(),
Qt::KeepAspectRatio);
}
QPixmap resizedPixmap = m_pixmap.scaled(size(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
coverArt->setPixmap(resizedPixmap);
// center the window
setGeometry(QStyle::alignedRect(
Qt::LeftToRight,
Qt::AlignCenter,
dialogSize,
QApplication::desktop()->availableGeometry()));
}
}
}

// slots to handle signals from the context menu
void DlgCoverArtFullSize::slotReloadCoverArt() {
if (m_pLoadedTrack != nullptr) {
CoverInfo coverInfo =
CoverArtUtils::guessCoverInfo(*m_pLoadedTrack);
slotCoverInfoSelected(coverInfo);
}
}

void DlgCoverArtFullSize::slotCoverInfoSelected(const CoverInfo& coverInfo) {
// qDebug() << "DlgCoverArtFullSize::slotCoverInfoSelected" << coverInfo;
if (m_pLoadedTrack != nullptr) {
m_pLoadedTrack->setCoverInfo(coverInfo);
}
}

void DlgCoverArtFullSize::mousePressEvent(QMouseEvent* event) {
Q_UNUSED(event);

if (m_pCoverMenu->isVisible()) {
return;
}

if (event->button() == Qt::LeftButton && isVisible()) {
close();
}
}

void DlgCoverArtFullSize::slotCoverMenu(const QPoint& pos) {
m_pCoverMenu->popup(mapToGlobal(pos));
}

void DlgCoverArtFullSize::resizeEvent(QResizeEvent* event) {
Q_UNUSED(event);
if (m_pixmap.isNull()) {
return;
}
// qDebug() << "DlgCoverArtFullSize::resizeEvent" << size();
QPixmap resizedPixmap = m_pixmap.scaled(size(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
coverArt->setPixmap(resizedPixmap);
}

void DlgCoverArtFullSize::wheelEvent(QWheelEvent* event) {
// Scale the image size
int oldWidth = width();
int oldHeight = height();
int newWidth = oldWidth + (0.2 * event->delta());
int newHeight = oldHeight + (0.2 * event->delta());
QSize newSize = size();
newSize.scale(newWidth, newHeight, Qt::KeepAspectRatio);

// To keep the same part of the image under the cursor, shift the
// origin (top left point) by the distance the point moves under the cursor.
QPoint oldOrigin = geometry().topLeft();
QPoint oldPointUnderCursor = event->pos();
int newPointX = (double) oldPointUnderCursor.x() / oldWidth * newSize.width();
int newPointY = (double) oldPointUnderCursor.y() / oldHeight * newSize.height();
QPoint newOrigin = QPoint(
oldOrigin.x() + (oldPointUnderCursor.x() - newPointX),
oldOrigin.y() + (oldPointUnderCursor.y() - newPointY));

// Calling resize() then move() causes flickering, so resize and move the window
// simultaneously with setGeometry().
setGeometry(QRect(newOrigin, newSize));

event->accept();
}
27 changes: 25 additions & 2 deletions src/library/dlgcoverartfullsize.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,39 @@

#include "library/ui_dlgcoverartfullsize.h"
#include "library/coverart.h"
#include "mixer/basetrackplayer.h"
#include "track/track.h"
#include "widget/wcoverartmenu.h"

class DlgCoverArtFullSize
: public QDialog,
public Ui::DlgCoverArtFullSize {
Q_OBJECT
public:
DlgCoverArtFullSize(QWidget* parent=0);
DlgCoverArtFullSize(QWidget* parent = nullptr, BaseTrackPlayer* pPlayer = nullptr);
virtual ~DlgCoverArtFullSize();

void init(QPixmap pixmap);
void init(TrackPointer pTrack);
void mousePressEvent(QMouseEvent* /* unused */) override;
void resizeEvent(QResizeEvent* event) override;
void wheelEvent(QWheelEvent* event) override;

public slots:
void slotLoadTrack(TrackPointer);
void slotCoverFound(const QObject* pRequestor,
const CoverInfo& info, QPixmap pixmap, bool fromCache);
void slotTrackCoverArtUpdated();

// slots that handle signals from WCoverArtMenu
void slotCoverMenu(const QPoint& pos);
void slotCoverInfoSelected(const CoverInfo& coverInfo);
void slotReloadCoverArt();

private:
QPixmap m_pixmap;
TrackPointer m_pLoadedTrack;
BaseTrackPlayer* m_pPlayer;
WCoverArtMenu* m_pCoverMenu;
};

#endif // DLGCOVERARTFULLSIZE_H
1 change: 1 addition & 0 deletions src/library/dlgtrackinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ void DlgTrackInfo::loadTrack(TrackPointer pTrack) {

populateFields(*m_pLoadedTrack);
populateCues(m_pLoadedTrack);
m_pWCoverArtLabel->loadTrack(m_pLoadedTrack);

// We already listen to changed() so we don't need to listen to individual
// signals such as cuesUpdates, coverArtUpdated(), etc.
Expand Down
25 changes: 5 additions & 20 deletions src/skin/legacyskinparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1107,8 +1107,10 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) {
dummy->setText(tr("Safe Mode Enabled"));
return dummy;
}

BaseTrackPlayer* pPlayer = m_pPlayerManager->getPlayer(channelStr);
WSpinny* spinny = new WSpinny(m_pParent, channelStr, m_pConfig,
m_pVCManager);
m_pVCManager, pPlayer);
if (!spinny->isValid()) {
delete spinny;
WLabel* dummy = new WLabel(m_pParent);
Expand All @@ -1122,16 +1124,6 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) {
connect(spinny, SIGNAL(trackDropped(QString, QString)),
m_pPlayerManager, SLOT(slotLoadToPlayer(QString, QString)));

BaseTrackPlayer* pPlayer = m_pPlayerManager->getPlayer(channelStr);
if (pPlayer != NULL) {
connect(pPlayer, SIGNAL(newTrackLoaded(TrackPointer)),
spinny, SLOT(slotLoadTrack(TrackPointer)));
connect(pPlayer, SIGNAL(loadingTrack(TrackPointer, TrackPointer)),
spinny, SLOT(slotLoadingTrack(TrackPointer, TrackPointer)));
// just in case a track is already loaded
spinny->slotLoadTrack(pPlayer->getLoadedTrack());
}

spinny->setup(node, *m_pContext);
spinny->installEventFilter(m_pKeyboard);
spinny->installEventFilter(m_pControllerManager->getControllerLearningEventFilter());
Expand Down Expand Up @@ -1161,7 +1153,7 @@ QWidget* LegacySkinParser::parseCoverArt(const QDomElement& node) {
QString channel = lookupNodeGroup(node);
BaseTrackPlayer* pPlayer = m_pPlayerManager->getPlayer(channel);

WCoverArt* pCoverArt = new WCoverArt(m_pParent, m_pConfig, channel);
WCoverArt* pCoverArt = new WCoverArt(m_pParent, m_pConfig, channel, pPlayer);
commonWidgetSetup(node, pCoverArt);
pCoverArt->setup(node, *m_pContext);

Expand All @@ -1174,16 +1166,9 @@ QWidget* LegacySkinParser::parseCoverArt(const QDomElement& node) {
pCoverArt, SLOT(slotEnable(bool)));
connect(m_pLibrary, SIGNAL(trackSelected(TrackPointer)),
pCoverArt, SLOT(slotLoadTrack(TrackPointer)));
} else if (pPlayer != NULL) {
connect(pPlayer, SIGNAL(newTrackLoaded(TrackPointer)),
pCoverArt, SLOT(slotLoadTrack(TrackPointer)));
connect(pPlayer, SIGNAL(loadingTrack(TrackPointer, TrackPointer)),
pCoverArt, SLOT(slotLoadingTrack(TrackPointer, TrackPointer)));
} else if (pPlayer != nullptr) {
connect(pCoverArt, SIGNAL(trackDropped(QString, QString)),
m_pPlayerManager, SLOT(slotLoadToPlayer(QString, QString)));

// just in case a track is already loaded
pCoverArt->slotLoadTrack(pPlayer->getLoadedTrack());
}

return pCoverArt;
Expand Down
1 change: 1 addition & 0 deletions src/skin/tooltips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void Tooltips::addStandardTooltips() {
<< tr("Spinning Vinyl")
<< tr("Rotates during playback and shows the position of a track.")
<< scratchMouse
<< tr("Right click to show cover art of loaded track.")
<< dropTracksHere
<< tr("If Vinyl control is enabled, displays time-coded vinyl signal quality (see Preferences -> Vinyl Control).");

Expand Down
22 changes: 15 additions & 7 deletions src/widget/wcoverart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@

WCoverArt::WCoverArt(QWidget* parent,
UserSettingsPointer pConfig,
const QString& group)
const QString& group,
BaseTrackPlayer* pPlayer)
: QWidget(parent),
WBaseWidget(this),
m_group(group),
m_pConfig(pConfig),
m_bEnable(true),
m_pMenu(new WCoverArtMenu(this)),
m_pDlgFullSize(new DlgCoverArtFullSize()) {
m_pPlayer(pPlayer),
m_pDlgFullSize(new DlgCoverArtFullSize(this, pPlayer)) {
// Accept drops if we have a group to load tracks into.
setAcceptDrops(!m_group.isEmpty());

Expand All @@ -39,6 +41,16 @@ WCoverArt::WCoverArt(QWidget* parent,
this, SLOT(slotCoverInfoSelected(const CoverInfo&)));
connect(m_pMenu, SIGNAL(reloadCoverArt()),
this, SLOT(slotReloadCoverArt()));

if (m_pPlayer != nullptr) {
connect(m_pPlayer, SIGNAL(newTrackLoaded(TrackPointer)),
this, SLOT(slotLoadTrack(TrackPointer)));
connect(m_pPlayer, SIGNAL(loadingTrack(TrackPointer, TrackPointer)),
this, SLOT(slotLoadingTrack(TrackPointer, TrackPointer)));

// just in case a track is already loaded
slotLoadTrack(m_pPlayer->getLoadedTrack());
}
}

WCoverArt::~WCoverArt() {
Expand Down Expand Up @@ -223,15 +235,11 @@ void WCoverArt::mousePressEvent(QMouseEvent* event) {
if (m_pDlgFullSize->isVisible()) {
m_pDlgFullSize->close();
} else {
m_pDlgFullSize->init(m_loadedCover);
m_pDlgFullSize->init(m_loadedTrack);
}
}
}

void WCoverArt::leaveEvent(QEvent* /*unused*/) {
m_pDlgFullSize->close();
}

void WCoverArt::mouseMoveEvent(QMouseEvent* event) {
if ((event->buttons() & Qt::LeftButton) && m_loadedTrack) {
DragAndDropHelper::dragTrack(m_loadedTrack, this, m_group);
Expand Down
Loading