Add a pretty image viewer widget to the artist info pane
This commit is contained in:
parent
f017587099
commit
f09a115339
|
@ -174,6 +174,7 @@ set(SOURCES
|
|||
widgets/nowplayingwidget.cpp
|
||||
widgets/osd.cpp
|
||||
widgets/osdpretty.cpp
|
||||
widgets/prettyimageview.cpp
|
||||
widgets/progressitemdelegate.cpp
|
||||
widgets/sliderwidget.cpp
|
||||
widgets/spinbox.cpp
|
||||
|
@ -310,6 +311,7 @@ set(HEADERS
|
|||
widgets/nowplayingwidget.h
|
||||
widgets/osd.h
|
||||
widgets/osdpretty.h
|
||||
widgets/prettyimageview.h
|
||||
widgets/progressitemdelegate.h
|
||||
widgets/sliderwidget.h
|
||||
widgets/spinbox.h
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "artistinfofetcher.h"
|
||||
#include "artistinfoview.h"
|
||||
#include "collapsibleinfopane.h"
|
||||
#include "widgets/prettyimageview.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QScrollArea>
|
||||
|
@ -24,8 +25,8 @@
|
|||
#include <QVBoxLayout>
|
||||
#include <QtDebug>
|
||||
|
||||
ArtistInfoView::ArtistInfoView(QWidget *parent)
|
||||
: SongInfoBase(parent),
|
||||
ArtistInfoView::ArtistInfoView(NetworkAccessManager* network, QWidget *parent)
|
||||
: SongInfoBase(network, parent),
|
||||
fetcher_(new ArtistInfoFetcher(this)),
|
||||
current_request_id_(-1),
|
||||
scroll_area_(new QScrollArea),
|
||||
|
@ -75,13 +76,16 @@ void ArtistInfoView::Clear() {
|
|||
void ArtistInfoView::Update(const Song& metadata) {
|
||||
Clear();
|
||||
current_request_id_ = fetcher_->FetchInfo(metadata.artist());
|
||||
|
||||
image_view_ = new PrettyImageView(network_);
|
||||
AddChild(image_view_);
|
||||
}
|
||||
|
||||
void ArtistInfoView::ImageReady(int id, const QUrl& url) {
|
||||
if (id != current_request_id_)
|
||||
return;
|
||||
|
||||
qDebug() << "Image" << url;
|
||||
image_view_->AddImage(url);
|
||||
}
|
||||
|
||||
void ArtistInfoView::InfoReady(int id, const QString& title, QWidget* widget) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "songinfobase.h"
|
||||
|
||||
class ArtistInfoFetcher;
|
||||
class PrettyImageView;
|
||||
|
||||
class QScrollArea;
|
||||
class QVBoxLayout;
|
||||
|
@ -28,7 +29,7 @@ class ArtistInfoView : public SongInfoBase {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ArtistInfoView(QWidget* parent = 0);
|
||||
ArtistInfoView(NetworkAccessManager* network, QWidget* parent = 0);
|
||||
~ArtistInfoView();
|
||||
|
||||
protected:
|
||||
|
@ -48,6 +49,8 @@ private:
|
|||
|
||||
QScrollArea* scroll_area_;
|
||||
QVBoxLayout* container_;
|
||||
PrettyImageView* image_view_;
|
||||
|
||||
QList<QWidget*> children_;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "lyricview.h"
|
||||
#include "ui_lyricview.h"
|
||||
|
||||
LyricView::LyricView(QWidget *parent)
|
||||
: SongInfoBase(parent),
|
||||
LyricView::LyricView(NetworkAccessManager* network, QWidget *parent)
|
||||
: SongInfoBase(network, parent),
|
||||
ui_(new Ui_LyricView),
|
||||
fetcher_(NULL),
|
||||
current_request_id_(-1)
|
||||
|
|
|
@ -28,7 +28,7 @@ class LyricView : public SongInfoBase {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LyricView(QWidget* parent = 0);
|
||||
LyricView(NetworkAccessManager* network, QWidget* parent = 0);
|
||||
~LyricView();
|
||||
|
||||
void set_network(NetworkAccessManager* network);
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
|
||||
#include "songinfobase.h"
|
||||
|
||||
SongInfoBase::SongInfoBase(QWidget* parent)
|
||||
SongInfoBase::SongInfoBase(NetworkAccessManager* network, QWidget* parent)
|
||||
: QWidget(parent),
|
||||
network_(network),
|
||||
dirty_(false)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -21,11 +21,13 @@
|
|||
|
||||
#include "core/song.h"
|
||||
|
||||
class NetworkAccessManager;
|
||||
|
||||
class SongInfoBase : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SongInfoBase(QWidget* parent = 0);
|
||||
SongInfoBase(NetworkAccessManager* network, QWidget* parent = 0);
|
||||
|
||||
public slots:
|
||||
void SongChanged(const Song& metadata);
|
||||
|
@ -36,6 +38,8 @@ protected:
|
|||
|
||||
virtual void Update(const Song& metadata) {}
|
||||
|
||||
NetworkAccessManager* network_;
|
||||
|
||||
private:
|
||||
Song queued_metadata_;
|
||||
bool dirty_;
|
||||
|
|
|
@ -1083,6 +1083,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1084,6 +1084,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1111,6 +1111,9 @@ msgstr "Carregant fluxe"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Carregant pistes"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Carregar fitxers/URLs, substituïnt l'actual llista de reproducció"
|
||||
|
||||
|
|
|
@ -1088,6 +1088,9 @@ msgstr "Načítám kanál"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Nahraj soubory/URL, výměnou za aktuální playlist"
|
||||
|
||||
|
|
|
@ -1089,6 +1089,9 @@ msgstr "Indlæser stream"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Indlæser filer/URL'er og erstatter nuværende spilleliste"
|
||||
|
||||
|
|
|
@ -1112,6 +1112,9 @@ msgstr "Lade Stream"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Lade Stücke"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Öffne Dateien/URLs und ersetze die Wiedergabeliste"
|
||||
|
||||
|
|
|
@ -1115,6 +1115,9 @@ msgstr "Φόρτωμα ροής (stream)"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Φόρτωση κομματιών"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Φορτώνει αρχεία/URLs, αντικαθιστώντας την τρέχουσα λίστα αναπαραγωγής"
|
||||
|
||||
|
|
|
@ -1087,6 +1087,9 @@ msgstr "Loading stream"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Loads files/URLs, replacing current playlist"
|
||||
|
||||
|
|
|
@ -1085,6 +1085,9 @@ msgstr "Loading stream"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Loads files/URLs, replacing current playlist"
|
||||
|
||||
|
|
|
@ -1116,6 +1116,9 @@ msgstr "Cargando flujo"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Cargando pistas"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Cargar archivos/URLs, remplazando la actual lista de reproducción"
|
||||
|
||||
|
|
|
@ -1085,6 +1085,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr "Ladataan kappaleita"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1120,6 +1120,9 @@ msgstr "Chargement du flux"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Chargement des pistes"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Charger des fichiers/URLs, et remplacer la liste de lecture actuelle"
|
||||
|
||||
|
|
|
@ -1090,6 +1090,9 @@ msgstr "A carregar a stream"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1109,6 +1109,9 @@ msgstr "Adatfolyam betöltése"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Számok betöltése"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Fájlok/URL-ek betöltése, lejátszási lista cseréje"
|
||||
|
||||
|
|
|
@ -1119,6 +1119,9 @@ msgstr "Caricamento flusso"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Caricamento delle tracce"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Carica file/URL, sostituendo la scaletta attuale"
|
||||
|
||||
|
|
|
@ -1085,6 +1085,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1084,6 +1084,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1087,6 +1087,9 @@ msgstr "Lader lydstrøm"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1113,6 +1113,9 @@ msgstr "Radiostream laden"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Tracks laden"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Laadt bestanden/URLs, en vervangt de huidige afspeellijst"
|
||||
|
||||
|
|
|
@ -1083,6 +1083,9 @@ msgstr "Cargament del flux"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1111,6 +1111,9 @@ msgstr "Ładowanie strumienia"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Wczytywanie ścieżek"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Wczytywanie plików/adresów URL, zamiana obecnej listy odtwarzania"
|
||||
|
||||
|
|
|
@ -1111,6 +1111,9 @@ msgstr "Carregando emissão"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Carregando faixas"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Carregar ficheiros/URLs, substituindo a lista atual"
|
||||
|
||||
|
|
|
@ -1100,6 +1100,9 @@ msgstr "Carregando transmissão"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Carregando faixas"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Carregar arquivos/sites, substiuindo a lista de reprodução atual"
|
||||
|
||||
|
|
|
@ -1084,6 +1084,9 @@ msgstr "Se încarcă fluxul"
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1104,6 +1104,9 @@ msgstr "Загрузка потока"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Загрузить композиции"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Загрузить файлы/URLs, заменяя текущий список воспроизведения"
|
||||
|
||||
|
|
|
@ -1106,6 +1106,9 @@ msgstr "Načítava sa stream"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Načítavajú sa skladby"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Načítať súbory/URLy, nahradiť nimi aktuálny playlist"
|
||||
|
||||
|
|
|
@ -1105,6 +1105,9 @@ msgstr "Nalaganje pretoka"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Nalaganje skladb"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Naloži datoteke/povezave in zamenjaj trenutni seznam predvajanja"
|
||||
|
||||
|
|
|
@ -1089,6 +1089,9 @@ msgstr "Учитавам ток"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Учитавам нумере"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1093,6 +1093,9 @@ msgstr "Laddar ström"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Läser in spår"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Ladda filer/webbadresser, ersätt nuvarande spellista"
|
||||
|
||||
|
|
|
@ -1108,6 +1108,9 @@ msgstr "Yayın akışı yükleniyor"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Parçalar yükleniyor"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Dosyaları/URLleri yükler, mevcut çalma listesinin yerine koyar"
|
||||
|
||||
|
|
|
@ -1074,6 +1074,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1105,6 +1105,9 @@ msgstr "Завнтаження потоку"
|
|||
msgid "Loading tracks"
|
||||
msgstr "Завантаження доріжок"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "Завантажити файли/адреси, замінюючи поточний список відтворення"
|
||||
|
||||
|
|
|
@ -1083,6 +1083,9 @@ msgstr ""
|
|||
msgid "Loading tracks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "装入文件/URL,替换当前播放列表"
|
||||
|
||||
|
|
|
@ -1089,6 +1089,9 @@ msgstr "載入串流"
|
|||
msgid "Loading tracks"
|
||||
msgstr "載入歌曲"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loads files/URLs, replacing current playlist"
|
||||
msgstr "加載檔案/網址,取代目前的播放清單"
|
||||
|
||||
|
|
|
@ -142,8 +142,8 @@ MainWindow::MainWindow(NetworkAccessManager* network, Engine::Type engine, QWidg
|
|||
file_view_(new FileView(this)),
|
||||
radio_view_(new RadioViewContainer(this)),
|
||||
device_view_(new DeviceView(this)),
|
||||
lyric_view_(new LyricView(this)),
|
||||
artist_info_view_(new ArtistInfoView(this)),
|
||||
lyric_view_(new LyricView(network, this)),
|
||||
artist_info_view_(new ArtistInfoView(network, this)),
|
||||
settings_dialog_(NULL),
|
||||
cover_manager_(NULL),
|
||||
equalizer_(new Equalizer),
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
/* This file is part of Clementine.
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "prettyimageview.h"
|
||||
#include "core/networkaccessmanager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include <QNetworkReply>
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QTimeLine>
|
||||
#include <QtDebug>
|
||||
|
||||
const int PrettyImageView::kArrowWidth = 35;
|
||||
const int PrettyImageView::kImageHeight = 160;
|
||||
const int PrettyImageView::kTotalHeight = 200;
|
||||
const int PrettyImageView::kBorderHeight = 10;
|
||||
|
||||
const int PrettyImageView::kBaseAnimationDuration = 500; // msec
|
||||
const int PrettyImageView::kArrowAnimationDuration = 250; // msec
|
||||
|
||||
PrettyImageView::PrettyImageView(NetworkAccessManager* network, QWidget* parent)
|
||||
: QWidget(parent),
|
||||
network_(network),
|
||||
next_image_request_id_(1),
|
||||
current_index_(0),
|
||||
base_timeline_(new QTimeLine(kBaseAnimationDuration, this)),
|
||||
left_timeline_(new QTimeLine(kArrowAnimationDuration, this)),
|
||||
right_timeline_(new QTimeLine(kArrowAnimationDuration, this))
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setMinimumHeight(kTotalHeight);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
connect(base_timeline_, SIGNAL(valueChanged(qreal)), SLOT(update()));
|
||||
connect(left_timeline_, SIGNAL(valueChanged(qreal)), SLOT(update()));
|
||||
connect(right_timeline_, SIGNAL(valueChanged(qreal)), SLOT(update()));
|
||||
}
|
||||
|
||||
QRect PrettyImageView::left() const {
|
||||
return QRect(0, 0, kArrowWidth, height());
|
||||
}
|
||||
|
||||
QRect PrettyImageView::right() const {
|
||||
return QRect(width() - kArrowWidth, 0, kArrowWidth, height());
|
||||
}
|
||||
|
||||
QPolygon PrettyImageView::arrow(const QRect& rect, int direction) const {
|
||||
QPoint point(direction > 0 ? rect.right() : rect.left(),
|
||||
(rect.bottom() - rect.top()) / 2 + rect.top());
|
||||
|
||||
return QPolygon()
|
||||
<< point
|
||||
<< QPoint(point.x() - direction * kArrowWidth, point.y() - kArrowWidth)
|
||||
<< QPoint(point.x() - direction * kArrowWidth, point.y() + kArrowWidth);
|
||||
}
|
||||
|
||||
void PrettyImageView::Clear() {
|
||||
images_.clear();
|
||||
image_requests_.clear();
|
||||
current_index_ = 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void PrettyImageView::AddImage(const QUrl& url) {
|
||||
const int index = images_.count();
|
||||
const int id = next_image_request_id_ ++;
|
||||
|
||||
// Add the image to the list
|
||||
images_ << Image(url);
|
||||
|
||||
// Start fetching the image
|
||||
network_->Get(url, this, "ImageFetched", id);
|
||||
image_requests_[id] = index;
|
||||
}
|
||||
|
||||
void PrettyImageView::ImageFetched(quint64 id, QNetworkReply* reply) {
|
||||
reply->deleteLater();
|
||||
|
||||
if (!image_requests_.contains(id))
|
||||
return;
|
||||
|
||||
Image& data = images_[image_requests_.take(id)];
|
||||
|
||||
QImage image = QImage::fromData(reply->readAll());
|
||||
if (image.isNull())
|
||||
return;
|
||||
|
||||
data.SetImage(image);
|
||||
update();
|
||||
}
|
||||
|
||||
void PrettyImageView::paintEvent(QPaintEvent*) {
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
p.setBrush(palette().color(QPalette::Highlight));
|
||||
p.setPen(QPen(palette().color(QPalette::Text), 0.5));
|
||||
|
||||
// Draw left arrow
|
||||
p.setOpacity(base_timeline_->currentValue() * (0.5 + left_timeline_->currentValue() * 0.5));
|
||||
p.drawConvexPolygon(arrow(left(), -1));
|
||||
|
||||
// Draw right arrow
|
||||
p.setOpacity(base_timeline_->currentValue() * (0.5 + right_timeline_->currentValue() * 0.5));
|
||||
p.drawConvexPolygon(arrow(right(), +1));
|
||||
|
||||
// Draw the current image
|
||||
if (current_index_ >= 0 && current_index_ < images_.count()) {
|
||||
QRect rect(0, 0, width(), kImageHeight - kBorderHeight);
|
||||
|
||||
p.setOpacity(1.0);
|
||||
DrawImage(&p, rect, images_[current_index_]);
|
||||
}
|
||||
}
|
||||
|
||||
void PrettyImageView::DrawImage(QPainter* p, const QRect& rect, const Image& image) {
|
||||
const int width = image.image_.isNull() ? rect.height() * 1.6 :
|
||||
float(image.image_.width()) / image.image_.height() * rect.height();
|
||||
|
||||
// Center the image in the rectangle
|
||||
QRect actual_rect(0, kBorderHeight, width, rect.height());
|
||||
actual_rect.moveLeft((rect.width() - width) / 2);
|
||||
|
||||
// Draw the main image
|
||||
DrawThumbnail(p, actual_rect, image);
|
||||
|
||||
// Draw the reflection
|
||||
// Figure out where to draw it
|
||||
QRect reflection_rect(actual_rect);
|
||||
reflection_rect.moveTop(reflection_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, -actual_rect.height());
|
||||
reflection_painter.setTransform(transform);
|
||||
|
||||
QRect fade_rect(reflection.rect().bottomLeft() - QPoint(0, kTotalHeight - kImageHeight),
|
||||
reflection.rect().bottomRight());
|
||||
|
||||
// Draw the reflection into the buffer
|
||||
DrawThumbnail(&reflection_painter, reflection.rect(), image);
|
||||
|
||||
// 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 PrettyImageView::DrawThumbnail(QPainter* p, const QRect& rect, const Image& image) {
|
||||
if (image.image_.isNull()) {
|
||||
// Draw an empty box if there's no image to show
|
||||
p->setPen(palette().color(QPalette::Disabled, QPalette::Text));
|
||||
p->drawText(rect, Qt::AlignHCenter | Qt::AlignBottom, tr("Loading..."));
|
||||
} else {
|
||||
// Draw the image
|
||||
p->drawPixmap(rect, image.thumbnail_);
|
||||
}
|
||||
}
|
||||
|
||||
void PrettyImageView::mouseReleaseEvent(QMouseEvent* e) {
|
||||
if (left().contains(e->pos()))
|
||||
current_index_ = qMax(0, current_index_ - 1);
|
||||
else if (right().contains(e->pos()))
|
||||
current_index_ = qMin(images_.count() - 1, current_index_ + 1);
|
||||
update();
|
||||
}
|
||||
|
||||
void PrettyImageView::mouseMoveEvent(QMouseEvent* e) {
|
||||
SetTimeLineActive(left_timeline_, left().contains(e->pos()));
|
||||
SetTimeLineActive(right_timeline_, right().contains(e->pos()));
|
||||
}
|
||||
|
||||
void PrettyImageView::enterEvent(QEvent*) {
|
||||
SetTimeLineActive(base_timeline_, true);
|
||||
}
|
||||
|
||||
void PrettyImageView::leaveEvent(QEvent*) {
|
||||
SetTimeLineActive(base_timeline_, false);
|
||||
}
|
||||
|
||||
void PrettyImageView::SetTimeLineActive(QTimeLine* timeline, bool active) {
|
||||
const QTimeLine::Direction direction =
|
||||
active ? QTimeLine::Forward : QTimeLine::Backward;
|
||||
|
||||
if (timeline->state() == QTimeLine::Running && timeline->direction() == direction)
|
||||
return;
|
||||
|
||||
timeline->setDirection(direction);
|
||||
|
||||
if (timeline->state() != QTimeLine::Running)
|
||||
timeline->resume();
|
||||
}
|
||||
|
||||
void PrettyImageView::Image::SetImage(const QImage& image) {
|
||||
image_ = image;
|
||||
thumbnail_ = QPixmap::fromImage(image_.scaledToHeight(
|
||||
kImageHeight, Qt::SmoothTransformation));
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/* This file is part of Clementine.
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PRETTYIMAGEVIEW_H
|
||||
#define PRETTYIMAGEVIEW_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QUrl>
|
||||
#include <QWidget>
|
||||
|
||||
class NetworkAccessManager;
|
||||
|
||||
class QNetworkReply;
|
||||
class QTimeLine;
|
||||
|
||||
class PrettyImageView : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PrettyImageView(NetworkAccessManager* network, QWidget* parent = 0);
|
||||
|
||||
static const int kTotalHeight;
|
||||
static const int kImageHeight;
|
||||
static const int kBorderHeight;
|
||||
static const int kArrowWidth;
|
||||
|
||||
static const int kBaseAnimationDuration;
|
||||
static const int kArrowAnimationDuration;
|
||||
|
||||
public slots:
|
||||
void Clear();
|
||||
void AddImage(const QUrl& url);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*);
|
||||
void mouseMoveEvent(QMouseEvent*);
|
||||
void mouseReleaseEvent(QMouseEvent*);
|
||||
void enterEvent(QEvent*);
|
||||
void leaveEvent(QEvent*);
|
||||
|
||||
private:
|
||||
struct Image {
|
||||
Image(const QUrl& url) : loading_(false), url_(url) {}
|
||||
|
||||
void SetImage(const QImage& image);
|
||||
|
||||
bool loading_;
|
||||
QUrl url_;
|
||||
QImage image_;
|
||||
QPixmap thumbnail_;
|
||||
};
|
||||
|
||||
QRect left() const;
|
||||
QRect right() const;
|
||||
QPolygon arrow(const QRect& rect, int direction) const;
|
||||
|
||||
void SetTimeLineActive(QTimeLine* timeline, bool active);
|
||||
|
||||
void DrawImage(QPainter* p, const QRect& rect, const Image& image);
|
||||
void DrawThumbnail(QPainter* p, const QRect& rect, const Image& image);
|
||||
|
||||
private slots:
|
||||
void ImageFetched(quint64 id, QNetworkReply* reply);
|
||||
|
||||
private:
|
||||
NetworkAccessManager* network_;
|
||||
|
||||
QMap<quint64, int> image_requests_;
|
||||
quint64 next_image_request_id_;
|
||||
|
||||
QList<Image> images_;
|
||||
int current_index_;
|
||||
|
||||
QTimeLine* base_timeline_;
|
||||
QTimeLine* left_timeline_;
|
||||
QTimeLine* right_timeline_;
|
||||
};
|
||||
|
||||
#endif // PRETTYIMAGEVIEW_H
|
Loading…
Reference in New Issue