Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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     d_data = new PrivateData;
00055 
00056 #if QT_VERSION < 0x040000
00057     setWFlags(Qt::WNoAutoErase);
00058 #endif
00059 
00060     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00061 
00062 #if QT_VERSION >= 0x040000
00063     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00064 #else
00065     clearWState( WState_OwnSizePolicy );
00066 #endif
00067 
00068     setUpdateTime(50);
00069 }
00070 
00072 QwtWheel::~QwtWheel()  
00073 {
00074 #if QT_VERSION < 0x040000
00075     if ( d_data->allocContext )
00076         QColor::destroyAllocContext( d_data->allocContext );
00077 #endif
00078     delete d_data;
00079 }
00080 
00082 void QwtWheel::setColorArray()
00083 {
00084     if ( !d_data->colors ) 
00085         return;
00086 
00087 #if QT_VERSION < 0x040000
00088     const QColor light = colorGroup().light();
00089     const QColor dark = colorGroup().dark();
00090 #else
00091     const QColor light = palette().color(QPalette::Light);
00092     const QColor dark = palette().color(QPalette::Dark);
00093 #endif
00094 
00095     if ( !d_data->colors[0].isValid() ||
00096         d_data->colors[0] != light ||
00097         d_data->colors[NUM_COLORS - 1] != dark )
00098     {
00099 #if QT_VERSION < 0x040000
00100         if ( d_data->allocContext )
00101             QColor::destroyAllocContext( d_data->allocContext );
00102 
00103         d_data->allocContext = QColor::enterAllocContext();
00104 #endif
00105 
00106         d_data->colors[0] = light;
00107         d_data->colors[NUM_COLORS - 1] = dark;
00108 
00109         int dh, ds, dv, lh, ls, lv;
00110 #if QT_VERSION < 0x040000
00111         d_data->colors[0].rgb(&lh, &ls, &lv);
00112         d_data->colors[NUM_COLORS - 1].rgb(&dh, &ds, &dv);
00113 #else
00114         d_data->colors[0].getRgb(&lh, &ls, &lv);
00115         d_data->colors[NUM_COLORS - 1].getRgb(&dh, &ds, &dv);
00116 #endif
00117 
00118         for ( int i = 1; i < NUM_COLORS - 1; ++i )
00119         {
00120             const double factor = double(i) / double(NUM_COLORS);
00121 
00122             d_data->colors[i].setRgb( lh + int( double(dh - lh) * factor ),
00123                       ls + int( double(ds - ls) * factor ),
00124                       lv + int( double(dv - lv) * factor ));
00125         }
00126 #if QT_VERSION < 0x040000
00127         QColor::leaveAllocContext();
00128 #endif
00129     }
00130 }
00131 
00140 void QwtWheel::setTickCnt(int cnt)
00141 {
00142     d_data->tickCnt = qwtLim( cnt, 6, 50 );
00143     update();
00144 }
00145 
00146 int QwtWheel::tickCnt() const 
00147 {
00148     return d_data->tickCnt;
00149 }
00150 
00154 double QwtWheel::mass() const
00155 {
00156     return QwtAbstractSlider::mass();
00157 }
00158 
00169 void QwtWheel::setInternalBorder( int w )
00170 {
00171     const int d = qwtMin( width(), height() ) / 3;
00172     w = qwtMin( w, d );
00173     d_data->intBorder = qwtMax( w, 1 );
00174     layoutWheel();
00175 }
00176 
00177 int QwtWheel::internalBorder() const 
00178 {
00179     return d_data->intBorder;
00180 }
00181 
00183 void QwtWheel::drawWheelBackground( QPainter *p, const QRect &r )
00184 {
00185     p->save();
00186 
00187     //
00188     // initialize pens
00189     //
00190 #if QT_VERSION < 0x040000
00191     const QColor light = colorGroup().light();
00192     const QColor dark = colorGroup().dark();
00193 #else
00194     const QColor light = palette().color(QPalette::Light);
00195     const QColor dark = palette().color(QPalette::Dark);
00196 #endif
00197 
00198     QPen lightPen;
00199     lightPen.setColor(light);
00200     lightPen.setWidth(d_data->intBorder);
00201 
00202     QPen darkPen;
00203     darkPen.setColor(dark);
00204     darkPen.setWidth(d_data->intBorder);
00205 
00206     setColorArray();
00207 
00208     //
00209     // initialize auxiliary variables
00210     //
00211 
00212     const int nFields = NUM_COLORS * 13 / 10;
00213     const int hiPos = nFields - NUM_COLORS + 1;
00214 
00215     if ( orientation() == Qt::Horizontal )
00216     {
00217         const int rx = r.x();
00218         int ry = r.y() + d_data->intBorder;
00219         const int rh = r.height() - 2* d_data->intBorder;
00220         const int rw = r.width();
00221         //
00222         //  draw shaded background
00223         //
00224         int x1 = rx;
00225         for (int i = 1; i < nFields; i++ )
00226         {
00227             const int x2 = rx + (rw * i) / nFields;
00228             p->fillRect(x1, ry, x2-x1 + 1 ,rh, d_data->colors[qwtAbs(i-hiPos)]);
00229             x1 = x2 + 1;
00230         }
00231         p->fillRect(x1, ry, rw - (x1 - rx), rh, d_data->colors[NUM_COLORS - 1]);
00232 
00233         //
00234         // draw internal border
00235         //
00236         p->setPen(lightPen);
00237         ry = r.y() + d_data->intBorder / 2;
00238         p->drawLine(r.x(), ry, r.x() + r.width() , ry);
00239 
00240         p->setPen(darkPen);
00241         ry = r.y() + r.height() - (d_data->intBorder - d_data->intBorder / 2);
00242         p->drawLine(r.x(), ry , r.x() + r.width(), ry);
00243     }
00244     else // Qt::Vertical
00245     {
00246         int rx = r.x() + d_data->intBorder;
00247         const int ry = r.y();
00248         const int rh = r.height();
00249         const int rw = r.width() - 2 * d_data->intBorder;
00250 
00251         //
00252         // draw shaded background
00253         //
00254         int y1 = ry;
00255         for ( int i = 1; i < nFields; i++ )
00256         {
00257             const int y2 = ry + (rh * i) / nFields;
00258             p->fillRect(rx, y1, rw, y2-y1 + 1, d_data->colors[qwtAbs(i-hiPos)]);
00259             y1 = y2 + 1;
00260         }
00261         p->fillRect(rx, y1, rw, rh - (y1 - ry), d_data->colors[NUM_COLORS - 1]);
00262 
00263         //
00264         //  draw internal borders
00265         //
00266         p->setPen(lightPen);
00267         rx = r.x() + d_data->intBorder / 2;
00268         p->drawLine(rx, r.y(), rx, r.y() + r.height());
00269 
00270         p->setPen(darkPen);
00271         rx = r.x() + r.width() - (d_data->intBorder - d_data->intBorder / 2);
00272         p->drawLine(rx, r.y(), rx , r.y() + r.height());
00273     }
00274 
00275     p->restore();
00276 }
00277 
00278 
00290 void QwtWheel::setTotalAngle(double angle)
00291 {
00292     d_data->totalAngle = qwtLim( angle, 10.0, 3600.0 );
00293     update();
00294 }
00295 
00296 double QwtWheel::totalAngle() const 
00297 {
00298     return d_data->totalAngle;
00299 }
00300 
00308 void QwtWheel::setOrientation(Qt::Orientation o)
00309 {
00310     if ( orientation() == o )
00311         return;
00312 
00313 #if QT_VERSION >= 0x040000
00314     if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
00315 #else
00316     if ( !testWState( WState_OwnSizePolicy ) ) 
00317 #endif
00318     {
00319         QSizePolicy sp = sizePolicy();
00320         sp.transpose();
00321         setSizePolicy(sp);
00322 
00323 #if QT_VERSION >= 0x040000
00324         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00325 #else
00326         clearWState( WState_OwnSizePolicy );
00327 #endif
00328     }
00329 
00330     QwtAbstractSlider::setOrientation(o);
00331     layoutWheel();
00332 }
00333 
00342 void QwtWheel::setViewAngle(double angle)
00343 {
00344     d_data->viewAngle = qwtLim( angle, 10.0, 175.0 );
00345     update();
00346 }
00347 
00348 double QwtWheel::viewAngle() const 
00349 {
00350     return d_data->viewAngle;
00351 }
00352 
00358 void QwtWheel::drawWheel( QPainter *p, const QRect &r )
00359 {
00360 #if QT_VERSION < 0x040000
00361     const QColor light = colorGroup().light();
00362     const QColor dark = colorGroup().dark();
00363 #else
00364     const QColor light = palette().color(QPalette::Light);
00365     const QColor dark = palette().color(QPalette::Dark);
00366 #endif
00367 
00368     const double sign = (minValue() < maxValue()) ? 1.0 : -1.0;
00369     double cnvFactor = qwtAbs(d_data->totalAngle / (maxValue() - minValue()));
00370     const double halfIntv = 0.5 * d_data->viewAngle / cnvFactor;
00371     const double loValue = value() - halfIntv;
00372     const double hiValue = value() + halfIntv;
00373     const double tickWidth = 360.0 / double(d_data->tickCnt) / cnvFactor;
00374     const double sinArc = sin(d_data->viewAngle * M_PI / 360.0);
00375     cnvFactor *= M_PI / 180.0;
00376 
00377     //
00378     // draw background gradient
00379     //
00380     drawWheelBackground( p, r );
00381 
00382     //
00383     // draw grooves
00384     //
00385     if ( orientation() == Qt::Horizontal )
00386     {
00387         const double halfSize = double(r.width()) * 0.5;
00388 
00389         int l1 = r.y() + d_data->intBorder;
00390         int l2 = r.y() + r.height() - d_data->intBorder - 1;
00391 
00392         // draw one point over the border if border > 1
00393         if ( d_data->intBorder > 1 )
00394         {
00395             l1 --;
00396             l2 ++;
00397         }
00398 
00399         const int maxpos = r.x() + r.width() - 2;
00400         const int minpos = r.x() + 2;
00401 
00402         //
00403         // draw tick marks
00404         //
00405         for ( double tickValue = ceil(loValue / tickWidth) * tickWidth;
00406             tickValue < hiValue; tickValue += tickWidth )
00407         {
00408             //
00409             //  calculate position
00410             //
00411             const int tickPos = r.x() + r.width()
00412                 - int( halfSize
00413                     * (sinArc + sign *  sin((tickValue - value()) * cnvFactor))
00414                     / sinArc);
00415             //
00416             // draw vertical line
00417             //
00418             if ( (tickPos <= maxpos) && (tickPos > minpos) )
00419             {
00420                 p->setPen(dark);
00421                 p->drawLine(tickPos -1 , l1, tickPos - 1,  l2 );  
00422                 p->setPen(light);
00423                 p->drawLine(tickPos, l1, tickPos, l2);  
00424             }
00425         }
00426     }
00427     else if ( orientation() == Qt::Vertical )
00428     {
00429         const double halfSize = double(r.height()) * 0.5;
00430 
00431         int l1 = r.x() + d_data->intBorder;
00432         int l2 = r.x() + r.width() - d_data->intBorder - 1;
00433 
00434         if ( d_data->intBorder > 1 )
00435         {
00436             l1--;
00437             l2++;
00438         }
00439 
00440         const int maxpos = r.y() + r.height() - 2;
00441         const int minpos = r.y() + 2;
00442 
00443         //
00444         // draw tick marks
00445         //
00446         for ( double tickValue = ceil(loValue / tickWidth) * tickWidth;
00447             tickValue < hiValue; tickValue += tickWidth )
00448         {
00449 
00450             //
00451             // calculate position
00452             //
00453             const int tickPos = r.y() + int( halfSize *
00454                 (sinArc + sign * sin((tickValue - value()) * cnvFactor))
00455                 / sinArc);
00456 
00457             //
00458             //  draw horizontal line
00459             //
00460             if ( (tickPos <= maxpos) && (tickPos > minpos) )
00461             {
00462                 p->setPen(dark);
00463                 p->drawLine(l1, tickPos - 1 ,l2, tickPos - 1);  
00464                 p->setPen(light);
00465                 p->drawLine(l1, tickPos, l2, tickPos);  
00466             }
00467         }
00468     }
00469 }
00470 
00471 
00473 double QwtWheel::getValue( const QPoint &p )
00474 {
00475     // The reference position is arbitrary, but the
00476     // sign of the offset is important
00477     int w, dx;
00478     if ( orientation() == Qt::Vertical )
00479     {
00480         w = d_data->sliderRect.height();
00481         dx = d_data->sliderRect.y() - p.y();
00482     }
00483     else
00484     {
00485         w = d_data->sliderRect.width();
00486         dx = p.x() - d_data->sliderRect.x();
00487     }
00488 
00489     // w pixels is an arc of viewAngle degrees,
00490     // so we convert change in pixels to change in angle
00491     const double ang = dx * d_data->viewAngle / w;
00492 
00493     // value range maps to totalAngle degrees,
00494     // so convert the change in angle to a change in value
00495     const double val = ang * ( maxValue() - minValue() ) / d_data->totalAngle;
00496 
00497     // Note, range clamping and rasterizing to step is automatically
00498     // handled by QwtAbstractSlider, so we simply return the change in value
00499     return val;
00500 }
00501 
00503 void QwtWheel::resizeEvent(QResizeEvent *)
00504 {
00505     layoutWheel( false );
00506 }
00507 
00509 //  the current rect and fonts.
00510 //  \param update_geometry  notify the layout system and call update
00511 //         to redraw the scale
00512 void QwtWheel::layoutWheel( bool update_geometry )
00513 {
00514     const QRect r = this->rect();
00515     d_data->sliderRect.setRect(r.x() + d_data->borderWidth, r.y() + d_data->borderWidth,
00516         r.width() - 2*d_data->borderWidth, r.height() - 2*d_data->borderWidth);
00517 
00518     if ( update_geometry )
00519     {
00520         updateGeometry();
00521         update();
00522     }
00523 }
00524 
00526 void QwtWheel::paintEvent(QPaintEvent *e)
00527 {
00528     // Use double-buffering
00529     const QRect &ur = e->rect();
00530     if ( ur.isValid() )
00531     {
00532 #if QT_VERSION < 0x040000
00533         QwtPaintBuffer paintBuffer(this, ur);
00534         draw(paintBuffer.painter(), ur);
00535 #else
00536         QPainter painter(this);
00537         draw(&painter, ur);
00538 #endif
00539     }
00540 }
00541 
00543 void QwtWheel::draw(QPainter *painter, const QRect&)
00544 {
00545     qDrawShadePanel( painter, rect().x(), rect().y(),
00546         rect().width(), rect().height(),
00547 #if QT_VERSION < 0x040000
00548         colorGroup(), 
00549 #else
00550         palette(), 
00551 #endif
00552         true, d_data->borderWidth );
00553 
00554     drawWheel( painter, d_data->sliderRect );
00555 
00556     if ( hasFocus() )
00557         QwtPainter::drawFocusRect(painter, this);
00558 }
00559 
00561 void QwtWheel::valueChange()
00562 {
00563     QwtAbstractSlider::valueChange();
00564     update();
00565 }
00566 
00567 
00575 void QwtWheel::getScrollMode( const QPoint &p, int &scrollMode, int &direction)
00576 {
00577     if ( d_data->sliderRect.contains(p) )
00578         scrollMode = ScrMouse;
00579     else
00580         scrollMode = ScrNone;
00581 
00582     direction = 0;
00583 }
00584 
00591 void QwtWheel::setMass(double val)
00592 {
00593     QwtAbstractSlider::setMass(val);
00594 }
00595 
00603 void QwtWheel::setWheelWidth(int w)
00604 {
00605     d_data->wheelWidth = w;
00606     layoutWheel();
00607 }
00608 
00612 QSize QwtWheel::sizeHint() const
00613 {
00614     return minimumSizeHint();
00615 }
00616 
00621 QSize QwtWheel::minimumSizeHint() const
00622 {
00623     QSize sz( 3*d_data->wheelWidth + 2*d_data->borderWidth,
00624     d_data->wheelWidth + 2*d_data->borderWidth );
00625     if ( orientation() != Qt::Horizontal )
00626         sz.transpose();
00627     return sz;
00628 }
00629 
00633 void QwtWheel::paletteChange( const QPalette& )
00634 {
00635     update();
00636 }
00637 

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