00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <math.h>
00011 #include <qpainter.h>
00012 #include <qpixmap.h>
00013 #include <qevent.h>
00014 #include "qwt_math.h"
00015 #include "qwt_paint_buffer.h"
00016 #include "qwt_painter.h"
00017 #include "qwt_dial_needle.h"
00018 #include "qwt_dial.h"
00019
00020 double QwtDial::d_previousDir = -1.0;
00021
00027 QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent):
00028 d_parent(parent),
00029 d_penWidth(1),
00030 d_visibleLabels(TRUE)
00031 {
00032 }
00033
00043 void QwtDialScaleDraw::showLabels(bool enable)
00044 {
00045 d_visibleLabels = enable;
00046 }
00047
00052 bool QwtDialScaleDraw::visibleLabels() const
00053 {
00054 return d_visibleLabels;
00055 }
00056
00064 void QwtDialScaleDraw::setPenWidth(uint penWidth)
00065 {
00066 d_penWidth = penWidth;
00067 }
00068
00073 uint QwtDialScaleDraw::penWidth() const
00074 {
00075 return d_penWidth;
00076 }
00077
00085 QString QwtDialScaleDraw::label(double value) const
00086 {
00087 if ( !d_visibleLabels )
00088 return QString::null;
00089
00090 if ( d_parent == NULL )
00091 return QwtScaleDraw::label(value);
00092
00093 return d_parent->scaleLabel(value);
00094 }
00095
00107 QwtDial::QwtDial(QWidget* parent, const char* name):
00108 QwtSliderBase(Qt::Horizontal, parent, name,
00109 Qt::WRepaintNoErase|Qt::WResizeNoErase),
00110 d_visibleBackground(FALSE),
00111 d_frameShadow(Sunken),
00112 d_lineWidth(0),
00113 d_mode(RotateNeedle),
00114 d_origin(90.0),
00115 d_minScaleArc(0.0),
00116 d_maxScaleArc(0.0),
00117 d_scaleDraw(0),
00118 d_maxMajIntv(36),
00119 d_maxMinIntv(10),
00120 d_scaleStep(0.0),
00121 d_needle(0)
00122 {
00123 setBackgroundMode(NoBackground);
00124 setFocusPolicy(QWidget::TabFocus);
00125
00126 QPalette p = palette();
00127 for ( int i = 0; i < QPalette::NColorGroups; i++ )
00128 {
00129 const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
00130
00131
00132
00133
00134 p.setColor(cg, QColorGroup::Foreground,
00135 p.color(cg, QColorGroup::Base));
00136 }
00137 setPalette(p);
00138
00139 d_scaleDraw = new QwtDialScaleDraw(this);
00140 d_scaleDraw->setGeometry(0, 0, 0, QwtScaleDraw::Round);
00141
00142 setScaleArc(0.0, 360.0);
00143 setRange(0.0, 360.0, 1.0, 10);
00144 }
00145
00147 QwtDial::~QwtDial()
00148 {
00149 delete d_scaleDraw;
00150 delete d_needle;
00151 }
00152
00161 void QwtDial::showBackground(bool show)
00162 {
00163 if ( d_visibleBackground != show )
00164 {
00165 d_visibleBackground = show;
00166
00167 if ( d_visibleBackground )
00168 clearMask();
00169 else
00170 setMask(QRegion(boundingRect(), QRegion::Ellipse));
00171
00172 update();
00173 }
00174 }
00175
00181 bool QwtDial::hasVisibleBackground() const
00182 {
00183 return d_visibleBackground;
00184 }
00185
00191 void QwtDial::setFrameShadow(Shadow shadow)
00192 {
00193 if ( shadow != d_frameShadow )
00194 {
00195 d_frameShadow = shadow;
00196 if ( lineWidth() > 0 )
00197 update();
00198 }
00199 }
00200
00206 QwtDial::Shadow QwtDial::frameShadow() const
00207 {
00208 return d_frameShadow;
00209 }
00210
00217 void QwtDial::setLineWidth(int lineWidth)
00218 {
00219 if ( lineWidth < 0 )
00220 lineWidth = 0;
00221
00222 if ( d_lineWidth != lineWidth )
00223 {
00224 d_lineWidth = lineWidth;
00225 update();
00226 }
00227 }
00228
00234 int QwtDial::lineWidth() const
00235 {
00236 return d_lineWidth;
00237 }
00238
00243 QRect QwtDial::contentsRect() const
00244 {
00245 const int lw = lineWidth();
00246
00247 QRect r = boundingRect();
00248 if ( lw > 0 )
00249 {
00250 r.setRect(r.x() + lw, r.y() + lw,
00251 r.width() - 2 * lw, r.height() - 2 * lw);
00252 }
00253 return r;
00254 }
00255
00260 QRect QwtDial::boundingRect() const
00261 {
00262 const int radius = QMIN(width(), height()) / 2;
00263
00264 QRect r(0, 0, 2 * radius, 2 * radius);
00265 r.moveCenter(rect().center());
00266 return r;
00267 }
00268
00273 QRect QwtDial::scaleContentsRect() const
00274 {
00275 const QPen scalePen(colorGroup().text(), 0, Qt::NoPen);
00276
00277 int scaleDist = 0;
00278 if ( d_scaleDraw )
00279 {
00280 scaleDist = QMAX(
00281 d_scaleDraw->maxWidth(scalePen, fontMetrics()),
00282 d_scaleDraw->maxHeight(scalePen, fontMetrics()));
00283 scaleDist++;
00284 }
00285
00286 const QRect rect = contentsRect();
00287 return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
00288 rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
00289 }
00290
00306 void QwtDial::setMode(Mode mode)
00307 {
00308 if ( mode != d_mode )
00309 {
00310 d_mode = mode;
00311 update();
00312 }
00313 }
00314
00329 QwtDial::Mode QwtDial::mode() const
00330 {
00331 return d_mode;
00332 }
00333
00344 void QwtDial::setWrapping(bool wrapping)
00345 {
00346 setPeriodic(wrapping);
00347 }
00348
00357 bool QwtDial::wrapping() const
00358 {
00359 return periodic();
00360 }
00361
00363 void QwtDial::resizeEvent(QResizeEvent *e)
00364 {
00365 QWidget::resizeEvent(e);
00366
00367 if ( !hasVisibleBackground() )
00368 setMask(QRegion(boundingRect(), QRegion::Ellipse));
00369 }
00370
00372 void QwtDial::paintEvent(QPaintEvent *e)
00373 {
00374 const QRect &ur = e->rect();
00375 if ( ur.isValid() )
00376 {
00377 QwtPaintBuffer paintBuffer(this, ur);
00378
00379 QPainter *painter = paintBuffer.painter();
00380
00381 drawContents(painter);
00382 drawFrame(painter);
00383
00384 if ( hasFocus() )
00385 drawFocusIndicator(painter);
00386 }
00387 }
00388
00394 void QwtDial::drawFocusIndicator(QPainter *painter) const
00395 {
00396 if ( !isReadOnly() )
00397 {
00398 QRect focusRect = contentsRect();
00399
00400 const int margin = 2;
00401 focusRect.setRect(
00402 focusRect.x() + margin,
00403 focusRect.y() + margin,
00404 focusRect.width() - 2 * margin,
00405 focusRect.height() - 2 * margin);
00406
00407 QColor color = colorGroup().color(QColorGroup::Base);
00408 if (color.isValid())
00409 {
00410 int h, s, v;
00411 color.hsv(&h, &s, &v);
00412 color = (v > 128) ? Qt::gray.dark(120) : Qt::gray.light(120);
00413 }
00414 else
00415 color = Qt::darkGray;
00416
00417 painter->save();
00418 painter->setBrush(Qt::NoBrush);
00419 painter->setPen(QPen(color, 0, Qt::DotLine));
00420 painter->drawEllipse(focusRect);
00421 painter->restore();
00422 }
00423 }
00424
00431 void QwtDial::drawFrame(QPainter *painter)
00432 {
00433 const int lw = lineWidth();
00434 const int off = (lw + 1) % 2;
00435
00436 QRect r = boundingRect();
00437 r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off,
00438 r.width() - lw + off + 1, r.height() - lw + off + 1);
00439
00440 if ( lw > 0 )
00441 {
00442 switch(d_frameShadow)
00443 {
00444 case QwtDial::Raised:
00445 QwtPainter::drawRoundFrame(painter, r,
00446 lw, colorGroup(), FALSE);
00447 break;
00448 case QwtDial::Sunken:
00449 QwtPainter::drawRoundFrame(painter, r,
00450 lw, colorGroup(), TRUE);
00451 break;
00452 default:
00453 {
00454 painter->save();
00455 painter->setPen(QPen(Qt::black, lw));
00456 painter->setBrush(Qt::NoBrush);
00457 painter->drawEllipse(r);
00458 painter->restore();
00459 }
00460 }
00461 }
00462 }
00463
00475 void QwtDial::drawContents(QPainter *painter) const
00476 {
00477 if ( backgroundMode() == NoBackground ||
00478 colorGroup().brush(QColorGroup::Base) !=
00479 colorGroup().brush(QColorGroup::Background) )
00480 {
00481
00482
00483
00484
00485 painter->save();
00486 painter->setPen(Qt::NoPen);
00487 painter->setBrush(colorGroup().brush(QColorGroup::Base));
00488
00489
00490
00491
00492
00493
00494 QRect br = boundingRect();
00495 #if QT_VERSION < 300
00496 #ifdef _WS_WIN32_
00497
00498 br.setTop(br.top()-1);
00499 br.setLeft(br.left()-1);
00500 br.setBottom(br.bottom()+1);
00501 br.setRight(br.right()+1);
00502 #endif
00503 #endif
00504 painter->setClipRegion(QRegion(painter->xForm(br), QRegion::Ellipse));
00505 painter->drawRect(br);
00506 painter->restore();
00507 }
00508
00509
00510 const QRect insideScaleRect = scaleContentsRect();
00511 if ( colorGroup().brush(QColorGroup::Foreground) !=
00512 colorGroup().brush(QColorGroup::Base) )
00513 {
00514 painter->save();
00515 painter->setPen(Qt::NoPen);
00516 painter->setBrush(colorGroup().brush(QColorGroup::Foreground));
00517
00518 painter->setClipRegion(
00519 QRegion(painter->xForm(insideScaleRect), QRegion::Ellipse));
00520 painter->drawRect(insideScaleRect);
00521 painter->restore();
00522 }
00523
00524 const QPoint center = insideScaleRect.center();
00525 const int radius = insideScaleRect.width() / 2;
00526
00527 painter->save();
00528 drawScaleContents(painter, center, radius);
00529 painter->restore();
00530
00531 double direction = d_origin;
00532
00533 if (isValid())
00534 {
00535 direction = d_origin + d_minScaleArc;
00536 if ( maxValue() > minValue() && d_maxScaleArc > d_minScaleArc )
00537 {
00538 const double ratio =
00539 (value() - minValue()) / (maxValue() - minValue());
00540 direction += ratio * (d_maxScaleArc - d_minScaleArc);
00541 }
00542
00543 if ( direction >= 360.0 )
00544 direction -= 360.0;
00545 }
00546
00547 double origin = d_origin;
00548 if ( mode() == RotateScale )
00549 {
00550 origin -= direction - d_origin;
00551 direction = d_origin;
00552 }
00553
00554 painter->save();
00555 drawScale(painter, center, radius, origin, d_minScaleArc, d_maxScaleArc);
00556 painter->restore();
00557
00558 if ( isValid() )
00559 {
00560 QPalette::ColorGroup cg;
00561 if ( isEnabled() )
00562 cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
00563 else
00564 cg = QPalette::Disabled;
00565
00566 painter->save();
00567 drawNeedle(painter, center, radius, direction, cg);
00568 painter->restore();
00569 }
00570 }
00571
00584 void QwtDial::drawNeedle(QPainter *painter, const QPoint ¢er,
00585 int radius, double direction, QPalette::ColorGroup cg) const
00586 {
00587 if ( d_needle )
00588 {
00589 direction = 360.0 - direction;
00590 d_needle->draw(painter, center, radius, direction, cg);
00591 }
00592 }
00593
00606 void QwtDial::drawScale(QPainter *painter, const QPoint ¢er,
00607 int radius, double origin, double minArc, double maxArc) const
00608 {
00609 if ( d_scaleDraw == NULL )
00610 return;
00611
00612 origin -= 270.0;
00613
00614 double angle = maxArc - minArc;
00615 if ( angle > 360.0 )
00616 angle = fmod(angle, 360.0);
00617
00618 minArc += origin;
00619 if ( minArc < -360.0 )
00620 minArc = fmod(minArc, 360.0);
00621
00622 maxArc = minArc + angle;
00623 if ( maxArc > 360.0 )
00624 {
00625
00626
00627 minArc -= 360.0;
00628 maxArc -= 360.0;
00629 }
00630
00631 painter->setFont(font());
00632 painter->setPen(QPen(colorGroup().text(), d_scaleDraw->penWidth()));
00633
00634 d_scaleDraw->setAngleRange(minArc, maxArc);
00635 d_scaleDraw->setGeometry(
00636 center.x() - radius + 1,
00637 center.y() - radius + 1,
00638 2 * radius, QwtScaleDraw::Round);
00639
00640 d_scaleDraw->draw(painter);
00641 }
00642
00643 void QwtDial::drawScaleContents(QPainter *,
00644 const QPoint &, int) const
00645 {
00646
00647 }
00648
00659 void QwtDial::setNeedle(QwtDialNeedle *needle)
00660 {
00661 if ( needle != d_needle )
00662 {
00663 if ( d_needle )
00664 delete d_needle;
00665
00666 d_needle = needle;
00667 update();
00668 }
00669 }
00670
00675 const QwtDialNeedle *QwtDial::needle() const
00676 {
00677 return d_needle;
00678 }
00679
00684 QwtDialNeedle *QwtDial::needle()
00685 {
00686 return d_needle;
00687 }
00688
00690 void QwtDial::rangeChange()
00691 {
00692 updateScale();
00693 }
00694
00699 void QwtDial::updateScale()
00700 {
00701 if ( d_scaleDraw )
00702 {
00703 d_scaleDraw->setScale(minValue(), maxValue(),
00704 d_maxMajIntv, d_maxMinIntv, d_scaleStep);
00705 }
00706 }
00707
00713 void QwtDial::setScaleDraw(QwtDialScaleDraw *scaleDraw)
00714 {
00715 if ( scaleDraw != d_scaleDraw )
00716 {
00717 if ( d_scaleDraw )
00718 delete d_scaleDraw;
00719
00720 d_scaleDraw = scaleDraw;
00721 updateScale();
00722 update();
00723 }
00724 }
00725
00730 void QwtDial::setScale(int maxMajIntv, int maxMinIntv, double step)
00731 {
00732 d_maxMajIntv = maxMajIntv;
00733 d_maxMinIntv = maxMinIntv;
00734 d_scaleStep = step;
00735
00736 updateScale();
00737 }
00738
00754 void QwtDial::setScaleOptions(int options)
00755 {
00756 if ( options == 0 )
00757 setScaleDraw(NULL);
00758
00759 if ( d_scaleDraw == NULL )
00760 return;
00761
00762 int flags = d_scaleDraw->options();
00763 if ( options & ScaleBackbone )
00764 flags |= QwtScaleDraw::Backbone;
00765 else
00766 flags &= ~QwtScaleDraw::Backbone;
00767 d_scaleDraw->setOptions(flags);
00768
00769 if ( !(options & ScaleTicks) )
00770 d_scaleDraw->setTickLength(0, 0, 0);
00771
00772 d_scaleDraw->showLabels(options & ScaleLabel);
00773 }
00774
00776 void QwtDial::setScaleTicks(int minLen, int medLen,
00777 int majLen, int penWidth)
00778 {
00779 if ( d_scaleDraw )
00780 {
00781 d_scaleDraw->setTickLength(minLen, medLen, majLen);
00782 d_scaleDraw->setPenWidth(penWidth);
00783 }
00784 }
00785
00789 QString QwtDial::scaleLabel(double value) const
00790 {
00791 #if 1
00792 if ( value == -0 )
00793 value = 0;
00794 #endif
00795
00796 QString text;
00797 text.sprintf("%g", value);
00798
00799 return text;
00800 }
00801
00810 void QwtDial::setOrigin(double origin)
00811 {
00812 d_origin = origin;
00813 update();
00814 }
00815
00822 double QwtDial::origin() const
00823 {
00824 return d_origin;
00825 }
00826
00833 void QwtDial::setScaleArc(double minArc, double maxArc)
00834 {
00835 if ( minArc != 360.0 && minArc != -360.0 )
00836 minArc = fmod(minArc, 360.0);
00837 if ( maxArc != 360.0 && maxArc != -360.0 )
00838 maxArc = fmod(maxArc, 360.0);
00839
00840 d_minScaleArc = QMIN(minArc, maxArc);
00841 d_maxScaleArc = QMAX(minArc, maxArc);
00842 if ( d_maxScaleArc - d_minScaleArc > 360.0 )
00843 d_maxScaleArc = d_minScaleArc + 360.0;
00844
00845 update();
00846 }
00847
00849 void QwtDial::valueChange()
00850 {
00851 update();
00852 QwtSliderBase::valueChange();
00853 }
00854
00858 QSize QwtDial::sizeHint() const
00859 {
00860 int sh = 0;
00861 if ( d_scaleDraw )
00862 sh = d_scaleDraw->minHeight( QPen(), fontMetrics() );
00863
00864 const int d = 6 * sh + 2 * lineWidth();
00865
00866 return QSize( d, d );
00867 }
00868
00874 QSize QwtDial::minimumSizeHint() const
00875 {
00876 int sh = 0;
00877 if ( d_scaleDraw )
00878 sh = d_scaleDraw->minHeight( QPen(), fontMetrics() );
00879
00880 const int d = 3 * sh + 2 * lineWidth();
00881
00882 return QSize( d, d );
00883 }
00884
00885 static double line2Radians(const QPoint &p1, const QPoint &p2)
00886 {
00887 const QPoint p = p2 - p1;
00888
00889 double angle;
00890 if ( p.x() == 0 )
00891 angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
00892 else
00893 {
00894 angle = atan(double(-p.y()) / double(p.x()));
00895 if ( p.x() < 0 )
00896 angle += M_PI;
00897 if ( angle < 0.0 )
00898 angle += 2 * M_PI;
00899 }
00900 return 360.0 - angle * 180.0 / M_PI;
00901 }
00902
00909 double QwtDial::getValue(const QPoint &pos)
00910 {
00911 if ( d_maxScaleArc == d_minScaleArc || maxValue() == minValue() )
00912 return minValue();
00913
00914 double dir = line2Radians(rect().center(), pos) - d_origin;
00915 if ( dir < 0.0 )
00916 dir += 360.0;
00917
00918 if ( mode() == RotateScale )
00919 dir = 360.0 - dir;
00920
00921
00922
00923
00924 const double completeCircle = 360.0 / (d_maxScaleArc - d_minScaleArc)
00925 * (maxValue() - minValue());
00926
00927 double posValue = minValue() + completeCircle * dir / 360.0;
00928
00929 if ( d_scrollMode == ScrMouse )
00930 {
00931 if ( d_previousDir >= 0.0 )
00932 {
00933
00934
00935
00936 bool clockWise = FALSE;
00937
00938 const double angle = dir - d_previousDir;
00939 if ( (angle >= 0.0 && angle <= 180.0) || angle < -180.0 )
00940 clockWise = TRUE;
00941
00942 if ( clockWise )
00943 {
00944 if ( dir < d_previousDir && d_mouseOffset > 0.0 )
00945 {
00946
00947 d_mouseOffset -= completeCircle;
00948 }
00949
00950 if ( wrapping() )
00951 {
00952 if ( posValue - d_mouseOffset > maxValue() )
00953 {
00954
00955
00956
00957 d_mouseOffset = posValue - minValue();
00958 }
00959 }
00960 else
00961 {
00962 if ( posValue - d_mouseOffset > maxValue() ||
00963 value() == maxValue() )
00964 {
00965
00966
00967
00968 d_mouseOffset = posValue - maxValue();
00969 }
00970 }
00971 }
00972 else
00973 {
00974 if ( dir > d_previousDir && d_mouseOffset < 0.0 )
00975 {
00976
00977 d_mouseOffset += completeCircle;
00978 }
00979
00980 if ( wrapping() )
00981 {
00982 if ( posValue - d_mouseOffset < minValue() )
00983 {
00984
00985
00986
00987 d_mouseOffset = posValue - maxValue();
00988 }
00989 }
00990 else
00991 {
00992 if ( posValue - d_mouseOffset < minValue() ||
00993 value() == minValue() )
00994 {
00995
00996
00997
00998 d_mouseOffset = posValue - minValue();
00999 }
01000 }
01001 }
01002 }
01003 d_previousDir = dir;
01004 }
01005
01006 return posValue;
01007 }
01008
01012 void QwtDial::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
01013 {
01014 direction = 0;
01015 scrollMode = ScrNone;
01016
01017 const QRegion region(contentsRect(), QRegion::Ellipse);
01018 if ( region.contains(p) && p != rect().center() )
01019 {
01020 scrollMode = ScrMouse;
01021 d_previousDir = -1.0;
01022 }
01023 }
01024
01044 void QwtDial::keyPressEvent(QKeyEvent *e)
01045 {
01046 if ( isReadOnly() )
01047 {
01048 #if QT_VERSION >= 300
01049 e->ignore();
01050 #endif
01051 return;
01052 }
01053
01054 if ( !isValid() )
01055 return;
01056
01057 double previous = prevValue();
01058 switch ( e->key() )
01059 {
01060 case Qt::Key_Down:
01061 case Qt::Key_Left:
01062 QwtDblRange::incValue(-1);
01063 break;
01064 case Qt::Key_Prior:
01065 QwtDblRange::incValue(-pageSize());
01066 break;
01067 case Qt::Key_Home:
01068 setValue(minValue());
01069 break;
01070
01071 case Qt::Key_Up:
01072 case Qt::Key_Right:
01073 QwtDblRange::incValue(1);
01074 break;
01075 case Qt::Key_Next:
01076 QwtDblRange::incValue(pageSize());
01077 break;
01078 case Qt::Key_End:
01079 setValue(maxValue());
01080 break;
01081 default:;
01082 #if QT_VERSION >= 300
01083 e->ignore();
01084 #endif
01085 }
01086
01087 if (value() != previous)
01088 emit sliderMoved(value());
01089 }
01090