annotate widgets/AudioDial.cpp @ 11:2d5005f2b3d9

* Rework handling of layer properties in file I/O -- we now get the individual layers to load and save them rather than doing it via generic property lists in the base class, so as to ensure we read and write meaningful values rather than generic int values requiring conversion.
author Chris Cannam
date Thu, 19 Jan 2006 12:54:38 +0000
parents 37b110168acf
children c53b949ef142
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@5 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 /**
Chris@0 11 * A rotary dial widget.
Chris@0 12 *
Chris@0 13 * Based on an original design by Thorsten Wilms.
Chris@0 14 *
Chris@0 15 * Implemented as a widget for the Rosegarden MIDI and audio sequencer
Chris@0 16 * and notation editor by Chris Cannam.
Chris@0 17 *
Chris@0 18 * Extracted into a standalone Qt3 widget by Pedro Lopez-Cabanillas
Chris@0 19 * and adapted for use in QSynth.
Chris@0 20 *
Chris@0 21 * Ported to Qt4 by Chris Cannam.
Chris@0 22 *
Chris@0 23 * This file copyright 2003-2005 Chris Cannam, copyright 2005 Pedro
Chris@0 24 * Lopez-Cabanillas.
Chris@0 25 *
Chris@0 26 * This program is free software; you can redistribute it and/or
Chris@0 27 * modify it under the terms of the GNU General Public License as
Chris@0 28 * published by the Free Software Foundation; either version 2 of the
Chris@0 29 * License, or (at your option) any later version. See the file
Chris@0 30 * COPYING included with this distribution for more information.
Chris@0 31 */
Chris@0 32
Chris@0 33 #include "AudioDial.h"
Chris@0 34
Chris@0 35 #include <cmath>
Chris@0 36 #include <iostream>
Chris@0 37
Chris@0 38 #include <QTimer>
Chris@0 39 #include <QPainter>
Chris@0 40 #include <QPixmap>
Chris@0 41 #include <QImage>
Chris@0 42 #include <QColormap>
Chris@0 43 #include <QMouseEvent>
Chris@0 44 #include <QPaintEvent>
Chris@0 45
Chris@0 46 using std::endl;
Chris@0 47 using std::cerr;
Chris@0 48
Chris@0 49
Chris@0 50 //!!! Pedro updated his version to use my up/down response code from RG -- need to grab that code in preference to this version from Rui
Chris@0 51
Chris@0 52
Chris@0 53 //-------------------------------------------------------------------------
Chris@0 54 // AudioDial - Instance knob widget class.
Chris@0 55 //
Chris@0 56
Chris@0 57 #define AUDIO_DIAL_MIN (0.25 * M_PI)
Chris@0 58 #define AUDIO_DIAL_MAX (1.75 * M_PI)
Chris@0 59 #define AUDIO_DIAL_RANGE (AUDIO_DIAL_MAX - AUDIO_DIAL_MIN)
Chris@0 60
Chris@0 61
Chris@0 62 // Constructor.
Chris@0 63 AudioDial::AudioDial(QWidget *parent) :
Chris@0 64 QDial(parent),
Chris@0 65 m_knobColor(Qt::black), m_meterColor(Qt::white)
Chris@0 66 {
Chris@0 67 m_mouseDial = false;
Chris@0 68 m_mousePressed = false;
Chris@0 69 }
Chris@0 70
Chris@0 71
Chris@0 72 // Destructor.
Chris@0 73 AudioDial::~AudioDial (void)
Chris@0 74 {
Chris@0 75 }
Chris@0 76
Chris@0 77
Chris@0 78 void AudioDial::paintEvent(QPaintEvent *)
Chris@0 79 {
Chris@0 80 QPainter paint;
Chris@0 81
Chris@0 82 float angle = AUDIO_DIAL_MIN // offset
Chris@0 83 + (AUDIO_DIAL_RANGE *
Chris@0 84 (float(QDial::value() - QDial::minimum()) /
Chris@0 85 (float(QDial::maximum() - QDial::minimum()))));
Chris@0 86 int degrees = int(angle * 180.0 / M_PI);
Chris@0 87
Chris@0 88 int ns = notchSize();
Chris@0 89 int numTicks = 1 + (maximum() + ns - minimum()) / ns;
Chris@0 90
Chris@0 91 QColor knobColor(m_knobColor);
Chris@0 92 if (knobColor == Qt::black)
Chris@0 93 knobColor = palette().mid().color();
Chris@0 94
Chris@0 95 QColor meterColor(m_meterColor);
Chris@0 96 if (!isEnabled())
Chris@0 97 meterColor = palette().mid().color();
Chris@0 98 else if (m_meterColor == Qt::white)
Chris@0 99 meterColor = palette().highlight().color();
Chris@0 100
Chris@0 101 int m_size = width() < height() ? width() : height();
Chris@0 102 int scale = 1;
Chris@0 103 int width = m_size - 2*scale, height = m_size - 2*scale;
Chris@0 104
Chris@0 105 paint.begin(this);
Chris@0 106 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@0 107 paint.translate(1, 1);
Chris@0 108
Chris@0 109 QPen pen;
Chris@0 110 QColor c;
Chris@0 111
Chris@0 112 // Knob body and face...
Chris@0 113
Chris@0 114 c = knobColor;
Chris@0 115 pen.setColor(knobColor);
Chris@0 116 pen.setWidth(scale * 2);
Chris@0 117 pen.setCapStyle(Qt::FlatCap);
Chris@0 118
Chris@0 119 paint.setPen(pen);
Chris@0 120 paint.setBrush(c);
Chris@0 121
Chris@0 122 int indent = (int)(width * 0.15 + 1);
Chris@0 123
Chris@0 124 paint.drawEllipse(indent-1, indent-1, width-2*indent, width-2*indent);
Chris@0 125
Chris@0 126 pen.setWidth(3 * scale);
Chris@0 127 int pos = indent-1 + (width-2*indent) / 20;
Chris@0 128 int darkWidth = (width-2*indent) * 3 / 4;
Chris@0 129 while (darkWidth) {
Chris@0 130 c = c.light(102);
Chris@0 131 pen.setColor(c);
Chris@0 132 paint.setPen(pen);
Chris@0 133 paint.drawEllipse(pos, pos, darkWidth, darkWidth);
Chris@0 134 if (!--darkWidth) break;
Chris@0 135 paint.drawEllipse(pos, pos, darkWidth, darkWidth);
Chris@0 136 if (!--darkWidth) break;
Chris@0 137 paint.drawEllipse(pos, pos, darkWidth, darkWidth);
Chris@0 138 ++pos; --darkWidth;
Chris@0 139 }
Chris@0 140
Chris@0 141 // Tick notches...
Chris@0 142
Chris@0 143 if ( true/* notchesVisible() */) {
Chris@0 144 // std::cerr << "Notches visible" << std::endl;
Chris@0 145 pen.setColor(palette().dark().color());
Chris@0 146 pen.setWidth(scale);
Chris@0 147 paint.setPen(pen);
Chris@0 148 for (int i = 0; i < numTicks; ++i) {
Chris@0 149 int div = numTicks;
Chris@0 150 if (div > 1) --div;
Chris@0 151 drawTick(paint, AUDIO_DIAL_MIN + (AUDIO_DIAL_MAX - AUDIO_DIAL_MIN) * i / div,
Chris@0 152 width, true);
Chris@0 153 }
Chris@0 154 }
Chris@0 155
Chris@0 156 // The bright metering bit...
Chris@0 157
Chris@0 158 c = meterColor;
Chris@0 159 pen.setColor(c);
Chris@0 160 pen.setWidth(indent);
Chris@0 161 paint.setPen(pen);
Chris@0 162
Chris@0 163 // std::cerr << "degrees " << degrees << ", gives us " << -(degrees - 45) * 16 << std::endl;
Chris@0 164
Chris@0 165 int arcLen = -(degrees - 45) * 16;
Chris@0 166 if (arcLen == 0) arcLen = -16;
Chris@0 167
Chris@0 168 paint.drawArc(indent/2, indent/2,
Chris@0 169 width-indent, width-indent, (180 + 45) * 16, arcLen);
Chris@0 170
Chris@0 171 paint.setBrush(Qt::NoBrush);
Chris@0 172
Chris@0 173 // Shadowing...
Chris@0 174
Chris@0 175 pen.setWidth(scale);
Chris@0 176 paint.setPen(pen);
Chris@0 177
Chris@0 178 // Knob shadow...
Chris@0 179
Chris@0 180 int shadowAngle = -720;
Chris@0 181 c = knobColor.dark();
Chris@0 182 for (int arc = 120; arc < 2880; arc += 240) {
Chris@0 183 pen.setColor(c);
Chris@0 184 paint.setPen(pen);
Chris@0 185 paint.drawArc(indent, indent,
Chris@0 186 width-2*indent, width-2*indent, shadowAngle + arc, 240);
Chris@0 187 paint.drawArc(indent, indent,
Chris@0 188 width-2*indent, width-2*indent, shadowAngle - arc, 240);
Chris@0 189 c = c.light(110);
Chris@0 190 }
Chris@0 191
Chris@0 192 // Scale shadow...
Chris@0 193
Chris@0 194 shadowAngle = 2160;
Chris@0 195 c = palette().dark().color();
Chris@0 196 for (int arc = 120; arc < 2880; arc += 240) {
Chris@0 197 pen.setColor(c);
Chris@0 198 paint.setPen(pen);
Chris@0 199 paint.drawArc(scale/2, scale/2,
Chris@0 200 width-scale, width-scale, shadowAngle + arc, 240);
Chris@0 201 paint.drawArc(scale/2, scale/2,
Chris@0 202 width-scale, width-scale, shadowAngle - arc, 240);
Chris@0 203 c = c.light(108);
Chris@0 204 }
Chris@0 205
Chris@0 206 // Undraw the bottom part...
Chris@0 207
Chris@0 208 pen.setColor(palette().background().color());
Chris@0 209 pen.setWidth(scale * 4);
Chris@0 210 paint.setPen(pen);
Chris@0 211 paint.drawArc(scale/2, scale/2,
Chris@0 212 width-scale, width-scale, -45 * 16, -92 * 16);
Chris@0 213
Chris@0 214 // Scale ends...
Chris@0 215
Chris@0 216 pen.setColor(palette().dark().color());
Chris@0 217 pen.setWidth(scale);
Chris@0 218 paint.setPen(pen);
Chris@0 219 for (int i = 0; i < numTicks; ++i) {
Chris@0 220 if (i != 0 && i != numTicks - 1) continue;
Chris@0 221 int div = numTicks;
Chris@0 222 if (div > 1) --div;
Chris@0 223 drawTick(paint, AUDIO_DIAL_MIN + (AUDIO_DIAL_MAX - AUDIO_DIAL_MIN) * i / div,
Chris@0 224 width, false);
Chris@0 225 }
Chris@0 226
Chris@0 227 // Pointer notch...
Chris@0 228
Chris@0 229 float hyp = float(width) / 2.0;
Chris@0 230 float len = hyp - indent;
Chris@0 231 --len;
Chris@0 232
Chris@0 233 float x0 = hyp;
Chris@0 234 float y0 = hyp;
Chris@0 235
Chris@0 236 float x = hyp - len * sin(angle);
Chris@0 237 float y = hyp + len * cos(angle);
Chris@0 238
Chris@0 239 c = palette().dark().color();
Chris@0 240 pen.setColor(isEnabled() ? c.dark(130) : c);
Chris@0 241 pen.setWidth(scale * 2);
Chris@0 242 paint.setPen(pen);
Chris@0 243 paint.drawLine(int(x0), int(y0), int(x), int(y));
Chris@0 244
Chris@0 245 paint.end();
Chris@0 246 }
Chris@0 247
Chris@0 248
Chris@0 249 void AudioDial::drawTick(QPainter &paint,
Chris@0 250 float angle, int size, bool internal)
Chris@0 251 {
Chris@0 252 float hyp = float(size) / 2.0;
Chris@0 253 float x0 = hyp - (hyp - 1) * sin(angle);
Chris@0 254 float y0 = hyp + (hyp - 1) * cos(angle);
Chris@0 255
Chris@0 256 // cerr << "drawTick: angle " << angle << ", size " << size << ", internal " << internal << endl;
Chris@0 257
Chris@0 258 if (internal) {
Chris@0 259
Chris@0 260 float len = hyp / 4;
Chris@0 261 float x1 = hyp - (hyp - len) * sin(angle);
Chris@0 262 float y1 = hyp + (hyp - len) * cos(angle);
Chris@0 263
Chris@0 264 paint.drawLine(int(x0), int(y0), int(x1), int(y1));
Chris@0 265
Chris@0 266 } else {
Chris@0 267
Chris@0 268 float len = hyp / 4;
Chris@0 269 float x1 = hyp - (hyp + len) * sin(angle);
Chris@0 270 float y1 = hyp + (hyp + len) * cos(angle);
Chris@0 271
Chris@0 272 paint.drawLine(int(x0), int(y0), int(x1), int(y1));
Chris@0 273 }
Chris@0 274 }
Chris@0 275
Chris@0 276
Chris@0 277 void AudioDial::setKnobColor(const QColor& color)
Chris@0 278 {
Chris@0 279 m_knobColor = color;
Chris@0 280 update();
Chris@0 281 }
Chris@0 282
Chris@0 283
Chris@0 284 void AudioDial::setMeterColor(const QColor& color)
Chris@0 285 {
Chris@0 286 m_meterColor = color;
Chris@0 287 update();
Chris@0 288 }
Chris@0 289
Chris@0 290
Chris@0 291 void AudioDial::setMouseDial(bool mouseDial)
Chris@0 292 {
Chris@0 293 m_mouseDial = mouseDial;
Chris@0 294 }
Chris@0 295
Chris@0 296
Chris@0 297 // Alternate mouse behavior event handlers.
Chris@0 298 void AudioDial::mousePressEvent(QMouseEvent *mouseEvent)
Chris@0 299 {
Chris@0 300 if (m_mouseDial) {
Chris@0 301 QDial::mousePressEvent(mouseEvent);
Chris@0 302 } else if (mouseEvent->button() == Qt::LeftButton) {
Chris@0 303 m_mousePressed = true;
Chris@0 304 m_posMouse = mouseEvent->pos();
Chris@0 305 }
Chris@0 306 }
Chris@0 307
Chris@0 308
Chris@0 309 void AudioDial::mouseMoveEvent(QMouseEvent *mouseEvent)
Chris@0 310 {
Chris@0 311 if (m_mouseDial) {
Chris@0 312 QDial::mouseMoveEvent(mouseEvent);
Chris@0 313 } else if (m_mousePressed) {
Chris@0 314 const QPoint& posMouse = mouseEvent->pos();
Chris@0 315 int v = QDial::value()
Chris@0 316 + (posMouse.x() - m_posMouse.x())
Chris@0 317 + (m_posMouse.y() - posMouse.y());
Chris@0 318 if (v > QDial::maximum())
Chris@0 319 v = QDial::maximum();
Chris@0 320 else
Chris@0 321 if (v < QDial::minimum())
Chris@0 322 v = QDial::minimum();
Chris@0 323 m_posMouse = posMouse;
Chris@0 324 QDial::setValue(v);
Chris@0 325 }
Chris@0 326 }
Chris@0 327
Chris@0 328
Chris@0 329 void AudioDial::mouseReleaseEvent(QMouseEvent *mouseEvent)
Chris@0 330 {
Chris@0 331 if (m_mouseDial) {
Chris@0 332 QDial::mouseReleaseEvent(mouseEvent);
Chris@0 333 } else if (m_mousePressed) {
Chris@0 334 m_mousePressed = false;
Chris@0 335 }
Chris@0 336 }
Chris@0 337
Chris@0 338 #ifdef INCLUDE_MOCFILES
Chris@0 339 #include "AudioDial.moc.cpp"
Chris@0 340 #endif
Chris@0 341