1 /*
2 * Cantata
3 *
4 * Copyright (c) 2011-2020 Craig Drummond <craig.p.drummond@gmail.com>
5 *
6 * ----
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "titlewidget.h"
25 #include "support/squeezedtextlabel.h"
26 #include "support/utils.h"
27 #include "support/icon.h"
28 #include "support/proxystyle.h"
29 #include "support/monoicon.h"
30 #include "gui/stdactions.h"
31 #include "toolbutton.h"
32 #include "groupedview.h"
33 #ifdef Q_OS_MAC
34 #include "support/osxstyle.h"
35 #endif
36 #include "gui/covers.h"
37 #include <QAction>
38 #include <QImage>
39 #include <QPixmap>
40 #include <QHBoxLayout>
41 #include <QVBoxLayout>
42 #include <QEvent>
43 #include <QMouseEvent>
44 #include <QApplication>
45 #include <QPainter>
46
TitleWidget(QWidget * p)47 TitleWidget::TitleWidget(QWidget *p)
48 : QListView(p)
49 , pressed(false)
50 , controls(nullptr)
51 {
52 setProperty(ProxyStyle::constModifyFrameProp, ProxyStyle::VF_Side|ProxyStyle::VF_Top);
53 QHBoxLayout *layout=new QHBoxLayout(this);
54 QVBoxLayout *textLayout=new QVBoxLayout(nullptr);
55 image=new QLabel(this);
56 mainText=new SqueezedTextLabel(this);
57 subText=new SqueezedTextLabel(this);
58 QLabel *chevron=new QLabel(this);
59 ToolButton tb(this);
60 tb.setIcon(StdActions::self()->appendToPlayQueueAction->icon());
61 tb.ensurePolished();
62 chevron->setPixmap(MonoIcon::icon(Qt::LeftToRight==layoutDirection() ? FontAwesome::chevronleft : FontAwesome::chevronright, Utils::monoIconColor()).pixmap(tb.iconSize()));
63 chevron->setFixedSize(tb.iconSize());
64 QFont f=mainText->font();
65 subText->setFont(Utils::smallFont(f));
66 mainText->setFont(f);
67 if (f.pixelSize()>0) {
68 f.setPixelSize(f.pixelSize()*2);
69 } else {
70 f.setPointSizeF(f.pointSizeF()*2);
71 }
72 QPalette pal=mainText->palette();
73 QColor col(mainText->palette().windowText().color());
74 col.setAlphaF(0.5);
75 pal.setColor(QPalette::WindowText, col);
76 subText->setPalette(pal);
77 chevron->setFont(f);
78 mainText->ensurePolished();
79 subText->ensurePolished();
80 setToolTip(tr("Click to go back"));
81 int spacing = Utils::layoutSpacing(this);
82 layout->addItem(new QSpacerItem(spacing, 1, QSizePolicy::Fixed, QSizePolicy::Fixed));
83 layout->addWidget(chevron);
84 layout->addItem(new QSpacerItem(spacing, 1, QSizePolicy::Fixed, QSizePolicy::Fixed));
85 layout->addWidget(image);
86 layout->addItem(new QSpacerItem(spacing, 1, QSizePolicy::Fixed, QSizePolicy::Fixed));
87 textLayout->addWidget(mainText);
88 textLayout->addWidget(subText);
89 layout->addItem(textLayout);
90 mainText->setAttribute(Qt::WA_TransparentForMouseEvents);
91 subText->setAttribute(Qt::WA_TransparentForMouseEvents);
92 image->setAttribute(Qt::WA_TransparentForMouseEvents);
93 chevron->setAttribute(Qt::WA_TransparentForMouseEvents);
94 viewport()->installEventFilter(this);
95 viewport()->setAttribute(Qt::WA_Hover);
96 connect(Covers::self(), SIGNAL(cover(Song,QImage,QString)), this, SLOT(coverRetrieved(Song,QImage,QString)));
97 connect(Covers::self(), SIGNAL(coverUpdated(Song,QImage,QString)), this, SLOT(coverRetrieved(Song,QImage,QString)));
98 connect(Covers::self(), SIGNAL(artistImage(Song,QImage,QString)), this, SLOT(coverRetrieved(Song,QImage,QString)));
99 layout->setMargin(0);
100 layout->setSpacing(2);
101 textLayout->setMargin(0);
102 textLayout->setSpacing(2);
103 mainText->setAlignment(Qt::AlignBottom);
104 subText->setAlignment(Qt::AlignTop);
105 image->setAlignment(Qt::AlignCenter);
106 chevron->setAlignment(Qt::AlignCenter);
107 chevron->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
108 image->setFixedSize(GroupedView::coverSize(), GroupedView::coverSize());
109 setFixedHeight(image->height()+((frameWidth()+2)*2));
110 setFocusPolicy(Qt::NoFocus);
111 }
112
update(const Song & sng,const QIcon & icon,const QString & text,const QString & sub,bool showControls)113 void TitleWidget::update(const Song &sng, const QIcon &icon, const QString &text, const QString &sub, bool showControls)
114 {
115 song=sng;
116 image->setVisible(true);
117 mainText->setText(text);
118 subText->setText(sub);
119 if (!showControls) {
120 if (controls) {
121 controls->setVisible(false);
122 }
123 } else {
124 if (!controls) {
125 controls=new QWidget(this);
126 QVBoxLayout *l=new QVBoxLayout(controls);
127 l->setMargin(0);
128 l->setSpacing(0);
129 ToolButton *add=new ToolButton(this);
130 ToolButton *replace=new ToolButton(this);
131 add->setIcon(StdActions::self()->appendToPlayQueueAction->icon());
132 replace->setIcon(StdActions::self()->replacePlayQueueAction->icon());
133 int size=qMin(add->iconSize().height()+6, height()/2);
134 add->setFixedSize(QSize(size, size));
135 replace->setFixedSize(add->size());
136 add->setToolTip(tr("Add All To Play Queue"));
137 replace->setToolTip(tr("Add All And Replace Play Queue"));
138 l->addWidget(replace);
139 l->addWidget(add);
140 connect(add, SIGNAL(clicked()), this, SIGNAL(addToPlayQueue()));
141 connect(replace, SIGNAL(clicked()), this, SIGNAL(replacePlayQueue()));
142 static_cast<QHBoxLayout *>(layout())->addWidget(controls);
143 }
144 controls->setVisible(true);
145 }
146 subText->setVisible(!sub.isEmpty());
147 mainText->setAlignment(sub.isEmpty() ? Qt::AlignVCenter : Qt::AlignBottom);
148 if (!sng.isEmpty()) {
149 Covers::Image cImg=Covers::self()->requestImage(sng, true);
150 if (!cImg.img.isNull()) {
151 setImage(cImg.img);
152 return;
153 }
154 }
155 if (icon.isNull()) {
156 image->setVisible(false);
157 } else {
158 int iconPad=Utils::scaleForDpi(8);
159 int iconSize=image->width()-iconPad;
160 if (iconSize<44 && iconSize>=32) {
161 iconSize=32;
162 }
163 double dpr=DEVICE_PIXEL_RATIO();
164 QPixmap pix=Icon::getScaledPixmap(icon, iconSize*dpr, iconSize*dpr, 96*dpr);
165 pix.setDevicePixelRatio(dpr);
166 image->setPixmap(pix);
167 }
168 }
169
eventFilter(QObject * o,QEvent * event)170 bool TitleWidget::eventFilter(QObject *o, QEvent *event)
171 {
172 if (isEnabled()) {
173 switch(event->type()) {
174 case QEvent::HoverEnter: {
175 QPalette pal = qApp->palette();
176 #ifdef Q_OS_MAC
177 QColor col(OSXStyle::self()->viewPalette().color(QPalette::Highlight));
178 #else
179 QColor col(pal.color(QPalette::Highlight));
180 #endif
181 col.setAlphaF(0.2);
182 pal.setColor(QPalette::Base, col);
183 setPalette(pal);
184 break;
185 }
186 case QEvent::HoverLeave: {
187 QPalette pal = qApp->palette();
188 QColor col(pal.color(QPalette::Base));
189 pal.setColor(QPalette::Base, col);
190 setPalette(pal);
191 break;
192 }
193 case QEvent::MouseButtonPress:
194 if (Qt::LeftButton==static_cast<QMouseEvent *>(event)->button() && Qt::NoModifier==static_cast<QMouseEvent *>(event)->modifiers()) {
195 QPalette pal = qApp->palette();
196 #ifdef Q_OS_MAC
197 QColor col(OSXStyle::self()->viewPalette().color(QPalette::Highlight));
198 #else
199 QColor col(pal.color(QPalette::Highlight));
200 #endif
201 col.setAlphaF(0.5);
202 pal.setColor(QPalette::Base, col);
203 setPalette(pal);
204 pressed=true;
205 }
206 break;
207 case QEvent::MouseButtonRelease:
208 if (pressed && Qt::LeftButton==static_cast<QMouseEvent *>(event)->button() && !QApplication::overrideCursor()) {
209 actions().first()->trigger();
210 }
211 pressed=false;
212 break;
213 default:
214 break;
215 }
216 }
217 return QWidget::eventFilter(o, event);
218 }
219
coverRetrieved(const Song & s,const QImage & img,const QString & file)220 void TitleWidget::coverRetrieved(const Song &s, const QImage &img, const QString &file)
221 {
222 Q_UNUSED(file);
223 if (song.isEmpty() || img.isNull()) {
224 return;
225 }
226 if (song.albumArtistOrComposer()!=s.albumArtistOrComposer()) {
227 return;
228 }
229 if (s.isArtistImageRequest()!=song.isArtistImageRequest()) {
230 return;
231 }
232 if (s.isComposerImageRequest()!=song.isComposerImageRequest()) {
233 return;
234 }
235 if (!s.isComposerImageRequest() && !s.isArtistImageRequest() && s.album!=song.album) {
236 return;
237 }
238 setImage(img);
239 }
240
241
setImage(const QImage & img)242 void TitleWidget::setImage(const QImage &img)
243 {
244 double dpr=DEVICE_PIXEL_RATIO();
245 QPixmap pix=QPixmap::fromImage(img.scaled(image->width()*dpr, image->height()*dpr, Qt::KeepAspectRatio, Qt::SmoothTransformation));
246 pix.setDevicePixelRatio(dpr);
247 image->setPixmap(pix);
248 }
249
250 #include "moc_titlewidget.cpp"
251