Retina support for covers in views.

This commit is contained in:
craig.p.drummond
2014-09-19 16:43:48 +00:00
committed by craig.p.drummond
parent 3321f64195
commit 0e05af098b
2 changed files with 147 additions and 69 deletions

View File

@@ -60,10 +60,9 @@
#include <QFont>
#include <QXmlStreamReader>
#include <QTimer>
#include <QCoreApplication>
#include <QApplication>
#ifdef ENABLE_KDE_SUPPORT
#include <KDE/KStandardDirs>
#include <QApplication>
#endif
GLOBAL_STATIC(Covers, instance)
@@ -95,6 +94,12 @@ static bool fetchCovers=true;
static QString constCoverInTagPrefix=QLatin1String("{tag}");
static QString constNoCover=QLatin1String("{nocover}");
#if QT_VERSION >= 0x050100
static double devicePixelRatio=1.0;
// Only scale images to device pixel ratio if un-scaled size is less then 300pixels.
static const int constRetinaScaleMaxSize=300;
#endif
static QImage scale(const Song &song, const QImage &img, int size)
{
if (song.isArtistImageRequest()) {
@@ -1004,7 +1009,13 @@ void CoverLoader::load()
QList<LoadedCover> covers;
foreach (const LoadedCover &s, toDo) {
DBUG << s.song.artist << s.song.albumId() << s.song.size;
covers.append(LoadedCover(s.song, loadScaledCover(s.song, s.song.size)));
int size=s.song.size;
#if QT_VERSION >= 0x050100
if (size<constRetinaScaleMaxSize) {
size*=devicePixelRatio;
}
#endif
covers.append(LoadedCover(s.song, loadScaledCover(s.song, size)));
}
if (!covers.isEmpty()) {
DBUG << "loaded" << covers.count();
@@ -1021,6 +1032,11 @@ Covers::Covers()
, locator(0)
, loader(0)
{
#if QT_VERSION >= 0x050100
if (Settings::self()->retinaSupport()) {
devicePixelRatio=qApp->devicePixelRatio();
}
#endif
#ifdef ENABLE_UBUNTU
cache.setMaxCost(20*1024*1024); // Not used?
cacheScaledCovers=false;
@@ -1133,6 +1149,12 @@ QPixmap * Covers::get(const Song &song, int size, bool urgent)
size=22;
}
int origSize=size;
#if QT_VERSION >= 0x050100
if (size<constRetinaScaleMaxSize) {
size*=devicePixelRatio;
}
#endif
if (!song.isUnknown()) {
key=cacheKey(song, size);
pix=cache.object(key);
@@ -1156,6 +1178,12 @@ QPixmap * Covers::get(const Song &song, int size, bool urgent)
}
#endif
if (pix) {
#if QT_VERSION >= 0x050100
if (size!=origSize) {
pix->setDevicePixelRatio(devicePixelRatio);
DBUG << "Set pixel ratio of cover" << devicePixelRatio;
}
#endif
cache.insert(key, pix, 1);
cacheSizes.insert(size);
}
@@ -1167,25 +1195,44 @@ QPixmap * Covers::get(const Song &song, int size, bool urgent)
if (cached.isNull()) {
Image img=findImage(song, false);
if (!img.img.isNull()) {
return saveScaledCover(scale(song, img.img, size), song, size);
pix=saveScaledCover(scale(song, img.img, size), song, size);
#if QT_VERSION >= 0x050100
if (size!=origSize) {
pix->setDevicePixelRatio(devicePixelRatio);
DBUG << "Set pixel ratio of saved scaled cover" << devicePixelRatio;
}
#endif
return pix;
} else if (constNoCover==img.fileName) {
return 0;
}
} else {
pix=new QPixmap(QPixmap::fromImage(cached));
#if QT_VERSION >= 0x050100
if (size!=origSize) {
pix->setDevicePixelRatio(devicePixelRatio);
DBUG << "Set pixel ratio of loaded scaled cover" << devicePixelRatio;
}
#endif
cache.insert(key, pix);
cacheSizes.insert(size);
return pix;
}
}
if (cacheScaledCovers) {
tryToLoad(setSizeRequest(song, size));
tryToLoad(setSizeRequest(song, origSize));
} else {
tryToLocate(setSizeRequest(song, size));
tryToLocate(setSizeRequest(song, origSize));
}
// Create a dummy image so that we dont keep on locating/loading/downloading files that do not exist!
pix=new QPixmap(1, 1);
#if QT_VERSION >= 0x050100
if (size!=origSize) {
pix->setDevicePixelRatio(devicePixelRatio);
DBUG << "Set pixel ratio of dummy cover" << devicePixelRatio;
}
#endif
cache.insert(key, pix, 1);
cacheSizes.insert(size);
}
@@ -1215,6 +1262,12 @@ QPixmap * Covers::get(const Song &song, int size, bool urgent)
? Icons::self()->podcastIcon
: Icons::self()->albumIcon;
pix=new QPixmap(icn.pixmap(size, size).scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
#if QT_VERSION >= 0x050100
if (size!=origSize) {
pix->setDevicePixelRatio(devicePixelRatio);
DBUG << "Set pixel ratio of dummy pixmap" << devicePixelRatio;
}
#endif
cache.insert(key, pix, 1);
cacheSizes.insert(size);
}
@@ -1250,10 +1303,20 @@ void Covers::updateCache(const Song &song, const QImage &img, bool dummyEntriesO
QPixmap *pix(cache.object(key));
if (pix && (!dummyEntriesOnly || pix->width()<2)) {
#if QT_VERSION >= 0x050100
double pixRatio=pix->devicePixelRatio();
#endif
cache.remove(key);
if (!img.isNull()) {
DBUG_CLASS("Covers");
if (saveScaledCover(scale(song, img, s), song, s) && emitLoaded) {
QPixmap *p=saveScaledCover(scale(song, img, s), song, s);
#if QT_VERSION >= 0x050100
if (p) {
p->setDevicePixelRatio(pixRatio);
DBUG << "Set pixel ratio of updated cached pixmap" << devicePixelRatio;
}
#endif
if (pix && emitLoaded) {
emit loaded(song, s);
}
}
@@ -1648,8 +1711,22 @@ void Covers::loaded(const QList<LoadedCover> &covers)
{
foreach (const LoadedCover &cvr, covers) {
if (!cvr.img.isNull()) {
cache.insert(cacheKey(cvr.song, cvr.song.size), new QPixmap(QPixmap::fromImage(cvr.img)));
cacheSizes.insert(cvr.song.size);
int size=cvr.song.size;
#if QT_VERSION >= 0x050100
int origSize=size;
if (size<constRetinaScaleMaxSize) {
size*=devicePixelRatio;
}
#endif
QPixmap *pix=new QPixmap(QPixmap::fromImage(cvr.img));
#if QT_VERSION >= 0x050100
if (size!=origSize) {
pix->setDevicePixelRatio(devicePixelRatio);
DBUG << "Set pixel ratio of loaded pixmap" << devicePixelRatio;
}
#endif
cache.insert(cacheKey(cvr.song, size), pix);
cacheSizes.insert(size);
emit loaded(cvr.song, cvr.song.size);
} else { // Failed to load a scaled cover, try locating non-scaled cover...
tryToLocate(cvr.song);

View File

@@ -426,73 +426,74 @@ public:
bool active=option.state&QStyle::State_Active;
bool mouseOver=underMouse && option.state&QStyle::State_MouseOver;
if (!gtk && 1==text.count()) {
QStyledItemDelegate::paint(painter, option, index);
if (mouseOver && gtk) {
GtkStyle::drawSelection(option, painter, selected ? 0.75 : 0.25);
} else {
if (mouseOver && gtk) {
GtkStyle::drawSelection(option, painter, selected ? 0.75 : 0.25);
} else {
QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0L);
}
QRect r(option.rect);
r.adjust(4, 0, -4, 0);
QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0L);
}
QRect r(option.rect);
r.adjust(4, 0, -4, 0);
if (!noIcons) {
QPixmap pix;
if (index.data(Cantata::Role_ListImage).toBool()) {
Song cSong=index.data(Cantata::Role_CoverSong).value<Song>();
if (!cSong.isEmpty()) {
QPixmap *cp=Covers::self()->get(cSong, listCoverSize);
if (cp) {
pix=*cp;
}
}
}
if (pix.isNull()) {
pix=index.data(Qt::DecorationRole).value<QIcon>().pixmap(simpleViewDecorationSize, simpleViewDecorationSize);
}
if (!pix.isNull()) {
int adjust=qMax(pix.width(), pix.height());
if (rtl) {
painter->drawPixmap(r.x()+r.width()-pix.width(), r.y()+((r.height()-pix.height())/2), pix.width(), pix.height(), pix);
r.adjust(3, 0, -(3+adjust), 0);
} else {
painter->drawPixmap(r.x(), r.y()+((r.height()-pix.height())/2), pix.width(), pix.height(), pix);
r.adjust(adjust+3, 0, -3, 0);
if (!noIcons) {
QPixmap pix;
if (index.data(Cantata::Role_ListImage).toBool()) {
Song cSong=index.data(Cantata::Role_CoverSong).value<Song>();
if (!cSong.isEmpty()) {
QPixmap *cp=Covers::self()->get(cSong, listCoverSize);
if (cp) {
pix=*cp;
}
}
}
if (text.count()>0) {
QFont textFont(QApplication::font());
QFontMetrics textMetrics(textFont);
int textHeight=textMetrics.height();
QColor color(option.palette.color(active ? QPalette::Active : QPalette::Inactive, selected ? QPalette::HighlightedText : QPalette::Text));
QTextOption textOpt(Qt::AlignVCenter);
QRect textRect(r.x(), r.y()+((r.height()-textHeight)/2), r.width(), textHeight);
QString str=textMetrics.elidedText(text.at(0), Qt::ElideRight, textRect.width(), QPalette::WindowText);
painter->save();
painter->setPen(color);
painter->setFont(textFont);
painter->drawText(textRect, str, textOpt);
if (text.count()>1) {
int mainWidth=textMetrics.width(str);
text.takeFirst();
str=text.join(" - ");
textRect=QRect(r.x()+(mainWidth+8), r.y()+((r.height()-textHeight)/2), r.width()-(mainWidth+8), textHeight);
if (textRect.width()>4) {
str = textMetrics.elidedText(str, Qt::ElideRight, textRect.width(), QPalette::WindowText);
color.setAlphaF(subTextAlpha(selected));
painter->setPen(color);
painter->drawText(textRect, str, textOpt/*QTextOption(Qt::AlignVCenter|Qt::AlignRight)*/);
}
}
painter->restore();
if (pix.isNull()) {
pix=index.data(Qt::DecorationRole).value<QIcon>().pixmap(simpleViewDecorationSize, simpleViewDecorationSize);
}
if (!pix.isNull()) {
#if QT_VERSION >= 0x050100
QSize layoutSize = pix.size() / pix.devicePixelRatio();
#else
QSize layoutSize = pix.size();
#endif
int adjust=qMax(layoutSize.width(), layoutSize.height());
if (rtl) {
painter->drawPixmap(r.x()+r.width()-layoutSize.width(), r.y()+((r.height()-layoutSize.height())/2), layoutSize.width(), layoutSize.height(), pix);
r.adjust(3, 0, -(3+adjust), 0);
} else {
painter->drawPixmap(r.x(), r.y()+((r.height()-layoutSize.height())/2), layoutSize.width(), layoutSize.height(), pix);
r.adjust(adjust+3, 0, -3, 0);
}
}
}
if (text.count()>0) {
QFont textFont(QApplication::font());
QFontMetrics textMetrics(textFont);
int textHeight=textMetrics.height();
QColor color(option.palette.color(active ? QPalette::Active : QPalette::Inactive, selected ? QPalette::HighlightedText : QPalette::Text));
QTextOption textOpt(Qt::AlignVCenter);
QRect textRect(r.x(), r.y()+((r.height()-textHeight)/2), r.width(), textHeight);
QString str=textMetrics.elidedText(text.at(0), Qt::ElideRight, textRect.width(), QPalette::WindowText);
painter->save();
painter->setPen(color);
painter->setFont(textFont);
painter->drawText(textRect, str, textOpt);
if (text.count()>1) {
int mainWidth=textMetrics.width(str);
text.takeFirst();
str=text.join(" - ");
textRect=QRect(r.x()+(mainWidth+8), r.y()+((r.height()-textHeight)/2), r.width()-(mainWidth+8), textHeight);
if (textRect.width()>4) {
str = textMetrics.elidedText(str, Qt::ElideRight, textRect.width(), QPalette::WindowText);
color.setAlphaF(subTextAlpha(selected));
painter->setPen(color);
painter->drawText(textRect, str, textOpt/*QTextOption(Qt::AlignVCenter|Qt::AlignRight)*/);
}
}
painter->restore();
}
if (mouseOver || Utils::touchFriendly()) {