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 #include <qpalette.h>
00012 #include <qstyle.h>
00013 #include <qevent.h>
00014 #include "qwt_round_scale_draw.h"
00015 #include "qwt_knob.h"
00016 #include "qwt_math.h"
00017 #include "qwt_painter.h"
00018 #include "qwt_paint_buffer.h"
00019 
00020 class QwtKnob::PrivateData
00021 {
00022 public:
00023     PrivateData()
00024     {
00025         angle = 0.0;
00026         nTurns = 0.0;
00027         borderWidth = 2;
00028         borderDist = 4;
00029         totalAngle = 270.0;
00030         scaleDist = 4;
00031         symbol = Line;
00032         maxScaleTicks = 11;
00033         knobWidth = 50;
00034         dotWidth = 8;
00035     }
00036 
00037     int borderWidth;
00038     int borderDist;
00039     int scaleDist;
00040     int maxScaleTicks;
00041     int knobWidth;
00042     int dotWidth;
00043 
00044     Symbol symbol;
00045     double angle;
00046     double totalAngle;
00047     double nTurns;
00048 
00049     QRect knobRect; // bounding rect of the knob without scale
00050 };
00051 
00056 QwtKnob::QwtKnob(QWidget* parent): 
00057     QwtAbstractSlider(Qt::Horizontal, parent)
00058 {
00059     initKnob();
00060 }
00061 
00062 #if QT_VERSION < 0x040000
00063 
00068 QwtKnob::QwtKnob(QWidget* parent, const char *name): 
00069     QwtAbstractSlider(Qt::Horizontal, parent)
00070 {
00071     setName(name);
00072     initKnob();
00073 }
00074 #endif
00075 
00076 void QwtKnob::initKnob()
00077 {
00078 #if QT_VERSION < 0x040000
00079     setWFlags(Qt::WNoAutoErase);
00080 #endif
00081 
00082     d_data = new PrivateData;
00083 
00084     setScaleDraw(new QwtRoundScaleDraw());
00085 
00086     setUpdateTime(50);
00087     setTotalAngle( 270.0 );
00088     recalcAngle();
00089     setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00090 
00091     setRange(0.0, 10.0, 1.0);
00092     setValue(0.0);
00093 }
00094 
00096 QwtKnob::~QwtKnob()
00097 {
00098     delete d_data;
00099 }
00100 
00105 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00106 {
00107     if ( d_data->symbol != s )
00108     {
00109         d_data->symbol = s;
00110         update();
00111     }
00112 }
00113 
00118 QwtKnob::Symbol QwtKnob::symbol() const
00119 {
00120     return d_data->symbol;
00121 }
00122 
00131 void QwtKnob::setTotalAngle (double angle)
00132 {
00133     if (angle < 10.0)
00134        d_data->totalAngle = 10.0;
00135     else
00136        d_data->totalAngle = angle;
00137 
00138     scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 
00139         0.5 * d_data->totalAngle);
00140     layoutKnob();
00141 }
00142 
00144 double QwtKnob::totalAngle() const 
00145 {
00146     return d_data->totalAngle;
00147 }
00148 
00158 void QwtKnob::setScaleDraw(QwtRoundScaleDraw *scaleDraw)
00159 {
00160     setAbstractScaleDraw(scaleDraw);
00161     setTotalAngle(d_data->totalAngle);
00162 }
00163 
00168 const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
00169 {
00170     return (QwtRoundScaleDraw *)abstractScaleDraw();
00171 }
00172 
00177 QwtRoundScaleDraw *QwtKnob::scaleDraw()
00178 {
00179     return (QwtRoundScaleDraw *)abstractScaleDraw();
00180 }
00181 
00187 void QwtKnob::drawKnob(QPainter *painter, const QRect &r)
00188 {
00189 #if QT_VERSION < 0x040000
00190     const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00191     const QColor buttonTextColor = colorGroup().buttonText();
00192     const QColor lightColor = colorGroup().light();
00193     const QColor darkColor = colorGroup().dark();
00194 #else
00195     const QBrush buttonBrush = palette().brush(QPalette::Button);
00196     const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00197     const QColor lightColor = palette().color(QPalette::Light);
00198     const QColor darkColor = palette().color(QPalette::Dark);
00199 #endif
00200 
00201     const int bw2 = d_data->borderWidth / 2;
00202 
00203     const int radius = (qwtMin(r.width(), r.height()) - bw2) / 2;
00204 
00205     const QRect aRect( 
00206         r.center().x() - radius, r.center().y() - radius,
00207         2 * radius, 2 * radius);
00208 
00209     //
00210     // draw button face
00211     //
00212     painter->setBrush(buttonBrush);
00213     painter->drawEllipse(aRect);
00214 
00215     //
00216     // draw button shades
00217     //
00218     QPen pn;
00219     pn.setWidth(d_data->borderWidth);
00220 
00221     pn.setColor(lightColor);
00222     painter->setPen(pn);
00223     painter->drawArc(aRect, 45*16, 180*16);
00224 
00225     pn.setColor(darkColor);
00226     painter->setPen(pn);
00227     painter->drawArc(aRect, 225*16, 180*16);
00228 
00229     //
00230     // draw marker
00231     //
00232     if ( isValid() )
00233         drawMarker(painter, d_data->angle, buttonTextColor);
00234 }
00235 
00242 void QwtKnob::valueChange()
00243 {
00244     recalcAngle();
00245     update();
00246     QwtAbstractSlider::valueChange();
00247 }
00248 
00255 double QwtKnob::getValue(const QPoint &p)
00256 {
00257     const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00258     const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00259 
00260     const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00261 
00262     double newValue =  0.5 * (minValue() + maxValue())
00263        + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00264       / d_data->totalAngle;
00265 
00266     const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00267     const double eqValue = value() + mouseOffset();
00268 
00269     if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00270     {
00271         if (newValue < eqValue)
00272            newValue += oneTurn;
00273         else
00274            newValue -= oneTurn;
00275     }
00276 
00277     return newValue;    
00278 }
00279 
00286 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00287 {
00288     const int r = d_data->knobRect.width() / 2;
00289 
00290     const int dx = d_data->knobRect.x() + r - p.x();
00291     const int dy = d_data->knobRect.y() + r - p.y();
00292 
00293     if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
00294     {
00295         scrollMode = ScrMouse;
00296         direction = 0;
00297     }
00298     else                                // point lies outside
00299     {
00300         scrollMode = ScrTimer;
00301         double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00302         if ( arc < d_data->angle)
00303            direction = -1;
00304         else if (arc > d_data->angle)
00305            direction = 1;
00306         else
00307            direction = 0;
00308     }
00309 }
00310 
00311 
00317 void QwtKnob::rangeChange()
00318 {
00319     if (autoScale())
00320         rescale(minValue(), maxValue());
00321 
00322     layoutKnob();
00323     recalcAngle();
00324 }
00325 
00329 void QwtKnob::resizeEvent(QResizeEvent *)
00330 {
00331     layoutKnob( false );
00332 }
00333 
00335 //  the current rect and fonts.
00336 //  \param update_geometry  notify the layout system and call update
00337 //         to redraw the scale
00338 void QwtKnob::layoutKnob( bool update_geometry )
00339 {
00340     const QRect r = rect();
00341     const int radius = d_data->knobWidth / 2;
00342 
00343     d_data->knobRect.setWidth(2 * radius);
00344     d_data->knobRect.setHeight(2 * radius);
00345     d_data->knobRect.moveCenter(r.center());
00346 
00347     scaleDraw()->setRadius(radius + d_data->scaleDist);
00348     scaleDraw()->moveCenter(r.center());
00349 
00350     if ( update_geometry )
00351     {
00352         updateGeometry();
00353         update();
00354     }
00355 }
00356 
00360 void QwtKnob::paintEvent(QPaintEvent *e)
00361 {
00362     const QRect &ur = e->rect();
00363     if ( ur.isValid() ) 
00364     {
00365 #if QT_VERSION < 0x040000
00366         QwtPaintBuffer paintBuffer(this, ur);
00367         draw(paintBuffer.painter(), ur);
00368 #else
00369         QPainter painter(this);
00370         painter.setRenderHint(QPainter::Antialiasing);
00371         draw(&painter, ur);
00372 #endif
00373     }
00374 }
00375 
00379 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00380 {
00381     if ( !d_data->knobRect.contains( ur ) ) // event from valueChange()
00382     {
00383 #if QT_VERSION < 0x040000
00384         scaleDraw()->draw( painter, colorGroup() );
00385 #else
00386         scaleDraw()->draw( painter, palette() );
00387 #endif
00388     }
00389 
00390     drawKnob( painter, d_data->knobRect );
00391 
00392     if ( hasFocus() )
00393         QwtPainter::drawFocusRect(painter, this);
00394 }
00395 
00402 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00403 {
00404     const double rarc = arc * M_PI / 180.0;
00405     const double ca = cos(rarc);
00406     const double sa = - sin(rarc);
00407 
00408     int radius = d_data->knobRect.width() / 2 - d_data->borderWidth;
00409     if (radius < 3) 
00410         radius = 3; 
00411 
00412     const int ym = d_data->knobRect.y() + radius + d_data->borderWidth;
00413     const int xm = d_data->knobRect.x() + radius + d_data->borderWidth;
00414 
00415     switch (d_data->symbol)
00416     {
00417         case Dot:
00418         {
00419             p->setBrush(c);
00420             p->setPen(Qt::NoPen);
00421 
00422             const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00423             p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00424                    ym - qRound(ca * rb) - d_data->dotWidth / 2,
00425                    d_data->dotWidth, d_data->dotWidth);
00426             break;
00427         }
00428         case Line:
00429         {
00430             p->setPen(QPen(c, 2));
00431 
00432             const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00433             const double re = qwtMax(double(radius - 4), 0.0);
00434             
00435             p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00436                 xm - qRound(sa * re), ym - qRound(ca * re));
00437             
00438             break;
00439         }
00440     }
00441 }
00442 
00449 void QwtKnob::setKnobWidth(int w)
00450 {
00451     d_data->knobWidth = qwtMax(w,5);
00452     layoutKnob();
00453 }
00454 
00456 int QwtKnob::knobWidth() const 
00457 {
00458     return d_data->knobWidth;
00459 }
00460 
00465 void QwtKnob::setBorderWidth(int bw)
00466 {
00467     d_data->borderWidth = qwtMax(bw, 0);
00468     layoutKnob();
00469 }
00470 
00472 int QwtKnob::borderWidth() const 
00473 {
00474     return d_data->borderWidth;
00475 }
00476 
00481 void QwtKnob::recalcAngle()
00482 {
00483     //
00484     // calculate the angle corresponding to the value
00485     //
00486     if (maxValue() == minValue())
00487     {
00488         d_data->angle = 0;
00489         d_data->nTurns = 0;
00490     }
00491     else
00492     {
00493         d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00494             / (maxValue() - minValue()) * d_data->totalAngle;
00495         d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00496         d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00497     }
00498 }
00499 
00500 
00505 void QwtKnob::scaleChange()
00506 {
00507     layoutKnob();
00508 }
00509 
00514 void QwtKnob::fontChange(const QFont &f)
00515 {
00516     QwtAbstractSlider::fontChange( f );
00517     layoutKnob();
00518 }
00519 
00523 QSize QwtKnob::sizeHint() const
00524 {
00525     return minimumSizeHint();
00526 }
00527 
00533 QSize QwtKnob::minimumSizeHint() const
00534 {
00535     // Add the scale radial thickness to the knobWidth
00536     const int sh = scaleDraw()->extent( QPen(), font() );
00537     const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00538 
00539     return QSize( d, d );
00540 }

Generated on Sun Mar 22 16:54:07 2009 for Qwt User's Guide by  doxygen 1.5.0