# 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 <qpaintengine.h>
    00014 #include <qbitmap.h>
    00015 #include <qpalette.h>
    00016 #endif
    00017 #include <qpixmap.h>
    00018 #include <qevent.h>
    00019 #include "qwt_math.h"
    00020 #include "qwt_scale_engine.h"
    00021 #include "qwt_scale_map.h"
    00022 #include "qwt_paint_buffer.h"
    00023 #include "qwt_painter.h"
    00024 #include "qwt_dial_needle.h"
    00025 #include "qwt_dial.h"
    00026
    00027 #if QT_VERSION >= 0x040000
    00028 static void setAntialiasing(QPainter *painter, bool on)
    00029 {
    00030     QPaintEngine *engine = painter->paintEngine();
    00031     if ( engine && engine->hasFeature(QPaintEngine::Antialiasing) )
    00032         painter->setRenderHint(QPainter::Antialiasing, on);
    00033 }
    00034 #else
    00035 static void setAntialiasing(QPainter *, bool)
    00036 {
    00037 }
    00038 #endif
    00039
    00040 class QwtDial::PrivateData
    00041 {
    00042 public:
    00043     PrivateData():
    00044         visibleBackground(true),
    00045         frameShadow(Sunken),
    00046         lineWidth(0),
    00047         mode(RotateNeedle),
    00048         origin(90.0),
    00049         minScaleArc(0.0),
    00050         maxScaleArc(0.0),
    00051         scaleDraw(0),
    00052         maxMajIntv(36),
    00053         maxMinIntv(10),
    00054         scaleStep(0.0),
    00055         needle(0)
    00056     {
    00057     }
    00058
    00059     ~PrivateData()
    00060     {
    00061         delete scaleDraw;
    00062         delete needle;
    00063     }
    00064     bool visibleBackground;
    00065     Shadow frameShadow;
    00066     int lineWidth;
    00067
    00068     QwtDial::Mode mode;
    00069
    00070     double origin;
    00071     double minScaleArc;
    00072     double maxScaleArc;
    00073
    00074     QwtDialScaleDraw *scaleDraw;
    00075     int maxMajIntv;
    00076     int maxMinIntv;
    00077     double scaleStep;
    00078
    00079     QwtDialNeedle *needle;
    00080
    00081     static double previousDir;
    00082 };
    00083
    00084 double QwtDial::PrivateData::previousDir = -1.0;
    00085
    00091 QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent):
    00092     d_parent(parent),
    00093     d_penWidth(1)
    00094 {
    00095 }
    00096
    00104 void QwtDialScaleDraw::setPenWidth(uint penWidth)
    00105 {
    00106     d_penWidth = penWidth;
    00107 }
    00108
    00113 uint QwtDialScaleDraw::penWidth() const
    00114 {
    00115     return d_penWidth;
    00116 }
    00117
    00125 QwtText QwtDialScaleDraw::label(double value) const
    00126 {
    00127     if ( d_parent == NULL )
    00128         return QwtRoundScaleDraw::label(value);
    00129
    00130     return d_parent->scaleLabel(value);
    00131 }
    00132
    00143 QwtDial::QwtDial(QWidget* parent):
    00144     QwtAbstractSlider(Qt::Horizontal, parent)
    00145 {
    00146     initDial();
    00147 }
    00148
    00149 #if QT_VERSION < 0x040000
    00150
    00160 QwtDial::QwtDial(QWidget* parent, const char *name):
    00161     QwtAbstractSlider(Qt::Horizontal, parent)
    00162 {
    00163     setName(name);
    00164     initDial();
    00165 }
    00166 #endif
    00167
    00168 void QwtDial::initDial()
    00169 {
    00170     d_data = new PrivateData;
    00171
    00172 #if QT_VERSION < 0x040000
    00173     setWFlags(Qt::WNoAutoErase);
    00174 #endif
    00175
    00176 #if QT_VERSION >= 0x040000
    00177     using namespace Qt;
    00178 #endif
    00179     setFocusPolicy(TabFocus);
    00180
    00181     QPalette p = palette();
    00182     for ( int i = 0; i < QPalette::NColorGroups; i++ )
    00183     {
    00184         const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
    00185
    00186         // Base: background color of the circle inside the frame.
    00187         // Foreground: background color of the circle inside the scale
    00188
    00189 #if QT_VERSION < 0x040000
    00190         p.setColor(cg, QColorGroup::Foreground,
    00191             p.color(cg, QColorGroup::Base));
    00192 #else
    00193         p.setColor(cg, QPalette::Foreground,
    00194             p.color(cg, QPalette::Base));
    00195 #endif
    00196     }
    00197     setPalette(p);
    00198
    00199     d_data->scaleDraw = new QwtDialScaleDraw(this);
    00200     d_data->scaleDraw->setRadius(0);
    00201
    00202     setScaleArc(0.0, 360.0); // scale as a full circle
    00203     setRange(0.0, 360.0, 1.0, 10); // degrees as deafult
    00204 }
    00205
    00207 QwtDial::~QwtDial()
    00208 {
    00209     delete d_data;
    00210 }
    00211
    00220 void QwtDial::showBackground(bool show)
    00221 {
    00222     if ( d_data->visibleBackground != show )
    00223     {
    00224         d_data->visibleBackground = show;
    00225         updateMask();
    00226     }
    00227 }
    00228
    00234 bool QwtDial::hasVisibleBackground() const
    00235 {
    00236     return d_data->visibleBackground;
    00237 }
    00238
    00244 void QwtDial::setFrameShadow(Shadow shadow)
    00245 {
    00246     if ( shadow != d_data->frameShadow )
    00247     {
    00248         d_data->frameShadow = shadow;
    00249         if ( lineWidth() > 0 )
    00250             update();
    00251     }
    00252 }
    00253
    00258 QwtDial::Shadow QwtDial::frameShadow() const
    00259 {
    00260     return d_data->frameShadow;
    00261 }
    00262
    00269 void QwtDial::setLineWidth(int lineWidth)
    00270 {
    00271     if ( lineWidth < 0 )
    00272         lineWidth = 0;
    00273
    00274     if ( d_data->lineWidth != lineWidth )
    00275     {
    00276         d_data->lineWidth = lineWidth;
    00277         update();
    00278     }
    00279 }
    00280
    00285 int QwtDial::lineWidth() const
    00286 {
    00287     return d_data->lineWidth;
    00288 }
    00289
    00294 QRect QwtDial::contentsRect() const
    00295 {
    00296     const int lw = lineWidth();
    00297
    00298     QRect r = boundingRect();
    00299     if ( lw > 0 )
    00300     {
    00301         r.setRect(r.x() + lw, r.y() + lw,
    00302             r.width() - 2 * lw, r.height() - 2 * lw);
    00303     }
    00304     return r;
    00305 }
    00306
    00311 QRect QwtDial::boundingRect() const
    00312 {
    00313     const int radius = qwtMin(width(), height()) / 2;
    00314
    00315     QRect r(0, 0, 2 * radius, 2 * radius);
    00316     r.moveCenter(rect().center());
    00317     return r;
    00318 }
    00319
    00324 QRect QwtDial::scaleContentsRect() const
    00325 {
    00326 #if QT_VERSION < 0x040000
    00327     const QPen scalePen(colorGroup().text(), 0, Qt::NoPen);
    00328 #else
    00329     const QPen scalePen(palette().text(), 0, Qt::NoPen);
    00330 #endif
    00331
    00332     int scaleDist = 0;
    00333     if ( d_data->scaleDraw )
    00334     {
    00335         scaleDist = d_data->scaleDraw->extent(scalePen, font());
    00336         scaleDist++; // margin
    00337     }
    00338
    00339     const QRect rect = contentsRect();
    00340     return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
    00341         rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
    00342 }
    00343
    00359 void QwtDial::setMode(Mode mode)
    00360 {
    00361     if ( mode != d_data->mode )
    00362     {
    00363         d_data->mode = mode;
    00364         update();
    00365     }
    00366 }
    00367
    00382 QwtDial::Mode QwtDial::mode() const
    00383 {
    00384     return d_data->mode;
    00385 }
    00386
    00397 void QwtDial::setWrapping(bool wrapping)
    00398 {
    00399     setPeriodic(wrapping);
    00400 }
    00401
    00410 bool QwtDial::wrapping() const
    00411 {
    00412     return periodic();
    00413 }
    00414
    00419 void QwtDial::resizeEvent(QResizeEvent *e)
    00420 {
    00421     QWidget::resizeEvent(e);
    00422
    00423     if ( !hasVisibleBackground() )
    00424         updateMask();
    00425 }
    00426
    00431 void QwtDial::paintEvent(QPaintEvent *e)
    00432 {
    00433     const QRect &ur = e->rect();
    00434     if ( ur.isValid() )
    00435     {
    00436 #if QT_VERSION < 0x040000
    00437         QwtPaintBuffer paintBuffer(this, ur);
    00438         QPainter &painter = *paintBuffer.painter();
    00439 #else
    00440         QPainter painter(this);
    00441 #endif
    00442
    00443         setAntialiasing(&painter, true);
    00444
    00445         painter.save();
    00446         drawContents(&painter);
    00447         painter.restore();
    00448
    00449         painter.save();
    00450         drawFrame(&painter);
    00451         painter.restore();
    00452
    00453         if ( hasFocus() )
    00454             drawFocusIndicator(&painter);
    00455     }
    00456 }
    00457
    00463 void QwtDial::drawFocusIndicator(QPainter *painter) const
    00464 {
    00465     if ( !isReadOnly() )
    00466     {
    00467         QRect focusRect = contentsRect();
    00468
    00469         const int margin = 2;
    00470         focusRect.setRect(
    00471             focusRect.x() + margin,
    00472             focusRect.y() + margin,
    00473             focusRect.width() - 2 * margin,
    00474             focusRect.height() - 2 * margin);
    00475
    00476 #if QT_VERSION < 0x040000
    00477         QColor color = colorGroup().color(QColorGroup::Base);
    00478 #else
    00479         QColor color = palette().color(QPalette::Base);
    00480 #endif
    00481         if (color.isValid())
    00482         {
    00483             const QColor gray(Qt::gray);
    00484
    00485             int h, s, v;
    00486 #if QT_VERSION < 0x040000
    00487             color.hsv(&h, &s, &v);
    00488 #else
    00489             color.getHsv(&h, &s, &v);
    00490 #endif
    00491             color = (v > 128) ? gray.dark(120) : gray.light(120);
    00492         }
    00493         else
    00494             color = Qt::darkGray;
    00495
    00496         painter->save();
    00497         painter->setBrush(Qt::NoBrush);
    00498         painter->setPen(QPen(color, 0, Qt::DotLine));
    00499         painter->drawEllipse(focusRect);
    00500         painter->restore();
    00501     }
    00502 }
    00503
    00510 void QwtDial::drawFrame(QPainter *painter)
    00511 {
    00512     const int lw = lineWidth();
    00513     const int off = (lw + 1) % 2;
    00514
    00515     QRect r = boundingRect();
    00516     r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off,
    00517         r.width() - lw + off + 1, r.height() - lw + off + 1);
    00518 #if QT_VERSION >= 0x040000
    00519 #ifdef __GNUC__
    00520 #endif
    00521     r.setX(r.x() + 1);
    00522     r.setY(r.y() + 1);
    00523     r.setWidth(r.width() - 2);
    00524     r.setHeight(r.height() - 2);
    00525 #endif
    00526
    00527     if ( lw > 0 )
    00528     {
    00529         switch(d_data->frameShadow)
    00530         {
    00531             case QwtDial::Raised:
    00532 #if QT_VERSION < 0x040000
    00533                 QwtPainter::drawRoundFrame(painter, r,
    00534                     lw, colorGroup(), false);
    00535 #else
    00536                 QwtPainter::drawRoundFrame(painter, r,
    00537                     lw, palette(), false);
    00538 #endif
    00539                 break;
    00540             case QwtDial::Sunken:
    00541 #if QT_VERSION < 0x040000
    00542                 QwtPainter::drawRoundFrame(painter, r,
    00543                     lw, colorGroup(), true);
    00544 #else
    00545                 QwtPainter::drawRoundFrame(painter, r,
    00546                     lw, palette(), true);
    00547 #endif
    00548                 break;
    00549             default: // Plain
    00550             {
    00551                 painter->save();
    00552                 painter->setPen(QPen(Qt::black, lw));
    00553                 painter->setBrush(Qt::NoBrush);
    00554                 painter->drawEllipse(r);
    00555                 painter->restore();
    00556             }
    00557         }
    00558     }
    00559 }
    00560
    00572 void QwtDial::drawContents(QPainter *painter) const
    00573 {
    00574 #if QT_VERSION < 0x040000
    00575     if ( backgroundMode() == Qt::NoBackground ||
    00576         colorGroup().brush(QColorGroup::Base) !=
    00577             colorGroup().brush(QColorGroup::Background) )
    00578 #else
    00579     if ( testAttribute(Qt::WA_NoSystemBackground) ||
    00580         palette().brush(QPalette::Base) !=
    00581             palette().brush(QPalette::Background) )
    00582 #endif
    00583     {
    00584
    00585         const QRect br = boundingRect();
    00586
    00587         painter->save();
    00588         painter->setPen(Qt::NoPen);
    00589
    00590 #if QT_VERSION < 0x040000
    00591         painter->setBrush(colorGroup().brush(QColorGroup::Base));
    00592 #else
    00593         painter->setBrush(palette().brush(QPalette::Base));
    00594 #endif
    00595
    00596         painter->drawEllipse(br);
    00597         painter->restore();
    00598     }
    00599
    00600
    00601     const QRect insideScaleRect = scaleContentsRect();
    00602 #if QT_VERSION < 0x040000
    00603     if ( colorGroup().brush(QColorGroup::Foreground) !=
    00604         colorGroup().brush(QColorGroup::Base) )
    00605 #else
    00606     if ( palette().brush(QPalette::Foreground) !=
    00607         palette().brush(QPalette::Base) )
    00608 #endif
    00609     {
    00610         painter->save();
    00611         painter->setPen(Qt::NoPen);
    00612
    00613 #if QT_VERSION < 0x040000
    00614         painter->setBrush(colorGroup().brush(QColorGroup::Foreground));
    00615 #else
    00616         painter->setBrush(palette().brush(QPalette::Foreground));
    00617 #endif
    00618
    00619         painter->drawEllipse(insideScaleRect.x() - 1, insideScaleRect.y() - 1,
    00620             insideScaleRect.width(), insideScaleRect.height() );
    00621
    00622         painter->restore();
    00623     }
    00624
    00625     const QPoint center = insideScaleRect.center();
    00626     const int radius = insideScaleRect.width() / 2;
    00627
    00628     painter->save();
    00629     drawScaleContents(painter, center, radius);
    00630     painter->restore();
    00631
    00632     double direction = d_data->origin;
    00633
    00634     if (isValid())
    00635     {
    00636         direction = d_data->origin + d_data->minScaleArc;
    00637         if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc )
    00638         {
    00639             const double ratio =
    00640                 (value() - minValue()) / (maxValue() - minValue());
    00641             direction += ratio * (d_data->maxScaleArc - d_data->minScaleArc);
    00642         }
    00643
    00644         if ( direction >= 360.0 )
    00645             direction -= 360.0;
    00646     }
    00647
    00648     double origin = d_data->origin;
    00649     if ( mode() == RotateScale )
    00650     {
    00651         origin -= direction - d_data->origin;
    00652         direction = d_data->origin;
    00653     }
    00654
    00655     painter->save();
    00656     drawScale(painter, center, radius, origin, d_data->minScaleArc, d_data->maxScaleArc);
    00657     painter->restore();
    00658
    00659     if ( isValid() )
    00660     {
    00661         QPalette::ColorGroup cg;
    00662         if ( isEnabled() )
    00663             cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
    00664         else
    00665             cg = QPalette::Disabled;
    00666
    00667         painter->save();
    00668         drawNeedle(painter, center, radius, direction, cg);
    00669         painter->restore();
    00670     }
    00671 }
    00672
    00682 void QwtDial::drawNeedle(QPainter *painter, const QPoint &center,
    00683     int radius, double direction, QPalette::ColorGroup cg) const
    00684 {
    00685     if ( d_data->needle )
    00686     {
    00687         direction = 360.0 - direction; // counter clockwise
    00688         d_data->needle->draw(painter, center, radius, direction, cg);
    00689     }
    00690 }
    00691
    00704 void QwtDial::drawScale(QPainter *painter, const QPoint &center,
    00705     int radius, double origin, double minArc, double maxArc) const
    00706 {
    00707     if ( d_data->scaleDraw == NULL )
    00708         return;
    00709
    00710     origin -= 270.0; // hardcoded origin of QwtScaleDraw
    00711
    00712     double angle = maxArc - minArc;
    00713     if ( angle > 360.0 )
    00714         angle = fmod(angle, 360.0);
    00715
    00716     minArc += origin;
    00717     if ( minArc < -360.0 )
    00718         minArc = fmod(minArc, 360.0);
    00719
    00720     maxArc = minArc + angle;
    00721     if ( maxArc > 360.0 )
    00722     {
    00723         // QwtAbstractScaleDraw::setAngleRange accepts only values
    00724         // in the range [-360.0..360.0]
    00725         minArc -= 360.0;
    00726         maxArc -= 360.0;
    00727     }
    00728
    00729     painter->setFont(font());
    00730
    00731     d_data->scaleDraw->setAngleRange(minArc, maxArc);
    00732     d_data->scaleDraw->setRadius(radius);
    00733     d_data->scaleDraw->moveCenter(center);
    00734
    00735 #if QT_VERSION < 0x040000
    00736     QColorGroup cg = colorGroup();
    00737
    00738     const QColor textColor = cg.color(QColorGroup::Text);
    00739     cg.setColor(QColorGroup::Foreground, textColor);
    00740     painter->setPen(QPen(textColor, d_data->scaleDraw->penWidth()));
    00741
    00742     d_data->scaleDraw->draw(painter, cg);
    00743 #else
    00744     QPalette pal = palette();
    00745
    00746     const QColor textColor = pal.color(QPalette::Text);
    00747     pal.setColor(QPalette::Foreground, textColor); //ticks, backbone
    00748
    00749     painter->setPen(QPen(textColor, d_data->scaleDraw->penWidth()));
    00750
    00751     d_data->scaleDraw->draw(painter, pal);
    00752 #endif
    00753 }
    00754
    00755 void QwtDial::drawScaleContents(QPainter *,
    00756     const QPoint &, int) const
    00757 {
    00758     // empty default implementation
    00759 }
    00760
    00771 void QwtDial::setNeedle(QwtDialNeedle *needle)
    00772 {
    00773     if ( needle != d_data->needle )
    00774     {
    00775         if ( d_data->needle )
    00776             delete d_data->needle;
    00777
    00778         d_data->needle = needle;
    00779         update();
    00780     }
    00781 }
    00782
    00787 const QwtDialNeedle *QwtDial::needle() const
    00788 {
    00789     return d_data->needle;
    00790 }
    00791
    00796 QwtDialNeedle *QwtDial::needle()
    00797 {
    00798     return d_data->needle;
    00799 }
    00800
    00802 void QwtDial::rangeChange()
    00803 {
    00804     updateScale();
    00805 }
    00806
    00811 void QwtDial::updateScale()
    00812 {
    00813     if ( d_data->scaleDraw )
    00814     {
    00815         QwtLinearScaleEngine scaleEngine;
    00816
    00817         const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
    00818             minValue(), maxValue(),
    00819             d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep);
    00820
    00821         d_data->scaleDraw->setTransformation(scaleEngine.transformation());
    00822         d_data->scaleDraw->setScaleDiv(scaleDiv);
    00823     }
    00824 }
    00825
    00827 QwtDialScaleDraw *QwtDial::scaleDraw()
    00828 {
    00829     return d_data->scaleDraw;
    00830 }
    00831
    00833 const QwtDialScaleDraw *QwtDial::scaleDraw() const
    00834 {
    00835     return d_data->scaleDraw;
    00836 }
    00837
    00844 void QwtDial::setScaleDraw(QwtDialScaleDraw *scaleDraw)
    00845 {
    00846     if ( scaleDraw != d_data->scaleDraw )
    00847     {
    00848         if ( d_data->scaleDraw )
    00849             delete d_data->scaleDraw;
    00850
    00851         d_data->scaleDraw = scaleDraw;
    00852         updateScale();
    00853         update();
    00854     }
    00855 }
    00856
    00861 void QwtDial::setScale(int maxMajIntv, int maxMinIntv, double step)
    00862 {
    00863     d_data->maxMajIntv = maxMajIntv;
    00864     d_data->maxMinIntv = maxMinIntv;
    00865     d_data->scaleStep = step;
    00866
    00867     updateScale();
    00868 }
    00869
    00884 void QwtDial::setScaleOptions(int options)
    00885 {
    00886     if ( options == 0 )
    00887         setScaleDraw(NULL);
    00888
    00889     QwtDialScaleDraw *sd = d_data->scaleDraw;
    00890     if ( sd == NULL )
    00891         return;
    00892
    00893     sd->enableComponent(QwtAbstractScaleDraw::Backbone,
    00894         options & ScaleBackbone);
    00895
    00896     sd->enableComponent(QwtAbstractScaleDraw::Ticks,
    00897         options & ScaleTicks);
    00898
    00899     sd->enableComponent(QwtAbstractScaleDraw::Labels,
    00900         options & ScaleLabel);
    00901 }
    00902
    00904 void QwtDial::setScaleTicks(int minLen, int medLen,
    00905     int majLen, int penWidth)
    00906 {
    00907     QwtDialScaleDraw *sd = d_data->scaleDraw;
    00908     if ( sd )
    00909     {
    00910         sd->setTickLength(QwtScaleDiv::MinorTick, minLen);
    00911         sd->setTickLength(QwtScaleDiv::MediumTick, medLen);
    00912         sd->setTickLength(QwtScaleDiv::MajorTick, majLen);
    00913         sd->setPenWidth(penWidth);
    00914     }
    00915 }
    00916
    00923 QwtText QwtDial::scaleLabel(double value) const
    00924 {
    00925 #if 1
    00926     if ( value == -0 )
    00927         value = 0;
    00928 #endif
    00929
    00930     return QString::number(value);
    00931 }
    00932
    00934 double QwtDial::minScaleArc() const
    00935 {
    00936     return d_data->minScaleArc;
    00937 }
    00938
    00940 double QwtDial::maxScaleArc() const
    00941 {
    00942     return d_data->maxScaleArc;
    00943 }
    00944
    00953 void QwtDial::setOrigin(double origin)
    00954 {
    00955     d_data->origin = origin;
    00956     update();
    00957 }
    00958
    00965 double QwtDial::origin() const
    00966 {
    00967     return d_data->origin;
    00968 }
    00969
    00976 void QwtDial::setScaleArc(double minArc, double maxArc)
    00977 {
    00978     if ( minArc != 360.0 && minArc != -360.0 )
    00979         minArc = fmod(minArc, 360.0);
    00980     if ( maxArc != 360.0 && maxArc != -360.0 )
    00981         maxArc = fmod(maxArc, 360.0);
    00982
    00983     d_data->minScaleArc = qwtMin(minArc, maxArc);
    00984     d_data->maxScaleArc = qwtMax(minArc, maxArc);
    00985     if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
    00986         d_data->maxScaleArc = d_data->minScaleArc + 360.0;
    00987
    00988     update();
    00989 }
    00990
    00992 void QwtDial::valueChange()
    00993 {
    00994     update();
    00995     QwtAbstractSlider::valueChange();
    00996 }
    00997
    01001 QSize QwtDial::sizeHint() const
    01002 {
    01003     int sh = 0;
    01004     if ( d_data->scaleDraw )
    01005         sh = d_data->scaleDraw->extent( QPen(), font() );
    01006
    01007     const int d = 6 * sh + 2 * lineWidth();
    01008
    01009     return QSize( d, d );
    01010 }
    01011
    01017 QSize QwtDial::minimumSizeHint() const
    01018 {
    01019     int sh = 0;
    01020     if ( d_data->scaleDraw )
    01021         sh = d_data->scaleDraw->extent(QPen(), font() );
    01022
    01023     const int d = 3 * sh + 2 * lineWidth();
    01024
    01025     return QSize( d, d );
    01026 }
    01027
    01028 static double line2Radians(const QPoint &p1, const QPoint &p2)
    01029 {
    01030     const QPoint p = p2 - p1;
    01031
    01032     double angle;
    01033     if ( p.x() == 0 )
    01034         angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
    01035     else
    01036     {
    01037         angle = atan(double(-p.y()) / double(p.x()));
    01038         if ( p.x() < 0 )
    01039             angle += M_PI;
    01040         if ( angle < 0.0 )
    01041             angle += 2 * M_PI;
    01042     }
    01043     return 360.0 - angle * 180.0 / M_PI;
    01044 }
    01045
    01052 double QwtDial::getValue(const QPoint &pos)
    01053 {
    01054     if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
    01055         return minValue();
    01056
    01057     double dir = line2Radians(rect().center(), pos) - d_data->origin;
    01058     if ( dir < 0.0 )
    01059         dir += 360.0;
    01060
    01061     if ( mode() == RotateScale )
    01062         dir = 360.0 - dir;
    01063
    01064     // The position might be in the area that is outside the scale arc.
    01065     // We need the range of the scale if it was a complete circle.
    01066
    01067     const double completeCircle = 360.0 / (d_data->maxScaleArc - d_data->minScaleArc)
    01068         * (maxValue() - minValue());
    01069
    01070     double posValue = minValue() + completeCircle * dir / 360.0;
    01071
    01072     if ( scrollMode() == ScrMouse )
    01073     {
    01074         if ( d_data->previousDir >= 0.0 ) // valid direction
    01075         {
    01076             // We have to find out whether the mouse is moving
    01077             // clock or counter clockwise
    01078
    01079             bool clockWise = false;
    01080
    01081             const double angle = dir - d_data->previousDir;
    01082             if ( (angle >= 0.0 && angle <= 180.0) || angle < -180.0 )
    01083                 clockWise = true;
    01084
    01085             if ( clockWise )
    01086             {
    01087                 if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
    01088                 {
    01089                     // We passed 360 -> 0
    01090                     setMouseOffset(mouseOffset() - completeCircle);
    01091                 }
    01092
    01093                 if ( wrapping() )
    01094                 {
    01095                     if ( posValue - mouseOffset() > maxValue() )
    01096                     {
    01097                         // We passed maxValue and the value will be set
    01098                         // to minValue. We have to adjust the mouseOffset.
    01099
    01100                         setMouseOffset(posValue - minValue());
    01101                     }
    01102                 }
    01103                 else
    01104                 {
    01105                     if ( posValue - mouseOffset() > maxValue() ||
    01106                         value() == maxValue() )
    01107                     {
    01108                         // We fix the value at maxValue by adjusting
    01109                         // the mouse offset.
    01110
    01111                         setMouseOffset(posValue - maxValue());
    01112                     }
    01113                 }
    01114             }
    01115             else
    01116             {
    01117                 if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
    01118                 {
    01119                     // We passed 0 -> 360
    01120                     setMouseOffset(mouseOffset() + completeCircle);
    01121                 }
    01122
    01123                 if ( wrapping() )
    01124                 {
    01125                     if ( posValue - mouseOffset() < minValue() )
    01126                     {
    01127                         // We passed minValue and the value will be set
    01128                         // to maxValue. We have to adjust the mouseOffset.
    01129
    01130                         setMouseOffset(posValue - maxValue());
    01131                     }
    01132                 }
    01133                 else
    01134                 {
    01135                     if ( posValue - mouseOffset() < minValue() ||
    01136                         value() == minValue() )
    01137                     {
    01138                         // We fix the value at minValue by adjusting
    01139                         // the mouse offset.
    01140
    01141                         setMouseOffset(posValue - minValue());
    01142                     }
    01143                 }
    01144             }
    01145         }
    01146         d_data->previousDir = dir;
    01147     }
    01148
    01149     return posValue;
    01150 }
    01151
    01155 void QwtDial::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
    01156 {
    01157     direction = 0;
    01158     scrollMode = ScrNone;
    01159
    01160     const QRegion region(contentsRect(), QRegion::Ellipse);
    01161     if ( region.contains(p) && p != rect().center() )
    01162     {
    01163         scrollMode = ScrMouse;
    01164         d_data->previousDir = -1.0;
    01165     }
    01166 }
    01167
    01187 void QwtDial::keyPressEvent(QKeyEvent *e)
    01188 {
    01189     if ( isReadOnly() )
    01190     {
    01191         e->ignore();
    01192         return;
    01193     }
    01194
    01195     if ( !isValid() )
    01196         return;
    01197
    01198     double previous = prevValue();
    01199     switch ( e->key() )
    01200     {
    01201         case Qt::Key_Down:
    01202         case Qt::Key_Left:
    01203             QwtDoubleRange::incValue(-1);
    01204             break;
    01205 #if QT_VERSION < 0x040000
    01206         case Qt::Key_Prior:
    01207 #else
    01208         case Qt::Key_PageUp:
    01209 #endif
    01210             QwtDoubleRange::incValue(-pageSize());
    01211             break;
    01212         case Qt::Key_Home:
    01213             setValue(minValue());
    01214             break;
    01215
    01216         case Qt::Key_Up:
    01217         case Qt::Key_Right:
    01218             QwtDoubleRange::incValue(1);
    01219             break;
    01220 #if QT_VERSION < 0x040000
    01221         case Qt::Key_Next:
    01222 #else
    01223         case Qt::Key_PageDown:
    01224 #endif
    01225             QwtDoubleRange::incValue(pageSize());
    01226             break;
    01227         case Qt::Key_End:
    01228             setValue(maxValue());
    01229             break;
    01230         default:;
    01231             e->ignore();
    01232     }
    01233
    01234     if (value() != previous)
    01235         emit sliderMoved(value());
    01236 }
    01237
    01246 void QwtDial::updateMask()
    01247 {
    01248     if ( d_data->visibleBackground )
    01249         clearMask();
    01250     else
    01251         setMask(QRegion(boundingRect(), QRegion::Ellipse));
    01252 }