Skip to content
qwt_picker.cpp 33.8 KiB
Newer Older
pixhawk's avatar
pixhawk committed
        x = qwtMin(rect.right(), x);

        int y = pos.y() + dy;
        y = qwtMax(rect.top(), y);
        y = qwtMin(rect.bottom(), y);

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

  Passes the event to the state machine.

  \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
      widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(),
      widgetWheelEvent(), widgetKeyPressEvent(), stateMachine()
*/
void QwtPicker::widgetKeyReleaseEvent(QKeyEvent *ke)
{
    transition(ke);
}

/*!
  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
  of the cursor (QCursor::pos()).

  \param e Event
*/
void QwtPicker::transition(const QEvent *e)
{
    if ( !d_data->stateMachine )
        return;

    QwtPickerMachine::CommandList commandList =
        d_data->stateMachine->transition(*this, e);

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

    for ( uint i = 0; i < (uint)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::End: {
            end();
            break;
        }
pixhawk's avatar
pixhawk committed
        }
    }
}

/*!
  Open a selection setting the state to active

  \sa isActive, end(), append(), move()
*/
void QwtPicker::begin()
{
    if ( d_data->isActive )
        return;

    d_data->selection.resize(0);
    d_data->isActive = true;

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

    updateDisplay();
    setMouseTracking(true);
}

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

  The selection is validated and maybe fixed by QwtPicker::accept().

  \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
  \sa isActive, begin(), append(), move(), selected(), accept()
*/
bool QwtPicker::end(bool ok)
{
    if ( d_data->isActive ) {
pixhawk's avatar
pixhawk committed
        setMouseTracking(false);

        d_data->isActive = false;

        if ( trackerMode() == ActiveOnly )
            d_data->trackerPosition = QPoint(-1, -1);

        if ( ok )
            ok = accept(d_data->selection);

        if ( ok )
            emit selected(d_data->selection);
        else
            d_data->selection.resize(0);

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

    return ok;
}

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

    if (isActive())
        end(false);
}

/*!
  Append a point to the selection and update rubberband and tracker.
  The appended() signal is emitted.

  \param pos Additional point

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

        updateDisplay();

        emit appended(pos);
    }
}

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

  \param pos New position
  \sa isActive, begin(), end(), append()

*/
void QwtPicker::move(const QPoint &pos)
{
    if ( d_data->isActive ) {
pixhawk's avatar
pixhawk committed
        const int idx = d_data->selection.count() - 1;
        if ( idx >= 0 ) {
            if ( d_data->selection[idx] != pos ) {
pixhawk's avatar
pixhawk committed
                d_data->selection[idx] = pos;

                updateDisplay();

                emit moved(pos);
            }
        }
    }
}

bool QwtPicker::accept(QwtPolygon &) const
{
    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;
}

//!  Return Selected points
const QwtPolygon &QwtPicker::selection() const
{
    return d_data->selection;
}

/*!
  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()
*/
void QwtPicker::stretchSelection(const QSize &oldSize, const QSize &newSize)
{
    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 =
        double(newSize.width()) / double(oldSize.width());
    const double yRatio =
        double(newSize.height()) / double(oldSize.height());

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

        emit changed(d_data->selection);
    }
}

/*!
  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.
*/

void QwtPicker::setMouseTracking(bool enable)
{
    QWidget *widget = parentWidget();
    if ( !widget )
        return;

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

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

  \return QFrame::contentsRect() if it is a QFrame, QWidget::rect() otherwise.
*/
QRect QwtPicker::pickRect() const
{
    QRect rect;

    const QWidget *widget = parentWidget();
    if ( !widget )
        return rect;

    if ( widget->inherits("QFrame") )
        rect = ((QFrame *)widget)->contentsRect();
    else
        rect = widget->rect();

    return rect;
}

void QwtPicker::updateDisplay()
{
    QWidget *w = parentWidget();

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

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

#if QT_VERSION < 0x040000
    QGuardedPtr<PickerWidget> &rw = d_data->rubberBandWidget;
#else
    QPointer<PickerWidget> &rw = d_data->rubberBandWidget;
#endif
    if ( showRubberband ) {
        if ( rw.isNull() ) {
pixhawk's avatar
pixhawk committed
            rw = new PickerWidget( this, w, PickerWidget::RubberBand);
            rw->resize(w->size());
        }
        rw->updateMask();
        rw->update(); // Needed, when the mask doesn't change
pixhawk's avatar
pixhawk committed
        delete rw;

#if QT_VERSION < 0x040000
    QGuardedPtr<PickerWidget> &tw = d_data->trackerWidget;
#else
    QPointer<PickerWidget> &tw = d_data->trackerWidget;
#endif
    if ( showTracker ) {
        if ( tw.isNull() ) {
pixhawk's avatar
pixhawk committed
            tw = new PickerWidget( this, w, PickerWidget::Text);
            tw->resize(w->size());
        }
        tw->updateMask();
        tw->update(); // Needed, when the mask doesn't change
pixhawk's avatar
pixhawk committed
        delete tw;
}

const QWidget *QwtPicker::rubberBandWidget() const
{
    return d_data->rubberBandWidget;
}

const QWidget *QwtPicker::trackerWidget() const
{
    return d_data->trackerWidget;
}