1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-19 04:50:16 +01:00

Collapse all info sections by default except the first one of each type but add support for using user preferences (they don't get saved yet), add a fade in/out animation to collapsed section headers.

This commit is contained in:
David Sansome 2010-10-11 19:49:12 +00:00
parent 0fcba76195
commit abbc908aaa
13 changed files with 102 additions and 4 deletions

View File

@ -58,4 +58,6 @@ void ArtistInfoView::ResultReady(int id, const SongInfoFetcher::Result& result)
foreach (const CollapsibleInfoPane::Data& data, result.info_) {
AddSection(new CollapsibleInfoPane(data, this));
}
CollapseSections();
}

View File

@ -19,6 +19,7 @@
#include <QApplication>
#include <QMouseEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyleOption>
const int CollapsibleInfoHeader::kHeight = 20;
@ -26,8 +27,10 @@ const int CollapsibleInfoHeader::kIconSize = 16;
CollapsibleInfoHeader::CollapsibleInfoHeader(QWidget* parent)
: QWidget(parent),
expanded_(true),
hovering_(false)
expanded_(false),
hovering_(false),
animation_(new QPropertyAnimation(this, "opacity", this)),
opacity_(0.0)
{
setMinimumHeight(kHeight);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@ -56,17 +59,45 @@ void CollapsibleInfoHeader::SetExpanded(bool expanded) {
void CollapsibleInfoHeader::enterEvent(QEvent*) {
hovering_ = true;
update();
if (!expanded_) {
animation_->stop();
animation_->setEndValue(1.0);
animation_->setDuration(80);
animation_->start();
}
}
void CollapsibleInfoHeader::leaveEvent(QEvent*) {
hovering_ = false;
if (!expanded_) {
animation_->stop();
animation_->setEndValue(0.0);
animation_->setDuration(160);
animation_->start();
}
}
void CollapsibleInfoHeader::set_opacity(float opacity) {
opacity_ = opacity;
update();
}
void CollapsibleInfoHeader::paintEvent(QPaintEvent* e) {
QPainter p(this);
QColor active_text_color(palette().color(QPalette::Active, QPalette::HighlightedText));
QColor inactive_text_color(palette().color(QPalette::Active, QPalette::Text));
QColor text_color;
if (expanded_) {
text_color = active_text_color;
} else {
p.setOpacity(0.4 + opacity_ * 0.6);
text_color = QColor(
active_text_color.red() * opacity_ + inactive_text_color.red() * (1.0 - opacity_),
active_text_color.green() * opacity_ + inactive_text_color.green() * (1.0 - opacity_),
active_text_color.blue() * opacity_ + inactive_text_color.blue() * (1.0 - opacity_));
}
QRect indicator_rect(0, 0, height(), height());
QRect icon_rect(height() + 2, (kHeight - kIconSize) / 2, kIconSize, kIconSize);
QRect text_rect(rect());
@ -112,7 +143,7 @@ void CollapsibleInfoHeader::paintEvent(QPaintEvent* e) {
bold_font.setBold(true);
p.setFont(bold_font);
p.setPen(palette().color(QPalette::Active, QPalette::HighlightedText));
p.setPen(text_color);
p.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, title_);
}

View File

@ -20,8 +20,11 @@
#include <QIcon>
#include <QWidget>
class QPropertyAnimation;
class CollapsibleInfoHeader : public QWidget {
Q_OBJECT
Q_PROPERTY(float opacity READ opacity WRITE set_opacity);
public:
CollapsibleInfoHeader(QWidget* parent = 0);
@ -34,6 +37,9 @@ public:
const QString& title() const { return title_; }
const QIcon& icon() const { return icon_; }
float opacity() const { return opacity_; }
void set_opacity(float opacity);
public slots:
void SetExpanded(bool expanded);
void SetTitle(const QString& title);
@ -55,6 +61,9 @@ private:
bool hovering_;
QString title_;
QIcon icon_;
QPropertyAnimation* animation_;
float opacity_;
};
#endif // COLLAPSIBLEINFOHEADER_H

View File

@ -32,6 +32,7 @@ CollapsibleInfoPane::CollapsibleInfoPane(const Data& data, QWidget* parent)
layout->addWidget(header_);
layout->addWidget(data.contents_);
data.contents_->hide();
header_->SetTitle(data.title_);
header_->SetIcon(data.icon_);

View File

@ -41,6 +41,7 @@ public:
TypeCount
};
QString id_;
QString title_;
QIcon icon_;
Type type_;

View File

@ -77,6 +77,7 @@ void EchoNestBiographies::RequestFinished() {
already_seen.insert(canonical_site);
CollapsibleInfoPane::Data data;
data.id_ = "echonest/bio/" + bio.site();
data.title_ = tr("Biography from %1").arg(bio.site());
data.type_ = CollapsibleInfoPane::Data::Type_Biography;

View File

@ -51,6 +51,7 @@ void EchoNestSimilarArtists::RequestFinished() {
if (!artists.isEmpty()) {
CollapsibleInfoPane::Data data;
data.id_ = "echonest/similarartists";
data.title_ = tr("Similar artists");
data.type_ = CollapsibleInfoPane::Data::Type_Similar;
data.icon_ = QIcon(":/providers/echonest.png");

View File

@ -53,6 +53,7 @@ void EchoNestTags::RequestFinished() {
if (!request->artist_->terms().isEmpty()) {
CollapsibleInfoPane::Data data;
data.id_ = "echonest/artisttags";
data.title_ = tr("Artist tags");
data.type_ = CollapsibleInfoPane::Data::Type_Tags;
data.icon_ = QIcon(":/last.fm/icon_tag.png");

View File

@ -81,6 +81,7 @@ void LastfmTrackInfoProvider::GetPlayCounts(int id, const lastfm::XmlQuery& q) {
return; // No useful data
CollapsibleInfoPane::Data data;
data.id_ = "lastfm/playcounts";
data.title_ = tr("Last.fm play counts");
data.type_ = CollapsibleInfoPane::Data::Type_PlayCounts;
data.icon_ = QIcon(":/last.fm/as.png");
@ -113,6 +114,7 @@ void LastfmTrackInfoProvider::GetWiki(int id, const lastfm::XmlQuery& q) {
return; // No useful data
CollapsibleInfoPane::Data data;
data.id_ = "lastfm/songwiki";
data.title_ = tr("Last.fm wiki");
data.type_ = CollapsibleInfoPane::Data::Type_Biography;
data.icon_ = QIcon(":/last.fm/as.png");
@ -131,6 +133,7 @@ void LastfmTrackInfoProvider::GetTags(int id, const lastfm::XmlQuery& q) {
return; // No tag elements
CollapsibleInfoPane::Data data;
data.id_ = "lastfm/songtags";
data.title_ = tr("Last.fm tags");
data.type_ = CollapsibleInfoPane::Data::Type_Biography;
data.icon_ = QIcon(":/last.fm/icon_tag.png");

View File

@ -18,10 +18,13 @@
#include <QFile>
#include <QScrollArea>
#include <QSettings>
#include <QSpacerItem>
#include <QTimer>
#include <QVBoxLayout>
const char* SongInfoBase::kSettingsGroup = "SongInfo";
SongInfoBase::SongInfoBase(NetworkAccessManager* network, QWidget* parent)
: QWidget(parent),
network_(network),
@ -141,3 +144,42 @@ void SongInfoBase::ResultReady(int id, const SongInfoFetcher::Result& result) {
delete data.contents_;
}
}
void SongInfoBase::CollapseSections() {
QSettings s;
s.beginGroup(kSettingsGroup);
// Sections are already sorted by type and relevance, so the algorithm we use
// to determine which ones to show by default is:
// * In the absense of any user preference, show the first (highest
// relevance section of each type and hide the rest)
// * If one or more sections in a type have been explicitly hidden/shown
// by the user before then hide all sections in that type and show only
// the ones that are explicitly shown. If there are multiple sections in
// that type, but they are all hidden, then show the first one.
QMap<CollapsibleInfoPane::Data::Type, CollapsibleInfoPane*> types_;
QSet<CollapsibleInfoPane::Data::Type> has_user_preference_;
QSet<CollapsibleInfoPane::Data::Type> has_user_preference_on_;
foreach (CollapsibleInfoPane* pane, sections_) {
const CollapsibleInfoPane::Data::Type type = pane->data().type_;
types_.insertMulti(type, pane);
QVariant preference = s.value(pane->data().id_);
if (preference.isValid()) {
has_user_preference_.insert(type);
if (preference.toBool()) {
has_user_preference_on_.insert(type);
pane->Expand();
}
}
}
foreach (CollapsibleInfoPane::Data::Type type, types_.keys()) {
if (!has_user_preference_.contains(type) ||
(!has_user_preference_on_.contains(type) && types_.values(type).count() > 1)) {
// Expand the first one
types_.values(type).last()->Expand();
}
}
}

View File

@ -37,6 +37,8 @@ class SongInfoBase : public QWidget {
public:
SongInfoBase(NetworkAccessManager* network, QWidget* parent = 0);
static const char* kSettingsGroup;
public slots:
void SongChanged(const Song& metadata);
void SongFinished();
@ -51,6 +53,7 @@ protected:
void AddWidget(QWidget* widget);
void AddSection(CollapsibleInfoPane* section);
void Clear();
void CollapseSections();
protected slots:
virtual void ResultReady(int id, const SongInfoFetcher::Result& result);

View File

@ -78,6 +78,8 @@ void SongInfoView::ResultReady(int id, const SongInfoFetcher::Result& result) {
foreach (const CollapsibleInfoPane::Data& data, result.info_) {
AddSection(new CollapsibleInfoPane(data, this));
}
CollapseSections();
}
void SongInfoView::ReloadSettings() {

View File

@ -116,6 +116,7 @@ void UltimateLyricsProvider::LyricsFetched(quint64 id, QNetworkReply* reply) {
if (!lyrics.isEmpty()) {
CollapsibleInfoPane::Data data;
data.id_ = "ultimatelyrics/" + name_;
data.title_ = tr("Lyrics from %1").arg(name_);
data.type_ = CollapsibleInfoPane::Data::Type_Lyrics;