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     initKnob();
00063 }
00064 
00065 #if QT_VERSION < 0x040000
00066 
00071 QwtKnob::QwtKnob(QWidget* parent, const char *name): 
00072     QwtAbstractSlider(Qt::Horizontal, parent)
00073 {
00074     setName(name);
00075     initKnob();
00076 }
00077 #endif
00078 
00079 void QwtKnob::initKnob()
00080 {
00081 #if QT_VERSION < 0x040000
00082     setWFlags(Qt::WNoAutoErase);
00083 #endif
00084 
00085     d_data = new PrivateData;
00086 
00087     setScaleDraw(new QwtRoundScaleDraw());
00088 
00089     setUpdateTime(50);
00090     setTotalAngle( 270.0 );
00091     recalcAngle();
00092     setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00093 
00094     setRange(0.0, 10.0, 1.0);
00095     setValue(0.0);
00096 }
00097 
00099 QwtKnob::~QwtKnob()
00100 {
00101     delete d_data;
00102 }
00103 
00108 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00109 {
00110     if ( d_data->symbol != s )
00111     {
00112         d_data->symbol = s;
00113         update();
00114     }
00115 }
00116 
00121 QwtKnob::Symbol QwtKnob::symbol() const
00122 {
00123     return d_data->symbol;
00124 }
00125 
00134 void QwtKnob::setTotalAngle (double angle)
00135 {
00136     if (angle < 10.0)
00137        d_data->totalAngle = 10.0;
00138     else
00139        d_data->totalAngle = angle;
00140 
00141     scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 
00142         0.5 * d_data->totalAngle);
00143     layoutKnob();
00144 }
00145 
00147 double QwtKnob::totalAngle() const 
00148 {
00149     return d_data->totalAngle;
00150 }
00151 
00161 void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
00162 {
00163     setAbstractScaleDraw(scaleDraw);
00164     setTotalAngle(d_data->totalAngle);
00165 }
00166 
00171 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00172 {
00173     return (QwtRoundScaleDraw *)abstractScaleDraw();
00174 }
00175 
00180 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00181 {
00182     return (QwtRoundScaleDraw *)abstractScaleDraw();
00183 }
00184 
00190 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00191 {
00192 #if QT_VERSION < 0x040000
00193     const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00194     const QColor buttonTextColor = colorGroup().buttonText();
00195     const QColor lightColor = colorGroup().light();
00196     const QColor darkColor = colorGroup().dark();
00197 #else
00198     const QBrush buttonBrush = palette().brush(QPalette::Button);
00199     const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00200     const QColor lightColor = palette().color(QPalette::Light);
00201     const QColor darkColor = palette().color(QPalette::Dark);
00202 #endif
00203 
00204     const int bw2 = d_data->borderWidth / 2;
00205 
00206     const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00207 
00208     const QRect aRect( 
00209         r.center().x() - radius, r.center().y() - radius,
00210         2 * radius, 2 * radius);
00211 
00212     //
00213     // draw button face
00214     //
00215     painter->setBrush(buttonBrush);
00216     painter->drawEllipse(aRect);
00217 
00218     //
00219     // draw button shades
00220     //
00221     QPen pn;
00222     pn.setWidth(d_data->borderWidth);
00223 
00224     pn.setColor(lightColor);
00225     painter->setPen(pn);
00226     painter->drawArc(aRect, 45*16, 180*16);
00227 
00228     pn.setColor(darkColor);
00229     painter->setPen(pn);
00230     painter->drawArc(aRect, 225*16, 180*16);
00231 
00232     //
00233     // draw marker
00234     //
00235     if ( isValid() )
00236         drawMarker(painter, d_data->angle, buttonTextColor);
00237 }
00238 
00245 void QwtKnob::valueChange()
00246 {
00247     recalcAngle();
00248     update();
00249     QwtAbstractSlider::valueChange();
00250 }
00251 
00258 double QwtKnob::getValue(const QPoint &p)
00259 {
00260     const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00261     const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00262 
00263     const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00264 
00265     double newValue =  0.5 * (minValue() + maxValue())
00266        + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00267       / d_data->totalAngle;
00268 
00269     const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00270     const double eqValue = value() + mouseOffset();
00271 
00272     if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00273     {
00274         if (newValue < eqValue)
00275            newValue += oneTurn;
00276         else
00277            newValue -= oneTurn;
00278     }
00279 
00280     return newValue;    
00281 }
00282 
00289 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00290 {
00291     const int r = d_data->knobRect.width() / 2;
00292 
00293     const int dx = d_data->knobRect.x() + r - p.x();
00294     const int dy = d_data->knobRect.y() + r - p.y();
00295 
00296     if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
00297     {
00298         scrollMode = ScrMouse;
00299         direction = 0;
00300     }
00301     else                                // point lies outside
00302     {
00303         scrollMode = ScrTimer;
00304         double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00305         if ( arc < d_data->angle)
00306            direction = -1;
00307         else if (arc > d_data->angle)
00308            direction = 1;
00309         else
00310            direction = 0;
00311     }
00312 }
00313 
00314 
00320 void QwtKnob::rangeChange()
00321 {
00322     if (autoScale())
00323         rescale(minValue(), maxValue());
00324 
00325     layoutKnob();
00326     recalcAngle();
00327 }
00328 
00332 void QwtKnob::resizeEvent(QResizeEvent *)
00333 {
00334     layoutKnob( false );
00335 }
00336 
00338 //  the current rect and fonts.
00339 //  \param update_geometry  notify the layout system and call update
00340 //         to redraw the scale
00341 void QwtKnob::layoutKnob( bool update_geometry )
00342 {
00343     const QRect r = rect();
00344     const int radius = d_data->knobWidth / 2;
00345 
00346     d_data->knobRect.setWidth(2 * radius);
00347     d_data->knobRect.setHeight(2 * radius);
00348     d_data->knobRect.moveCenter(r.center());
00349 
00350     scaleDraw()->setRadius(radius + d_data->scaleDist);
00351     scaleDraw()->moveCenter(r.center());
00352 
00353     if ( update_geometry )
00354     {
00355         updateGeometry();
00356         update();
00357     }
00358 }
00359 
00363 void QwtKnob::paintEvent(QPaintEvent *e)
00364 {
00365     const QRect &ur = e->rect();
00366     if ( ur.isValid() ) 
00367     {
00368 #if QT_VERSION < 0x040000
00369         QwtPaintBuffer paintBuffer(this, ur);
00370         draw(paintBuffer.painter(), ur);
00371 #else
00372         QPainter painter(this);
00373         if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00374             painter.setRenderHint(QPainter::Antialiasing);
00375         draw(&painter, ur);
00376 #endif
00377     }
00378 }
00379 
00383 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00384 {
00385     if ( !d_data->knobRect.contains( ur ) ) // event from valueChange()
00386     {
00387 #if QT_VERSION < 0x040000
00388         scaleDraw()->draw( painter, colorGroup() );
00389 #else
00390         scaleDraw()->draw( painter, palette() );
00391 #endif
00392     }
00393 
00394     drawKnob( painter, d_data->knobRect );
00395 
00396     if ( hasFocus() )
00397         QwtPainter::drawFocusRect(painter, this);
00398 }
00399 
00406 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00407 {
00408     const double rarc = arc * M_PI / 180.0;
00409     const double ca = cos(rarc);
00410     const double sa = - sin(rarc);
00411 
00412     int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00413     if (radius < 3) 
00414         radius = 3; 
00415 
00416     const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00417     const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00418 
00419     switch (d_data->symbol)
00420     {
00421         case Dot:
00422         {
00423             p->setBrush(c);
00424             p->setPen(Qt::NoPen);
00425 
00426             const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00427             p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00428                    ym - qRound(ca * rb) - d_data->dotWidth / 2,
00429                    d_data->dotWidth, d_data->dotWidth);
00430             break;
00431         }
00432         case Line:
00433         {
00434             p->setPen(QPen(c, 2));
00435 
00436             const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00437             const double re = qwtMax(double(radius - 4), 0.0);
00438             
00439             p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00440                 xm - qRound(sa * re), ym - qRound(ca * re));
00441             
00442             break;
00443         }
00444     }
00445 }
00446 
00453 void QwtKnob::setKnobWidth(int w)
00454 {
00455     d_data->knobWidth = qwtMax(w,5);
00456     layoutKnob();
00457 }
00458 
00460 int QwtKnob::knobWidth() const 
00461 {
00462     return d_data->knobWidth;
00463 }
00464 
00469 void QwtKnob::setBorderWidth(int bw)
00470 {
00471     d_data->borderWidth = qwtMax(bw, 0);
00472     layoutKnob();
00473 }
00474 
00476 int QwtKnob::borderWidth() const 
00477 {
00478     return d_data->borderWidth;
00479 }
00480 
00485 void QwtKnob::recalcAngle()
00486 {
00487     //
00488     // calculate the angle corresponding to the value
00489     //
00490     if (maxValue() == minValue())
00491     {
00492         d_data->angle = 0;
00493         d_data->nTurns = 0;
00494     }
00495     else
00496     {
00497         d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00498             / (maxValue() - minValue()) * d_data->totalAngle;
00499         d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00500         d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00501     }
00502 }
00503 
00504 
00509 void QwtKnob::scaleChange()
00510 {
00511     layoutKnob();
00512 }
00513 
00518 void QwtKnob::fontChange(const QFont &f)
00519 {
00520     QwtAbstractSlider::fontChange( f );
00521     layoutKnob();
00522 }
00523 
00527 QSize QwtKnob::sizeHint() const
00528 {
00529     return minimumSizeHint();
00530 }
00531 
00537 QSize QwtKnob::minimumSizeHint() const
00538 {
00539     // Add the scale radial thickness to the knobWidth
00540     const int sh = scaleDraw()->extent( QPen(), font() );
00541     const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00542 
00543     return QSize( d, d );
00544 }

Generated on Sat May 24 18:47:39 2008 for Qwt User's Guide by  doxygen 1.5.0