Skip to content
Snippets Groups Projects
qwt_dial.cpp 19 KiB
Newer Older
  • Learn to ignore specific revisions
  • pixhawk's avatar
    pixhawk committed
    /* -*- 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
     *****************************************************************************/
    
    
    Bryant's avatar
    Bryant committed
    #include "qwt_dial.h"
    #include "qwt_dial_needle.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "qwt_math.h"
    #include "qwt_scale_engine.h"
    #include "qwt_scale_map.h"
    
    Bryant's avatar
    Bryant committed
    #include "qwt_round_scale_draw.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "qwt_painter.h"
    
    Bryant's avatar
    Bryant committed
    #include <qpainter.h>
    #include <qpalette.h>
    #include <qpixmap.h>
    #include <qevent.h>
    #include <qalgorithms.h>
    #include <qmath.h>
    #include <qstyle.h>
    #include <qstyleoption.h>
    #include <qapplication.h>
    
    static inline double qwtAngleDist( double a1, double a2 )
    {
        double dist = qAbs( a2 - a1 );
        if ( dist > 360.0 )
            dist -= 360.0;
    
        return dist;
    }
    
    static inline bool qwtIsOnArc( double angle, double min, double max )
    {
        if ( min < max )
        {
            return ( angle >= min ) && ( angle <= max );
        }
        else
        {
            return ( angle >= min ) || ( angle <= max );
        }
    }
    
    static inline double qwtBoundedAngle( double min, double angle, double max )
    {
        double from = qwtNormalizeDegrees( min );
        double to = qwtNormalizeDegrees( max );
    
        double a;
    
        if ( qwtIsOnArc( angle, from, to ) )
        {
            a = angle;
            if ( a < min )
                a += 360.0;
        }
        else
        {
            if ( qwtAngleDist( angle, from ) <
                qwtAngleDist( angle, to ) )
            {
                a = min;
            }
            else
            {
                a = max;
            }
        }
    
        return a;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    class QwtDial::PrivateData
    {
    public:
        PrivateData():
    
    Bryant's avatar
    Bryant committed
            frameShadow( Sunken ),
            lineWidth( 0 ),
            mode( RotateNeedle ),
            origin( 90.0 ),
            minScaleArc( 0.0 ),
            maxScaleArc( 0.0 ),
            needle( NULL ),
            arcOffset( 0.0 ),
            mouseOffset( 0.0 )
        {
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        ~PrivateData()
        {
    
    pixhawk's avatar
    pixhawk committed
            delete needle;
        }
        Shadow frameShadow;
        int lineWidth;
    
        QwtDial::Mode mode;
    
        double origin;
        double minScaleArc;
        double maxScaleArc;
    
    
    Bryant's avatar
    Bryant committed
        double scalePenWidth;
    
    pixhawk's avatar
    pixhawk committed
        QwtDialNeedle *needle;
    
    
    Bryant's avatar
    Bryant committed
        double arcOffset;
        double mouseOffset;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QPixmap pixmapCache;
    };
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
      \brief Constructor
      \param parent Parent widget
    
    
    Bryant's avatar
    Bryant committed
      Create a dial widget with no needle. The scale is initialized
      to [ 0.0, 360.0 ] and 360 steps ( QwtAbstractSlider::setTotalSteps() ).
      The origin of the scale is at 90°,
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      The value is set to 0.0.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      The default mode is QwtDial::RotateNeedle.
    
    Bryant's avatar
    Bryant committed
    QwtDial::QwtDial( QWidget* parent ):
        QwtAbstractSlider( parent )
    
    pixhawk's avatar
    pixhawk committed
    {
        d_data = new PrivateData;
    
    
    Bryant's avatar
    Bryant committed
        setFocusPolicy( Qt::TabFocus );
    
    pixhawk's avatar
    pixhawk committed
    
        QPalette p = palette();
    
    Bryant's avatar
    Bryant committed
        for ( int i = 0; i < QPalette::NColorGroups; i++ )
        {
            const QPalette::ColorGroup colorGroup =
                static_cast<QPalette::ColorGroup>( i );
    
    pixhawk's avatar
    pixhawk committed
    
            // Base: background color of the circle inside the frame.
    
    Bryant's avatar
    Bryant committed
            // WindowText: background color of the circle inside the scale
    
            p.setColor( colorGroup, QPalette::WindowText,
                p.color( colorGroup, QPalette::Base ) );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
        setPalette( p );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
        scaleDraw->setRadius( 0 );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        setScaleDraw( scaleDraw );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        setScaleArc( 0.0, 360.0 ); // scale as a full circle
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        setScaleMaxMajor( 10 );
        setScaleMaxMinor( 5 );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        setValue( 0.0 );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //!  Destructor
    QwtDial::~QwtDial()
    
    Bryant's avatar
    Bryant committed
        delete d_data;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Sets the frame shadow value from the frame style.
    
    Bryant's avatar
    Bryant committed
    
    
    pixhawk's avatar
    pixhawk committed
      \param shadow Frame shadow
      \sa setLineWidth(), QFrame::setFrameShadow()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setFrameShadow( Shadow shadow )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( shadow != d_data->frameShadow )
        {
            invalidateCache();
    
    
    pixhawk's avatar
    pixhawk committed
            d_data->frameShadow = shadow;
            if ( lineWidth() > 0 )
                update();
        }
    }
    
    /*!
      \return Frame shadow
    
    Bryant's avatar
    Bryant committed
      /sa setFrameShadow(), lineWidth(), QFrame::frameShadow()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    QwtDial::Shadow QwtDial::frameShadow() const
    {
        return d_data->frameShadow;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Sets the line width of the frame
    
    pixhawk's avatar
    pixhawk committed
    
      \param lineWidth Line width
      \sa setFrameShadow()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setLineWidth( int lineWidth )
    
    pixhawk's avatar
    pixhawk committed
    {
        if ( lineWidth < 0 )
            lineWidth = 0;
    
    
    Bryant's avatar
    Bryant committed
        if ( d_data->lineWidth != lineWidth )
        {
            invalidateCache();
    
    
    pixhawk's avatar
    pixhawk committed
            d_data->lineWidth = lineWidth;
            update();
        }
    }
    
    /*!
      \return Line width of the frame
      \sa setLineWidth(), frameShadow(), lineWidth()
    */
    
    int QwtDial::lineWidth() const
    {
        return d_data->lineWidth;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return bounding rectangle of the circle inside the frame
      \sa setLineWidth(), scaleInnerRect(), boundingRect()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    QRect QwtDial::innerRect() const
    
    pixhawk's avatar
    pixhawk committed
    {
        const int lw = lineWidth();
    
    Bryant's avatar
    Bryant committed
        return boundingRect().adjusted( lw, lw, -lw, -lw );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return bounding rectangle of the dial including the frame
      \sa setLineWidth(), scaleInnerRect(), innerRect()
    
    pixhawk's avatar
    pixhawk committed
    */
    QRect QwtDial::boundingRect() const
    {
    
    Bryant's avatar
    Bryant committed
        const QRect cr = contentsRect();
    
        const double dim = qMin( cr.width(), cr.height() );
    
        QRect inner( 0, 0, dim, dim );
        inner.moveCenter( cr.center() );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        return inner;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return rectangle inside the scale
      \sa setLineWidth(), boundingRect(), innerRect()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    QRect QwtDial::scaleInnerRect() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRect rect = innerRect();
    
        const QwtAbstractScaleDraw *sd = scaleDraw();
        if ( sd )
        {
            int scaleDist = qCeil( sd->extent( font() ) );
    
    pixhawk's avatar
    pixhawk committed
            scaleDist++; // margin
    
    Bryant's avatar
    Bryant committed
    
            rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        return rect;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief Change the mode of the dial.
    
      \param mode New mode
    
    
    Bryant's avatar
    Bryant committed
      In case of QwtDial::RotateNeedle the needle is rotating, in case of
    
    pixhawk's avatar
    pixhawk committed
      QwtDial::RotateScale, the needle points to origin()
      and the scale is rotating.
    
    pixhawk's avatar
    pixhawk committed
      The default mode is QwtDial::RotateNeedle.
    
      \sa mode(), setValue(), setOrigin()
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setMode( Mode mode )
    
    Bryant's avatar
    Bryant committed
        if ( mode != d_data->mode )
        {
            invalidateCache();
    
    
    pixhawk's avatar
    pixhawk committed
            d_data->mode = mode;
    
    Bryant's avatar
    Bryant committed
            sliderChange();
    
    pixhawk's avatar
    pixhawk committed
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \return Mode of the dial.
    
    pixhawk's avatar
    pixhawk committed
      \sa setMode(), origin(), setScaleArc(), value()
    */
    QwtDial::Mode QwtDial::mode() const
    {
        return d_data->mode;
    }
    
    
    Bryant's avatar
    Bryant committed
      Invalidate the internal caches used to speed up repainting
     */
    void QwtDial::invalidateCache()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        d_data->pixmapCache = QPixmap();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
       Paint the dial
       \param event Paint event
    
    Bryant's avatar
    Bryant committed
    void QwtDial::paintEvent( QPaintEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QPainter painter( this );
        painter.setClipRegion( event->region() );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QStyleOption opt;
        opt.init(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( d_data->mode == QwtDial::RotateScale )
        {
            painter.save();
            painter.setRenderHint( QPainter::Antialiasing, true );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            drawContents( &painter );
    
    pixhawk's avatar
    pixhawk committed
    
            painter.restore();
    
    Bryant's avatar
    Bryant committed
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        const QRect r = contentsRect();
        if ( r.size() != d_data->pixmapCache.size() )
        {
            d_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
            d_data->pixmapCache.fill( Qt::transparent );
    
            QPainter p( &d_data->pixmapCache );
            p.setRenderHint( QPainter::Antialiasing, true );
            p.translate( -r.topLeft() );
                
            if ( d_data->mode != QwtDial::RotateScale )
                drawContents( &p );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            if ( lineWidth() > 0 )
                drawFrame( &p );
    
            if ( d_data->mode != QwtDial::RotateNeedle )
                drawNeedle( &p );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
    
        painter.drawPixmap( r.topLeft(), d_data->pixmapCache );
    
        if ( d_data->mode == QwtDial::RotateNeedle )
            drawNeedle( &painter );
    
        if ( hasFocus() )
            drawFocusIndicator( &painter );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Draw the focus indicator
    
    pixhawk's avatar
    pixhawk committed
      \param painter Painter
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::drawFocusIndicator( QPainter *painter ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtPainter::drawFocusRect( painter, this, boundingRect() );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Draw the frame around the dial
    
      \param painter Painter
      \sa lineWidth(), frameShadow()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::drawFrame( QPainter *painter )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtPainter::drawRoundFrame( painter, boundingRect(),
            palette(), lineWidth(), d_data->frameShadow );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      \brief Draw the contents inside the frame
    
    Bryant's avatar
    Bryant committed
      QPalette::Window is the background color outside of the frame.
      QPalette::Base is the background color inside the frame.
      QPalette::WindowText is the background color inside the scale.
    
    pixhawk's avatar
    pixhawk committed
    
      \param painter Painter
    
    Bryant's avatar
    Bryant committed
    
      \sa boundingRect(), innerRect(),
        scaleInnerRect(), QWidget::setPalette()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::drawContents( QPainter *painter ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( testAttribute( Qt::WA_NoSystemBackground ) ||
            palette().brush( QPalette::Base ) !=
                palette().brush( QPalette::Window ) )
    
    pixhawk's avatar
    pixhawk committed
        {
    
    Bryant's avatar
    Bryant committed
            const QRectF br = boundingRect();
    
    pixhawk's avatar
    pixhawk committed
    
            painter->save();
    
    Bryant's avatar
    Bryant committed
            painter->setPen( Qt::NoPen );
            painter->setBrush( palette().brush( QPalette::Base ) );
            painter->drawEllipse( br );
    
    pixhawk's avatar
    pixhawk committed
            painter->restore();
        }
    
    
    Bryant's avatar
    Bryant committed
        const QRectF insideScaleRect = scaleInnerRect();
        if ( palette().brush( QPalette::WindowText ) !=
                palette().brush( QPalette::Base ) )
    
    pixhawk's avatar
    pixhawk committed
        {
            painter->save();
    
    Bryant's avatar
    Bryant committed
            painter->setPen( Qt::NoPen );
            painter->setBrush( palette().brush( QPalette::WindowText ) );
            painter->drawEllipse( insideScaleRect );
    
    pixhawk's avatar
    pixhawk committed
            painter->restore();
        }
    
    
    Bryant's avatar
    Bryant committed
        const QPointF center = insideScaleRect.center();
        const double radius = 0.5 * insideScaleRect.width();
    
    pixhawk's avatar
    pixhawk committed
    
        painter->save();
    
    Bryant's avatar
    Bryant committed
        drawScale( painter, center, radius );
    
    pixhawk's avatar
    pixhawk committed
        painter->restore();
    
        painter->save();
    
    Bryant's avatar
    Bryant committed
        drawScaleContents( painter, center, radius );
    
    pixhawk's avatar
    pixhawk committed
        painter->restore();
    }
    
    /*!
      Draw the needle
    
      \param painter Painter
      \param center Center of the dial
      \param radius Length for the needle
      \param direction Direction of the needle in degrees, counter clockwise
    
    Bryant's avatar
    Bryant committed
      \param colorGroup ColorGroup
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::drawNeedle( QPainter *painter, const QPointF &center,
        double radius, double direction, QPalette::ColorGroup colorGroup ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( d_data->needle )
        {
    
    pixhawk's avatar
    pixhawk committed
            direction = 360.0 - direction; // counter clockwise
    
    Bryant's avatar
    Bryant committed
            d_data->needle->draw( painter, center, radius, direction, colorGroup );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    
    Bryant's avatar
    Bryant committed
    void QwtDial::drawNeedle( QPainter *painter ) const
    {
        if ( !isValid() )
            return;
    
        QPalette::ColorGroup colorGroup;
        if ( isEnabled() )
            colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
        else
            colorGroup = QPalette::Disabled;
    
        const QRectF sr = scaleInnerRect();
    
        painter->save();
        painter->setRenderHint( QPainter::Antialiasing, true );
        drawNeedle( painter, sr.center(), 0.5 * sr.width(),
            transform( value() ) + 270.0, colorGroup );
        painter->restore();
    }
    
    
    pixhawk's avatar
    pixhawk committed
    /*!
      Draw the scale
    
      \param painter Painter
      \param center Center of the dial
      \param radius Radius of the scale
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::drawScale( QPainter *painter, 
        const QPointF &center, double radius ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
        if ( sd == NULL )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        sd->setRadius( radius );
        sd->moveCenter( center );
    
    pixhawk's avatar
    pixhawk committed
        QPalette pal = palette();
    
    
    Bryant's avatar
    Bryant committed
        const QColor textColor = pal.color( QPalette::Text );
        pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
    
    Bryant's avatar
    Bryant committed
        painter->setFont( font() );
        painter->setPen( QPen( textColor, sd->penWidth() ) );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->setBrush( Qt::red );
        sd->draw( painter, pal );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Draw the contents inside the scale
    
      Paints nothing.
    
      \param painter Painter
      \param center Center of the contents circle
      \param radius Radius of the contents circle
    */
    void QwtDial::drawScaleContents( QPainter *painter,
        const QPointF &center, double radius ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        Q_UNUSED(painter);
        Q_UNUSED(center);
        Q_UNUSED(radius);
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Set a needle for the dial
    
      \param needle Needle
    
    Bryant's avatar
    Bryant committed
    
    
    pixhawk's avatar
    pixhawk committed
      \warning The needle will be deleted, when a different needle is
    
    Bryant's avatar
    Bryant committed
               set or in ~QwtDial()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setNeedle( QwtDialNeedle *needle )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( needle != d_data->needle )
        {
    
    pixhawk's avatar
    pixhawk committed
            if ( d_data->needle )
                delete d_data->needle;
    
            d_data->needle = needle;
            update();
        }
    }
    
    
    pixhawk's avatar
    pixhawk committed
      \return needle
      \sa setNeedle()
    */
    
    const QwtDialNeedle *QwtDial::needle() const
    {
        return d_data->needle;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    pixhawk's avatar
    pixhawk committed
      \return needle
      \sa setNeedle()
    */
    
    QwtDialNeedle *QwtDial::needle()
    {
        return d_data->needle;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! \return the scale draw
    QwtRoundScaleDraw *QwtDial::scaleDraw()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! \return the scale draw
    const QwtRoundScaleDraw *QwtDial::scaleDraw() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Set an individual scale draw
    
    
    Bryant's avatar
    Bryant committed
      The motivation for setting a scale draw is often
      to overload QwtRoundScaleDraw::label() to return 
      individual tick labels.
      
    
    pixhawk's avatar
    pixhawk committed
      \param scaleDraw Scale draw
      \warning The previous scale draw is deleted
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setAbstractScaleDraw( scaleDraw );
        sliderChange();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Change the arc of the scale
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param minArc Lower limit
      \param maxArc Upper limit
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \sa minScaleArc(), maxScaleArc()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setScaleArc( double minArc, double maxArc )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( minArc != 360.0 && minArc != -360.0 )
            minArc = ::fmod( minArc, 360.0 );
        if ( maxArc != 360.0 && maxArc != -360.0 )
            maxArc = ::fmod( maxArc, 360.0 );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        double minScaleArc = qMin( minArc, maxArc );
        double maxScaleArc = qMax( minArc, maxArc );
    
    Bryant's avatar
    Bryant committed
        if ( maxScaleArc - minScaleArc > 360.0 )
            maxScaleArc = minScaleArc + 360.0;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( ( minScaleArc != d_data->minScaleArc ) || 
            ( maxScaleArc != d_data->maxScaleArc ) )
        {
            d_data->minScaleArc = minScaleArc;
            d_data->maxScaleArc = maxScaleArc;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            invalidateCache();
            sliderChange();
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    
    Bryant's avatar
    Bryant committed
    /*! 
      Set the lower limit for the scale arc
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param min Lower limit of the scale arc
      \sa setScaleArc(), setMaxScaleArc()
     */
    void QwtDial::setMinScaleArc( double min )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setScaleArc( min, d_data->maxScaleArc );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*! 
      \return Lower limit of the scale arc
      \sa setScaleArc()
    */
    
    double QwtDial::minScaleArc() const
    {
        return d_data->minScaleArc;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*! 
      Set the upper limit for the scale arc
    
      \param max Upper limit of the scale arc
      \sa setScaleArc(), setMinScaleArc()
     */
    void QwtDial::setMaxScaleArc( double max )
    {
        setScaleArc( d_data->minScaleArc, max );
    }
    
    /*! 
      \return Upper limit of the scale arc
      \sa setScaleArc()
    */
    
    double QwtDial::maxScaleArc() const
    {
        return d_data->maxScaleArc;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
      \brief Change the origin
    
    
    pixhawk's avatar
    pixhawk committed
      The origin is the angle where scale and needle is relative to.
    
      \param origin New origin
      \sa origin()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setOrigin( double origin )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        invalidateCache();
    
    
    pixhawk's avatar
    pixhawk committed
        d_data->origin = origin;
    
    Bryant's avatar
    Bryant committed
        sliderChange();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      The origin is the angle where scale and needle is relative to.
    
      \return Origin of the dial
      \sa setOrigin()
    */
    double QwtDial::origin() const
    {
        return d_data->origin;
    }
    
    /*!
      \return Size hint
    
    Bryant's avatar
    Bryant committed
      \sa minimumSizeHint()
    
    pixhawk's avatar
    pixhawk committed
    */
    QSize QwtDial::sizeHint() const
    {
        int sh = 0;
    
    Bryant's avatar
    Bryant committed
        if ( scaleDraw() )
            sh = qCeil( scaleDraw()->extent( font() ) );
    
    pixhawk's avatar
    pixhawk committed
    
        const int d = 6 * sh + 2 * lineWidth();
    
    Bryant's avatar
    Bryant committed
        QSize hint( d, d ); 
        if ( !isReadOnly() )
            hint = hint.expandedTo( QApplication::globalStrut() );
    
        return hint;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
      \return Minimum size hint
      \sa sizeHint()
    
    pixhawk's avatar
    pixhawk committed
    QSize QwtDial::minimumSizeHint() const
    
    pixhawk's avatar
    pixhawk committed
        int sh = 0;
    
    Bryant's avatar
    Bryant committed
        if ( scaleDraw() )
            sh = qCeil( scaleDraw()->extent( font() ) );
    
    pixhawk's avatar
    pixhawk committed
    
        const int d = 3 * sh + 2 * lineWidth();
    
    pixhawk's avatar
    pixhawk committed
        return QSize( d, d );
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \brief Determine what to do when the user presses a mouse button.
    
      \param pos Mouse position
    
      \retval True, when the inner circle contains pos 
      \sa scrolledTo()
    */
    bool QwtDial::isScrollPosition( const QPoint &pos ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const QRegion region( innerRect(), QRegion::Ellipse );
        if ( region.contains( pos ) && ( pos != innerRect().center() ) )
        {
            double angle = QLineF( rect().center(), pos ).angle();
            if ( d_data->mode == QwtDial::RotateScale )
                angle = 360.0 - angle;
    
            double valueAngle = 
                qwtNormalizeDegrees( 90.0 - transform( value() ) );
    
            d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
            d_data->arcOffset = scaleMap().p1();
    
            return true;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
    
        return false;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief Determine the value for a new position of the
             slider handle.
    
      \param pos Mouse position
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \return Value for the mouse position
      \sa isScrollPosition()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    double QwtDial::scrolledTo( const QPoint &pos ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        double angle = QLineF( rect().center(), pos ).angle();
        if ( d_data->mode == QwtDial::RotateScale )
        {
            angle += scaleMap().p1() - d_data->arcOffset;
            angle = 360.0 - angle;
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
        angle = qwtNormalizeDegrees( 90.0 - angle );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( scaleMap().pDist() >= 360.0 )
        {
            if ( angle < scaleMap().p1() )
                angle += 360.0;
    
            if ( !wrapping() )
            {
                double boundedAngle = angle;
    
                const double arc = angle - transform( value() );
                if ( qAbs( arc ) > 180.0 )
                {
                    boundedAngle = ( arc > 0 ) 
                        ? scaleMap().p1() : scaleMap().p2();
    
    pixhawk's avatar
    pixhawk committed
                }
    
    Bryant's avatar
    Bryant committed
    
                d_data->mouseOffset += ( boundedAngle - angle );
    
                angle = boundedAngle;
    
    pixhawk's avatar
    pixhawk committed
            }
    
    Bryant's avatar
    Bryant committed
        }
        else
        {
            const double boundedAngle =
                qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
    
            if ( !wrapping() )
                d_data->mouseOffset += ( boundedAngle - angle );
    
            angle = boundedAngle;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        return invTransform( angle );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Change Event handler
      \param event Change event
    
      Invalidates internal paint caches if necessary
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::changeEvent( QEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        switch( event->type() )
        {
            case QEvent::EnabledChange:
            case QEvent::FontChange:
            case QEvent::StyleChange:
            case QEvent::PaletteChange:
            case QEvent::LanguageChange:
            case QEvent::LocaleChange:
            {
                invalidateCache();
                break;
            }
            default:
                break;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
        
        QwtAbstractSlider::changeEvent( event );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
      Wheel Event handler
      \param event Wheel event
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtDial::wheelEvent( QWheelEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const QRegion region( innerRect(), QRegion::Ellipse );
        if ( region.contains( event->pos() ) )
            QwtAbstractSlider::wheelEvent( event );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    void QwtDial::setAngleRange( double angle, double span )
    {
        QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
        if ( sd  )
        {
            angle = qwtNormalizeDegrees( angle - 270.0 );
            sd->setAngleRange( angle, angle + span );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Invalidate the internal caches and call 
      QwtAbstractSlider::scaleChange()
     */
    void QwtDial::scaleChange()
    {
        invalidateCache();
        QwtAbstractSlider::scaleChange();
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    void QwtDial::sliderChange()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setAngleRange( d_data->origin + d_data->minScaleArc,
            d_data->maxScaleArc - d_data->minScaleArc );
    
        if ( mode() == RotateScale )
        {
            const double arc = transform( value() ) - scaleMap().p1();
            setAngleRange( d_data->origin - arc,
                d_data->maxScaleArc - d_data->minScaleArc );
        }
    
        QwtAbstractSlider::sliderChange();
    
    pixhawk's avatar
    pixhawk committed
    }