annotate widgets/Thumbwheel.cpp @ 1614:c6f5c822b10d

Fix potential divide-by-zero (depending on a race elsewhere)
author Chris Cannam
date Tue, 30 Jun 2020 10:56:56 +0100
parents a798a7b5e215
children
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@187 18 #include "base/RangeMapper.h"
Chris@190 19 #include "base/Profiler.h"
Chris@187 20
Chris@132 21 #include <QMouseEvent>
Chris@132 22 #include <QPaintEvent>
Chris@132 23 #include <QWheelEvent>
Chris@187 24 #include <QInputDialog>
Chris@132 25 #include <QPainter>
Chris@190 26 #include <QPainterPath>
Chris@1586 27 #include <QMenu>
Chris@1586 28
Chris@1586 29 #include "MenuTitle.h"
Chris@132 30
Chris@132 31 #include <cmath>
Chris@132 32 #include <iostream>
Chris@132 33
Chris@133 34 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
Chris@1266 35 QWidget *parent) :
Chris@132 36 QWidget(parent),
Chris@133 37 m_min(0),
Chris@133 38 m_max(100),
Chris@133 39 m_default(50),
Chris@133 40 m_value(50),
Chris@187 41 m_mappedValue(50),
Chris@187 42 m_noMappedUpdate(false),
Chris@165 43 m_rotation(0.5),
Chris@132 44 m_orientation(orientation),
Chris@165 45 m_speed(1.0),
Chris@132 46 m_tracking(true),
Chris@132 47 m_showScale(true),
Chris@132 48 m_clicked(false),
Chris@133 49 m_atDefault(true),
Chris@187 50 m_clickRotation(m_rotation),
Chris@187 51 m_showTooltip(true),
Chris@1586 52 m_provideContextMenu(true),
Chris@1586 53 m_lastContextMenu(nullptr),
Chris@1408 54 m_rangeMapper(nullptr)
Chris@132 55 {
Chris@1586 56 setContextMenuPolicy(Qt::CustomContextMenu);
Chris@1586 57 connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
Chris@1586 58 this, SLOT(contextMenuRequested(const QPoint &)));
Chris@132 59 }
Chris@132 60
Chris@132 61 Thumbwheel::~Thumbwheel()
Chris@132 62 {
Chris@187 63 delete m_rangeMapper;
Chris@1586 64 delete m_lastContextMenu;
Chris@1586 65 }
Chris@1586 66
Chris@1586 67 void
Chris@1586 68 Thumbwheel::contextMenuRequested(const QPoint &pos)
Chris@1586 69 {
Chris@1586 70 if (!m_provideContextMenu) {
Chris@1586 71 return;
Chris@1586 72 }
Chris@1586 73
Chris@1589 74 delete m_lastContextMenu;
Chris@1589 75 m_lastContextMenu = new QMenu;
Chris@1589 76 auto m = m_lastContextMenu;
Chris@1586 77
Chris@1586 78 if (m_title == "") {
Chris@1586 79 MenuTitle::addTitle(m, tr("Thumbwheel"));
Chris@1586 80 } else {
Chris@1586 81 MenuTitle::addTitle(m, m_title);
Chris@1586 82 }
Chris@1586 83
Chris@1602 84 m->addAction(tr("&Edit..."), this, SLOT(edit()));
Chris@1602 85 m->addAction(tr("&Reset to Default"), this, SLOT(resetToDefault()));
Chris@1586 86
Chris@1586 87 m->popup(mapToGlobal(pos));
Chris@187 88 }
Chris@187 89
Chris@187 90 void
Chris@187 91 Thumbwheel::setRangeMapper(RangeMapper *mapper)
Chris@187 92 {
Chris@187 93 if (m_rangeMapper == mapper) return;
Chris@187 94
Chris@187 95 if (!m_rangeMapper && mapper) {
Chris@187 96 connect(this, SIGNAL(valueChanged(int)),
Chris@187 97 this, SLOT(updateMappedValue(int)));
Chris@187 98 }
Chris@187 99
Chris@187 100 delete m_rangeMapper;
Chris@187 101 m_rangeMapper = mapper;
Chris@187 102
Chris@187 103 updateMappedValue(getValue());
Chris@187 104 }
Chris@187 105
Chris@187 106 void
Chris@187 107 Thumbwheel::setShowToolTip(bool show)
Chris@187 108 {
Chris@187 109 m_showTooltip = show;
Chris@187 110 m_noMappedUpdate = true;
Chris@187 111 updateMappedValue(getValue());
Chris@187 112 m_noMappedUpdate = false;
Chris@132 113 }
Chris@132 114
Chris@132 115 void
Chris@1589 116 Thumbwheel::setProvideContextMenu(bool provide)
Chris@1589 117 {
Chris@1589 118 m_provideContextMenu = provide;
Chris@1589 119 }
Chris@1589 120
Chris@1589 121 void
Chris@133 122 Thumbwheel::setMinimumValue(int min)
Chris@133 123 {
Chris@133 124 if (m_min == min) return;
Chris@133 125
Chris@133 126 m_min = min;
Chris@133 127 if (m_max <= m_min) m_max = m_min + 1;
Chris@133 128 if (m_value < m_min) m_value = m_min;
Chris@133 129 if (m_value > m_max) m_value = m_max;
Chris@165 130
Chris@165 131 m_rotation = float(m_value - m_min) / float(m_max - m_min);
Chris@165 132 update();
Chris@133 133 }
Chris@133 134
Chris@133 135 int
Chris@133 136 Thumbwheel::getMinimumValue() const
Chris@133 137 {
Chris@133 138 return m_min;
Chris@133 139 }
Chris@133 140
Chris@133 141 void
Chris@133 142 Thumbwheel::setMaximumValue(int max)
Chris@133 143 {
Chris@133 144 if (m_max == max) return;
Chris@133 145
Chris@133 146 m_max = max;
Chris@133 147 if (m_min >= m_max) m_min = m_max - 1;
Chris@133 148 if (m_value < m_min) m_value = m_min;
Chris@133 149 if (m_value > m_max) m_value = m_max;
Chris@165 150
Chris@165 151 m_rotation = float(m_value - m_min) / float(m_max - m_min);
Chris@165 152 update();
Chris@133 153 }
Chris@133 154
Chris@133 155 int
Chris@133 156 Thumbwheel::getMaximumValue() const
Chris@133 157 {
Chris@133 158 return m_max;
Chris@133 159 }
Chris@133 160
Chris@133 161 void
Chris@133 162 Thumbwheel::setDefaultValue(int deft)
Chris@133 163 {
Chris@133 164 if (m_default == deft) return;
Chris@133 165
Chris@133 166 m_default = deft;
Chris@133 167 if (m_atDefault) {
Chris@133 168 setValue(m_default);
Chris@165 169 m_atDefault = true; // setValue unsets this
Chris@382 170 m_cache = QImage();
Chris@133 171 emit valueChanged(getValue());
Chris@133 172 }
Chris@133 173 }
Chris@133 174
Chris@187 175 void
Chris@908 176 Thumbwheel::setMappedValue(double mappedValue)
Chris@187 177 {
Chris@187 178 if (m_rangeMapper) {
Chris@187 179 int newValue = m_rangeMapper->getPositionForValue(mappedValue);
Chris@190 180 bool changed = (m_mappedValue != mappedValue);
Chris@187 181 m_mappedValue = mappedValue;
Chris@187 182 m_noMappedUpdate = true;
Chris@587 183 // SVDEBUG << "Thumbwheel::setMappedValue(" << mappedValue << "): new value is " << newValue << " (visible " << isVisible() << ")" << endl;
Chris@187 184 if (newValue != getValue()) {
Chris@187 185 setValue(newValue);
Chris@190 186 changed = true;
Chris@382 187 m_cache = QImage();
Chris@187 188 }
Chris@190 189 if (changed) emit valueChanged(newValue);
Chris@187 190 m_noMappedUpdate = false;
Chris@187 191 } else {
Chris@190 192 int v = int(mappedValue);
Chris@190 193 if (v != getValue()) {
Chris@190 194 setValue(v);
Chris@382 195 m_cache = QImage();
Chris@190 196 emit valueChanged(v);
Chris@190 197 }
Chris@187 198 }
Chris@187 199 }
Chris@187 200
Chris@133 201 int
Chris@133 202 Thumbwheel::getDefaultValue() const
Chris@133 203 {
Chris@133 204 return m_default;
Chris@133 205 }
Chris@133 206
Chris@133 207 void
Chris@132 208 Thumbwheel::setValue(int value)
Chris@132 209 {
Chris@587 210 // SVDEBUG << "Thumbwheel::setValue(" << value << ") (from " << m_value
Chris@585 211 // << ", rotation " << m_rotation << ")" << " (visible " << isVisible() << ")" << endl;
Chris@133 212
Chris@165 213 if (m_value != value) {
Chris@165 214
Chris@165 215 m_atDefault = false;
Chris@165 216
Chris@165 217 if (value < m_min) value = m_min;
Chris@165 218 if (value > m_max) value = m_max;
Chris@165 219 m_value = value;
Chris@165 220 }
Chris@165 221
Chris@165 222 m_rotation = float(m_value - m_min) / float(m_max - m_min);
Chris@382 223 m_cache = QImage();
Chris@1586 224
Chris@1586 225 if (isVisible()) {
Chris@1586 226 update();
Chris@1586 227 updateTitle();
Chris@1586 228 }
Chris@132 229 }
Chris@132 230
Chris@133 231 void
Chris@133 232 Thumbwheel::resetToDefault()
Chris@133 233 {
Chris@133 234 if (m_default == m_value) return;
Chris@133 235 setValue(m_default);
Chris@133 236 m_atDefault = true;
Chris@382 237 m_cache = QImage();
Chris@133 238 emit valueChanged(getValue());
Chris@133 239 }
Chris@133 240
Chris@132 241 int
Chris@132 242 Thumbwheel::getValue() const
Chris@132 243 {
Chris@132 244 return m_value;
Chris@132 245 }
Chris@132 246
Chris@908 247 double
Chris@187 248 Thumbwheel::getMappedValue() const
Chris@187 249 {
Chris@187 250 if (m_rangeMapper) {
Chris@587 251 // SVDEBUG << "Thumbwheel::getMappedValue(): value = " << getValue() << ", mappedValue = " << m_mappedValue << endl;
Chris@187 252 return m_mappedValue;
Chris@187 253 }
Chris@187 254 return getValue();
Chris@187 255 }
Chris@187 256
Chris@187 257 void
Chris@187 258 Thumbwheel::updateMappedValue(int value)
Chris@187 259 {
Chris@187 260 if (!m_noMappedUpdate) {
Chris@187 261 if (m_rangeMapper) {
Chris@187 262 m_mappedValue = m_rangeMapper->getValueForPosition(value);
Chris@187 263 } else {
Chris@187 264 m_mappedValue = value;
Chris@187 265 }
Chris@187 266 }
Chris@187 267
Chris@1586 268 updateTitle();
Chris@1586 269 }
Chris@1586 270
Chris@1586 271 void
Chris@1586 272 Thumbwheel::updateTitle()
Chris@1586 273 {
Chris@1586 274 QString name = objectName();
Chris@1586 275 QString unit = "";
Chris@1586 276 QString text;
Chris@1586 277 double mappedValue = getMappedValue();
Chris@1586 278
Chris@1586 279 if (m_rangeMapper) unit = m_rangeMapper->getUnit();
Chris@1586 280 if (name != "") {
Chris@1586 281 text = tr("%1: %2%3").arg(name).arg(mappedValue).arg(unit);
Chris@1586 282 } else {
Chris@1586 283 text = tr("%2%3").arg(mappedValue).arg(unit);
Chris@1586 284 }
Chris@1586 285
Chris@1586 286 m_title = text;
Chris@1586 287
Chris@187 288 if (m_showTooltip) {
Chris@187 289 setToolTip(text);
Chris@1586 290 } else {
Chris@1586 291 setToolTip("");
Chris@187 292 }
Chris@187 293 }
Chris@187 294
Chris@132 295 void
Chris@256 296 Thumbwheel::scroll(bool up)
Chris@256 297 {
Chris@908 298 int step = int(lrintf(m_speed));
Chris@256 299 if (step == 0) step = 1;
Chris@256 300
Chris@256 301 if (up) {
Chris@1266 302 setValue(m_value + step);
Chris@256 303 } else {
Chris@1266 304 setValue(m_value - step);
Chris@256 305 }
Chris@256 306
Chris@256 307 emit valueChanged(getValue());
Chris@256 308 }
Chris@256 309
Chris@256 310 void
Chris@132 311 Thumbwheel::setSpeed(float speed)
Chris@132 312 {
Chris@132 313 m_speed = speed;
Chris@132 314 }
Chris@132 315
Chris@132 316 float
Chris@132 317 Thumbwheel::getSpeed() const
Chris@132 318 {
Chris@132 319 return m_speed;
Chris@132 320 }
Chris@132 321
Chris@132 322 void
Chris@132 323 Thumbwheel::setTracking(bool tracking)
Chris@132 324 {
Chris@132 325 m_tracking = tracking;
Chris@132 326 }
Chris@132 327
Chris@132 328 bool
Chris@132 329 Thumbwheel::getTracking() const
Chris@132 330 {
Chris@132 331 return m_tracking;
Chris@132 332 }
Chris@132 333
Chris@132 334 void
Chris@132 335 Thumbwheel::setShowScale(bool showScale)
Chris@132 336 {
Chris@132 337 m_showScale = showScale;
Chris@132 338 }
Chris@132 339
Chris@132 340 bool
Chris@132 341 Thumbwheel::getShowScale() const
Chris@132 342 {
Chris@132 343 return m_showScale;
Chris@132 344 }
Chris@132 345
Chris@132 346 void
Chris@189 347 Thumbwheel::enterEvent(QEvent *)
Chris@189 348 {
Chris@189 349 emit mouseEntered();
Chris@189 350 }
Chris@189 351
Chris@189 352 void
Chris@189 353 Thumbwheel::leaveEvent(QEvent *)
Chris@189 354 {
Chris@189 355 emit mouseLeft();
Chris@189 356 }
Chris@189 357
Chris@189 358 void
Chris@132 359 Thumbwheel::mousePressEvent(QMouseEvent *e)
Chris@132 360 {
Chris@187 361 if (e->button() == Qt::MidButton ||
Chris@187 362 ((e->button() == Qt::LeftButton) &&
Chris@187 363 (e->modifiers() & Qt::ControlModifier))) {
Chris@187 364 resetToDefault();
Chris@187 365 } else if (e->button() == Qt::LeftButton) {
Chris@133 366 m_clicked = true;
Chris@133 367 m_clickPos = e->pos();
Chris@165 368 m_clickRotation = m_rotation;
Chris@133 369 }
Chris@132 370 }
Chris@132 371
Chris@132 372 void
Chris@187 373 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
Chris@132 374 {
Chris@188 375 //!!! needs a common base class with AudioDial (and Panner?)
Chris@187 376
Chris@187 377 if (mouseEvent->button() != Qt::LeftButton) {
Chris@187 378 return;
Chris@187 379 }
Chris@187 380
Chris@1586 381 edit();
Chris@1586 382 }
Chris@1586 383
Chris@1586 384 void
Chris@1586 385 Thumbwheel::edit()
Chris@1586 386 {
Chris@187 387 bool ok = false;
Chris@187 388
Chris@187 389 if (m_rangeMapper) {
Chris@187 390
Chris@908 391 double min = m_rangeMapper->getValueForPosition(m_min);
Chris@908 392 double max = m_rangeMapper->getValueForPosition(m_max);
Chris@187 393
Chris@187 394 if (min > max) {
Chris@908 395 double tmp = min;
Chris@187 396 min = max;
Chris@187 397 max = tmp;
Chris@187 398 }
Chris@187 399
Chris@187 400 QString unit = m_rangeMapper->getUnit();
Chris@187 401
Chris@187 402 QString text;
Chris@187 403 if (objectName() != "") {
Chris@187 404 if (unit != "") {
Chris@187 405 text = tr("New value for %1, from %2 to %3 %4:")
Chris@187 406 .arg(objectName()).arg(min).arg(max).arg(unit);
Chris@187 407 } else {
Chris@187 408 text = tr("New value for %1, from %2 to %3:")
Chris@187 409 .arg(objectName()).arg(min).arg(max);
Chris@187 410 }
Chris@187 411 } else {
Chris@187 412 if (unit != "") {
Chris@187 413 text = tr("Enter a new value from %1 to %2 %3:")
Chris@187 414 .arg(min).arg(max).arg(unit);
Chris@187 415 } else {
Chris@187 416 text = tr("Enter a new value from %1 to %2:")
Chris@187 417 .arg(min).arg(max);
Chris@187 418 }
Chris@187 419 }
Chris@187 420
Chris@908 421 double newValue = QInputDialog::getDouble
Chris@187 422 (this,
Chris@187 423 tr("Enter new value"),
Chris@187 424 text,
Chris@187 425 m_mappedValue,
Chris@187 426 min,
Chris@187 427 max,
Chris@187 428 4,
Chris@187 429 &ok);
Chris@187 430
Chris@187 431 if (ok) {
Chris@187 432 setMappedValue(newValue);
Chris@187 433 }
Chris@187 434
Chris@187 435 } else {
Chris@187 436
Chris@616 437 int newValue = QInputDialog::getInt
Chris@187 438 (this,
Chris@187 439 tr("Enter new value"),
Chris@187 440 tr("Enter a new value from %1 to %2:")
Chris@187 441 .arg(m_min).arg(m_max),
Chris@187 442 getValue(), m_min, m_max, 1, &ok);
Chris@187 443
Chris@187 444 if (ok) {
Chris@187 445 setValue(newValue);
Chris@187 446 }
Chris@187 447 }
Chris@132 448 }
Chris@132 449
Chris@187 450
Chris@132 451 void
Chris@132 452 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
Chris@132 453 {
Chris@133 454 if (!m_clicked) return;
Chris@132 455 int dist = 0;
Chris@132 456 if (m_orientation == Qt::Horizontal) {
Chris@132 457 dist = e->x() - m_clickPos.x();
Chris@132 458 } else {
Chris@132 459 dist = e->y() - m_clickPos.y();
Chris@132 460 }
Chris@165 461
Chris@908 462 float rotation = m_clickRotation + (m_speed * float(dist)) / 100;
Chris@165 463 if (rotation < 0.f) rotation = 0.f;
Chris@165 464 if (rotation > 1.f) rotation = 1.f;
Chris@908 465 int value = int(lrintf(float(m_min) + float(m_max - m_min) * m_rotation));
Chris@132 466 if (value != m_value) {
Chris@132 467 setValue(value);
Chris@132 468 if (m_tracking) emit valueChanged(getValue());
Chris@165 469 m_rotation = rotation;
Chris@165 470 } else if (fabsf(rotation - m_rotation) > 0.001) {
Chris@165 471 m_rotation = rotation;
Chris@165 472 repaint();
Chris@165 473 }
Chris@132 474 }
Chris@132 475
Chris@132 476 void
Chris@132 477 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
Chris@132 478 {
Chris@133 479 if (!m_clicked) return;
Chris@132 480 bool reallyTracking = m_tracking;
Chris@132 481 m_tracking = true;
Chris@132 482 mouseMoveEvent(e);
Chris@132 483 m_tracking = reallyTracking;
Chris@133 484 m_clicked = false;
Chris@132 485 }
Chris@132 486
Chris@132 487 void
Chris@132 488 Thumbwheel::wheelEvent(QWheelEvent *e)
Chris@132 489 {
Chris@1303 490 int delta = m_wheelCounter.count(e);
Chris@132 491
Chris@1303 492 if (delta == 0) {
Chris@1303 493 return;
Chris@132 494 }
Chris@1303 495
Chris@1303 496 setValue(m_value + delta);
Chris@132 497 emit valueChanged(getValue());
Chris@132 498 }
Chris@132 499
Chris@132 500 void
Chris@132 501 Thumbwheel::paintEvent(QPaintEvent *)
Chris@132 502 {
Chris@382 503 Profiler profiler("Thumbwheel::paintEvent");
Chris@382 504
Chris@382 505 if (!m_cache.isNull()) {
Chris@382 506 QPainter paint(this);
Chris@1192 507 paint.drawImage(rect(), m_cache, m_cache.rect());
Chris@382 508 return;
Chris@382 509 }
Chris@382 510
Chris@382 511 Profiler profiler2("Thumbwheel::paintEvent (no cache)");
Chris@382 512
Chris@1192 513 QSize imageSize = size() * devicePixelRatio();
Chris@1192 514 m_cache = QImage(imageSize, QImage::Format_ARGB32);
Chris@382 515 m_cache.fill(Qt::transparent);
Chris@190 516
Chris@1193 517 int w = m_cache.width();
Chris@1193 518 int h = m_cache.height();
Chris@1192 519 int bw = 3; // border width
Chris@191 520
Chris@191 521 QRect subclip;
Chris@191 522 if (m_orientation == Qt::Horizontal) {
Chris@1192 523 subclip = QRect(bw, bw+1, w - bw*2, h - bw*2 - 2);
Chris@191 524 } else {
Chris@1192 525 subclip = QRect(bw+1, bw, w - bw*2 - 2, h - bw*2);
Chris@191 526 }
Chris@191 527
Chris@382 528 QPainter paint(&m_cache);
Chris@1192 529 paint.setClipRect(m_cache.rect());
Chris@1478 530 paint.fillRect(subclip, palette().window().color());
Chris@190 531
Chris@190 532 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@133 533
Chris@908 534 double w0 = 0.5;
Chris@908 535 double w1 = w - 0.5;
Chris@190 536
Chris@908 537 double h0 = 0.5;
Chris@908 538 double h1 = h - 0.5;
Chris@190 539
Chris@190 540 for (int i = bw-1; i >= 0; --i) {
Chris@190 541
Chris@133 542 int grey = (i + 1) * (256 / (bw + 1));
Chris@133 543 QColor fc = QColor(grey, grey, grey);
Chris@133 544 paint.setPen(fc);
Chris@190 545
Chris@190 546 QPainterPath path;
Chris@190 547
Chris@190 548 if (m_orientation == Qt::Horizontal) {
Chris@190 549 path.moveTo(w0 + i, h0 + i + 2);
Chris@190 550 path.quadTo(w/2, i * 1.25, w1 - i, h0 + i + 2);
Chris@190 551 path.lineTo(w1 - i, h1 - i - 2);
Chris@190 552 path.quadTo(w/2, h - i * 1.25, w0 + i, h1 - i - 2);
Chris@190 553 path.closeSubpath();
Chris@190 554 } else {
Chris@190 555 path.moveTo(w0 + i + 2, h0 + i);
Chris@190 556 path.quadTo(i * 1.25, h/2, w0 + i + 2, h1 - i);
Chris@190 557 path.lineTo(w1 - i - 2, h1 - i);
Chris@190 558 path.quadTo(w - i * 1.25, h/2, w1 - i - 2, h0 + i);
Chris@190 559 path.closeSubpath();
Chris@190 560 }
Chris@190 561
Chris@190 562 paint.drawPath(path);
Chris@133 563 }
Chris@133 564
Chris@191 565 paint.setClipRect(subclip);
Chris@133 566
Chris@908 567 double radians = m_rotation * 1.5f * M_PI;
Chris@132 568
Chris@682 569 // cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << endl;
Chris@132 570
Chris@1192 571 int ww = (m_orientation == Qt::Horizontal ? w : h) - bw*2; // wheel width
Chris@132 572
Chris@132 573 // total number of notches on the entire wheel
Chris@132 574 int notches = 25;
Chris@132 575
Chris@132 576 // radius of the wheel including invisible part
Chris@1192 577 int radius = int(ww / 2 + 2);
Chris@132 578
Chris@132 579 for (int i = 0; i < notches; ++i) {
Chris@132 580
Chris@908 581 double a0 = (2.0 * M_PI * i) / notches + radians;
Chris@908 582 double a1 = a0 + M_PI / (notches * 2);
Chris@908 583 double a2 = (2.0 * M_PI * (i + 1)) / notches + radians;
Chris@132 584
Chris@908 585 double depth = cos((a0 + a2) / 2);
Chris@132 586 if (depth < 0) continue;
Chris@132 587
Chris@1192 588 double x0 = radius * sin(a0) + ww/2;
Chris@1192 589 double x1 = radius * sin(a1) + ww/2;
Chris@1192 590 double x2 = radius * sin(a2) + ww/2;
Chris@1192 591 if (x2 < 0 || x0 > ww) continue;
Chris@132 592
Chris@132 593 if (x0 < 0) x0 = 0;
Chris@1192 594 if (x2 > ww) x2 = ww;
Chris@132 595
Chris@133 596 x0 += bw;
Chris@133 597 x1 += bw;
Chris@133 598 x2 += bw;
Chris@133 599
Chris@908 600 int grey = int(lrint(120 * depth));
Chris@541 601
Chris@132 602 QColor fc = QColor(grey, grey, grey);
Chris@541 603 QColor oc = palette().highlight().color();
Chris@132 604
Chris@541 605 paint.setPen(fc);
Chris@132 606
Chris@132 607 if (m_showScale) {
Chris@132 608
Chris@132 609 paint.setBrush(oc);
Chris@132 610
Chris@908 611 double prop;
Chris@132 612 if (i >= notches / 4) {
Chris@908 613 prop = double(notches - (((i - double(notches) / 4.f) * 4.f) / 3.f))
Chris@132 614 / notches;
Chris@132 615 } else {
Chris@132 616 prop = 0.f;
Chris@132 617 }
Chris@132 618
Chris@132 619 if (m_orientation == Qt::Horizontal) {
Chris@1192 620 paint.drawRect(QRectF(x1, h - (h - bw*2) * prop - bw,
Chris@1192 621 x2 - x1, h * prop));
Chris@132 622 } else {
Chris@1192 623 paint.drawRect(QRectF(bw, x1, (w - bw*2) * prop, x2 - x1));
Chris@132 624 }
Chris@132 625 }
Chris@132 626
Chris@541 627 paint.setPen(fc);
Chris@1478 628 paint.setBrush(palette().window().color());
Chris@132 629
Chris@132 630 if (m_orientation == Qt::Horizontal) {
Chris@1192 631 paint.drawRect(QRectF(x0, bw, x1 - x0, h - bw*2));
Chris@132 632 } else {
Chris@1192 633 paint.drawRect(QRectF(bw, x0, w - bw*2, x1 - x0));
Chris@132 634 }
Chris@132 635 }
Chris@382 636
Chris@382 637 QPainter paint2(this);
Chris@1192 638 paint2.drawImage(rect(), m_cache, m_cache.rect());
Chris@132 639 }
Chris@132 640
Chris@132 641 QSize
Chris@132 642 Thumbwheel::sizeHint() const
Chris@132 643 {
Chris@132 644 if (m_orientation == Qt::Horizontal) {
Chris@132 645 return QSize(80, 12);
Chris@132 646 } else {
Chris@132 647 return QSize(12, 80);
Chris@132 648 }
Chris@132 649 }
Chris@132 650