annotate widgets/Thumbwheel.cpp @ 178:05015e717a0d

* Somewhat better handling of running out of memory or disc space
author Chris Cannam
date Mon, 13 Nov 2006 14:48:57 +0000
parents 793df5f0c6cb
children 42118892f428
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@132 7 This file copyright 2006 Chris Cannam.
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