Chris@132: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@132: Chris@132: /* Chris@132: Sonic Visualiser Chris@132: An audio file viewer and annotation editor. Chris@132: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 QMUL. Chris@132: Chris@132: This program is free software; you can redistribute it and/or Chris@132: modify it under the terms of the GNU General Public License as Chris@132: published by the Free Software Foundation; either version 2 of the Chris@132: License, or (at your option) any later version. See the file Chris@132: COPYING included with this distribution for more information. Chris@132: */ Chris@132: Chris@132: #include "Thumbwheel.h" Chris@132: Chris@132: #include Chris@132: #include Chris@132: #include Chris@132: #include Chris@132: Chris@132: #include Chris@132: #include Chris@132: Chris@133: Thumbwheel::Thumbwheel(Qt::Orientation orientation, Chris@132: QWidget *parent) : Chris@132: QWidget(parent), Chris@133: m_min(0), Chris@133: m_max(100), Chris@133: m_default(50), Chris@133: m_value(50), Chris@165: m_rotation(0.5), Chris@132: m_orientation(orientation), Chris@165: m_speed(1.0), Chris@132: m_tracking(true), Chris@132: m_showScale(true), Chris@132: m_clicked(false), Chris@133: m_atDefault(true), Chris@165: m_clickRotation(m_rotation) Chris@132: { Chris@132: } Chris@132: Chris@132: Thumbwheel::~Thumbwheel() Chris@132: { Chris@132: } Chris@132: Chris@132: void Chris@133: Thumbwheel::setMinimumValue(int min) Chris@133: { Chris@133: if (m_min == min) return; Chris@133: Chris@133: m_min = min; Chris@133: if (m_max <= m_min) m_max = m_min + 1; Chris@133: if (m_value < m_min) m_value = m_min; Chris@133: if (m_value > m_max) m_value = m_max; Chris@165: Chris@165: m_rotation = float(m_value - m_min) / float(m_max - m_min); Chris@165: update(); Chris@133: } Chris@133: Chris@133: int Chris@133: Thumbwheel::getMinimumValue() const Chris@133: { Chris@133: return m_min; Chris@133: } Chris@133: Chris@133: void Chris@133: Thumbwheel::setMaximumValue(int max) Chris@133: { Chris@133: if (m_max == max) return; Chris@133: Chris@133: m_max = max; Chris@133: if (m_min >= m_max) m_min = m_max - 1; Chris@133: if (m_value < m_min) m_value = m_min; Chris@133: if (m_value > m_max) m_value = m_max; Chris@165: Chris@165: m_rotation = float(m_value - m_min) / float(m_max - m_min); Chris@165: update(); Chris@133: } Chris@133: Chris@133: int Chris@133: Thumbwheel::getMaximumValue() const Chris@133: { Chris@133: return m_max; Chris@133: } Chris@133: Chris@133: void Chris@133: Thumbwheel::setDefaultValue(int deft) Chris@133: { Chris@133: if (m_default == deft) return; Chris@133: Chris@133: m_default = deft; Chris@133: if (m_atDefault) { Chris@133: setValue(m_default); Chris@165: m_atDefault = true; // setValue unsets this Chris@133: emit valueChanged(getValue()); Chris@133: } Chris@133: } Chris@133: Chris@133: int Chris@133: Thumbwheel::getDefaultValue() const Chris@133: { Chris@133: return m_default; Chris@133: } Chris@133: Chris@133: void Chris@132: Thumbwheel::setValue(int value) Chris@132: { Chris@165: // std::cerr << "Thumbwheel::setValue(" << value << ") (from " << m_value Chris@165: // << ", rotation " << m_rotation << ")" << std::endl; Chris@133: Chris@165: if (m_value != value) { Chris@165: Chris@165: m_atDefault = false; Chris@165: Chris@165: if (value < m_min) value = m_min; Chris@165: if (value > m_max) value = m_max; Chris@165: m_value = value; Chris@165: } Chris@165: Chris@165: m_rotation = float(m_value - m_min) / float(m_max - m_min); Chris@132: update(); Chris@132: } Chris@132: Chris@133: void Chris@133: Thumbwheel::resetToDefault() Chris@133: { Chris@133: if (m_default == m_value) return; Chris@133: setValue(m_default); Chris@133: m_atDefault = true; Chris@133: emit valueChanged(getValue()); Chris@133: } Chris@133: Chris@132: int Chris@132: Thumbwheel::getValue() const Chris@132: { Chris@132: return m_value; Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::setSpeed(float speed) Chris@132: { Chris@132: m_speed = speed; Chris@132: } Chris@132: Chris@132: float Chris@132: Thumbwheel::getSpeed() const Chris@132: { Chris@132: return m_speed; Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::setTracking(bool tracking) Chris@132: { Chris@132: m_tracking = tracking; Chris@132: } Chris@132: Chris@132: bool Chris@132: Thumbwheel::getTracking() const Chris@132: { Chris@132: return m_tracking; Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::setShowScale(bool showScale) Chris@132: { Chris@132: m_showScale = showScale; Chris@132: } Chris@132: Chris@132: bool Chris@132: Thumbwheel::getShowScale() const Chris@132: { Chris@132: return m_showScale; Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::mousePressEvent(QMouseEvent *e) Chris@132: { Chris@133: if (e->button() == Qt::LeftButton) { Chris@133: m_clicked = true; Chris@133: m_clickPos = e->pos(); Chris@165: m_clickRotation = m_rotation; Chris@133: } else if (e->button() == Qt::MidButton) { Chris@133: resetToDefault(); Chris@133: } Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::mouseDoubleClickEvent(QMouseEvent *) Chris@132: { Chris@133: resetToDefault(); Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::mouseMoveEvent(QMouseEvent *e) Chris@132: { Chris@133: if (!m_clicked) return; Chris@132: int dist = 0; Chris@132: if (m_orientation == Qt::Horizontal) { Chris@132: dist = e->x() - m_clickPos.x(); Chris@132: } else { Chris@132: dist = e->y() - m_clickPos.y(); Chris@132: } Chris@165: Chris@165: float rotation = m_clickRotation + (m_speed * dist) / 100; Chris@165: if (rotation < 0.f) rotation = 0.f; Chris@165: if (rotation > 1.f) rotation = 1.f; Chris@165: int value = lrintf(m_min + (m_max - m_min) * m_rotation); Chris@132: if (value != m_value) { Chris@132: setValue(value); Chris@132: if (m_tracking) emit valueChanged(getValue()); Chris@165: m_rotation = rotation; Chris@165: } else if (fabsf(rotation - m_rotation) > 0.001) { Chris@165: m_rotation = rotation; Chris@165: repaint(); Chris@165: } Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::mouseReleaseEvent(QMouseEvent *e) Chris@132: { Chris@133: if (!m_clicked) return; Chris@132: bool reallyTracking = m_tracking; Chris@132: m_tracking = true; Chris@132: mouseMoveEvent(e); Chris@132: m_tracking = reallyTracking; Chris@133: m_clicked = false; Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::wheelEvent(QWheelEvent *e) Chris@132: { Chris@132: int step = lrintf(m_speed); Chris@132: if (step == 0) step = 1; Chris@132: Chris@132: if (e->delta() > 0) { Chris@132: setValue(m_value + step); Chris@132: } else { Chris@132: setValue(m_value - step); Chris@132: } Chris@132: Chris@132: emit valueChanged(getValue()); Chris@132: } Chris@132: Chris@132: void Chris@132: Thumbwheel::paintEvent(QPaintEvent *) Chris@132: { Chris@133: QPainter paint(this); Chris@133: paint.fillRect(rect(), palette().background().color()); Chris@133: paint.setRenderHint(QPainter::Antialiasing, false); Chris@133: Chris@133: int bw = 3; Chris@133: Chris@133: for (int i = 0; i < bw; ++i) { Chris@133: int grey = (i + 1) * (256 / (bw + 1)); Chris@133: QColor fc = QColor(grey, grey, grey); Chris@133: paint.setPen(fc); Chris@133: paint.drawRect(i, i, width() - i*2 - 1, height() - i*2 - 1); Chris@133: } Chris@133: Chris@133: paint.setClipRect(QRect(bw, bw, width() - bw*2, height() - bw*2)); Chris@133: Chris@165: float radians = m_rotation * 1.5f * M_PI; Chris@132: Chris@132: // std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl; Chris@132: Chris@133: int w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2; Chris@132: Chris@132: // total number of notches on the entire wheel Chris@132: int notches = 25; Chris@132: Chris@132: // radius of the wheel including invisible part Chris@132: int radius = w / 2 + 2; Chris@132: Chris@132: paint.setRenderHint(QPainter::Antialiasing, true); Chris@132: Chris@132: for (int i = 0; i < notches; ++i) { Chris@132: Chris@165: float a0 = (2.f * M_PI * i) / notches + radians; Chris@132: float a1 = a0 + M_PI / (notches * 2); Chris@165: float a2 = (2.f * M_PI * (i + 1)) / notches + radians; Chris@132: Chris@132: float depth = cosf((a0 + a2) / 2); Chris@132: if (depth < 0) continue; Chris@132: Chris@132: float x0 = radius * sinf(a0) + w/2; Chris@132: float x1 = radius * sinf(a1) + w/2; Chris@132: float x2 = radius * sinf(a2) + w/2; Chris@132: if (x2 < 0 || x0 > w) continue; Chris@132: Chris@132: if (x0 < 0) x0 = 0; Chris@132: if (x2 > w) x2 = w; Chris@132: Chris@133: x0 += bw; Chris@133: x1 += bw; Chris@133: x2 += bw; Chris@133: Chris@132: int grey = lrintf(255 * depth); Chris@132: QColor fc = QColor(grey, grey, grey); Chris@132: QColor oc = palette().dark().color(); Chris@132: Chris@132: paint.setPen(oc); Chris@132: paint.setBrush(fc); Chris@132: Chris@132: if (m_orientation == Qt::Horizontal) { Chris@133: paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2)); Chris@132: } else { Chris@133: paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1)); Chris@132: } Chris@132: Chris@132: if (m_showScale) { Chris@132: Chris@132: paint.setBrush(oc); Chris@132: Chris@132: float prop; Chris@132: if (i >= notches / 4) { Chris@132: prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f)) Chris@132: / notches; Chris@132: } else { Chris@132: prop = 0.f; Chris@132: } Chris@132: Chris@132: if (m_orientation == Qt::Horizontal) { Chris@133: paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw, Chris@132: x2 - x1, height() * prop)); Chris@132: } else { Chris@133: paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1)); Chris@132: } Chris@132: } Chris@132: Chris@132: paint.setPen(oc); Chris@132: paint.setBrush(palette().background().color()); Chris@132: Chris@132: if (m_orientation == Qt::Horizontal) { Chris@133: paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2)); Chris@132: } else { Chris@133: paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0)); Chris@132: } Chris@132: } Chris@132: } Chris@132: Chris@132: QSize Chris@132: Thumbwheel::sizeHint() const Chris@132: { Chris@132: if (m_orientation == Qt::Horizontal) { Chris@132: return QSize(80, 12); Chris@132: } else { Chris@132: return QSize(12, 80); Chris@132: } Chris@132: } Chris@132: