1 /*
2 * Pixmap Dial, a custom Qt4 widget
3 * Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * For a full copy of the GNU General Public License see the COPYING file
16 */
17
18 #include "pixmapdial.hpp"
19
20 #include <cmath>
21
22 #include <QtCore/QTimer>
23 #include <QtGui/QPainter>
24 #include <QtGui/QPaintEvent>
25 #include <QtGui/QPainterPath>
26
PixmapDial(QWidget * parent)27 PixmapDial::PixmapDial(QWidget* parent)
28 : QDial(parent),
29 fPixmap(":/bitmaps/dial_01d.png"),
30 fPixmapNum("01"),
31 fCustomPaint(CUSTOM_PAINT_NULL),
32 fOrientation(fPixmap.width() > fPixmap.height() ? HORIZONTAL : VERTICAL),
33 fHovered(false),
34 fHoverStep(HOVER_MIN),
35 fLabel(""),
36 fLabelPos(0.0f, 0.0f),
37 fLabelWidth(0),
38 fLabelHeight(0),
39 fLabelGradient(0, 0, 0, 1)
40 {
41 fLabelFont.setPointSize(6);
42
43 if (palette().window().color().lightness() > 100)
44 {
45 // Light background
46 const QColor c(palette().dark().color());
47 fColor1 = c;
48 fColor2 = QColor(c.red(), c.green(), c.blue(), 0);
49 fColorT[0] = palette().buttonText().color();
50 fColorT[1] = palette().mid().color();
51 }
52 else
53 {
54 // Dark background
55 fColor1 = QColor(0, 0, 0, 255);
56 fColor2 = QColor(0, 0, 0, 0);
57 fColorT[0] = Qt::white;
58 fColorT[1] = Qt::darkGray;
59 }
60
61 updateSizes();
62 }
63
getSize() const64 int PixmapDial::getSize() const
65 {
66 return fSize;
67 }
68
setCustomPaint(CustomPaint paint)69 void PixmapDial::setCustomPaint(CustomPaint paint)
70 {
71 fCustomPaint = paint;
72 fLabelPos.setY(fSize + fLabelHeight/2);
73 update();
74 }
75
setEnabled(bool enabled)76 void PixmapDial::setEnabled(bool enabled)
77 {
78 if (isEnabled() != enabled)
79 {
80 fPixmap.load(QString(":/bitmaps/dial_%1%2.png").arg(fPixmapNum).arg(enabled ? "" : "d"));
81 updateSizes();
82 update();
83 }
84 QDial::setEnabled(enabled);
85 }
86
setLabel(QString label)87 void PixmapDial::setLabel(QString label)
88 {
89 fLabel = label;
90
91 fLabelWidth = QFontMetrics(font()).width(label);
92 fLabelHeight = QFontMetrics(font()).height();
93
94 fLabelPos.setX(float(fSize)/2.0f - float(fLabelWidth)/2.0f);
95 fLabelPos.setY(fSize + fLabelHeight);
96
97 fLabelGradient.setColorAt(0.0f, fColor1);
98 fLabelGradient.setColorAt(0.6f, fColor1);
99 fLabelGradient.setColorAt(1.0f, fColor2);
100
101 fLabelGradient.setStart(0, float(fSize)/2.0f);
102 fLabelGradient.setFinalStop(0, fSize + fLabelHeight + 5);
103
104 fLabelGradientRect = QRectF(float(fSize)/8.0f, float(fSize)/2.0f, float(fSize*6)/8.0f, fSize+fLabelHeight+5);
105 update();
106 }
107
setPixmap(int pixmapId)108 void PixmapDial::setPixmap(int pixmapId)
109 {
110 fPixmapNum.sprintf("%02i", pixmapId);
111 fPixmap.load(QString(":/bitmaps/dial_%1%2.png").arg(fPixmapNum).arg(isEnabled() ? "" : "d"));
112
113 if (fPixmap.width() > fPixmap.height())
114 fOrientation = HORIZONTAL;
115 else
116 fOrientation = VERTICAL;
117
118 updateSizes();
119 update();
120 }
121
minimumSizeHint() const122 QSize PixmapDial::minimumSizeHint() const
123 {
124 return QSize(fSize, fSize);
125 }
126
sizeHint() const127 QSize PixmapDial::sizeHint() const
128 {
129 return QSize(fSize, fSize);
130 }
131
updateSizes()132 void PixmapDial::updateSizes()
133 {
134 fWidth = fPixmap.width();
135 fHeight = fPixmap.height();
136
137 if (fWidth < 1)
138 fWidth = 1;
139
140 if (fHeight < 1)
141 fHeight = 1;
142
143 if (fOrientation == HORIZONTAL)
144 {
145 fSize = fHeight;
146 fCount = fWidth/fHeight;
147 }
148 else
149 {
150 fSize = fWidth;
151 fCount = fHeight/fWidth;
152 }
153
154 setMinimumSize(fSize, fSize + fLabelHeight + 5);
155 setMaximumSize(fSize, fSize + fLabelHeight + 5);
156 }
157
enterEvent(QEvent * event)158 void PixmapDial::enterEvent(QEvent* event)
159 {
160 fHovered = true;
161 if (fHoverStep == HOVER_MIN)
162 fHoverStep = HOVER_MIN + 1;
163 QDial::enterEvent(event);
164 }
165
leaveEvent(QEvent * event)166 void PixmapDial::leaveEvent(QEvent* event)
167 {
168 fHovered = false;
169 if (fHoverStep == HOVER_MAX)
170 fHoverStep = HOVER_MAX - 1;
171 QDial::leaveEvent(event);
172 }
173
paintEvent(QPaintEvent * event)174 void PixmapDial::paintEvent(QPaintEvent* event)
175 {
176 event->accept();
177
178 QPainter painter(this);
179 painter.save();
180 painter.setRenderHint(QPainter::Antialiasing, true);
181
182 if (! fLabel.isEmpty())
183 {
184 if (fCustomPaint == CUSTOM_PAINT_NULL)
185 {
186 painter.setPen(fColor2);
187 painter.setBrush(fLabelGradient);
188 painter.drawRect(fLabelGradientRect);
189 }
190
191 painter.setFont(fLabelFont);
192 painter.setPen(fColorT[isEnabled() ? 0 : 1]);
193 painter.drawText(fLabelPos, fLabel);
194 }
195
196 if (isEnabled())
197 {
198 float current = value()-minimum();
199 float divider = maximum()-minimum();
200
201 if (divider == 0.0f)
202 return;
203
204 float value = current/divider;
205 QRectF source, target(0.0f, 0.0f, fSize, fSize);
206
207 int xpos, ypos, per = (fCount-1)*value;
208
209 if (fOrientation == HORIZONTAL)
210 {
211 xpos = fSize*per;
212 ypos = 0.0f;
213 }
214 else
215 {
216 xpos = 0.0f;
217 ypos = fSize*per;
218 }
219
220 source = QRectF(xpos, ypos, fSize, fSize);
221 painter.drawPixmap(target, fPixmap, source);
222
223 // Custom knobs (Dry/Wet and Volume)
224 if (fCustomPaint == CUSTOM_PAINT_CARLA_WET || fCustomPaint == CUSTOM_PAINT_CARLA_VOL)
225 {
226 // knob color
227 QColor colorGreen(0x5D, 0xE7, 0x3D, 191 + fHoverStep*7);
228 QColor colorBlue(0x3E, 0xB8, 0xBE, 191 + fHoverStep*7);
229
230 // draw small circle
231 QRectF ballRect(8.0f, 8.0f, 15.0f, 15.0f);
232 QPainterPath ballPath;
233 ballPath.addEllipse(ballRect);
234 //painter.drawRect(ballRect);
235 float tmpValue = (0.375f + 0.75f*value);
236 float ballValue = tmpValue - std::floor(tmpValue);
237 QPointF ballPoint(ballPath.pointAtPercent(ballValue));
238
239 // draw arc
240 int startAngle = 216*16;
241 int spanAngle = -252*16*value;
242
243 if (fCustomPaint == CUSTOM_PAINT_CARLA_WET)
244 {
245 painter.setBrush(colorBlue);
246 painter.setPen(QPen(colorBlue, 0));
247 painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2f, 2.2f));
248
249 QConicalGradient gradient(15.5f, 15.5f, -45);
250 gradient.setColorAt(0.0f, colorBlue);
251 gradient.setColorAt(0.125f, colorBlue);
252 gradient.setColorAt(0.625f, colorGreen);
253 gradient.setColorAt(0.75f, colorGreen);
254 gradient.setColorAt(0.76f, colorGreen);
255 gradient.setColorAt(1.0f, colorGreen);
256 painter.setBrush(gradient);
257 painter.setPen(QPen(gradient, 3));
258 }
259 else
260 {
261 painter.setBrush(colorBlue);
262 painter.setPen(QPen(colorBlue, 0));
263 painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2f, 2.2f));
264
265 painter.setBrush(colorBlue);
266 painter.setPen(QPen(colorBlue, 3));
267 }
268
269 painter.drawArc(4.0f, 4.0f, 26.0f, 26.0f, startAngle, spanAngle);
270 }
271 // Custom knobs (L and R)
272 else if (fCustomPaint == CUSTOM_PAINT_CARLA_L || fCustomPaint == CUSTOM_PAINT_CARLA_R)
273 {
274 // knob color
275 QColor color(0xAD + fHoverStep*5, 0xD5 + fHoverStep*4, 0x4B + fHoverStep*5);
276
277 // draw small circle
278 QRectF ballRect(7.0f, 8.0f, 11.0f, 12.0f);
279 QPainterPath ballPath;
280 ballPath.addEllipse(ballRect);
281 //painter.drawRect(ballRect);
282 float tmpValue = (0.375f + 0.75f*value);
283 float ballValue = tmpValue - std::floor(tmpValue);
284 QPointF ballPoint(ballPath.pointAtPercent(ballValue));
285
286 painter.setBrush(color);
287 painter.setPen(QPen(color, 0));
288 painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0f, 2.0f));
289
290 int startAngle, spanAngle;
291
292 // draw arc
293 if (fCustomPaint == CUSTOM_PAINT_CARLA_L)
294 {
295 startAngle = 216*16;
296 spanAngle = -252.0*16*value;
297 }
298 else if (fCustomPaint == CUSTOM_PAINT_CARLA_R)
299 {
300 startAngle = 324.0*16;
301 spanAngle = 252.0*16*(1.0-value);
302 }
303 else
304 return;
305
306 painter.setPen(QPen(color, 2));
307 painter.drawArc(3.5f, 4.5f, 22.0f, 22.0f, startAngle, spanAngle);
308
309 if (HOVER_MIN < fHoverStep && fHoverStep < HOVER_MAX)
310 {
311 fHoverStep += fHovered ? 1 : -1;
312 QTimer::singleShot(20, this, SLOT(update()));
313 }
314 }
315
316 if (HOVER_MIN < fHoverStep && fHoverStep < HOVER_MAX)
317 {
318 fHoverStep += fHovered ? 1 : -1;
319 QTimer::singleShot(20, this, SLOT(update()));
320 }
321 }
322 else
323 {
324 QRectF target(0.0f, 0.0f, fSize, fSize);
325 painter.drawPixmap(target, fPixmap, target);
326 }
327
328 painter.restore();
329 }
330
resizeEvent(QResizeEvent * event)331 void PixmapDial::resizeEvent(QResizeEvent* event)
332 {
333 updateSizes();
334 QDial::resizeEvent(event);
335 }
336