Mercurial > hg > svgui
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 |