123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
- * Qwt Widget Library
- * Copyright (C) 1997 Josef Wilgen
- * Copyright (C) 2002 Uwe Rathmann
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the Qwt License, Version 1.0
- *****************************************************************************/
- #include "qwt_wheel.h"
- #include "qwt_math.h"
- #include "qwt_painter.h"
- #include <qevent.h>
- #include <qdrawutil.h>
- #include <qpainter.h>
- #include <qstyle.h>
- #define NUM_COLORS 30
- class QwtWheel::PrivateData
- {
- public:
- PrivateData()
- {
- viewAngle = 175.0;
- totalAngle = 360.0;
- tickCnt = 10;
- intBorder = 2;
- borderWidth = 2;
- wheelWidth = 20;
- };
- QRect sliderRect;
- double viewAngle;
- double totalAngle;
- int tickCnt;
- int intBorder;
- int borderWidth;
- int wheelWidth;
- QColor colors[NUM_COLORS];
- };
- //! Constructor
- QwtWheel::QwtWheel( QWidget *parent ):
- QwtAbstractSlider( Qt::Horizontal, parent )
- {
- initWheel();
- }
- void QwtWheel::initWheel()
- {
- d_data = new PrivateData;
- setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
- setAttribute( Qt::WA_WState_OwnSizePolicy, false );
- setUpdateTime( 50 );
- }
- //! Destructor
- QwtWheel::~QwtWheel()
- {
- delete d_data;
- }
- //! Set up the color array for the background pixmap.
- void QwtWheel::setColorArray()
- {
- if ( !d_data->colors )
- return;
- const QColor light = palette().color( QPalette::Light );
- const QColor dark = palette().color( QPalette::Dark );
- if ( !d_data->colors[0].isValid() ||
- d_data->colors[0] != light ||
- d_data->colors[NUM_COLORS - 1] != dark )
- {
- d_data->colors[0] = light;
- d_data->colors[NUM_COLORS - 1] = dark;
- int dh, ds, dv, lh, ls, lv;
- d_data->colors[0].getRgb( &lh, &ls, &lv );
- d_data->colors[NUM_COLORS - 1].getRgb( &dh, &ds, &dv );
- for ( int i = 1; i < NUM_COLORS - 1; ++i )
- {
- const double factor = double( i ) / double( NUM_COLORS );
- d_data->colors[i].setRgb( lh + int( double( dh - lh ) * factor ),
- ls + int( double( ds - ls ) * factor ),
- lv + int( double( dv - lv ) * factor ) );
- }
- }
- }
- /*!
- \brief Adjust the number of grooves in the wheel's surface.
- The number of grooves is limited to 6 <= cnt <= 50.
- Values outside this range will be clipped.
- The default value is 10.
- \param cnt Number of grooves per 360 degrees
- \sa tickCnt()
- */
- void QwtWheel::setTickCnt( int cnt )
- {
- d_data->tickCnt = qwtLim( cnt, 6, 50 );
- update();
- }
- /*!
- \return Number of grooves in the wheel's surface.
- \sa setTickCnt()
- */
- int QwtWheel::tickCnt() const
- {
- return d_data->tickCnt;
- }
- /*!
- \return mass
- */
- double QwtWheel::mass() const
- {
- return QwtAbstractSlider::mass();
- }
- /*!
- \brief Set the internal border width of the wheel.
- The internal border must not be smaller than 1
- and is limited in dependence on the wheel's size.
- Values outside the allowed range will be clipped.
- The internal border defaults to 2.
- \param w border width
- \sa internalBorder()
- */
- void QwtWheel::setInternalBorder( int w )
- {
- const int d = qMin( width(), height() ) / 3;
- w = qMin( w, d );
- d_data->intBorder = qMax( w, 1 );
- layoutWheel();
- }
- /*!
- \return Internal border width of the wheel.
- \sa setInternalBorder()
- */
- int QwtWheel::internalBorder() const
- {
- return d_data->intBorder;
- }
- /*!
- Draw the Wheel's background gradient
- \param painter Painter
- \param r Bounding rectangle
- */
- void QwtWheel::drawWheelBackground( QPainter *painter, const QRect &r )
- {
- painter->save();
- //
- // initialize pens
- //
- const QColor light = palette().color( QPalette::Light );
- const QColor dark = palette().color( QPalette::Dark );
- QPen lightPen;
- lightPen.setColor( light );
- lightPen.setWidth( d_data->intBorder );
- QPen darkPen;
- darkPen.setColor( dark );
- darkPen.setWidth( d_data->intBorder );
- setColorArray();
- //
- // initialize auxiliary variables
- //
- const int nFields = NUM_COLORS * 13 / 10;
- const int hiPos = nFields - NUM_COLORS + 1;
- if ( orientation() == Qt::Horizontal )
- {
- const int rx = r.x();
- int ry = r.y() + d_data->intBorder;
- const int rh = r.height() - 2 * d_data->intBorder;
- const int rw = r.width();
- //
- // draw shaded background
- //
- int x1 = rx;
- for ( int i = 1; i < nFields; i++ )
- {
- const int x2 = rx + ( rw * i ) / nFields;
- painter->fillRect( x1, ry, x2 - x1 + 1 , rh,
- d_data->colors[qAbs( i-hiPos )] );
- x1 = x2 + 1;
- }
- painter->fillRect( x1, ry, rw - ( x1 - rx ), rh,
- d_data->colors[NUM_COLORS - 1] );
- //
- // draw internal border
- //
- painter->setPen( lightPen );
- ry = r.y() + d_data->intBorder / 2;
- painter->drawLine( r.x(), ry, r.x() + r.width() , ry );
- painter->setPen( darkPen );
- ry = r.y() + r.height() - ( d_data->intBorder - d_data->intBorder / 2 );
- painter->drawLine( r.x(), ry , r.x() + r.width(), ry );
- }
- else // Qt::Vertical
- {
- int rx = r.x() + d_data->intBorder;
- const int ry = r.y();
- const int rh = r.height();
- const int rw = r.width() - 2 * d_data->intBorder;
- //
- // draw shaded background
- //
- int y1 = ry;
- for ( int i = 1; i < nFields; i++ )
- {
- const int y2 = ry + ( rh * i ) / nFields;
- painter->fillRect( rx, y1, rw, y2 - y1 + 1,
- d_data->colors[qAbs( i-hiPos )] );
- y1 = y2 + 1;
- }
- painter->fillRect( rx, y1, rw, rh - ( y1 - ry ),
- d_data->colors[NUM_COLORS - 1] );
- //
- // draw internal borders
- //
- painter->setPen( lightPen );
- rx = r.x() + d_data->intBorder / 2;
- painter->drawLine( rx, r.y(), rx, r.y() + r.height() );
- painter->setPen( darkPen );
- rx = r.x() + r.width() - ( d_data->intBorder - d_data->intBorder / 2 );
- painter->drawLine( rx, r.y(), rx , r.y() + r.height() );
- }
- painter->restore();
- }
- /*!
- \brief Set the total angle which the wheel can be turned.
- One full turn of the wheel corresponds to an angle of
- 360 degrees. A total angle of n*360 degrees means
- that the wheel has to be turned n times around its axis
- to get from the minimum value to the maximum value.
- The default setting of the total angle is 360 degrees.
- \param angle total angle in degrees
- \sa totalAngle()
- */
- void QwtWheel::setTotalAngle( double angle )
- {
- if ( angle < 0.0 )
- angle = 0.0;
- d_data->totalAngle = angle;
- update();
- }
- /*!
- \return Total angle which the wheel can be turned.
- \sa setTotalAngle()
- */
- double QwtWheel::totalAngle() const
- {
- return d_data->totalAngle;
- }
- /*!
- \brief Set the wheel's orientation.
- \param o Orientation. Allowed values are
- Qt::Horizontal and Qt::Vertical.
- Defaults to Qt::Horizontal.
- \sa QwtAbstractSlider::orientation()
- */
- void QwtWheel::setOrientation( Qt::Orientation o )
- {
- if ( orientation() == o )
- return;
- if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
- {
- QSizePolicy sp = sizePolicy();
- sp.transpose();
- setSizePolicy( sp );
- setAttribute( Qt::WA_WState_OwnSizePolicy, false );
- }
- QwtAbstractSlider::setOrientation( o );
- layoutWheel();
- }
- /*!
- \brief Specify the visible portion of the wheel.
- You may use this function for fine-tuning the appearance of
- the wheel. The default value is 175 degrees. The value is
- limited from 10 to 175 degrees.
- \param angle Visible angle in degrees
- \sa viewAngle(), setTotalAngle()
- */
- void QwtWheel::setViewAngle( double angle )
- {
- d_data->viewAngle = qwtLim( angle, 10.0, 175.0 );
- update();
- }
- /*!
- \return Visible portion of the wheel
- \sa setViewAngle(), totalAngle()
- */
- double QwtWheel::viewAngle() const
- {
- return d_data->viewAngle;
- }
- /*!
- \brief Redraw the wheel
- \param painter painter
- \param r contents rectangle
- */
- void QwtWheel::drawWheel( QPainter *painter, const QRect &r )
- {
- //
- // draw background gradient
- //
- drawWheelBackground( painter, r );
- if ( maxValue() == minValue() || d_data->totalAngle == 0.0 )
- return;
- const QColor light = palette().color( QPalette::Light );
- const QColor dark = palette().color( QPalette::Dark );
- const double sign = ( minValue() < maxValue() ) ? 1.0 : -1.0;
- double cnvFactor = qAbs( d_data->totalAngle / ( maxValue() - minValue() ) );
- const double halfIntv = 0.5 * d_data->viewAngle / cnvFactor;
- const double loValue = value() - halfIntv;
- const double hiValue = value() + halfIntv;
- const double tickWidth = 360.0 / double( d_data->tickCnt ) / cnvFactor;
- const double sinArc = qSin( d_data->viewAngle * M_PI / 360.0 );
- cnvFactor *= M_PI / 180.0;
- //
- // draw grooves
- //
- if ( orientation() == Qt::Horizontal )
- {
- const double halfSize = double( r.width() ) * 0.5;
- int l1 = r.y() + d_data->intBorder;
- int l2 = r.y() + r.height() - d_data->intBorder - 1;
- // draw one point over the border if border > 1
- if ( d_data->intBorder > 1 )
- {
- l1 --;
- l2 ++;
- }
- const int maxpos = r.x() + r.width() - 2;
- const int minpos = r.x() + 2;
- //
- // draw tick marks
- //
- for ( double tickValue = qCeil( loValue / tickWidth ) * tickWidth;
- tickValue < hiValue; tickValue += tickWidth )
- {
- //
- // calculate position
- //
- const int tickPos = r.x() + r.width()
- - int( halfSize
- * ( sinArc + sign * qSin( ( tickValue - value() ) * cnvFactor ) )
- / sinArc );
- //
- // draw vertical line
- //
- if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
- {
- painter->setPen( dark );
- painter->drawLine( tickPos - 1 , l1, tickPos - 1, l2 );
- painter->setPen( light );
- painter->drawLine( tickPos, l1, tickPos, l2 );
- }
- }
- }
- else if ( orientation() == Qt::Vertical )
- {
- const double halfSize = double( r.height() ) * 0.5;
- int l1 = r.x() + d_data->intBorder;
- int l2 = r.x() + r.width() - d_data->intBorder - 1;
- if ( d_data->intBorder > 1 )
- {
- l1--;
- l2++;
- }
- const int maxpos = r.y() + r.height() - 2;
- const int minpos = r.y() + 2;
- //
- // draw tick marks
- //
- for ( double tickValue = qCeil( loValue / tickWidth ) * tickWidth;
- tickValue < hiValue; tickValue += tickWidth )
- {
- //
- // calculate position
- //
- const int tickPos = r.y() + int( halfSize *
- ( sinArc + sign * qSin( ( tickValue - value() ) * cnvFactor ) )
- / sinArc );
- //
- // draw horizontal line
- //
- if ( ( tickPos <= maxpos ) && ( tickPos > minpos ) )
- {
- painter->setPen( dark );
- painter->drawLine( l1, tickPos - 1 , l2, tickPos - 1 );
- painter->setPen( light );
- painter->drawLine( l1, tickPos, l2, tickPos );
- }
- }
- }
- }
- //! Determine the value corresponding to a specified point
- double QwtWheel::getValue( const QPoint &p )
- {
- // The reference position is arbitrary, but the
- // sign of the offset is important
- int w, dx;
- if ( orientation() == Qt::Vertical )
- {
- w = d_data->sliderRect.height();
- dx = d_data->sliderRect.y() - p.y();
- }
- else
- {
- w = d_data->sliderRect.width();
- dx = p.x() - d_data->sliderRect.x();
- }
- // w pixels is an arc of viewAngle degrees,
- // so we convert change in pixels to change in angle
- const double ang = dx * d_data->viewAngle / w;
- // value range maps to totalAngle degrees,
- // so convert the change in angle to a change in value
- const double val = ang * ( maxValue() - minValue() ) / d_data->totalAngle;
- // Note, range clamping and rasterizing to step is automatically
- // handled by QwtAbstractSlider, so we simply return the change in value
- return val;
- }
- //! Qt Resize Event
- void QwtWheel::resizeEvent( QResizeEvent * )
- {
- layoutWheel( false );
- }
- //! Recalculate the slider's geometry and layout based on
- // the current rect and fonts.
- // \param update_geometry notify the layout system and call update
- // to redraw the scale
- void QwtWheel::layoutWheel( bool update_geometry )
- {
- const QRect r = this->rect();
- d_data->sliderRect.setRect( r.x() + d_data->borderWidth, r.y() + d_data->borderWidth,
- r.width() - 2*d_data->borderWidth, r.height() - 2*d_data->borderWidth );
- if ( update_geometry )
- {
- updateGeometry();
- update();
- }
- }
- //! Qt Paint Event
- void QwtWheel::paintEvent( QPaintEvent *e )
- {
- // Use double-buffering
- const QRect &ur = e->rect();
- if ( ur.isValid() )
- {
- QPainter painter( this );
- draw( &painter, ur );
- }
- }
- /*!
- Redraw panel and wheel
- \param painter Painter
- */
- void QwtWheel::draw( QPainter *painter, const QRect& )
- {
- qDrawShadePanel( painter, rect().x(), rect().y(),
- rect().width(), rect().height(),
- palette(), true, d_data->borderWidth );
- drawWheel( painter, d_data->sliderRect );
- if ( hasFocus() )
- QwtPainter::drawFocusRect( painter, this );
- }
- //! Notify value change
- void QwtWheel::valueChange()
- {
- QwtAbstractSlider::valueChange();
- update();
- }
- /*!
- \brief Determine the scrolling mode and direction corresponding
- to a specified point
- \param p point
- \param scrollMode scrolling mode
- \param direction direction
- */
- void QwtWheel::getScrollMode( const QPoint &p, int &scrollMode, int &direction )
- {
- if ( d_data->sliderRect.contains( p ) )
- scrollMode = ScrMouse;
- else
- scrollMode = ScrNone;
- direction = 0;
- }
- /*!
- \brief Set the mass of the wheel
- Assigning a mass turns the wheel into a flywheel.
- \param val the wheel's mass
- */
- void QwtWheel::setMass( double val )
- {
- QwtAbstractSlider::setMass( val );
- }
- /*!
- \brief Set the width of the wheel
- Corresponds to the wheel height for horizontal orientation,
- and the wheel width for vertical orientation.
- \param w the wheel's width
- */
- void QwtWheel::setWheelWidth( int w )
- {
- d_data->wheelWidth = w;
- layoutWheel();
- }
- /*!
- \return a size hint
- */
- QSize QwtWheel::sizeHint() const
- {
- return minimumSizeHint();
- }
- /*!
- \brief Return a minimum size hint
- \warning The return value is based on the wheel width.
- */
- QSize QwtWheel::minimumSizeHint() const
- {
- QSize sz( 3*d_data->wheelWidth + 2*d_data->borderWidth,
- d_data->wheelWidth + 2*d_data->borderWidth );
- if ( orientation() != Qt::Horizontal )
- sz.transpose();
- return sz;
- }
- /*!
- \brief Call update() when the palette changes
- */
- void QwtWheel::paletteChange( const QPalette& )
- {
- update();
- }
|