Skip to content
qwt_picker.cpp 38.3 KiB
Newer Older
Bryant's avatar
Bryant committed
*/
void QwtPicker::widgetEnterEvent( QEvent *event )
{
    transition( event );
pixhawk's avatar
pixhawk committed
}

/*!
  Handle a leave event for the observed widget.

Bryant's avatar
Bryant committed
  \param event Qt event

pixhawk's avatar
pixhawk committed
  \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
      widgetMouseDoubleClickEvent(),
      widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
*/
Bryant's avatar
Bryant committed
void QwtPicker::widgetLeaveEvent( QEvent *event )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    transition( event );

    d_data->trackerPosition = QPoint( -1, -1 );
pixhawk's avatar
pixhawk committed
    if ( !isActive() )
        updateDisplay();
}

/*!
Bryant's avatar
Bryant committed
  Handle a mouse release event for the observed widget.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param mouseEvent Mouse event
pixhawk's avatar
pixhawk committed

  \sa eventFilter(), widgetMousePressEvent(),
pixhawk's avatar
pixhawk committed
      widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
      widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
*/
Bryant's avatar
Bryant committed
void QwtPicker::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    transition( mouseEvent );
pixhawk's avatar
pixhawk committed
}

/*!
  Handle mouse double click event for the observed widget.

Bryant's avatar
Bryant committed
  \param mouseEvent Mouse event
pixhawk's avatar
pixhawk committed

  \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
      widgetMouseMoveEvent(),
      widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent()
*/
Bryant's avatar
Bryant committed
void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent *mouseEvent )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    transition( mouseEvent );
pixhawk's avatar
pixhawk committed
}
pixhawk's avatar
pixhawk committed

/*!
  Handle a wheel event for the observed widget.

  Move the last point of the selection in case of isActive() == true

Bryant's avatar
Bryant committed
  \param wheelEvent Wheel event

pixhawk's avatar
pixhawk committed
  \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
      widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
      widgetKeyPressEvent(), widgetKeyReleaseEvent()
*/
Bryant's avatar
Bryant committed
void QwtPicker::widgetWheelEvent( QWheelEvent *wheelEvent )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( pickArea().contains( wheelEvent->pos() ) )
        d_data->trackerPosition = wheelEvent->pos();
pixhawk's avatar
pixhawk committed
    else
Bryant's avatar
Bryant committed
        d_data->trackerPosition = QPoint( -1, -1 );
pixhawk's avatar
pixhawk committed

    updateDisplay();

Bryant's avatar
Bryant committed
    transition( wheelEvent );
pixhawk's avatar
pixhawk committed
}

/*!
  Handle a key press event for the observed widget.

  Selections can be completely done by the keyboard. The arrow keys
  move the cursor, the abort key aborts a selection. All other keys
  are handled by the current state machine.

Bryant's avatar
Bryant committed
  \param keyEvent Key event

pixhawk's avatar
pixhawk committed
  \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
      widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
      widgetWheelEvent(), widgetKeyReleaseEvent(), stateMachine(),
      QwtEventPattern::KeyPatternCode
*/
Bryant's avatar
Bryant committed
void QwtPicker::widgetKeyPressEvent( QKeyEvent *keyEvent )
pixhawk's avatar
pixhawk committed
{
    int dx = 0;
    int dy = 0;

    int offset = 1;
Bryant's avatar
Bryant committed
    if ( keyEvent->isAutoRepeat() )
pixhawk's avatar
pixhawk committed
        offset = 5;

Bryant's avatar
Bryant committed
    if ( keyMatch( KeyLeft, keyEvent ) )
pixhawk's avatar
pixhawk committed
        dx = -offset;
Bryant's avatar
Bryant committed
    else if ( keyMatch( KeyRight, keyEvent ) )
pixhawk's avatar
pixhawk committed
        dx = offset;
Bryant's avatar
Bryant committed
    else if ( keyMatch( KeyUp, keyEvent ) )
pixhawk's avatar
pixhawk committed
        dy = -offset;
Bryant's avatar
Bryant committed
    else if ( keyMatch( KeyDown, keyEvent ) )
pixhawk's avatar
pixhawk committed
        dy = offset;
Bryant's avatar
Bryant committed
    else if ( keyMatch( KeyAbort, keyEvent ) )
    {
pixhawk's avatar
pixhawk committed
        reset();
Bryant's avatar
Bryant committed
    }
    else
        transition( keyEvent );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( dx != 0 || dy != 0 )
    {
        const QRect rect = pickArea().boundingRect().toRect();
        const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() );
pixhawk's avatar
pixhawk committed

        int x = pos.x() + dx;
Bryant's avatar
Bryant committed
        x = qMax( rect.left(), x );
        x = qMin( rect.right(), x );
pixhawk's avatar
pixhawk committed

        int y = pos.y() + dy;
Bryant's avatar
Bryant committed
        y = qMax( rect.top(), y );
        y = qMin( rect.bottom(), y );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) );
pixhawk's avatar
pixhawk committed
    }
}
pixhawk's avatar
pixhawk committed
/*!
  Handle a key release event for the observed widget.

  Passes the event to the state machine.

Bryant's avatar
Bryant committed
  \param keyEvent Key event

pixhawk's avatar
pixhawk committed
  \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
      widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
      widgetWheelEvent(), widgetKeyPressEvent(), stateMachine()
*/
Bryant's avatar
Bryant committed
void QwtPicker::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    transition( keyEvent );
pixhawk's avatar
pixhawk committed
}

/*!
  Passes an event to the state machine and executes the resulting
pixhawk's avatar
pixhawk committed
  commands. Append and Move commands use the current position
Bryant's avatar
Bryant committed
  of the cursor ( QCursor::pos() ).
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param event Event
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPicker::transition( const QEvent *event )
pixhawk's avatar
pixhawk committed
{
    if ( !d_data->stateMachine )
        return;

Bryant's avatar
Bryant committed
    const QList<QwtPickerMachine::Command> commandList =
        d_data->stateMachine->transition( *this, event );
pixhawk's avatar
pixhawk committed

    QPoint pos;
Bryant's avatar
Bryant committed
    switch ( event->type() )
    {
        case QEvent::MouseButtonDblClick:
        case QEvent::MouseButtonPress:
        case QEvent::MouseButtonRelease:
        case QEvent::MouseMove:
        {
            const QMouseEvent *me = 
                static_cast< const QMouseEvent * >( event );
            pos = me->pos();
Bryant's avatar
Bryant committed
        default:
            pos = parentWidget()->mapFromGlobal( QCursor::pos() );
    }

    for ( int i = 0; i < commandList.count(); i++ )
    {
        switch ( commandList[i] )
        {
            case QwtPickerMachine::Begin:
            {
                begin();
                break;
            }
            case QwtPickerMachine::Append:
            {
                append( pos );
                break;
            }
            case QwtPickerMachine::Move:
            {
                move( pos );
                break;
            }
            case QwtPickerMachine::Remove:
            {
                remove();
                break;
            }
            case QwtPickerMachine::End:
            {
                end();
                break;
            }
pixhawk's avatar
pixhawk committed
        }
    }
}

/*!
  Open a selection setting the state to active

Bryant's avatar
Bryant committed
  \sa isActive(), end(), append(), move()
pixhawk's avatar
pixhawk committed
*/
void QwtPicker::begin()
{
    if ( d_data->isActive )
        return;

Bryant's avatar
Bryant committed
    d_data->pickedPoints.resize( 0 );
pixhawk's avatar
pixhawk committed
    d_data->isActive = true;
Bryant's avatar
Bryant committed
    Q_EMIT activated( true );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( trackerMode() != AlwaysOff )
    {
        if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
        {
pixhawk's avatar
pixhawk committed
            QWidget *w = parentWidget();
            if ( w )
Bryant's avatar
Bryant committed
                d_data->trackerPosition = w->mapFromGlobal( QCursor::pos() );
pixhawk's avatar
pixhawk committed
        }
    }

    updateDisplay();
Bryant's avatar
Bryant committed
    setMouseTracking( true );
pixhawk's avatar
pixhawk committed
}

/*!
  \brief Close a selection setting the state to inactive.

Bryant's avatar
Bryant committed
  The selection is validated and maybe fixed by accept().
pixhawk's avatar
pixhawk committed

  \param ok If true, complete the selection and emit a selected signal
            otherwise discard the selection.
  \return true if the selection is accepted, false otherwise
Bryant's avatar
Bryant committed
  \sa isActive(), begin(), append(), move(), selected(), accept()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
bool QwtPicker::end( bool ok )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->isActive )
    {
        setMouseTracking( false );
pixhawk's avatar
pixhawk committed

        d_data->isActive = false;
Bryant's avatar
Bryant committed
        Q_EMIT activated( false );
pixhawk's avatar
pixhawk committed

        if ( trackerMode() == ActiveOnly )
Bryant's avatar
Bryant committed
            d_data->trackerPosition = QPoint( -1, -1 );
pixhawk's avatar
pixhawk committed

        if ( ok )
Bryant's avatar
Bryant committed
            ok = accept( d_data->pickedPoints );
pixhawk's avatar
pixhawk committed

        if ( ok )
Bryant's avatar
Bryant committed
            Q_EMIT selected( d_data->pickedPoints );
pixhawk's avatar
pixhawk committed
        else
Bryant's avatar
Bryant committed
            d_data->pickedPoints.resize( 0 );
pixhawk's avatar
pixhawk committed

        updateDisplay();
Bryant's avatar
Bryant committed
    }
    else
pixhawk's avatar
pixhawk committed
        ok = false;

    return ok;
}

/*!
Bryant's avatar
Bryant committed
   Reset the state machine and terminate ( end(false) ) the selection
pixhawk's avatar
pixhawk committed
*/
void QwtPicker::reset()
{
    if ( d_data->stateMachine )
        d_data->stateMachine->reset();

Bryant's avatar
Bryant committed
    if ( isActive() )
        end( false );
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
  Append a point to the selection and update rubber band and tracker.
pixhawk's avatar
pixhawk committed
  The appended() signal is emitted.

  \param pos Additional point

Bryant's avatar
Bryant committed
  \sa isActive(), begin(), end(), move(), appended()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPicker::append( const QPoint &pos )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->isActive )
    {
        const int idx = d_data->pickedPoints.count();
        d_data->pickedPoints.resize( idx + 1 );
        d_data->pickedPoints[idx] = pos;
pixhawk's avatar
pixhawk committed

        updateDisplay();
Bryant's avatar
Bryant committed
        Q_EMIT appended( pos );
pixhawk's avatar
pixhawk committed
    }
}

/*!
  Move the last point of the selection
  The moved() signal is emitted.

  \param pos New position
Bryant's avatar
Bryant committed
  \sa isActive(), begin(), end(), append()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPicker::move( const QPoint &pos )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->isActive )
    {
        const int idx = d_data->pickedPoints.count() - 1;
        if ( idx >= 0 )
        {
            if ( d_data->pickedPoints[idx] != pos )
            {
                d_data->pickedPoints[idx] = pos;
pixhawk's avatar
pixhawk committed

                updateDisplay();
Bryant's avatar
Bryant committed
                Q_EMIT moved( pos );
Bryant's avatar
Bryant committed
/*!
  Remove the last point of the selection
  The removed() signal is emitted.

  \sa isActive(), begin(), end(), append(), move()
*/
void QwtPicker::remove()
{
    if ( d_data->isActive )
    {
        const int idx = d_data->pickedPoints.count() - 1;
        if ( idx > 0 )
        {
            const int idx = d_data->pickedPoints.count();

            const QPoint pos = d_data->pickedPoints[idx - 1];
            d_data->pickedPoints.resize( idx - 1 );

            updateDisplay();
            Q_EMIT removed( pos );
        }
    }
}

/*!
  \brief Validate and fix up the selection

  Accepts all selections unmodified

  \param selection Selection to validate and fix up
  \return true, when accepted, false otherwise
*/
bool QwtPicker::accept( QPolygon &selection ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    Q_UNUSED( selection );
pixhawk's avatar
pixhawk committed
    return true;
}

/*!
  A picker is active between begin() and end().
  \return true if the selection is active.
*/
bool QwtPicker::isActive() const
pixhawk's avatar
pixhawk committed
{
    return d_data->isActive;
}

Bryant's avatar
Bryant committed
/*!
  Return the points, that have been collected so far. The selection()
  is calculated from the pickedPoints() in adjustedPoints().
  \return Picked points
*/
const QPolygon &QwtPicker::pickedPoints() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->pickedPoints;
pixhawk's avatar
pixhawk committed
}

/*!
  Scale the selection by the ratios of oldSize and newSize
  The changed() signal is emitted.

  \param oldSize Previous size
  \param newSize Current size

  \sa ResizeMode, setResizeMode(), resizeMode()
*/
Bryant's avatar
Bryant committed
void QwtPicker::stretchSelection( const QSize &oldSize, const QSize &newSize )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( oldSize.isEmpty() )
    {
        // avoid division by zero. But scaling for small sizes also
pixhawk's avatar
pixhawk committed
        // doesn't make much sense, because of rounding losses. TODO ...
        return;
    }

    const double xRatio =
Bryant's avatar
Bryant committed
        double( newSize.width() ) / double( oldSize.width() );
pixhawk's avatar
pixhawk committed
    const double yRatio =
Bryant's avatar
Bryant committed
        double( newSize.height() ) / double( oldSize.height() );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    for ( int i = 0; i < int( d_data->pickedPoints.count() ); i++ )
    {
        QPoint &p = d_data->pickedPoints[i];
        p.setX( qRound( p.x() * xRatio ) );
        p.setY( qRound( p.y() * yRatio ) );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        Q_EMIT changed( d_data->pickedPoints );
pixhawk's avatar
pixhawk committed
    }
}

/*!
  Set mouse tracking for the observed widget.

  In case of enable is true, the previous value
  is saved, that is restored when enable is false.

  \warning Even when enable is false, mouse tracking might be restored
           to true. When mouseTracking for the observed widget
           has been changed directly by QWidget::setMouseTracking
           while mouse tracking has been set to true, this value can't
           be restored.
*/

Bryant's avatar
Bryant committed
void QwtPicker::setMouseTracking( bool enable )
pixhawk's avatar
pixhawk committed
{
    QWidget *widget = parentWidget();
    if ( !widget )
        return;

Bryant's avatar
Bryant committed
    if ( enable )
    {
pixhawk's avatar
pixhawk committed
        d_data->mouseTracking = widget->hasMouseTracking();
Bryant's avatar
Bryant committed
        widget->setMouseTracking( true );
    }
    else
    {
        widget->setMouseTracking( d_data->mouseTracking );
pixhawk's avatar
pixhawk committed
    }
}

/*!
  Find the area of the observed widget, where selection might happen.

Bryant's avatar
Bryant committed
  \return parentWidget()->contentsRect() 
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QPainterPath QwtPicker::pickArea() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    QPainterPath path;
pixhawk's avatar
pixhawk committed

    const QWidget *widget = parentWidget();
Bryant's avatar
Bryant committed
    if ( widget )
        path.addRect( widget->contentsRect() );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return path;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
//! Update the state of rubber band and tracker label
pixhawk's avatar
pixhawk committed
void QwtPicker::updateDisplay()
{
    QWidget *w = parentWidget();

    bool showRubberband = false;
    bool showTracker = false;
Bryant's avatar
Bryant committed

    if ( w && w->isVisible() && d_data->enabled )
    {
pixhawk's avatar
pixhawk committed
        if ( rubberBand() != NoRubberBand && isActive() &&
Bryant's avatar
Bryant committed
            rubberBandPen().style() != Qt::NoPen )
        {
pixhawk's avatar
pixhawk committed
            showRubberband = true;
        }

        if ( trackerMode() == AlwaysOn ||
Bryant's avatar
Bryant committed
            ( trackerMode() == ActiveOnly && isActive() ) )
        {
            if ( trackerPen() != Qt::NoPen 
                && !trackerRect( QFont() ).isEmpty() )
            {
pixhawk's avatar
pixhawk committed
                showTracker = true;
Bryant's avatar
Bryant committed
            }
pixhawk's avatar
pixhawk committed
        }
    }

Bryant's avatar
Bryant committed
    QPointer< QwtPickerRubberband > &rw = d_data->rubberBandOverlay;
    if ( showRubberband )
    {
        if ( rw.isNull() )
        {
            rw = new QwtPickerRubberband( this, w );
            rw->setObjectName( "PickerRubberBand" );
            rw->resize( w->size() );
pixhawk's avatar
pixhawk committed
        }
Bryant's avatar
Bryant committed

        if ( d_data->rubberBand <= RectRubberBand )
            rw->setMaskMode( QwtWidgetOverlay::MaskHint );
        else
            rw->setMaskMode( QwtWidgetOverlay::AlphaMask );

        rw->updateOverlay();
    }
    else
    {
        if ( d_data->openGL )
        {
            // Qt 4.8 crashes for a delete
            if ( !rw.isNull() )
            {
                rw->hide();
                rw->deleteLater();
                rw = NULL;
            }
        }
        else
        {
            delete rw;
pixhawk's avatar
pixhawk committed
        }
Bryant's avatar
Bryant committed
    }

    QPointer< QwtPickerTracker > &tw = d_data->trackerOverlay;
    if ( showTracker )
    {
        if ( tw.isNull() )
        {
            tw = new QwtPickerTracker( this, w );
            tw->setObjectName( "PickerTracker" );
            tw->resize( w->size() );
        }
        tw->setFont( d_data->trackerFont );
        tw->updateOverlay();
    }
    else
    {
        if ( d_data->openGL )
        {
            // Qt 4.8 crashes for a delete
            if ( !tw.isNull() )
            {
                tw->hide();
                tw->deleteLater();
                tw = NULL;
            }
        }
        else
        {
            delete tw;
        }
    }
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
//! \return Overlay displaying the rubber band
const QwtWidgetOverlay *QwtPicker::rubberBandOverlay() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->rubberBandOverlay;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
//! \return Overlay displaying the tracker text
const QwtWidgetOverlay *QwtPicker::trackerOverlay() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->trackerOverlay;
pixhawk's avatar
pixhawk committed
}