qwt_wheel.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 <qevent.h>
00011 #include <qdrawutil.h>
00012 #include <qpainter.h>
00013 #include <qstyle.h>
00014 #include "qwt_math.h"
00015 #include "qwt_painter.h"
00016 #include "qwt_paint_buffer.h"
00017 #include "qwt_wheel.h"
00018 
00019 #define NUM_COLORS 30
00020 
00021 class QwtWheel::PrivateData
00022 {
00023 public:
00024     PrivateData()
00025     {
00026         viewAngle = 175.0;
00027         totalAngle = 360.0;
00028         tickCnt = 10;
00029         intBorder = 2;
00030         borderWidth = 2;
00031         wheelWidth = 20;
00032 #if QT_VERSION < 0x040000
00033         allocContext = 0;
00034 #endif
00035     };
00036 
00037     QRect sliderRect;
00038     double viewAngle;
00039     double totalAngle;
00040     int tickCnt;
00041     int intBorder;
00042     int borderWidth;
00043     int wheelWidth;
00044 #if QT_VERSION < 0x040000
00045     int allocContext;
00046 #endif
00047     QColor colors[NUM_COLORS];
00048 };
00049 
00051 QwtWheel::QwtWheel(QWidget *parent): 
00052     QwtAbstractSlider(Qt::Horizontal, parent)
00053 {
00054     initWheel();
00055 }
00056 
00057 #if QT_VERSION < 0x040000
00058 QwtWheel::QwtWheel(QWidget *parent, const char *name): 
00059     QwtAbstractSlider(Qt::Horizontal, parent)
00060 {
00061     setName(name);
00062     initWheel();
00063 }
00064 #endif
00065 
00066 void QwtWheel::initWheel()
00067 {
00068     d_data = new PrivateData;
00069 
00070 #if QT_VERSION < 0x040000
00071     setWFlags(Qt::WNoAutoErase);
00072 #endif
00073 
00074     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00075 
00076 #if QT_VERSION >= 0x040000
00077     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00078 #else
00079     clearWState( WState_OwnSizePolicy );
00080 #endif
00081 
00082     setUpdateTime(50);
00083 }
00084 
00086 QwtWheel::~QwtWheel()  
00087 {
00088 #if QT_VERSION < 0x040000
00089     if ( d_data->allocContext )
00090         QColor::destroyAllocContext( d_data->allocContext );
00091 #endif
00092     delete d_data;
00093 }
00094 
00096 void QwtWheel::setColorArray()
00097 {
00098     if ( !d_data->colors ) 
00099         return;
00100 
00101 #if QT_VERSION < 0x040000
00102     const QColor light = colorGroup().light();
00103     const QColor dark = colorGroup().dark();
00104 #else
00105     const QColor light = palette().color(QPalette::Light);
00106     const QColor dark = palette().color(QPalette::Dark);
00107 #endif
00108 
00109     if ( !d_data->colors[0].isValid() ||
00110         d_data->colors[0] != light ||
00111         d_data->colors[NUM_COLORS - 1] != dark )
00112     {
00113 #if QT_VERSION < 0x040000
00114         if ( d_data->allocContext )
00115             QColor::destroyAllocContext( d_data->allocContext );
00116 
00117         d_data->allocContext = QColor::enterAllocContext();
00118 #endif
00119 
00120         d_data->colors[0] = light;
00121         d_data->colors[NUM_COLORS - 1] = dark;
00122 
00123         int dh, ds, dv, lh, ls, lv;
00124 #if QT_VERSION < 0x040000
00125         d_data->colors[0].rgb(&lh, &ls, &lv);
00126         d_data->colors[NUM_COLORS - 1].rgb(&dh, &ds, &dv);
00127 #else
00128         d_data->colors[0].getRgb(&lh, &ls, &lv);
00129         d_data->colors[NUM_COLORS - 1].getRgb(&dh, &ds, &dv);
00130 #endif
00131 
00132         for ( int i = 1; i < NUM_COLORS - 1; ++i )
00133         {
00134             const double factor = double(i) / double(NUM_COLORS);
00135 
00136             d_data->colors[i].setRgb( lh + int( double(dh - lh) * factor ),
00137                       ls + int( double(ds - ls) * factor ),
00138                       lv + int( double(dv - lv) * factor ));
00139         }
00140 #if QT_VERSION < 0x040000
00141         QColor::leaveAllocContext();
00142 #endif
00143     }
00144 }
00145 
00154 void QwtWheel::setTickCnt(int cnt)
00155 {
00156     d_data->tickCnt = qwtLim( cnt, 6, 50 );
00157     update();
00158 }
00159 
00160 int QwtWheel::tickCnt() const 
00161 {
00162     return d_data->tickCnt;
00163 }
00164 
00168 double QwtWheel::mass() const
00169 {
00170     return QwtAbstractSlider::mass();
00171 }
00172 
00183 void QwtWheel::setInternalBorder( int w )
00184 {
00185     const int d = qwtMin( width(), height() ) / 3;
00186     w = qwtMin( w, d );
00187     d_data->intBorder = qwtMax( w, 1 );
00188     layoutWheel();
00189 }
00190 
00191 int QwtWheel::internalBorder() const 
00192 {
00193     return d_data->intBorder;
00194 }
00195 
00197 void QwtWheel::drawWheelBackground( QPainter *p, const QRect &r )
00198 {
00199     p->save();
00200 
00201     //
00202     // initialize pens
00203     //
00204 #if QT_VERSION < 0x040000
00205     const QColor light = colorGroup().light();
00206     const QColor dark = colorGroup().dark();
00207 #else
00208     const QColor light = palette().color(QPalette::Light);
00209     const QColor dark = palette().color(QPalette::Dark);
00210 #endif
00211 
00212     QPen lightPen;
00213     lightPen.setColor(light);
00214     lightPen.setWidth(d_data->intBorder);
00215 
00216     QPen darkPen;
00217     darkPen.setColor(dark);
00218     darkPen.setWidth(d_data->intBorder);
00219 
00220     setColorArray();
00221 
00222     //
00223     // initialize auxiliary variables
00224     //
00225 
00226     const int nFields = NUM_COLORS * 13 / 10;
00227     const int hiPos = nFields - NUM_COLORS + 1;
00228 
00229     if ( orientation() == Qt::Horizontal )
00230     {
00231         const int rx = r.x();
00232         int ry = r.y() + d_data->intBorder;
00233         const int rh = r.height() - 2* d_data->intBorder;
00234         const int rw = r.width();
00235         //
00236         //  draw shaded background
00237         //
00238         int x1 = rx;
00239         for (int i = 1; i < nFields; i++ )
00240         {
00241             const int x2 = rx + (rw * i) / nFields;
00242             p->fillRect(x1, ry, x2-x1 + 1 ,rh, d_data->colors[qwtAbs(i-hiPos)]);
00243             x1 = x2 + 1;
00244         }
00245         p->fillRect(x1, ry, rw - (x1 - rx), rh, d_data->colors[NUM_COLORS - 1]);
00246 
00247         //
00248         // draw internal border
00249         //
00250         p->setPen(lightPen);
00251         ry = r.y() + d_data->intBorder / 2;
00252         p->drawLine(r.x(), ry, r.x() + r.width() , ry);
00253 
00254         p->setPen(darkPen);
00255         ry = r.y() + r.height() - (d_data->intBorder - d_data->intBorder / 2);
00256         p->drawLine(r.x(), ry , r.x() + r.width(), ry);
00257     }
00258     else // Qt::Vertical
00259     {
00260         int rx = r.x() + d_data->intBorder;
00261         const int ry = r.y();
00262         const int rh = r.height();
00263         const int rw = r.width() - 2 * d_data->intBorder;
00264 
00265         //
00266         // draw shaded background
00267         //
00268         int y1 = ry;
00269         for ( int i = 1; i < nFields; i++ )
00270         {
00271             const int y2 = ry + (rh * i) / nFields;
00272             p->fillRect(rx, y1, rw, y2-y1 + 1, d_data->colors[qwtAbs(i-hiPos)]);
00273             y1 = y2 + 1;
00274         }
00275         p->fillRect(rx, y1, rw, rh - (y1 - ry), d_data->colors[NUM_COLORS - 1]);
00276 
00277         //
00278         //  draw internal borders
00279         //
00280         p->setPen(lightPen);
00281         rx = r.x() + d_data->intBorder / 2;
00282         p->drawLine(rx, r.y(), rx, r.y() + r.height());
00283 
00284         p->setPen(darkPen);
00285         rx = r.x() + r.width() - (d_data->intBorder - d_data->intBorder / 2);
00286         p->drawLine(rx, r.y(), rx , r.y() + r.height());
00287     }
00288 
00289     p->restore();
00290 }
00291 
00292 
00304 void QwtWheel::setTotalAngle(double angle)
00305 {
00306     if ( angle < 0.0 )
00307         angle = 0.0;
00308 
00309     d_data->totalAngle = angle;
00310     update();
00311 }
00312 
00313 double QwtWheel::totalAngle() const 
00314 {
00315     return d_data->totalAngle;
00316 }
00317 
00325 void QwtWheel::setOrientation(Qt::Orientation o)
00326 {
00327     if ( orientation() == o )
00328         return;
00329 
00330 #if QT_VERSION >= 0x040000
00331     if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
00332 #else
00333     if ( !testWState( WState_OwnSizePolicy ) ) 
00334 #endif
00335     {
00336         QSizePolicy sp = sizePolicy();
00337         sp.transpose();
00338         setSizePolicy(sp);
00339 
00340 #if QT_VERSION >= 0x040000
00341         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00342 #else
00343         clearWState( WState_OwnSizePolicy );
00344 #endif
00345     }
00346 
00347     QwtAbstractSlider::setOrientation(o);
00348     layoutWheel();
00349 }
00350 
00359 void QwtWheel::setViewAngle(double angle)
00360 {
00361     d_data->viewAngle = qwtLim( angle, 10.0, 175.0 );
00362     update();
00363 }
00364 
00365 double QwtWheel::viewAngle() const 
00366 {
00367     return d_data->viewAngle;
00368 }
00369 
00375 void QwtWheel::drawWheel( QPainter *p, const QRect &r )
00376 {
00377     //
00378     // draw background gradient
00379     //
00380     drawWheelBackground( p, r );
00381 
00382     if ( maxValue() == minValue() || d_data->totalAngle == 0.0 )
00383         return;
00384 
00385 #if QT_VERSION < 0x040000
00386     const QColor light = colorGroup().light();
00387     const QColor dark = colorGroup().dark();
00388 #else
00389     const QColor light = palette().color(QPalette::Light);
00390     const QColor dark = palette().color(QPalette::Dark);
00391 #endif
00392 
00393     const double sign = (minValue() < maxValue()) ? 1.0 : -1.0;
00394     double cnvFactor = qwtAbs(d_data->totalAngle / (maxValue() - minValue()));
00395     const double halfIntv = 0.5 * d_data->viewAngle / cnvFactor;
00396     const double loValue = value() - halfIntv;
00397     const double hiValue = value() + halfIntv;
00398     const double tickWidth = 360.0 / double(d_data->tickCnt) / cnvFactor;
00399     const double sinArc = sin(d_data->viewAngle * M_PI / 360.0);
00400     cnvFactor *= M_PI / 180.0;
00401 
00402 
00403     //
00404     // draw grooves
00405     //
00406     if ( orientation() == Qt::Horizontal )
00407     {
00408         const double halfSize = double(r.width()) * 0.5;
00409 
00410         int l1 = r.y() + d_data->intBorder;
00411         int l2 = r.y() + r.height() - d_data->intBorder - 1;
00412 
00413         // draw one point over the border if border > 1
00414         if ( d_data->intBorder > 1 )
00415         {
00416             l1 --;
00417             l2 ++;
00418         }
00419 
00420         const int maxpos = r.x() + r.width() - 2;
00421         const int minpos = r.x() + 2;
00422 
00423         //
00424         // draw tick marks
00425         //
00426         for ( double tickValue = ceil(loValue / tickWidth) * tickWidth;
00427             tickValue < hiValue; tickValue += tickWidth )
00428         {
00429             //
00430             //  calculate position
00431             //
00432             const int tickPos = r.x() + r.width()
00433                 - int( halfSize
00434                     * (sinArc + sign *  sin((tickValue - value()) * cnvFactor))
00435                     / sinArc);
00436             //
00437             // draw vertical line
00438             //
00439             if ( (tickPos <= maxpos) && (tickPos > minpos) )
00440             {
00441                 p->setPen(dark);
00442                 p->drawLine(tickPos -1 , l1, tickPos - 1,  l2 );  
00443                 p->setPen(light);
00444                 p->drawLine(tickPos, l1, tickPos, l2);  
00445             }
00446         }
00447     }
00448     else if ( orientation() == Qt::Vertical )
00449     {
00450         const double halfSize = double(r.height()) * 0.5;
00451 
00452         int l1 = r.x() + d_data->intBorder;
00453         int l2 = r.x() + r.width() - d_data->intBorder - 1;
00454 
00455         if ( d_data->intBorder > 1 )
00456         {
00457             l1--;
00458             l2++;
00459         }
00460 
00461         const int maxpos = r.y() + r.height() - 2;
00462         const int minpos = r.y() + 2;
00463 
00464         //
00465         // draw tick marks
00466         //
00467         for ( double tickValue = ceil(loValue / tickWidth) * tickWidth;
00468             tickValue < hiValue; tickValue += tickWidth )
00469         {
00470 
00471             //
00472             // calculate position
00473             //
00474             const int tickPos = r.y() + int( halfSize *
00475                 (sinArc + sign * sin((tickValue - value()) * cnvFactor))
00476                 / sinArc);
00477 
00478             //
00479             //  draw horizontal line
00480             //
00481             if ( (tickPos <= maxpos) && (tickPos > minpos) )
00482             {
00483                 p->setPen(dark);
00484                 p->drawLine(l1, tickPos - 1 ,l2, tickPos - 1);  
00485                 p->setPen(light);
00486                 p->drawLine(l1, tickPos, l2, tickPos);  
00487             }
00488         }
00489     }
00490 }
00491 
00492 
00494 double QwtWheel::getValue( const QPoint &p )
00495 {
00496     // The reference position is arbitrary, but the
00497     // sign of the offset is important
00498     int w, dx;
00499     if ( orientation() == Qt::Vertical )
00500     {
00501         w = d_data->sliderRect.height();
00502         dx = d_data->sliderRect.y() - p.y();
00503     }
00504     else
00505     {
00506         w = d_data->sliderRect.width();
00507         dx = p.x() - d_data->sliderRect.x();
00508     }
00509 
00510     // w pixels is an arc of viewAngle degrees,
00511     // so we convert change in pixels to change in angle
00512     const double ang = dx * d_data->viewAngle / w;
00513 
00514     // value range maps to totalAngle degrees,
00515     // so convert the change in angle to a change in value
00516     const double val = ang * ( maxValue() - minValue() ) / d_data->totalAngle;
00517 
00518     // Note, range clamping and rasterizing to step is automatically
00519     // handled by QwtAbstractSlider, so we simply return the change in value
00520     return val;
00521 }
00522 
00524 void QwtWheel::resizeEvent(QResizeEvent *)
00525 {
00526     layoutWheel( false );
00527 }
00528 
00530 //  the current rect and fonts.
00531 //  \param update_geometry  notify the layout system and call update
00532 //         to redraw the scale
00533 void QwtWheel::layoutWheel( bool update_geometry )
00534 {
00535     const QRect r = this->rect();
00536     d_data->sliderRect.setRect(r.x() + d_data->borderWidth, r.y() + d_data->borderWidth,
00537         r.width() - 2*d_data->borderWidth, r.height() - 2*d_data->borderWidth);
00538 
00539     if ( update_geometry )
00540     {
00541         updateGeometry();
00542         update();
00543     }
00544 }
00545 
00547 void QwtWheel::paintEvent(QPaintEvent *e)
00548 {
00549     // Use double-buffering
00550     const QRect &ur = e->rect();
00551     if ( ur.isValid() )
00552     {
00553 #if QT_VERSION < 0x040000
00554         QwtPaintBuffer paintBuffer(this, ur);
00555         draw(paintBuffer.painter(), ur);
00556 #else
00557         QPainter painter(this);
00558         draw(&painter, ur);
00559 #endif
00560     }
00561 }
00562 
00564 void QwtWheel::draw(QPainter *painter, const QRect&)
00565 {
00566     qDrawShadePanel( painter, rect().x(), rect().y(),
00567         rect().width(), rect().height(),
00568 #if QT_VERSION < 0x040000
00569         colorGroup(), 
00570 #else
00571         palette(), 
00572 #endif
00573         true, d_data->borderWidth );
00574 
00575     drawWheel( painter, d_data->sliderRect );
00576 
00577     if ( hasFocus() )
00578         QwtPainter::drawFocusRect(painter, this);
00579 }
00580 
00582 void QwtWheel::valueChange()
00583 {
00584     QwtAbstractSlider::valueChange();
00585     update();
00586 }
00587 
00588 
00596 void QwtWheel::getScrollMode( const QPoint &p, int &scrollMode, int &direction)
00597 {
00598     if ( d_data->sliderRect.contains(p) )
00599         scrollMode = ScrMouse;
00600     else
00601         scrollMode = ScrNone;
00602 
00603     direction = 0;
00604 }
00605 
00612 void QwtWheel::setMass(double val)
00613 {
00614     QwtAbstractSlider::setMass(val);
00615 }
00616 
00624 void QwtWheel::setWheelWidth(int w)
00625 {
00626     d_data->wheelWidth = w;
00627     layoutWheel();
00628 }
00629 
00633 QSize QwtWheel::sizeHint() const
00634 {
00635     return minimumSizeHint();
00636 }
00637 
00642 QSize QwtWheel::minimumSizeHint() const
00643 {
00644     QSize sz( 3*d_data->wheelWidth + 2*d_data->borderWidth,
00645     d_data->wheelWidth + 2*d_data->borderWidth );
00646     if ( orientation() != Qt::Horizontal )
00647         sz.transpose();
00648     return sz;
00649 }
00650 
00654 void QwtWheel::paletteChange( const QPalette& )
00655 {
00656     update();
00657 }
00658 

Generated on Mon Feb 26 21:22:39 2007 for Qwt User's Guide by  doxygen 1.4.6