00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "Thumbwheel.h"
00017
00018 #include "base/RangeMapper.h"
00019 #include "base/Profiler.h"
00020
00021 #include <QMouseEvent>
00022 #include <QPaintEvent>
00023 #include <QWheelEvent>
00024 #include <QInputDialog>
00025 #include <QPainter>
00026 #include <QPainterPath>
00027
00028 #include <cmath>
00029 #include <iostream>
00030
00031 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
00032 QWidget *parent) :
00033 QWidget(parent),
00034 m_min(0),
00035 m_max(100),
00036 m_default(50),
00037 m_value(50),
00038 m_mappedValue(50),
00039 m_noMappedUpdate(false),
00040 m_rotation(0.5),
00041 m_orientation(orientation),
00042 m_speed(1.0),
00043 m_tracking(true),
00044 m_showScale(true),
00045 m_clicked(false),
00046 m_atDefault(true),
00047 m_clickRotation(m_rotation),
00048 m_showTooltip(true),
00049 m_rangeMapper(0)
00050 {
00051 }
00052
00053 Thumbwheel::~Thumbwheel()
00054 {
00055 delete m_rangeMapper;
00056 }
00057
00058 void
00059 Thumbwheel::setRangeMapper(RangeMapper *mapper)
00060 {
00061 if (m_rangeMapper == mapper) return;
00062
00063 if (!m_rangeMapper && mapper) {
00064 connect(this, SIGNAL(valueChanged(int)),
00065 this, SLOT(updateMappedValue(int)));
00066 }
00067
00068 delete m_rangeMapper;
00069 m_rangeMapper = mapper;
00070
00071 updateMappedValue(getValue());
00072 }
00073
00074 void
00075 Thumbwheel::setShowToolTip(bool show)
00076 {
00077 m_showTooltip = show;
00078 m_noMappedUpdate = true;
00079 updateMappedValue(getValue());
00080 m_noMappedUpdate = false;
00081 }
00082
00083 void
00084 Thumbwheel::setMinimumValue(int min)
00085 {
00086 if (m_min == min) return;
00087
00088 m_min = min;
00089 if (m_max <= m_min) m_max = m_min + 1;
00090 if (m_value < m_min) m_value = m_min;
00091 if (m_value > m_max) m_value = m_max;
00092
00093 m_rotation = float(m_value - m_min) / float(m_max - m_min);
00094 update();
00095 }
00096
00097 int
00098 Thumbwheel::getMinimumValue() const
00099 {
00100 return m_min;
00101 }
00102
00103 void
00104 Thumbwheel::setMaximumValue(int max)
00105 {
00106 if (m_max == max) return;
00107
00108 m_max = max;
00109 if (m_min >= m_max) m_min = m_max - 1;
00110 if (m_value < m_min) m_value = m_min;
00111 if (m_value > m_max) m_value = m_max;
00112
00113 m_rotation = float(m_value - m_min) / float(m_max - m_min);
00114 update();
00115 }
00116
00117 int
00118 Thumbwheel::getMaximumValue() const
00119 {
00120 return m_max;
00121 }
00122
00123 void
00124 Thumbwheel::setDefaultValue(int deft)
00125 {
00126 if (m_default == deft) return;
00127
00128 m_default = deft;
00129 if (m_atDefault) {
00130 setValue(m_default);
00131 m_atDefault = true;
00132 emit valueChanged(getValue());
00133 }
00134 }
00135
00136 void
00137 Thumbwheel::setMappedValue(float mappedValue)
00138 {
00139 if (m_rangeMapper) {
00140 int newValue = m_rangeMapper->getPositionForValue(mappedValue);
00141 bool changed = (m_mappedValue != mappedValue);
00142 m_mappedValue = mappedValue;
00143 m_noMappedUpdate = true;
00144
00145 if (newValue != getValue()) {
00146 setValue(newValue);
00147 changed = true;
00148 }
00149 if (changed) emit valueChanged(newValue);
00150 m_noMappedUpdate = false;
00151 } else {
00152 int v = int(mappedValue);
00153 if (v != getValue()) {
00154 setValue(v);
00155 emit valueChanged(v);
00156 }
00157 }
00158 }
00159
00160 int
00161 Thumbwheel::getDefaultValue() const
00162 {
00163 return m_default;
00164 }
00165
00166 void
00167 Thumbwheel::setValue(int value)
00168 {
00169
00170
00171
00172 if (m_value != value) {
00173
00174 m_atDefault = false;
00175
00176 if (value < m_min) value = m_min;
00177 if (value > m_max) value = m_max;
00178 m_value = value;
00179 }
00180
00181 m_rotation = float(m_value - m_min) / float(m_max - m_min);
00182 if (isVisible()) update();
00183 }
00184
00185 void
00186 Thumbwheel::resetToDefault()
00187 {
00188 if (m_default == m_value) return;
00189 setValue(m_default);
00190 m_atDefault = true;
00191 emit valueChanged(getValue());
00192 }
00193
00194 int
00195 Thumbwheel::getValue() const
00196 {
00197 return m_value;
00198 }
00199
00200 float
00201 Thumbwheel::getMappedValue() const
00202 {
00203 if (m_rangeMapper) {
00204
00205 return m_mappedValue;
00206 }
00207 return getValue();
00208 }
00209
00210 void
00211 Thumbwheel::updateMappedValue(int value)
00212 {
00213 if (!m_noMappedUpdate) {
00214 if (m_rangeMapper) {
00215 m_mappedValue = m_rangeMapper->getValueForPosition(value);
00216 } else {
00217 m_mappedValue = value;
00218 }
00219 }
00220
00221 if (m_showTooltip) {
00222 QString name = objectName();
00223 QString unit = "";
00224 QString text;
00225 if (m_rangeMapper) unit = m_rangeMapper->getUnit();
00226 if (name != "") {
00227 text = tr("%1: %2%3").arg(name).arg(m_mappedValue).arg(unit);
00228 } else {
00229 text = tr("%2%3").arg(m_mappedValue).arg(unit);
00230 }
00231 setToolTip(text);
00232 }
00233 }
00234
00235 void
00236 Thumbwheel::scroll(bool up)
00237 {
00238 int step = lrintf(m_speed);
00239 if (step == 0) step = 1;
00240
00241 if (up) {
00242 setValue(m_value + step);
00243 } else {
00244 setValue(m_value - step);
00245 }
00246
00247 emit valueChanged(getValue());
00248 }
00249
00250 void
00251 Thumbwheel::setSpeed(float speed)
00252 {
00253 m_speed = speed;
00254 }
00255
00256 float
00257 Thumbwheel::getSpeed() const
00258 {
00259 return m_speed;
00260 }
00261
00262 void
00263 Thumbwheel::setTracking(bool tracking)
00264 {
00265 m_tracking = tracking;
00266 }
00267
00268 bool
00269 Thumbwheel::getTracking() const
00270 {
00271 return m_tracking;
00272 }
00273
00274 void
00275 Thumbwheel::setShowScale(bool showScale)
00276 {
00277 m_showScale = showScale;
00278 }
00279
00280 bool
00281 Thumbwheel::getShowScale() const
00282 {
00283 return m_showScale;
00284 }
00285
00286 void
00287 Thumbwheel::enterEvent(QEvent *)
00288 {
00289 emit mouseEntered();
00290 }
00291
00292 void
00293 Thumbwheel::leaveEvent(QEvent *)
00294 {
00295 emit mouseLeft();
00296 }
00297
00298 void
00299 Thumbwheel::mousePressEvent(QMouseEvent *e)
00300 {
00301 if (e->button() == Qt::MidButton ||
00302 ((e->button() == Qt::LeftButton) &&
00303 (e->modifiers() & Qt::ControlModifier))) {
00304 resetToDefault();
00305 } else if (e->button() == Qt::LeftButton) {
00306 m_clicked = true;
00307 m_clickPos = e->pos();
00308 m_clickRotation = m_rotation;
00309 }
00310 }
00311
00312 void
00313 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
00314 {
00316
00317 if (mouseEvent->button() != Qt::LeftButton) {
00318 return;
00319 }
00320
00321 bool ok = false;
00322
00323 if (m_rangeMapper) {
00324
00325 float min = m_rangeMapper->getValueForPosition(m_min);
00326 float max = m_rangeMapper->getValueForPosition(m_max);
00327
00328 if (min > max) {
00329 float tmp = min;
00330 min = max;
00331 max = tmp;
00332 }
00333
00334 QString unit = m_rangeMapper->getUnit();
00335
00336 QString text;
00337 if (objectName() != "") {
00338 if (unit != "") {
00339 text = tr("New value for %1, from %2 to %3 %4:")
00340 .arg(objectName()).arg(min).arg(max).arg(unit);
00341 } else {
00342 text = tr("New value for %1, from %2 to %3:")
00343 .arg(objectName()).arg(min).arg(max);
00344 }
00345 } else {
00346 if (unit != "") {
00347 text = tr("Enter a new value from %1 to %2 %3:")
00348 .arg(min).arg(max).arg(unit);
00349 } else {
00350 text = tr("Enter a new value from %1 to %2:")
00351 .arg(min).arg(max);
00352 }
00353 }
00354
00355 float newValue = QInputDialog::getDouble
00356 (this,
00357 tr("Enter new value"),
00358 text,
00359 m_mappedValue,
00360 min,
00361 max,
00362 4,
00363 &ok);
00364
00365 if (ok) {
00366 setMappedValue(newValue);
00367 }
00368
00369 } else {
00370
00371 int newValue = QInputDialog::getInteger
00372 (this,
00373 tr("Enter new value"),
00374 tr("Enter a new value from %1 to %2:")
00375 .arg(m_min).arg(m_max),
00376 getValue(), m_min, m_max, 1, &ok);
00377
00378 if (ok) {
00379 setValue(newValue);
00380 }
00381 }
00382 }
00383
00384
00385 void
00386 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
00387 {
00388 if (!m_clicked) return;
00389 int dist = 0;
00390 if (m_orientation == Qt::Horizontal) {
00391 dist = e->x() - m_clickPos.x();
00392 } else {
00393 dist = e->y() - m_clickPos.y();
00394 }
00395
00396 float rotation = m_clickRotation + (m_speed * dist) / 100;
00397 if (rotation < 0.f) rotation = 0.f;
00398 if (rotation > 1.f) rotation = 1.f;
00399 int value = lrintf(m_min + (m_max - m_min) * m_rotation);
00400 if (value != m_value) {
00401 setValue(value);
00402 if (m_tracking) emit valueChanged(getValue());
00403 m_rotation = rotation;
00404 } else if (fabsf(rotation - m_rotation) > 0.001) {
00405 m_rotation = rotation;
00406 repaint();
00407 }
00408 }
00409
00410 void
00411 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
00412 {
00413 if (!m_clicked) return;
00414 bool reallyTracking = m_tracking;
00415 m_tracking = true;
00416 mouseMoveEvent(e);
00417 m_tracking = reallyTracking;
00418 m_clicked = false;
00419 }
00420
00421 void
00422 Thumbwheel::wheelEvent(QWheelEvent *e)
00423 {
00424 int step = lrintf(m_speed);
00425 if (step == 0) step = 1;
00426
00427 if (e->delta() > 0) {
00428 setValue(m_value + step);
00429 } else {
00430 setValue(m_value - step);
00431 }
00432
00433 emit valueChanged(getValue());
00434 }
00435
00436 void
00437 Thumbwheel::paintEvent(QPaintEvent *)
00438 {
00439 Profiler profiler("Thumbwheel::paintEvent", true);
00440
00441 int bw = 3;
00442
00443 QRect subclip;
00444 if (m_orientation == Qt::Horizontal) {
00445 subclip = QRect(bw, bw+1, width() - bw*2, height() - bw*2 - 2);
00446 } else {
00447 subclip = QRect(bw+1, bw, width() - bw*2 - 2, height() - bw*2);
00448 }
00449
00450 QPainter paint(this);
00451 paint.fillRect(subclip, palette().background().color());
00452
00453 paint.setRenderHint(QPainter::Antialiasing, true);
00454
00455 float w = width();
00456 float w0 = 0.5;
00457 float w1 = w - 0.5;
00458
00459 float h = height();
00460 float h0 = 0.5;
00461 float h1 = h - 0.5;
00462
00463 for (int i = bw-1; i >= 0; --i) {
00464
00465
00466 int grey = (i + 1) * (256 / (bw + 1));
00467 QColor fc = QColor(grey, grey, grey);
00468 paint.setPen(fc);
00469
00470 QPainterPath path;
00471
00472 if (m_orientation == Qt::Horizontal) {
00473 path.moveTo(w0 + i, h0 + i + 2);
00474 path.quadTo(w/2, i * 1.25, w1 - i, h0 + i + 2);
00475 path.lineTo(w1 - i, h1 - i - 2);
00476 path.quadTo(w/2, h - i * 1.25, w0 + i, h1 - i - 2);
00477 path.closeSubpath();
00478 } else {
00479 path.moveTo(w0 + i + 2, h0 + i);
00480 path.quadTo(i * 1.25, h/2, w0 + i + 2, h1 - i);
00481 path.lineTo(w1 - i - 2, h1 - i);
00482 path.quadTo(w - i * 1.25, h/2, w1 - i - 2, h0 + i);
00483 path.closeSubpath();
00484 }
00485
00486 paint.drawPath(path);
00487 }
00488
00489 paint.setClipRect(subclip);
00490
00491 float radians = m_rotation * 1.5f * M_PI;
00492
00493
00494
00495 w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2;
00496
00497
00498 int notches = 25;
00499
00500
00501 int radius = int(w / 2 + 2);
00502
00503 for (int i = 0; i < notches; ++i) {
00504
00505 float a0 = (2.f * M_PI * i) / notches + radians;
00506 float a1 = a0 + M_PI / (notches * 2);
00507 float a2 = (2.f * M_PI * (i + 1)) / notches + radians;
00508
00509 float depth = cosf((a0 + a2) / 2);
00510 if (depth < 0) continue;
00511
00512 float x0 = radius * sinf(a0) + w/2;
00513 float x1 = radius * sinf(a1) + w/2;
00514 float x2 = radius * sinf(a2) + w/2;
00515 if (x2 < 0 || x0 > w) continue;
00516
00517 if (x0 < 0) x0 = 0;
00518 if (x2 > w) x2 = w;
00519
00520 x0 += bw;
00521 x1 += bw;
00522 x2 += bw;
00523
00524 int grey = lrintf(255 * depth);
00525 QColor fc = QColor(grey, grey, grey);
00526 QColor oc = palette().dark().color();
00527
00528 paint.setPen(oc);
00529 paint.setBrush(fc);
00530
00531 if (m_orientation == Qt::Horizontal) {
00532 paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2));
00533 } else {
00534 paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1));
00535 }
00536
00537 if (m_showScale) {
00538
00539 paint.setBrush(oc);
00540
00541 float prop;
00542 if (i >= notches / 4) {
00543 prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f))
00544 / notches;
00545 } else {
00546 prop = 0.f;
00547 }
00548
00549 if (m_orientation == Qt::Horizontal) {
00550 paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw,
00551 x2 - x1, height() * prop));
00552 } else {
00553 paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1));
00554 }
00555 }
00556
00557 paint.setPen(oc);
00558 paint.setBrush(palette().background().color());
00559
00560 if (m_orientation == Qt::Horizontal) {
00561 paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2));
00562 } else {
00563 paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0));
00564 }
00565 }
00566 }
00567
00568 QSize
00569 Thumbwheel::sizeHint() const
00570 {
00571 if (m_orientation == Qt::Horizontal) {
00572 return QSize(80, 12);
00573 } else {
00574 return QSize(12, 80);
00575 }
00576 }
00577