Main Page | Class Hierarchy | Alphabetical List | Class List | 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_paint_buffer.h"
    00016 #include "qwt_wheel.h"
    00017
    00018
    00020 QwtWheel::QwtWheel(QWidget *parent, const char *name):
    00021     QwtSliderBase(Qt::Horizontal, parent, name,
    00022         Qt::WRepaintNoErase|Qt::WResizeNoErase )
    00023 {
    00024     d_viewAngle = 175.0;
    00025     d_totalAngle = 360.0;
    00026     d_tickCnt = 10;
    00027     d_intBorder = 2;
    00028     d_borderWidth = 2;
    00029     d_colorCnt = 30;
    00030     d_wheelWidth = 20;
    00031     d_allocContext = 0;
    00032     d_colors = new QColor[d_colorCnt];
    00033     setUpdateTime(50);
    00034 }
    00035
    00037 QwtWheel::~QwtWheel()
    00038 {
    00039     if ( d_allocContext )
    00040         QColor::destroyAllocContext( d_allocContext );
    00041     delete[] d_colors;
    00042 }
    00043
    00045 void QwtWheel::setColorArray()
    00046 {
    00047     if ( !d_colors )
    00048         return;
    00049
    00050     QColorGroup g = colorGroup();
    00051
    00052     if ( !d_colors[0].isValid() ||
    00053         d_colors[0] != g.light() ||
    00054         d_colors[d_colorCnt - 1] != g.dark() )
    00055     {
    00056         if ( d_allocContext )
    00057             QColor::destroyAllocContext( d_allocContext );
    00058
    00059         d_allocContext = QColor::enterAllocContext();
    00060
    00061         d_colors[0] = g.light();
    00062         d_colors[d_colorCnt - 1] = g.dark();
    00063
    00064         int dh, ds, dv, lh, ls, lv;
    00065         d_colors[0].rgb(&lh, &ls, &lv);
    00066         d_colors[d_colorCnt - 1].rgb(&dh, &ds, &dv);
    00067
    00068         for ( int i = 1; i < d_colorCnt - 1; ++i )
    00069         {
    00070             const double factor = double(i) / double(d_colorCnt);
    00071
    00072             d_colors[i].setRgb( lh + int( double(dh - lh) * factor ),
    00073                       ls + int( double(ds - ls) * factor ),
    00074                       lv + int( double(dv - lv) * factor ));
    00075         }
    00076         QColor::leaveAllocContext();
    00077     }
    00078 }
    00079
    00088 void QwtWheel::setTickCnt(int cnt)
    00089 {
    00090     d_tickCnt = qwtLim( cnt, 6, 50 );
    00091     update();
    00092 }
    00093
    00097 double QwtWheel::mass() const
    00098 {
    00099     return QwtSliderBase::mass();
    00100 }
    00101
    00102
    00103
    00114 void QwtWheel::setInternalBorder( int w )
    00115 {
    00116     const int d = qwtMin( width(), height() ) / 3;
    00117     w = qwtMin( w, d );
    00118     d_intBorder = qwtMax( w, 1 );
    00119     layoutWheel();
    00120 }
    00121
    00123 void QwtWheel::drawWheelBackground( QPainter *p, const QRect &r )
    00124 {
    00125     p->save();
    00126
    00127     //
    00128     // initialize pens
    00129     //
    00130     const QColorGroup g = colorGroup();
    00131
    00132     QPen lightPen;
    00133     lightPen.setColor(g.light());
    00134     lightPen.setWidth(d_intBorder);
    00135
    00136     QPen darkPen;
    00137     darkPen.setColor(g.dark());
    00138     darkPen.setWidth(d_intBorder);
    00139
    00140     setColorArray();
    00141
    00142     //
    00143     // initialize auxiliary variables
    00144     //
    00145
    00146     const int nFields = d_colorCnt * 13 / 10;
    00147     const int hiPos = nFields - d_colorCnt + 1;
    00148
    00149     if ( orientation() == Qt::Horizontal )
    00150     {
    00151         const int rx = r.x();
    00152         int ry = r.y() + d_intBorder;
    00153         const int rh = r.height() - 2* d_intBorder;
    00154         const int rw = r.width();
    00155         //
    00156         //  draw shaded background
    00157         //
    00158         int x1 = rx;
    00159         for (int i = 1; i < nFields; i++ )
    00160         {
    00161             const int x2 = rx + (rw * i) / nFields;
    00162             p->fillRect(x1, ry, x2-x1 + 1 ,rh, d_colors[qwtAbs(i-hiPos)]);
    00163             x1 = x2 + 1;
    00164         }
    00165         p->fillRect(x1, ry, rw - (x1 - rx), rh, d_colors[d_colorCnt - 1]);
    00166
    00167         //
    00168         // draw internal border
    00169         //
    00170         p->setPen(lightPen);
    00171         ry = r.y() + d_intBorder / 2;
    00172         p->drawLine(r.x(), ry, r.x() + r.width() , ry);
    00173
    00174         p->setPen(darkPen);
    00175         ry = r.y() + r.height() - (d_intBorder - d_intBorder / 2);
    00176         p->drawLine(r.x(), ry , r.x() + r.width(), ry);
    00177     }
    00178     else // Qt::Vertical
    00179     {
    00180         int rx = r.x() + d_intBorder;
    00181         const int ry = r.y();
    00182         const int rh = r.height();
    00183         const int rw = r.width() - 2 * d_intBorder;
    00184
    00185         //
    00186         // draw shaded background
    00187         //
    00188         int y1 = ry;
    00189         for ( int i = 1; i < nFields; i++ )
    00190         {
    00191             const int y2 = ry + (rh * i) / nFields;
    00192             p->fillRect(rx, y1, rw, y2-y1 + 1, d_colors[qwtAbs(i-hiPos)]);
    00193             y1 = y2 + 1;
    00194         }
    00195         p->fillRect(rx, y1, rw, rh - (y1 - ry), d_colors[d_colorCnt - 1]);
    00196
    00197         //
    00198         //  draw internal borders
    00199         //
    00200         p->setPen(lightPen);
    00201         rx = r.x() + d_intBorder / 2;
    00202         p->drawLine(rx, r.y(), rx, r.y() + r.height());
    00203
    00204         p->setPen(darkPen);
    00205         rx = r.x() + r.width() - (d_intBorder - d_intBorder / 2);
    00206         p->drawLine(rx, r.y(), rx , r.y() + r.height());
    00207     }
    00208
    00209     p->restore();
    00210 }
    00211
    00212
    00224 void QwtWheel::setTotalAngle(double angle)
    00225 {
    00226     d_totalAngle = qwtLim( angle, 10.0, 3600.0 );
    00227     update();
    00228 }
    00229
    00237 void QwtWheel::setOrientation(Qt::Orientation o)
    00238 {
    00239     if ( orientation() != o )
    00240     {
    00241         QwtSliderBase::setOrientation(o);
    00242         layoutWheel();
    00243     }
    00244 }
    00245
    00254 void QwtWheel::setViewAngle(double angle)
    00255 {
    00256     d_viewAngle = qwtLim( angle, 10.0, 175.0 );
    00257     update();
    00258 }
    00259
    00265 void QwtWheel::drawWheel( QPainter *p, const QRect &r )
    00266 {
    00267     const double sign = (minValue() < maxValue()) ? 1.0 : -1.0;
    00268     double cnvFactor = qwtAbs(d_totalAngle / (maxValue() - minValue()));
    00269     const double halfIntv = 0.5 * d_viewAngle / cnvFactor;
    00270     const double loValue = value() - halfIntv;
    00271     const double hiValue = value() + halfIntv;
    00272     const double tickWidth = 360.0 / double(d_tickCnt) / cnvFactor;
    00273     const double sinArc = sin(d_viewAngle * M_PI / 360.0);
    00274     cnvFactor *= M_PI / 180.0;
    00275
    00276     //
    00277     // draw background gradient
    00278     //
    00279     drawWheelBackground( p, r );
    00280
    00281     //
    00282     // draw grooves
    00283     //
    00284     if ( orientation() == Qt::Horizontal )
    00285     {
    00286         const double halfSize = double(r.width()) * 0.5;
    00287
    00288         int l1 = r.y() + d_intBorder;
    00289         int l2 = r.y() + r.height() - d_intBorder - 1;
    00290
    00291         // draw one point over the border if border > 1
    00292         if ( d_intBorder > 1 )
    00293         {
    00294             l1 --;
    00295             l2 ++;
    00296         }
    00297
    00298         const int maxpos = r.x() + r.width() - 2;
    00299         const int minpos = r.x() + 2;
    00300
    00301         //
    00302         // draw tick marks
    00303         //
    00304         for ( double tickValue = ceil(loValue / tickWidth) * tickWidth;
    00305             tickValue < hiValue; tickValue += tickWidth )
    00306         {
    00307             //
    00308             //  calculate position
    00309             //
    00310             const int tickPos = r.x() + r.width()
    00311                 - int( halfSize
    00312                     * (sinArc + sign *  sin((tickValue - value()) * cnvFactor))
    00313                     / sinArc);
    00314             //
    00315             // draw vertical line
    00316             //
    00317             if ( (tickPos <= maxpos) && (tickPos > minpos) )
    00318             {
    00319                 p->setPen(colorGroup().dark());
    00320                 p->drawLine(tickPos -1 , l1, tickPos - 1,  l2 );
    00321                 p->setPen(colorGroup().light());
    00322                 p->drawLine(tickPos, l1, tickPos, l2);
    00323             }
    00324         }
    00325     }
    00326     else if ( orientation() == Qt::Vertical )
    00327     {
    00328         const double halfSize = double(r.height()) * 0.5;
    00329
    00330         int l1 = r.x() + d_intBorder;
    00331         int l2 = r.x() + r.width() - d_intBorder - 1;
    00332
    00333         if ( d_intBorder > 1 )
    00334         {
    00335             l1--;
    00336             l2++;
    00337         }
    00338
    00339         const int maxpos = r.y() + r.height() - 2;
    00340         const int minpos = r.y() + 2;
    00341
    00342         //
    00343         // draw tick marks
    00344         //
    00345         for ( double tickValue = ceil(loValue / tickWidth) * tickWidth;
    00346             tickValue < hiValue; tickValue += tickWidth )
    00347         {
    00348
    00349             //
    00350             // calculate position
    00351             //
    00352             const int tickPos = r.y() + int( halfSize *
    00353                 (sinArc + sign * sin((tickValue - value()) * cnvFactor))
    00354                 / sinArc);
    00355
    00356             //
    00357             //  draw horizontal line
    00358             //
    00359             if ( (tickPos <= maxpos) && (tickPos > minpos) )
    00360             {
    00361                 p->setPen(colorGroup().dark());
    00362                 p->drawLine(l1, tickPos - 1 ,l2, tickPos - 1);
    00363                 p->setPen(colorGroup().light());
    00364                 p->drawLine(l1, tickPos, l2, tickPos);
    00365             }
    00366         }
    00367     }
    00368 }
    00369
    00370
    00372 double QwtWheel::getValue( const QPoint &p )
    00373 {
    00374     // The reference position is arbitrary, but the
    00375     // sign of the offset is important
    00376     int w, dx;
    00377     if ( orientation() == Qt::Vertical )
    00378     {
    00379         w = d_sliderRect.height();
    00380         dx = d_sliderRect.y() - p.y();
    00381     }
    00382     else
    00383     {
    00384         w = d_sliderRect.width();
    00385         dx = p.x() - d_sliderRect.x();
    00386     }
    00387
    00388     // w pixels is an arc of viewAngle degrees,
    00389     // so we convert change in pixels to change in angle
    00390     const double ang = dx * d_viewAngle / w;
    00391
    00392     // value range maps to totalAngle degrees,
    00393     // so convert the change in angle to a change in value
    00394     const double val = ang * ( maxValue() - minValue() ) / d_totalAngle;
    00395
    00396     // Note, range clamping and rasterizing to step is automatically
    00397     // handled by QwtSliderBase, so we simply return the change in value
    00398     return val;
    00399 }
    00400
    00402 void QwtWheel::resizeEvent(QResizeEvent *)
    00403 {
    00404     layoutWheel( FALSE );
    00405 }
    00406
    00408 //  the current rect and fonts.
    00409 //  \param update_geometry  notify the layout system and call update
    00410 //         to redraw the scale
    00411 void QwtWheel::layoutWheel( bool update_geometry )
    00412 {
    00413     const QRect r = this->rect();
    00414     d_sliderRect.setRect(r.x() + d_borderWidth, r.y() + d_borderWidth,
    00415         r.width() - 2*d_borderWidth, r.height() - 2*d_borderWidth);
    00416
    00417     if ( update_geometry )
    00418     {
    00419         updateGeometry();
    00420         update();
    00421     }
    00422 }
    00423
    00425 void QwtWheel::paintEvent(QPaintEvent *e)
    00426 {
    00427     // Use double-buffering
    00428     const QRect &ur = e->rect();
    00429     if ( ur.isValid() )
    00430     {
    00431         QwtPaintBuffer paintBuffer(this, ur);
    00432         draw(paintBuffer.painter(), ur);
    00433     }
    00434 }
    00435
    00437 void QwtWheel::draw(QPainter *painter, const QRect&)
    00438 {
    00439     QColorGroup cg = colorGroup();
    00440
    00441     // Rather than maintain a separate color group
    00442     // for the outer frame, use our parent's cg
    00443     QWidget *parent = parentWidget();
    00444     if ( parent )
    00445         cg = parent->colorGroup();
    00446
    00447     qDrawShadePanel( painter, rect().x(), rect().y(),
    00448         rect().width(), rect().height(),
    00449         cg, TRUE, d_borderWidth );
    00450
    00451     drawWheel( painter, d_sliderRect );
    00452
    00453     if ( hasFocus() )
    00454     {
    00455         QRect r = rect();
    00456
    00457 #if QT_VERSION < 300
    00458         style().drawFocusRect(painter, r, colorGroup());
    00459 #else
    00460         style().drawPrimitive(QStyle::PE_FocusRect, painter,
    00461             r, colorGroup());
    00462 #endif
    00463     }
    00464 }
    00465
    00467 void QwtWheel::valueChange()
    00468 {
    00469     QwtSliderBase::valueChange();
    00470     update();
    00471 }
    00472
    00473
    00481 void QwtWheel::getScrollMode( const QPoint &p, int &scrollMode, int &direction)
    00482 {
    00483     if ( d_sliderRect.contains(p) )
    00484         scrollMode = ScrMouse;
    00485     else
    00486         scrollMode = ScrNone;
    00487
    00488     direction = 0;
    00489 }
    00490
    00497 void QwtWheel::setMass(double val)
    00498 {
    00499     QwtSliderBase::setMass(val);
    00500 }
    00501
    00509 void QwtWheel::setWheelWidth(int w)
    00510 {
    00511     d_wheelWidth = w;
    00512     layoutWheel();
    00513 }
    00514
    00520 QSizePolicy QwtWheel::sizePolicy() const
    00521 {
    00522     QSizePolicy sp;
    00523     if ( orientation() == Qt::Horizontal )
    00524     {
    00525         sp.setHorData( QSizePolicy::Preferred );
    00526         sp.setVerData( QSizePolicy::Fixed );
    00527     }
    00528     else
    00529     {
    00530         sp.setHorData( QSizePolicy::Fixed );
    00531         sp.setVerData( QSizePolicy::Preferred );
    00532     }
    00533     return sp;
    00534 }
    00535
    00539 QSize QwtWheel::sizeHint() const
    00540 {
    00541     return minimumSizeHint();
    00542 }
    00543
    00548 QSize QwtWheel::minimumSizeHint() const
    00549 {
    00550     QSize sz( 3*d_wheelWidth + 2*d_borderWidth,
    00551     d_wheelWidth + 2*d_borderWidth );
    00552     if ( orientation() != Qt::Horizontal )
    00553         sz.transpose();
    00554     return sz;
    00555 }
    00556
    00560 void QwtWheel::paletteChange( const QPalette& )
    00561 {
    00562     update();
    00563 }
    00564