Thumbwheel.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 QMUL.
00008 
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "Thumbwheel.h"
00017 
00018 #include "base/RangeMapper.h"
00019 #include "base/Profiler.h"
00020 
00021 #include <QMouseEvent>
00022 #include <QPaintEvent>
00023 #include <QWheelEvent>
00024 #include <QInputDialog>
00025 #include <QPainter>
00026 #include <QPainterPath>
00027 
00028 #include <cmath>
00029 #include <iostream>
00030 
00031 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
00032                        QWidget *parent) :
00033     QWidget(parent),
00034     m_min(0),
00035     m_max(100),
00036     m_default(50),
00037     m_value(50),
00038     m_mappedValue(50),
00039     m_noMappedUpdate(false),
00040     m_rotation(0.5),
00041     m_orientation(orientation),
00042     m_speed(1.0),
00043     m_tracking(true),
00044     m_showScale(true),
00045     m_clicked(false),
00046     m_atDefault(true),
00047     m_clickRotation(m_rotation),
00048     m_showTooltip(true),
00049     m_rangeMapper(0)
00050 {
00051 }
00052 
00053 Thumbwheel::~Thumbwheel()
00054 {
00055     delete m_rangeMapper;
00056 }
00057 
00058 void
00059 Thumbwheel::setRangeMapper(RangeMapper *mapper)
00060 {
00061     if (m_rangeMapper == mapper) return;
00062 
00063     if (!m_rangeMapper && mapper) {
00064         connect(this, SIGNAL(valueChanged(int)),
00065                 this, SLOT(updateMappedValue(int)));
00066     }
00067 
00068     delete m_rangeMapper;
00069     m_rangeMapper = mapper;
00070 
00071     updateMappedValue(getValue());
00072 }
00073 
00074 void
00075 Thumbwheel::setShowToolTip(bool show)
00076 {
00077     m_showTooltip = show;
00078     m_noMappedUpdate = true;
00079     updateMappedValue(getValue());
00080     m_noMappedUpdate = false;
00081 }
00082 
00083 void
00084 Thumbwheel::setMinimumValue(int min)
00085 {
00086     if (m_min == min) return;
00087 
00088     m_min = min;
00089     if (m_max <= m_min) m_max = m_min + 1;
00090     if (m_value < m_min) m_value = m_min;
00091     if (m_value > m_max) m_value = m_max;
00092 
00093     m_rotation = float(m_value - m_min) / float(m_max - m_min);
00094     update();
00095 }
00096 
00097 int
00098 Thumbwheel::getMinimumValue() const
00099 {
00100     return m_min;
00101 }
00102 
00103 void
00104 Thumbwheel::setMaximumValue(int max)
00105 {
00106     if (m_max == max) return;
00107 
00108     m_max = max;
00109     if (m_min >= m_max) m_min = m_max - 1;
00110     if (m_value < m_min) m_value = m_min;
00111     if (m_value > m_max) m_value = m_max;
00112 
00113     m_rotation = float(m_value - m_min) / float(m_max - m_min);
00114     update();
00115 }
00116 
00117 int
00118 Thumbwheel::getMaximumValue() const
00119 {
00120     return m_max;
00121 }
00122 
00123 void
00124 Thumbwheel::setDefaultValue(int deft)
00125 {
00126     if (m_default == deft) return;
00127 
00128     m_default = deft;
00129     if (m_atDefault) {
00130         setValue(m_default);
00131         m_atDefault = true; // setValue unsets this
00132         emit valueChanged(getValue());
00133     }
00134 }
00135 
00136 void
00137 Thumbwheel::setMappedValue(float mappedValue)
00138 {
00139     if (m_rangeMapper) {
00140         int newValue = m_rangeMapper->getPositionForValue(mappedValue);
00141         bool changed = (m_mappedValue != mappedValue);
00142         m_mappedValue = mappedValue;
00143         m_noMappedUpdate = true;
00144 //        std::cerr << "Thumbwheel::setMappedValue(" << mappedValue << "): new value is " << newValue << " (visible " << isVisible() << ")" << std::endl;
00145         if (newValue != getValue()) {
00146             setValue(newValue);
00147             changed = true;
00148         }
00149         if (changed) emit valueChanged(newValue);
00150         m_noMappedUpdate = false;
00151     } else {
00152         int v = int(mappedValue);
00153         if (v != getValue()) {
00154             setValue(v);
00155             emit valueChanged(v);
00156         }
00157     }
00158 }
00159 
00160 int
00161 Thumbwheel::getDefaultValue() const
00162 {
00163     return m_default;
00164 }
00165 
00166 void
00167 Thumbwheel::setValue(int value)
00168 {
00169 //    std::cerr << "Thumbwheel::setValue(" << value << ") (from " << m_value
00170 //              << ", rotation " << m_rotation << ")" << " (visible " << isVisible() << ")" << std::endl;
00171 
00172     if (m_value != value) {
00173 
00174         m_atDefault = false;
00175 
00176         if (value < m_min) value = m_min;
00177         if (value > m_max) value = m_max;
00178         m_value = value;
00179     }
00180 
00181     m_rotation = float(m_value - m_min) / float(m_max - m_min);
00182     if (isVisible()) update();
00183 }
00184 
00185 void
00186 Thumbwheel::resetToDefault()
00187 {
00188     if (m_default == m_value) return;
00189     setValue(m_default);
00190     m_atDefault = true;
00191     emit valueChanged(getValue());
00192 }
00193 
00194 int
00195 Thumbwheel::getValue() const
00196 {
00197     return m_value;
00198 }
00199 
00200 float
00201 Thumbwheel::getMappedValue() const
00202 {
00203     if (m_rangeMapper) {
00204 //        std::cerr << "Thumbwheel::getMappedValue(): value = " << getValue() << ", mappedValue = " << m_mappedValue << std::endl;
00205         return m_mappedValue;
00206     }
00207     return getValue();
00208 }
00209 
00210 void
00211 Thumbwheel::updateMappedValue(int value)
00212 {
00213     if (!m_noMappedUpdate) {
00214         if (m_rangeMapper) {
00215             m_mappedValue = m_rangeMapper->getValueForPosition(value);
00216         } else {
00217             m_mappedValue = value;
00218         }
00219     }
00220 
00221     if (m_showTooltip) {
00222         QString name = objectName();
00223         QString unit = "";
00224         QString text;
00225         if (m_rangeMapper) unit = m_rangeMapper->getUnit();
00226         if (name != "") {
00227             text = tr("%1: %2%3").arg(name).arg(m_mappedValue).arg(unit);
00228         } else {
00229             text = tr("%2%3").arg(m_mappedValue).arg(unit);
00230         }
00231         setToolTip(text);
00232     }
00233 }
00234 
00235 void
00236 Thumbwheel::scroll(bool up)
00237 {
00238     int step = lrintf(m_speed);
00239     if (step == 0) step = 1;
00240 
00241     if (up) {
00242         setValue(m_value + step);
00243     } else {
00244         setValue(m_value - step);
00245     }
00246     
00247     emit valueChanged(getValue());
00248 }
00249 
00250 void
00251 Thumbwheel::setSpeed(float speed)
00252 {
00253     m_speed = speed;
00254 }
00255 
00256 float
00257 Thumbwheel::getSpeed() const
00258 {
00259     return m_speed;
00260 }
00261 
00262 void
00263 Thumbwheel::setTracking(bool tracking)
00264 {
00265     m_tracking = tracking;
00266 }
00267 
00268 bool
00269 Thumbwheel::getTracking() const
00270 {
00271     return m_tracking;
00272 }
00273 
00274 void
00275 Thumbwheel::setShowScale(bool showScale)
00276 {
00277     m_showScale = showScale;
00278 }
00279 
00280 bool
00281 Thumbwheel::getShowScale() const
00282 {
00283     return m_showScale;
00284 }
00285 
00286 void
00287 Thumbwheel::enterEvent(QEvent *)
00288 {
00289     emit mouseEntered();
00290 }
00291 
00292 void
00293 Thumbwheel::leaveEvent(QEvent *)
00294 {
00295     emit mouseLeft();
00296 }
00297 
00298 void
00299 Thumbwheel::mousePressEvent(QMouseEvent *e)
00300 {
00301     if (e->button() == Qt::MidButton ||
00302         ((e->button() == Qt::LeftButton) &&
00303          (e->modifiers() & Qt::ControlModifier))) {
00304         resetToDefault();
00305     } else if (e->button() == Qt::LeftButton) {
00306         m_clicked = true;
00307         m_clickPos = e->pos();
00308         m_clickRotation = m_rotation;
00309     }
00310 }
00311 
00312 void
00313 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
00314 {
00316 
00317     if (mouseEvent->button() != Qt::LeftButton) {
00318         return;
00319     }
00320 
00321     bool ok = false;
00322 
00323     if (m_rangeMapper) {
00324         
00325         float min = m_rangeMapper->getValueForPosition(m_min);
00326         float max = m_rangeMapper->getValueForPosition(m_max);
00327                 
00328         if (min > max) { 
00329             float tmp = min;
00330             min = max;
00331             max = tmp;
00332         }
00333 
00334         QString unit = m_rangeMapper->getUnit();
00335         
00336         QString text;
00337         if (objectName() != "") {
00338             if (unit != "") {
00339                 text = tr("New value for %1, from %2 to %3 %4:")
00340                     .arg(objectName()).arg(min).arg(max).arg(unit);
00341             } else {
00342                 text = tr("New value for %1, from %2 to %3:")
00343                     .arg(objectName()).arg(min).arg(max);
00344             }
00345         } else {
00346             if (unit != "") {
00347                 text = tr("Enter a new value from %1 to %2 %3:")
00348                     .arg(min).arg(max).arg(unit);
00349             } else {
00350                 text = tr("Enter a new value from %1 to %2:")
00351                     .arg(min).arg(max);
00352             }
00353         }
00354         
00355         float newValue = QInputDialog::getDouble
00356             (this,
00357              tr("Enter new value"),
00358              text,
00359              m_mappedValue,
00360              min,
00361              max,
00362              4, 
00363              &ok);
00364         
00365         if (ok) {
00366             setMappedValue(newValue);
00367         }
00368         
00369     } else {
00370         
00371         int newValue = QInputDialog::getInteger
00372             (this,
00373              tr("Enter new value"),
00374              tr("Enter a new value from %1 to %2:")
00375              .arg(m_min).arg(m_max),
00376              getValue(), m_min, m_max, 1, &ok);
00377         
00378         if (ok) {
00379             setValue(newValue);
00380         }
00381     }
00382 }
00383 
00384 
00385 void
00386 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
00387 {
00388     if (!m_clicked) return;
00389     int dist = 0;
00390     if (m_orientation == Qt::Horizontal) {
00391         dist = e->x() - m_clickPos.x();
00392     } else {
00393         dist = e->y() - m_clickPos.y();
00394     }
00395 
00396     float rotation = m_clickRotation + (m_speed * dist) / 100;
00397     if (rotation < 0.f) rotation = 0.f;
00398     if (rotation > 1.f) rotation = 1.f;
00399     int value = lrintf(m_min + (m_max - m_min) * m_rotation);
00400     if (value != m_value) {
00401         setValue(value);
00402         if (m_tracking) emit valueChanged(getValue());
00403         m_rotation = rotation;
00404     } else if (fabsf(rotation - m_rotation) > 0.001) {
00405         m_rotation = rotation;
00406         repaint();
00407     }
00408 }
00409 
00410 void
00411 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
00412 {
00413     if (!m_clicked) return;
00414     bool reallyTracking = m_tracking;
00415     m_tracking = true;
00416     mouseMoveEvent(e);
00417     m_tracking = reallyTracking;
00418     m_clicked = false;
00419 }
00420 
00421 void
00422 Thumbwheel::wheelEvent(QWheelEvent *e)
00423 {
00424     int step = lrintf(m_speed);
00425     if (step == 0) step = 1;
00426 
00427     if (e->delta() > 0) {
00428         setValue(m_value + step);
00429     } else {
00430         setValue(m_value - step);
00431     }
00432     
00433     emit valueChanged(getValue());
00434 }
00435 
00436 void
00437 Thumbwheel::paintEvent(QPaintEvent *)
00438 {
00439     Profiler profiler("Thumbwheel::paintEvent", true);
00440 
00441     int bw = 3;
00442 
00443     QRect subclip;
00444     if (m_orientation == Qt::Horizontal) {
00445         subclip = QRect(bw, bw+1, width() - bw*2, height() - bw*2 - 2);
00446     } else {
00447         subclip = QRect(bw+1, bw, width() - bw*2 - 2, height() - bw*2);
00448     }
00449 
00450     QPainter paint(this);
00451     paint.fillRect(subclip, palette().background().color());
00452 
00453     paint.setRenderHint(QPainter::Antialiasing, true);
00454 
00455     float w  = width();
00456     float w0 = 0.5;
00457     float w1 = w - 0.5;
00458 
00459     float h  = height();
00460     float h0 = 0.5;
00461     float h1 = h - 0.5;
00462 
00463     for (int i = bw-1; i >= 0; --i) {
00464 //    for (int i = 0; i < 1; ++i) {
00465 
00466         int grey = (i + 1) * (256 / (bw + 1));
00467         QColor fc = QColor(grey, grey, grey);
00468         paint.setPen(fc);
00469 
00470         QPainterPath path;
00471 
00472         if (m_orientation == Qt::Horizontal) {
00473             path.moveTo(w0 + i, h0 + i + 2);
00474             path.quadTo(w/2, i * 1.25, w1 - i, h0 + i + 2);
00475             path.lineTo(w1 - i, h1 - i - 2);
00476             path.quadTo(w/2, h - i * 1.25, w0 + i, h1 - i - 2);
00477             path.closeSubpath();
00478         } else {
00479             path.moveTo(w0 + i + 2, h0 + i);
00480             path.quadTo(i * 1.25, h/2, w0 + i + 2, h1 - i);
00481             path.lineTo(w1 - i - 2, h1 - i);
00482             path.quadTo(w - i * 1.25, h/2, w1 - i - 2, h0 + i);
00483             path.closeSubpath();
00484         }
00485 
00486         paint.drawPath(path);
00487     }
00488 
00489     paint.setClipRect(subclip);
00490 
00491     float radians = m_rotation * 1.5f * M_PI;
00492 
00493 //    std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl;
00494 
00495     w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2;
00496 
00497     // total number of notches on the entire wheel
00498     int notches = 25;
00499     
00500     // radius of the wheel including invisible part
00501     int radius = int(w / 2 + 2);
00502 
00503     for (int i = 0; i < notches; ++i) {
00504 
00505         float a0 = (2.f * M_PI * i) / notches + radians;
00506         float a1 = a0 + M_PI / (notches * 2);
00507         float a2 = (2.f * M_PI * (i + 1)) / notches + radians;
00508 
00509         float depth = cosf((a0 + a2) / 2);
00510         if (depth < 0) continue;
00511 
00512         float x0 = radius * sinf(a0) + w/2;
00513         float x1 = radius * sinf(a1) + w/2;
00514         float x2 = radius * sinf(a2) + w/2;
00515         if (x2 < 0 || x0 > w) continue;
00516 
00517         if (x0 < 0) x0 = 0;
00518         if (x2 > w) x2 = w;
00519 
00520         x0 += bw;
00521         x1 += bw;
00522         x2 += bw;
00523 
00524         int grey = lrintf(255 * depth);
00525         QColor fc = QColor(grey, grey, grey);
00526         QColor oc = palette().dark().color();
00527 
00528         paint.setPen(oc);
00529         paint.setBrush(fc);
00530 
00531         if (m_orientation == Qt::Horizontal) {
00532             paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2));
00533         } else {
00534             paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1));
00535         }
00536 
00537         if (m_showScale) {
00538 
00539             paint.setBrush(oc);
00540 
00541             float prop;
00542             if (i >= notches / 4) {
00543                 prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f))
00544                     / notches;
00545             } else {
00546                 prop = 0.f;
00547             }
00548             
00549             if (m_orientation == Qt::Horizontal) {
00550                 paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw,
00551                                       x2 - x1, height() * prop));
00552             } else {
00553                 paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1));
00554             }
00555         }
00556 
00557         paint.setPen(oc);
00558         paint.setBrush(palette().background().color());
00559 
00560         if (m_orientation == Qt::Horizontal) {
00561             paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2));
00562         } else {
00563             paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0));
00564         }
00565     }
00566 }
00567 
00568 QSize
00569 Thumbwheel::sizeHint() const
00570 {
00571     if (m_orientation == Qt::Horizontal) {
00572         return QSize(80, 12);
00573     } else {
00574         return QSize(12, 80);
00575     }
00576 }
00577 

Generated on Wed Feb 20 15:45:29 2008 for SonicVisualiser by  doxygen 1.5.1