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

qwt_knob.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 <qpainter.h>
00011 #if QT_VERSION >= 0x040000
00012 #include <qpaintengine.h>
00013 #endif
00014 #include <qpalette.h>
00015 #include <qstyle.h>
00016 #include <qevent.h>
00017 #include "qwt_round_scale_draw.h"
00018 #include "qwt_knob.h"
00019 #include "qwt_math.h"
00020 #include "qwt_painter.h"
00021 #include "qwt_paint_buffer.h"
00022 
00023 class QwtKnob::PrivateData
00024 {
00025 public:
00026     PrivateData()
00027     {
00028         angle = 0.0;
00029         nTurns = 0.0;
00030         borderWidth = 2;
00031         borderDist = 4;
00032         totalAngle = 270.0;
00033         scaleDist = 4;
00034         symbol = Line;
00035         maxScaleTicks = 11;
00036         knobWidth = 50;
00037         dotWidth = 8;
00038     }
00039 
00040     int borderWidth;
00041     int borderDist;
00042     int scaleDist;
00043     int maxScaleTicks;
00044     int knobWidth;
00045     int dotWidth;
00046 
00047     Symbol symbol;
00048     double angle;
00049     double totalAngle;
00050     double nTurns;
00051 
00052     QRect knobRect; // bounding rect of the knob without scale
00053 };
00054 
00059 QwtKnob::QwtKnob(QWidget* parent): 
00060     QwtAbstractSlider(Qt::Horizontal, parent)
00061 {
00062 #if QT_VERSION < 0x040000
00063     setWFlags(Qt::WNoAutoErase);
00064 #endif
00065 
00066     d_data = new PrivateData;
00067 
00068     setScaleDraw(new QwtRoundScaleDraw());
00069 
00070     setUpdateTime(50);
00071     setTotalAngle( 270.0 );
00072     recalcAngle();
00073     setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00074 
00075     setRange(0.0, 10.0, 1.0);
00076     setValue(0.0);
00077 }
00078 
00080 QwtKnob::~QwtKnob()
00081 {
00082     delete d_data;
00083 }
00084 
00089 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00090 {
00091     if ( d_data->symbol != s )
00092     {
00093         d_data->symbol = s;
00094         update();
00095     }
00096 }
00097 
00102 QwtKnob::Symbol QwtKnob::symbol() const
00103 {
00104     return d_data->symbol;
00105 }
00106 
00115 void QwtKnob::setTotalAngle (double angle)
00116 {
00117     if (angle < 10.0)
00118        d_data->totalAngle = 10.0;
00119     else
00120        d_data->totalAngle = angle;
00121 
00122     scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 
00123         0.5 * d_data->totalAngle);
00124     layoutKnob();
00125 }
00126 
00128 double QwtKnob::totalAngle() const 
00129 {
00130     return d_data->totalAngle;
00131 }
00132 
00142 void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
00143 {
00144     setAbstractScaleDraw(scaleDraw);
00145 }
00146 
00151 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00152 {
00153     return (QwtRoundScaleDraw *)abstractScaleDraw();
00154 }
00155 
00160 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00161 {
00162     return (QwtRoundScaleDraw *)abstractScaleDraw();
00163 }
00164 
00170 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00171 {
00172 #if QT_VERSION < 0x040000
00173     const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00174     const QColor buttonTextColor = colorGroup().buttonText();
00175     const QColor lightColor = colorGroup().light();
00176     const QColor darkColor = colorGroup().dark();
00177 #else
00178     const QBrush buttonBrush = palette().brush(QPalette::Button);
00179     const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00180     const QColor lightColor = palette().color(QPalette::Light);
00181     const QColor darkColor = palette().color(QPalette::Dark);
00182 #endif
00183 
00184     const int bw2 = d_data->borderWidth / 2;
00185 
00186     const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00187 
00188     const QRect aRect( 
00189         r.center().x() - radius, r.center().y() - radius,
00190         2 * radius, 2 * radius);
00191 
00192     //
00193     // draw button face
00194     //
00195     painter->setBrush(buttonBrush);
00196     painter->drawEllipse(aRect);
00197 
00198     //
00199     // draw button shades
00200     //
00201     QPen pn;
00202     pn.setWidth(d_data->borderWidth);
00203 
00204     pn.setColor(lightColor);
00205     painter->setPen(pn);
00206     painter->drawArc(aRect, 45*16, 180*16);
00207 
00208     pn.setColor(darkColor);
00209     painter->setPen(pn);
00210     painter->drawArc(aRect, 225*16, 180*16);
00211 
00212     //
00213     // draw marker
00214     //
00215     if ( isValid() )
00216         drawMarker(painter, d_data->angle, buttonTextColor);
00217 }
00218 
00225 void QwtKnob::valueChange()
00226 {
00227     recalcAngle();
00228     update();
00229     QwtAbstractSlider::valueChange();
00230 }
00231 
00238 double QwtKnob::getValue(const QPoint &p)
00239 {
00240     const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00241     const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00242 
00243     const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00244 
00245     double newValue =  0.5 * (minValue() + maxValue())
00246        + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00247       / d_data->totalAngle;
00248 
00249     const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00250     const double eqValue = value() + mouseOffset();
00251 
00252     if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00253     {
00254         if (newValue < eqValue)
00255            newValue += oneTurn;
00256         else
00257            newValue -= oneTurn;
00258     }
00259 
00260     return newValue;    
00261 }
00262 
00269 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00270 {
00271     const int r = d_data->knobRect.width() / 2;
00272 
00273     const int dx = d_data->knobRect.x() + r - p.x();
00274     const int dy = d_data->knobRect.y() + r - p.y();
00275 
00276     if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
00277     {
00278         scrollMode = ScrMouse;
00279         direction = 0;
00280     }
00281     else                                // point lies outside
00282     {
00283         scrollMode = ScrTimer;
00284         double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00285         if ( arc < d_data->angle)
00286            direction = -1;
00287         else if (arc > d_data->angle)
00288            direction = 1;
00289         else
00290            direction = 0;
00291     }
00292 }
00293 
00294 
00300 void QwtKnob::rangeChange()
00301 {
00302     if (autoScale())
00303         rescale(minValue(), maxValue());
00304 
00305     layoutKnob();
00306     recalcAngle();
00307 }
00308 
00312 void QwtKnob::resizeEvent(QResizeEvent *)
00313 {
00314     layoutKnob( false );
00315 }
00316 
00318 //  the current rect and fonts.
00319 //  \param update_geometry  notify the layout system and call update
00320 //         to redraw the scale
00321 void QwtKnob::layoutKnob( bool update_geometry )
00322 {
00323     const QRect r = rect();
00324     const int radius = d_data->knobWidth / 2;
00325 
00326     d_data->knobRect.setWidth(2 * radius);
00327     d_data->knobRect.setHeight(2 * radius);
00328     d_data->knobRect.moveCenter(r.center());
00329 
00330     scaleDraw()->setRadius(radius + d_data->scaleDist);
00331     scaleDraw()->moveCenter(r.center());
00332 
00333     if ( update_geometry )
00334     {
00335         updateGeometry();
00336         update();
00337     }
00338 }
00339 
00343 void QwtKnob::paintEvent(QPaintEvent *e)
00344 {
00345     const QRect &ur = e->rect();
00346     if ( ur.isValid() ) 
00347     {
00348 #if QT_VERSION < 0x040000
00349         QwtPaintBuffer paintBuffer(this, ur);
00350         draw(paintBuffer.painter(), ur);
00351 #else
00352         QPainter painter(this);
00353         if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00354             painter.setRenderHint(QPainter::Antialiasing);
00355         draw(&painter, ur);
00356 #endif
00357     }
00358 }
00359 
00363 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00364 {
00365     if ( !d_data->knobRect.contains( ur ) ) // event from valueChange()
00366     {
00367 #if QT_VERSION < 0x040000
00368         scaleDraw()->draw( painter, colorGroup() );
00369 #else
00370         scaleDraw()->draw( painter, palette() );
00371 #endif
00372     }
00373 
00374     drawKnob( painter, d_data->knobRect );
00375 
00376     if ( hasFocus() )
00377         QwtPainter::drawFocusRect(painter, this);
00378 }
00379 
00386 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00387 {
00388     const double rarc = arc * M_PI / 180.0;
00389     const double ca = cos(rarc);
00390     const double sa = - sin(rarc);
00391 
00392     int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00393     if (radius < 3) 
00394         radius = 3; 
00395 
00396     const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00397     const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00398 
00399     switch (d_data->symbol)
00400     {
00401         case Dot:
00402         {
00403             p->setBrush(c);
00404             p->setPen(Qt::NoPen);
00405 
00406             const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00407             p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00408                    ym - qRound(ca * rb) - d_data->dotWidth / 2,
00409                    d_data->dotWidth, d_data->dotWidth);
00410             break;
00411         }
00412         case Line:
00413         {
00414             p->setPen(QPen(c, 2));
00415 
00416             const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00417             const double re = qwtMax(double(radius - 4), 0.0);
00418             
00419             p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00420                 xm - qRound(sa * re), ym - qRound(ca * re));
00421             
00422             break;
00423         }
00424     }
00425 }
00426 
00433 void QwtKnob::setKnobWidth(int w)
00434 {
00435     d_data->knobWidth = qwtMax(w,5);
00436     layoutKnob();
00437 }
00438 
00440 int QwtKnob::knobWidth() const 
00441 {
00442     return d_data->knobWidth;
00443 }
00444 
00449 void QwtKnob::setBorderWidth(int bw)
00450 {
00451     d_data->borderWidth = qwtMax(bw, 0);
00452     layoutKnob();
00453 }
00454 
00456 int QwtKnob::borderWidth() const 
00457 {
00458     return d_data->borderWidth;
00459 }
00460 
00465 void QwtKnob::recalcAngle()
00466 {
00467     //
00468     // calculate the angle corresponding to the value
00469     //
00470     if (maxValue() == minValue())
00471     {
00472         d_data->angle = 0;
00473         d_data->nTurns = 0;
00474     }
00475     else
00476     {
00477         d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00478             / (maxValue() - minValue()) * d_data->totalAngle;
00479         d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00480         d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00481     }
00482 }
00483 
00484 
00489 void QwtKnob::scaleChange()
00490 {
00491     layoutKnob();
00492 }
00493 
00498 void QwtKnob::fontChange(const QFont &f)
00499 {
00500     QwtAbstractSlider::fontChange( f );
00501     layoutKnob();
00502 }
00503 
00507 QSize QwtKnob::sizeHint() const
00508 {
00509     return minimumSizeHint();
00510 }
00511 
00517 QSize QwtKnob::minimumSizeHint() const
00518 {
00519     // Add the scale radial thickness to the knobWidth
00520     const int sh = scaleDraw()->extent( QPen(), font() );
00521     const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00522 
00523     return QSize( d, d );
00524 }

Generated on Mon Jan 30 22:16:25 2006 for Qwt User's Guide by  doxygen 1.4.4