annotate widgets/Thumbwheel.cpp @ 183:5f86ae638b04

* Omit translucent blue fill for selection rectangles that are superimposed over layers that use colours for meaningful purposes such as the spectrogram (CHARM change request)
author Chris Cannam
date Fri, 24 Nov 2006 16:56:15 +0000
parents 42118892f428
children e7cf6044c2a0
rev   line source
Chris@132 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@132 2
Chris@132 3 /*
Chris@132 4 Sonic Visualiser
Chris@132 5 An audio file viewer and annotation editor.
Chris@132 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 QMUL.
Chris@132 8
Chris@132 9 This program is free software; you can redistribute it and/or
Chris@132 10 modify it under the terms of the GNU General Public License as
Chris@132 11 published by the Free Software Foundation; either version 2 of the
Chris@132 12 License, or (at your option) any later version. See the file
Chris@132 13 COPYING included with this distribution for more information.
Chris@132 14 */
Chris@132 15
Chris@132 16 #include "Thumbwheel.h"
Chris@132 17
Chris@132 18 #include <QMouseEvent>
Chris@132 19 #include <QPaintEvent>
Chris@132 20 #include <QWheelEvent>
Chris@132 21 #include <QPainter>
Chris@132 22
Chris@132 23 #include <cmath>
Chris@132 24 #include <iostream>
Chris@132 25
Chris@133 26 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
Chris@132 27 QWidget *parent) :
Chris@132 28 QWidget(parent),
Chris@133 29 m_min(0),
Chris@133 30 m_max(100),
Chris@133 31 m_default(50),
Chris@133 32 m_value(50),
Chris@165 33 m_rotation(0.5),
Chris@132 34 m_orientation(orientation),
Chris@165 35 m_speed(1.0),
Chris@132 36 m_tracking(true),
Chris@132 37 m_showScale(true),
Chris@132 38 m_clicked(false),
Chris@133 39 m_atDefault(true),
Chris@165 40 m_clickRotation(m_rotation)
Chris@132 41 {
Chris@132 42 }
Chris@132 43
Chris@132 44 Thumbwheel::~Thumbwheel()
Chris@132 45 {
Chris@132 46 }
Chris@132 47
Chris@132 48 void
Chris@133 49 Thumbwheel::setMinimumValue(int min)
Chris@133 50 {
Chris@133 51 if (m_min == min) return;
Chris@133 52
Chris@133 53 m_min = min;
Chris@133 54 if (m_max <= m_min) m_max = m_min + 1;
Chris@133 55 if (m_value < m_min) m_value = m_min;
Chris@133 56 if (m_value > m_max) m_value = m_max;
Chris@165 57
Chris@165 58 m_rotation = float(m_value - m_min) / float(m_max - m_min);
Chris@165 59 update();
Chris@133 60 }
Chris@133 61
Chris@133 62 int
Chris@133 63 Thumbwheel::getMinimumValue() const
Chris@133 64 {
Chris@133 65 return m_min;
Chris@133 66 }
Chris@133 67
Chris@133 68 void
Chris@133 69 Thumbwheel::setMaximumValue(int max)
Chris@133 70 {
Chris@133 71 if (m_max == max) return;
Chris@133 72
Chris@133 73 m_max = max;
Chris@133 74 if (m_min >= m_max) m_min = m_max - 1;
Chris@133 75 if (m_value < m_min) m_value = m_min;
Chris@133 76 if (m_value > m_max) m_value = m_max;
Chris@165 77
Chris@165 78 m_rotation = float(m_value - m_min) / float(m_max - m_min);
Chris@165 79 update();
Chris@133 80 }
Chris@133 81
Chris@133 82 int
Chris@133 83 Thumbwheel::getMaximumValue() const
Chris@133 84 {
Chris@133 85 return m_max;
Chris@133 86 }
Chris@133 87
Chris@133 88 void
Chris@133 89 Thumbwheel::setDefaultValue(int deft)
Chris@133 90 {
Chris@133 91 if (m_default == deft) return;
Chris@133 92
Chris@133 93 m_default = deft;
Chris@133 94 if (m_atDefault) {
Chris@133 95 setValue(m_default);
Chris@165 96 m_atDefault = true; // setValue unsets this
Chris@133 97 emit valueChanged(getValue());
Chris@133 98 }
Chris@133 99 }
Chris@133 100
Chris@133 101 int
Chris@133 102 Thumbwheel::getDefaultValue() const
Chris@133 103 {
Chris@133 104 return m_default;
Chris@133 105 }
Chris@133 106
Chris@133 107 void
Chris@132 108 Thumbwheel::setValue(int value)
Chris@132 109 {
Chris@165 110 // std::cerr << "Thumbwheel::setValue(" << value << ") (from " << m_value
Chris@165 111 // << ", rotation " << m_rotation << ")" << std::endl;
Chris@133 112
Chris@165 113 if (m_value != value) {
Chris@165 114
Chris@165 115 m_atDefault = false;
Chris@165 116
Chris@165 117 if (value < m_min) value = m_min;
Chris@165 118 if (value > m_max) value = m_max;
Chris@165 119 m_value = value;
Chris@165 120 }
Chris@165 121
Chris@165 122 m_rotation = float(m_value - m_min) / float(m_max - m_min);
Chris@132 123 update();
Chris@132 124 }
Chris@132 125
Chris@133 126 void
Chris@133 127 Thumbwheel::resetToDefault()
Chris@133 128 {
Chris@133 129 if (m_default == m_value) return;
Chris@133 130 setValue(m_default);
Chris@133 131 m_atDefault = true;
Chris@133 132 emit valueChanged(getValue());
Chris@133 133 }
Chris@133 134
Chris@132 135 int
Chris@132 136 Thumbwheel::getValue() const
Chris@132 137 {
Chris@132 138 return m_value;
Chris@132 139 }
Chris@132 140
Chris@132 141 void
Chris@132 142 Thumbwheel::setSpeed(float speed)
Chris@132 143 {
Chris@132 144 m_speed = speed;
Chris@132 145 }
Chris@132 146
Chris@132 147 float
Chris@132 148 Thumbwheel::getSpeed() const
Chris@132 149 {
Chris@132 150 return m_speed;
Chris@132 151 }
Chris@132 152
Chris@132 153 void
Chris@132 154 Thumbwheel::setTracking(bool tracking)
Chris@132 155 {
Chris@132 156 m_tracking = tracking;
Chris@132 157 }
Chris@132 158
Chris@132 159 bool
Chris@132 160 Thumbwheel::getTracking() const
Chris@132 161 {
Chris@132 162 return m_tracking;
Chris@132 163 }
Chris@132 164
Chris@132 165 void
Chris@132 166 Thumbwheel::setShowScale(bool showScale)
Chris@132 167 {
Chris@132 168 m_showScale = showScale;
Chris@132 169 }
Chris@132 170
Chris@132 171 bool
Chris@132 172 Thumbwheel::getShowScale() const
Chris@132 173 {
Chris@132 174 return m_showScale;
Chris@132 175 }
Chris@132 176
Chris@132 177 void
Chris@132 178 Thumbwheel::mousePressEvent(QMouseEvent *e)
Chris@132 179 {
Chris@133 180 if (e->button() == Qt::LeftButton) {
Chris@133 181 m_clicked = true;
Chris@133 182 m_clickPos = e->pos();
Chris@165 183 m_clickRotation = m_rotation;
Chris@133 184 } else if (e->button() == Qt::MidButton) {
Chris@133 185 resetToDefault();
Chris@133 186 }
Chris@132 187 }
Chris@132 188
Chris@132 189 void
Chris@132 190 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *)
Chris@132 191 {
Chris@133 192 resetToDefault();
Chris@132 193 }
Chris@132 194
Chris@132 195 void
Chris@132 196 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
Chris@132 197 {
Chris@133 198 if (!m_clicked) return;
Chris@132 199 int dist = 0;
Chris@132 200 if (m_orientation == Qt::Horizontal) {
Chris@132 201 dist = e->x() - m_clickPos.x();
Chris@132 202 } else {
Chris@132 203 dist = e->y() - m_clickPos.y();
Chris@132 204 }
Chris@165 205
Chris@165 206 float rotation = m_clickRotation + (m_speed * dist) / 100;
Chris@165 207 if (rotation < 0.f) rotation = 0.f;
Chris@165 208 if (rotation > 1.f) rotation = 1.f;
Chris@165 209 int value = lrintf(m_min + (m_max - m_min) * m_rotation);
Chris@132 210 if (value != m_value) {
Chris@132 211 setValue(value);
Chris@132 212 if (m_tracking) emit valueChanged(getValue());
Chris@165 213 m_rotation = rotation;
Chris@165 214 } else if (fabsf(rotation - m_rotation) > 0.001) {
Chris@165 215 m_rotation = rotation;
Chris@165 216 repaint();
Chris@165 217 }
Chris@132 218 }
Chris@132 219
Chris@132 220 void
Chris@132 221 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
Chris@132 222 {
Chris@133 223 if (!m_clicked) return;
Chris@132 224 bool reallyTracking = m_tracking;
Chris@132 225 m_tracking = true;
Chris@132 226 mouseMoveEvent(e);
Chris@132 227 m_tracking = reallyTracking;
Chris@133 228 m_clicked = false;
Chris@132 229 }
Chris@132 230
Chris@132 231 void
Chris@132 232 Thumbwheel::wheelEvent(QWheelEvent *e)
Chris@132 233 {
Chris@132 234 int step = lrintf(m_speed);
Chris@132 235 if (step == 0) step = 1;
Chris@132 236
Chris@132 237 if (e->delta() > 0) {
Chris@132 238 setValue(m_value + step);
Chris@132 239 } else {
Chris@132 240 setValue(m_value - step);
Chris@132 241 }
Chris@132 242
Chris@132 243 emit valueChanged(getValue());
Chris@132 244 }
Chris@132 245
Chris@132 246 void
Chris@132 247 Thumbwheel::paintEvent(QPaintEvent *)
Chris@132 248 {
Chris@133 249 QPainter paint(this);
Chris@133 250 paint.fillRect(rect(), palette().background().color());
Chris@133 251 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@133 252
Chris@133 253 int bw = 3;
Chris@133 254
Chris@133 255 for (int i = 0; i < bw; ++i) {
Chris@133 256 int grey = (i + 1) * (256 / (bw + 1));
Chris@133 257 QColor fc = QColor(grey, grey, grey);
Chris@133 258 paint.setPen(fc);
Chris@133 259 paint.drawRect(i, i, width() - i*2 - 1, height() - i*2 - 1);
Chris@133 260 }
Chris@133 261
Chris@133 262 paint.setClipRect(QRect(bw, bw, width() - bw*2, height() - bw*2));
Chris@133 263
Chris@165 264 float radians = m_rotation * 1.5f * M_PI;
Chris@132 265
Chris@132 266 // std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl;
Chris@132 267
Chris@133 268 int w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2;
Chris@132 269
Chris@132 270 // total number of notches on the entire wheel
Chris@132 271 int notches = 25;
Chris@132 272
Chris@132 273 // radius of the wheel including invisible part
Chris@132 274 int radius = w / 2 + 2;
Chris@132 275
Chris@132 276 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@132 277
Chris@132 278 for (int i = 0; i < notches; ++i) {
Chris@132 279
Chris@165 280 float a0 = (2.f * M_PI * i) / notches + radians;
Chris@132 281 float a1 = a0 + M_PI / (notches * 2);
Chris@165 282 float a2 = (2.f * M_PI * (i + 1)) / notches + radians;
Chris@132 283
Chris@132 284 float depth = cosf((a0 + a2) / 2);
Chris@132 285 if (depth < 0) continue;
Chris@132 286
Chris@132 287 float x0 = radius * sinf(a0) + w/2;
Chris@132 288 float x1 = radius * sinf(a1) + w/2;
Chris@132 289 float x2 = radius * sinf(a2) + w/2;
Chris@132 290 if (x2 < 0 || x0 > w) continue;
Chris@132 291
Chris@132 292 if (x0 < 0) x0 = 0;
Chris@132 293 if (x2 > w) x2 = w;
Chris@132 294
Chris@133 295 x0 += bw;
Chris@133 296 x1 += bw;
Chris@133 297 x2 += bw;
Chris@133 298
Chris@132 299 int grey = lrintf(255 * depth);
Chris@132 300 QColor fc = QColor(grey, grey, grey);
Chris@132 301 QColor oc = palette().dark().color();
Chris@132 302
Chris@132 303 paint.setPen(oc);
Chris@132 304 paint.setBrush(fc);
Chris@132 305
Chris@132 306 if (m_orientation == Qt::Horizontal) {
Chris@133 307 paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2));
Chris@132 308 } else {
Chris@133 309 paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1));
Chris@132 310 }
Chris@132 311
Chris@132 312 if (m_showScale) {
Chris@132 313
Chris@132 314 paint.setBrush(oc);
Chris@132 315
Chris@132 316 float prop;
Chris@132 317 if (i >= notches / 4) {
Chris@132 318 prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f))
Chris@132 319 / notches;
Chris@132 320 } else {
Chris@132 321 prop = 0.f;
Chris@132 322 }
Chris@132 323
Chris@132 324 if (m_orientation == Qt::Horizontal) {
Chris@133 325 paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw,
Chris@132 326 x2 - x1, height() * prop));
Chris@132 327 } else {
Chris@133 328 paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1));
Chris@132 329 }
Chris@132 330 }
Chris@132 331
Chris@132 332 paint.setPen(oc);
Chris@132 333 paint.setBrush(palette().background().color());
Chris@132 334
Chris@132 335 if (m_orientation == Qt::Horizontal) {
Chris@133 336 paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2));
Chris@132 337 } else {
Chris@133 338 paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0));
Chris@132 339 }
Chris@132 340 }
Chris@132 341 }
Chris@132 342
Chris@132 343 QSize
Chris@132 344 Thumbwheel::sizeHint() const
Chris@132 345 {
Chris@132 346 if (m_orientation == Qt::Horizontal) {
Chris@132 347 return QSize(80, 12);
Chris@132 348 } else {
Chris@132 349 return QSize(12, 80);
Chris@132 350 }
Chris@132 351 }
Chris@132 352