# qwt_dial.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 #include <math.h>
    00011 #include <qpainter.h>
    00012 #if QT_VERSION >= 0x040000
    00013 #include <qbitmap.h>
    00014 #include <qpalette.h>
    00015 #endif
    00016 #include <qpixmap.h>
    00017 #include <qevent.h>
    00018 #include "qwt_math.h"
    00019 #include "qwt_scale_engine.h"
    00020 #include "qwt_scale_map.h"
    00021 #include "qwt_paint_buffer.h"
    00022 #include "qwt_painter.h"
    00023 #include "qwt_dial_needle.h"
    00024 #include "qwt_dial.h"
    00025
    00026 class QwtDial::PrivateData
    00027 {
    00028 public:
    00029     PrivateData():
    00030         visibleBackground(true),
    00031         frameShadow(Sunken),
    00032         lineWidth(0),
    00033         mode(RotateNeedle),
    00034         origin(90.0),
    00035         minScaleArc(0.0),
    00036         maxScaleArc(0.0),
    00037         scaleDraw(0),
    00038         maxMajIntv(36),
    00039         maxMinIntv(10),
    00040         scaleStep(0.0),
    00041         needle(0)
    00042     {
    00043     }
    00044
    00045     ~PrivateData()
    00046     {
    00047         delete scaleDraw;
    00048         delete needle;
    00049     }
    00050     bool visibleBackground;
    00051     Shadow frameShadow;
    00052     int lineWidth;
    00053
    00054     QwtDial::Mode mode;
    00055
    00056     double origin;
    00057     double minScaleArc;
    00058     double maxScaleArc;
    00059
    00060     QwtDialScaleDraw *scaleDraw;
    00061     int maxMajIntv;
    00062     int maxMinIntv;
    00063     double scaleStep;
    00064
    00065     QwtDialNeedle *needle;
    00066
    00067     static double previousDir;
    00068 };
    00069
    00070 double QwtDial::PrivateData::previousDir = -1.0;
    00071
    00077 QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent):
    00078     d_parent(parent),
    00079     d_penWidth(1)
    00080 {
    00081 }
    00082
    00090 void QwtDialScaleDraw::setPenWidth(uint penWidth)
    00091 {
    00092     d_penWidth = penWidth;
    00093 }
    00094
    00099 uint QwtDialScaleDraw::penWidth() const
    00100 {
    00101     return d_penWidth;
    00102 }
    00103
    00111 QwtText QwtDialScaleDraw::label(double value) const
    00112 {
    00113     if ( d_parent == NULL )
    00114         return QwtRoundScaleDraw::label(value);
    00115
    00116     return d_parent->scaleLabel(value);
    00117 }
    00118
    00129 QwtDial::QwtDial(QWidget* parent):
    00130     QwtAbstractSlider(Qt::Horizontal, parent)
    00131 {
    00132     initDial();
    00133 }
    00134
    00135 #if QT_VERSION < 0x040000
    00136
    00146 QwtDial::QwtDial(QWidget* parent, const char *name):
    00147     QwtAbstractSlider(Qt::Horizontal, parent)
    00148 {
    00149     setName(name);
    00150     initDial();
    00151 }
    00152 #endif
    00153
    00154 void QwtDial::initDial()
    00155 {
    00156     d_data = new PrivateData;
    00157
    00158 #if QT_VERSION < 0x040000
    00159     setWFlags(Qt::WNoAutoErase);
    00160 #endif
    00161
    00162 #if QT_VERSION >= 0x040000
    00163     using namespace Qt;
    00164 #endif
    00165     setFocusPolicy(TabFocus);
    00166
    00167     QPalette p = palette();
    00168     for ( int i = 0; i < QPalette::NColorGroups; i++ )
    00169     {
    00170         const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
    00171
    00172         // Base: background color of the circle inside the frame.
    00173         // Foreground: background color of the circle inside the scale
    00174
    00175 #if QT_VERSION < 0x040000
    00176         p.setColor(cg, QColorGroup::Foreground,
    00177             p.color(cg, QColorGroup::Base));
    00178 #else
    00179         p.setColor(cg, QPalette::Foreground,
    00180             p.color(cg, QPalette::Base));
    00181 #endif
    00182     }
    00183     setPalette(p);
    00184
    00185     d_data->scaleDraw = new QwtDialScaleDraw(this);
    00186     d_data->scaleDraw->setRadius(0);
    00187
    00188     setScaleArc(0.0, 360.0); // scale as a full circle
    00189     setRange(0.0, 360.0, 1.0, 10); // degrees as deafult
    00190 }
    00191
    00193 QwtDial::~QwtDial()
    00194 {
    00195     delete d_data;
    00196 }
    00197
    00206 void QwtDial::showBackground(bool show)
    00207 {
    00208     if ( d_data->visibleBackground != show )
    00209     {
    00210         d_data->visibleBackground = show;
    00211         updateMask();
    00212     }
    00213 }
    00214
    00220 bool QwtDial::hasVisibleBackground() const
    00221 {
    00222     return d_data->visibleBackground;
    00223 }
    00224
    00230 void QwtDial::setFrameShadow(Shadow shadow)
    00231 {
    00232     if ( shadow != d_data->frameShadow )
    00233     {
    00234         d_data->frameShadow = shadow;
    00235         if ( lineWidth() > 0 )
    00236             update();
    00237     }
    00238 }
    00239
    00244 QwtDial::Shadow QwtDial::frameShadow() const
    00245 {
    00246     return d_data->frameShadow;
    00247 }
    00248
    00255 void QwtDial::setLineWidth(int lineWidth)
    00256 {
    00257     if ( lineWidth < 0 )
    00258         lineWidth = 0;
    00259
    00260     if ( d_data->lineWidth != lineWidth )
    00261     {
    00262         d_data->lineWidth = lineWidth;
    00263         update();
    00264     }
    00265 }
    00266
    00271 int QwtDial::lineWidth() const
    00272 {
    00273     return d_data->lineWidth;
    00274 }
    00275
    00280 QRect QwtDial::contentsRect() const
    00281 {
    00282     const int lw = lineWidth();
    00283
    00284     QRect r = boundingRect();
    00285     if ( lw > 0 )
    00286     {
    00287         r.setRect(r.x() + lw, r.y() + lw,
    00288             r.width() - 2 * lw, r.height() - 2 * lw);
    00289     }
    00290     return r;
    00291 }
    00292
    00297 QRect QwtDial::boundingRect() const
    00298 {
    00299     const int radius = qwtMin(width(), height()) / 2;
    00300
    00301     QRect r(0, 0, 2 * radius, 2 * radius);
    00302     r.moveCenter(rect().center());
    00303     return r;
    00304 }
    00305
    00310 QRect QwtDial::scaleContentsRect() const
    00311 {
    00312 #if QT_VERSION < 0x040000
    00313     const QPen scalePen(colorGroup().text(), 0, Qt::NoPen);
    00314 #else
    00315     const QPen scalePen(palette().text(), 0, Qt::NoPen);
    00316 #endif
    00317
    00318     int scaleDist = 0;
    00319     if ( d_data->scaleDraw )
    00320     {
    00321         scaleDist = d_data->scaleDraw->extent(scalePen, font());
    00322         scaleDist++; // margin
    00323     }
    00324
    00325     const QRect rect = contentsRect();
    00326     return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
    00327         rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
    00328 }
    00329
    00345 void QwtDial::setMode(Mode mode)
    00346 {
    00347     if ( mode != d_data->mode )
    00348     {
    00349         d_data->mode = mode;
    00350         update();
    00351     }
    00352 }
    00353
    00368 QwtDial::Mode QwtDial::mode() const
    00369 {
    00370     return d_data->mode;
    00371 }
    00372
    00383 void QwtDial::setWrapping(bool wrapping)
    00384 {
    00385     setPeriodic(wrapping);
    00386 }
    00387
    00396 bool QwtDial::wrapping() const
    00397 {
    00398     return periodic();
    00399 }
    00400
    00405 void QwtDial::resizeEvent(QResizeEvent *e)
    00406 {
    00407     QWidget::resizeEvent(e);
    00408
    00409     if ( !hasVisibleBackground() )
    00410         updateMask();
    00411 }
    00412
    00417 void QwtDial::paintEvent(QPaintEvent *e)
    00418 {
    00419     const QRect &ur = e->rect();
    00420     if ( ur.isValid() )
    00421     {
    00422 #if QT_VERSION < 0x040000
    00423         QwtPaintBuffer paintBuffer(this, ur);
    00424         QPainter &painter = *paintBuffer.painter();
    00425 #else
    00426         QPainter painter(this);
    00427         painter.setRenderHint(QPainter::Antialiasing, true);
    00428 #endif
    00429
    00430         painter.save();
    00431         drawContents(&painter);
    00432         painter.restore();
    00433
    00434         painter.save();
    00435         drawFrame(&painter);
    00436         painter.restore();
    00437
    00438         if ( hasFocus() )
    00439             drawFocusIndicator(&painter);
    00440     }
    00441 }
    00442
    00448 void QwtDial::drawFocusIndicator(QPainter *painter) const
    00449 {
    00450     if ( !isReadOnly() )
    00451     {
    00452         QRect focusRect = contentsRect();
    00453
    00454         const int margin = 2;
    00455         focusRect.setRect(
    00456             focusRect.x() + margin,
    00457             focusRect.y() + margin,
    00458             focusRect.width() - 2 * margin,
    00459             focusRect.height() - 2 * margin);
    00460
    00461 #if QT_VERSION < 0x040000
    00462         QColor color = colorGroup().color(QColorGroup::Base);
    00463 #else
    00464         QColor color = palette().color(QPalette::Base);
    00465 #endif
    00466         if (color.isValid())
    00467         {
    00468             const QColor gray(Qt::gray);
    00469
    00470             int h, s, v;
    00471 #if QT_VERSION < 0x040000
    00472             color.hsv(&h, &s, &v);
    00473 #else
    00474             color.getHsv(&h, &s, &v);
    00475 #endif
    00476             color = (v > 128) ? gray.dark(120) : gray.light(120);
    00477         }
    00478         else
    00479             color = Qt::darkGray;
    00480
    00481         painter->save();
    00482         painter->setBrush(Qt::NoBrush);
    00483         painter->setPen(QPen(color, 0, Qt::DotLine));
    00484         painter->drawEllipse(focusRect);
    00485         painter->restore();
    00486     }
    00487 }
    00488
    00495 void QwtDial::drawFrame(QPainter *painter)
    00496 {
    00497     const int lw = lineWidth();
    00498     const int off = (lw + 1) % 2;
    00499
    00500     QRect r = boundingRect();
    00501     r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off,
    00502         r.width() - lw + off + 1, r.height() - lw + off + 1);
    00503 #if QT_VERSION >= 0x040000
    00504 #ifdef __GNUC__
    00505 #endif
    00506     r.setX(r.x() + 1);
    00507     r.setY(r.y() + 1);
    00508     r.setWidth(r.width() - 2);
    00509     r.setHeight(r.height() - 2);
    00510 #endif
    00511
    00512     if ( lw > 0 )
    00513     {
    00514         switch(d_data->frameShadow)
    00515         {
    00516             case QwtDial::Raised:
    00517 #if QT_VERSION < 0x040000
    00518                 QwtPainter::drawRoundFrame(painter, r,
    00519                     lw, colorGroup(), false);
    00520 #else
    00521                 QwtPainter::drawRoundFrame(painter, r,
    00522                     lw, palette(), false);
    00523 #endif
    00524                 break;
    00525             case QwtDial::Sunken:
    00526 #if QT_VERSION < 0x040000
    00527                 QwtPainter::drawRoundFrame(painter, r,
    00528                     lw, colorGroup(), true);
    00529 #else
    00530                 QwtPainter::drawRoundFrame(painter, r,
    00531                     lw, palette(), true);
    00532 #endif
    00533                 break;
    00534             default: // Plain
    00535             {
    00536                 painter->save();
    00537                 painter->setPen(QPen(Qt::black, lw));
    00538                 painter->setBrush(Qt::NoBrush);
    00539                 painter->drawEllipse(r);
    00540                 painter->restore();
    00541             }
    00542         }
    00543     }
    00544 }
    00545
    00557 void QwtDial::drawContents(QPainter *painter) const
    00558 {
    00559 #if QT_VERSION < 0x040000
    00560     if ( backgroundMode() == Qt::NoBackground ||
    00561         colorGroup().brush(QColorGroup::Base) !=
    00562             colorGroup().brush(QColorGroup::Background) )
    00563 #else
    00564     if ( testAttribute(Qt::WA_NoSystemBackground) ||
    00565         palette().brush(QPalette::Base) !=
    00566             palette().brush(QPalette::Background) )
    00567 #endif
    00568     {
    00569
    00570         const QRect br = boundingRect();
    00571
    00572         painter->save();
    00573         painter->setPen(Qt::NoPen);
    00574
    00575 #if QT_VERSION < 0x040000
    00576         painter->setBrush(colorGroup().brush(QColorGroup::Base));
    00577 #else
    00578         painter->setBrush(palette().brush(QPalette::Base));
    00579 #endif
    00580
    00581         painter->drawEllipse(br);
    00582         painter->restore();
    00583     }
    00584
    00585
    00586     const QRect insideScaleRect = scaleContentsRect();
    00587 #if QT_VERSION < 0x040000
    00588     if ( colorGroup().brush(QColorGroup::Foreground) !=
    00589         colorGroup().brush(QColorGroup::Base) )
    00590 #else
    00591     if ( palette().brush(QPalette::Foreground) !=
    00592         palette().brush(QPalette::Base) )
    00593 #endif
    00594     {
    00595         painter->save();
    00596         painter->setPen(Qt::NoPen);
    00597
    00598 #if QT_VERSION < 0x040000
    00599         painter->setBrush(colorGroup().brush(QColorGroup::Foreground));
    00600 #else
    00601         painter->setBrush(palette().brush(QPalette::Foreground));
    00602 #endif
    00603
    00604         painter->drawEllipse(insideScaleRect.x() - 1, insideScaleRect.y() - 1,
    00605             insideScaleRect.width(), insideScaleRect.height() );
    00606
    00607         painter->restore();
    00608     }
    00609
    00610     const QPoint center = insideScaleRect.center();
    00611     const int radius = insideScaleRect.width() / 2;
    00612
    00613     painter->save();
    00614     drawScaleContents(painter, center, radius);
    00615     painter->restore();
    00616
    00617     double direction = d_data->origin;
    00618
    00619     if (isValid())
    00620     {
    00621         direction = d_data->origin + d_data->minScaleArc;
    00622         if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc )
    00623         {
    00624             const double ratio =
    00625                 (value() - minValue()) / (maxValue() - minValue());
    00626             direction += ratio * (d_data->maxScaleArc - d_data->minScaleArc);
    00627         }
    00628
    00629         if ( direction >= 360.0 )
    00630             direction -= 360.0;
    00631     }
    00632
    00633     double origin = d_data->origin;
    00634     if ( mode() == RotateScale )
    00635     {
    00636         origin -= direction - d_data->origin;
    00637         direction = d_data->origin;
    00638     }
    00639
    00640     painter->save();
    00641     drawScale(painter, center, radius, origin, d_data->minScaleArc, d_data->maxScaleArc);
    00642     painter->restore();
    00643
    00644     if ( isValid() )
    00645     {
    00646         QPalette::ColorGroup cg;
    00647         if ( isEnabled() )
    00648             cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
    00649         else
    00650             cg = QPalette::Disabled;
    00651
    00652         painter->save();
    00653         drawNeedle(painter, center, radius, direction, cg);
    00654         painter->restore();
    00655     }
    00656 }
    00657
    00667 void QwtDial::drawNeedle(QPainter *painter, const QPoint &center,
    00668     int radius, double direction, QPalette::ColorGroup cg) const
    00669 {
    00670     if ( d_data->needle )
    00671     {
    00672         direction = 360.0 - direction; // counter clockwise
    00673         d_data->needle->draw(painter, center, radius, direction, cg);
    00674     }
    00675 }
    00676
    00689 void QwtDial::drawScale(QPainter *painter, const QPoint &center,
    00690     int radius, double origin, double minArc, double maxArc) const
    00691 {
    00692     if ( d_data->scaleDraw == NULL )
    00693         return;
    00694
    00695     origin -= 270.0; // hardcoded origin of QwtScaleDraw
    00696
    00697     double angle = maxArc - minArc;
    00698     if ( angle > 360.0 )
    00699         angle = fmod(angle, 360.0);
    00700
    00701     minArc += origin;
    00702     if ( minArc < -360.0 )
    00703         minArc = fmod(minArc, 360.0);
    00704
    00705     maxArc = minArc + angle;
    00706     if ( maxArc > 360.0 )
    00707     {
    00708         // QwtAbstractScaleDraw::setAngleRange accepts only values
    00709         // in the range [-360.0..360.0]
    00710         minArc -= 360.0;
    00711         maxArc -= 360.0;
    00712     }
    00713
    00714     painter->setFont(font());
    00715
    00716     d_data->scaleDraw->setAngleRange(minArc, maxArc);
    00717     d_data->scaleDraw->setRadius(radius);
    00718     d_data->scaleDraw->moveCenter(center);
    00719
    00720 #if QT_VERSION < 0x040000
    00721     QColorGroup cg = colorGroup();
    00722
    00723     const QColor textColor = cg.color(QColorGroup::Text);
    00724     cg.setColor(QColorGroup::Foreground, textColor);
    00725     painter->setPen(QPen(textColor, d_data->scaleDraw->penWidth()));
    00726
    00727     d_data->scaleDraw->draw(painter, cg);
    00728 #else
    00729     QPalette pal = palette();
    00730
    00731     const QColor textColor = pal.color(QPalette::Text);
    00732     pal.setColor(QPalette::Foreground, textColor); //ticks, backbone
    00733
    00734     painter->setPen(QPen(textColor, d_data->scaleDraw->penWidth()));
    00735
    00736     d_data->scaleDraw->draw(painter, pal);
    00737 #endif
    00738 }
    00739
    00740 void QwtDial::drawScaleContents(QPainter *,
    00741     const QPoint &, int) const
    00742 {
    00743     // empty default implementation
    00744 }
    00745
    00756 void QwtDial::setNeedle(QwtDialNeedle *needle)
    00757 {
    00758     if ( needle != d_data->needle )
    00759     {
    00760         if ( d_data->needle )
    00761             delete d_data->needle;
    00762
    00763         d_data->needle = needle;
    00764         update();
    00765     }
    00766 }
    00767
    00772 const QwtDialNeedle *QwtDial::needle() const
    00773 {
    00774     return d_data->needle;
    00775 }
    00776
    00781 QwtDialNeedle *QwtDial::needle()
    00782 {
    00783     return d_data->needle;
    00784 }
    00785
    00787 void QwtDial::rangeChange()
    00788 {
    00789     updateScale();
    00790 }
    00791
    00796 void QwtDial::updateScale()
    00797 {
    00798     if ( d_data->scaleDraw )
    00799     {
    00800         QwtLinearScaleEngine scaleEngine;
    00801
    00802         const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
    00803             minValue(), maxValue(),
    00804             d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep);
    00805
    00806         d_data->scaleDraw->setTransformation(scaleEngine.transformation());
    00807         d_data->scaleDraw->setScaleDiv(scaleDiv);
    00808     }
    00809 }
    00810
    00812 QwtDialScaleDraw *QwtDial::scaleDraw()
    00813 {
    00814     return d_data->scaleDraw;
    00815 }
    00816
    00818 const QwtDialScaleDraw *QwtDial::scaleDraw() const
    00819 {
    00820     return d_data->scaleDraw;
    00821 }
    00822
    00829 void QwtDial::setScaleDraw(QwtDialScaleDraw *scaleDraw)
    00830 {
    00831     if ( scaleDraw != d_data->scaleDraw )
    00832     {
    00833         if ( d_data->scaleDraw )
    00834             delete d_data->scaleDraw;
    00835
    00836         d_data->scaleDraw = scaleDraw;
    00837         updateScale();
    00838         update();
    00839     }
    00840 }
    00841
    00846 void QwtDial::setScale(int maxMajIntv, int maxMinIntv, double step)
    00847 {
    00848     d_data->maxMajIntv = maxMajIntv;
    00849     d_data->maxMinIntv = maxMinIntv;
    00850     d_data->scaleStep = step;
    00851
    00852     updateScale();
    00853 }
    00854
    00869 void QwtDial::setScaleOptions(int options)
    00870 {
    00871     if ( options == 0 )
    00872         setScaleDraw(NULL);
    00873
    00874     QwtDialScaleDraw *sd = d_data->scaleDraw;
    00875     if ( sd == NULL )
    00876         return;
    00877
    00878     sd->enableComponent(QwtAbstractScaleDraw::Backbone,
    00879         options & ScaleBackbone);
    00880
    00881     sd->enableComponent(QwtAbstractScaleDraw::Ticks,
    00882         options & ScaleTicks);
    00883
    00884     sd->enableComponent(QwtAbstractScaleDraw::Labels,
    00885         options & ScaleLabel);
    00886 }
    00887
    00889 void QwtDial::setScaleTicks(int minLen, int medLen,
    00890     int majLen, int penWidth)
    00891 {
    00892     QwtDialScaleDraw *sd = d_data->scaleDraw;
    00893     if ( sd )
    00894     {
    00895         sd->setTickLength(QwtScaleDiv::MinorTick, minLen);
    00896         sd->setTickLength(QwtScaleDiv::MediumTick, medLen);
    00897         sd->setTickLength(QwtScaleDiv::MajorTick, majLen);
    00898         sd->setPenWidth(penWidth);
    00899     }
    00900 }
    00901
    00908 QwtText QwtDial::scaleLabel(double value) const
    00909 {
    00910 #if 1
    00911     if ( value == -0 )
    00912         value = 0;
    00913 #endif
    00914
    00915     return QString::number(value);
    00916 }
    00917
    00919 double QwtDial::minScaleArc() const
    00920 {
    00921     return d_data->minScaleArc;
    00922 }
    00923
    00925 double QwtDial::maxScaleArc() const
    00926 {
    00927     return d_data->maxScaleArc;
    00928 }
    00929
    00938 void QwtDial::setOrigin(double origin)
    00939 {
    00940     d_data->origin = origin;
    00941     update();
    00942 }
    00943
    00950 double QwtDial::origin() const
    00951 {
    00952     return d_data->origin;
    00953 }
    00954
    00961 void QwtDial::setScaleArc(double minArc, double maxArc)
    00962 {
    00963     if ( minArc != 360.0 && minArc != -360.0 )
    00964         minArc = fmod(minArc, 360.0);
    00965     if ( maxArc != 360.0 && maxArc != -360.0 )
    00966         maxArc = fmod(maxArc, 360.0);
    00967
    00968     d_data->minScaleArc = qwtMin(minArc, maxArc);
    00969     d_data->maxScaleArc = qwtMax(minArc, maxArc);
    00970     if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
    00971         d_data->maxScaleArc = d_data->minScaleArc + 360.0;
    00972
    00973     update();
    00974 }
    00975
    00977 void QwtDial::valueChange()
    00978 {
    00979     update();
    00980     QwtAbstractSlider::valueChange();
    00981 }
    00982
    00986 QSize QwtDial::sizeHint() const
    00987 {
    00988     int sh = 0;
    00989     if ( d_data->scaleDraw )
    00990         sh = d_data->scaleDraw->extent( QPen(), font() );
    00991
    00992     const int d = 6 * sh + 2 * lineWidth();
    00993
    00994     return QSize( d, d );
    00995 }
    00996
    01002 QSize QwtDial::minimumSizeHint() const
    01003 {
    01004     int sh = 0;
    01005     if ( d_data->scaleDraw )
    01006         sh = d_data->scaleDraw->extent(QPen(), font() );
    01007
    01008     const int d = 3 * sh + 2 * lineWidth();
    01009
    01010     return QSize( d, d );
    01011 }
    01012
    01013 static double line2Radians(const QPoint &p1, const QPoint &p2)
    01014 {
    01015     const QPoint p = p2 - p1;
    01016
    01017     double angle;
    01018     if ( p.x() == 0 )
    01019         angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
    01020     else
    01021     {
    01022         angle = atan(double(-p.y()) / double(p.x()));
    01023         if ( p.x() < 0 )
    01024             angle += M_PI;
    01025         if ( angle < 0.0 )
    01026             angle += 2 * M_PI;
    01027     }
    01028     return 360.0 - angle * 180.0 / M_PI;
    01029 }
    01030
    01037 double QwtDial::getValue(const QPoint &pos)
    01038 {
    01039     if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
    01040         return minValue();
    01041
    01042     double dir = line2Radians(rect().center(), pos) - d_data->origin;
    01043     if ( dir < 0.0 )
    01044         dir += 360.0;
    01045
    01046     if ( mode() == RotateScale )
    01047         dir = 360.0 - dir;
    01048
    01049     // The position might be in the area that is outside the scale arc.
    01050     // We need the range of the scale if it was a complete circle.
    01051
    01052     const double completeCircle = 360.0 / (d_data->maxScaleArc - d_data->minScaleArc)
    01053         * (maxValue() - minValue());
    01054
    01055     double posValue = minValue() + completeCircle * dir / 360.0;
    01056
    01057     if ( scrollMode() == ScrMouse )
    01058     {
    01059         if ( d_data->previousDir >= 0.0 ) // valid direction
    01060         {
    01061             // We have to find out whether the mouse is moving
    01062             // clock or counter clockwise
    01063
    01064             bool clockWise = false;
    01065
    01066             const double angle = dir - d_data->previousDir;
    01067             if ( (angle >= 0.0 && angle <= 180.0) || angle < -180.0 )
    01068                 clockWise = true;
    01069
    01070             if ( clockWise )
    01071             {
    01072                 if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
    01073                 {
    01074                     // We passed 360 -> 0
    01075                     setMouseOffset(mouseOffset() - completeCircle);
    01076                 }
    01077
    01078                 if ( wrapping() )
    01079                 {
    01080                     if ( posValue - mouseOffset() > maxValue() )
    01081                     {
    01082                         // We passed maxValue and the value will be set
    01083                         // to minValue. We have to adjust the mouseOffset.
    01084
    01085                         setMouseOffset(posValue - minValue());
    01086                     }
    01087                 }
    01088                 else
    01089                 {
    01090                     if ( posValue - mouseOffset() > maxValue() ||
    01091                         value() == maxValue() )
    01092                     {
    01093                         // We fix the value at maxValue by adjusting
    01094                         // the mouse offset.
    01095
    01096                         setMouseOffset(posValue - maxValue());
    01097                     }
    01098                 }
    01099             }
    01100             else
    01101             {
    01102                 if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
    01103                 {
    01104                     // We passed 0 -> 360
    01105                     setMouseOffset(mouseOffset() + completeCircle);
    01106                 }
    01107
    01108                 if ( wrapping() )
    01109                 {
    01110                     if ( posValue - mouseOffset() < minValue() )
    01111                     {
    01112                         // We passed minValue and the value will be set
    01113                         // to maxValue. We have to adjust the mouseOffset.
    01114
    01115                         setMouseOffset(posValue - maxValue());
    01116                     }
    01117                 }
    01118                 else
    01119                 {
    01120                     if ( posValue - mouseOffset() < minValue() ||
    01121                         value() == minValue() )
    01122                     {
    01123                         // We fix the value at minValue by adjusting
    01124                         // the mouse offset.
    01125
    01126                         setMouseOffset(posValue - minValue());
    01127                     }
    01128                 }
    01129             }
    01130         }
    01131         d_data->previousDir = dir;
    01132     }
    01133
    01134     return posValue;
    01135 }
    01136
    01140 void QwtDial::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
    01141 {
    01142     direction = 0;
    01143     scrollMode = ScrNone;
    01144
    01145     const QRegion region(contentsRect(), QRegion::Ellipse);
    01146     if ( region.contains(p) && p != rect().center() )
    01147     {
    01148         scrollMode = ScrMouse;
    01149         d_data->previousDir = -1.0;
    01150     }
    01151 }
    01152
    01172 void QwtDial::keyPressEvent(QKeyEvent *e)
    01173 {
    01174     if ( isReadOnly() )
    01175     {
    01176         e->ignore();
    01177         return;
    01178     }
    01179
    01180     if ( !isValid() )
    01181         return;
    01182
    01183     double previous = prevValue();
    01184     switch ( e->key() )
    01185     {
    01186         case Qt::Key_Down:
    01187         case Qt::Key_Left:
    01188             QwtDoubleRange::incValue(-1);
    01189             break;
    01190 #if QT_VERSION < 0x040000
    01191         case Qt::Key_Prior:
    01192 #else
    01193         case Qt::Key_PageUp:
    01194 #endif
    01195             QwtDoubleRange::incValue(-pageSize());
    01196             break;
    01197         case Qt::Key_Home:
    01198             setValue(minValue());
    01199             break;
    01200
    01201         case Qt::Key_Up:
    01202         case Qt::Key_Right:
    01203             QwtDoubleRange::incValue(1);
    01204             break;
    01205 #if QT_VERSION < 0x040000
    01206         case Qt::Key_Next:
    01207 #else
    01208         case Qt::Key_PageDown:
    01209 #endif
    01210             QwtDoubleRange::incValue(pageSize());
    01211             break;
    01212         case Qt::Key_End:
    01213             setValue(maxValue());
    01214             break;
    01215         default:;
    01216             e->ignore();
    01217     }
    01218
    01219     if (value() != previous)
    01220         emit sliderMoved(value());
    01221 }
    01222
    01231 void QwtDial::updateMask()
    01232 {
    01233     if ( d_data->visibleBackground )
    01234         clearMask();
    01235     else
    01236         setMask(QRegion(boundingRect(), QRegion::Ellipse));
    01237 }