Skip to content
Snippets Groups Projects
qwt_picker.cpp 38.3 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_picker.h"
    #include "qwt_picker_machine.h"
    #include "qwt_painter.h"
    #include "qwt_math.h"
    #include "qwt_widget_overlay.h"
    
    pixhawk's avatar
    pixhawk committed
    #include <qapplication.h>
    #include <qevent.h>
    #include <qpainter.h>
    #include <qframe.h>
    #include <qcursor.h>
    #include <qbitmap.h>
    #include <qpointer.h>
    #include <qpaintengine.h>
    
    Bryant's avatar
    Bryant committed
    #include <qmath.h>
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    static inline QRegion qwtMaskRegion( const QRect &r, int penWidth )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const int pw = qMax( penWidth, 1 );
        const int pw2 = penWidth / 2;
    
        int x1 = r.left() - pw2;
        int x2 = r.right() + 1 + pw2 + ( pw % 2 );
    
        int y1 = r.top() - pw2;
        int y2 = r.bottom() + 1 + pw2 + ( pw % 2 );
    
        QRegion region;
    
        region += QRect( x1, y1, x2 - x1, pw );
        region += QRect( x1, y1, pw, y2 - y1 );
        region += QRect( x1, y2 - pw, x2 - x1, pw );
        region += QRect( x2 - pw, y1, pw, y2 - y1 );
    
        return region;
    }
    
    static inline QRegion qwtMaskRegion( const QLine &l, int penWidth )
    {
        const int pw = qMax( penWidth, 1 );
        const int pw2 = penWidth / 2;
    
        QRegion region;
    
        if ( l.x1() == l.x2() )
        {
            region += QRect( l.x1() - pw2, l.y1(), 
                pw, l.y2() ).normalized();
        }
        else if ( l.y1() == l.y2() )
        {
            region += QRect( l.x1(), l.y1() - pw2, 
                l.x2(), pw ).normalized();
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        return region;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    class QwtPickerRubberband: public QwtWidgetOverlay
    {
    public:
        QwtPickerRubberband( QwtPicker *, QWidget * );
    
    pixhawk's avatar
    pixhawk committed
    
    protected:
    
    Bryant's avatar
    Bryant committed
        virtual void drawOverlay( QPainter * ) const;
        virtual QRegion maskHint() const;
    
    pixhawk's avatar
    pixhawk committed
    
        QwtPicker *d_picker;
    };
    
    
    Bryant's avatar
    Bryant committed
    class QwtPickerTracker: public QwtWidgetOverlay
    {                                  
    public:
        QwtPickerTracker( QwtPicker *, QWidget * );
        
    protected:
        virtual void drawOverlay( QPainter * ) const;
        virtual QRegion maskHint() const;
        
        QwtPicker *d_picker;
    };  
    
    
    
    pixhawk's avatar
    pixhawk committed
    class QwtPicker::PrivateData
    {
    public:
    
    Bryant's avatar
    Bryant committed
        PrivateData():
            enabled( false ),
            stateMachine( NULL ),
            resizeMode( QwtPicker::Stretch ),
            rubberBand( QwtPicker::NoRubberBand ),
            trackerMode( QwtPicker::AlwaysOff ),
            isActive( false ),
            trackerPosition( -1, -1 ),
            mouseTracking( false ),
            openGL( false )
        {
        }
            
    
    pixhawk's avatar
    pixhawk committed
        bool enabled;
    
        QwtPickerMachine *stateMachine;
    
        QwtPicker::ResizeMode resizeMode;
    
        QwtPicker::RubberBand rubberBand;
        QPen rubberBandPen;
    
        QwtPicker::DisplayMode trackerMode;
        QPen trackerPen;
        QFont trackerFont;
    
    
    Bryant's avatar
    Bryant committed
        QPolygon pickedPoints;
    
    pixhawk's avatar
    pixhawk committed
        bool isActive;
        QPoint trackerPosition;
    
        bool mouseTracking; // used to save previous value
    
    
    Bryant's avatar
    Bryant committed
        QPointer< QwtPickerRubberband > rubberBandOverlay;
        QPointer< QwtPickerTracker> trackerOverlay;
    
        bool openGL;
    
    pixhawk's avatar
    pixhawk committed
    };
    
    
    Bryant's avatar
    Bryant committed
    QwtPickerRubberband::QwtPickerRubberband(
            QwtPicker *picker, QWidget *parent ):
        QwtWidgetOverlay( parent ),
        d_picker( picker )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setMaskMode( QwtWidgetOverlay::MaskHint );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    QRegion QwtPickerRubberband::maskHint() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_picker->rubberBandMask();
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    void QwtPickerRubberband::drawOverlay( QPainter *painter ) const
    {
        painter->setPen( d_picker->rubberBandPen() );
        d_picker->drawRubberBand( painter );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    QwtPickerTracker::QwtPickerTracker(
            QwtPicker *picker, QWidget *parent ):
        QwtWidgetOverlay( parent ),
        d_picker( picker )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setMaskMode( QwtWidgetOverlay::MaskHint );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    QRegion QwtPickerTracker::maskHint() const
    {
        return d_picker->trackerRect( font() );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    void QwtPickerTracker::drawOverlay( QPainter *painter ) const
    {
        painter->setPen( d_picker->trackerPen() );
        d_picker->drawTracker( painter );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Constructor
    
    
    Bryant's avatar
    Bryant committed
      Creates an picker that is enabled, but without a state machine.
      rubber band and tracker are disabled.
    
    pixhawk's avatar
    pixhawk committed
      \param parent Parent widget, that will be observed
     */
    
    
    Bryant's avatar
    Bryant committed
    QwtPicker::QwtPicker( QWidget *parent ):
        QObject( parent )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        init( parent, NoRubberBand, AlwaysOff );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Constructor
    
    
    Bryant's avatar
    Bryant committed
      \param rubberBand Rubber band style
    
    pixhawk's avatar
    pixhawk committed
      \param trackerMode Tracker mode
      \param parent Parent widget, that will be observed
     */
    
    Bryant's avatar
    Bryant committed
    QwtPicker::QwtPicker( RubberBand rubberBand,
            DisplayMode trackerMode, QWidget *parent ):
        QObject( parent )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        init( parent, rubberBand, trackerMode );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //! Destructor
    QwtPicker::~QwtPicker()
    {
    
    Bryant's avatar
    Bryant committed
        setMouseTracking( false );
    
    
    pixhawk's avatar
    pixhawk committed
        delete d_data->stateMachine;
    
    Bryant's avatar
    Bryant committed
        delete d_data->rubberBandOverlay;
        delete d_data->trackerOverlay;
    
    
    pixhawk's avatar
    pixhawk committed
        delete d_data;
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Initialize the picker - used by the constructors
    void QwtPicker::init( QWidget *parent,
        RubberBand rubberBand, DisplayMode trackerMode )
    
    pixhawk's avatar
    pixhawk committed
    {
        d_data = new PrivateData;
    
        d_data->rubberBand = rubberBand;
    
    Bryant's avatar
    Bryant committed
    
        if ( parent )
        {
    
    pixhawk's avatar
    pixhawk committed
            if ( parent->focusPolicy() == Qt::NoFocus )
    
    Bryant's avatar
    Bryant committed
                parent->setFocusPolicy( Qt::WheelFocus );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            d_data->openGL = parent->inherits( "QGLWidget" );
    
    pixhawk's avatar
    pixhawk committed
            d_data->trackerFont = parent->font();
            d_data->mouseTracking = parent->hasMouseTracking();
    
    Bryant's avatar
    Bryant committed
    
            setEnabled( true );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
    
        setTrackerMode( trackerMode );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Set a state machine and delete the previous one
    
      \param stateMachine State machine
      \sa stateMachine()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setStateMachine( QwtPickerMachine *stateMachine )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( d_data->stateMachine != stateMachine )
        {
    
    pixhawk's avatar
    pixhawk committed
            reset();
    
            delete d_data->stateMachine;
            d_data->stateMachine = stateMachine;
    
            if ( d_data->stateMachine )
                d_data->stateMachine->reset();
        }
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return Assigned state machine
      \sa setStateMachine()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    QwtPickerMachine *QwtPicker::stateMachine()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_data->stateMachine;
    }
    
    /*!
      \return Assigned state machine
      \sa setStateMachine()
    */
    const QwtPickerMachine *QwtPicker::stateMachine() const
    {
        return d_data->stateMachine;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //! Return the parent widget, where the selection happens
    QWidget *QwtPicker::parentWidget()
    {
        QObject *obj = parent();
        if ( obj && obj->isWidgetType() )
    
    Bryant's avatar
    Bryant committed
            return static_cast<QWidget *>( obj );
    
    pixhawk's avatar
    pixhawk committed
    
        return NULL;
    }
    
    //! Return the parent widget, where the selection happens
    const QWidget *QwtPicker::parentWidget() const
    {
        QObject *obj = parent();
        if ( obj && obj->isWidgetType() )
    
    Bryant's avatar
    Bryant committed
            return static_cast< const QWidget *>( obj );
    
    pixhawk's avatar
    pixhawk committed
    
        return NULL;
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Set the rubber band style
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param rubberBand Rubber band style
    
    pixhawk's avatar
    pixhawk committed
             The default value is NoRubberBand.
    
      \sa rubberBand(), RubberBand, setRubberBandPen()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setRubberBand( RubberBand rubberBand )
    
    pixhawk's avatar
    pixhawk committed
    {
        d_data->rubberBand = rubberBand;
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return Rubber band style
    
    pixhawk's avatar
    pixhawk committed
      \sa setRubberBand(), RubberBand, rubberBandPen()
    */
    QwtPicker::RubberBand QwtPicker::rubberBand() const
    {
        return d_data->rubberBand;
    }
    
    /*!
      \brief Set the display mode of the tracker.
    
      A tracker displays information about current position of
      the cursor as a string. The display mode controls
      if the tracker has to be displayed whenever the observed
      widget has focus and cursor (AlwaysOn), never (AlwaysOff), or
      only when the selection is active (ActiveOnly).
    
    pixhawk's avatar
    pixhawk committed
      \param mode Tracker display mode
    
      \warning In case of AlwaysOn, mouseTracking will be enabled
               for the observed widget.
      \sa trackerMode(), DisplayMode
    */
    
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setTrackerMode( DisplayMode mode )
    
    Bryant's avatar
    Bryant committed
        if ( d_data->trackerMode != mode )
        {
    
    pixhawk's avatar
    pixhawk committed
            d_data->trackerMode = mode;
    
    Bryant's avatar
    Bryant committed
            setMouseTracking( d_data->trackerMode == AlwaysOn );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
      \return Tracker display mode
      \sa setTrackerMode(), DisplayMode
    */
    QwtPicker::DisplayMode QwtPicker::trackerMode() const
    
    pixhawk's avatar
    pixhawk committed
        return d_data->trackerMode;
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
      \brief Set the resize mode.
    
      The resize mode controls what to do with the selected points of an active
      selection when the observed widget is resized.
    
      Stretch means the points are scaled according to the new
      size, KeepSize means the points remain unchanged.
    
      The default mode is Stretch.
    
      \param mode Resize mode
      \sa resizeMode(), ResizeMode
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setResizeMode( ResizeMode mode )
    
    pixhawk's avatar
    pixhawk committed
    {
        d_data->resizeMode = mode;
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
      \return Resize mode
      \sa setResizeMode(), ResizeMode
    */
    
    QwtPicker::ResizeMode QwtPicker::resizeMode() const
    
    pixhawk's avatar
    pixhawk committed
        return d_data->resizeMode;
    }
    
    /*!
      \brief En/disable the picker
    
      When enabled is true an event filter is installed for
      the observed widget, otherwise the event filter is removed.
    
      \param enabled true or false
      \sa isEnabled(), eventFilter()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setEnabled( bool enabled )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( d_data->enabled != enabled )
        {
    
    pixhawk's avatar
    pixhawk committed
            d_data->enabled = enabled;
    
            QWidget *w = parentWidget();
    
    Bryant's avatar
    Bryant committed
            if ( w )
            {
    
    pixhawk's avatar
    pixhawk committed
                if ( enabled )
    
    Bryant's avatar
    Bryant committed
                    w->installEventFilter( this );
    
    pixhawk's avatar
    pixhawk committed
                else
    
    Bryant's avatar
    Bryant committed
                    w->removeEventFilter( this );
    
    pixhawk's avatar
    pixhawk committed
            }
    
            updateDisplay();
        }
    }
    
    /*!
      \return true when enabled, false otherwise
    
    Bryant's avatar
    Bryant committed
      \sa setEnabled(), eventFilter()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    bool QwtPicker::isEnabled() const
    {
        return d_data->enabled;
    }
    
    /*!
      Set the font for the tracker
    
      \param font Tracker font
      \sa trackerFont(), setTrackerMode(), setTrackerPen()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setTrackerFont( const QFont &font )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( font != d_data->trackerFont )
        {
    
    pixhawk's avatar
    pixhawk committed
            d_data->trackerFont = font;
            updateDisplay();
        }
    }
    
    /*!
      \return Tracker font
      \sa setTrackerFont(), trackerMode(), trackerPen()
    */
    
    QFont QwtPicker::trackerFont() const
    {
        return d_data->trackerFont;
    }
    
    /*!
      Set the pen for the tracker
    
      \param pen Tracker pen
      \sa trackerPen(), setTrackerMode(), setTrackerFont()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setTrackerPen( const QPen &pen )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( pen != d_data->trackerPen )
        {
    
    pixhawk's avatar
    pixhawk committed
            d_data->trackerPen = pen;
            updateDisplay();
        }
    }
    
    /*!
      \return Tracker pen
      \sa setTrackerPen(), trackerMode(), trackerFont()
    */
    QPen QwtPicker::trackerPen() const
    {
        return d_data->trackerPen;
    }
    
    /*!
      Set the pen for the rubberband
    
    
    Bryant's avatar
    Bryant committed
      \param pen Rubber band pen
    
    pixhawk's avatar
    pixhawk committed
      \sa rubberBandPen(), setRubberBand()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::setRubberBandPen( const QPen &pen )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( pen != d_data->rubberBandPen )
        {
    
    pixhawk's avatar
    pixhawk committed
            d_data->rubberBandPen = pen;
            updateDisplay();
        }
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return Rubber band pen
    
    pixhawk's avatar
    pixhawk committed
      \sa setRubberBandPen(), rubberBand()
    */
    QPen QwtPicker::rubberBandPen() const
    {
        return d_data->rubberBandPen;
    }
    
    /*!
       \brief Return the label for a position
    
       In case of HLineRubberBand the label is the value of the
       y position, in case of VLineRubberBand the value of the x position.
       Otherwise the label contains x and y position separated by a ',' .
    
       The format for the string conversion is "%d".
    
       \param pos Position
       \return Converted position as string
    */
    
    
    Bryant's avatar
    Bryant committed
    QwtText QwtPicker::trackerText( const QPoint &pos ) const
    
    pixhawk's avatar
    pixhawk committed
    {
        QString label;
    
    
    Bryant's avatar
    Bryant committed
        switch ( rubberBand() )
        {
            case HLineRubberBand:
                label.sprintf( "%d", pos.y() );
                break;
            case VLineRubberBand:
                label.sprintf( "%d", pos.x() );
                break;
            default:
                label.sprintf( "%d, %d", pos.x(), pos.y() );
    
    pixhawk's avatar
    pixhawk committed
        }
        return label;
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Calculate the mask for the rubber band overlay
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \return Region for the mask
      \sa QWidget::setMask()
     */
    QRegion QwtPicker::rubberBandMask() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRegion mask;
    
    
        if ( !isActive() || rubberBand() == NoRubberBand ||
    
    Bryant's avatar
    Bryant committed
            rubberBandPen().style() == Qt::NoPen )
        {
            return mask;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        const QPolygon pa = adjustedPoints( d_data->pickedPoints );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QwtPickerMachine::SelectionType selectionType =
            QwtPickerMachine::NoSelection;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( d_data->stateMachine )
            selectionType = d_data->stateMachine->selectionType();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        switch ( selectionType )
        {
            case QwtPickerMachine::NoSelection:
            case QwtPickerMachine::PointSelection:
            {
                if ( pa.count() < 1 )
                    return mask;
    
                const QPoint pos = pa[0];
                const int pw = rubberBandPen().width();
    
                const QRect pRect = pickArea().boundingRect().toRect();
                switch ( rubberBand() )
                {
                    case VLineRubberBand:
                    {
                        mask += qwtMaskRegion( QLine( pos.x(), pRect.top(), 
                            pos.x(), pRect.bottom() ), pw );
                        break;
                    }
                    case HLineRubberBand:
                    {
                        mask += qwtMaskRegion( QLine( pRect.left(), pos.y(), 
                            pRect.right(), pos.y() ), pw );
                        break;
                    }
                    case CrossRubberBand:
                    {
                        mask += qwtMaskRegion( QLine( pos.x(), pRect.top(), 
                            pos.x(), pRect.bottom() ), pw );
                        mask += qwtMaskRegion( QLine( pRect.left(), pos.y(), 
                            pRect.right(), pos.y() ), pw );
                        break;
                    }
                    default:
                        break;
                }
    
    Bryant's avatar
    Bryant committed
            }
            case QwtPickerMachine::RectSelection:
            {
                if ( pa.count() < 2 )
                    return mask;
    
    Bryant's avatar
    Bryant committed
                const int pw = rubberBandPen().width();
    
                switch ( rubberBand() )
                {
                    case RectRubberBand:
                    {
                        const QRect r = QRect( pa.first(), pa.last() );
                        mask = qwtMaskRegion( r.normalized(), pw );
                        break;
                    }
                    case EllipseRubberBand:
                    {
                        const QRect r = QRect( pa.first(), pa.last() );
                        mask += r.adjusted( -pw, -pw, pw, pw );
                        break;
                    }
                    default:
                        break;
                }
    
    Bryant's avatar
    Bryant committed
            }
            case QwtPickerMachine::PolygonSelection:
            {
                const int pw = rubberBandPen().width();
                if ( pw <= 1 )
                {
                    // because of the join style we better
                    // return a mask for a pen width <= 1 only
    
    Bryant's avatar
    Bryant committed
                    const int off = 2 * pw;
                    const QRect r = pa.boundingRect();
                    mask += r.adjusted( -off, -off, off, off );
                }
    
    Bryant's avatar
    Bryant committed
            }
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        return mask;
    }
    
    /*!
       Draw a rubber band, depending on rubberBand()
    
       \param painter Painter, initialized with a clip region
    
       \sa rubberBand(), RubberBand
    */
    
    void QwtPicker::drawRubberBand( QPainter *painter ) const
    {
        if ( !isActive() || rubberBand() == NoRubberBand ||
            rubberBandPen().style() == Qt::NoPen )
        {
            return;
        }
    
        const QPolygon pa = adjustedPoints( d_data->pickedPoints );
    
        QwtPickerMachine::SelectionType selectionType =
            QwtPickerMachine::NoSelection;
    
        if ( d_data->stateMachine )
            selectionType = d_data->stateMachine->selectionType();
    
        switch ( selectionType )
        {
            case QwtPickerMachine::NoSelection:
            case QwtPickerMachine::PointSelection:
            {
                if ( pa.count() < 1 )
                    return;
    
                const QPoint pos = pa[0];
    
                const QRect pRect = pickArea().boundingRect().toRect();
                switch ( rubberBand() )
                {
                    case VLineRubberBand:
                    {
                        QwtPainter::drawLine( painter, pos.x(),
                            pRect.top(), pos.x(), pRect.bottom() );
                        break;
                    }
                    case HLineRubberBand:
                    {
                        QwtPainter::drawLine( painter, pRect.left(),
                            pos.y(), pRect.right(), pos.y() );
                        break;
                    }
                    case CrossRubberBand:
                    {
                        QwtPainter::drawLine( painter, pos.x(),
                            pRect.top(), pos.x(), pRect.bottom() );
                        QwtPainter::drawLine( painter, pRect.left(),
                            pos.y(), pRect.right(), pos.y() );
                        break;
                    }
                    default:
                        break;
                }
                break;
    
    pixhawk's avatar
    pixhawk committed
            }
    
    Bryant's avatar
    Bryant committed
            case QwtPickerMachine::RectSelection:
            {
                if ( pa.count() < 2 )
                    return;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                const QRect rect = QRect( pa.first(), pa.last() ).normalized();
                switch ( rubberBand() )
                {
                    case EllipseRubberBand:
                    {
                        QwtPainter::drawEllipse( painter, rect );
                        break;
                    }
                    case RectRubberBand:
                    {
                        QwtPainter::drawRect( painter, rect );
                        break;
                    }
                    default:
                        break;
                }
    
    Bryant's avatar
    Bryant committed
            }
            case QwtPickerMachine::PolygonSelection:
            {
                if ( rubberBand() == PolygonRubberBand )
                    painter->drawPolyline( pa );
    
    Bryant's avatar
    Bryant committed
            }
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    /*!
       Draw the tracker
    
       \param painter Painter
       \sa trackerRect(), trackerText()
    */
    
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::drawTracker( QPainter *painter ) const
    {
        const QRect textRect = trackerRect( painter->font() );
        if ( !textRect.isEmpty() )
        {
            const QwtText label = trackerText( d_data->trackerPosition );
            if ( !label.isEmpty() )
                label.draw( painter, textRect );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
       \brief Map the pickedPoints() into a selection()
    
       adjustedPoints() maps the points, that have been collected on
       the parentWidget() into a selection(). The default implementation
       simply returns the points unmodified.
    
       The reason, why a selection() differs from the picked points
       depends on the application requirements. F.e. :
    
       - A rectangular selection might need to have a specific aspect ratio only.\n
       - A selection could accept non intersecting polygons only.\n
       - ...\n
    
       The example below is for a rectangular selection, where the first
       point is the center of the selected rectangle.
      \par Example
      \verbatim QPolygon MyPicker::adjustedPoints(const QPolygon &points) const
    {
        QPolygon adjusted;
        if ( points.size() == 2 )
        {
            const int width = qAbs(points[1].x() - points[0].x());
            const int height = qAbs(points[1].y() - points[0].y());
    
            QRect rect(0, 0, 2 * width, 2 * height);
            rect.moveCenter(points[0]);
    
            adjusted += rect.topLeft();
            adjusted += rect.bottomRight();
        }
        return adjusted;
    }\endverbatim\n
    
      \param points Selected points
      \return Selected points unmodified
    */
    QPolygon QwtPicker::adjustedPoints( const QPolygon &points ) const
    {
        return points;
    }
    
    /*!
      \return Selected points
      \sa pickedPoints(), adjustedPoints()
    */
    QPolygon QwtPicker::selection() const
    {
        return adjustedPoints( d_data->pickedPoints );
    }
    
    //! \return Current position of the tracker
    
    QPoint QwtPicker::trackerPosition() const
    
    pixhawk's avatar
    pixhawk committed
    {
        return d_data->trackerPosition;
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
       Calculate the bounding rectangle for the tracker text
       from the current position of the tracker
    
       \param font Font of the tracker text
       \return Bounding rectangle of the tracker text
    
       \sa trackerPosition()
    */
    QRect QwtPicker::trackerRect( const QFont &font ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
        if ( trackerMode() == AlwaysOff ||
    
    Bryant's avatar
    Bryant committed
            ( trackerMode() == ActiveOnly && !isActive() ) )
        {
    
    pixhawk's avatar
    pixhawk committed
            return QRect();
        }
    
        if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
            return QRect();
    
    
    Bryant's avatar
    Bryant committed
        QwtText text = trackerText( d_data->trackerPosition );
    
    pixhawk's avatar
    pixhawk committed
        if ( text.isEmpty() )
            return QRect();
    
    
    Bryant's avatar
    Bryant committed
        const QSizeF textSize = text.textSize( font );
        QRect textRect( 0, 0, qCeil( textSize.width() ), qCeil( textSize.height() ) );
    
    pixhawk's avatar
    pixhawk committed
    
        const QPoint &pos = d_data->trackerPosition;
    
        int alignment = 0;
    
    Bryant's avatar
    Bryant committed
        if ( isActive() && d_data->pickedPoints.count() > 1
            && rubberBand() != NoRubberBand )
        {
    
            const QPoint last =
    
    Bryant's avatar
    Bryant committed
                d_data->pickedPoints[int( d_data->pickedPoints.count() ) - 2];
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft;
            alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop;
        }
        else
    
    pixhawk's avatar
    pixhawk committed
            alignment = Qt::AlignTop | Qt::AlignRight;
    
        const int margin = 5;
    
        int x = pos.x();
        if ( alignment & Qt::AlignLeft )
            x -= textRect.width() + margin;
        else if ( alignment & Qt::AlignRight )
            x += margin;
    
        int y = pos.y();
        if ( alignment & Qt::AlignBottom )
            y += margin;
        else if ( alignment & Qt::AlignTop )
            y -= textRect.height() + margin;
    
    Bryant's avatar
    Bryant committed
        textRect.moveTopLeft( QPoint( x, y ) );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        const QRect pickRect = pickArea().boundingRect().toRect();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        int right = qMin( textRect.right(), pickRect.right() - margin );
        int bottom = qMin( textRect.bottom(), pickRect.bottom() - margin );
        textRect.moveBottomRight( QPoint( right, bottom ) );
    
        int left = qMax( textRect.left(), pickRect.left() + margin );
        int top = qMax( textRect.top(), pickRect.top() + margin );
        textRect.moveTopLeft( QPoint( left, top ) );
    
    pixhawk's avatar
    pixhawk committed
    
        return textRect;
    }
    
    /*!
      \brief Event filter
    
    
    Bryant's avatar
    Bryant committed
      When isEnabled() is true all events of the observed widget are filtered.
    
    pixhawk's avatar
    pixhawk committed
      Mouse and keyboard events are translated into widgetMouse- and widgetKey-
    
      and widgetWheel-events. Paint and Resize events are handled to keep
    
    Bryant's avatar
    Bryant committed
      rubber band and tracker up to date.
    
      \param object Object to be filtered
      \param event Event
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \return Always false.
    
      \sa widgetEnterEvent(), widgetLeaveEvent(),
          widgetMousePressEvent(), widgetMouseReleaseEvent(),
    
    pixhawk's avatar
    pixhawk committed
          widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
    
    Bryant's avatar
    Bryant committed
          widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent(),
          QObject::installEventFilter(), QObject::event()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    bool QwtPicker::eventFilter( QObject *object, QEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( object && object == parentWidget() )
        {
            switch ( event->type() )
            {
                case QEvent::Resize:
                {
                    const QResizeEvent *re = static_cast<QResizeEvent *>( event );
                    if ( d_data->resizeMode == Stretch )
                        stretchSelection( re->oldSize(), re->size() );
    
    Bryant's avatar
    Bryant committed
                    break;
                }
                case QEvent::Enter:
                {
                    widgetEnterEvent( event );
                    break;
                }
                case QEvent::Leave:
                {
                    widgetLeaveEvent( event );
                    break;
                }
                case QEvent::MouseButtonPress:
                {
                    widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
                    break;
                }
                case QEvent::MouseButtonRelease:
                {
                    widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
                    break;
                }
                case QEvent::MouseButtonDblClick:
                {
                    widgetMouseDoubleClickEvent( static_cast<QMouseEvent *>( event ) );
                    break;
                }
                case QEvent::MouseMove:
                {
                    widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
                    break;
                }
                case QEvent::KeyPress:
                {
                    widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
                    break;
                }
                case QEvent::KeyRelease:
                {
                    widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
                    break;
                }
                case QEvent::Wheel:
                {
                    widgetWheelEvent( static_cast<QWheelEvent *>( event ) );
                    break;
                }
                default:
                    break;
    
    pixhawk's avatar
    pixhawk committed
            }
        }
        return false;
    }
    
    /*!
      Handle a mouse press event for the observed widget.
    
    
    Bryant's avatar
    Bryant committed
      \param mouseEvent Mouse event
    
    pixhawk's avatar
    pixhawk committed
    
      \sa eventFilter(), widgetMouseReleaseEvent(),
          widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
          widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::widgetMousePressEvent( QMouseEvent *mouseEvent )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        transition( mouseEvent );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Handle a mouse move event for the observed widget.
    
    
    Bryant's avatar
    Bryant committed
      \param mouseEvent Mouse event
    
    pixhawk's avatar
    pixhawk committed
    
      \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
          widgetMouseDoubleClickEvent(),
          widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPicker::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( pickArea().contains( mouseEvent->pos() ) )
            d_data->trackerPosition = mouseEvent->pos();
    
    pixhawk's avatar
    pixhawk committed
        else
    
    Bryant's avatar
    Bryant committed
            d_data->trackerPosition = QPoint( -1, -1 );
    
    pixhawk's avatar
    pixhawk committed
    
        if ( !isActive() )
            updateDisplay();
    
    
    Bryant's avatar
    Bryant committed
        transition( mouseEvent );
    }
    
    /*!
      Handle a enter event for the observed widget.
    
      \param event Qt event
    
      \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
          widgetMouseDoubleClickEvent(),
          widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()