Mercurial > hg > easaier-soundaccess
diff widgets/Thumbwheel.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/Thumbwheel.cpp Fri May 11 09:08:14 2007 +0000 @@ -0,0 +1,562 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "Thumbwheel.h" + +#include "base/RangeMapper.h" +#include "base/Profiler.h" + +#include <QMouseEvent> +#include <QPaintEvent> +#include <QWheelEvent> +#include <QInputDialog> +#include <QPainter> +#include <QPainterPath> + +#include <cmath> +#include <iostream> + +Thumbwheel::Thumbwheel(Qt::Orientation orientation, + QWidget *parent) : + QWidget(parent), + m_min(0), + m_max(100), + m_default(50), + m_value(50), + m_mappedValue(50), + m_noMappedUpdate(false), + m_rotation(0.5), + m_orientation(orientation), + m_speed(1.0), + m_tracking(true), + m_showScale(true), + m_clicked(false), + m_atDefault(true), + m_clickRotation(m_rotation), + m_showTooltip(true), + m_rangeMapper(0) +{ +} + +Thumbwheel::~Thumbwheel() +{ + delete m_rangeMapper; +} + +void +Thumbwheel::setRangeMapper(RangeMapper *mapper) +{ + if (m_rangeMapper == mapper) return; + + if (!m_rangeMapper && mapper) { + connect(this, SIGNAL(valueChanged(int)), + this, SLOT(updateMappedValue(int))); + } + + delete m_rangeMapper; + m_rangeMapper = mapper; + + updateMappedValue(getValue()); +} + +void +Thumbwheel::setShowToolTip(bool show) +{ + m_showTooltip = show; + m_noMappedUpdate = true; + updateMappedValue(getValue()); + m_noMappedUpdate = false; +} + +void +Thumbwheel::setMinimumValue(int min) +{ + if (m_min == min) return; + + m_min = min; + if (m_max <= m_min) m_max = m_min + 1; + if (m_value < m_min) m_value = m_min; + if (m_value > m_max) m_value = m_max; + + m_rotation = float(m_value - m_min) / float(m_max - m_min); + update(); +} + +int +Thumbwheel::getMinimumValue() const +{ + return m_min; +} + +void +Thumbwheel::setMaximumValue(int max) +{ + if (m_max == max) return; + + m_max = max; + if (m_min >= m_max) m_min = m_max - 1; + if (m_value < m_min) m_value = m_min; + if (m_value > m_max) m_value = m_max; + + m_rotation = float(m_value - m_min) / float(m_max - m_min); + update(); +} + +int +Thumbwheel::getMaximumValue() const +{ + return m_max; +} + +void +Thumbwheel::setDefaultValue(int deft) +{ + if (m_default == deft) return; + + m_default = deft; + if (m_atDefault) { + setValue(m_default); + m_atDefault = true; // setValue unsets this + emit valueChanged(getValue()); + } +} + +void +Thumbwheel::setMappedValue(float mappedValue) +{ + if (m_rangeMapper) { + int newValue = m_rangeMapper->getPositionForValue(mappedValue); + bool changed = (m_mappedValue != mappedValue); + m_mappedValue = mappedValue; + m_noMappedUpdate = true; +// std::cerr << "Thumbwheel::setMappedValue(" << mappedValue << "): new value is " << newValue << " (visible " << isVisible() << ")" << std::endl; + if (newValue != getValue()) { + setValue(newValue); + changed = true; + } + if (changed) emit valueChanged(newValue); + m_noMappedUpdate = false; + } else { + int v = int(mappedValue); + if (v != getValue()) { + setValue(v); + emit valueChanged(v); + } + } +} + +int +Thumbwheel::getDefaultValue() const +{ + return m_default; +} + +void +Thumbwheel::setValue(int value) +{ +// std::cerr << "Thumbwheel::setValue(" << value << ") (from " << m_value +// << ", rotation " << m_rotation << ")" << " (visible " << isVisible() << ")" << std::endl; + + if (m_value != value) { + + m_atDefault = false; + + if (value < m_min) value = m_min; + if (value > m_max) value = m_max; + m_value = value; + } + + m_rotation = float(m_value - m_min) / float(m_max - m_min); + if (isVisible()) update(); +} + +void +Thumbwheel::resetToDefault() +{ + if (m_default == m_value) return; + setValue(m_default); + m_atDefault = true; + emit valueChanged(getValue()); +} + +int +Thumbwheel::getValue() const +{ + return m_value; +} + +float +Thumbwheel::getMappedValue() const +{ + if (m_rangeMapper) { +// std::cerr << "Thumbwheel::getMappedValue(): value = " << getValue() << ", mappedValue = " << m_mappedValue << std::endl; + return m_mappedValue; + } + return getValue(); +} + +void +Thumbwheel::updateMappedValue(int value) +{ + if (!m_noMappedUpdate) { + if (m_rangeMapper) { + m_mappedValue = m_rangeMapper->getValueForPosition(value); + } else { + m_mappedValue = value; + } + } + + if (m_showTooltip) { + QString name = objectName(); + QString unit = ""; + QString text; + if (m_rangeMapper) unit = m_rangeMapper->getUnit(); + if (name != "") { + text = tr("%1: %2%3").arg(name).arg(m_mappedValue).arg(unit); + } else { + text = tr("%2%3").arg(m_mappedValue).arg(unit); + } + setToolTip(text); + } +} + +void +Thumbwheel::setSpeed(float speed) +{ + m_speed = speed; +} + +float +Thumbwheel::getSpeed() const +{ + return m_speed; +} + +void +Thumbwheel::setTracking(bool tracking) +{ + m_tracking = tracking; +} + +bool +Thumbwheel::getTracking() const +{ + return m_tracking; +} + +void +Thumbwheel::setShowScale(bool showScale) +{ + m_showScale = showScale; +} + +bool +Thumbwheel::getShowScale() const +{ + return m_showScale; +} + +void +Thumbwheel::enterEvent(QEvent *) +{ + emit mouseEntered(); +} + +void +Thumbwheel::leaveEvent(QEvent *) +{ + emit mouseLeft(); +} + +void +Thumbwheel::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == Qt::MidButton || + ((e->button() == Qt::LeftButton) && + (e->modifiers() & Qt::ControlModifier))) { + resetToDefault(); + } else if (e->button() == Qt::LeftButton) { + m_clicked = true; + m_clickPos = e->pos(); + m_clickRotation = m_rotation; + } +} + +void +Thumbwheel::mouseDoubleClickEvent(QMouseEvent *mouseEvent) +{ + //!!! needs a common base class with AudioDial (and Panner?) + + if (mouseEvent->button() != Qt::LeftButton) { + return; + } + + bool ok = false; + + if (m_rangeMapper) { + + float min = m_rangeMapper->getValueForPosition(m_min); + float max = m_rangeMapper->getValueForPosition(m_max); + + if (min > max) { + float tmp = min; + min = max; + max = tmp; + } + + QString unit = m_rangeMapper->getUnit(); + + QString text; + if (objectName() != "") { + if (unit != "") { + text = tr("New value for %1, from %2 to %3 %4:") + .arg(objectName()).arg(min).arg(max).arg(unit); + } else { + text = tr("New value for %1, from %2 to %3:") + .arg(objectName()).arg(min).arg(max); + } + } else { + if (unit != "") { + text = tr("Enter a new value from %1 to %2 %3:") + .arg(min).arg(max).arg(unit); + } else { + text = tr("Enter a new value from %1 to %2:") + .arg(min).arg(max); + } + } + + float newValue = QInputDialog::getDouble + (this, + tr("Enter new value"), + text, + m_mappedValue, + min, + max, + 4, + &ok); + + if (ok) { + setMappedValue(newValue); + } + + } else { + + int newValue = QInputDialog::getInteger + (this, + tr("Enter new value"), + tr("Enter a new value from %1 to %2:") + .arg(m_min).arg(m_max), + getValue(), m_min, m_max, 1, &ok); + + if (ok) { + setValue(newValue); + } + } +} + + +void +Thumbwheel::mouseMoveEvent(QMouseEvent *e) +{ + if (!m_clicked) return; + int dist = 0; + if (m_orientation == Qt::Horizontal) { + dist = e->x() - m_clickPos.x(); + } else { + dist = e->y() - m_clickPos.y(); + } + + float rotation = m_clickRotation + (m_speed * dist) / 100; + if (rotation < 0.f) rotation = 0.f; + if (rotation > 1.f) rotation = 1.f; + int value = lrintf(m_min + (m_max - m_min) * m_rotation); + if (value != m_value) { + setValue(value); + if (m_tracking) emit valueChanged(getValue()); + m_rotation = rotation; + } else if (fabsf(rotation - m_rotation) > 0.001) { + m_rotation = rotation; + repaint(); + } +} + +void +Thumbwheel::mouseReleaseEvent(QMouseEvent *e) +{ + if (!m_clicked) return; + bool reallyTracking = m_tracking; + m_tracking = true; + mouseMoveEvent(e); + m_tracking = reallyTracking; + m_clicked = false; +} + +void +Thumbwheel::wheelEvent(QWheelEvent *e) +{ + int step = lrintf(m_speed); + if (step == 0) step = 1; + + if (e->delta() > 0) { + setValue(m_value + step); + } else { + setValue(m_value - step); + } + + emit valueChanged(getValue()); +} + +void +Thumbwheel::paintEvent(QPaintEvent *) +{ + Profiler profiler("Thumbwheel::paintEvent", true); + + int bw = 3; + + QRect subclip; + if (m_orientation == Qt::Horizontal) { + subclip = QRect(bw, bw+1, width() - bw*2, height() - bw*2 - 2); + } else { + subclip = QRect(bw+1, bw, width() - bw*2 - 2, height() - bw*2); + } + + QPainter paint(this); + paint.fillRect(subclip, palette().background().color()); + + paint.setRenderHint(QPainter::Antialiasing, true); + + float w = width(); + float w0 = 0.5; + float w1 = w - 0.5; + + float h = height(); + float h0 = 0.5; + float h1 = h - 0.5; + + for (int i = bw-1; i >= 0; --i) { +// for (int i = 0; i < 1; ++i) { + + int grey = (i + 1) * (256 / (bw + 1)); + QColor fc = QColor(grey, grey, grey); + paint.setPen(fc); + + QPainterPath path; + + if (m_orientation == Qt::Horizontal) { + path.moveTo(w0 + i, h0 + i + 2); + path.quadTo(w/2, i * 1.25, w1 - i, h0 + i + 2); + path.lineTo(w1 - i, h1 - i - 2); + path.quadTo(w/2, h - i * 1.25, w0 + i, h1 - i - 2); + path.closeSubpath(); + } else { + path.moveTo(w0 + i + 2, h0 + i); + path.quadTo(i * 1.25, h/2, w0 + i + 2, h1 - i); + path.lineTo(w1 - i - 2, h1 - i); + path.quadTo(w - i * 1.25, h/2, w1 - i - 2, h0 + i); + path.closeSubpath(); + } + + paint.drawPath(path); + } + + paint.setClipRect(subclip); + + float radians = m_rotation * 1.5f * M_PI; + +// std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl; + + w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2; + + // total number of notches on the entire wheel + int notches = 25; + + // radius of the wheel including invisible part + int radius = int(w / 2 + 2); + + for (int i = 0; i < notches; ++i) { + + float a0 = (2.f * M_PI * i) / notches + radians; + float a1 = a0 + M_PI / (notches * 2); + float a2 = (2.f * M_PI * (i + 1)) / notches + radians; + + float depth = cosf((a0 + a2) / 2); + if (depth < 0) continue; + + float x0 = radius * sinf(a0) + w/2; + float x1 = radius * sinf(a1) + w/2; + float x2 = radius * sinf(a2) + w/2; + if (x2 < 0 || x0 > w) continue; + + if (x0 < 0) x0 = 0; + if (x2 > w) x2 = w; + + x0 += bw; + x1 += bw; + x2 += bw; + + int grey = lrintf(255 * depth); + QColor fc = QColor(grey, grey, grey); + QColor oc = palette().dark().color(); + + paint.setPen(oc); + paint.setBrush(fc); + + if (m_orientation == Qt::Horizontal) { + paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2)); + } else { + paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1)); + } + + if (m_showScale) { + + paint.setBrush(oc); + + float prop; + if (i >= notches / 4) { + prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f)) + / notches; + } else { + prop = 0.f; + } + + if (m_orientation == Qt::Horizontal) { + paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw, + x2 - x1, height() * prop)); + } else { + paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1)); + } + } + + paint.setPen(oc); + paint.setBrush(palette().background().color()); + + if (m_orientation == Qt::Horizontal) { + paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2)); + } else { + paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0)); + } + } +} + +QSize +Thumbwheel::sizeHint() const +{ + if (m_orientation == Qt::Horizontal) { + return QSize(80, 12); + } else { + return QSize(12, 80); + } +} +