New context with albums and lyrics +++ much more

* Added new lyrics provider with lyrics from AudD and API Seeds
* New improved context widget with albums and lyrics
* Fixed playing and context widget getting stuck in play mode when there was an error
* Changed icons for artists in collection, tidal and cover manager
* Removed "search" icon from "Search automatically" checkbox (right click) that looked ugly
* Removed some unused widgets from the src/widgets directory
* Fixed initial size of window and side panel
* Fixed saving window size correctly
This commit is contained in:
Jonas Kvinge
2018-08-29 21:42:24 +02:00
parent 3b30e66e87
commit ac6cac8da1
96 changed files with 4361 additions and 3135 deletions

View File

@@ -34,17 +34,19 @@ const int AutoExpandingTreeView::kRowsToShow = 50;
AutoExpandingTreeView::AutoExpandingTreeView(QWidget *parent)
: QTreeView(parent),
auto_open_(true),
expand_on_reset_(true),
auto_open_(false),
expand_on_reset_(false),
add_on_double_click_(true),
ignore_next_click_(false)
{
setExpandsOnDoubleClick(false);
{
setExpandsOnDoubleClick(true);
setAnimated(true);
connect(this, SIGNAL(expanded(QModelIndex)), SLOT(ItemExpanded(QModelIndex)));
connect(this, SIGNAL(clicked(QModelIndex)), SLOT(ItemClicked(QModelIndex)));
connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(ItemDoubleClicked(QModelIndex)));
}
void AutoExpandingTreeView::reset() {
@@ -158,8 +160,7 @@ void AutoExpandingTreeView::keyPressEvent(QKeyEvent *e) {
case Qt::Key_Left:
// Set focus on the root of the current branch
if (index.isValid() && index.parent() != rootIndex() &&
(!isExpanded(index) || model()->rowCount(index) == 0)) {
if (index.isValid() && index.parent() != rootIndex() && (!isExpanded(index) || model()->rowCount(index) == 0)) {
setCurrentIndex(index.parent());
setFocus();
e->accept();

View File

@@ -1,184 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QObject>
#include <QWidget>
#include <QFlags>
#include <QFontMetrics>
#include <QString>
#include <QStringBuilder>
#include <QIcon>
#include <QPainter>
#include <QPalette>
#include <QColor>
#include <QRect>
#include <QSize>
#include <QToolButton>
#include <QtEvents>
#include "didyoumean.h"
const int DidYouMean::kPadding = 3;
DidYouMean::DidYouMean(QWidget *buddy, QWidget *parent)
: QWidget(parent, Qt::ToolTip),
buddy_(buddy),
close_(new QToolButton(this)),
normal_font_(font()),
correction_font_(font()),
press_enter_font_(font()) {
// Close icon
close_->setToolTip(tr("Close"));
close_->setIcon(QIcon(":/qt-project.org/styles/macstyle/images/closedock-16.png"));
close_->setIconSize(QSize(16, 16));
connect(close_, SIGNAL(clicked()), SLOT(hide()));
// Cursors
setCursor(Qt::PointingHandCursor);
close_->setCursor(Qt::ArrowCursor);
// Fonts
correction_font_.setBold(true);
press_enter_font_.setBold(true);
press_enter_font_.setPointSizeF(7.5);
hide();
buddy_->installEventFilter(this);
// Texts
did_you_mean_ = tr("Did you mean") + ": ";
press_enter_ = "(" + tr("press enter") + ")";
// Texts' sizes
did_you_mean_size_ = QFontMetrics(normal_font_).width(did_you_mean_);
press_enter_size_ = QFontMetrics(press_enter_font_).width(press_enter_);
}
bool DidYouMean::eventFilter(QObject *object, QEvent *event) {
if (object != buddy_) {
return QObject::eventFilter(object, event);
}
switch (event->type()) {
case QEvent::Move:
case QEvent::Resize:
if (isVisible()) {
UpdateGeometry();
}
break;
case QEvent::KeyPress:
if (!isVisible()) {
break;
}
switch (static_cast<QKeyEvent*>(event)->key()) {
case Qt::Key_Return:
case Qt::Key_Enter:
emit Accepted(correction_);
// fallthrough
case Qt::Key_Escape:
hide();
return true;
default:
break;
}
break;
case QEvent::FocusOut:
case QEvent::WindowDeactivate:
hide();
break;
default:
break;
}
return QObject::eventFilter(object, event);
}
void DidYouMean::showEvent(QShowEvent*) {
UpdateGeometry();
}
void DidYouMean::UpdateGeometry() {
const int text_height = fontMetrics().height();
const int height = text_height + kPadding * 2;
move(buddy_->mapToGlobal(buddy_->rect().bottomLeft()));
// Resize to len(text to display) + total number of padding added + size(close button), so the "Did you mean" widget is always fully displayed
resize(QSize(did_you_mean_size_ + QFontMetrics(correction_font_).width(correction_ + " ") + press_enter_size_ + kPadding * 6 + close_->width(), height));
close_->move(kPadding, kPadding);
close_->resize(text_height, text_height);
}
void DidYouMean::paintEvent(QPaintEvent*) {
QPainter p(this);
// Draw the background
QColor bg(palette().color(QPalette::Inactive, QPalette::ToolTipBase));
p.fillRect(0, 0, width()-1, height()-1, bg);
// Border
p.setPen(Qt::black);
p.drawRect(0, 0, width()-1, height()-1);
// Text rectangle
QRect text_rect(kPadding + close_->width() + kPadding, kPadding, rect().width() - kPadding, rect().height() - kPadding);
// Text
p.setFont(normal_font_);
p.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, did_you_mean_);
text_rect.setLeft(text_rect.left() + p.fontMetrics().width(did_you_mean_));
p.setFont(correction_font_);
p.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, correction_);
text_rect.setLeft(text_rect.left() + p.fontMetrics().width(correction_ + " "));
p.setPen(palette().color(QPalette::Disabled, QPalette::Text));
p.setFont(press_enter_font_);
p.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, press_enter_);
}
void DidYouMean::SetCorrection(const QString &correction) {
correction_ = correction;
UpdateGeometry();
update();
}
void DidYouMean::Show(const QString &correction) {
SetCorrection(correction);
show();
}
void DidYouMean::mouseReleaseEvent(QMouseEvent *e) {
emit Accepted(correction_);
hide();
}

View File

@@ -1,83 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef DIDYOUMEAN_H
#define DIDYOUMEAN_H
#include "config.h"
#include <stdbool.h>
#include <QObject>
#include <QWidget>
#include <QFont>
#include <QString>
#include <QToolButton>
#include <QtEvents>
class QEvent;
class QMouseEvent;
class QPaintEvent;
class QShowEvent;
class DidYouMean : public QWidget {
Q_OBJECT
public:
DidYouMean(QWidget *buddy, QWidget *parent);
static const int kPadding;
public slots:
void SetCorrection(const QString& correction);
void Show(const QString& correction);
signals:
void Accepted(const QString& correction);
protected:
void paintEvent(QPaintEvent*);
void showEvent(QShowEvent*);
void mouseReleaseEvent(QMouseEvent *e);
bool eventFilter(QObject *object, QEvent *event);
private:
void UpdateGeometry();
private:
QWidget *buddy_;
QString correction_;
QToolButton *close_;
QFont normal_font_;
QFont correction_font_;
QFont press_enter_font_;
QString did_you_mean_;
QString press_enter_;
// Size of the text to display, according to QFonts above.
// Stored here to avoid to recompute them each time
int did_you_mean_size_;
int press_enter_size_;
};
#endif // DIDYOUMEAN_H

View File

@@ -1,46 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QWidget>
#include <QString>
#include <QLabel>
#include <QFontMetrics>
#include <QtEvents>
#include "elidedlabel.h"
class QResizeEvent;
ElidedLabel::ElidedLabel(QWidget *parent) : QLabel(parent) {}
void ElidedLabel::SetText(const QString& text) {
text_ = text;
UpdateText();
}
void ElidedLabel::resizeEvent(QResizeEvent *) {
UpdateText();
}
void ElidedLabel::UpdateText() {
setText(fontMetrics().elidedText(text_, Qt::ElideRight, width() - 5));
}

View File

@@ -1,53 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ELIDEDLABEL_H
#define ELIDEDLABEL_H
#include "config.h"
#include <QObject>
#include <QWidget>
#include <QString>
#include <QLabel>
#include <QtEvents>
class QResizeEvent;
class ElidedLabel : public QLabel {
Q_OBJECT
public:
ElidedLabel(QWidget *parent = nullptr);
public slots:
void SetText(const QString &text);
protected:
void resizeEvent(QResizeEvent *e);
private:
void UpdateText();
private:
QString text_;
};
#endif // ELIDEDLABEL_H

View File

@@ -126,7 +126,8 @@ void FancyTabProxyStyle::drawControl(ControlElement element, const QStyleOption*
if (vertical_tabs) {
m = QTransform::fromTranslate(rect.left(), rect.bottom());
m.rotate(-90);
} else {
}
else {
m = QTransform::fromTranslate(rect.left(), rect.top());
}
@@ -314,8 +315,7 @@ QSize FancyTabBar::tabSizeHint(bool minimum) const {
return QSize(width, iconHeight + spacing + fm.height());
}
void FancyTabBar::paintEvent(QPaintEvent *event)
{
void FancyTabBar::paintEvent(QPaintEvent *event) {
Q_UNUSED(event)
QPainter p(this);
@@ -328,8 +328,7 @@ void FancyTabBar::paintEvent(QPaintEvent *event)
paintTab(&p, currentIndex());
}
bool FancyTab::event(QEvent* event)
{
bool FancyTab::event(QEvent* event) {
if (event->type() == QEvent::ToolTip) {
QFontMetrics metrics (font());
int text_width = metrics.width(text);
@@ -338,7 +337,8 @@ bool FancyTab::event(QEvent* event)
// The text is elided: show the tooltip
QHelpEvent* he = static_cast<QHelpEvent*>(event);
QToolTip::showText(he->globalPos(), text);
} else {
}
else {
QToolTip::hideText();
}
return true;
@@ -346,30 +346,25 @@ bool FancyTab::event(QEvent* event)
return QWidget::event(event);
}
void FancyTab::enterEvent(QEvent*)
{
void FancyTab::enterEvent(QEvent*) {
fadeIn();
}
void FancyTab::leaveEvent(QEvent*)
{
void FancyTab::leaveEvent(QEvent*) {
fadeOut();
}
QSize FancyTabBar::sizeHint() const
{
QSize FancyTabBar::sizeHint() const {
QSize sh = tabSizeHint();
return QSize(sh.width(), sh.height() * m_tabs.count());
}
QSize FancyTabBar::minimumSizeHint() const
{
QSize FancyTabBar::minimumSizeHint() const {
QSize sh = tabSizeHint(true);
return QSize(sh.width(), sh.height() * m_tabs.count());
}
QRect FancyTabBar::tabRect(int index) const
{
QRect FancyTabBar::tabRect(int index) const {
return m_tabs[index]->geometry();
}
@@ -382,13 +377,11 @@ void FancyTabBar::setTabToolTip(int index, const QString& toolTip) {
}
// This keeps the sidebar responsive since we get a repaint before loading the mode itself
void FancyTabBar::emitCurrentIndex()
{
void FancyTabBar::emitCurrentIndex() {
emit currentChanged(m_currentIndex);
}
void FancyTabBar::mousePressEvent(QMouseEvent *e)
{
void FancyTabBar::mousePressEvent(QMouseEvent *e) {
e->accept();
for (int index = 0; index < m_tabs.count(); ++index) {
if (tabRect(index).contains(e->pos())) {
@@ -415,8 +408,7 @@ void FancyTabBar::addSpacer(int size) {
new QSpacerItem(0, size, QSizePolicy::Fixed, QSizePolicy::Maximum));
}
void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
{
void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const {
if (!validIndex(tabIndex)) {
qWarning("invalid index");
return;
@@ -427,7 +419,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
bool selected = (tabIndex == m_currentIndex);
if (selected) {
//background
//background
painter->save();
QLinearGradient grad(rect.topLeft(), rect.topRight());
grad.setColorAt(0, QColor(255, 255, 255, 140));
@@ -435,21 +427,21 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const
painter->fillRect(rect.adjusted(0, 0, 0, -1), grad);
painter->restore();
//shadows
//shadows
painter->setPen(QColor(0, 0, 0, 110));
painter->drawLine(rect.topLeft() + QPoint(1,-1), rect.topRight() - QPoint(0,1));
painter->drawLine(rect.topLeft() + QPoint(1,-1), rect.topRight() - QPoint(0,1));
painter->drawLine(rect.bottomLeft(), rect.bottomRight());
painter->setPen(QColor(0, 0, 0, 40));
painter->drawLine(rect.topLeft(), rect.bottomLeft());
//highlights
//highlights
painter->setPen(QColor(255, 255, 255, 50));
painter->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0,2));
painter->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0,1));
painter->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0,2));
painter->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0,1));
painter->setPen(QColor(255, 255, 255, 40));
painter->drawLine(rect.topLeft() + QPoint(0, 0), rect.topRight());
painter->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1));
painter->drawLine(rect.bottomLeft() + QPoint(0,-1), rect.bottomRight()-QPoint(0,1));
painter->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1));
painter->drawLine(rect.bottomLeft() + QPoint(0,-1), rect.bottomRight()-QPoint(0,1));
}
QString tabText(painter->fontMetrics().elidedText(this->tabText(tabIndex), Qt::ElideRight, width()));
@@ -567,6 +559,7 @@ void FancyTabWidget::SetBackgroundPixmap(const QPixmap& pixmap) {
}
void FancyTabWidget::paintEvent(QPaintEvent*) {
if (!use_background_) return;
QPainter painter(this);
@@ -602,9 +595,11 @@ int FancyTabWidget::currentIndex() const {
void FancyTabWidget::setCurrentIndex(int index) {
if (FancyTabBar* bar = qobject_cast<FancyTabBar*>(tab_bar_)) {
bar->setCurrentIndex(index);
} else if (QTabBar* bar = qobject_cast<QTabBar*>(tab_bar_)) {
}
else if (QTabBar* bar = qobject_cast<QTabBar*>(tab_bar_)) {
bar->setCurrentIndex(index);
} else {
}
else {
stack_->setCurrentIndex(index);
}
}
@@ -709,8 +704,7 @@ void FancyTabWidget::AddMenuItem(QSignalMapper* mapper, QActionGroup* group, con
if (mode == mode_) action->setChecked(true);
}
void FancyTabWidget::MakeTabBar(QTabBar::Shape shape, bool text, bool icons,
bool fancy) {
void FancyTabWidget::MakeTabBar(QTabBar::Shape shape, bool text, bool icons, bool fancy) {
QTabBar* bar = new QTabBar(this);
bar->setShape(shape);
bar->setDocumentMode(true);

View File

@@ -49,6 +49,8 @@
#include "covermanager/currentartloader.h"
#include "playingwidget.h"
using std::unique_ptr;
const char *PlayingWidget::kSettingsGroup = "PlayingWidget";
// Space between the cover and the details in small mode
@@ -58,20 +60,18 @@ const int PlayingWidget::kPadding = 2;
const int PlayingWidget::kGradientHead = 40;
const int PlayingWidget::kGradientTail = 20;
// Maximum height of the cover in large mode, and offset between the
// bottom of the cover and bottom of the widget
// Maximum height of the cover in large mode, and offset between the bottom of the cover and bottom of the widget
const int PlayingWidget::kMaxCoverSize = 260;
const int PlayingWidget::kBottomOffset = 0;
// Border for large mode
const int PlayingWidget::kTopBorder = 4;
PlayingWidget::PlayingWidget(QWidget *parent)
: QWidget(parent),
app_(nullptr),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
mode_(SmallSongDetails),
mode_(LargeSongDetails),
menu_(new QMenu(this)),
fit_cover_width_action_(nullptr),
enabled_(false),
@@ -79,12 +79,14 @@ PlayingWidget::PlayingWidget(QWidget *parent)
active_(false),
small_ideal_height_(0),
fit_width_(false),
show_hide_animation_(new QTimeLine(500, this)),
fade_animation_(new QTimeLine(1000, this)),
timeline_show_hide_(new QTimeLine(500, this)),
timeline_fade_(new QTimeLine(1000, this)),
details_(new QTextDocument(this)),
previous_track_opacity_(0.0),
pixmap_previous_track_opacity_(0.0),
downloading_covers_(false) {
SetHeight(0);
// Load settings
QSettings s;
s.beginGroup(kSettingsGroup);
@@ -129,26 +131,20 @@ PlayingWidget::PlayingWidget(QWidget *parent)
menu_->addSeparator();
// Animations
connect(show_hide_animation_, SIGNAL(frameChanged(int)), SLOT(SetHeight(int)));
setMaximumHeight(0);
connect(fade_animation_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousTrack(qreal)));
fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
connect(timeline_show_hide_, SIGNAL(frameChanged(int)), SLOT(SetHeight(int)));
connect(timeline_fade_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousTrack(qreal)));
timeline_fade_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
// add placeholder text to get the correct height
if (mode_ == LargeSongDetails) {
details_->setDefaultStyleSheet(
"p {"
" font-size: small;"
" color: black;"
"}");
details_->setDefaultStyleSheet("p { font-size: small; font-weight: bold; }");
details_->setHtml(QString("<p align=center><i></i><br/><br/></p>"));
}
UpdateHeight();
connect(album_cover_choice_controller_, SIGNAL(AutomaticCoverSearchDone()), this, SLOT(AutomaticCoverSearchDone()));
}
PlayingWidget::~PlayingWidget() {
@@ -163,14 +159,34 @@ void PlayingWidget::SetApplication(Application *app) {
}
void PlayingWidget::CreateModeAction(Mode mode, const QString &text, QActionGroup *group, QSignalMapper* mapper) {
QAction* action = new QAction(text, group);
action->setCheckable(true);
mapper->setMapping(action, mode);
connect(action, SIGNAL(triggered()), mapper, SLOT(map()));
void PlayingWidget::SetEnabled() {
enabled_ = true;
if (!visible_ && active_) SetVisible(true);
}
if (mode == mode_) action->setChecked(true);
void PlayingWidget::SetDisabled() {
enabled_ = false;
if (visible_) SetVisible(false);
}
void PlayingWidget::SetVisible(bool visible) {
if (timeline_show_hide_->state() == QTimeLine::Running) {
if (timeline_show_hide_->direction() == QTimeLine::Backward && enabled_ && active_) {
timeline_show_hide_->toggleDirection();
}
if (timeline_show_hide_->direction() == QTimeLine::Forward && (!enabled_ || !active_)) {
timeline_show_hide_->toggleDirection();
}
return;
}
if (visible == visible_) return;
timeline_show_hide_->setFrameRange(0, total_height_);
timeline_show_hide_->setDirection(visible ? QTimeLine::Forward : QTimeLine::Backward);
timeline_show_hide_->start();
}
@@ -182,218 +198,22 @@ void PlayingWidget::set_ideal_height(int height) {
}
QSize PlayingWidget::sizeHint() const {
return QSize(cover_loader_options_.desired_height_, total_height_);
}
void PlayingWidget::UpdateHeight() {
void PlayingWidget::CreateModeAction(Mode mode, const QString &text, QActionGroup *group, QSignalMapper *mapper) {
switch (mode_) {
case SmallSongDetails:
cover_loader_options_.desired_height_ = small_ideal_height_;
total_height_ = small_ideal_height_;
break;
case LargeSongDetails:
if (fit_width_) cover_loader_options_.desired_height_ = width();
else cover_loader_options_.desired_height_ = qMin(kMaxCoverSize, width());
total_height_ = kTopBorder + cover_loader_options_.desired_height_ + kBottomOffset + details_->size().height();
break;
}
QAction *action = new QAction(text, group);
action->setCheckable(true);
mapper->setMapping(action, mode);
connect(action, SIGNAL(triggered()), mapper, SLOT(map()));
// Update the animation settings and resize the widget now if we're visible
show_hide_animation_->setFrameRange(0, total_height_);
if (visible_ && show_hide_animation_->state() != QTimeLine::Running) setMaximumHeight(total_height_);
if (mode == mode_) action->setChecked(true);
// Re-scale the current image
if (metadata_.is_valid()) {
ScaleCover();
}
// Tell Qt we've changed size
updateGeometry();
}
void PlayingWidget::Stopped() {
active_ = false;
SetVisible(false);
}
void PlayingWidget::UpdateDetailsText() {
QString html;
switch (mode_) {
case SmallSongDetails:
details_->setTextWidth(-1);
details_->setDefaultStyleSheet("");
html += "<p>";
break;
case LargeSongDetails:
details_->setTextWidth(cover_loader_options_.desired_height_);
if (fit_width_) {
details_->setDefaultStyleSheet(
"p {"
" font-size: small;"
"}");
}
else {
details_->setDefaultStyleSheet(
"p {"
" font-size: small;"
" color: black;"
"}");
}
html += "<p align=center>";
break;
}
// TODO: Make this configurable
html += QString("<i>%1</i><br/>%2<br/>%3").arg(metadata_.PrettyTitle().toHtmlEscaped(), metadata_.artist().toHtmlEscaped(), metadata_.album().toHtmlEscaped());
html += "</p>";
details_->setHtml(html);
// if something spans multiple lines the height needs to change
if (mode_ == LargeSongDetails) UpdateHeight();
}
void PlayingWidget::ScaleCover() {
cover_ = QPixmap::fromImage(AlbumCoverLoader::ScaleAndPad(cover_loader_options_, original_));
update();
}
void PlayingWidget::AlbumArtLoaded(const Song &metadata, const QString &, const QImage &image) {
active_ = true;
metadata_ = metadata;
downloading_covers_ = false;
SetImage(image);
// Search for cover automatically?
GetCoverAutomatically();
}
void PlayingWidget::SetImage(const QImage &image) {
active_ = true;
if (visible_) {
// Cache the current pixmap so we can fade between them
previous_track_ = QPixmap(size());
previous_track_.fill(palette().background().color());
previous_track_opacity_ = 1.0;
QPainter p(&previous_track_);
DrawContents(&p);
p.end();
}
original_ = image;
UpdateDetailsText();
ScaleCover();
if (enabled_ == true) SetVisible(true);
// Were we waiting for this cover to load before we started fading?
if (!previous_track_.isNull()) {
fade_animation_->start();
}
}
void PlayingWidget::SetHeight(int height) {
setMaximumHeight(height);
}
void PlayingWidget::SetVisible(bool visible) {
if (visible == visible_) return;
visible_ = visible;
show_hide_animation_->setDirection(visible ? QTimeLine::Forward : QTimeLine::Backward);
show_hide_animation_->start();
}
void PlayingWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
DrawContents(&p);
// Draw the previous track's image if we're fading
if (!previous_track_.isNull()) {
p.setOpacity(previous_track_opacity_);
p.drawPixmap(0, 0, previous_track_);
}
}
void PlayingWidget::DrawContents(QPainter *p) {
switch (mode_) {
case SmallSongDetails:
// Draw the cover
p->drawPixmap(0, 0, small_ideal_height_, small_ideal_height_, cover_);
if (downloading_covers_) {
p->drawPixmap(small_ideal_height_ - 18, 6, 16, 16, spinner_animation_->currentPixmap());
}
// Draw the details
p->translate(small_ideal_height_ + kPadding, 0);
details_->drawContents(p);
p->translate(-small_ideal_height_ - kPadding, 0);
break;
case LargeSongDetails:
// Work out how high the text is going to be
const int text_height = details_->size().height();
const int cover_size = fit_width_ ? width() : qMin(kMaxCoverSize, width());
const int x_offset = (width() - cover_loader_options_.desired_height_) / 2;
if (!fit_width_) {
// Draw the black background
//p->fillRect(QRect(0, kTopBorder, width(), height() - kTopBorder), Qt::black);
}
// Draw the cover
p->drawPixmap(x_offset, kTopBorder, cover_size, cover_size, cover_);
if (downloading_covers_) {
p->drawPixmap(x_offset + 45, 35, 16, 16, spinner_animation_->currentPixmap());
}
// Draw the text below
p->translate(x_offset, height() - text_height);
details_->drawContents(p);
p->translate(-x_offset, -height() + text_height);
break;
}
}
void PlayingWidget::FadePreviousTrack(qreal value) {
previous_track_opacity_ = value;
if (qFuzzyCompare(previous_track_opacity_, qreal(0.0))) {
previous_track_ = QPixmap();
}
update();
}
void PlayingWidget::SetMode(int mode) {
mode_ = Mode(mode);
if (mode_ == SmallSongDetails) {
@@ -413,9 +233,222 @@ void PlayingWidget::SetMode(int mode) {
}
void PlayingWidget::FitCoverWidth(bool fit) {
fit_width_ = fit;
UpdateHeight();
update();
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("fit_cover_width", fit_width_);
}
void PlayingWidget::Playing() {
}
void PlayingWidget::Stopped() {
active_ = false;
SetVisible(false);
}
void PlayingWidget::Error() {
active_ = false;
}
void PlayingWidget::SongChanged(const Song &song) {
song_ = song;
}
void PlayingWidget::AlbumArtLoaded(const Song &song, const QString &, const QImage &image) {
if (song == song_) {}
else {
qLog(Error) << __PRETTY_FUNCTION__ << "Ignoring" << song.title() << "because current song is" << song_.title();
return;
}
active_ = true;
downloading_covers_ = false;
SetImage(image);
GetCoverAutomatically();
}
void PlayingWidget::SetImage(const QImage &image) {
if (enabled_ && visible_ && active_) {
// Cache the current pixmap so we can fade between them
QSize psize(size());
if (size().height() <= 0) psize.setHeight(total_height_);
pixmap_previous_track_ = QPixmap(psize);
pixmap_previous_track_.fill(palette().background().color());
pixmap_previous_track_opacity_ = 1.0;
QPainter p(&pixmap_previous_track_);
DrawContents(&p);
p.end();
}
else { pixmap_previous_track_ = QPixmap(); }
image_original_ = image;
UpdateDetailsText();
ScaleCover();
if (enabled_ && active_) {
SetVisible(true);
// Were we waiting for this cover to load before we started fading?
if (!pixmap_previous_track_.isNull()) {
timeline_fade_->stop();
timeline_fade_->start();
}
}
}
void PlayingWidget::ScaleCover() {
pixmap_cover_ = QPixmap::fromImage(AlbumCoverLoader::ScaleAndPad(cover_loader_options_, image_original_));
update();
}
void PlayingWidget::SetHeight(int height) {
setMaximumHeight(height);
update();
if (height >= total_height_) visible_ = true;
if (height <= 0) visible_ = false;
if (timeline_show_hide_->state() == QTimeLine::Running) {
if (timeline_show_hide_->direction() == QTimeLine::Backward && enabled_ && active_) {
timeline_show_hide_->toggleDirection();
}
if (timeline_show_hide_->direction() == QTimeLine::Forward && (!enabled_ || !active_)) {
timeline_show_hide_->toggleDirection();
}
}
}
void PlayingWidget::UpdateHeight() {
switch (mode_) {
case SmallSongDetails:
cover_loader_options_.desired_height_ = small_ideal_height_;
total_height_ = small_ideal_height_;
break;
case LargeSongDetails:
if (fit_width_) cover_loader_options_.desired_height_ = width();
else cover_loader_options_.desired_height_ = qMin(kMaxCoverSize, width());
total_height_ = kTopBorder + cover_loader_options_.desired_height_ + kBottomOffset + details_->size().height();
break;
}
// Update the animation settings and resize the widget now if we're visible
timeline_show_hide_->setFrameRange(0, total_height_);
if (visible_ && active_ && timeline_show_hide_->state() != QTimeLine::Running) setMaximumHeight(total_height_);
// Re-scale the current image
if (song_.is_valid()) {
ScaleCover();
}
// Tell Qt we've changed size
updateGeometry();
}
void PlayingWidget::UpdateDetailsText() {
QString html("");
details_->setDefaultStyleSheet("p { font-size: small; font-weight: bold; }");
switch (mode_) {
case SmallSongDetails:
details_->setTextWidth(-1);
html += "<p>";
break;
case LargeSongDetails:
details_->setTextWidth(cover_loader_options_.desired_height_);
html += "<p align=center>";
break;
}
html += QString("%1<br/>%2<br/>%3").arg(song_.PrettyTitle().toHtmlEscaped(), song_.artist().toHtmlEscaped(), song_.album().toHtmlEscaped());
html += "</p>";
details_->setHtml(html);
// if something spans multiple lines the height needs to change
if (mode_ == LargeSongDetails) UpdateHeight();
}
void PlayingWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
DrawContents(&p);
// Draw the previous track's image if we're fading
if (!pixmap_previous_track_.isNull()) {
p.setOpacity(pixmap_previous_track_opacity_);
p.drawPixmap(0, 0, pixmap_previous_track_);
}
}
void PlayingWidget::DrawContents(QPainter *p) {
switch (mode_) {
case SmallSongDetails:
// Draw the cover
p->drawPixmap(0, 0, small_ideal_height_, small_ideal_height_, pixmap_cover_);
if (downloading_covers_) {
p->drawPixmap(small_ideal_height_ - 18, 6, 16, 16, spinner_animation_->currentPixmap());
}
// Draw the details
p->translate(small_ideal_height_ + kPadding, 0);
details_->drawContents(p);
p->translate(-small_ideal_height_ - kPadding, 0);
break;
case LargeSongDetails:
// Work out how high the text is going to be
const int text_height = details_->size().height();
const int cover_size = fit_width_ ? width() : qMin(kMaxCoverSize, width());
const int x_offset = (width() - cover_loader_options_.desired_height_) / 2;
// Draw the cover
p->drawPixmap(x_offset, kTopBorder, cover_size, cover_size, pixmap_cover_);
if (downloading_covers_) {
p->drawPixmap(x_offset + 45, 35, 16, 16, spinner_animation_->currentPixmap());
}
// Draw the text below
p->translate(x_offset, height() - text_height);
details_->drawContents(p);
p->translate(-x_offset, -height() + text_height);
break;
}
}
void PlayingWidget::FadePreviousTrack(qreal value) {
if (!visible_) return;
pixmap_previous_track_opacity_ = value;
if (qFuzzyCompare(pixmap_previous_track_opacity_, qreal(0.0))) {
pixmap_previous_track_ = QPixmap();
}
update();
}
void PlayingWidget::resizeEvent(QResizeEvent* e) {
if (visible_ && e->oldSize() != e->size()) {
//if (visible_ && e->oldSize() != e->size()) {
if (e->oldSize() != e->size()) {
if (mode_ == LargeSongDetails) {
UpdateHeight();
UpdateDetailsText();
@@ -435,51 +468,6 @@ void PlayingWidget::mouseReleaseEvent(QMouseEvent*) {
}
void PlayingWidget::FitCoverWidth(bool fit) {
fit_width_ = fit;
UpdateHeight();
update();
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("fit_cover_width", fit_width_);
}
void PlayingWidget::LoadCoverFromFile() {
album_cover_choice_controller_->LoadCoverFromFile(&metadata_);
}
void PlayingWidget::LoadCoverFromURL() {
album_cover_choice_controller_->LoadCoverFromURL(&metadata_);
}
void PlayingWidget::SearchForCover() {
album_cover_choice_controller_->SearchForCover(&metadata_);
}
void PlayingWidget::SaveCoverToFile() {
album_cover_choice_controller_->SaveCoverToFile(metadata_, original_);
}
void PlayingWidget::UnsetCover() {
album_cover_choice_controller_->UnsetCover(&metadata_);
}
void PlayingWidget::ShowCover() {
album_cover_choice_controller_->ShowCover(metadata_);
}
void PlayingWidget::SearchCoverAutomatically() {
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked());
GetCoverAutomatically();
}
void PlayingWidget::dragEnterEvent(QDragEnterEvent *e) {
if (AlbumCoverChoiceController::CanAcceptDrag(e)) {
@@ -492,7 +480,7 @@ void PlayingWidget::dragEnterEvent(QDragEnterEvent *e) {
void PlayingWidget::dropEvent(QDropEvent *e) {
album_cover_choice_controller_->SaveCover(&metadata_, e);
album_cover_choice_controller_->SaveCover(&song_, e);
QWidget::dropEvent(e);
@@ -503,14 +491,13 @@ bool PlayingWidget::GetCoverAutomatically() {
// Search for cover automatically?
bool search =
album_cover_choice_controller_->search_cover_auto_action()->isChecked() &&
!metadata_.has_manually_unset_cover() &&
metadata_.art_automatic().isEmpty() && metadata_.art_manual().isEmpty() &&
!metadata_.artist().isEmpty() && !metadata_.album().isEmpty();
!song_.has_manually_unset_cover() &&
song_.art_automatic().isEmpty() && song_.art_manual().isEmpty() &&
!song_.artist().isEmpty() && !song_.album().isEmpty();
if (search) {
//qLog(Debug) << "GetCoverAutomatically";
downloading_covers_ = true;
album_cover_choice_controller_->SearchCoverAutomatically(metadata_);
album_cover_choice_controller_->SearchCoverAutomatically(song_);
// Show a spinner animation
spinner_animation_.reset(new QMovie(":/pictures/spinner.gif", QByteArray(), this));
@@ -531,22 +518,38 @@ void PlayingWidget::AutomaticCoverSearchDone() {
}
void PlayingWidget::SetEnabled() {
void PlayingWidget::SearchCoverAutomatically() {
if (enabled_ == true) return;
if ((active_ == true) && (visible_ == false)) SetVisible(true);
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked());
s.endGroup();
enabled_ = true;
GetCoverAutomatically();
}
void PlayingWidget::SetDisabled() {
if (enabled_ == false) return;
if (visible_ == true) SetVisible(false);
enabled_ = false;
void PlayingWidget::LoadCoverFromFile() {
album_cover_choice_controller_->LoadCoverFromFile(&song_);
}
void PlayingWidget::LoadCoverFromURL() {
album_cover_choice_controller_->LoadCoverFromURL(&song_);
}
void PlayingWidget::SearchForCover() {
album_cover_choice_controller_->SearchForCover(&song_);
}
void PlayingWidget::SaveCoverToFile() {
album_cover_choice_controller_->SaveCoverToFile(song_, image_original_);
}
void PlayingWidget::UnsetCover() {
album_cover_choice_controller_->UnsetCover(&song_);
}
void PlayingWidget::ShowCover() {
album_cover_choice_controller_->ShowCover(song_);
}

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,6 +33,7 @@
#include <QString>
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QSize>
#include <QSignalMapper>
#include <QTextDocument>
@@ -45,12 +47,13 @@
#include "core/song.h"
#include "covermanager/albumcoverloaderoptions.h"
using std::unique_ptr;
class QContextMenuEvent;
class QDragEnterEvent;
class QDropEvent;
class QMouseEvent;
class QPaintEvent;
class QPainter;
class QResizeEvent;
class AlbumCoverChoiceController;
@@ -63,35 +66,22 @@ class PlayingWidget : public QWidget {
PlayingWidget(QWidget *parent = nullptr);
~PlayingWidget();
static const char *kSettingsGroup;
static const int kPadding;
static const int kGradientHead;
static const int kGradientTail;
static const int kMaxCoverSize;
static const int kBottomOffset;
static const int kTopBorder;
// Values are saved in QSettings
enum Mode {
SmallSongDetails = 0,
LargeSongDetails = 1,
};
void SetApplication(Application *app);
void SetEnabled();
void SetDisabled();
void set_ideal_height(int height);
QSize sizeHint() const;
signals:
signals:
void ShowAboveStatusBarChanged(bool above);
public slots:
public slots:
void Playing();
void Stopped();
void Error();
void SongChanged(const Song &song);
protected:
protected:
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent*);
void contextMenuEvent(QContextMenuEvent *e);
@@ -99,17 +89,11 @@ protected:
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
private slots:
private slots:
void SetMode(int mode);
void FitCoverWidth(bool fit);
void AlbumArtLoaded(const Song &metadata, const QString &uri, const QImage &image);
void SetVisible(bool visible);
void SetHeight(int height);
void FadePreviousTrack(qreal value);
void LoadCoverFromFile();
void SaveCoverToFile();
void LoadCoverFromURL();
@@ -119,49 +103,58 @@ private slots:
void SearchCoverAutomatically();
void AutomaticCoverSearchDone();
private:
void CreateModeAction(Mode mode, const QString &text, QActionGroup *group, QSignalMapper *mapper);
void UpdateDetailsText();
void UpdateHeight();
void DrawContents(QPainter *p);
void SetImage(const QImage &image);
void ScaleCover();
bool GetCoverAutomatically();
void AlbumArtLoaded(const Song &song, const QString &uri, const QImage &image);
void SetHeight(int height);
void FadePreviousTrack(qreal value);
private:
enum Mode {
SmallSongDetails = 0,
LargeSongDetails = 1,
};
static const char *kSettingsGroup;
static const int kPadding;
static const int kGradientHead;
static const int kGradientTail;
static const int kMaxCoverSize;
static const int kBottomOffset;
static const int kTopBorder;
private:
Application *app_;
AlbumCoverChoiceController *album_cover_choice_controller_;
Mode mode_;
QMenu *menu_;
QAction *fit_cover_width_action_;
bool enabled_;
bool visible_;
bool active_;
int small_ideal_height_;
AlbumCoverLoaderOptions cover_loader_options_;
int total_height_;
bool fit_width_;
QTimeLine *show_hide_animation_;
QTimeLine *fade_animation_;
// Information about the current track
Song metadata_;
QPixmap cover_;
// A copy of the original, unscaled album cover.
QImage original_;
QTimeLine *timeline_show_hide_;
QTimeLine *timeline_fade_;
QTextDocument *details_;
// Holds the last track while we're fading to the new track
QPixmap previous_track_;
qreal previous_track_opacity_;
std::unique_ptr<QMovie> spinner_animation_;
qreal pixmap_previous_track_opacity_;
bool downloading_covers_;
Song song_;
QImage image_original_;
QPixmap pixmap_cover_;
QPixmap pixmap_previous_track_;
std::unique_ptr<QMovie> spinner_animation_;
void SetVisible(bool visible);
void CreateModeAction(Mode mode, const QString &text, QActionGroup *group, QSignalMapper *mapper);
void UpdateDetailsText();
void UpdateHeight();
void SetImage(const QImage &image);
void DrawContents(QPainter *p);
void ScaleCover();
bool GetCoverAutomatically();
};
#endif // PLAYINGWIDGET_H

View File

@@ -1,268 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdbool.h>
#include <QtGlobal>
#include <QWidget>
#include <QApplication>
#include <QtConcurrentRun>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QVariant>
#include <QString>
#include <QStringBuilder>
#include <QUrl>
#include <QImage>
#include <QPixmap>
#include <QFrame>
#include <QFuture>
#include <QPainter>
#include <QPalette>
#include <QColor>
#include <QBrush>
#include <QPoint>
#include <QRect>
#include <QLabel>
#include <QMenu>
#include <QScrollArea>
#include <QSizePolicy>
#include <QTransform>
#include <QDesktopWidget>
#include <QLinearGradient>
#include <QSettings>
#include <QFlags>
#include <QtDebug>
#include <QtEvents>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include "core/closure.h"
#include "core/iconloader.h"
#include "core/logging.h"
#include "core/network.h"
#include "prettyimage.h"
const int PrettyImage::kTotalHeight = 200;
const int PrettyImage::kReflectionHeight = 40;
const int PrettyImage::kImageHeight = PrettyImage::kTotalHeight - PrettyImage::kReflectionHeight;
const int PrettyImage::kMaxImageWidth = 300;
const char *PrettyImage::kSettingsGroup = "PrettyImageView";
PrettyImage::PrettyImage(const QUrl &url, QNetworkAccessManager* network, QWidget* parent)
: QWidget(parent),
network_(network),
state_(State_WaitingForLazyLoad),
url_(url),
menu_(nullptr) {
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
LazyLoad();
}
void PrettyImage::LazyLoad() {
if (state_ != State_WaitingForLazyLoad) return;
// Start fetching the image
QNetworkReply* reply = network_->get(QNetworkRequest(url_));
RedirectFollower* follower = new RedirectFollower(reply);
state_ = State_Fetching;
NewClosure(follower, SIGNAL(finished()), this, SLOT(ImageFetched(RedirectFollower*)), follower);
}
QSize PrettyImage::image_size() const {
if (state_ != State_Finished) return QSize(kImageHeight * 1.6, kImageHeight);
QSize ret = image_.size();
ret.scale(kMaxImageWidth, kImageHeight, Qt::KeepAspectRatio);
return ret;
}
QSize PrettyImage::sizeHint() const {
return QSize(image_size().width(), kTotalHeight);
}
void PrettyImage::ImageFetched(RedirectFollower* follower) {
follower->deleteLater();
QNetworkReply* reply = follower->reply();
reply->deleteLater();
QImage image = QImage::fromData(reply->readAll());
if (image.isNull()) {
qLog(Debug) << "Image failed to load" << reply->request().url() << reply->error();
deleteLater();
}
else {
state_ = State_CreatingThumbnail;
image_ = image;
QFuture<QImage> future = QtConcurrent::run(image_, &QImage::scaled, image_size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
NewClosure(future, this, SLOT(ImageScaled(QFuture<QImage>)), future);
}
}
void PrettyImage::ImageScaled(QFuture<QImage> future) {
thumbnail_ = QPixmap::fromImage(future.result());
state_ = State_Finished;
updateGeometry();
update();
emit Loaded();
}
void PrettyImage::paintEvent(QPaintEvent* ) {
// Draw at the bottom of our area
QRect image_rect(QPoint(0, 0), image_size());
image_rect.moveBottom(kImageHeight);
QPainter p(this);
// Draw the main image
DrawThumbnail(&p, image_rect);
// Draw the reflection
// Figure out where to draw it
QRect reflection_rect(image_rect);
reflection_rect.moveTop(image_rect.bottom());
// Create the reflected pixmap
QImage reflection(reflection_rect.size(), QImage::Format_ARGB32_Premultiplied);
reflection.fill(palette().color(QPalette::Base).rgba());
QPainter reflection_painter(&reflection);
// Set up the transformation
QTransform transform;
transform.scale(1.0, -1.0);
transform.translate(0.0, -reflection_rect.height());
reflection_painter.setTransform(transform);
QRect fade_rect(reflection.rect().bottomLeft() - QPoint(0, kReflectionHeight), reflection.rect().bottomRight());
// Draw the reflection into the buffer
DrawThumbnail(&reflection_painter, reflection.rect());
// Make it fade out towards the bottom
QLinearGradient fade_gradient(fade_rect.topLeft(), fade_rect.bottomLeft());
fade_gradient.setColorAt(0.0, QColor(0, 0, 0, 0));
fade_gradient.setColorAt(1.0, QColor(0, 0, 0, 128));
reflection_painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
reflection_painter.fillRect(fade_rect, fade_gradient);
reflection_painter.end();
// Draw the reflection on the image
p.drawImage(reflection_rect, reflection);
}
void PrettyImage::DrawThumbnail(QPainter* p, const QRect& rect) {
switch (state_) {
case State_WaitingForLazyLoad:
case State_Fetching:
case State_CreatingThumbnail:
p->setPen(palette().color(QPalette::Disabled, QPalette::Text));
p->drawText(rect, Qt::AlignHCenter | Qt::AlignBottom, tr("Loading..."));
break;
case State_Finished:
p->drawPixmap(rect, thumbnail_);
break;
}
}
void PrettyImage::contextMenuEvent(QContextMenuEvent* e) {
if (e->pos().y() >= kImageHeight) return;
if (!menu_) {
menu_ = new QMenu(this);
menu_->addAction(IconLoader::Load("zoom-in"), tr("Show fullsize..."), this, SLOT(ShowFullsize()));
menu_->addAction(IconLoader::Load("document-save"), tr("Save image") + "...", this, SLOT(SaveAs()));
}
menu_->popup(e->globalPos());
}
void PrettyImage::ShowFullsize() {
// Work out how large to make the window, based on the size of the screen
QRect desktop_rect(QApplication::desktop()->availableGeometry(this));
QSize window_size(qMin(desktop_rect.width() - 20, image_.width()), qMin(desktop_rect.height() - 20, image_.height()));
// Create the window
QScrollArea* window = new QScrollArea;
window->setAttribute(Qt::WA_DeleteOnClose, true);
window->setWindowTitle(tr("Strawberry image viewer"));
window->resize(window_size);
// Create the label that displays the image
QLabel* label = new QLabel(window);
label->setPixmap(QPixmap::fromImage(image_));
// Show the label in the window
window->setWidget(label);
window->setFrameShape(QFrame::NoFrame);
window->show();
}
void PrettyImage::SaveAs() {
QString filename = QFileInfo(url_.path()).fileName();
if (filename.isEmpty()) filename = "artwork.jpg";
QSettings s;
s.beginGroup(kSettingsGroup);
QString last_save_dir = s.value("last_save_dir", QDir::homePath()).toString();
QString path = last_save_dir.isEmpty() ? QDir::homePath() : last_save_dir;
QFileInfo path_info(path);
if (path_info.isDir()) {
path += "/" + filename;
}
else {
path = path_info.path() + "/" + filename;
}
filename = QFileDialog::getSaveFileName(this, tr("Save image"), path);
if (filename.isEmpty()) return;
image_.save(filename);
s.setValue("last_save_dir", last_save_dir);
}

View File

@@ -1,101 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRETTYIMAGE_H
#define PRETTYIMAGE_H
#include "config.h"
#include <QObject>
#include <QWidget>
#include <QFuture>
#include <QString>
#include <QUrl>
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QRect>
#include <QSize>
#include <QMenu>
#include <QNetworkAccessManager>
#include <QtEvents>
class QContextMenuEvent;
class QPaintEvent;
class RedirectFollower;
class PrettyImage : public QWidget {
Q_OBJECT
public:
PrettyImage(const QUrl &url, QNetworkAccessManager *network, QWidget *parent = nullptr);
static const int kTotalHeight;
static const int kReflectionHeight;
static const int kImageHeight;
static const int kMaxImageWidth;
static const char *kSettingsGroup;
QSize sizeHint() const;
QSize image_size() const;
signals:
void Loaded();
public slots:
void LazyLoad();
void SaveAs();
void ShowFullsize();
protected:
void contextMenuEvent(QContextMenuEvent*);
void paintEvent(QPaintEvent*);
private slots:
void ImageFetched(RedirectFollower *reply);
void ImageScaled(QFuture<QImage> future);
private:
enum State {
State_WaitingForLazyLoad,
State_Fetching,
State_CreatingThumbnail,
State_Finished,
};
void DrawThumbnail(QPainter *p, const QRect &rect);
private:
QNetworkAccessManager *network_;
State state_;
QUrl url_;
QImage image_;
QPixmap thumbnail_;
QMenu *menu_;
QString last_save_dir_;
};
#endif // PRETTYIMAGE_H

View File

@@ -1,191 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QUrl>
#include <QFrame>
#include <QPoint>
#include <QRect>
#include <QAbstractSlider>
#include <QEasingCurve>
#include <QLayout>
#include <QLayoutItem>
#include <QBoxLayout>
#include <QScrollBar>
#include <QSizePolicy>
#include <QPropertyAnimation>
#include <QScrollArea>
#include <QNetworkAccessManager>
#include <QtEvents>
#include "prettyimage.h"
#include "prettyimageview.h"
PrettyImageView::PrettyImageView(QNetworkAccessManager* network, QWidget* parent)
: QScrollArea(parent),
network_(network),
container_(new QWidget(this)),
layout_(new QHBoxLayout(container_)),
current_index_(-1),
scroll_animation_(new QPropertyAnimation(horizontalScrollBar(), "value", this)),
recursion_filter_(false)
{
setWidget(container_);
setWidgetResizable(true);
setMinimumHeight(PrettyImage::kTotalHeight + 10);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setFrameShape(QFrame::NoFrame);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scroll_animation_->setDuration(250);
scroll_animation_->setEasingCurve(QEasingCurve::InOutCubic);
connect(horizontalScrollBar(), SIGNAL(sliderReleased()), SLOT(ScrollBarReleased()));
connect(horizontalScrollBar(), SIGNAL(actionTriggered(int)), SLOT(ScrollBarAction(int)));
layout_->setSizeConstraint(QLayout::SetMinAndMaxSize);
layout_->setContentsMargins(6, 6, 6, 6);
layout_->setSpacing(6);
layout_->addSpacing(200);
layout_->addSpacing(200);
container_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
}
bool PrettyImageView::eventFilter(QObject* obj, QEvent* event) {
// Work around infinite recursion in QScrollArea resizes.
if (recursion_filter_) {
return false;
}
recursion_filter_ = true;
bool ret = QScrollArea::eventFilter(obj, event);
recursion_filter_ = false;
return ret;
}
void PrettyImageView::AddImage(const QUrl &url) {
PrettyImage *image = new PrettyImage(url, network_, container_);
connect(image, SIGNAL(destroyed()), SLOT(ScrollToCurrent()));
connect(image, SIGNAL(Loaded()), SLOT(ScrollToCurrent()));
layout_->insertWidget(layout_->count() - 1, image);
if (current_index_ == -1) ScrollTo(0);
}
void PrettyImageView::mouseReleaseEvent(QMouseEvent* e) {
// Find the image that was clicked on
QWidget* widget = container_->childAt(container_->mapFrom(this, e->pos()));
if (!widget) return;
// Get the index of that image
const int index = layout_->indexOf(widget) - 1;
if (index == -1) return;
if (index == current_index_) {
// Show the image fullsize
PrettyImage* pretty_image = qobject_cast<PrettyImage*>(widget);
if (pretty_image) {
pretty_image->ShowFullsize();
}
}
else {
// Scroll to the image
ScrollTo(index);
}
}
void PrettyImageView::ScrollTo(int index, bool smooth) {
current_index_ = qBound(0, index, layout_->count() - 3);
const int layout_index = current_index_ + 1;
const QWidget* target_widget = layout_->itemAt(layout_index)->widget();
if (!target_widget) return;
const int current_x = horizontalScrollBar()->value();
const int target_x = target_widget->geometry().center().x() - width() / 2;
if (current_x == target_x) return;
if (smooth) {
scroll_animation_->setStartValue(current_x);
scroll_animation_->setEndValue(target_x);
scroll_animation_->start();
}
else {
scroll_animation_->stop();
horizontalScrollBar()->setValue(target_x);
}
}
void PrettyImageView::ScrollToCurrent() {
ScrollTo(current_index_);
}
void PrettyImageView::ScrollBarReleased() {
// Find the nearest widget to where the scroll bar was released
const int current_x = horizontalScrollBar()->value() + width() / 2;
int layout_index = 1;
for (; layout_index<layout_->count() - 1 ; ++layout_index) {
const QWidget* widget = layout_->itemAt(layout_index)->widget();
if (widget && widget->geometry().right() > current_x) {
break;
}
}
ScrollTo(layout_index - 1);
}
void PrettyImageView::ScrollBarAction(int action) {
switch (action) {
case QAbstractSlider::SliderSingleStepAdd:
case QAbstractSlider::SliderPageStepAdd:
ScrollTo(current_index_ + 1);
break;
case QAbstractSlider::SliderSingleStepSub:
case QAbstractSlider::SliderPageStepSub:
ScrollTo(current_index_ - 1);
break;
}
}
void PrettyImageView::resizeEvent(QResizeEvent* e) {
QScrollArea::resizeEvent(e);
ScrollTo(current_index_, false);
}
void PrettyImageView::wheelEvent(QWheelEvent* e) {
const int d = e->delta() > 0 ? -1 : 1;
ScrollTo(current_index_ + d, true);
}

View File

@@ -1,80 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PRETTYIMAGEVIEW_H
#define PRETTYIMAGEVIEW_H
#include "config.h"
#include <stdbool.h>
#include <QObject>
#include <QWidget>
#include <QString>
#include <QUrl>
#include <QScrollArea>
#include <QBoxLayout>
#include <QPropertyAnimation>
#include <QNetworkAccessManager>
#include <QtEvents>
class QEvent;
class QMouseEvent;
class QResizeEvent;
class QWheelEvent;
class PrettyImageView : public QScrollArea {
Q_OBJECT
public:
PrettyImageView(QNetworkAccessManager *network, QWidget *parent = nullptr);
static const char *kSettingsGroup;
public slots:
void AddImage(const QUrl& url);
protected:
void mouseReleaseEvent(QMouseEvent*);
void resizeEvent(QResizeEvent *e);
void wheelEvent(QWheelEvent *e);
private slots:
void ScrollBarReleased();
void ScrollBarAction(int action);
void ScrollTo(int index, bool smooth = true);
void ScrollToCurrent();
private:
bool eventFilter(QObject*, QEvent*);
QNetworkAccessManager *network_;
QWidget *container_;
QHBoxLayout *layout_;
int current_index_;
QPropertyAnimation *scroll_animation_;
bool recursion_filter_;
};
#endif // PRETTYIMAGEVIEW_H

View File

@@ -1,65 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdbool.h>
#include <QObject>
#include <QAbstractItemModel>
#include <QStyledItemDelegate>
#include <QApplication>
#include <QVariant>
#include <QString>
#include <QStringBuilder>
#include <QPainter>
#include <QStyle>
#include <QRect>
#include <QStyleOptionProgressBar>
#include "progressitemdelegate.h"
ProgressItemDelegate::ProgressItemDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
bool ok = false;
int progress = index.data().toInt(&ok);
if (ok) {
QStyleOptionProgressBar opt;
opt.rect = option.rect;
opt.minimum = 0;
opt.maximum = 100;
opt.progress = progress;
opt.text = QString::number(progress) + "%";
opt.textVisible = true;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &opt, painter);
}
else {
QStyledItemDelegate::paint(painter, option, index);
}
}

View File

@@ -1,44 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PROGRESSITEMDELEGATE_H
#define PROGRESSITEMDELEGATE_H
#include "config.h"
#include <QObject>
#include <QString>
#include <QPainter>
#include <QStyleOption>
#include <QStyledItemDelegate>
#include <QStyleOptionViewItem>
class QModelIndex;
class ProgressItemDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
ProgressItemDelegate(QObject* parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif // PROGRESSITEMDELEGATE_H

View File

@@ -1,165 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdbool.h>
#include <QtGlobal>
#include <QWidget>
#include <QPixmap>
#include <QFrame>
#include <QPainter>
#include <QRect>
#include <QPoint>
#include <QSize>
#include <QSizePolicy>
#include <QStyle>
#include <QStyleOption>
#include <QStylePainter>
#include <QtEvents>
#include "ratingwidget.h"
const int RatingPainter::kStarCount;
const int RatingPainter::kStarSize;
RatingPainter::RatingPainter() {
// Load the base pixmaps
QPixmap on(":/icons/64x64/star.png");
QPixmap off(":/icons/64x64/star-grey.png");
// Generate the 10 states, better to do it now than on the fly
for (int i = 0; i < kStarCount * 2 + 1; ++i) {
const float rating = float(i) / 2.0;
// Clear the pixmap
stars_[i] = QPixmap(kStarSize * kStarCount, kStarSize);
stars_[i].fill(Qt::transparent);
QPainter p(&stars_[i]);
// Draw the stars
int x = 0;
for (int i = 0; i < kStarCount; ++i, x += kStarSize) {
const QRect rect(x, 0, kStarSize, kStarSize);
if (rating - 0.25 <= i) {
// Totally empty
p.drawPixmap(rect, off);
} else if (rating - 0.75 <= i) {
// Half full
const QRect target_left(rect.x(), rect.y(), kStarSize/2, kStarSize);
const QRect target_right(rect.x() + kStarSize/2, rect.y(), kStarSize/2, kStarSize);
const QRect source_left(0, 0, kStarSize/2, kStarSize);
const QRect source_right(kStarSize/2, 0, kStarSize/2, kStarSize);
p.drawPixmap(target_left, on, source_left);
p.drawPixmap(target_right, off, source_right);
}
else {
// Totally full
p.drawPixmap(rect, on);
}
}
}
}
QRect RatingPainter::Contents(const QRect& rect) {
const int width = kStarSize * kStarCount;
const int x = rect.x() + (rect.width() - width) / 2;
return QRect(x, rect.y(), width, rect.height());
}
double RatingPainter::RatingForPos(const QPoint& pos, const QRect& rect) {
const QRect contents = Contents(rect);
const double raw = double(pos.x() - contents.left()) / contents.width();
// Round to the nearest 0.1
return double(int(raw * kStarCount * 2 + 0.5)) / (kStarCount * 2);
}
void RatingPainter::Paint(QPainter* painter, const QRect& rect, float rating) const {
QSize size(qMin(kStarSize*kStarCount, rect.width()), qMin(kStarSize, rect.height()));
QPoint pos(rect.center() - QPoint(size.width() / 2, size.height() / 2));
rating *= kStarCount;
// Draw the stars
const int star = qBound(0, int(rating*2.0 + 0.5), kStarCount*2);
painter->drawPixmap(QRect(pos, size), stars_[star], QRect(QPoint(0,0), size));
}
RatingWidget::RatingWidget(QWidget* parent)
: QWidget(parent),
rating_(0.0),
hover_rating_(-1.0)
{
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
setMouseTracking(true);
}
QSize RatingWidget::sizeHint() const {
const int frame_width = 1 + style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
return QSize(RatingPainter::kStarSize * (RatingPainter::kStarCount+2) + frame_width*2, RatingPainter::kStarSize + frame_width*2);
}
void RatingWidget::set_rating(float rating) {
rating_ = rating;
update();
}
void RatingWidget::paintEvent(QPaintEvent* e) {
QStylePainter p(this);
// Draw the background
QStyleOptionFrameV3 opt;
opt.initFrom(this);
opt.state |= QStyle::State_Sunken;
opt.frameShape = QFrame::StyledPanel;
opt.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this);
opt.midLineWidth = 0;
p.drawPrimitive(QStyle::PE_PanelLineEdit, opt);
// Draw the stars
painter_.Paint(&p, rect(), hover_rating_ == -1.0 ? rating_ : hover_rating_);
}
void RatingWidget::mousePressEvent(QMouseEvent* e) {
rating_ = RatingPainter::RatingForPos(e->pos(), rect());
emit RatingChanged(rating_);
}
void RatingWidget::mouseMoveEvent(QMouseEvent* e) {
hover_rating_ = RatingPainter::RatingForPos(e->pos(), rect());
update();
}
void RatingWidget::leaveEvent(QEvent*) {
hover_rating_ = -1.0;
update();
}

View File

@@ -1,83 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef RATINGWIDGET_H
#define RATINGWIDGET_H
#include "config.h"
#include <QObject>
#include <QWidget>
#include <QString>
#include <QPixmap>
#include <QPainter>
#include <QRect>
#include <QSize>
#include <QPoint>
#include <QtEvents>
class QEvent;
class QMouseEvent;
class QPaintEvent;
class RatingPainter {
public:
RatingPainter();
static const int kStarCount = 5;
static const int kStarSize = 15;
static QRect Contents(const QRect& rect);
static double RatingForPos(const QPoint& pos, const QRect& rect);
void Paint(QPainter *painter, const QRect& rect, float rating) const;
private:
QPixmap stars_[kStarCount*2+1];
};
class RatingWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(float rating READ rating WRITE set_rating);
public:
RatingWidget(QWidget *parent = nullptr);
QSize sizeHint() const;
float rating() const { return rating_; }
void set_rating(float rating);
signals:
void RatingChanged(float rating);
protected:
void paintEvent(QPaintEvent*);
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void leaveEvent(QEvent*);
private:
RatingPainter painter_;
float rating_;
float hover_rating_;
};
#endif // RATINGWIDGET_H

View File

@@ -1,582 +0,0 @@
/*
* Strawberry Music Player
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QIODevice>
#include <QFile>
#include <QByteArray>
#include <QList>
#include <QVariant>
#include <QString>
#include <QImage>
#include <QPixmap>
#include <QMovie>
#include <QAction>
#include <QPainter>
#include <QPalette>
#include <QBrush>
#include <QLabel>
#include <QLayout>
#include <QMenu>
#include <QScrollArea>
#include <QBoxLayout>
#include <QSettings>
#include <QSizePolicy>
#include <QTimeLine>
#include <QtEvents>
#include "core/application.h"
#include "core/logging.h"
#include "core/player.h"
#include "core/song.h"
#include "core/utilities.h"
#include "engine/engine_fwd.h"
#include "engine/enginebase.h"
#include "engine/enginetype.h"
#include "collection/collectionbackend.h"
#include "collection/collectionquery.h"
#include "collection/collectionview.h"
#include "collection/collectionviewcontainer.h"
#include "covermanager/albumcoverchoicecontroller.h"
#include "covermanager/albumcoverloader.h"
#include "covermanager/currentartloader.h"
#include "statusview.h"
const char *StatusView::kSettingsGroup = "StatusView";
StatusView::StatusView(CollectionViewContainer *collectionviewcontainer, QWidget *parent) :
QWidget(parent),
layout_(new QVBoxLayout),
scrollarea_(new QScrollArea),
container_layout_(new QVBoxLayout),
container_widget_(new QWidget),
widget_stopped_ (nullptr),
widget_playing_ (nullptr),
layout_playing_(nullptr),
layout_stopped_(nullptr),
label_stopped_top_ (nullptr),
label_stopped_logo_(nullptr),
label_stopped_text_(nullptr),
label_playing_top_(nullptr),
label_playing_album_(nullptr),
label_playing_text_(nullptr),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
fade_animation_(new QTimeLine(1000, this)),
image_blank_(""),
image_nosong_(":/pictures/strawberry.png"),
widgetstate_(None),
menu_(new QMenu(this))
{
collectionview_ = collectionviewcontainer->view();
connect(collectionview_, SIGNAL(TotalSongCountUpdated_()), this, SLOT(UpdateNoSong()));
connect(collectionview_, SIGNAL(TotalArtistCountUpdated_()), this, SLOT(UpdateNoSong()));
connect(collectionview_, SIGNAL(TotalAlbumCountUpdated_()), this, SLOT(UpdateNoSong()));
connect(fade_animation_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousTrack(qreal)));
fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
cover_loader_options_.desired_height_ = 300;
cover_loader_options_.pad_output_image_ = true;
cover_loader_options_.scale_output_image_ = true;
pixmap_current_ = QPixmap::fromImage(AlbumCoverLoader::ScaleAndPad(cover_loader_options_, image_blank_));
CreateWidget();
NoSongWidget();
NoSong();
AddActions();
// Load settings
QSettings s;
s.beginGroup(kSettingsGroup);
album_cover_choice_controller_->search_cover_auto_action()->setChecked(s.value("search_for_cover_auto", true).toBool());
s.endGroup();
}
StatusView::~StatusView() {
}
void StatusView::AddActions() {
QList<QAction*> actions = album_cover_choice_controller_->GetAllActions();
// Here we add the search automatically action, too!
actions.append(album_cover_choice_controller_->search_cover_auto_action());
connect(album_cover_choice_controller_->cover_from_file_action(), SIGNAL(triggered()), this, SLOT(LoadCoverFromFile()));
connect(album_cover_choice_controller_->cover_to_file_action(), SIGNAL(triggered()), this, SLOT(SaveCoverToFile()));
connect(album_cover_choice_controller_->cover_from_url_action(), SIGNAL(triggered()), this, SLOT(LoadCoverFromURL()));
connect(album_cover_choice_controller_->search_for_cover_action(), SIGNAL(triggered()), this, SLOT(SearchForCover()));
connect(album_cover_choice_controller_->unset_cover_action(), SIGNAL(triggered()), this, SLOT(UnsetCover()));
connect(album_cover_choice_controller_->show_cover_action(), SIGNAL(triggered()), this, SLOT(ShowCover()));
connect(album_cover_choice_controller_->search_cover_auto_action(), SIGNAL(triggered()), this, SLOT(SearchCoverAutomatically()));
menu_->addActions(actions);
menu_->addSeparator();
}
void StatusView::CreateWidget() {
setLayout(layout_);
layout_->setSizeConstraint(QLayout::SetMinAndMaxSize);
layout_->setContentsMargins(0, 0, 0, 0);
layout_->setSpacing(6);
layout_->addWidget(scrollarea_);
scrollarea_->setWidget(container_widget_);
scrollarea_->setWidgetResizable(true);
scrollarea_->setStyleSheet("background-color: white;");
scrollarea_->setVisible(true);
container_widget_->setLayout(container_layout_);
container_widget_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
container_widget_->setBackgroundRole(QPalette::Base);
container_layout_->setSizeConstraint(QLayout::SetMinAndMaxSize);
container_layout_->setContentsMargins(0, 0, 0, 0);
container_layout_->setSpacing(6);
container_layout_->addStretch();
}
void StatusView::SetApplication(Application *app) {
app_ = app;
album_cover_choice_controller_->SetApplication(app_);
connect(app_->current_art_loader(), SIGNAL(ArtLoaded(Song, QString, QImage)), SLOT(AlbumArtLoaded(Song, QString, QImage)));
}
void StatusView::NoSongWidget() {
if (widgetstate_ == Playing) {
container_layout_->removeWidget(widget_playing_);
widget_playing_->setVisible(false);
delete label_playing_top_;
delete label_playing_album_;
delete label_playing_text_;
delete layout_playing_;
delete widget_playing_;
}
widget_stopped_ = new QWidget;
layout_stopped_ = new QVBoxLayout;
label_stopped_top_ = new QLabel;
label_stopped_logo_ = new QLabel;
label_stopped_text_ = new QLabel;
layout_stopped_->addWidget(label_stopped_top_);
layout_stopped_->addWidget(label_stopped_logo_);
layout_stopped_->addWidget(label_stopped_text_);
layout_stopped_->addStretch();
label_stopped_top_->setFixedHeight(40);
label_stopped_top_->setFixedWidth(300);
label_stopped_top_->setAlignment(Qt::AlignTop|Qt::AlignLeft);
widget_stopped_->setLayout(layout_stopped_);
container_layout_->insertWidget(0, widget_stopped_);
widget_stopped_->setVisible(true);
widgetstate_ = Stopped;
}
void StatusView::SongWidget() {
if (widgetstate_ == Stopped) {
container_layout_->removeWidget(widget_stopped_);
widget_stopped_->setVisible(false);
delete label_stopped_top_ ;
delete label_stopped_logo_;
delete label_stopped_text_;
delete layout_stopped_;
delete widget_stopped_;
}
widget_playing_ = new QWidget;
widget_playing_ = new QWidget;
layout_playing_ = new QVBoxLayout;
label_playing_top_ = new QLabel;
label_playing_album_ = new QLabel;
label_playing_text_ = new QLabel;
layout_playing_->addWidget(label_playing_top_);
layout_playing_->addWidget(label_playing_album_);
layout_playing_->addWidget(label_playing_text_);
layout_playing_->addStretch();
label_playing_top_->setAlignment(Qt::AlignTop|Qt::AlignLeft);
label_playing_top_->setFixedHeight(40);
label_playing_top_->setFixedWidth(300);
label_playing_top_->setWordWrap(true);
label_playing_text_->setAlignment(Qt::AlignTop|Qt::AlignLeft);
label_playing_text_->setFixedWidth(300);
label_playing_text_->setWordWrap(true);
label_playing_album_->setFixedHeight(300);
label_playing_album_->setFixedWidth(300);
label_playing_album_->setStyleSheet("background-color: transparent;");
label_playing_album_->installEventFilter(this);
widget_playing_->setLayout(layout_playing_);
container_layout_->insertWidget(0, widget_playing_);
QFile stylesheet(":/style/statusview.css");
if (stylesheet.open(QIODevice::ReadOnly)) {
setStyleSheet(QString::fromLatin1(stylesheet.readAll()));
label_playing_text_->setStyleSheet(QString::fromLatin1(stylesheet.readAll()));
}
widget_playing_->setVisible(true);
widgetstate_ = Playing;
}
void StatusView::SwitchWidgets(WidgetState state) {
if (widgetstate_ == None) NoSongWidget();
if ((state == Stopped) && (widgetstate_ != Stopped)) {
NoSongWidget();
}
if ((widgetstate_ != Playing) && (state == Playing)) {
SongWidget();
}
}
void StatusView::UpdateSong() {
SwitchWidgets(Playing);
const QueryOptions opt;
CollectionBackend::AlbumList albumlist;
label_playing_top_->setText("");
label_playing_text_->setText("");
QString html;
QString html_albums;
html += QString("<b>%1 - %2</b><br/>%3").arg(metadata_.PrettyTitle().toHtmlEscaped(), metadata_.artist().toHtmlEscaped(), metadata_.album().toHtmlEscaped());
label_playing_top_->setText(html);
html = "";
html += QString("Filetype: %1<br />\n").arg(metadata_.TextForFiletype());
html += QString("Length: %1<br />\n").arg(Utilities::PrettyTimeNanosec(metadata_.length_nanosec()));
html += QString("Bitrate: %1 kbps<br />\n").arg(metadata_.bitrate());
html += QString("Samplerate: %1 hz / %2 bit<br />\n").arg(metadata_.samplerate()).arg(metadata_.bitdepth());
if (app_->player()->engine() && app_->player()->engine()->type() != Engine::EngineType::None) {
html += QString("<br />");
html += QString("Engine: %1<br />").arg(EngineDescription(app_->player()->engine()->type()));
}
html += QString("<br />");
html_albums += QString("<b>Albums by %1:</b>").arg( metadata_.artist().toHtmlEscaped() );
albumlist = app_->collection_backend()->GetAlbumsByArtist(metadata_.artist(), opt);
html_albums += QString("<ul>");
int i=0;
for (CollectionBackend::Album album : albumlist) {
i++;
html_albums += QString("<li>%1</li>\n").arg(album.album_name.toHtmlEscaped());
}
html_albums += QString("</ul>");
html_albums += QString("");
if (i > 1) html += html_albums;
label_playing_text_->setText(html);
}
void StatusView::NoSong() {
QString html;
QImage image_logo(":/pictures/strawberry.png");
QImage image_logo_scaled = image_logo.scaled(300, 300, Qt::KeepAspectRatio);
QPixmap pixmap_logo(QPixmap::fromImage(image_logo_scaled));
SwitchWidgets(Stopped);
label_stopped_top_->setText("<b>No Track Playing</b>");
label_stopped_logo_->setPixmap(pixmap_logo);
html += QString(
"<html>\n"
"<head>\n"
"<style type=\"text/css\">:/style/statusview.css</style>\n"
"</head>\n"
"<body>\n"
"%1 songs<br />\n"
"%2 artists<br />\n"
"%3 albums<br />\n"
"</body>\n"
"</html>\n"
)
.arg(collectionview_->TotalSongs())
.arg(collectionview_->TotalArtists())
.arg(collectionview_->TotalAlbums())
;
label_stopped_text_->setText(html);
}
void StatusView::SongChanged(const Song &song) {
stopped_ = false;
metadata_ = song;
UpdateSong();
update();
}
void StatusView::SongFinished() {
stopped_ = true;
SetImage(image_blank_);
}
bool StatusView::eventFilter(QObject *object, QEvent *event) {
switch(event->type()) {
case QEvent::Paint:{
handlePaintEvent(object, event);
}
default:{
return QObject::eventFilter(object, event);
}
}
return(true);
}
void StatusView::handlePaintEvent(QObject *object, QEvent *event) {
if (object == label_playing_album_) {
paintEvent_album(event);
}
return;
}
void StatusView::paintEvent_album(QEvent *event) {
QPainter p(label_playing_album_);
DrawImage(&p);
// Draw the previous track's image if we're fading
if (!pixmap_previous_.isNull()) {
p.setOpacity(pixmap_previous_opacity_);
p.drawPixmap(0, 0, pixmap_previous_);
}
}
void StatusView::DrawImage(QPainter *p) {
p->drawPixmap(0, 0, 300, 300, pixmap_current_);
if ((downloading_covers_) && (spinner_animation_ != nullptr)) {
p->drawPixmap(50, 50, 16, 16, spinner_animation_->currentPixmap());
}
}
void StatusView::FadePreviousTrack(qreal value) {
pixmap_previous_opacity_ = value;
if (qFuzzyCompare(pixmap_previous_opacity_, qreal(0.0))) {
pixmap_previous_ = QPixmap();
}
update();
if ((value == 0) && (stopped_ == true)) {
SwitchWidgets(Stopped);
NoSong();
}
}
void StatusView::contextMenuEvent(QContextMenuEvent *e) {
// show the menu
if (menu_ && widgetstate_ == Playing) menu_->popup(mapToGlobal(e->pos()));
}
void StatusView::mouseReleaseEvent(QMouseEvent *) {
}
void StatusView::dragEnterEvent(QDragEnterEvent *e) {
QWidget::dragEnterEvent(e);
}
void StatusView::dropEvent(QDropEvent *e) {
QWidget::dropEvent(e);
}
void StatusView::ScaleCover() {
pixmap_current_ = QPixmap::fromImage(AlbumCoverLoader::ScaleAndPad(cover_loader_options_, original_));
update();
}
void StatusView::AlbumArtLoaded(const Song &metadata, const QString&, const QImage &image) {
SwitchWidgets(Playing);
label_playing_album_->clear();
metadata_ = metadata;
downloading_covers_ = false;
SetImage(image);
// Search for cover automatically?
GetCoverAutomatically();
}
void StatusView::SetImage(const QImage &image) {
// Cache the current pixmap so we can fade between them
pixmap_previous_ = QPixmap(size());
pixmap_previous_.fill(palette().background().color());
pixmap_previous_opacity_ = 1.0;
QPainter p(&pixmap_previous_);
DrawImage(&p);
p.end();
original_ = image;
ScaleCover();
// Were we waiting for this cover to load before we started fading?
if (!pixmap_previous_.isNull() && fade_animation_) {
fade_animation_->start();
}
}
bool StatusView::GetCoverAutomatically() {
SwitchWidgets(Playing);
// Search for cover automatically?
bool search =
!metadata_.has_manually_unset_cover() &&
metadata_.art_automatic().isEmpty() &&
metadata_.art_manual().isEmpty() &&
!metadata_.artist().isEmpty() &&
!metadata_.album().isEmpty();
if (search) {
qLog(Debug) << "GetCoverAutomatically";
downloading_covers_ = true;
album_cover_choice_controller_->SearchCoverAutomatically(metadata_);
// Show a spinner animation
spinner_animation_.reset(new QMovie(":/pictures/spinner.gif", QByteArray(), this));
connect(spinner_animation_.get(), SIGNAL(updated(const QRect&)), SLOT(update()));
spinner_animation_->start();
update();
}
return search;
}
void StatusView::AutomaticCoverSearchDone() {
downloading_covers_ = false;
spinner_animation_.reset();
update();
}
void StatusView::UpdateNoSong() {
if (widgetstate_ == Playing) return;
NoSong();
}
void StatusView::LoadCoverFromFile() {
album_cover_choice_controller_->LoadCoverFromFile(&metadata_);
}
void StatusView::LoadCoverFromURL() {
album_cover_choice_controller_->LoadCoverFromURL(&metadata_);
}
void StatusView::SearchForCover() {
album_cover_choice_controller_->SearchForCover(&metadata_);
}
void StatusView::SaveCoverToFile() {
album_cover_choice_controller_->SaveCoverToFile(metadata_, original_);
}
void StatusView::UnsetCover() {
album_cover_choice_controller_->UnsetCover(&metadata_);
}
void StatusView::ShowCover() {
album_cover_choice_controller_->ShowCover(metadata_);
}
void StatusView::SearchCoverAutomatically() {
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked());
GetCoverAutomatically();
}

View File

@@ -1,177 +0,0 @@
/*
* Strawberry Music Player
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STATUSVIEW_H
#define STATUSVIEW_H
#include "config.h"
#include <memory>
#include <stdbool.h>
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QString>
#include <QImage>
#include <QPixmap>
#include <QMovie>
#include <QPainter>
#include <QTimeLine>
#include <QAction>
#include <QLabel>
#include <QMenu>
#include <QScrollArea>
#include <QBoxLayout>
#include <QtEvents>
#include "core/song.h"
#include "covermanager/albumcoverloaderoptions.h"
class QEvent;
class QContextMenuEvent;
class QDragEnterEvent;
class QDropEvent;
class QMouseEvent;
class Application;
class CollectionView;
class CollectionViewContainer;
class AlbumCoverChoiceController;
class StatusView : public QWidget {
Q_OBJECT
public:
StatusView(CollectionViewContainer *collectionviewcontainer, QWidget *parent = nullptr);
~StatusView();
static const char* kSettingsGroup;
static const int kPadding;
static const int kGradientHead;
static const int kGradientTail;
static const int kMaxCoverSize;
static const int kBottomOffset;
static const int kTopBorder;
void SetApplication(Application *app);
public slots:
void SongChanged(const Song &song);
void SongFinished();
void AlbumArtLoaded(const Song& metadata, const QString &uri, const QImage &image);
void FadePreviousTrack(qreal value);
void LoadCoverFromFile();
void SaveCoverToFile();
void LoadCoverFromURL();
void SearchForCover();
void UnsetCover();
void ShowCover();
void SearchCoverAutomatically();
void AutomaticCoverSearchDone();
private:
QVBoxLayout *layout_;
QScrollArea *scrollarea_;
QVBoxLayout *container_layout_;
QWidget *container_widget_;
QWidget *widget_stopped_;
QWidget *widget_playing_;
QVBoxLayout *layout_playing_;
QVBoxLayout *layout_stopped_;
QLabel *label_stopped_top_;
QLabel *label_stopped_logo_;
QLabel *label_stopped_text_;
QLabel *label_playing_top_;
QLabel *label_playing_album_;
QLabel *label_playing_text_;
QPixmap *pixmap_album_;
QPainter *painter_album_;
CollectionView *collectionview_;
AlbumCoverLoaderOptions cover_loader_options_;
QImage original_;
void CreateWidget();
void NoSongWidget();
void SongWidget();
void AddActions();
void SetImage(const QImage &image);
void DrawImage(QPainter *p);
void ScaleCover();
bool GetCoverAutomatically();
Application *app_;
AlbumCoverChoiceController *album_cover_choice_controller_;
QAction *fit_cover_width_action_;
bool visible_;
int small_ideal_height_;
int total_height_;
bool fit_width_;
QTimeLine *fade_animation_;
QImage image_blank_;
QImage image_nosong_;
// Information about the current track
Song metadata_;
QPixmap pixmap_current_;
// Holds the last track while we're fading to the new track
QPixmap pixmap_previous_;
qreal pixmap_previous_opacity_;
std::unique_ptr<QMovie> spinner_animation_;
bool downloading_covers_;
bool stopped_;
bool playing_;
enum WidgetState {
None = 0,
Playing,
Stopped
};
WidgetState widgetstate_;
QMenu *menu_;
protected:
bool eventFilter(QObject *, QEvent *);
void handlePaintEvent(QObject *object, QEvent *event);
void paintEvent_album(QEvent *event);
void contextMenuEvent(QContextMenuEvent *e);
void mouseReleaseEvent(QMouseEvent *);
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
void UpdateSong();
void NoSong();
void SwitchWidgets(WidgetState state);
private slots:
void UpdateNoSong();
};
#endif // STATUSVIEW_H

View File

@@ -1,177 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QtGlobal>
#include <QWidget>
#include <QString>
#include <QFont>
#include <QFontMetrics>
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QPalette>
#include <QColor>
#include <QBrush>
#include <QRect>
#include <QSize>
#include <QTimeLine>
#include <QtEvents>
#include "core/qt_blurimage.h"
#include "widgetfadehelper.h"
const int WidgetFadeHelper::kLoadingPadding = 9;
const int WidgetFadeHelper::kLoadingBorderRadius = 10;
WidgetFadeHelper::WidgetFadeHelper(QWidget* parent, int msec)
: QWidget(parent),
parent_(parent),
blur_timeline_(new QTimeLine(msec, this)),
fade_timeline_(new QTimeLine(msec, this))
{
parent->installEventFilter(this);
connect(blur_timeline_, SIGNAL(valueChanged(qreal)), SLOT(update()));
connect(fade_timeline_, SIGNAL(valueChanged(qreal)), SLOT(update()));
connect(fade_timeline_, SIGNAL(finished()), SLOT(FadeFinished()));
hide();
}
bool WidgetFadeHelper::eventFilter(QObject* obj, QEvent* event) {
// We're only interested in our parent's resize events
if (obj != parent_ || event->type() != QEvent::Resize) return false;
// Don't care if we're hidden
if (!isVisible()) return false;
QResizeEvent* re = static_cast<QResizeEvent*>(event);
if (re->oldSize() == re->size()) {
// Ignore phoney resize events
return false;
}
// Get a new capture of the parent
hide();
CaptureParent();
show();
return false;
}
void WidgetFadeHelper::StartBlur() {
CaptureParent();
// Cover the parent
raise();
show();
// Start the timeline
blur_timeline_->stop();
blur_timeline_->start();
setAttribute(Qt::WA_TransparentForMouseEvents, false);
}
void WidgetFadeHelper::CaptureParent() {
// Take a "screenshot" of the window
original_pixmap_ = QPixmap::grabWidget(parent_);
QImage original_image = original_pixmap_.toImage();
// Blur it
QImage blurred(original_image.size(), QImage::Format_ARGB32_Premultiplied);
blurred.fill(Qt::transparent);
QPainter blur_painter(&blurred);
blur_painter.save();
qt_blurImage(&blur_painter, original_image, 10.0, true, false);
blur_painter.restore();
// Draw some loading text over the top
QFont loading_font(font());
loading_font.setBold(true);
QFontMetrics loading_font_metrics(loading_font);
const QString loading_text = tr("Loading...");
const QSize loading_size(kLoadingPadding*2 + loading_font_metrics.width(loading_text), kLoadingPadding*2 + loading_font_metrics.height());
const QRect loading_rect((blurred.width() - loading_size.width()) / 2, 100, loading_size.width(), loading_size.height());
blur_painter.setRenderHint(QPainter::Antialiasing);
blur_painter.setRenderHint(QPainter::HighQualityAntialiasing);
blur_painter.translate(0.5, 0.5);
blur_painter.setPen(QColor(200, 200, 200, 255));
blur_painter.setBrush(QColor(200, 200, 200, 192));
blur_painter.drawRoundedRect(loading_rect, kLoadingBorderRadius, kLoadingBorderRadius);
blur_painter.setPen(palette().brush(QPalette::Text).color());
blur_painter.setFont(loading_font);
blur_painter.drawText(loading_rect.translated(-1, -1), Qt::AlignCenter, loading_text);
blur_painter.translate(-0.5, -0.5);
blur_painter.end();
blurred_pixmap_ = QPixmap::fromImage(blurred);
resize(parent_->size());
}
void WidgetFadeHelper::StartFade() {
if (blur_timeline_->state() == QTimeLine::Running) {
// Blur timeline is still running, so we need render the current state into a new pixmap.
QPixmap pixmap(original_pixmap_);
QPainter painter(&pixmap);
painter.setOpacity(blur_timeline_->currentValue());
painter.drawPixmap(0, 0, blurred_pixmap_);
painter.end();
blurred_pixmap_ = pixmap;
}
blur_timeline_->stop();
original_pixmap_ = QPixmap();
// Start the timeline
fade_timeline_->stop();
fade_timeline_->start();
setAttribute(Qt::WA_TransparentForMouseEvents, true);
}
void WidgetFadeHelper::paintEvent(QPaintEvent* ) {
QPainter p(this);
if (fade_timeline_->state() != QTimeLine::Running) {
// We're fading in the blur
p.drawPixmap(0, 0, original_pixmap_);
p.setOpacity(blur_timeline_->currentValue());
}
else {
// Fading out the blur into the new image
p.setOpacity(1.0 - fade_timeline_->currentValue());
}
p.drawPixmap(0, 0, blurred_pixmap_);
}
void WidgetFadeHelper::FadeFinished() {
hide();
original_pixmap_ = QPixmap();
blurred_pixmap_ = QPixmap();
}

View File

@@ -1,71 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef WIDGETFADEHELPER_H
#define WIDGETFADEHELPER_H
#include "config.h"
#include <stdbool.h>
#include <QtGlobal>
#include <QObject>
#include <QWidget>
#include <QString>
#include <QPixmap>
#include <QTimeLine>
#include <QtEvents>
class QEvent;
class QPaintEvent;
class WidgetFadeHelper : public QWidget {
Q_OBJECT
public:
WidgetFadeHelper(QWidget* parent, int msec = 500);
public slots:
void StartBlur();
void StartFade();
protected:
void paintEvent(QPaintEvent*);
bool eventFilter(QObject* obj, QEvent* event);
private slots:
void FadeFinished();
private:
void CaptureParent();
private:
static const int kLoadingPadding;
static const int kLoadingBorderRadius;
QWidget* parent_;
QTimeLine* blur_timeline_;
QTimeLine* fade_timeline_;
QPixmap original_pixmap_;
QPixmap blurred_pixmap_;
};
#endif // WIDGETFADEHELPER_H