Main Page | Class Hierarchy | Alphabetical List | Class List | 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 #include <qpalette.h>
00012 #include <qstyle.h>
00013 #include <qevent.h>
00014 #include "qwt_knob.h"
00015 #include "qwt_math.h"
00016 #include "qwt_paint_buffer.h"
00017 
00023 QwtKnob::QwtKnob(QWidget* parent, const char *name): 
00024     QwtSliderBase(Qt::Horizontal, parent, name, 
00025                 Qt::WRepaintNoErase|Qt::WResizeNoErase)
00026 {
00027     d_angle = 0.0;
00028     d_oldAngle = 0.0;
00029     d_nTurns = 0.0;
00030     d_borderWidth = 2;
00031     d_borderDist = 4;
00032     d_totalAngle = 270.0;
00033     d_scaleDist = 4;
00034     d_hasScale = 0;
00035     d_symbol = Line;
00036     d_maxScaleTicks = 11;
00037     d_knobWidth = 50;
00038     d_dotWidth = 8;
00039 
00040     scaleDraw()->setGeometry(
00041         0, 0, d_knobWidth + 2 * d_scaleDist, QwtScaleDraw::Round );
00042     setUpdateTime(50);
00043     setTotalAngle( 270.0 );
00044     recalcAngle();
00045     setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
00046 }
00047 
00049 QwtKnob::~QwtKnob()
00050 {
00051 }
00052 
00057 void QwtKnob::setSymbol(QwtKnob::Symbol s)
00058 {
00059     if ( d_symbol != s )
00060     {
00061         d_symbol = s;
00062         update();
00063     }
00064 }
00065 
00070 QwtKnob::Symbol QwtKnob::symbol() const
00071 {
00072     return d_symbol;
00073 }
00074 
00083 void QwtKnob::setTotalAngle (double angle)
00084 {
00085     if (angle < 10.0)
00086        d_totalAngle = 10.0;
00087     else
00088        d_totalAngle = angle;
00089     scaleDraw()->setAngleRange( -0.5 * d_totalAngle, 0.5 * d_totalAngle);
00090     layoutKnob();
00091 }
00092 
00093 
00099 void QwtKnob::drawKnob(QPainter *p, const QRect &r)
00100 {
00101     const int bw2 = d_borderWidth / 2;
00102 
00103     QRect aRect(r.x() + bw2, r.y() + bw2,
00104           r.width() - 2 * bw2, r.height() - 2 * bw2);
00105 
00106     //
00107     // draw button face
00108     //
00109     p->setBrush(colorGroup().brush(QColorGroup::Button));
00110     p->drawEllipse(aRect);
00111 
00112     //
00113     // draw button shades
00114     //
00115     QPen pn;
00116     pn.setWidth(d_borderWidth);
00117 
00118     pn.setColor(colorGroup().light());
00119     p->setPen(pn);
00120     p->drawArc(aRect, 45*16,180*16);
00121 
00122     pn.setColor(colorGroup().dark());
00123     p->setPen(pn);
00124     p->drawArc(aRect, 225*16,180*16);
00125 
00126     //
00127     // draw marker
00128     //
00129     if ( isValid() )
00130         drawMarker(p, d_angle, colorGroup().buttonText());
00131 }
00132 
00139 void QwtKnob::valueChange()
00140 {
00141     recalcAngle();
00142     update();
00143     QwtSliderBase::valueChange();
00144 }
00145 
00152 double QwtKnob::getValue(const QPoint &p)
00153 {
00154     const double dx = double((rect().x() + rect().width() / 2) - p.x() );
00155     const double dy = double((rect().y() + rect().height() / 2) - p.y() );
00156 
00157     const double arc = atan2(-dx,dy) * 180.0 / M_PI;
00158 
00159     double newValue =  0.5 * (minValue() + maxValue())
00160        + (arc + d_nTurns * 360.0) * (maxValue() - minValue())
00161       / d_totalAngle;
00162 
00163     const double oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_totalAngle;
00164     const double eqValue = value() + d_mouseOffset;
00165 
00166     if (fabs(newValue - eqValue) > 0.5 * oneTurn)
00167     {
00168         if (newValue < eqValue)
00169            newValue += oneTurn;
00170         else
00171            newValue -= oneTurn;
00172     }
00173 
00174     return newValue;    
00175 }
00176 
00183 void QwtKnob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
00184 {
00185     const int r = d_kRect.width() / 2;
00186 
00187     const int dx = d_kRect.x() + r - p.x();
00188     const int dy = d_kRect.y() + r - p.y();
00189 
00190     if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
00191     {
00192         scrollMode = ScrMouse;
00193         direction = 0;
00194     }
00195     else                                // point lies outside
00196     {
00197         scrollMode = ScrTimer;
00198         double arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
00199         if ( arc < d_angle)
00200            direction = -1;
00201         else if (arc > d_angle)
00202            direction = 1;
00203         else
00204            direction = 0;
00205     }
00206 }
00207 
00208 
00214 void QwtKnob::rangeChange()
00215 {
00216     if (!hasUserScale())
00217     {
00218         scaleDraw()->setScale(minValue(), maxValue(),
00219             scaleMaxMajor(), scaleMaxMinor());
00220     }
00221     layoutKnob();
00222     recalcAngle();
00223 }
00224 
00228 void QwtKnob::resizeEvent(QResizeEvent *)
00229 {
00230     layoutKnob( FALSE );
00231 }
00232 
00234 //  the current rect and fonts.
00235 //  \param update_geometry  notify the layout system and call update
00236 //         to redraw the scale
00237 void QwtKnob::layoutKnob( bool update_geometry )
00238 {
00239     const QRect &r = rect();
00240 
00241     const int width = qwtMin(qwtMin(r.height(), r.width()), d_knobWidth);
00242     const int width_2 = width / 2;
00243 
00244     d_kRect.setRect(r.x() + r.width() / 2 - width_2,
00245             r.y() + r.height() / 2 - width_2,
00246             width, width);
00247 
00248     scaleDraw()->setGeometry(d_kRect.x() - d_scaleDist,
00249             d_kRect.y() - d_scaleDist,
00250             width + 2 * d_scaleDist, QwtScaleDraw::Round );
00251 
00252     if ( update_geometry )
00253     {
00254         updateGeometry();
00255         update();
00256     }
00257 }
00258 
00262 void QwtKnob::paintEvent(QPaintEvent *e)
00263 {
00264     const QRect &ur = e->rect();
00265     if ( ur.isValid() ) 
00266     {
00267         QwtPaintBuffer paintBuffer(this, ur);
00268         draw(paintBuffer.painter(), ur);
00269     }
00270 }
00271 
00275 void QwtKnob::draw(QPainter *painter, const QRect& ur)
00276 {
00277     if ( !d_kRect.contains( ur ) ) // event from valueChange()
00278         scaleDraw()->draw( painter );
00279     drawKnob( painter, d_kRect );
00280 
00281     if ( hasFocus() )
00282     {
00283         QRect r = rect();
00284 
00285 #if QT_VERSION < 300
00286         style().drawFocusRect(painter, r, colorGroup());
00287 #else
00288         style().drawPrimitive(QStyle::PE_FocusRect, painter,
00289             r, colorGroup());
00290 #endif
00291     }
00292 
00293 }
00294 
00301 void QwtKnob::drawMarker(QPainter *p, double arc, const QColor &c)
00302 {
00303     const double rarc = arc * M_PI / 180.0;
00304     const double ca = cos(rarc);
00305     const double sa = - sin(rarc);
00306 
00307     int radius = d_kRect.width() / 2 - d_borderWidth;
00308     if (radius < 3) 
00309         radius = 3; 
00310 
00311     const int ym = d_kRect.y() + radius + d_borderWidth;
00312     const int xm = d_kRect.x() + radius + d_borderWidth;
00313 
00314     switch (d_symbol)
00315     {
00316         case Dot:
00317         {
00318             p->setBrush(c);
00319             p->setPen(Qt::NoPen);
00320 
00321             const double rb = double(qwtMax(radius - 4 - d_dotWidth / 2, 0));
00322             p->drawEllipse(xm - int(floor (sa * rb + 0.5)) - d_dotWidth / 2,
00323                    ym - int(floor (ca * rb + 0.5)) - d_dotWidth / 2,
00324                    d_dotWidth, d_dotWidth);
00325             break;
00326         }
00327         case Line:
00328         {
00329             p->setPen(QPen(c, 2));
00330 
00331             const double rb = qwtMax(double((radius - 4) / 3.0), 0.0);
00332             const double re = qwtMax(double(radius - 4), 0.0);
00333             
00334             p->drawLine (xm - int (floor (sa * rb + 0.5)),
00335                  ym - int (floor (ca * rb + 0.5)),
00336                  xm - int (floor (sa * re + 0.5)),
00337                  ym - int (floor (ca * re + 0.5)));
00338             
00339             break;
00340         }
00341     }
00342 }
00343 
00350 void QwtKnob::setKnobWidth(int w)
00351 {
00352     d_knobWidth = qwtMax(w,5);
00353     layoutKnob();
00354 }
00355 
00360 void QwtKnob::setBorderWidth(int bw)
00361 {
00362     d_borderWidth = qwtMax(bw, 0);
00363     layoutKnob();
00364 }
00365 
00370 void QwtKnob::recalcAngle()
00371 {
00372     d_oldAngle = d_angle;
00373 
00374     //
00375     // calculate the angle corresponding to the value
00376     //
00377     if (maxValue() == minValue())
00378     {
00379         d_angle = 0;
00380         d_nTurns = 0;
00381     }
00382     else
00383     {
00384         d_angle = (value() - 0.5 * (minValue() + maxValue()))
00385             / (maxValue() - minValue()) * d_totalAngle;
00386         d_nTurns = floor((d_angle + 180.0) / 360.0);
00387         d_angle = d_angle - d_nTurns * 360.0;
00388     }
00389 }
00390 
00391 
00396 void QwtKnob::scaleChange()
00397 {
00398     layoutKnob();
00399 }
00400 
00405 void QwtKnob::fontChange(const QFont &f)
00406 {
00407     QwtSliderBase::fontChange( f );
00408     layoutKnob();
00409 }
00410 
00414 QSize QwtKnob::sizeHint() const
00415 {
00416     return minimumSizeHint();
00417 }
00418 
00424 QSize QwtKnob::minimumSizeHint() const
00425 {
00426     // Add the scale radial thickness to the knobWidth
00427     const int sh = scaleDraw()->minHeight( QPen(), fontMetrics() );
00428     const int d = 2 * sh + 2 * d_scaleDist + d_knobWidth;
00429 
00430     return QSize( d, d );
00431 }
00432 
00433 // Local Variables:
00434 // mode: C++
00435 // c-file-style: "stroustrup"
00436 // indent-tabs-mode: nil
00437 // End:

Generated on Sun Nov 21 11:12:43 2004 for Qwt User's Guide by doxygen 1.3.5