Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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_paint_buffer.h"
00022 #include "qwt_painter.h"
00023 #include "qwt_dial_needle.h"
00024 #include "qwt_dial.h"
00025 
00026 static void setAntialiasing(QPainter *painter, bool on)
00027 {
00028 #if QT_VERSION >= 0x040000
00029     QPaintEngine *engine = painter->paintEngine();
00030     if ( engine && engine->hasFeature(QPaintEngine::Antialiasing) )
00031         painter->setRenderHint(QPainter::Antialiasing, on);
00032 #endif
00033 }
00034 
00035 class QwtDial::PrivateData
00036 {
00037 public:
00038     PrivateData():
00039         visibleBackground(true),
00040         frameShadow(Sunken),
00041         lineWidth(0),
00042         mode(RotateNeedle),
00043         origin(90.0),
00044         minScaleArc(0.0),
00045         maxScaleArc(0.0),
00046         scaleDraw(0),
00047         maxMajIntv(36),
00048         maxMinIntv(10),
00049         scaleStep(0.0),
00050         needle(0)
00051     {
00052     }
00053 
00054     ~PrivateData()
00055     {
00056         delete scaleDraw;
00057         delete needle;
00058     }
00059     bool visibleBackground;
00060     Shadow frameShadow;
00061     int lineWidth;
00062 
00063     QwtDial::Mode mode;
00064 
00065     double origin;
00066     double minScaleArc;
00067     double maxScaleArc;
00068 
00069     QwtDialScaleDraw *scaleDraw;
00070     int maxMajIntv;
00071     int maxMinIntv;
00072     double scaleStep;
00073 
00074     QwtDialNeedle *needle;
00075 
00076     static double previousDir;
00077 };
00078 
00079 double QwtDial::PrivateData::previousDir = -1.0;
00080 
00086 QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent):
00087     d_parent(parent),
00088     d_penWidth(1),
00089     d_visibleLabels(true)
00090 {
00091 }
00092 
00102 void QwtDialScaleDraw::showLabels(bool enable)
00103 {
00104     d_visibleLabels = enable;
00105 }
00106 
00111 bool QwtDialScaleDraw::visibleLabels() const
00112 {
00113     return d_visibleLabels;
00114 }
00115 
00123 void QwtDialScaleDraw::setPenWidth(uint penWidth)
00124 {
00125     d_penWidth = penWidth;
00126 }
00127 
00132 uint QwtDialScaleDraw::penWidth() const
00133 {
00134     return d_penWidth;
00135 }
00136 
00144 QString QwtDialScaleDraw::label(double value) const
00145 {
00146     if ( !d_visibleLabels )
00147         return QString::null;
00148 
00149     if ( d_parent == NULL )
00150         return QwtScaleDraw::label(value);
00151 
00152     return d_parent->scaleLabel(value);
00153 }
00154 
00165 QwtDial::QwtDial(QWidget* parent):
00166     QwtAbstractSlider(Qt::Horizontal, parent)
00167 {
00168     d_data = new PrivateData;
00169 
00170 #if QT_VERSION < 0x040000
00171     setWFlags(Qt::WNoAutoErase);
00172 #endif 
00173 
00174 #if QT_VERSION >= 0x040000
00175     using namespace Qt;
00176 #endif
00177     setFocusPolicy(TabFocus);
00178 
00179     QPalette p = palette();
00180     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00181     {
00182         const QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
00183 
00184         // Base: background color of the circle inside the frame.
00185         // Foreground: background color of the circle inside the scale
00186 
00187 #if QT_VERSION < 0x040000
00188         p.setColor(cg, QColorGroup::Foreground, 
00189             p.color(cg, QColorGroup::Base));
00190 #else
00191         p.setColor(cg, QPalette::Foreground, 
00192             p.color(cg, QPalette::Base));
00193 #endif
00194     }
00195     setPalette(p);
00196 
00197     d_data->scaleDraw = new QwtDialScaleDraw(this);
00198     d_data->scaleDraw->setGeometry(0, 0, 0, QwtScaleDraw::Round);
00199 
00200     setScaleArc(0.0, 360.0); // scale as a full circle
00201     setRange(0.0, 360.0, 1.0, 10); // degrees as deafult
00202 }
00203 
00205 QwtDial::~QwtDial() 
00206 {
00207     delete d_data;
00208 }
00209 
00218 void QwtDial::showBackground(bool show)
00219 {
00220     if ( d_data->visibleBackground != show )
00221     {
00222         d_data->visibleBackground = show;
00223         updateMask();
00224     }
00225 }
00226 
00232 bool QwtDial::hasVisibleBackground() const 
00233 { 
00234     return d_data->visibleBackground; 
00235 }
00236 
00242 void QwtDial::setFrameShadow(Shadow shadow)
00243 {
00244     if ( shadow != d_data->frameShadow )
00245     {
00246         d_data->frameShadow = shadow;
00247         if ( lineWidth() > 0 )
00248             update();
00249     }
00250 }
00251 
00257 QwtDial::Shadow QwtDial::frameShadow() const 
00258 { 
00259     return d_data->frameShadow; 
00260 }
00261 
00268 void QwtDial::setLineWidth(int lineWidth)
00269 {
00270     if ( lineWidth < 0 )
00271         lineWidth = 0;
00272 
00273     if ( d_data->lineWidth != lineWidth )
00274     {
00275         d_data->lineWidth = lineWidth;
00276         update();
00277     }
00278 }
00279 
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 = qwtMax(
00336             d_data->scaleDraw->maxWidth(scalePen, font()),
00337             d_data->scaleDraw->maxHeight(scalePen, font()));
00338         scaleDist++; // margin
00339     }
00340 
00341     const QRect rect = contentsRect();
00342     return QRect(rect.x() + scaleDist, rect.y() + scaleDist,
00343         rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);
00344 }
00345 
00361 void QwtDial::setMode(Mode mode)
00362 {   
00363     if ( mode != d_data->mode )
00364     {
00365         d_data->mode = mode;
00366         update(); 
00367     }
00368 }       
00369 
00384 QwtDial::Mode QwtDial::mode() const
00385 {
00386     return d_data->mode;
00387 }
00388 
00399 void QwtDial::setWrapping(bool wrapping)
00400 {
00401     setPeriodic(wrapping);
00402 } 
00403 
00412 bool QwtDial::wrapping() const
00413 {
00414     return periodic();
00415 }
00416 
00418 void QwtDial::resizeEvent(QResizeEvent *e)
00419 {
00420     QWidget::resizeEvent(e);
00421 
00422     if ( !hasVisibleBackground() )
00423         updateMask();
00424 }
00425 
00427 void QwtDial::paintEvent(QPaintEvent *e)
00428 {
00429     const QRect &ur = e->rect();
00430     if ( ur.isValid() )
00431     {
00432 #if QT_VERSION < 0x040000
00433         QwtPaintBuffer paintBuffer(this, ur);
00434         QPainter &painter = *paintBuffer.painter();
00435 #else
00436         QPainter painter(this);
00437 #endif
00438 
00439         setAntialiasing(&painter, true);
00440 
00441         painter.save();
00442         drawContents(&painter);
00443         painter.restore();
00444 
00445         painter.save();
00446         drawFrame(&painter);
00447         painter.restore();
00448 
00449         if ( hasFocus() )
00450             drawFocusIndicator(&painter);
00451     }
00452 }
00453 
00459 void QwtDial::drawFocusIndicator(QPainter *painter) const
00460 {
00461     if ( !isReadOnly() )
00462     {
00463         QRect focusRect = contentsRect();
00464 
00465         const int margin = 2;
00466         focusRect.setRect( 
00467             focusRect.x() + margin,
00468             focusRect.y() + margin,
00469             focusRect.width() - 2 * margin,
00470             focusRect.height() - 2 * margin);
00471 
00472 #if QT_VERSION < 0x040000
00473         QColor color = colorGroup().color(QColorGroup::Base);
00474 #else
00475         QColor color = palette().color(QPalette::Base);
00476 #endif
00477         if (color.isValid())
00478         {
00479             const QColor gray(Qt::gray);
00480 
00481             int h, s, v;
00482 #if QT_VERSION < 0x040000
00483             color.hsv(&h, &s, &v);
00484 #else
00485             color.getHsv(&h, &s, &v);
00486 #endif
00487             color = (v > 128) ? gray.dark(120) : gray.light(120);
00488         }
00489         else
00490             color = Qt::darkGray;
00491 
00492         painter->save();
00493         painter->setBrush(Qt::NoBrush);
00494         painter->setPen(QPen(color, 0, Qt::DotLine));
00495         painter->drawEllipse(focusRect);
00496         painter->restore();
00497     }
00498 }
00499 
00506 void QwtDial::drawFrame(QPainter *painter)
00507 {
00508     const int lw = lineWidth();
00509     const int off = (lw + 1) % 2;
00510 
00511     QRect r = boundingRect();
00512     r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off,
00513         r.width() - lw + off + 1, r.height() - lw + off + 1);
00514 
00515     if ( lw > 0 )
00516     {
00517         switch(d_data->frameShadow)
00518         {
00519             case QwtDial::Raised:
00520 #if QT_VERSION < 0x040000
00521                 QwtPainter::drawRoundFrame(painter, r, 
00522                     lw, colorGroup(), false);
00523 #else
00524                 QwtPainter::drawRoundFrame(painter, r, 
00525                     lw, palette(), false);
00526 #endif
00527                 break;
00528             case QwtDial::Sunken:
00529 #if QT_VERSION < 0x040000
00530                 QwtPainter::drawRoundFrame(painter, r, 
00531                     lw, colorGroup(), true);
00532 #else
00533                 QwtPainter::drawRoundFrame(painter, r, 
00534                     lw, palette(), true);
00535 #endif
00536                 break;
00537             default: // Plain
00538             {
00539                 painter->save();
00540                 painter->setPen(QPen(Qt::black, lw));
00541                 painter->setBrush(Qt::NoBrush);
00542                 painter->drawEllipse(r);
00543                 painter->restore();
00544             }
00545         }
00546     }
00547 }
00548 
00560 void QwtDial::drawContents(QPainter *painter) const
00561 {
00562 #if QT_VERSION < 0x040000
00563     if ( backgroundMode() == Qt::NoBackground || 
00564         colorGroup().brush(QColorGroup::Base) != 
00565             colorGroup().brush(QColorGroup::Background) )
00566 #else
00567     if ( testAttribute(Qt::WA_NoSystemBackground) ||
00568         palette().brush(QPalette::Base) != 
00569             palette().brush(QPalette::Background) )
00570 #endif
00571     {
00572 
00573 #if QT_VERSION >= 0x040000
00574 #ifdef __GNUC__
00575 #warning Check QPainter::drawEllipse in Qt4
00576 #endif
00577 #endif
00578 
00579         // Donīt use QPainter::drawEllipse. There are some pixels
00580         // different compared to the region in the mask, leaving
00581         // them in background color.
00582 
00583         painter->save();
00584         painter->setPen(Qt::NoPen);
00585 #if QT_VERSION < 0x040000
00586         painter->setBrush(colorGroup().brush(QColorGroup::Base));
00587 #else
00588         painter->setBrush(palette().brush(QPalette::Base));
00589 #endif
00590 
00591         // Even if we want to fill the contentsRect only, we fill the
00592         // complete boundingRect. The frame will be painted later
00593         // above, but we want to have the base color below it
00594         // because round objects doesnīt cover all pixels.
00595 
00596         const QRect br = boundingRect();
00597 #if QT_VERSION < 0x040000
00598         const QRect clipRect = painter->xForm(br);
00599 #else
00600         const QRect clipRect = painter->matrix().mapRect(br);
00601 #endif
00602         painter->setClipRegion(QRegion(clipRect, QRegion::Ellipse));
00603         painter->drawRect(br);
00604         painter->restore();
00605     }
00606 
00607 
00608     const QRect insideScaleRect = scaleContentsRect();
00609 #if QT_VERSION < 0x040000
00610     if ( colorGroup().brush(QColorGroup::Foreground) !=
00611         colorGroup().brush(QColorGroup::Base) )
00612 #else
00613     if ( palette().brush(QPalette::Foreground) !=
00614         palette().brush(QPalette::Base) )
00615 #endif
00616     {
00617         painter->save();
00618         painter->setPen(Qt::NoPen);
00619 #if QT_VERSION < 0x040000
00620         painter->setBrush(colorGroup().brush(QColorGroup::Foreground));
00621 #else
00622         painter->setBrush(palette().brush(QPalette::Foreground));
00623 #endif
00624 
00625 #if QT_VERSION < 0x040000
00626         const QRect clipRect = painter->xForm(insideScaleRect);
00627 #else
00628         const QRect clipRect = painter->matrix().mapRect(insideScaleRect);
00629 #endif
00630         painter->setClipRegion( QRegion(clipRect, QRegion::Ellipse));
00631         painter->drawRect(insideScaleRect);
00632         painter->restore();
00633     }
00634 
00635     const QPoint center = insideScaleRect.center();
00636     const int radius = insideScaleRect.width() / 2;
00637 
00638     painter->save();
00639     drawScaleContents(painter, center, radius);
00640     painter->restore();
00641 
00642     double direction = d_data->origin;
00643 
00644     if (isValid())
00645     {
00646         direction = d_data->origin + d_data->minScaleArc;
00647         if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc )
00648         {
00649             const double ratio = 
00650                 (value() - minValue()) / (maxValue() - minValue());
00651             direction += ratio * (d_data->maxScaleArc - d_data->minScaleArc);
00652         }
00653 
00654         if ( direction >= 360.0 )
00655             direction -= 360.0;
00656     }
00657 
00658     double origin = d_data->origin;
00659     if ( mode() == RotateScale )
00660     {
00661         origin -= direction - d_data->origin;
00662         direction = d_data->origin;
00663     }
00664 
00665     painter->save();
00666     drawScale(painter, center, radius, origin, d_data->minScaleArc, d_data->maxScaleArc);
00667     painter->restore();
00668 
00669     if ( isValid() )
00670     {
00671         QPalette::ColorGroup cg;
00672         if ( isEnabled() )
00673             cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
00674         else
00675             cg = QPalette::Disabled;
00676 
00677         painter->save();
00678         drawNeedle(painter, center, radius, direction, cg);
00679         painter->restore();
00680     }
00681 }
00682 
00695 void QwtDial::drawNeedle(QPainter *painter, const QPoint &center, 
00696     int radius, double direction, QPalette::ColorGroup cg) const
00697 {
00698     if ( d_data->needle )
00699     {
00700         direction = 360.0 - direction; // counter clockwise
00701         d_data->needle->draw(painter, center, radius, direction, cg);
00702     }
00703 }
00704 
00717 void QwtDial::drawScale(QPainter *painter, const QPoint &center,
00718     int radius, double origin, double minArc, double maxArc) const
00719 {
00720     if ( d_data->scaleDraw == NULL )
00721         return;
00722 
00723     origin -= 270.0; // hardcoded origin of QwtScaleDraw
00724 
00725     double angle = maxArc - minArc;
00726     if ( angle > 360.0 )
00727         angle = fmod(angle, 360.0);
00728 
00729     minArc += origin;
00730     if ( minArc < -360.0 )
00731         minArc = fmod(minArc, 360.0);
00732     
00733     maxArc = minArc + angle;
00734     if ( maxArc > 360.0 )
00735     {
00736         // QwtScaleDraw::setAngleRange accepts only values
00737         // in the range [-360.0..360.0]
00738         minArc -= 360.0;
00739         maxArc -= 360.0;
00740     }
00741     
00742     painter->setFont(font());
00743 #if QT_VERSION < 0x040000
00744     const QColor penColor = colorGroup().text();
00745 #else
00746     const QColor penColor = palette().color(QPalette::Text);
00747 #endif
00748     painter->setPen(QPen(penColor, d_data->scaleDraw->penWidth()));
00749 
00750     d_data->scaleDraw->setAngleRange(minArc, maxArc);
00751     d_data->scaleDraw->setGeometry(
00752         center.x() - radius + 1, 
00753         center.y() - radius + 1,
00754         2 * radius, QwtScaleDraw::Round);
00755 
00756 #if QT_VERSION < 0x040000
00757     d_data->scaleDraw->draw(painter, colorGroup());
00758 #else
00759     d_data->scaleDraw->draw(painter, palette());
00760 #endif
00761 }
00762 
00763 void QwtDial::drawScaleContents(QPainter *, 
00764     const QPoint &, int) const
00765 {
00766     // empty default implementation
00767 }
00768 
00779 void QwtDial::setNeedle(QwtDialNeedle *needle)
00780 {
00781     if ( needle != d_data->needle )
00782     {
00783         if ( d_data->needle )
00784             delete d_data->needle;
00785 
00786         d_data->needle = needle;
00787         update();
00788     }
00789 }
00790 
00795 const QwtDialNeedle *QwtDial::needle() const 
00796 { 
00797     return d_data->needle; 
00798 }
00799 
00804 QwtDialNeedle *QwtDial::needle() 
00805 { 
00806     return d_data->needle; 
00807 }
00808 
00810 void QwtDial::rangeChange()
00811 {
00812     updateScale();
00813 }
00814 
00819 void QwtDial::updateScale()
00820 {
00821     if ( d_data->scaleDraw )
00822     {
00823         QwtLinearScaleEngine scaleEngine;
00824 
00825         const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
00826             minValue(), maxValue(), 
00827             d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep);
00828 
00829         d_data->scaleDraw->setTransformation(scaleEngine.transformation());
00830         d_data->scaleDraw->setScaleDiv(scaleDiv);
00831     }
00832 }
00833 
00835 QwtDialScaleDraw *QwtDial::scaleDraw() 
00836 { 
00837     return d_data->scaleDraw; 
00838 }
00839 
00841 const QwtDialScaleDraw *QwtDial::scaleDraw() const 
00842 { 
00843     return d_data->scaleDraw; 
00844 }
00845 
00851 void QwtDial::setScaleDraw(QwtDialScaleDraw *scaleDraw)
00852 {
00853     if ( scaleDraw != d_data->scaleDraw )
00854     {
00855         if ( d_data->scaleDraw )
00856             delete d_data->scaleDraw;
00857     
00858         d_data->scaleDraw = scaleDraw;
00859         updateScale();
00860         update();
00861     }
00862 }
00863 
00868 void QwtDial::setScale(int maxMajIntv, int maxMinIntv, double step)
00869 {
00870     d_data->maxMajIntv = maxMajIntv;
00871     d_data->maxMinIntv = maxMinIntv;
00872     d_data->scaleStep = step;
00873 
00874     updateScale();
00875 }
00876 
00892 void QwtDial::setScaleOptions(int options)
00893 {
00894     if ( options == 0 )
00895         setScaleDraw(NULL);
00896 
00897     if ( d_data->scaleDraw == NULL )
00898         return;
00899 
00900     int flags = d_data->scaleDraw->options();
00901     if ( options & ScaleBackbone )
00902         flags |= QwtScaleDraw::Backbone;
00903     else
00904         flags &= ~QwtScaleDraw::Backbone;
00905     d_data->scaleDraw->setOptions(flags);
00906 
00907     if ( !(options & ScaleTicks) )
00908         d_data->scaleDraw->setTickLength(0, 0, 0);
00909 
00910     d_data->scaleDraw->showLabels(options & ScaleLabel);
00911 }
00912 
00914 void QwtDial::setScaleTicks(int minLen, int medLen, 
00915     int majLen, int penWidth)
00916 {
00917     if ( d_data->scaleDraw )
00918     {
00919         d_data->scaleDraw->setTickLength(minLen, medLen, majLen);
00920         d_data->scaleDraw->setPenWidth(penWidth);
00921     }
00922 }
00923 
00927 QString QwtDial::scaleLabel(double value) const
00928 {
00929 #if 1
00930     if ( value == -0 )
00931         value = 0;
00932 #endif
00933 
00934     QString text;
00935     text.sprintf("%g", value);
00936 
00937     return text;
00938 }
00939 
00941 double QwtDial::minScaleArc() const 
00942 { 
00943     return d_data->minScaleArc; 
00944 }
00945 
00947 double QwtDial::maxScaleArc() const 
00948 { 
00949     return d_data->maxScaleArc; 
00950 }
00951 
00960 void QwtDial::setOrigin(double origin)
00961 {
00962     d_data->origin = origin;
00963     update();
00964 }
00965 
00972 double QwtDial::origin() const
00973 {
00974     return d_data->origin;
00975 }
00976 
00983 void QwtDial::setScaleArc(double minArc, double maxArc)
00984 {
00985     if ( minArc != 360.0 && minArc != -360.0 )
00986         minArc = fmod(minArc, 360.0);
00987     if ( maxArc != 360.0 && maxArc != -360.0 )
00988         maxArc = fmod(maxArc, 360.0);
00989 
00990     d_data->minScaleArc = qwtMin(minArc, maxArc);
00991     d_data->maxScaleArc = qwtMax(minArc, maxArc);
00992     if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
00993         d_data->maxScaleArc = d_data->minScaleArc + 360.0;
00994     
00995     update();
00996 }
00997 
00999 void QwtDial::valueChange()
01000 {
01001     update();
01002     QwtAbstractSlider::valueChange();
01003 }
01004 
01008 QSize QwtDial::sizeHint() const
01009 {
01010     int sh = 0;
01011     if ( d_data->scaleDraw )
01012         sh = d_data->scaleDraw->minHeight( QPen(), font() );
01013 
01014     const int d = 6 * sh + 2 * lineWidth();
01015     
01016     return QSize( d, d );
01017 }
01018 
01024 QSize QwtDial::minimumSizeHint() const
01025 {   
01026     int sh = 0;
01027     if ( d_data->scaleDraw )
01028         sh = d_data->scaleDraw->minHeight( QPen(), font() );
01029 
01030     const int d = 3 * sh + 2 * lineWidth();
01031     
01032     return QSize( d, d );
01033 }
01034 
01035 static double line2Radians(const QPoint &p1, const QPoint &p2)
01036 {
01037     const QPoint p = p2 - p1;
01038 
01039     double angle;
01040     if ( p.x() == 0 )
01041         angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
01042     else
01043     {
01044         angle = atan(double(-p.y()) / double(p.x()));
01045         if ( p.x() < 0 )
01046             angle += M_PI;
01047         if ( angle < 0.0 )
01048             angle += 2 * M_PI;
01049     }
01050     return 360.0 - angle * 180.0 / M_PI;
01051 }
01052 
01059 double QwtDial::getValue(const QPoint &pos)
01060 {
01061     if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
01062         return minValue();
01063 
01064     double dir = line2Radians(rect().center(), pos) - d_data->origin;
01065     if ( dir < 0.0 )
01066         dir += 360.0;
01067 
01068     if ( mode() == RotateScale )
01069         dir = 360.0 - dir;
01070 
01071     // The position might be in the area that is outside the scale arc.
01072     // We need the range of the scale if it was a complete circle.
01073 
01074     const double completeCircle = 360.0 / (d_data->maxScaleArc - d_data->minScaleArc) 
01075         * (maxValue() - minValue());
01076 
01077     double posValue = minValue() + completeCircle * dir / 360.0;
01078 
01079     if ( scrollMode() == ScrMouse )
01080     {
01081         if ( d_data->previousDir >= 0.0 ) // valid direction
01082         {
01083             // We have to find out whether the mouse is moving
01084             // clock or counter clockwise
01085 
01086             bool clockWise = false;
01087 
01088             const double angle = dir - d_data->previousDir;
01089             if ( (angle >= 0.0 && angle <= 180.0) || angle < -180.0 )
01090                 clockWise = true;
01091 
01092             if ( clockWise )
01093             {
01094                 if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
01095                 {
01096                     // We passed 360 -> 0
01097                     setMouseOffset(mouseOffset() - completeCircle);
01098                 }
01099 
01100                 if ( wrapping() )
01101                 {
01102                     if ( posValue - mouseOffset() > maxValue() )
01103                     {
01104                         // We passed maxValue and the value will be set
01105                         // to minValue. We have to adjust the mouseOffset.
01106 
01107                         setMouseOffset(posValue - minValue());
01108                     }
01109                 }
01110                 else
01111                 {
01112                     if ( posValue - mouseOffset() > maxValue() ||
01113                         value() == maxValue() )
01114                     {
01115                         // We fix the value at maxValue by adjusting
01116                         // the mouse offset.
01117 
01118                         setMouseOffset(posValue - maxValue());
01119                     }
01120                 }
01121             }
01122             else
01123             {
01124                 if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
01125                 {
01126                     // We passed 0 -> 360 
01127                     setMouseOffset(mouseOffset() + completeCircle);    
01128                 }
01129 
01130                 if ( wrapping() )
01131                 {
01132                     if ( posValue - mouseOffset() < minValue() )
01133                     {
01134                         // We passed minValue and the value will be set
01135                         // to maxValue. We have to adjust the mouseOffset.
01136 
01137                         setMouseOffset(posValue - maxValue());
01138                     }
01139                 }
01140                 else
01141                 {
01142                     if ( posValue - mouseOffset() < minValue() ||
01143                         value() == minValue() )
01144                     {
01145                         // We fix the value at minValue by adjusting
01146                         // the mouse offset.
01147 
01148                         setMouseOffset(posValue - minValue());
01149                     }
01150                 }
01151             }
01152         }
01153         d_data->previousDir = dir;
01154     }
01155 
01156     return posValue;
01157 }
01158 
01162 void QwtDial::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
01163 {
01164     direction = 0;
01165     scrollMode = ScrNone;
01166 
01167     const QRegion region(contentsRect(), QRegion::Ellipse);
01168     if ( region.contains(p) && p != rect().center() )
01169     {
01170         scrollMode = ScrMouse;
01171         d_data->previousDir = -1.0;
01172     }
01173 }
01174 
01194 void QwtDial::keyPressEvent(QKeyEvent *e)
01195 {
01196     if ( isReadOnly() )
01197     {
01198         e->ignore();
01199         return;
01200     }
01201 
01202     if ( !isValid() )
01203         return;
01204 
01205     double previous = prevValue();
01206     switch ( e->key() )
01207     {
01208         case Qt::Key_Down:
01209         case Qt::Key_Left:
01210             QwtDoubleRange::incValue(-1);
01211             break;
01212 #if QT_VERSION < 0x040000
01213         case Qt::Key_Prior:
01214 #else
01215         case Qt::Key_PageUp:
01216 #endif
01217             QwtDoubleRange::incValue(-pageSize());
01218             break;
01219         case Qt::Key_Home:
01220             setValue(minValue());
01221             break;
01222 
01223         case Qt::Key_Up:
01224         case Qt::Key_Right:
01225             QwtDoubleRange::incValue(1);
01226             break;
01227 #if QT_VERSION < 0x040000
01228         case Qt::Key_Next:
01229 #else
01230         case Qt::Key_PageDown:
01231 #endif
01232             QwtDoubleRange::incValue(pageSize());
01233             break;
01234         case Qt::Key_End:
01235             setValue(maxValue());
01236             break;
01237         default:;
01238             e->ignore();
01239     }
01240 
01241     if (value() != previous)
01242         emit sliderMoved(value());
01243 }
01244 
01245 void QwtDial::updateMask()
01246 {
01247     if ( d_data->visibleBackground )
01248         clearMask();
01249     else
01250         setMask(QRegion(boundingRect(), QRegion::Ellipse));
01251 }

Generated on Wed Aug 31 23:02:29 2005 for Qwt User's Guide by  doxygen 1.4.1