annotate widgets/LevelPanWidget.cpp @ 1600:1acd7be4df9a

Complete round-trip name-type conversion for melodic range & peak freq spectrograms (also has the effect of making them creatable from OSC)
author Chris Cannam
date Wed, 29 Apr 2020 13:26:23 +0100
parents 5af5c611f4cb
children
rev   line source
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