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@1302
|
77 m_includeHalfSteps(true),
|
Chris@1302
|
78 m_pendingWheelAngle(0)
|
Chris@923
|
79 {
|
Chris@1191
|
80 setToolTip(tr("Drag vertically to adjust level, horizontally to adjust pan"));
|
Chris@1201
|
81 setLevel(1.0);
|
Chris@1201
|
82 setPan(0.0);
|
Chris@923
|
83 }
|
Chris@923
|
84
|
Chris@923
|
85 LevelPanWidget::~LevelPanWidget()
|
Chris@923
|
86 {
|
Chris@923
|
87 }
|
Chris@923
|
88
|
Chris@1249
|
89 void
|
Chris@1249
|
90 LevelPanWidget::setToDefault()
|
Chris@1249
|
91 {
|
Chris@1249
|
92 setLevel(1.0);
|
Chris@1249
|
93 setPan(0.0);
|
Chris@1250
|
94 emitLevelChanged();
|
Chris@1250
|
95 emitPanChanged();
|
Chris@1249
|
96 }
|
Chris@1249
|
97
|
Chris@929
|
98 QSize
|
Chris@929
|
99 LevelPanWidget::sizeHint() const
|
Chris@929
|
100 {
|
Chris@1176
|
101 return WidgetScale::scaleQSize(QSize(40, 40));
|
Chris@929
|
102 }
|
Chris@929
|
103
|
Chris@1301
|
104 int
|
Chris@1301
|
105 LevelPanWidget::clampNotch(int notch) const
|
Chris@940
|
106 {
|
Chris@1301
|
107 if (notch < m_minNotch) notch = m_minNotch;
|
Chris@1301
|
108 if (notch > m_maxNotch) notch = m_maxNotch;
|
Chris@1301
|
109 if (!m_includeHalfSteps) {
|
Chris@1301
|
110 notch = (notch / 2) * 2;
|
Chris@1301
|
111 }
|
Chris@1301
|
112 return notch;
|
Chris@940
|
113 }
|
Chris@940
|
114
|
Chris@1177
|
115 int
|
Chris@1302
|
116 LevelPanWidget::clampPan(int pan) const
|
Chris@1302
|
117 {
|
Chris@1302
|
118 if (pan < -maxPan) pan = -maxPan;
|
Chris@1302
|
119 if (pan > maxPan) pan = maxPan;
|
Chris@1302
|
120 return pan;
|
Chris@1302
|
121 }
|
Chris@1302
|
122
|
Chris@1302
|
123 int
|
Chris@1301
|
124 LevelPanWidget::audioLevelToNotch(float audioLevel) const
|
Chris@1177
|
125 {
|
Chris@1301
|
126 int notch = AudioLevel::multiplier_to_fader
|
Chris@1301
|
127 (audioLevel, m_maxNotch, AudioLevel::ShortFader);
|
Chris@1301
|
128 return clampNotch(notch);
|
Chris@1177
|
129 }
|
Chris@1177
|
130
|
Chris@1177
|
131 float
|
Chris@1301
|
132 LevelPanWidget::notchToAudioLevel(int notch) const
|
Chris@1177
|
133 {
|
Chris@1301
|
134 return float(AudioLevel::fader_to_multiplier
|
Chris@1301
|
135 (notch, m_maxNotch, AudioLevel::ShortFader));
|
Chris@1177
|
136 }
|
Chris@1177
|
137
|
Chris@923
|
138 void
|
Chris@1301
|
139 LevelPanWidget::setLevel(float level)
|
Chris@923
|
140 {
|
Chris@1301
|
141 int notch = audioLevelToNotch(level);
|
Chris@1301
|
142 if (notch != m_notch) {
|
Chris@1301
|
143 m_notch = notch;
|
Chris@1266
|
144 float convertsTo = getLevel();
|
Chris@1301
|
145 if (fabsf(convertsTo - level) > 1e-5) {
|
Chris@1266
|
146 emitLevelChanged();
|
Chris@1266
|
147 }
|
Chris@1266
|
148 update();
|
Chris@925
|
149 }
|
Chris@1301
|
150 SVCERR << "setLevel: level " << level << " -> notch " << m_notch << " (which converts back to level " << getLevel() << ")" << endl;
|
Chris@923
|
151 }
|
Chris@923
|
152
|
Chris@940
|
153 float
|
Chris@940
|
154 LevelPanWidget::getLevel() const
|
Chris@940
|
155 {
|
Chris@1301
|
156 return notchToAudioLevel(m_notch);
|
Chris@1177
|
157 }
|
Chris@1177
|
158
|
Chris@1177
|
159 int
|
Chris@1301
|
160 LevelPanWidget::audioPanToPan(float audioPan) const
|
Chris@1177
|
161 {
|
Chris@1177
|
162 int pan = int(round(audioPan * maxPan));
|
Chris@1302
|
163 pan = clampPan(pan);
|
Chris@1177
|
164 return pan;
|
Chris@1177
|
165 }
|
Chris@1177
|
166
|
Chris@1177
|
167 float
|
Chris@1301
|
168 LevelPanWidget::panToAudioPan(int pan) const
|
Chris@1177
|
169 {
|
Chris@1177
|
170 return float(pan) / float(maxPan);
|
Chris@1177
|
171 }
|
Chris@1177
|
172
|
Chris@1177
|
173 void
|
Chris@1177
|
174 LevelPanWidget::setPan(float fpan)
|
Chris@1177
|
175 {
|
Chris@1177
|
176 int pan = audioPanToPan(fpan);
|
Chris@1177
|
177 if (pan != m_pan) {
|
Chris@1177
|
178 m_pan = pan;
|
Chris@1177
|
179 update();
|
Chris@940
|
180 }
|
Chris@940
|
181 }
|
Chris@940
|
182
|
Chris@1177
|
183 float
|
Chris@1177
|
184 LevelPanWidget::getPan() const
|
Chris@1177
|
185 {
|
Chris@1177
|
186 return panToAudioPan(m_pan);
|
Chris@1177
|
187 }
|
Chris@1177
|
188
|
Chris@923
|
189 void
|
Chris@1177
|
190 LevelPanWidget::setMonitoringLevels(float left, float right)
|
Chris@923
|
191 {
|
Chris@1177
|
192 m_monitorLeft = left;
|
Chris@1177
|
193 m_monitorRight = right;
|
Chris@923
|
194 update();
|
Chris@923
|
195 }
|
Chris@923
|
196
|
Chris@940
|
197 bool
|
Chris@940
|
198 LevelPanWidget::isEditable() const
|
Chris@940
|
199 {
|
Chris@940
|
200 return m_editable;
|
Chris@940
|
201 }
|
Chris@940
|
202
|
Chris@940
|
203 bool
|
Chris@940
|
204 LevelPanWidget::includesMute() const
|
Chris@940
|
205 {
|
Chris@940
|
206 return m_includeMute;
|
Chris@940
|
207 }
|
Chris@940
|
208
|
Chris@923
|
209 void
|
Chris@923
|
210 LevelPanWidget::setEditable(bool editable)
|
Chris@923
|
211 {
|
Chris@923
|
212 m_editable = editable;
|
Chris@923
|
213 update();
|
Chris@923
|
214 }
|
Chris@923
|
215
|
Chris@940
|
216 void
|
Chris@940
|
217 LevelPanWidget::setIncludeMute(bool include)
|
Chris@923
|
218 {
|
Chris@940
|
219 m_includeMute = include;
|
Chris@1301
|
220 if (m_includeMute) {
|
Chris@1301
|
221 m_minNotch = 0;
|
Chris@1301
|
222 } else {
|
Chris@1301
|
223 m_minNotch = 1;
|
Chris@1301
|
224 }
|
Chris@940
|
225 emitLevelChanged();
|
Chris@940
|
226 update();
|
Chris@923
|
227 }
|
Chris@923
|
228
|
Chris@923
|
229 void
|
Chris@923
|
230 LevelPanWidget::emitLevelChanged()
|
Chris@923
|
231 {
|
Chris@923
|
232 emit levelChanged(getLevel());
|
Chris@923
|
233 }
|
Chris@923
|
234
|
Chris@923
|
235 void
|
Chris@923
|
236 LevelPanWidget::emitPanChanged()
|
Chris@923
|
237 {
|
Chris@923
|
238 emit panChanged(getPan());
|
Chris@923
|
239 }
|
Chris@923
|
240
|
Chris@923
|
241 void
|
Chris@923
|
242 LevelPanWidget::mousePressEvent(QMouseEvent *e)
|
Chris@923
|
243 {
|
Chris@1249
|
244 if (e->button() == Qt::MidButton ||
|
Chris@1249
|
245 ((e->button() == Qt::LeftButton) &&
|
Chris@1249
|
246 (e->modifiers() & Qt::ControlModifier))) {
|
Chris@1249
|
247 setToDefault();
|
Chris@1249
|
248 } else if (e->button() == Qt::LeftButton) {
|
Chris@1249
|
249 m_editing = true;
|
Chris@1249
|
250 mouseMoveEvent(e);
|
Chris@1249
|
251 }
|
Chris@1249
|
252 }
|
Chris@1249
|
253
|
Chris@1249
|
254 void
|
Chris@1249
|
255 LevelPanWidget::mouseReleaseEvent(QMouseEvent *e)
|
Chris@1249
|
256 {
|
Chris@923
|
257 mouseMoveEvent(e);
|
Chris@1249
|
258 m_editing = false;
|
Chris@923
|
259 }
|
Chris@923
|
260
|
Chris@923
|
261 void
|
Chris@923
|
262 LevelPanWidget::mouseMoveEvent(QMouseEvent *e)
|
Chris@923
|
263 {
|
Chris@923
|
264 if (!m_editable) return;
|
Chris@1249
|
265 if (!m_editing) return;
|
Chris@923
|
266
|
Chris@1301
|
267 int notch = coordsToNotch(rect(), e->pos());
|
Chris@1301
|
268 int pan = coordsToPan(rect(), e->pos());
|
Chris@1301
|
269
|
Chris@1301
|
270 if (notch == m_notch && pan == m_pan) {
|
Chris@1266
|
271 return;
|
Chris@923
|
272 }
|
Chris@1301
|
273 if (notch != m_notch) {
|
Chris@1301
|
274 m_notch = notch;
|
Chris@1266
|
275 emitLevelChanged();
|
Chris@923
|
276 }
|
Chris@923
|
277 if (pan != m_pan) {
|
Chris@1266
|
278 m_pan = pan;
|
Chris@1266
|
279 emitPanChanged();
|
Chris@923
|
280 }
|
Chris@923
|
281 update();
|
Chris@923
|
282 }
|
Chris@923
|
283
|
Chris@923
|
284 void
|
Chris@923
|
285 LevelPanWidget::wheelEvent(QWheelEvent *e)
|
Chris@923
|
286 {
|
Chris@1302
|
287 e->accept();
|
Chris@1302
|
288
|
Chris@1302
|
289 int dy = e->angleDelta().y();
|
Chris@1302
|
290 if (dy == 0) {
|
Chris@1302
|
291 return;
|
Chris@1302
|
292 }
|
Chris@1302
|
293
|
Chris@1302
|
294 if (e->phase() == Qt::ScrollBegin ||
|
Chris@1302
|
295 std::abs(dy) >= 120 ||
|
Chris@1302
|
296 (dy > 0 && m_pendingWheelAngle < 0) ||
|
Chris@1302
|
297 (dy < 0 && m_pendingWheelAngle > 0)) {
|
Chris@1302
|
298 m_pendingWheelAngle = dy;
|
Chris@1302
|
299 } else {
|
Chris@1302
|
300 m_pendingWheelAngle += dy;
|
Chris@1302
|
301 }
|
Chris@1302
|
302
|
Chris@1302
|
303 if (abs(m_pendingWheelAngle) >= 600) {
|
Chris@1302
|
304 // discard absurd results
|
Chris@1302
|
305 m_pendingWheelAngle = 0;
|
Chris@1302
|
306 return;
|
Chris@1302
|
307 }
|
Chris@1302
|
308
|
Chris@1302
|
309 while (abs(m_pendingWheelAngle) >= 120) {
|
Chris@1302
|
310
|
Chris@1302
|
311 int sign = (m_pendingWheelAngle < 0 ? -1 : 1);
|
Chris@1302
|
312
|
Chris@1302
|
313 if (e->modifiers() & Qt::ControlModifier) {
|
Chris@1302
|
314 m_pan += sign;
|
Chris@1302
|
315 m_pan = clampPan(m_pan);
|
Chris@1302
|
316 emitPanChanged();
|
Chris@1302
|
317 update();
|
Chris@1266
|
318 } else {
|
Chris@1302
|
319 m_notch += sign;
|
Chris@1302
|
320 m_notch = clampNotch(m_notch);
|
Chris@1302
|
321 emitLevelChanged();
|
Chris@1302
|
322 update();
|
Chris@1266
|
323 }
|
Chris@1302
|
324
|
Chris@1302
|
325 m_pendingWheelAngle -= sign * 120;
|
Chris@923
|
326 }
|
Chris@923
|
327 }
|
Chris@923
|
328
|
Chris@1301
|
329 int
|
Chris@1301
|
330 LevelPanWidget::coordsToNotch(QRectF rect, QPointF loc) const
|
Chris@923
|
331 {
|
Chris@1301
|
332 double h = rect.height();
|
Chris@1301
|
333
|
Chris@1301
|
334 int nnotch = m_maxNotch + 1;
|
Chris@1301
|
335 double cell = h / nnotch;
|
Chris@1301
|
336
|
Chris@1301
|
337 int notch = int((h - (loc.y() - rect.y())) / cell);
|
Chris@1301
|
338 notch = clampNotch(notch);
|
Chris@1301
|
339
|
Chris@1301
|
340 return notch;
|
Chris@1301
|
341 }
|
Chris@1301
|
342
|
Chris@1301
|
343 int
|
Chris@1301
|
344 LevelPanWidget::coordsToPan(QRectF rect, QPointF loc) const
|
Chris@1301
|
345 {
|
Chris@1301
|
346 double w = rect.width();
|
Chris@929
|
347
|
Chris@923
|
348 int npan = maxPan * 2 + 1;
|
Chris@1301
|
349 double cell = w / npan;
|
Chris@929
|
350
|
Chris@1301
|
351 int pan = int((loc.x() - rect.x()) / cell) - maxPan;
|
Chris@1302
|
352 pan = clampPan(pan);
|
Chris@1301
|
353
|
Chris@1301
|
354 return pan;
|
Chris@923
|
355 }
|
Chris@923
|
356
|
Chris@923
|
357 QSizeF
|
Chris@929
|
358 LevelPanWidget::cellSize(QRectF rect) const
|
Chris@923
|
359 {
|
Chris@929
|
360 double w = rect.width(), h = rect.height();
|
Chris@1301
|
361 int ncol = maxPan * 2 + 1;
|
Chris@1301
|
362 int nrow = m_maxNotch/2;
|
Chris@1301
|
363 double wcell = w / ncol, hcell = h / nrow;
|
Chris@923
|
364 return QSizeF(wcell, hcell);
|
Chris@923
|
365 }
|
Chris@923
|
366
|
Chris@923
|
367 QPointF
|
Chris@1301
|
368 LevelPanWidget::cellCentre(QRectF rect, int row, int col) const
|
Chris@923
|
369 {
|
Chris@929
|
370 QSizeF cs = cellSize(rect);
|
Chris@1301
|
371 return QPointF(rect.x() +
|
Chris@1301
|
372 cs.width() * (col + maxPan) + cs.width() / 2.,
|
Chris@1301
|
373 rect.y() + rect.height() -
|
Chris@1301
|
374 cs.height() * (row + 1) + cs.height() / 2.);
|
Chris@923
|
375 }
|
Chris@923
|
376
|
Chris@923
|
377 QSizeF
|
Chris@929
|
378 LevelPanWidget::cellLightSize(QRectF rect) const
|
Chris@923
|
379 {
|
Chris@923
|
380 double extent = 3. / 4.;
|
Chris@929
|
381 QSizeF cs = cellSize(rect);
|
Chris@923
|
382 double m = std::min(cs.width(), cs.height());
|
Chris@923
|
383 return QSizeF(m * extent, m * extent);
|
Chris@923
|
384 }
|
Chris@923
|
385
|
Chris@923
|
386 QRectF
|
Chris@1301
|
387 LevelPanWidget::cellLightRect(QRectF rect, int row, int col) const
|
Chris@923
|
388 {
|
Chris@929
|
389 QSizeF cls = cellLightSize(rect);
|
Chris@1301
|
390 QPointF cc = cellCentre(rect, row, col);
|
Chris@923
|
391 return QRectF(cc.x() - cls.width() / 2.,
|
Chris@1266
|
392 cc.y() - cls.height() / 2.,
|
Chris@1266
|
393 cls.width(),
|
Chris@1266
|
394 cls.height());
|
Chris@923
|
395 }
|
Chris@923
|
396
|
Chris@923
|
397 double
|
Chris@929
|
398 LevelPanWidget::thinLineWidth(QRectF rect) const
|
Chris@923
|
399 {
|
Chris@929
|
400 double tw = ceil(rect.width() / (maxPan * 2. * 10.));
|
Chris@1301
|
401 double th = ceil(rect.height() / (m_maxNotch/2 * 10.));
|
Chris@923
|
402 return std::min(th, tw);
|
Chris@923
|
403 }
|
Chris@923
|
404
|
Chris@1301
|
405 QRectF
|
Chris@1301
|
406 LevelPanWidget::cellOutlineRect(QRectF rect, int row, int col) const
|
Chris@941
|
407 {
|
Chris@1301
|
408 QRectF clr = cellLightRect(rect, row, col);
|
Chris@1301
|
409 double adj = thinLineWidth(rect)/2;
|
Chris@1301
|
410 return clr.adjusted(-adj, -adj, adj, adj);
|
Chris@1301
|
411 }
|
Chris@1301
|
412
|
Chris@1301
|
413 QColor
|
Chris@1301
|
414 LevelPanWidget::notchToColour(int notch) const
|
Chris@1301
|
415 {
|
Chris@1301
|
416 if (notch < 3) return Qt::black;
|
Chris@1301
|
417 if (notch < 5) return QColor(80, 0, 0);
|
Chris@1301
|
418 if (notch < 7) return QColor(160, 0, 0);
|
Chris@1301
|
419 if (notch < 9) return QColor(255, 0, 0);
|
Chris@1301
|
420 return QColor(255, 255, 0);
|
Chris@941
|
421 }
|
Chris@941
|
422
|
Chris@923
|
423 void
|
Chris@929
|
424 LevelPanWidget::renderTo(QPaintDevice *dev, QRectF rect, bool asIfEditable) const
|
Chris@923
|
425 {
|
Chris@929
|
426 QPainter paint(dev);
|
Chris@923
|
427
|
Chris@923
|
428 paint.setRenderHint(QPainter::Antialiasing, true);
|
Chris@923
|
429
|
Chris@923
|
430 QPen pen;
|
Chris@923
|
431
|
Chris@929
|
432 double thin = thinLineWidth(rect);
|
Chris@938
|
433
|
Chris@1301
|
434 QColor columnBackground = QColor(180, 180, 180);
|
Chris@1301
|
435 pen.setColor(columnBackground);
|
Chris@929
|
436 pen.setWidthF(cellLightSize(rect).width() + thin);
|
Chris@923
|
437 pen.setCapStyle(Qt::RoundCap);
|
Chris@923
|
438 paint.setPen(pen);
|
Chris@1177
|
439 paint.setBrush(Qt::NoBrush);
|
Chris@923
|
440
|
Chris@923
|
441 for (int pan = -maxPan; pan <= maxPan; ++pan) {
|
Chris@1301
|
442 paint.drawLine(cellCentre(rect, 0, pan),
|
Chris@1301
|
443 cellCentre(rect, m_maxNotch/2 - 1, pan));
|
Chris@924
|
444 }
|
Chris@924
|
445
|
Chris@1301
|
446 bool monitoring = (m_monitorLeft > 0.f || m_monitorRight > 0.f);
|
Chris@1301
|
447
|
Chris@1301
|
448 if (isEnabled()) {
|
Chris@1301
|
449 pen.setColor(Qt::black);
|
Chris@1301
|
450 } else {
|
Chris@1301
|
451 pen.setColor(Qt::darkGray);
|
Chris@1301
|
452 }
|
Chris@1301
|
453
|
Chris@1301
|
454 if (!asIfEditable && m_includeMute && m_notch == 0) {
|
Chris@1301
|
455 // The X for mute takes up the whole display when we're not
|
Chris@1301
|
456 // being rendered in editable style
|
Chris@1301
|
457 pen.setWidthF(thin * 2);
|
Chris@1301
|
458 pen.setCapStyle(Qt::RoundCap);
|
Chris@1301
|
459 paint.setPen(pen);
|
Chris@1301
|
460 paint.drawLine(cellCentre(rect, 0, -maxPan),
|
Chris@1301
|
461 cellCentre(rect, m_maxNotch/2 - 1, maxPan));
|
Chris@1301
|
462 paint.drawLine(cellCentre(rect, m_maxNotch/2 - 1, -maxPan),
|
Chris@1301
|
463 cellCentre(rect, 0, maxPan));
|
Chris@1301
|
464 } else {
|
Chris@1301
|
465 // the normal case
|
Chris@1301
|
466
|
Chris@1301
|
467 // pen a bit less thin than in theory, so that we can erase
|
Chris@1301
|
468 // semi-circles later without leaving a faint edge
|
Chris@1301
|
469 pen.setWidthF(thin * 0.8);
|
Chris@1301
|
470 pen.setCapStyle(Qt::FlatCap);
|
Chris@1301
|
471 paint.setPen(pen);
|
Chris@1301
|
472
|
Chris@1301
|
473 if (m_includeMute && m_notch == 0) {
|
Chris@1301
|
474 QRectF clr = cellLightRect(rect, 0, m_pan);
|
Chris@1301
|
475 paint.drawLine(clr.topLeft(), clr.bottomRight());
|
Chris@1301
|
476 paint.drawLine(clr.bottomLeft(), clr.topRight());
|
Chris@1301
|
477 } else {
|
Chris@1301
|
478 for (int notch = 1; notch <= m_notch; notch += 2) {
|
Chris@1301
|
479 if (isEnabled() && !monitoring) {
|
Chris@1301
|
480 paint.setBrush(notchToColour(notch));
|
Chris@1301
|
481 }
|
Chris@1301
|
482 QRectF clr = cellLightRect(rect, notch/2, m_pan);
|
Chris@1301
|
483 paint.drawEllipse(clr);
|
Chris@1301
|
484 }
|
Chris@1301
|
485 if (m_notch % 2 != 0) {
|
Chris@1301
|
486 QRectF clr = cellOutlineRect(rect, (m_notch-1)/2, m_pan);
|
Chris@1301
|
487 paint.save();
|
Chris@1301
|
488 paint.setPen(Qt::NoPen);
|
Chris@1301
|
489 paint.setBrush(columnBackground);
|
Chris@1301
|
490 paint.drawPie(clr, 0, 180 * 16);
|
Chris@1301
|
491 paint.restore();
|
Chris@1301
|
492 }
|
Chris@1301
|
493 }
|
Chris@1301
|
494 }
|
Chris@1301
|
495
|
Chris@1301
|
496 if (monitoring) {
|
Chris@1177
|
497 paint.setPen(Qt::NoPen);
|
Chris@1177
|
498 for (int pan = -maxPan; pan <= maxPan; ++pan) {
|
Chris@1177
|
499 float audioPan = panToAudioPan(pan);
|
Chris@1177
|
500 float audioLevel;
|
Chris@1177
|
501 if (audioPan < 0.f) {
|
Chris@1177
|
502 audioLevel = m_monitorLeft + m_monitorRight * (1.f + audioPan);
|
Chris@1177
|
503 } else {
|
Chris@1177
|
504 audioLevel = m_monitorRight + m_monitorLeft * (1.f - audioPan);
|
Chris@1177
|
505 }
|
Chris@1301
|
506 int notchHere = audioLevelToNotch(audioLevel);
|
Chris@1301
|
507 for (int notch = 1; notch <= notchHere; notch += 2) {
|
Chris@1301
|
508 paint.setBrush(notchToColour(notch));
|
Chris@1301
|
509 QRectF clr = cellLightRect(rect, (notch-1)/2, pan);
|
Chris@1301
|
510 double adj = thinLineWidth(rect)/2;
|
Chris@1301
|
511 clr = clr.adjusted(adj, adj, -adj, -adj);
|
Chris@1301
|
512 if (notch + 2 > notchHere && notchHere % 2 != 0) {
|
Chris@1301
|
513 paint.drawPie(clr, 180 * 16, 180 * 16);
|
Chris@1301
|
514 } else {
|
Chris@1301
|
515 paint.drawEllipse(clr);
|
Chris@1301
|
516 }
|
Chris@1177
|
517 }
|
Chris@1177
|
518 }
|
Chris@1177
|
519 paint.setPen(pen);
|
Chris@1177
|
520 paint.setBrush(Qt::NoBrush);
|
Chris@1177
|
521 }
|
Chris@923
|
522 }
|
Chris@923
|
523
|
Chris@929
|
524 void
|
Chris@929
|
525 LevelPanWidget::paintEvent(QPaintEvent *)
|
Chris@929
|
526 {
|
Chris@929
|
527 renderTo(this, rect(), m_editable);
|
Chris@929
|
528 }
|
Chris@923
|
529
|
Chris@1180
|
530 void
|
Chris@1180
|
531 LevelPanWidget::enterEvent(QEvent *e)
|
Chris@1180
|
532 {
|
Chris@1180
|
533 QWidget::enterEvent(e);
|
Chris@1180
|
534 emit mouseEntered();
|
Chris@1180
|
535 }
|
Chris@929
|
536
|
Chris@1180
|
537 void
|
Chris@1180
|
538 LevelPanWidget::leaveEvent(QEvent *e)
|
Chris@1180
|
539 {
|
Chris@1180
|
540 QWidget::enterEvent(e);
|
Chris@1180
|
541 emit mouseLeft();
|
Chris@1180
|
542 }
|
Chris@929
|
543
|