Chris@923
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@923
|
2
|
Chris@923
|
3 /*
|
Chris@923
|
4 Sonic Visualiser
|
Chris@923
|
5 An audio file viewer and annotation editor.
|
Chris@923
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@923
|
7
|
Chris@923
|
8 This program is free software; you can redistribute it and/or
|
Chris@923
|
9 modify it under the terms of the GNU General Public License as
|
Chris@923
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@923
|
11 License, or (at your option) any later version. See the file
|
Chris@923
|
12 COPYING included with this distribution for more information.
|
Chris@923
|
13 */
|
Chris@923
|
14
|
Chris@923
|
15 #include "LevelPanWidget.h"
|
Chris@923
|
16
|
Chris@923
|
17 #include <QPainter>
|
Chris@923
|
18 #include <QMouseEvent>
|
Chris@923
|
19 #include <QWheelEvent>
|
Chris@923
|
20
|
Chris@923
|
21 #include "layer/ColourMapper.h"
|
Chris@925
|
22 #include "base/AudioLevel.h"
|
Chris@923
|
23
|
Chris@1176
|
24 #include "WidgetScale.h"
|
Chris@1176
|
25
|
Chris@923
|
26 #include <iostream>
|
Chris@926
|
27 #include <cmath>
|
Chris@940
|
28 #include <cassert>
|
Chris@923
|
29
|
Chris@923
|
30 using std::cerr;
|
Chris@923
|
31 using std::endl;
|
Chris@923
|
32
|
Chris@1301
|
33 /**
|
Chris@1301
|
34 * Gain and pan scales:
|
Chris@1301
|
35 *
|
Chris@1301
|
36 * Gain: we have 5 circles vertically in the display, each of which
|
Chris@1301
|
37 * has half-circle and full-circle versions, and we also have "no
|
Chris@1301
|
38 * circles", so there are in total 11 distinct levels, which we refer
|
Chris@1301
|
39 * to as "notches" and number 0-10. (We use "notch" because "level" is
|
Chris@1301
|
40 * used by the external API to refer to audio gain.)
|
Chris@1301
|
41 *
|
Chris@1301
|
42 * i.e. the levels are represented by these (schematic, rotated to
|
Chris@1301
|
43 * horizontal) displays:
|
Chris@1301
|
44 *
|
Chris@1301
|
45 * 0 X
|
Chris@1301
|
46 * 1 [
|
Chris@1301
|
47 * 2 []
|
Chris@1301
|
48 * 3 [][
|
Chris@1301
|
49 * ...
|
Chris@1301
|
50 * 9 [][][][][
|
Chris@1301
|
51 * 10 [][][][][]
|
Chris@1301
|
52 *
|
Chris@1301
|
53 * If we have mute enabled, then we map the range 0-10 to gain using
|
Chris@1301
|
54 * AudioLevel::fader_to_* with the ShortFader type, which treats fader
|
Chris@1301
|
55 * 0 as muted. If mute is disabled, then we map the range 1-10.
|
Chris@1301
|
56 *
|
Chris@1301
|
57 * We can also disable half-circles, which leaves the range unchanged
|
Chris@1301
|
58 * but limits the notches to even values.
|
Chris@1301
|
59 *
|
Chris@1301
|
60 * Pan: we have 5 columns with no finer resolution, so we only have 2
|
Chris@1301
|
61 * possible pan values on each side of centre.
|
Chris@1301
|
62 */
|
Chris@1301
|
63
|
Chris@923
|
64 static const int maxPan = 2; // range is -maxPan to maxPan
|
Chris@923
|
65
|
Chris@923
|
66 LevelPanWidget::LevelPanWidget(QWidget *parent) :
|
Chris@923
|
67 QWidget(parent),
|
Chris@1301
|
68 m_minNotch(0),
|
Chris@1301
|
69 m_maxNotch(10),
|
Chris@1301
|
70 m_notch(m_maxNotch),
|
Chris@923
|
71 m_pan(0),
|
Chris@1177
|
72 m_monitorLeft(-1),
|
Chris@1177
|
73 m_monitorRight(-1),
|
Chris@940
|
74 m_editable(true),
|
Chris@1249
|
75 m_editing(false),
|
Chris@1301
|
76 m_includeMute(true),
|
Chris@1303
|
77 m_includeHalfSteps(true)
|
Chris@923
|
78 {
|
Chris@1191
|
79 setToolTip(tr("Drag vertically to adjust level, horizontally to adjust pan"));
|
Chris@1201
|
80 setLevel(1.0);
|
Chris@1201
|
81 setPan(0.0);
|
Chris@923
|
82 }
|
Chris@923
|
83
|
Chris@923
|
84 LevelPanWidget::~LevelPanWidget()
|
Chris@923
|
85 {
|
Chris@923
|
86 }
|
Chris@923
|
87
|
Chris@1249
|
88 void
|
Chris@1249
|
89 LevelPanWidget::setToDefault()
|
Chris@1249
|
90 {
|
Chris@1249
|
91 setLevel(1.0);
|
Chris@1249
|
92 setPan(0.0);
|
Chris@1250
|
93 emitLevelChanged();
|
Chris@1250
|
94 emitPanChanged();
|
Chris@1249
|
95 }
|
Chris@1249
|
96
|
Chris@929
|
97 QSize
|
Chris@929
|
98 LevelPanWidget::sizeHint() const
|
Chris@929
|
99 {
|
Chris@1176
|
100 return WidgetScale::scaleQSize(QSize(40, 40));
|
Chris@929
|
101 }
|
Chris@929
|
102
|
Chris@1301
|
103 int
|
Chris@1301
|
104 LevelPanWidget::clampNotch(int notch) const
|
Chris@940
|
105 {
|
Chris@1301
|
106 if (notch < m_minNotch) notch = m_minNotch;
|
Chris@1301
|
107 if (notch > m_maxNotch) notch = m_maxNotch;
|
Chris@1301
|
108 if (!m_includeHalfSteps) {
|
Chris@1301
|
109 notch = (notch / 2) * 2;
|
Chris@1301
|
110 }
|
Chris@1301
|
111 return notch;
|
Chris@940
|
112 }
|
Chris@940
|
113
|
Chris@1177
|
114 int
|
Chris@1302
|
115 LevelPanWidget::clampPan(int pan) const
|
Chris@1302
|
116 {
|
Chris@1302
|
117 if (pan < -maxPan) pan = -maxPan;
|
Chris@1302
|
118 if (pan > maxPan) pan = maxPan;
|
Chris@1302
|
119 return pan;
|
Chris@1302
|
120 }
|
Chris@1302
|
121
|
Chris@1302
|
122 int
|
Chris@1301
|
123 LevelPanWidget::audioLevelToNotch(float audioLevel) const
|
Chris@1177
|
124 {
|
Chris@1301
|
125 int notch = AudioLevel::multiplier_to_fader
|
Chris@1301
|
126 (audioLevel, m_maxNotch, AudioLevel::ShortFader);
|
Chris@1301
|
127 return clampNotch(notch);
|
Chris@1177
|
128 }
|
Chris@1177
|
129
|
Chris@1177
|
130 float
|
Chris@1301
|
131 LevelPanWidget::notchToAudioLevel(int notch) const
|
Chris@1177
|
132 {
|
Chris@1301
|
133 return float(AudioLevel::fader_to_multiplier
|
Chris@1301
|
134 (notch, m_maxNotch, AudioLevel::ShortFader));
|
Chris@1177
|
135 }
|
Chris@1177
|
136
|
Chris@923
|
137 void
|
Chris@1301
|
138 LevelPanWidget::setLevel(float level)
|
Chris@923
|
139 {
|
Chris@1301
|
140 int notch = audioLevelToNotch(level);
|
Chris@1301
|
141 if (notch != m_notch) {
|
Chris@1301
|
142 m_notch = notch;
|
Chris@1266
|
143 float convertsTo = getLevel();
|
Chris@1301
|
144 if (fabsf(convertsTo - level) > 1e-5) {
|
Chris@1266
|
145 emitLevelChanged();
|
Chris@1266
|
146 }
|
Chris@1266
|
147 update();
|
Chris@925
|
148 }
|
Chris@923
|
149 }
|
Chris@923
|
150
|
Chris@940
|
151 float
|
Chris@940
|
152 LevelPanWidget::getLevel() const
|
Chris@940
|
153 {
|
Chris@1301
|
154 return notchToAudioLevel(m_notch);
|
Chris@1177
|
155 }
|
Chris@1177
|
156
|
Chris@1177
|
157 int
|
Chris@1301
|
158 LevelPanWidget::audioPanToPan(float audioPan) const
|
Chris@1177
|
159 {
|
Chris@1177
|
160 int pan = int(round(audioPan * maxPan));
|
Chris@1302
|
161 pan = clampPan(pan);
|
Chris@1177
|
162 return pan;
|
Chris@1177
|
163 }
|
Chris@1177
|
164
|
Chris@1177
|
165 float
|
Chris@1301
|
166 LevelPanWidget::panToAudioPan(int pan) const
|
Chris@1177
|
167 {
|
Chris@1177
|
168 return float(pan) / float(maxPan);
|
Chris@1177
|
169 }
|
Chris@1177
|
170
|
Chris@1177
|
171 void
|
Chris@1177
|
172 LevelPanWidget::setPan(float fpan)
|
Chris@1177
|
173 {
|
Chris@1177
|
174 int pan = audioPanToPan(fpan);
|
Chris@1177
|
175 if (pan != m_pan) {
|
Chris@1177
|
176 m_pan = pan;
|
Chris@1177
|
177 update();
|
Chris@940
|
178 }
|
Chris@940
|
179 }
|
Chris@940
|
180
|
Chris@1177
|
181 float
|
Chris@1177
|
182 LevelPanWidget::getPan() const
|
Chris@1177
|
183 {
|
Chris@1177
|
184 return panToAudioPan(m_pan);
|
Chris@1177
|
185 }
|
Chris@1177
|
186
|
Chris@923
|
187 void
|
Chris@1177
|
188 LevelPanWidget::setMonitoringLevels(float left, float right)
|
Chris@923
|
189 {
|
Chris@1177
|
190 m_monitorLeft = left;
|
Chris@1177
|
191 m_monitorRight = right;
|
Chris@923
|
192 update();
|
Chris@923
|
193 }
|
Chris@923
|
194
|
Chris@940
|
195 bool
|
Chris@940
|
196 LevelPanWidget::isEditable() const
|
Chris@940
|
197 {
|
Chris@940
|
198 return m_editable;
|
Chris@940
|
199 }
|
Chris@940
|
200
|
Chris@940
|
201 bool
|
Chris@940
|
202 LevelPanWidget::includesMute() const
|
Chris@940
|
203 {
|
Chris@940
|
204 return m_includeMute;
|
Chris@940
|
205 }
|
Chris@940
|
206
|
Chris@923
|
207 void
|
Chris@923
|
208 LevelPanWidget::setEditable(bool editable)
|
Chris@923
|
209 {
|
Chris@923
|
210 m_editable = editable;
|
Chris@923
|
211 update();
|
Chris@923
|
212 }
|
Chris@923
|
213
|
Chris@940
|
214 void
|
Chris@940
|
215 LevelPanWidget::setIncludeMute(bool include)
|
Chris@923
|
216 {
|
Chris@940
|
217 m_includeMute = include;
|
Chris@1301
|
218 if (m_includeMute) {
|
Chris@1301
|
219 m_minNotch = 0;
|
Chris@1301
|
220 } else {
|
Chris@1301
|
221 m_minNotch = 1;
|
Chris@1301
|
222 }
|
Chris@940
|
223 emitLevelChanged();
|
Chris@940
|
224 update();
|
Chris@923
|
225 }
|
Chris@923
|
226
|
Chris@923
|
227 void
|
Chris@923
|
228 LevelPanWidget::emitLevelChanged()
|
Chris@923
|
229 {
|
Chris@923
|
230 emit levelChanged(getLevel());
|
Chris@923
|
231 }
|
Chris@923
|
232
|
Chris@923
|
233 void
|
Chris@923
|
234 LevelPanWidget::emitPanChanged()
|
Chris@923
|
235 {
|
Chris@923
|
236 emit panChanged(getPan());
|
Chris@923
|
237 }
|
Chris@923
|
238
|
Chris@923
|
239 void
|
Chris@923
|
240 LevelPanWidget::mousePressEvent(QMouseEvent *e)
|
Chris@923
|
241 {
|
Chris@1249
|
242 if (e->button() == Qt::MidButton ||
|
Chris@1249
|
243 ((e->button() == Qt::LeftButton) &&
|
Chris@1249
|
244 (e->modifiers() & Qt::ControlModifier))) {
|
Chris@1249
|
245 setToDefault();
|
Chris@1249
|
246 } else if (e->button() == Qt::LeftButton) {
|
Chris@1249
|
247 m_editing = true;
|
Chris@1249
|
248 mouseMoveEvent(e);
|
Chris@1249
|
249 }
|
Chris@1249
|
250 }
|
Chris@1249
|
251
|
Chris@1249
|
252 void
|
Chris@1249
|
253 LevelPanWidget::mouseReleaseEvent(QMouseEvent *e)
|
Chris@1249
|
254 {
|
Chris@923
|
255 mouseMoveEvent(e);
|
Chris@1249
|
256 m_editing = false;
|
Chris@923
|
257 }
|
Chris@923
|
258
|
Chris@923
|
259 void
|
Chris@923
|
260 LevelPanWidget::mouseMoveEvent(QMouseEvent *e)
|
Chris@923
|
261 {
|
Chris@923
|
262 if (!m_editable) return;
|
Chris@1249
|
263 if (!m_editing) return;
|
Chris@923
|
264
|
Chris@1301
|
265 int notch = coordsToNotch(rect(), e->pos());
|
Chris@1301
|
266 int pan = coordsToPan(rect(), e->pos());
|
Chris@1301
|
267
|
Chris@1301
|
268 if (notch == m_notch && pan == m_pan) {
|
Chris@1266
|
269 return;
|
Chris@923
|
270 }
|
Chris@1301
|
271 if (notch != m_notch) {
|
Chris@1301
|
272 m_notch = notch;
|
Chris@1266
|
273 emitLevelChanged();
|
Chris@923
|
274 }
|
Chris@923
|
275 if (pan != m_pan) {
|
Chris@1266
|
276 m_pan = pan;
|
Chris@1266
|
277 emitPanChanged();
|
Chris@923
|
278 }
|
Chris@923
|
279 update();
|
Chris@923
|
280 }
|
Chris@923
|
281
|
Chris@923
|
282 void
|
Chris@923
|
283 LevelPanWidget::wheelEvent(QWheelEvent *e)
|
Chris@923
|
284 {
|
Chris@1303
|
285 int delta = m_wheelCounter.count(e);
|
Chris@1303
|
286
|
Chris@1303
|
287 if (delta == 0) {
|
Chris@1302
|
288 return;
|
Chris@1302
|
289 }
|
Chris@1302
|
290
|
Chris@1303
|
291 if (e->modifiers() & Qt::ControlModifier) {
|
Chris@1303
|
292 m_pan = clampPan(m_pan + delta);
|
Chris@1303
|
293 emitPanChanged();
|
Chris@1303
|
294 update();
|
Chris@1302
|
295 } else {
|
Chris@1303
|
296 m_notch = clampNotch(m_notch + delta);
|
Chris@1303
|
297 emitLevelChanged();
|
Chris@1303
|
298 update();
|
Chris@923
|
299 }
|
Chris@923
|
300 }
|
Chris@923
|
301
|
Chris@1301
|
302 int
|
Chris@1301
|
303 LevelPanWidget::coordsToNotch(QRectF rect, QPointF loc) const
|
Chris@923
|
304 {
|
Chris@1301
|
305 double h = rect.height();
|
Chris@1301
|
306
|
Chris@1301
|
307 int nnotch = m_maxNotch + 1;
|
Chris@1301
|
308 double cell = h / nnotch;
|
Chris@1301
|
309
|
Chris@1301
|
310 int notch = int((h - (loc.y() - rect.y())) / cell);
|
Chris@1301
|
311 notch = clampNotch(notch);
|
Chris@1301
|
312
|
Chris@1301
|
313 return notch;
|
Chris@1301
|
314 }
|
Chris@1301
|
315
|
Chris@1301
|
316 int
|
Chris@1301
|
317 LevelPanWidget::coordsToPan(QRectF rect, QPointF loc) const
|
Chris@1301
|
318 {
|
Chris@1301
|
319 double w = rect.width();
|
Chris@929
|
320
|
Chris@923
|
321 int npan = maxPan * 2 + 1;
|
Chris@1301
|
322 double cell = w / npan;
|
Chris@929
|
323
|
Chris@1301
|
324 int pan = int((loc.x() - rect.x()) / cell) - maxPan;
|
Chris@1302
|
325 pan = clampPan(pan);
|
Chris@1301
|
326
|
Chris@1301
|
327 return pan;
|
Chris@923
|
328 }
|
Chris@923
|
329
|
Chris@923
|
330 QSizeF
|
Chris@929
|
331 LevelPanWidget::cellSize(QRectF rect) const
|
Chris@923
|
332 {
|
Chris@929
|
333 double w = rect.width(), h = rect.height();
|
Chris@1301
|
334 int ncol = maxPan * 2 + 1;
|
Chris@1301
|
335 int nrow = m_maxNotch/2;
|
Chris@1301
|
336 double wcell = w / ncol, hcell = h / nrow;
|
Chris@923
|
337 return QSizeF(wcell, hcell);
|
Chris@923
|
338 }
|
Chris@923
|
339
|
Chris@923
|
340 QPointF
|
Chris@1301
|
341 LevelPanWidget::cellCentre(QRectF rect, int row, int col) const
|
Chris@923
|
342 {
|
Chris@929
|
343 QSizeF cs = cellSize(rect);
|
Chris@1301
|
344 return QPointF(rect.x() +
|
Chris@1301
|
345 cs.width() * (col + maxPan) + cs.width() / 2.,
|
Chris@1301
|
346 rect.y() + rect.height() -
|
Chris@1301
|
347 cs.height() * (row + 1) + cs.height() / 2.);
|
Chris@923
|
348 }
|
Chris@923
|
349
|
Chris@923
|
350 QSizeF
|
Chris@929
|
351 LevelPanWidget::cellLightSize(QRectF rect) const
|
Chris@923
|
352 {
|
cannam@1307
|
353 double extent = 0.7;
|
Chris@929
|
354 QSizeF cs = cellSize(rect);
|
Chris@923
|
355 double m = std::min(cs.width(), cs.height());
|
Chris@923
|
356 return QSizeF(m * extent, m * extent);
|
Chris@923
|
357 }
|
Chris@923
|
358
|
Chris@923
|
359 QRectF
|
Chris@1301
|
360 LevelPanWidget::cellLightRect(QRectF rect, int row, int col) const
|
Chris@923
|
361 {
|
Chris@929
|
362 QSizeF cls = cellLightSize(rect);
|
Chris@1301
|
363 QPointF cc = cellCentre(rect, row, col);
|
Chris@923
|
364 return QRectF(cc.x() - cls.width() / 2.,
|
Chris@1266
|
365 cc.y() - cls.height() / 2.,
|
Chris@1266
|
366 cls.width(),
|
Chris@1266
|
367 cls.height());
|
Chris@923
|
368 }
|
Chris@923
|
369
|
Chris@923
|
370 double
|
Chris@929
|
371 LevelPanWidget::thinLineWidth(QRectF rect) const
|
Chris@923
|
372 {
|
Chris@929
|
373 double tw = ceil(rect.width() / (maxPan * 2. * 10.));
|
Chris@1301
|
374 double th = ceil(rect.height() / (m_maxNotch/2 * 10.));
|
Chris@923
|
375 return std::min(th, tw);
|
Chris@923
|
376 }
|
Chris@923
|
377
|
Chris@1304
|
378 double
|
Chris@1304
|
379 LevelPanWidget::cornerRadius(QRectF rect) const
|
Chris@1304
|
380 {
|
Chris@1304
|
381 QSizeF cs = cellSize(rect);
|
Chris@1304
|
382 double m = std::min(cs.width(), cs.height());
|
Chris@1304
|
383 return m / 5;
|
Chris@1304
|
384 }
|
Chris@1304
|
385
|
Chris@1301
|
386 QRectF
|
Chris@1301
|
387 LevelPanWidget::cellOutlineRect(QRectF rect, int row, int col) const
|
Chris@941
|
388 {
|
Chris@1301
|
389 QRectF clr = cellLightRect(rect, row, col);
|
cannam@1307
|
390 double adj = thinLineWidth(rect)/2 + 0.5;
|
Chris@1301
|
391 return clr.adjusted(-adj, -adj, adj, adj);
|
Chris@1301
|
392 }
|
Chris@1301
|
393
|
Chris@1301
|
394 QColor
|
Chris@1306
|
395 LevelPanWidget::cellToColour(int cell) const
|
Chris@1301
|
396 {
|
Chris@1306
|
397 if (cell < 1) return Qt::black;
|
Chris@1306
|
398 if (cell < 2) return QColor(80, 0, 0);
|
Chris@1306
|
399 if (cell < 3) return QColor(160, 0, 0);
|
Chris@1306
|
400 if (cell < 4) return QColor(255, 0, 0);
|
Chris@1301
|
401 return QColor(255, 255, 0);
|
Chris@941
|
402 }
|
Chris@941
|
403
|
Chris@923
|
404 void
|
Chris@929
|
405 LevelPanWidget::renderTo(QPaintDevice *dev, QRectF rect, bool asIfEditable) const
|
Chris@923
|
406 {
|
Chris@929
|
407 QPainter paint(dev);
|
Chris@923
|
408
|
Chris@923
|
409 paint.setRenderHint(QPainter::Antialiasing, true);
|
Chris@923
|
410
|
Chris@929
|
411 double thin = thinLineWidth(rect);
|
Chris@1304
|
412 double radius = cornerRadius(rect);
|
Chris@938
|
413
|
Chris@1301
|
414 QColor columnBackground = QColor(180, 180, 180);
|
Chris@1306
|
415
|
Chris@1306
|
416 bool monitoring = (m_monitorLeft > 0.f || m_monitorRight > 0.f);
|
Chris@1306
|
417
|
Chris@1306
|
418 QPen pen;
|
Chris@1306
|
419 if (isEnabled()) {
|
Chris@1306
|
420 pen.setColor(Qt::black);
|
Chris@1306
|
421 } else {
|
Chris@1306
|
422 pen.setColor(Qt::darkGray);
|
Chris@1306
|
423 }
|
Chris@1306
|
424 pen.setWidthF(thin);
|
Chris@1306
|
425 pen.setCapStyle(Qt::FlatCap);
|
Chris@1306
|
426 pen.setJoinStyle(Qt::MiterJoin);
|
Chris@923
|
427
|
Chris@923
|
428 for (int pan = -maxPan; pan <= maxPan; ++pan) {
|
Chris@1306
|
429
|
Chris@1306
|
430 paint.setPen(Qt::NoPen);
|
Chris@1306
|
431 paint.setBrush(columnBackground);
|
Chris@1306
|
432
|
Chris@1304
|
433 QRectF top = cellOutlineRect(rect, m_maxNotch/2 - 1, pan);
|
Chris@1304
|
434 QRectF bottom = cellOutlineRect(rect, 0, pan);
|
Chris@1304
|
435 paint.drawRoundedRect(QRectF(top.x(),
|
Chris@1304
|
436 top.y(),
|
Chris@1304
|
437 top.width(),
|
Chris@1304
|
438 bottom.y() + bottom.height() - top.y()),
|
Chris@1304
|
439 radius, radius);
|
Chris@924
|
440
|
Chris@1306
|
441 if (!asIfEditable && m_includeMute && m_notch == 0) {
|
Chris@1306
|
442 // We will instead be drawing a single big X for mute,
|
Chris@1306
|
443 // after this loop
|
Chris@1306
|
444 continue;
|
Chris@1306
|
445 }
|
Chris@1306
|
446
|
Chris@1306
|
447 if (!monitoring && m_pan != pan) {
|
Chris@1306
|
448 continue;
|
Chris@1306
|
449 }
|
Chris@1306
|
450
|
Chris@1306
|
451 int monitorNotch = 0;
|
Chris@1306
|
452 if (monitoring) {
|
Chris@1306
|
453 float rprop = float(pan - (-maxPan)) / float(maxPan * 2);
|
Chris@1306
|
454 float lprop = float(maxPan - pan) / float(maxPan * 2);
|
Chris@1306
|
455 float monitorLevel =
|
Chris@1306
|
456 lprop * m_monitorLeft * m_monitorLeft +
|
Chris@1306
|
457 rprop * m_monitorRight * m_monitorRight;
|
Chris@1306
|
458 monitorNotch = audioLevelToNotch(monitorLevel);
|
Chris@1306
|
459 }
|
Chris@1306
|
460
|
Chris@1306
|
461 int firstCell = 0;
|
Chris@1306
|
462 int lastCell = m_maxNotch / 2 - 1;
|
Chris@1306
|
463
|
Chris@1306
|
464 for (int cell = firstCell; cell <= lastCell; ++cell) {
|
Chris@1306
|
465
|
Chris@1306
|
466 QRectF clr = cellLightRect(rect, cell, pan);
|
Chris@1306
|
467
|
Chris@1306
|
468 if (m_includeMute && m_pan == pan && m_notch == 0) {
|
Chris@1306
|
469 // X for mute in the bottom cell
|
Chris@1306
|
470 paint.setPen(pen);
|
Chris@1306
|
471 paint.drawLine(clr.topLeft(), clr.bottomRight());
|
Chris@1306
|
472 paint.drawLine(clr.bottomLeft(), clr.topRight());
|
Chris@1306
|
473 break;
|
Chris@1306
|
474 }
|
Chris@1306
|
475
|
Chris@1306
|
476 const int none = 0, half = 1, full = 2;
|
Chris@1306
|
477
|
Chris@1306
|
478 int fill = none;
|
Chris@1306
|
479
|
Chris@1306
|
480 int outline = none;
|
Chris@1306
|
481 if (m_pan == pan && m_notch > cell * 2 + 1) {
|
Chris@1306
|
482 outline = full;
|
Chris@1306
|
483 } else if (m_pan == pan && m_notch == cell * 2 + 1) {
|
Chris@1306
|
484 outline = half;
|
Chris@1306
|
485 }
|
Chris@1306
|
486
|
Chris@1306
|
487 if (monitoring) {
|
Chris@1306
|
488 if (monitorNotch > cell * 2 + 1) {
|
Chris@1306
|
489 fill = full;
|
Chris@1306
|
490 } else if (monitorNotch == cell * 2 + 1) {
|
Chris@1306
|
491 fill = half;
|
Chris@1306
|
492 }
|
Chris@1306
|
493 } else {
|
Chris@1306
|
494 if (isEnabled()) {
|
Chris@1306
|
495 fill = outline;
|
Chris@1306
|
496 }
|
Chris@1306
|
497 }
|
Chris@1306
|
498
|
Chris@1306
|
499 // If one of {fill, outline} is "full" and the other is
|
Chris@1306
|
500 // "half", then we draw the "half" one first (because we
|
Chris@1306
|
501 // need to erase half of it)
|
Chris@1306
|
502
|
Chris@1306
|
503 if (fill == half || outline == half) {
|
Chris@1306
|
504 if (fill == half) {
|
Chris@1306
|
505 paint.setBrush(cellToColour(cell));
|
Chris@1306
|
506 } else {
|
Chris@1306
|
507 paint.setBrush(Qt::NoBrush);
|
Chris@1306
|
508 }
|
Chris@1306
|
509 if (outline == half) {
|
Chris@1306
|
510 paint.setPen(pen);
|
Chris@1306
|
511 } else {
|
Chris@1306
|
512 paint.setPen(Qt::NoPen);
|
Chris@1306
|
513 }
|
Chris@1306
|
514
|
Chris@1306
|
515 paint.drawRoundedRect(clr, radius, radius);
|
Chris@1306
|
516
|
Chris@1306
|
517 paint.setBrush(columnBackground);
|
Chris@1306
|
518
|
Chris@1306
|
519 if (cell == lastCell) {
|
Chris@1306
|
520 QPen bgpen(pen);
|
Chris@1306
|
521 bgpen.setColor(columnBackground);
|
Chris@1306
|
522 paint.setPen(bgpen);
|
Chris@1306
|
523 paint.drawRoundedRect(QRectF(clr.x(),
|
Chris@1306
|
524 clr.y(),
|
Chris@1306
|
525 clr.width(),
|
Chris@1306
|
526 clr.height()/4),
|
Chris@1306
|
527 radius, radius);
|
Chris@1306
|
528 paint.drawRect(QRectF(clr.x(),
|
Chris@1306
|
529 clr.y() + clr.height()/4,
|
Chris@1306
|
530 clr.width(),
|
Chris@1306
|
531 clr.height()/4));
|
Chris@1306
|
532 } else {
|
Chris@1306
|
533 paint.setPen(Qt::NoPen);
|
cannam@1307
|
534 QRectF cor = cellOutlineRect(rect, cell, pan);
|
cannam@1307
|
535 paint.drawRect(QRectF(cor.x(),
|
cannam@1307
|
536 cor.y() - 0.5,
|
cannam@1307
|
537 cor.width(),
|
cannam@1307
|
538 cor.height()/2));
|
Chris@1306
|
539 }
|
Chris@1306
|
540 }
|
Chris@1306
|
541
|
Chris@1306
|
542 if (outline == full || fill == full) {
|
Chris@1306
|
543
|
Chris@1306
|
544 if (fill == full) {
|
Chris@1306
|
545 paint.setBrush(cellToColour(cell));
|
Chris@1306
|
546 } else {
|
Chris@1306
|
547 paint.setBrush(Qt::NoBrush);
|
Chris@1306
|
548 }
|
Chris@1306
|
549 if (outline == full) {
|
Chris@1306
|
550 paint.setPen(pen);
|
Chris@1306
|
551 } else {
|
Chris@1306
|
552 paint.setPen(Qt::NoPen);
|
Chris@1306
|
553 }
|
Chris@1306
|
554
|
Chris@1306
|
555 paint.drawRoundedRect(clr, radius, radius);
|
Chris@1306
|
556 }
|
Chris@1306
|
557 }
|
Chris@1301
|
558 }
|
Chris@1301
|
559
|
Chris@1301
|
560 if (!asIfEditable && m_includeMute && m_notch == 0) {
|
Chris@1301
|
561 // The X for mute takes up the whole display when we're not
|
Chris@1301
|
562 // being rendered in editable style
|
Chris@1306
|
563 pen.setColor(Qt::black);
|
Chris@1301
|
564 pen.setWidthF(thin * 2);
|
Chris@1301
|
565 pen.setCapStyle(Qt::RoundCap);
|
Chris@1301
|
566 paint.setPen(pen);
|
Chris@1301
|
567 paint.drawLine(cellCentre(rect, 0, -maxPan),
|
Chris@1301
|
568 cellCentre(rect, m_maxNotch/2 - 1, maxPan));
|
Chris@1301
|
569 paint.drawLine(cellCentre(rect, m_maxNotch/2 - 1, -maxPan),
|
Chris@1301
|
570 cellCentre(rect, 0, maxPan));
|
Chris@1177
|
571 }
|
Chris@923
|
572 }
|
Chris@923
|
573
|
Chris@929
|
574 void
|
Chris@929
|
575 LevelPanWidget::paintEvent(QPaintEvent *)
|
Chris@929
|
576 {
|
Chris@929
|
577 renderTo(this, rect(), m_editable);
|
Chris@929
|
578 }
|
Chris@923
|
579
|
Chris@1180
|
580 void
|
Chris@1180
|
581 LevelPanWidget::enterEvent(QEvent *e)
|
Chris@1180
|
582 {
|
Chris@1180
|
583 QWidget::enterEvent(e);
|
Chris@1180
|
584 emit mouseEntered();
|
Chris@1180
|
585 }
|
Chris@929
|
586
|
Chris@1180
|
587 void
|
Chris@1180
|
588 LevelPanWidget::leaveEvent(QEvent *e)
|
Chris@1180
|
589 {
|
Chris@1180
|
590 QWidget::enterEvent(e);
|
Chris@1180
|
591 emit mouseLeft();
|
Chris@1180
|
592 }
|
Chris@929
|
593
|