00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00038 #include "AudioDial.h"
00039
00040 #include "base/RangeMapper.h"
00041
00042 #include <cmath>
00043 #include <iostream>
00044
00045 #include <QTimer>
00046 #include <QPainter>
00047 #include <QPixmap>
00048 #include <QColormap>
00049 #include <QMouseEvent>
00050 #include <QPaintEvent>
00051 #include <QInputDialog>
00052
00053 using std::endl;
00054 using std::cerr;
00055
00056
00058
00059
00060
00061
00062
00063
00064 #define AUDIO_DIAL_MIN (0.25 * M_PI)
00065 #define AUDIO_DIAL_MAX (1.75 * M_PI)
00066 #define AUDIO_DIAL_RANGE (AUDIO_DIAL_MAX - AUDIO_DIAL_MIN)
00067
00068
00069
00070
00071
00072
00073 AudioDial::AudioDial(QWidget *parent) :
00074 QDial(parent),
00075 m_knobColor(Qt::black),
00076 m_meterColor(Qt::white),
00077 m_defaultValue(0),
00078 m_defaultMappedValue(0),
00079 m_mappedValue(0),
00080 m_noMappedUpdate(false),
00081 m_showTooltip(true),
00082 m_rangeMapper(0)
00083 {
00084 m_mouseDial = false;
00085 m_mousePressed = false;
00086
00087 }
00088
00089
00090
00091 AudioDial::~AudioDial (void)
00092 {
00093 delete m_rangeMapper;
00094
00095 }
00096
00097
00098 void AudioDial::setRangeMapper(RangeMapper *mapper)
00099 {
00100
00101
00102 if (m_rangeMapper == mapper) return;
00103
00104 if (!m_rangeMapper && mapper) {
00105 connect(this, SIGNAL(valueChanged(int)),
00106 this, SLOT(updateMappedValue(int)));
00107 }
00108
00109 delete m_rangeMapper;
00110 m_rangeMapper = mapper;
00111
00112 updateMappedValue(value());
00113 }
00114
00115
00116 void AudioDial::paintEvent(QPaintEvent *)
00117 {
00118 QPainter paint;
00119
00120 float angle = AUDIO_DIAL_MIN
00121 + (AUDIO_DIAL_RANGE *
00122 (float(QDial::value() - QDial::minimum()) /
00123 (float(QDial::maximum() - QDial::minimum()))));
00124 int degrees = int(angle * 180.0 / M_PI);
00125
00126 int ns = notchSize();
00127 int numTicks = 1 + (maximum() + ns - minimum()) / ns;
00128
00129 QColor knobColor(m_knobColor);
00130 if (knobColor == Qt::black)
00131 knobColor = palette().window().color();
00132
00133 QColor meterColor(m_meterColor);
00134 if (!isEnabled())
00135 meterColor = palette().mid().color();
00136 else if (m_meterColor == Qt::white)
00137 meterColor = palette().highlight().color();
00138
00139 int m_size = width() < height() ? width() : height();
00140 int scale = 1;
00141 int width = m_size - 2*scale;
00142
00143 paint.begin(this);
00144 paint.setRenderHint(QPainter::Antialiasing, true);
00145 paint.translate(1, 1);
00146
00147 QPen pen;
00148 QColor c;
00149
00150
00151
00152 c = knobColor;
00153 pen.setColor(knobColor);
00154 pen.setWidth(scale * 2);
00155 pen.setCapStyle(Qt::FlatCap);
00156
00157 paint.setPen(pen);
00158 paint.setBrush(c);
00159
00160 int indent = (int)(width * 0.15 + 1);
00161
00162 paint.drawEllipse(indent-1, indent-1, width-2*indent, width-2*indent);
00163
00164 pen.setWidth(3 * scale);
00165 int pos = indent-1 + (width-2*indent) / 20;
00166 int darkWidth = (width-2*indent) * 3 / 4;
00167 while (darkWidth) {
00168 c = c.light(102);
00169 pen.setColor(c);
00170 paint.setPen(pen);
00171 paint.drawEllipse(pos, pos, darkWidth, darkWidth);
00172 if (!--darkWidth) break;
00173 paint.drawEllipse(pos, pos, darkWidth, darkWidth);
00174 if (!--darkWidth) break;
00175 paint.drawEllipse(pos, pos, darkWidth, darkWidth);
00176 ++pos; --darkWidth;
00177 }
00178
00179
00180
00181 if ( notchesVisible() ) {
00182
00183 pen.setColor(palette().dark().color());
00184 pen.setWidth(scale);
00185 paint.setPen(pen);
00186 for (int i = 0; i < numTicks; ++i) {
00187 int div = numTicks;
00188 if (div > 1) --div;
00189 drawTick(paint, AUDIO_DIAL_MIN + (AUDIO_DIAL_MAX - AUDIO_DIAL_MIN) * i / div,
00190 width, true);
00191 }
00192 }
00193
00194
00195
00196 c = meterColor;
00197 pen.setColor(c);
00198 pen.setWidth(indent);
00199 paint.setPen(pen);
00200
00201
00202
00203 int arcLen = -(degrees - 45) * 16;
00204 if (arcLen == 0) arcLen = -16;
00205
00206 paint.drawArc(indent/2, indent/2,
00207 width-indent, width-indent, (180 + 45) * 16, arcLen);
00208
00209 paint.setBrush(Qt::NoBrush);
00210
00211
00212
00213 pen.setWidth(scale);
00214 paint.setPen(pen);
00215
00216
00217
00218 int shadowAngle = -720;
00219 c = knobColor.dark();
00220 for (int arc = 120; arc < 2880; arc += 240) {
00221 pen.setColor(c);
00222 paint.setPen(pen);
00223 paint.drawArc(indent, indent,
00224 width-2*indent, width-2*indent, shadowAngle + arc, 240);
00225 paint.drawArc(indent, indent,
00226 width-2*indent, width-2*indent, shadowAngle - arc, 240);
00227 c = c.light(110);
00228 }
00229
00230
00231
00232 shadowAngle = 2160;
00233 c = palette().dark().color();
00234 for (int arc = 120; arc < 2880; arc += 240) {
00235 pen.setColor(c);
00236 paint.setPen(pen);
00237 paint.drawArc(scale/2, scale/2,
00238 width-scale, width-scale, shadowAngle + arc, 240);
00239 paint.drawArc(scale/2, scale/2,
00240 width-scale, width-scale, shadowAngle - arc, 240);
00241 c = c.light(108);
00242 }
00243
00244
00245
00246 pen.setColor(palette().background().color());
00247 pen.setWidth(scale * 4);
00248 paint.setPen(pen);
00249 paint.drawArc(scale/2, scale/2,
00250 width-scale, width-scale, -45 * 16, -92 * 16);
00251
00252
00253
00254 pen.setColor(palette().dark().color());
00255 pen.setWidth(scale);
00256 paint.setPen(pen);
00257 for (int i = 0; i < numTicks; ++i) {
00258 if (i != 0 && i != numTicks - 1) continue;
00259 int div = numTicks;
00260 if (div > 1) --div;
00261 drawTick(paint, AUDIO_DIAL_MIN + (AUDIO_DIAL_MAX - AUDIO_DIAL_MIN) * i / div,
00262 width, false);
00263 }
00264
00265
00266
00267 float hyp = float(width) / 2.0;
00268 float len = hyp - indent;
00269 --len;
00270
00271 float x0 = hyp;
00272 float y0 = hyp;
00273
00274 float x = hyp - len * sin(angle);
00275 float y = hyp + len * cos(angle);
00276
00277 c = palette().dark().color();
00278 pen.setColor(isEnabled() ? c.dark(130) : c);
00279 pen.setWidth(scale * 2);
00280 paint.setPen(pen);
00281 paint.drawLine(int(x0), int(y0), int(x), int(y));
00282
00283 paint.end();
00284 }
00285
00286
00287 void AudioDial::drawTick(QPainter &paint,
00288 float angle, int size, bool internal)
00289 {
00290 float hyp = float(size) / 2.0;
00291 float x0 = hyp - (hyp - 1) * sin(angle);
00292 float y0 = hyp + (hyp - 1) * cos(angle);
00293
00294
00295
00296 if (internal) {
00297
00298 float len = hyp / 4;
00299 float x1 = hyp - (hyp - len) * sin(angle);
00300 float y1 = hyp + (hyp - len) * cos(angle);
00301
00302 paint.drawLine(int(x0), int(y0), int(x1), int(y1));
00303
00304 } else {
00305
00306 float len = hyp / 4;
00307 float x1 = hyp - (hyp + len) * sin(angle);
00308 float y1 = hyp + (hyp + len) * cos(angle);
00309
00310 paint.drawLine(int(x0), int(y0), int(x1), int(y1));
00311 }
00312 }
00313
00314
00315 void AudioDial::setKnobColor(const QColor& color)
00316 {
00317 m_knobColor = color;
00318 update();
00319 }
00320
00321
00322 void AudioDial::setMeterColor(const QColor& color)
00323 {
00324 m_meterColor = color;
00325 update();
00326 }
00327
00328
00329 void AudioDial::setMouseDial(bool mouseDial)
00330 {
00331 m_mouseDial = mouseDial;
00332 }
00333
00334
00335 void AudioDial::setDefaultValue(int defaultValue)
00336 {
00337 m_defaultValue = defaultValue;
00338 if (m_rangeMapper) {
00339 m_defaultMappedValue = m_rangeMapper->getValueForPosition(defaultValue);
00340 }
00341 }
00342
00343 void AudioDial::setValue(int value)
00344 {
00345 QDial::setValue(value);
00346 updateMappedValue(value);
00347 }
00348
00349 void AudioDial::setDefaultMappedValue(float value)
00350 {
00351 m_defaultMappedValue = value;
00352 if (m_rangeMapper) {
00353 m_defaultValue = m_rangeMapper->getPositionForValue(value);
00354 }
00355 }
00356
00357 void AudioDial::setMappedValue(float mappedValue)
00358 {
00359 if (m_rangeMapper) {
00360 int newPosition = m_rangeMapper->getPositionForValue(mappedValue);
00361 bool changed = (m_mappedValue != mappedValue);
00362 m_mappedValue = mappedValue;
00363 m_noMappedUpdate = true;
00364 std::cerr << "AudioDial::setMappedValue(" << mappedValue << "): new position is " << newPosition << std::endl;
00365 if (newPosition != value()) {
00366 setValue(newPosition);
00367 } else if (changed) {
00368 emit valueChanged(newPosition);
00369 }
00370 m_noMappedUpdate = false;
00371 } else {
00372 setValue(int(mappedValue));
00373 }
00374 }
00375
00376
00377 void AudioDial::setShowToolTip(bool show)
00378 {
00379 m_showTooltip = show;
00380 m_noMappedUpdate = true;
00381 updateMappedValue(value());
00382 m_noMappedUpdate = false;
00383 }
00384
00385
00386 float AudioDial::mappedValue() const
00387 {
00388 if (m_rangeMapper) {
00389
00390 return m_mappedValue;
00391 }
00392 return value();
00393 }
00394
00395
00396 void AudioDial::updateMappedValue(int value)
00397 {
00398 if (!m_noMappedUpdate) {
00399 if (m_rangeMapper) {
00400 m_mappedValue = m_rangeMapper->getValueForPosition(value);
00401 } else {
00402 m_mappedValue = value;
00403 }
00404 }
00405
00406 if (m_showTooltip) {
00407 QString name = objectName();
00408 QString unit = "";
00409 QString text;
00410 if (m_rangeMapper) unit = m_rangeMapper->getUnit();
00411 if (name != "") {
00412 text = tr("%1: %2%3").arg(name).arg(m_mappedValue).arg(unit);
00413 } else {
00414 text = tr("%2%3").arg(m_mappedValue).arg(unit);
00415 }
00416 setToolTip(text);
00417 }
00418 }
00419
00420 void
00421 AudioDial::setToDefault()
00422 {
00423 if (m_rangeMapper) {
00424 setMappedValue(m_defaultMappedValue);
00425 return;
00426 }
00427 int dv = m_defaultValue;
00428 if (dv < minimum()) dv = minimum();
00429 if (dv > maximum()) dv = maximum();
00430 setValue(m_defaultValue);
00431 }
00432
00433
00434 void AudioDial::mousePressEvent(QMouseEvent *mouseEvent)
00435 {
00436 if (m_mouseDial) {
00437 QDial::mousePressEvent(mouseEvent);
00438 } else if (mouseEvent->button() == Qt::MidButton ||
00439 ((mouseEvent->button() == Qt::LeftButton) &&
00440 (mouseEvent->modifiers() & Qt::ControlModifier))) {
00441 setToDefault();
00442 } else if (mouseEvent->button() == Qt::LeftButton) {
00443 m_mousePressed = true;
00444 m_posMouse = mouseEvent->pos();
00445 }
00446 }
00447
00448
00449 void AudioDial::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
00450 {
00452
00453 if (m_mouseDial) {
00454 QDial::mouseDoubleClickEvent(mouseEvent);
00455 } else if (mouseEvent->button() != Qt::LeftButton) {
00456 return;
00457 }
00458
00459 bool ok = false;
00460
00461 if (m_rangeMapper) {
00462
00463 float min = m_rangeMapper->getValueForPosition(minimum());
00464 float max = m_rangeMapper->getValueForPosition(maximum());
00465
00466 if (min > max) {
00467 float tmp = min;
00468 min = max;
00469 max = tmp;
00470 }
00471
00472 QString unit = m_rangeMapper->getUnit();
00473
00474 QString text;
00475 if (objectName() != "") {
00476 if (unit != "") {
00477 text = tr("New value for %1, from %2 to %3 %4:")
00478 .arg(objectName()).arg(min).arg(max).arg(unit);
00479 } else {
00480 text = tr("New value for %1, from %2 to %3:")
00481 .arg(objectName()).arg(min).arg(max);
00482 }
00483 } else {
00484 if (unit != "") {
00485 text = tr("Enter a new value from %1 to %2 %3:")
00486 .arg(min).arg(max).arg(unit);
00487 } else {
00488 text = tr("Enter a new value from %1 to %2:")
00489 .arg(min).arg(max);
00490 }
00491 }
00492
00493 float newValue = QInputDialog::getDouble
00494 (this,
00495 tr("Enter new value"),
00496 text,
00497 m_mappedValue,
00498 min,
00499 max,
00500 4,
00501 &ok);
00502
00503 if (ok) {
00504 setMappedValue(newValue);
00505 }
00506
00507 } else {
00508
00509 int newPosition = QInputDialog::getInteger
00510 (this,
00511 tr("Enter new value"),
00512 tr("Enter a new value from %1 to %2:")
00513 .arg(minimum()).arg(maximum()),
00514 value(), minimum(), maximum(), pageStep(), &ok);
00515
00516 if (ok) {
00517 setValue(newPosition);
00518 }
00519 }
00520 }
00521
00522
00523 void AudioDial::mouseMoveEvent(QMouseEvent *mouseEvent)
00524 {
00525 if (m_mouseDial) {
00526 QDial::mouseMoveEvent(mouseEvent);
00527 } else if (m_mousePressed) {
00528 const QPoint& posMouse = mouseEvent->pos();
00529 int v = QDial::value()
00530 + (posMouse.x() - m_posMouse.x())
00531 + (m_posMouse.y() - posMouse.y());
00532 if (v > QDial::maximum())
00533 v = QDial::maximum();
00534 else
00535 if (v < QDial::minimum())
00536 v = QDial::minimum();
00537 m_posMouse = posMouse;
00538 QDial::setValue(v);
00539 }
00540 }
00541
00542
00543 void AudioDial::mouseReleaseEvent(QMouseEvent *mouseEvent)
00544 {
00545 if (m_mouseDial) {
00546 QDial::mouseReleaseEvent(mouseEvent);
00547 } else if (m_mousePressed) {
00548 m_mousePressed = false;
00549 }
00550 }
00551
00552 void
00553 AudioDial::enterEvent(QEvent *e)
00554 {
00555 QDial::enterEvent(e);
00556 emit mouseEntered();
00557 }
00558
00559 void
00560 AudioDial::leaveEvent(QEvent *e)
00561 {
00562 QDial::enterEvent(e);
00563 emit mouseLeft();
00564 }
00565