annotate widgets/LevelPanWidget.cpp @ 923:2a9f1eb6e0ed tonioni

Try adding a combined simple level/pan widget
author Chris Cannam
date Tue, 24 Mar 2015 14:40:31 +0000
parents
children cfcdec324712
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@923 22
Chris@923 23 #include <iostream>
Chris@923 24
Chris@923 25 using std::cerr;
Chris@923 26 using std::endl;
Chris@923 27
Chris@923 28 static const int maxLevel = 5;
Chris@923 29 static const int maxPan = 2; // range is -maxPan to maxPan
Chris@923 30
Chris@923 31 LevelPanWidget::LevelPanWidget(QWidget *parent) :
Chris@923 32 QWidget(parent),
Chris@923 33 m_level(maxLevel),
Chris@923 34 m_pan(0),
Chris@923 35 m_editable(true)
Chris@923 36 {
Chris@923 37 }
Chris@923 38
Chris@923 39 LevelPanWidget::~LevelPanWidget()
Chris@923 40 {
Chris@923 41 }
Chris@923 42
Chris@923 43 void
Chris@923 44 LevelPanWidget::setLevel(float level)
Chris@923 45 {
Chris@923 46 m_level = int(round(level * maxLevel));
Chris@923 47 if (m_level < 0) m_level = 0;
Chris@923 48 if (m_level > maxLevel) m_level = maxLevel;
Chris@923 49 update();
Chris@923 50 }
Chris@923 51
Chris@923 52 void
Chris@923 53 LevelPanWidget::setPan(float pan)
Chris@923 54 {
Chris@923 55 m_pan = int(round(pan * maxPan));
Chris@923 56 if (m_pan < -maxPan) m_pan = -maxPan;
Chris@923 57 if (m_pan > maxPan) m_pan = maxPan;
Chris@923 58 update();
Chris@923 59 }
Chris@923 60
Chris@923 61 void
Chris@923 62 LevelPanWidget::setEditable(bool editable)
Chris@923 63 {
Chris@923 64 m_editable = editable;
Chris@923 65 update();
Chris@923 66 }
Chris@923 67
Chris@923 68 float
Chris@923 69 LevelPanWidget::getLevel() const
Chris@923 70 {
Chris@923 71 return float(m_level) / float(maxLevel);
Chris@923 72 }
Chris@923 73
Chris@923 74 float
Chris@923 75 LevelPanWidget::getPan() const
Chris@923 76 {
Chris@923 77 return float(m_pan) / float(maxPan);
Chris@923 78 }
Chris@923 79
Chris@923 80 void
Chris@923 81 LevelPanWidget::emitLevelChanged()
Chris@923 82 {
Chris@923 83 cerr << "emitting levelChanged(" << getLevel() << ")" << endl;
Chris@923 84 emit levelChanged(getLevel());
Chris@923 85 }
Chris@923 86
Chris@923 87 void
Chris@923 88 LevelPanWidget::emitPanChanged()
Chris@923 89 {
Chris@923 90 cerr << "emitting panChanged(" << getPan() << ")" << endl;
Chris@923 91 emit panChanged(getPan());
Chris@923 92 }
Chris@923 93
Chris@923 94 void
Chris@923 95 LevelPanWidget::mousePressEvent(QMouseEvent *e)
Chris@923 96 {
Chris@923 97 mouseMoveEvent(e);
Chris@923 98 }
Chris@923 99
Chris@923 100 void
Chris@923 101 LevelPanWidget::mouseMoveEvent(QMouseEvent *e)
Chris@923 102 {
Chris@923 103 if (!m_editable) return;
Chris@923 104
Chris@923 105 int level, pan;
Chris@923 106 toCell(e->pos(), level, pan);
Chris@923 107 if (level == m_level && pan == m_pan) {
Chris@923 108 return;
Chris@923 109 }
Chris@923 110 if (level != m_level) {
Chris@923 111 m_level = level;
Chris@923 112 emitLevelChanged();
Chris@923 113 }
Chris@923 114 if (pan != m_pan) {
Chris@923 115 m_pan = pan;
Chris@923 116 emitPanChanged();
Chris@923 117 }
Chris@923 118 update();
Chris@923 119 }
Chris@923 120
Chris@923 121 void
Chris@923 122 LevelPanWidget::mouseReleaseEvent(QMouseEvent *e)
Chris@923 123 {
Chris@923 124 mouseMoveEvent(e);
Chris@923 125 }
Chris@923 126
Chris@923 127 void
Chris@923 128 LevelPanWidget::wheelEvent(QWheelEvent *e)
Chris@923 129 {
Chris@923 130 if (e->modifiers() & Qt::ControlModifier) {
Chris@923 131 if (e->delta() > 0) {
Chris@923 132 if (m_pan < maxPan) {
Chris@923 133 ++m_pan;
Chris@923 134 emitPanChanged();
Chris@923 135 update();
Chris@923 136 }
Chris@923 137 } else {
Chris@923 138 if (m_pan > -maxPan) {
Chris@923 139 --m_pan;
Chris@923 140 emitPanChanged();
Chris@923 141 update();
Chris@923 142 }
Chris@923 143 }
Chris@923 144 } else {
Chris@923 145 if (e->delta() > 0) {
Chris@923 146 if (m_level < maxLevel) {
Chris@923 147 ++m_level;
Chris@923 148 emitLevelChanged();
Chris@923 149 update();
Chris@923 150 }
Chris@923 151 } else {
Chris@923 152 if (m_level > 0) {
Chris@923 153 --m_level;
Chris@923 154 emitLevelChanged();
Chris@923 155 update();
Chris@923 156 }
Chris@923 157 }
Chris@923 158 }
Chris@923 159 }
Chris@923 160
Chris@923 161 void
Chris@923 162 LevelPanWidget::toCell(QPointF loc, int &level, int &pan) const
Chris@923 163 {
Chris@923 164 double w = width(), h = height();
Chris@923 165 int npan = maxPan * 2 + 1;
Chris@923 166 double wcell = w / npan, hcell = h / maxLevel;
Chris@923 167 level = int((h - loc.y()) / hcell) + 1;
Chris@923 168 if (level < 1) level = 1;
Chris@923 169 if (level > maxLevel) level = maxLevel;
Chris@923 170 pan = int(loc.x() / wcell) - maxPan;
Chris@923 171 if (pan < -maxPan) pan = -maxPan;
Chris@923 172 if (pan > maxPan) pan = maxPan;
Chris@923 173 }
Chris@923 174
Chris@923 175 QSizeF
Chris@923 176 LevelPanWidget::cellSize() const
Chris@923 177 {
Chris@923 178 double w = width(), h = height();
Chris@923 179 int npan = maxPan * 2 + 1;
Chris@923 180 double wcell = w / npan, hcell = h / maxLevel;
Chris@923 181 return QSizeF(wcell, hcell);
Chris@923 182 }
Chris@923 183
Chris@923 184 QPointF
Chris@923 185 LevelPanWidget::cellCentre(int level, int pan) const
Chris@923 186 {
Chris@923 187 QSizeF cs = cellSize();
Chris@923 188 return QPointF(cs.width() * (pan + maxPan) + cs.width() / 2.,
Chris@923 189 height() - cs.height() * level + cs.height() / 2.);
Chris@923 190 }
Chris@923 191
Chris@923 192 QSizeF
Chris@923 193 LevelPanWidget::cellLightSize() const
Chris@923 194 {
Chris@923 195 double extent = 3. / 4.;
Chris@923 196 QSizeF cs = cellSize();
Chris@923 197 double m = std::min(cs.width(), cs.height());
Chris@923 198 return QSizeF(m * extent, m * extent);
Chris@923 199 }
Chris@923 200
Chris@923 201 QRectF
Chris@923 202 LevelPanWidget::cellLightRect(int level, int pan) const
Chris@923 203 {
Chris@923 204 QSizeF cls = cellLightSize();
Chris@923 205 QPointF cc = cellCentre(level, pan);
Chris@923 206 return QRectF(cc.x() - cls.width() / 2.,
Chris@923 207 cc.y() - cls.height() / 2.,
Chris@923 208 cls.width(),
Chris@923 209 cls.height());
Chris@923 210 }
Chris@923 211
Chris@923 212 double
Chris@923 213 LevelPanWidget::thinLineWidth() const
Chris@923 214 {
Chris@923 215 double tw = ceil(width() / (maxPan * 2. * 10.));
Chris@923 216 double th = ceil(height() / (maxLevel * 10.));
Chris@923 217 return std::min(th, tw);
Chris@923 218 }
Chris@923 219
Chris@923 220 void
Chris@923 221 LevelPanWidget::paintEvent(QPaintEvent *)
Chris@923 222 {
Chris@923 223 QPainter paint(this);
Chris@923 224 ColourMapper mapper(ColourMapper::Sunset, 0, maxLevel);
Chris@923 225
Chris@923 226 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@923 227
Chris@923 228 QPen pen;
Chris@923 229
Chris@923 230 double thin = thinLineWidth();
Chris@923 231
Chris@923 232 pen.setColor(QColor(127, 127, 127, 127));
Chris@923 233 pen.setWidthF(cellLightSize().width() + thin);
Chris@923 234 pen.setCapStyle(Qt::RoundCap);
Chris@923 235 paint.setPen(pen);
Chris@923 236
Chris@923 237 for (int pan = -maxPan; pan <= maxPan; ++pan) {
Chris@923 238 paint.drawLine(cellCentre(1, pan), cellCentre(maxLevel, pan));
Chris@923 239 }
Chris@923 240
Chris@923 241 pen.setColor(Qt::black);
Chris@923 242 pen.setWidthF(thin);
Chris@923 243 pen.setCapStyle(Qt::FlatCap);
Chris@923 244 paint.setPen(pen);
Chris@923 245
Chris@923 246 for (int level = 1; level <= m_level; ++level) {
Chris@923 247 // level starts at 1 because we handle mute separately
Chris@923 248 paint.setBrush(mapper.map(level));
Chris@923 249 paint.drawEllipse(cellLightRect(level, m_pan));
Chris@923 250 }
Chris@923 251 }
Chris@923 252
Chris@923 253