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_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         oldAngle = 0.0;
00030         nTurns = 0.0;
00031         borderWidth = 2;
00032         borderDist = 4;
00033         totalAngle = 270.0;
00034         scaleDist = 4;
00035         hasScale = 0;
00036         symbol = Line;
00037         maxScaleTicks = 11;
00038         knobWidth = 50;
00039         dotWidth = 8;
00040     }
00041 
00042     int borderWidth;
00043     int borderDist;
00044     int hasScale;
00045     int scaleDist;
00046     int maxScaleTicks;
00047     int knobWidth;
00048     int dotWidth;
00049 
00050     Symbol symbol;
00051     double angle;
00052     double oldAngle;
00053     double totalAngle;
00054     double nTurns;
00055 
00056     QRect kRect;
00057 };
00058 
00064 QwtKnob::QwtKnob(QWidget* parent): 
00065     QwtAbstractSlider(Qt::Horizontal, parent)
00066 {
00067 #if QT_VERSION < 0x040000
00068     setWFlags(Qt::WNoAutoErase);
00069 #endif
00070 
00071     d_data = new PrivateData;
00072 
00073     scaleDraw()->setGeometry(
00074         0, 0, d_data->knobWidth + 2 * d_data->scaleDist, QwtScaleDraw::Round );
00075     setUpdateTime(50);
00076     setTotalAngle( 270.0 );
00077     recalcAngle();
00078     setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00079 
00080     setRange(0.0, 10.0, 1.0);
00081     setValue(0.0);
00082 }
00083 
00085 QwtKnob::~QwtKnob()
00086 {
00087     delete d_data;
00088 }
00089 
00094 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00095 {
00096     if ( d_data->symbol != s )
00097     {
00098         d_data->symbol = s;
00099         update();
00100     }
00101 }
00102 
00107 QwtKnob::Symbol QwtKnob::symbol() const
00108 {
00109     return d_data->symbol;
00110 }
00111 
00120 void QwtKnob::setTotalAngle (double angle)
00121 {
00122     if (angle < 10.0)
00123        d_data->totalAngle = 10.0;
00124     else
00125        d_data->totalAngle = angle;
00126 
00127     scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle, 
00128         0.5 * d_data->totalAngle);
00129     layoutKnob();
00130 }
00131 
00133 double QwtKnob::totalAngle() const 
00134 {
00135     return d_data->totalAngle;
00136 }
00137 
00138 
00139 
00145 void QwtKnob::drawKnob(QPainter *p, const QRect &r)
00146 {
00147 #if QT_VERSION < 0x040000
00148     const QBrush buttonBrush = colorGroup().brush(QColorGroup::Button);
00149     const QColor buttonTextColor = colorGroup().buttonText();
00150     const QColor lightColor = colorGroup().light();
00151     const QColor darkColor = colorGroup().dark();
00152 #else
00153     const QBrush buttonBrush = palette().brush(QPalette::Button);
00154     const QColor buttonTextColor = palette().color(QPalette::ButtonText);
00155     const QColor lightColor = palette().color(QPalette::Light);
00156     const QColor darkColor = palette().color(QPalette::Dark);
00157 #endif
00158     const int bw2 = d_data->borderWidth / 2;
00159 
00160     QRect aRect(r.x() + bw2, r.y() + bw2,
00161           r.width() - 2 * bw2, r.height() - 2 * bw2);
00162 
00163     //
00164     // draw button face
00165     //
00166     p->setBrush(buttonBrush);
00167     p->drawEllipse(aRect);
00168 
00169     //
00170     // draw button shades
00171     //
00172     QPen pn;
00173     pn.setWidth(d_data->borderWidth);
00174 
00175     pn.setColor(lightColor);
00176     p->setPen(pn);
00177     p->drawArc(aRect, 45*16,180*16);
00178 
00179     pn.setColor(darkColor);
00180     p->setPen(pn);
00181     p->drawArc(aRect, 225*16,180*16);
00182 
00183     //
00184     // draw marker
00185     //
00186     if ( isValid() )
00187         drawMarker(p, d_data->angle, buttonTextColor);
00188 }
00189 
00196 void QwtKnob::valueChange()
00197 {
00198     recalcAngle();
00199     update();
00200     QwtAbstractSlider::valueChange();
00201 }
00202 
00209 double QwtKnob::getValue(const QPoint &p)
00210 {
00211     const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00212     const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00213 
00214     const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00215 
00216     double newValue =  0.5 * (minValue() + maxValue())
00217        + (arc + d_data->nTurns * 360.0) * (maxValue() - minValue())
00218       / d_data->totalAngle;
00219 
00220     const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_data->totalAngle;
00221     const double eqValue = value() + mouseOffset();
00222 
00223     if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00224     {
00225         if (newValue < eqValue)
00226            newValue += oneTurn;
00227         else
00228            newValue -= oneTurn;
00229     }
00230 
00231     return newValue;    
00232 }
00233 
00240 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00241 {
00242     const int r = d_data->kRect.width() / 2;
00243 
00244     const int dx = d_data->kRect.x() + r - p.x();
00245     const int dy = d_data->kRect.y() + r - p.y();
00246 
00247     if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
00248     {
00249         scrollMode = ScrMouse;
00250         direction = 0;
00251     }
00252     else                                // point lies outside
00253     {
00254         scrollMode = ScrTimer;
00255         double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00256         if ( arc < d_data->angle)
00257            direction = -1;
00258         else if (arc > d_data->angle)
00259            direction = 1;
00260         else
00261            direction = 0;
00262     }
00263 }
00264 
00265 
00271 void QwtKnob::rangeChange()
00272 {
00273     if (autoScale())
00274         rescale(minValue(), maxValue());
00275 
00276     layoutKnob();
00277     recalcAngle();
00278 }
00279 
00283 void QwtKnob::resizeEvent(QResizeEvent *)
00284 {
00285     layoutKnob( false );
00286 }
00287 
00289 //  the current rect and fonts.
00290 //  \param update_geometry  notify the layout system and call update
00291 //         to redraw the scale
00292 void QwtKnob::layoutKnob( bool update_geometry )
00293 {
00294     const QRect &r = rect();
00295 
00296     const int width = qwtMin(qwtMin(r.height(), r.width()), d_data->knobWidth);
00297     const int width_2 = width / 2;
00298 
00299     d_data->kRect.setRect(r.x() + r.width() / 2 - width_2,
00300             r.y() + r.height() / 2 - width_2,
00301             width, width);
00302 
00303     scaleDraw()->setGeometry(d_data->kRect.x() - d_data->scaleDist,
00304             d_data->kRect.y() - d_data->scaleDist,
00305             width + 2 * d_data->scaleDist, QwtScaleDraw::Round );
00306 
00307     if ( update_geometry )
00308     {
00309         updateGeometry();
00310         update();
00311     }
00312 }
00313 
00317 void QwtKnob::paintEvent(QPaintEvent *e)
00318 {
00319     const QRect &ur = e->rect();
00320     if ( ur.isValid() ) 
00321     {
00322 #if QT_VERSION < 0x040000
00323         QwtPaintBuffer paintBuffer(this, ur);
00324         draw(paintBuffer.painter(), ur);
00325 #else
00326         QPainter painter(this);
00327         if ( paintEngine()->hasFeature(QPaintEngine::Antialiasing) )
00328             painter.setRenderHint(QPainter::Antialiasing);
00329         draw(&painter, ur);
00330 #endif
00331     }
00332 }
00333 
00337 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00338 {
00339     if ( !d_data->kRect.contains( ur ) ) // event from valueChange()
00340     {
00341 #if QT_VERSION < 0x040000
00342         scaleDraw()->draw( painter, colorGroup() );
00343 #else
00344         scaleDraw()->draw( painter, palette() );
00345 #endif
00346     }
00347 
00348     drawKnob( painter, d_data->kRect );
00349 
00350     if ( hasFocus() )
00351         QwtPainter::drawFocusRect(painter, this);
00352 }
00353 
00360 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00361 {
00362     const double rarc = arc * M_PI / 180.0;
00363     const double ca = cos(rarc);
00364     const double sa = - sin(rarc);
00365 
00366     int radius = d_data->kRect.width() / 2 - d_data->borderWidth;
00367     if (radius < 3) 
00368         radius = 3; 
00369 
00370     const int ym = d_data->kRect.y() + radius + d_data->borderWidth;
00371     const int xm = d_data->kRect.x() + radius + d_data->borderWidth;
00372 
00373     switch (d_data->symbol)
00374     {
00375         case Dot:
00376         {
00377             p->setBrush(c);
00378             p->setPen(Qt::NoPen);
00379 
00380             const double rb = double(qwtMax(radius - 4 - d_data->dotWidth / 2, 0));
00381             p->drawEllipse(xm - qRound(sa * rb) - d_data->dotWidth / 2,
00382                    ym - qRound(ca * rb) - d_data->dotWidth / 2,
00383                    d_data->dotWidth, d_data->dotWidth);
00384             break;
00385         }
00386         case Line:
00387         {
00388             p->setPen(QPen(c, 2));
00389 
00390             const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00391             const double re = qwtMax(double(radius - 4), 0.0);
00392             
00393             p->drawLine ( xm - qRound(sa * rb), ym - qRound(ca * rb),
00394                 xm - qRound(sa * re), ym - qRound(ca * re));
00395             
00396             break;
00397         }
00398     }
00399 }
00400 
00407 void QwtKnob::setKnobWidth(int w)
00408 {
00409     d_data->knobWidth = qwtMax(w,5);
00410     layoutKnob();
00411 }
00412 
00414 int QwtKnob::knobWidth() const 
00415 {
00416     return d_data->knobWidth;
00417 }
00418 
00423 void QwtKnob::setBorderWidth(int bw)
00424 {
00425     d_data->borderWidth = qwtMax(bw, 0);
00426     layoutKnob();
00427 }
00428 
00430 int QwtKnob::borderWidth() const 
00431 {
00432     return d_data->borderWidth;
00433 }
00434 
00439 void QwtKnob::recalcAngle()
00440 {
00441     d_data->oldAngle = d_data->angle;
00442 
00443     //
00444     // calculate the angle corresponding to the value
00445     //
00446     if (maxValue() == minValue())
00447     {
00448         d_data->angle = 0;
00449         d_data->nTurns = 0;
00450     }
00451     else
00452     {
00453         d_data->angle = (value() - 0.5 * (minValue() + maxValue()))
00454             / (maxValue() - minValue()) * d_data->totalAngle;
00455         d_data->nTurns = floor((d_data->angle + 180.0) / 360.0);
00456         d_data->angle = d_data->angle - d_data->nTurns * 360.0;
00457     }
00458 }
00459 
00460 
00465 void QwtKnob::scaleChange()
00466 {
00467     layoutKnob();
00468 }
00469 
00474 void QwtKnob::fontChange(const QFont &f)
00475 {
00476     QwtAbstractSlider::fontChange( f );
00477     layoutKnob();
00478 }
00479 
00483 QSize QwtKnob::sizeHint() const
00484 {
00485     return minimumSizeHint();
00486 }
00487 
00493 QSize QwtKnob::minimumSizeHint() const
00494 {
00495     // Add the scale radial thickness to the knobWidth
00496     const int sh = scaleDraw()->minHeight( QPen(), font() );
00497     const int d = 2 * sh + 2 * d_data->scaleDist + d_data->knobWidth;
00498 
00499     return QSize( d, d );
00500 }

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