comparison widgets/LevelPanWidget.cpp @ 1324:13d9b422f7fe zoom

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