annotate widgets/Thumbwheel.cpp @ 133:9e6b3e239b9d

* Add zoom thumbwheels to Pane. Implement horizontal thumbwheel, and vertical depending on layer type (supported for waveform and spectrogram, though wrong for log-scale spectrogram at the moment). * Add bare bones of a spectrum layer. * Add window icon * Add shortcut for "insert time instant" on laptops without keypad enter (";") * Delete FFT processing thread when it exits (at least, next time we're asked for something interesting) * Get audio file extensions from the file readers, and thus from libsndfile for the wave file reader -- leads to rather a wide combo box in file dialog though * Better refresh order for spectrogram (redraw centre section first)
author Chris Cannam
date Fri, 04 Aug 2006 17:01:37 +0000
parents 5d3a483856ff
children 793df5f0c6cb
rev   line source
Chris@132 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@132 2
Chris@132 3 /*
Chris@132 4 Sonic Visualiser
Chris@132 5 An audio file viewer and annotation editor.
Chris@132 6 Centre for Digital Music, Queen Mary, University of London.
Chris@132 7 This file copyright 2006 Chris Cannam.
Chris@132 8
Chris@132 9 This program is free software; you can redistribute it and/or
Chris@132 10 modify it under the terms of the GNU General Public License as
Chris@132 11 published by the Free Software Foundation; either version 2 of the
Chris@132 12 License, or (at your option) any later version. See the file
Chris@132 13 COPYING included with this distribution for more information.
Chris@132 14 */
Chris@132 15
Chris@132 16 #include "Thumbwheel.h"
Chris@132 17
Chris@132 18 #include <QMouseEvent>
Chris@132 19 #include <QPaintEvent>
Chris@132 20 #include <QWheelEvent>
Chris@132 21 #include <QPainter>
Chris@132 22
Chris@132 23 #include <cmath>
Chris@132 24 #include <iostream>
Chris@132 25
Chris@133 26 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
Chris@132 27 QWidget *parent) :
Chris@132 28 QWidget(parent),
Chris@133 29 m_min(0),
Chris@133 30 m_max(100),
Chris@133 31 m_default(50),
Chris@133 32 m_value(50),
Chris@132 33 m_orientation(orientation),
Chris@133 34 m_speed(0.25),
Chris@132 35 m_tracking(true),
Chris@132 36 m_showScale(true),
Chris@132 37 m_clicked(false),
Chris@133 38 m_atDefault(true),
Chris@132 39 m_clickValue(m_value)
Chris@132 40 {
Chris@132 41 }
Chris@132 42
Chris@132 43 Thumbwheel::~Thumbwheel()
Chris@132 44 {
Chris@132 45 }
Chris@132 46
Chris@132 47 void
Chris@133 48 Thumbwheel::setMinimumValue(int min)
Chris@133 49 {
Chris@133 50 if (m_min == min) return;
Chris@133 51
Chris@133 52 m_min = min;
Chris@133 53 if (m_max <= m_min) m_max = m_min + 1;
Chris@133 54 if (m_value < m_min) m_value = m_min;
Chris@133 55 if (m_value > m_max) m_value = m_max;
Chris@133 56 }
Chris@133 57
Chris@133 58 int
Chris@133 59 Thumbwheel::getMinimumValue() const
Chris@133 60 {
Chris@133 61 return m_min;
Chris@133 62 }
Chris@133 63
Chris@133 64 void
Chris@133 65 Thumbwheel::setMaximumValue(int max)
Chris@133 66 {
Chris@133 67 if (m_max == max) return;
Chris@133 68
Chris@133 69 m_max = max;
Chris@133 70 if (m_min >= m_max) m_min = m_max - 1;
Chris@133 71 if (m_value < m_min) m_value = m_min;
Chris@133 72 if (m_value > m_max) m_value = m_max;
Chris@133 73 }
Chris@133 74
Chris@133 75 int
Chris@133 76 Thumbwheel::getMaximumValue() const
Chris@133 77 {
Chris@133 78 return m_max;
Chris@133 79 }
Chris@133 80
Chris@133 81 void
Chris@133 82 Thumbwheel::setDefaultValue(int deft)
Chris@133 83 {
Chris@133 84 if (m_default == deft) return;
Chris@133 85
Chris@133 86 m_default = deft;
Chris@133 87 if (m_atDefault) {
Chris@133 88 setValue(m_default);
Chris@133 89 emit valueChanged(getValue());
Chris@133 90 }
Chris@133 91 }
Chris@133 92
Chris@133 93 int
Chris@133 94 Thumbwheel::getDefaultValue() const
Chris@133 95 {
Chris@133 96 return m_default;
Chris@133 97 }
Chris@133 98
Chris@133 99 void
Chris@132 100 Thumbwheel::setValue(int value)
Chris@132 101 {
Chris@133 102 if (m_value == value) return;
Chris@133 103 m_atDefault = false;
Chris@133 104
Chris@132 105 if (value < m_min) value = m_min;
Chris@132 106 if (value > m_max) value = m_max;
Chris@132 107 m_value = value;
Chris@132 108 update();
Chris@132 109 }
Chris@132 110
Chris@133 111 void
Chris@133 112 Thumbwheel::resetToDefault()
Chris@133 113 {
Chris@133 114 if (m_default == m_value) return;
Chris@133 115 setValue(m_default);
Chris@133 116 m_atDefault = true;
Chris@133 117 emit valueChanged(getValue());
Chris@133 118 }
Chris@133 119
Chris@132 120 int
Chris@132 121 Thumbwheel::getValue() const
Chris@132 122 {
Chris@132 123 return m_value;
Chris@132 124 }
Chris@132 125
Chris@132 126 void
Chris@132 127 Thumbwheel::setSpeed(float speed)
Chris@132 128 {
Chris@132 129 m_speed = speed;
Chris@132 130 }
Chris@132 131
Chris@132 132 float
Chris@132 133 Thumbwheel::getSpeed() const
Chris@132 134 {
Chris@132 135 return m_speed;
Chris@132 136 }
Chris@132 137
Chris@132 138 void
Chris@132 139 Thumbwheel::setTracking(bool tracking)
Chris@132 140 {
Chris@132 141 m_tracking = tracking;
Chris@132 142 }
Chris@132 143
Chris@132 144 bool
Chris@132 145 Thumbwheel::getTracking() const
Chris@132 146 {
Chris@132 147 return m_tracking;
Chris@132 148 }
Chris@132 149
Chris@132 150 void
Chris@132 151 Thumbwheel::setShowScale(bool showScale)
Chris@132 152 {
Chris@132 153 m_showScale = showScale;
Chris@132 154 }
Chris@132 155
Chris@132 156 bool
Chris@132 157 Thumbwheel::getShowScale() const
Chris@132 158 {
Chris@132 159 return m_showScale;
Chris@132 160 }
Chris@132 161
Chris@132 162 void
Chris@132 163 Thumbwheel::mousePressEvent(QMouseEvent *e)
Chris@132 164 {
Chris@133 165 if (e->button() == Qt::LeftButton) {
Chris@133 166 m_clicked = true;
Chris@133 167 m_clickPos = e->pos();
Chris@133 168 m_clickValue = m_value;
Chris@133 169 } else if (e->button() == Qt::MidButton) {
Chris@133 170 resetToDefault();
Chris@133 171 }
Chris@132 172 }
Chris@132 173
Chris@132 174 void
Chris@132 175 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *)
Chris@132 176 {
Chris@133 177 resetToDefault();
Chris@132 178 }
Chris@132 179
Chris@132 180 void
Chris@132 181 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
Chris@132 182 {
Chris@133 183 if (!m_clicked) return;
Chris@132 184 int dist = 0;
Chris@132 185 if (m_orientation == Qt::Horizontal) {
Chris@132 186 dist = e->x() - m_clickPos.x();
Chris@132 187 } else {
Chris@132 188 dist = e->y() - m_clickPos.y();
Chris@132 189 }
Chris@132 190 int value = m_clickValue + lrintf(m_speed * dist);
Chris@132 191 if (value < m_min) value = m_min;
Chris@132 192 if (value > m_max) value = m_max;
Chris@132 193 if (value != m_value) {
Chris@132 194 setValue(value);
Chris@132 195 if (m_tracking) emit valueChanged(getValue());
Chris@132 196 }
Chris@132 197 }
Chris@132 198
Chris@132 199 void
Chris@132 200 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
Chris@132 201 {
Chris@133 202 if (!m_clicked) return;
Chris@132 203 bool reallyTracking = m_tracking;
Chris@132 204 m_tracking = true;
Chris@132 205 mouseMoveEvent(e);
Chris@132 206 m_tracking = reallyTracking;
Chris@133 207 m_clicked = false;
Chris@132 208 }
Chris@132 209
Chris@132 210 void
Chris@132 211 Thumbwheel::wheelEvent(QWheelEvent *e)
Chris@132 212 {
Chris@132 213 int step = lrintf(m_speed);
Chris@132 214 if (step == 0) step = 1;
Chris@132 215
Chris@132 216 if (e->delta() > 0) {
Chris@132 217 setValue(m_value + step);
Chris@132 218 } else {
Chris@132 219 setValue(m_value - step);
Chris@132 220 }
Chris@132 221
Chris@132 222 emit valueChanged(getValue());
Chris@132 223 }
Chris@132 224
Chris@132 225 void
Chris@132 226 Thumbwheel::paintEvent(QPaintEvent *)
Chris@132 227 {
Chris@133 228 QPainter paint(this);
Chris@133 229 paint.fillRect(rect(), palette().background().color());
Chris@133 230 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@133 231
Chris@133 232 int bw = 3;
Chris@133 233
Chris@133 234 for (int i = 0; i < bw; ++i) {
Chris@133 235 int grey = (i + 1) * (256 / (bw + 1));
Chris@133 236 QColor fc = QColor(grey, grey, grey);
Chris@133 237 paint.setPen(fc);
Chris@133 238 paint.drawRect(i, i, width() - i*2 - 1, height() - i*2 - 1);
Chris@133 239 }
Chris@133 240
Chris@133 241 paint.setClipRect(QRect(bw, bw, width() - bw*2, height() - bw*2));
Chris@133 242
Chris@132 243 float distance = float(m_value - m_min) / float(m_max - m_min);
Chris@132 244 float rotation = distance * 1.5f * M_PI;
Chris@132 245
Chris@132 246 // std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl;
Chris@132 247
Chris@133 248 int w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2;
Chris@132 249
Chris@132 250 // total number of notches on the entire wheel
Chris@132 251 int notches = 25;
Chris@132 252
Chris@132 253 // radius of the wheel including invisible part
Chris@132 254 int radius = w / 2 + 2;
Chris@132 255
Chris@132 256 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@132 257
Chris@132 258 for (int i = 0; i < notches; ++i) {
Chris@132 259
Chris@132 260 float a0 = (2.f * M_PI * i) / notches + rotation;
Chris@132 261 float a1 = a0 + M_PI / (notches * 2);
Chris@132 262 float a2 = (2.f * M_PI * (i + 1)) / notches + rotation;
Chris@132 263
Chris@132 264 float depth = cosf((a0 + a2) / 2);
Chris@132 265 if (depth < 0) continue;
Chris@132 266
Chris@132 267 float x0 = radius * sinf(a0) + w/2;
Chris@132 268 float x1 = radius * sinf(a1) + w/2;
Chris@132 269 float x2 = radius * sinf(a2) + w/2;
Chris@132 270 if (x2 < 0 || x0 > w) continue;
Chris@132 271
Chris@132 272 if (x0 < 0) x0 = 0;
Chris@132 273 if (x2 > w) x2 = w;
Chris@132 274
Chris@133 275 x0 += bw;
Chris@133 276 x1 += bw;
Chris@133 277 x2 += bw;
Chris@133 278
Chris@132 279 int grey = lrintf(255 * depth);
Chris@132 280 QColor fc = QColor(grey, grey, grey);
Chris@132 281 QColor oc = palette().dark().color();
Chris@132 282
Chris@132 283 paint.setPen(oc);
Chris@132 284 paint.setBrush(fc);
Chris@132 285
Chris@132 286 if (m_orientation == Qt::Horizontal) {
Chris@133 287 paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2));
Chris@132 288 } else {
Chris@133 289 paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1));
Chris@132 290 }
Chris@132 291
Chris@132 292 if (m_showScale) {
Chris@132 293
Chris@132 294 paint.setBrush(oc);
Chris@132 295
Chris@132 296 float prop;
Chris@132 297 if (i >= notches / 4) {
Chris@132 298 prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f))
Chris@132 299 / notches;
Chris@132 300 } else {
Chris@132 301 prop = 0.f;
Chris@132 302 }
Chris@132 303
Chris@132 304 if (m_orientation == Qt::Horizontal) {
Chris@133 305 paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw,
Chris@132 306 x2 - x1, height() * prop));
Chris@132 307 } else {
Chris@133 308 paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1));
Chris@132 309 }
Chris@132 310 }
Chris@132 311
Chris@132 312 paint.setPen(oc);
Chris@132 313 paint.setBrush(palette().background().color());
Chris@132 314
Chris@132 315 if (m_orientation == Qt::Horizontal) {
Chris@133 316 paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2));
Chris@132 317 } else {
Chris@133 318 paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0));
Chris@132 319 }
Chris@132 320 }
Chris@132 321 }
Chris@132 322
Chris@132 323 QSize
Chris@132 324 Thumbwheel::sizeHint() const
Chris@132 325 {
Chris@132 326 if (m_orientation == Qt::Horizontal) {
Chris@132 327 return QSize(80, 12);
Chris@132 328 } else {
Chris@132 329 return QSize(12, 80);
Chris@132 330 }
Chris@132 331 }
Chris@132 332