1 /* This file is part of Clementine.
2 Copyright 2010, David Sansome <me@davidsansome.com>
3
4 Clementine is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 Clementine is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Clementine. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "freespacebar.h"
19 #include "core/utilities.h"
20
21 #include <QLinearGradient>
22 #include <QPainter>
23 #include <QPainterPath>
24
25 const int FreeSpaceBar::kBarHeight = 20;
26 const int FreeSpaceBar::kBarBorderRadius = 8;
27 const int FreeSpaceBar::kMarkerSpacing = 32;
28 const int FreeSpaceBar::kLabelBoxSize = 12;
29 const int FreeSpaceBar::kLabelBoxPadding = 4;
30 const int FreeSpaceBar::kLabelSpacing = 16;
31
32 const QRgb FreeSpaceBar::kColorBg1 = qRgb(214, 207, 200);
33 const QRgb FreeSpaceBar::kColorBg2 = qRgb(234, 226, 218);
34 const QRgb FreeSpaceBar::kColorAdd1 = qRgb(136, 180, 229);
35 const QRgb FreeSpaceBar::kColorAdd2 = qRgb(72, 146, 229);
36 const QRgb FreeSpaceBar::kColorBar1 = qRgb(250, 148, 76);
37 const QRgb FreeSpaceBar::kColorBar2 = qRgb(214, 102, 24);
38 const QRgb FreeSpaceBar::kColorBorder = qRgb(174, 168, 162);
39
FreeSpaceBar(QWidget * parent)40 FreeSpaceBar::FreeSpaceBar(QWidget* parent)
41 : QWidget(parent),
42 free_(100),
43 additional_(0),
44 total_(100),
45 free_text_(tr("Available")),
46 additional_text_(tr("New songs")),
47 used_text_(tr("Used")) {
48 setMinimumHeight(sizeHint().height());
49 }
50
sizeHint() const51 QSize FreeSpaceBar::sizeHint() const {
52 return QSize(150, kBarHeight + kLabelBoxPadding + fontMetrics().height());
53 }
54
paintEvent(QPaintEvent *)55 void FreeSpaceBar::paintEvent(QPaintEvent*) {
56 // Geometry
57 QRect bar_rect(rect());
58 bar_rect.setHeight(kBarHeight);
59
60 QRect reflection_rect(bar_rect);
61 reflection_rect.moveTop(reflection_rect.bottom());
62
63 QRect labels_rect(rect());
64 labels_rect.setTop(labels_rect.top() + kBarHeight + kLabelBoxPadding);
65
66 // Draw the reflection
67 // Create the reflected pixmap
68 QImage reflection(reflection_rect.size(),
69 QImage::Format_ARGB32_Premultiplied);
70 reflection.fill(palette().color(QPalette::Background).rgba());
71 QPainter p(&reflection);
72
73 // Set up the transformation
74 QTransform transform;
75 transform.scale(1.0, -1.0);
76 transform.translate(0.0, -reflection.height());
77 p.setTransform(transform);
78
79 // Draw the bar
80 DrawBar(&p, QRect(QPoint(0, 0), reflection.size()));
81
82 // Make it fade out towards the bottom
83 QLinearGradient fade_gradient(reflection.rect().topLeft(),
84 reflection.rect().bottomLeft());
85 fade_gradient.setColorAt(0.0, QColor(0, 0, 0, 0));
86 fade_gradient.setColorAt(1.0, QColor(0, 0, 0, 128));
87
88 p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
89 p.fillRect(reflection.rect(), fade_gradient);
90
91 p.end();
92
93 // Draw on the widget
94 p.begin(this);
95 DrawBar(&p, bar_rect);
96 p.drawImage(reflection_rect, reflection);
97 DrawText(&p, labels_rect);
98 }
99
DrawBar(QPainter * p,const QRect & r)100 void FreeSpaceBar::DrawBar(QPainter* p, const QRect& r) {
101 p->setRenderHint(QPainter::Antialiasing, true);
102 p->setRenderHint(QPainter::HighQualityAntialiasing, true);
103
104 QRect bar_rect(r);
105 bar_rect.setWidth(float(bar_rect.width()) * (float(total_ - free_) / total_));
106
107 QLinearGradient background_gradient(r.topLeft(), r.bottomLeft());
108 background_gradient.setColorAt(0, kColorBg1);
109 background_gradient.setColorAt(1, kColorBg2);
110
111 QLinearGradient bar_gradient(bar_rect.topLeft(), bar_rect.bottomLeft());
112 bar_gradient.setColorAt(0, kColorBar1);
113 bar_gradient.setColorAt(1, kColorBar2);
114
115 // Draw the background
116 p->setPen(Qt::NoPen);
117 p->setBrush(background_gradient);
118 p->drawRoundedRect(r, kBarBorderRadius, kBarBorderRadius);
119
120 // Create a path to use for clipping the bars
121 QPainterPath clip_path;
122 clip_path.addRoundedRect(r, kBarBorderRadius, kBarBorderRadius);
123 p->setClipPath(clip_path);
124
125 // Draw any additional space
126 if (additional_) {
127 QRect additional_rect(bar_rect);
128 additional_rect.setLeft(bar_rect.right());
129 additional_rect.setWidth(
130 float(r.width()) * (float(qMin(free_, additional_)) / total_) + 1);
131
132 QLinearGradient additional_gradient(additional_rect.topLeft(),
133 additional_rect.bottomLeft());
134 additional_gradient.setColorAt(0, kColorAdd1);
135 additional_gradient.setColorAt(1, kColorAdd2);
136
137 p->fillRect(additional_rect, additional_gradient);
138 }
139
140 // Draw the bar foreground
141 p->fillRect(bar_rect, bar_gradient);
142
143 // Draw a border
144 p->setClipping(false);
145 p->setPen(kColorBorder);
146 p->setBrush(Qt::NoBrush);
147 p->drawRoundedRect(r, kBarBorderRadius, kBarBorderRadius);
148
149 // Draw marker lines over the top every few pixels
150 p->setOpacity(0.35);
151 p->setRenderHint(QPainter::Antialiasing, false);
152 p->setPen(QPen(palette().color(QPalette::Light), 1.0));
153 for (int x = r.left() + kMarkerSpacing; x < r.right(); x += kMarkerSpacing) {
154 p->drawLine(x, r.top() + 2, x, r.bottom() - 2);
155 }
156
157 p->setOpacity(1.0);
158 }
159
DrawText(QPainter * p,const QRect & r)160 void FreeSpaceBar::DrawText(QPainter* p, const QRect& r) {
161 QFont small_font(font());
162 small_font.setPointSize(small_font.pointSize() - 1);
163 small_font.setBold(true);
164 QFontMetrics small_metrics(small_font);
165 p->setFont(small_font);
166
167 // Work out the geometry for the text
168 QList<Label> labels;
169 labels << Label(TextForSize(used_text_, total_ - free_), kColorBar1);
170 if (additional_)
171 labels << Label(TextForSize(additional_text_, additional_), kColorAdd1);
172 labels << Label(TextForSize(free_text_, free_ - additional_), kColorBg2);
173
174 int text_width = 0;
175 for (const Label& label : labels) {
176 text_width += kLabelBoxSize + kLabelBoxPadding + kLabelSpacing +
177 small_metrics.width(label.text);
178 }
179
180 // Draw the text
181 int x = (r.width() - text_width) / 2;
182
183 p->setRenderHint(QPainter::Antialiasing, false);
184 for (const Label& label : labels) {
185 const bool light = palette().color(QPalette::Base).value() > 128;
186
187 QRect box(x, r.top() + (r.height() - kLabelBoxSize) / 2, kLabelBoxSize,
188 kLabelBoxSize);
189 p->setPen(label.color.darker());
190 p->setBrush(label.color);
191 p->drawRect(box);
192
193 QRect text(x + kLabelBoxSize + kLabelBoxPadding, r.top(),
194 small_metrics.width(label.text), r.height());
195 p->setPen(light ? label.color.darker() : label.color);
196 p->drawText(text, Qt::AlignCenter, label.text);
197
198 x += kLabelBoxSize + kLabelBoxPadding + kLabelSpacing +
199 small_metrics.width(label.text);
200 }
201 }
202
TextForSize(const QString & prefix,qint64 size) const203 QString FreeSpaceBar::TextForSize(const QString& prefix, qint64 size) const {
204 QString ret;
205 if (size > 0)
206 ret = Utilities::PrettySize(size);
207 else if (size < 0)
208 ret = "-" + Utilities::PrettySize(-size);
209 else
210 ret = "0 MB";
211
212 if (!prefix.isEmpty()) ret.prepend(prefix + " ");
213 return ret;
214 }
215