# qwt_picker.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 #include <qapplication.h>
    00011 #include <qevent.h>
    00012 #include <qpainter.h>
    00013 #include <qframe.h>
    00014 #include <qcursor.h>
    00015 #include <qbitmap.h>
    00016 #include "qwt_math.h"
    00017 #include "qwt_painter.h"
    00018 #include "qwt_picker_machine.h"
    00019 #include "qwt_picker.h"
    00020 #if QT_VERSION < 0x040000
    00021 #include <qguardedptr.h>
    00022 #else
    00023 #include <qpointer.h>
    00024 #include <qpaintengine.h>
    00025 #endif
    00026
    00027 class QwtPicker::PickerWidget: public QWidget
    00028 {
    00029 public:
    00030     enum Type
    00031     {
    00032         RubberBand,
    00033         Text
    00034     };
    00035
    00036     PickerWidget(QwtPicker *, QWidget *, Type);
    00037     virtual void updateMask();
    00038
    00039     /*
    00040        For a tracker text with a background we can use the background
    00041        rect as mask. Also for "regular" Qt widgets >= 4.3.0 we
    00042        don't need to mask the text anymore.
    00043      */
    00044     bool d_hasTextMask;
    00045
    00046 protected:
    00047     virtual void paintEvent(QPaintEvent *);
    00048
    00049     QwtPicker *d_picker;
    00050     Type d_type;
    00051 };
    00052
    00053 class QwtPicker::PrivateData
    00054 {
    00055 public:
    00056     bool enabled;
    00057
    00058     QwtPickerMachine *stateMachine;
    00059
    00060     int selectionFlags;
    00061     QwtPicker::ResizeMode resizeMode;
    00062
    00063     QwtPicker::RubberBand rubberBand;
    00064     QPen rubberBandPen;
    00065
    00066     QwtPicker::DisplayMode trackerMode;
    00067     QPen trackerPen;
    00068     QFont trackerFont;
    00069
    00070     QwtPolygon selection;
    00071     bool isActive;
    00072     QPoint trackerPosition;
    00073
    00074     bool mouseTracking; // used to save previous value
    00075
    00076     /*
    00077       On X11 the widget below the picker widgets gets paint events
    00078       with a region that is the bounding rect of the mask, if it is complex.
    00079       In case of (f.e) a CrossRubberBand and a text this creates complete
    00080       repaints of the widget. So we better use two different widgets.
    00081      */
    00082
    00083 #if QT_VERSION < 0x040000
    00084     QGuardedPtr<PickerWidget> rubberBandWidget;
    00085     QGuardedPtr<PickerWidget> trackerWidget;
    00086 #else
    00087     QPointer<PickerWidget> rubberBandWidget;
    00088     QPointer<PickerWidget> trackerWidget;
    00089 #endif
    00090 };
    00091
    00092 QwtPicker::PickerWidget::PickerWidget(
    00093         QwtPicker *picker, QWidget *parent, Type type):
    00094     QWidget(parent),
    00095     d_hasTextMask(false),
    00096     d_picker(picker),
    00097     d_type(type)
    00098 {
    00099 #if QT_VERSION >= 0x040000
    00100     setAttribute(Qt::WA_TransparentForMouseEvents);
    00101     setAttribute(Qt::WA_NoSystemBackground);
    00102     setFocusPolicy(Qt::NoFocus);
    00103 #else
    00104     setBackgroundMode(Qt::NoBackground);
    00105     setFocusPolicy(QWidget::NoFocus);
    00106     setMouseTracking(true);
    00107 #endif
    00108     hide();
    00109 }
    00110
    00111 void QwtPicker::PickerWidget::updateMask()
    00112 {
    00113     QRegion mask;
    00114
    00115     if ( d_type == RubberBand )
    00116     {
    00117         QBitmap bm(width(), height());
    00118         bm.fill(Qt::color0);
    00119
    00120         QPainter painter(&bm);
    00121         QPen pen = d_picker->rubberBandPen();
    00122         pen.setColor(Qt::color1);
    00123         painter.setPen(pen);
    00124
    00125         d_picker->drawRubberBand(&painter);
    00126
    00127         mask = QRegion(bm);
    00128     }
    00129     if ( d_type == Text )
    00130     {
    00131         d_hasTextMask = true;
    00132 #if QT_VERSION >= 0x040300
    00133         if ( !parentWidget()->testAttribute(Qt::WA_PaintOnScreen) )
    00134         {
    00135 #if 0
    00136             if ( parentWidget()->paintEngine()->type() != QPaintEngine::OpenGL )
    00137 #endif
    00138             {
    00139                 // With Qt >= 4.3 drawing of the tracker can be implemented in an
    00140                 // easier way, using the textRect as mask.
    00141
    00142                 d_hasTextMask = false;
    00143             }
    00144         }
    00145 #endif
    00146
    00147         if ( d_hasTextMask )
    00148         {
    00149             const QwtText label = d_picker->trackerText(
    00150                 d_picker->trackerPosition());
    00151             if ( label.testPaintAttribute(QwtText::PaintBackground)
    00152                 && label.backgroundBrush().style() != Qt::NoBrush )
    00153             {
    00154 #if QT_VERSION >= 0x040300
    00155                 if ( label.backgroundBrush().color().alpha() > 0 )
    00156 #endif
    00157                 // We don't need a text mask, when we have a background
    00158                 d_hasTextMask = false;
    00159             }
    00160         }
    00161
    00162         if ( d_hasTextMask )
    00163         {
    00164             QBitmap bm(width(), height());
    00165             bm.fill(Qt::color0);
    00166
    00167             QPainter painter(&bm);
    00168             painter.setFont(font());
    00169
    00170             QPen pen = d_picker->trackerPen();
    00171             pen.setColor(Qt::color1);
    00172             painter.setPen(pen);
    00173
    00174             d_picker->drawTracker(&painter);
    00175
    00176             mask = QRegion(bm);
    00177         }
    00178         else
    00179         {
    00180             mask = d_picker->trackerRect(font());
    00181         }
    00182     }
    00183
    00184 #if QT_VERSION < 0x040000
    00185     QWidget *w = parentWidget();
    00186     const bool doUpdate = w->isUpdatesEnabled();
    00187     const Qt::BackgroundMode bgMode = w->backgroundMode();
    00188     w->setUpdatesEnabled(false);
    00189     if ( bgMode != Qt::NoBackground )
    00190         w->setBackgroundMode(Qt::NoBackground);
    00191 #endif
    00192
    00193     setMask(mask);
    00194
    00195 #if QT_VERSION < 0x040000
    00196     if ( bgMode != Qt::NoBackground )
    00197         w->setBackgroundMode(bgMode);
    00198
    00199     w->setUpdatesEnabled(doUpdate);
    00200 #endif
    00201
    00202     setShown(!mask.isEmpty());
    00203 }
    00204
    00205 void QwtPicker::PickerWidget::paintEvent(QPaintEvent *e)
    00206 {
    00207     QPainter painter(this);
    00208     painter.setClipRegion(e->region());
    00209
    00210     if ( d_type == RubberBand )
    00211     {
    00212         painter.setPen(d_picker->rubberBandPen());
    00213         d_picker->drawRubberBand(&painter);
    00214     }
    00215
    00216     if ( d_type == Text )
    00217     {
    00218         /*
    00219            If we have a text mask we simply fill the region of
    00220            the mask. This gives better results for antialiased fonts.
    00221          */
    00222         bool doDrawTracker = !d_hasTextMask;
    00223 #if QT_VERSION < 0x040000
    00224         if ( !doDrawTracker && QPainter::redirect(this) )
    00225         {
    00226             // setMask + painter redirection doesn't work
    00227             doDrawTracker = true;
    00228         }
    00229 #endif
    00230         if ( doDrawTracker )
    00231         {
    00232             painter.setPen(d_picker->trackerPen());
    00233             d_picker->drawTracker(&painter);
    00234         }
    00235         else
    00236             painter.fillRect(e->rect(), QBrush(d_picker->trackerPen().color()));
    00237     }
    00238 }
    00239
    00249 QwtPicker::QwtPicker(QWidget *parent):
    00250     QObject(parent)
    00251 {
    00252     init(parent, NoSelection, NoRubberBand, AlwaysOff);
    00253 }
    00254
    00264 QwtPicker::QwtPicker(int selectionFlags, RubberBand rubberBand,
    00265         DisplayMode trackerMode, QWidget *parent):
    00266     QObject(parent)
    00267 {
    00268     init(parent, selectionFlags, rubberBand, trackerMode);
    00269 }
    00270
    00272 QwtPicker::~QwtPicker()
    00273 {
    00274     setMouseTracking(false);
    00275     delete d_data->stateMachine;
    00276     delete d_data->rubberBandWidget;
    00277     delete d_data->trackerWidget;
    00278     delete d_data;
    00279 }
    00280
    00282 void QwtPicker::init(QWidget *parent, int selectionFlags,
    00283     RubberBand rubberBand, DisplayMode trackerMode)
    00284 {
    00285     d_data = new PrivateData;
    00286
    00287     d_data->rubberBandWidget = NULL;
    00288     d_data->trackerWidget = NULL;
    00289
    00290     d_data->rubberBand = rubberBand;
    00291     d_data->enabled = false;
    00292     d_data->resizeMode = Stretch;
    00293     d_data->trackerMode = AlwaysOff;
    00294     d_data->isActive = false;
    00295     d_data->trackerPosition = QPoint(-1, -1);
    00296     d_data->mouseTracking = false;
    00297
    00298     d_data->stateMachine = NULL;
    00299     setSelectionFlags(selectionFlags);
    00300
    00301     if ( parent )
    00302     {
    00303 #if QT_VERSION >= 0x040000
    00304         if ( parent->focusPolicy() == Qt::NoFocus )
    00305             parent->setFocusPolicy(Qt::WheelFocus);
    00306 #else
    00307         if ( parent->focusPolicy() == QWidget::NoFocus )
    00308             parent->setFocusPolicy(QWidget::WheelFocus);
    00309 #endif
    00310
    00311         d_data->trackerFont = parent->font();
    00312         d_data->mouseTracking = parent->hasMouseTracking();
    00313         setEnabled(true);
    00314     }
    00315     setTrackerMode(trackerMode);
    00316 }
    00317
    00321 void QwtPicker::setStateMachine(QwtPickerMachine *stateMachine)
    00322 {
    00323     if ( d_data->stateMachine != stateMachine )
    00324     {
    00325         reset();
    00326
    00327         delete d_data->stateMachine;
    00328         d_data->stateMachine = stateMachine;
    00329
    00330         if ( d_data->stateMachine )
    00331             d_data->stateMachine->reset();
    00332     }
    00333 }
    00334
    00351 QwtPickerMachine *QwtPicker::stateMachine(int flags) const
    00352 {
    00353     if ( flags & PointSelection )
    00354     {
    00355         if ( flags & ClickSelection )
    00356             return new QwtPickerClickPointMachine;
    00357         else
    00358             return new QwtPickerDragPointMachine;
    00359     }
    00360     if ( flags & RectSelection )
    00361     {
    00362         if ( flags & ClickSelection )
    00363             return new QwtPickerClickRectMachine;
    00364         else
    00365             return new QwtPickerDragRectMachine;
    00366     }
    00367     if ( flags & PolygonSelection )
    00368     {
    00369         return new QwtPickerPolygonMachine();
    00370     }
    00371     return NULL;
    00372 }
    00373
    00375 QWidget *QwtPicker::parentWidget()
    00376 {
    00377     QObject *obj = parent();
    00378     if ( obj && obj->isWidgetType() )
    00379         return (QWidget *)obj;
    00380
    00381     return NULL;
    00382 }
    00383
    00385 const QWidget *QwtPicker::parentWidget() const
    00386 {
    00387     QObject *obj = parent();
    00388     if ( obj && obj->isWidgetType() )
    00389         return (QWidget *)obj;
    00390
    00391     return NULL;
    00392 }
    00393
    00403 void QwtPicker::setSelectionFlags(int flags)
    00404 {
    00405     d_data->selectionFlags = flags;
    00406     setStateMachine(stateMachine(flags));
    00407 }
    00408
    00414 int QwtPicker::selectionFlags() const
    00415 {
    00416     return d_data->selectionFlags;
    00417 }
    00418
    00427 void QwtPicker::setRubberBand(RubberBand rubberBand)
    00428 {
    00429     d_data->rubberBand = rubberBand;
    00430 }
    00431
    00436 QwtPicker::RubberBand QwtPicker::rubberBand() const
    00437 {
    00438     return d_data->rubberBand;
    00439 }
    00440
    00457 void QwtPicker::setTrackerMode(DisplayMode mode)
    00458 {
    00459     if ( d_data->trackerMode != mode )
    00460     {
    00461         d_data->trackerMode = mode;
    00462         setMouseTracking(d_data->trackerMode == AlwaysOn);
    00463     }
    00464 }
    00465
    00470 QwtPicker::DisplayMode QwtPicker::trackerMode() const
    00471 {
    00472     return d_data->trackerMode;
    00473 }
    00474
    00489 void QwtPicker::setResizeMode(ResizeMode mode)
    00490 {
    00491     d_data->resizeMode = mode;
    00492 }
    00493
    00499 QwtPicker::ResizeMode QwtPicker::resizeMode() const
    00500 {
    00501     return d_data->resizeMode;
    00502 }
    00503
    00513 void QwtPicker::setEnabled(bool enabled)
    00514 {
    00515     if ( d_data->enabled != enabled )
    00516     {
    00517         d_data->enabled = enabled;
    00518
    00519         QWidget *w = parentWidget();
    00520         if ( w )
    00521         {
    00522             if ( enabled )
    00523                 w->installEventFilter(this);
    00524             else
    00525                 w->removeEventFilter(this);
    00526         }
    00527
    00528         updateDisplay();
    00529     }
    00530 }
    00531
    00537 bool QwtPicker::isEnabled() const
    00538 {
    00539     return d_data->enabled;
    00540 }
    00541
    00548 void QwtPicker::setTrackerFont(const QFont &font)
    00549 {
    00550     if ( font != d_data->trackerFont )
    00551     {
    00552         d_data->trackerFont = font;
    00553         updateDisplay();
    00554     }
    00555 }
    00556
    00562 QFont QwtPicker::trackerFont() const
    00563 {
    00564     return d_data->trackerFont;
    00565 }
    00566
    00573 void QwtPicker::setTrackerPen(const QPen &pen)
    00574 {
    00575     if ( pen != d_data->trackerPen )
    00576     {
    00577         d_data->trackerPen = pen;
    00578         updateDisplay();
    00579     }
    00580 }
    00581
    00586 QPen QwtPicker::trackerPen() const
    00587 {
    00588     return d_data->trackerPen;
    00589 }
    00590
    00597 void QwtPicker::setRubberBandPen(const QPen &pen)
    00598 {
    00599     if ( pen != d_data->rubberBandPen )
    00600     {
    00601         d_data->rubberBandPen = pen;
    00602         updateDisplay();
    00603     }
    00604 }
    00605
    00610 QPen QwtPicker::rubberBandPen() const
    00611 {
    00612     return d_data->rubberBandPen;
    00613 }
    00614
    00628 QwtText QwtPicker::trackerText(const QPoint &pos) const
    00629 {
    00630     QString label;
    00631
    00632     switch(rubberBand())
    00633     {
    00634         case HLineRubberBand:
    00635             label.sprintf("%d", pos.y());
    00636             break;
    00637         case VLineRubberBand:
    00638             label.sprintf("%d", pos.x());
    00639             break;
    00640         default:
    00641             label.sprintf("%d, %d", pos.x(), pos.y());
    00642     }
    00643     return label;
    00644 }
    00645
    00654 void QwtPicker::drawRubberBand(QPainter *painter) const
    00655 {
    00656     if ( !isActive() || rubberBand() == NoRubberBand ||
    00657         rubberBandPen().style() == Qt::NoPen )
    00658     {
    00659         return;
    00660     }
    00661
    00662     const QRect &pRect = pickRect();
    00663     const QwtPolygon &pa = d_data->selection;
    00664
    00665     if ( selectionFlags() & PointSelection )
    00666     {
    00667         if ( pa.count() < 1 )
    00668             return;
    00669
    00670         const QPoint pos = pa[0];
    00671
    00672         switch(rubberBand())
    00673         {
    00674             case VLineRubberBand:
    00675                 QwtPainter::drawLine(painter, pos.x(),
    00676                     pRect.top(), pos.x(), pRect.bottom());
    00677                 break;
    00678
    00679             case HLineRubberBand:
    00680                 QwtPainter::drawLine(painter, pRect.left(),
    00681                     pos.y(), pRect.right(), pos.y());
    00682                 break;
    00683
    00684             case CrossRubberBand:
    00685                 QwtPainter::drawLine(painter, pos.x(),
    00686                     pRect.top(), pos.x(), pRect.bottom());
    00687                 QwtPainter::drawLine(painter, pRect.left(),
    00688                     pos.y(), pRect.right(), pos.y());
    00689                 break;
    00690             default:
    00691                 break;
    00692         }
    00693     }
    00694
    00695     else if ( selectionFlags() & RectSelection )
    00696     {
    00697         if ( pa.count() < 2 )
    00698             return;
    00699
    00700         QPoint p1 = pa[0];
    00701         QPoint p2 = pa[int(pa.count() - 1)];
    00702
    00703         if ( selectionFlags() & CenterToCorner )
    00704         {
    00705             p1.setX(p1.x() - (p2.x() - p1.x()));
    00706             p1.setY(p1.y() - (p2.y() - p1.y()));
    00707         }
    00708         else if ( selectionFlags() & CenterToRadius )
    00709         {
    00710             const int radius = qwtMax(qwtAbs(p2.x() - p1.x()),
    00711                 qwtAbs(p2.y() - p1.y()));
    00712             p2.setX(p1.x() + radius);
    00713             p2.setY(p1.y() + radius);
    00714             p1.setX(p1.x() - radius);
    00715             p1.setY(p1.y() - radius);
    00716         }
    00717
    00718 #if QT_VERSION < 0x040000
    00719         const QRect rect = QRect(p1, p2).normalize();
    00720 #else
    00721         const QRect rect = QRect(p1, p2).normalized();
    00722 #endif
    00723         switch(rubberBand())
    00724         {
    00725             case EllipseRubberBand:
    00726                 QwtPainter::drawEllipse(painter, rect);
    00727                 break;
    00728             case RectRubberBand:
    00729                 QwtPainter::drawRect(painter, rect);
    00730                 break;
    00731             default:
    00732                 break;
    00733         }
    00734     }
    00735     else if ( selectionFlags() & PolygonSelection )
    00736     {
    00737         if ( rubberBand() == PolygonRubberBand )
    00738             painter->drawPolyline(pa);
    00739     }
    00740 }
    00741
    00749 void QwtPicker::drawTracker(QPainter *painter) const
    00750 {
    00751     const QRect textRect = trackerRect(painter->font());
    00752     if ( !textRect.isEmpty() )
    00753     {
    00754         QwtText label = trackerText(d_data->trackerPosition);
    00755         if ( !label.isEmpty() )
    00756         {
    00757             painter->save();
    00758
    00759 #if defined(Q_WS_MAC)
    00760             // Antialiased fonts are broken on the Mac.
    00761 #if QT_VERSION >= 0x040000
    00762             painter->setRenderHint(QPainter::TextAntialiasing, false);
    00763 #else
    00764             QFont fnt = label.usedFont(painter->font());
    00765             fnt.setStyleStrategy(QFont::NoAntialias);
    00766             label.setFont(fnt);
    00767 #endif
    00768 #endif
    00769             label.draw(painter, textRect);
    00770
    00771             painter->restore();
    00772         }
    00773     }
    00774 }
    00775
    00776 QPoint QwtPicker::trackerPosition() const
    00777 {
    00778     return d_data->trackerPosition;
    00779 }
    00780
    00781 QRect QwtPicker::trackerRect(const QFont &font) const
    00782 {
    00783     if ( trackerMode() == AlwaysOff ||
    00784         (trackerMode() == ActiveOnly && !isActive() ) )
    00785     {
    00786         return QRect();
    00787     }
    00788
    00789     if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
    00790         return QRect();
    00791
    00792     QwtText text = trackerText(d_data->trackerPosition);
    00793     if ( text.isEmpty() )
    00794         return QRect();
    00795
    00796     QRect textRect(QPoint(0, 0), text.textSize(font));
    00797
    00798     const QPoint &pos = d_data->trackerPosition;
    00799
    00800     int alignment = 0;
    00801     if ( isActive() && d_data->selection.count() > 1
    00802         && rubberBand() != NoRubberBand )
    00803     {
    00804         const QPoint last =
    00805             d_data->selection[int(d_data->selection.count()) - 2];
    00806
    00807         alignment |= (pos.x() >= last.x()) ? Qt::AlignRight : Qt::AlignLeft;
    00808         alignment |= (pos.y() > last.y()) ? Qt::AlignBottom : Qt::AlignTop;
    00809     }
    00810     else
    00811         alignment = Qt::AlignTop | Qt::AlignRight;
    00812
    00813     const int margin = 5;
    00814
    00815     int x = pos.x();
    00816     if ( alignment & Qt::AlignLeft )
    00817         x -= textRect.width() + margin;
    00818     else if ( alignment & Qt::AlignRight )
    00819         x += margin;
    00820
    00821     int y = pos.y();
    00822     if ( alignment & Qt::AlignBottom )
    00823         y += margin;
    00824     else if ( alignment & Qt::AlignTop )
    00825         y -= textRect.height() + margin;
    00826
    00827     textRect.moveTopLeft(QPoint(x, y));
    00828
    00829     int right = qwtMin(textRect.right(), pickRect().right() - margin);
    00830     int bottom = qwtMin(textRect.bottom(), pickRect().bottom() - margin);
    00831     textRect.moveBottomRight(QPoint(right, bottom));
    00832
    00833     int left = qwtMax(textRect.left(), pickRect().left() + margin);
    00834     int top = qwtMax(textRect.top(), pickRect().top() + margin);
    00835     textRect.moveTopLeft(QPoint(left, top));
    00836
    00837     return textRect;
    00838 }
    00839
    00852 bool QwtPicker::eventFilter(QObject *o, QEvent *e)
    00853 {
    00854     if ( o && o == parentWidget() )
    00855     {
    00856         switch(e->type())
    00857         {
    00858             case QEvent::Resize:
    00859             {
    00860                 const QResizeEvent *re = (QResizeEvent *)e;
    00861                 if ( d_data->resizeMode == Stretch )
    00862                     stretchSelection(re->oldSize(), re->size());
    00863
    00864                 if ( d_data->rubberBandWidget )
    00865                     d_data->rubberBandWidget->resize(re->size());
    00866
    00867                 if ( d_data->trackerWidget )
    00868                     d_data->trackerWidget->resize(re->size());
    00869                 break;
    00870             }
    00871             case QEvent::Leave:
    00872                 widgetLeaveEvent(e);
    00873                 break;
    00874             case QEvent::MouseButtonPress:
    00875                 widgetMousePressEvent((QMouseEvent *)e);
    00876                 break;
    00877             case QEvent::MouseButtonRelease:
    00878                 widgetMouseReleaseEvent((QMouseEvent *)e);
    00879                 break;
    00880             case QEvent::MouseButtonDblClick:
    00881                 widgetMouseDoubleClickEvent((QMouseEvent *)e);
    00882                 break;
    00883             case QEvent::MouseMove:
    00884                 widgetMouseMoveEvent((QMouseEvent *)e);
    00885                 break;
    00886             case QEvent::KeyPress:
    00887                 widgetKeyPressEvent((QKeyEvent *)e);
    00888                 break;
    00889             case QEvent::KeyRelease:
    00890                 widgetKeyReleaseEvent((QKeyEvent *)e);
    00891                 break;
    00892             case QEvent::Wheel:
    00893                 widgetWheelEvent((QWheelEvent *)e);
    00894                 break;
    00895             default:
    00896                 break;
    00897         }
    00898     }
    00899     return false;
    00900 }
    00901
    00912 void QwtPicker::widgetMousePressEvent(QMouseEvent *e)
    00913 {
    00914     transition(e);
    00915 }
    00916
    00926 void QwtPicker::widgetMouseMoveEvent(QMouseEvent *e)
    00927 {
    00928     if ( pickRect().contains(e->pos()) )
    00929         d_data->trackerPosition = e->pos();
    00930     else
    00931         d_data->trackerPosition = QPoint(-1, -1);
    00932
    00933     if ( !isActive() )
    00934         updateDisplay();
    00935
    00936     transition(e);
    00937 }
    00938
    00946 void QwtPicker::widgetLeaveEvent(QEvent *)
    00947 {
    00948     d_data->trackerPosition = QPoint(-1, -1);
    00949     if ( !isActive() )
    00950         updateDisplay();
    00951 }
    00952
    00963 void QwtPicker::widgetMouseReleaseEvent(QMouseEvent *e)
    00964 {
    00965     transition(e);
    00966 }
    00967
    00977 void QwtPicker::widgetMouseDoubleClickEvent(QMouseEvent *me)
    00978 {
    00979     transition(me);
    00980 }
    00981
    00982
    00992 void QwtPicker::widgetWheelEvent(QWheelEvent *e)
    00993 {
    00994     if ( pickRect().contains(e->pos()) )
    00995         d_data->trackerPosition = e->pos();
    00996     else
    00997         d_data->trackerPosition = QPoint(-1, -1);
    00998
    00999     updateDisplay();
    01000
    01001     transition(e);
    01002 }
    01003
    01017 void QwtPicker::widgetKeyPressEvent(QKeyEvent *ke)
    01018 {
    01019     int dx = 0;
    01020     int dy = 0;
    01021
    01022     int offset = 1;
    01023     if ( ke->isAutoRepeat() )
    01024         offset = 5;
    01025
    01026     if ( keyMatch(KeyLeft, ke) )
    01027         dx = -offset;
    01028     else if ( keyMatch(KeyRight, ke) )
    01029         dx = offset;
    01030     else if ( keyMatch(KeyUp, ke) )
    01031         dy = -offset;
    01032     else if ( keyMatch(KeyDown, ke) )
    01033         dy = offset;
    01034     else if ( keyMatch(KeyAbort, ke) )
    01035     {
    01036         reset();
    01037     }
    01038     else
    01039         transition(ke);
    01040
    01041     if ( dx != 0 || dy != 0 )
    01042     {
    01043         const QRect rect = pickRect();
    01044         const QPoint pos = parentWidget()->mapFromGlobal(QCursor::pos());
    01045
    01046         int x = pos.x() + dx;
    01047         x = qwtMax(rect.left(), x);
    01048         x = qwtMin(rect.right(), x);
    01049
    01050         int y = pos.y() + dy;
    01051         y = qwtMax(rect.top(), y);
    01052         y = qwtMin(rect.bottom(), y);
    01053
    01054         QCursor::setPos(parentWidget()->mapToGlobal(QPoint(x, y)));
    01055     }
    01056 }
    01057
    01067 void QwtPicker::widgetKeyReleaseEvent(QKeyEvent *ke)
    01068 {
    01069     transition(ke);
    01070 }
    01071
    01079 void QwtPicker::transition(const QEvent *e)
    01080 {
    01081     if ( !d_data->stateMachine )
    01082         return;
    01083
    01084     QwtPickerMachine::CommandList commandList =
    01085         d_data->stateMachine->transition(*this, e);
    01086
    01087     QPoint pos;
    01088     switch(e->type())
    01089     {
    01090         case QEvent::MouseButtonDblClick:
    01091         case QEvent::MouseButtonPress:
    01092         case QEvent::MouseButtonRelease:
    01093         case QEvent::MouseMove:
    01094         {
    01095             const QMouseEvent *me = (QMouseEvent *)e;
    01096             pos = me->pos();
    01097             break;
    01098         }
    01099         default:
    01100             pos = parentWidget()->mapFromGlobal(QCursor::pos());
    01101     }
    01102
    01103     for ( uint i = 0; i < (uint)commandList.count(); i++ )
    01104     {
    01105         switch(commandList[i])
    01106         {
    01107             case QwtPickerMachine::Begin:
    01108             {
    01109                 begin();
    01110                 break;
    01111             }
    01112             case QwtPickerMachine::Append:
    01113             {
    01114                 append(pos);
    01115                 break;
    01116             }
    01117             case QwtPickerMachine::Move:
    01118             {
    01119                 move(pos);
    01120                 break;
    01121             }
    01122             case QwtPickerMachine::End:
    01123             {
    01124                 end();
    01125                 break;
    01126             }
    01127         }
    01128     }
    01129 }
    01130
    01136 void QwtPicker::begin()
    01137 {
    01138     if ( d_data->isActive )
    01139         return;
    01140
    01141     d_data->selection.resize(0);
    01142     d_data->isActive = true;
    01143
    01144     if ( trackerMode() != AlwaysOff )
    01145     {
    01146         if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
    01147         {
    01148             QWidget *w = parentWidget();
    01149             if ( w )
    01150                 d_data->trackerPosition = w->mapFromGlobal(QCursor::pos());
    01151         }
    01152     }
    01153
    01154     updateDisplay();
    01155     setMouseTracking(true);
    01156 }
    01157
    01168 bool QwtPicker::end(bool ok)
    01169 {
    01170     if ( d_data->isActive )
    01171     {
    01172         setMouseTracking(false);
    01173
    01174         d_data->isActive = false;
    01175
    01176         if ( trackerMode() == ActiveOnly )
    01177             d_data->trackerPosition = QPoint(-1, -1);
    01178
    01179         if ( ok )
    01180             ok = accept(d_data->selection);
    01181
    01182         if ( ok )
    01183             emit selected(d_data->selection);
    01184         else
    01185             d_data->selection.resize(0);
    01186
    01187         updateDisplay();
    01188     }
    01189     else
    01190         ok = false;
    01191
    01192     return ok;
    01193 }
    01194
    01198 void QwtPicker::reset()
    01199 {
    01200     if ( d_data->stateMachine )
    01201         d_data->stateMachine->reset();
    01202
    01203     if (isActive())
    01204         end(false);
    01205 }
    01206
    01215 void QwtPicker::append(const QPoint &pos)
    01216 {
    01217     if ( d_data->isActive )
    01218     {
    01219         const int idx = d_data->selection.count();
    01220         d_data->selection.resize(idx + 1);
    01221         d_data->selection[idx] = pos;
    01222
    01223         updateDisplay();
    01224
    01225         emit appended(pos);
    01226     }
    01227 }
    01228
    01237 void QwtPicker::move(const QPoint &pos)
    01238 {
    01239     if ( d_data->isActive )
    01240     {
    01241         const int idx = d_data->selection.count() - 1;
    01242         if ( idx >= 0 )
    01243         {
    01244             if ( d_data->selection[idx] != pos )
    01245             {
    01246                 d_data->selection[idx] = pos;
    01247
    01248                 updateDisplay();
    01249
    01250                 emit moved(pos);
    01251             }
    01252         }
    01253     }
    01254 }
    01255
    01256 bool QwtPicker::accept(QwtPolygon &) const
    01257 {
    01258     return true;
    01259 }
    01260
    01265 bool QwtPicker::isActive() const
    01266 {
    01267     return d_data->isActive;
    01268 }
    01269
    01271 const QwtPolygon &QwtPicker::selection() const
    01272 {
    01273     return d_data->selection;
    01274 }
    01275
    01285 void QwtPicker::stretchSelection(const QSize &oldSize, const QSize &newSize)
    01286 {
    01287     if ( oldSize.isEmpty() )
    01288     {
    01289         // avoid division by zero. But scaling for small sizes also
    01290         // doesn't make much sense, because of rounding losses. TODO ...
    01291         return;
    01292     }
    01293
    01294     const double xRatio =
    01295         double(newSize.width()) / double(oldSize.width());
    01296     const double yRatio =
    01297         double(newSize.height()) / double(oldSize.height());
    01298
    01299     for ( int i = 0; i < int(d_data->selection.count()); i++ )
    01300     {
    01301         QPoint &p = d_data->selection[i];
    01302         p.setX(qRound(p.x() * xRatio));
    01303         p.setY(qRound(p.y() * yRatio));
    01304
    01305         emit changed(d_data->selection);
    01306     }
    01307 }
    01308
    01322 void QwtPicker::setMouseTracking(bool enable)
    01323 {
    01324     QWidget *widget = parentWidget();
    01325     if ( !widget )
    01326         return;
    01327
    01328     if ( enable )
    01329     {
    01330         d_data->mouseTracking = widget->hasMouseTracking();
    01331         widget->setMouseTracking(true);
    01332     }
    01333     else
    01334     {
    01335         widget->setMouseTracking(d_data->mouseTracking);
    01336     }
    01337 }
    01338
    01344 QRect QwtPicker::pickRect() const
    01345 {
    01346     QRect rect;
    01347
    01348     const QWidget *widget = parentWidget();
    01349     if ( !widget )
    01350         return rect;
    01351
    01352     if ( widget->inherits("QFrame") )
    01353         rect = ((QFrame *)widget)->contentsRect();
    01354     else
    01355         rect = widget->rect();
    01356
    01357     return rect;
    01358 }
    01359
    01360 void QwtPicker::updateDisplay()
    01361 {
    01362     QWidget *w = parentWidget();
    01363
    01364     bool showRubberband = false;
    01365     bool showTracker = false;
    01366     if ( w && w->isVisible() && d_data->enabled )
    01367     {
    01368         if ( rubberBand() != NoRubberBand && isActive() &&
    01369             rubberBandPen().style() != Qt::NoPen )
    01370         {
    01371             showRubberband = true;
    01372         }
    01373
    01374         if ( trackerMode() == AlwaysOn ||
    01375             (trackerMode() == ActiveOnly && isActive() ) )
    01376         {
    01377             if ( trackerPen() != Qt::NoPen )
    01378                 showTracker = true;
    01379         }
    01380     }
    01381
    01382 #if QT_VERSION < 0x040000
    01383     QGuardedPtr<PickerWidget> &rw = d_data->rubberBandWidget;
    01384 #else
    01385     QPointer<PickerWidget> &rw = d_data->rubberBandWidget;
    01386 #endif
    01387     if ( showRubberband )
    01388     {
    01389         if ( rw.isNull() )
    01390         {
    01391             rw = new PickerWidget( this, w, PickerWidget::RubberBand);
    01392             rw->resize(w->size());
    01393         }
    01394         rw->updateMask();
    01395         rw->update(); // Needed, when the mask doesn't change
    01396     }
    01397     else
    01398         delete rw;
    01399
    01400 #if QT_VERSION < 0x040000
    01401     QGuardedPtr<PickerWidget> &tw = d_data->trackerWidget;
    01402 #else
    01403     QPointer<PickerWidget> &tw = d_data->trackerWidget;
    01404 #endif
    01405     if ( showTracker )
    01406     {
    01407         if ( tw.isNull() )
    01408         {
    01409             tw = new PickerWidget( this, w, PickerWidget::Text);
    01410             tw->resize(w->size());
    01411         }
    01412         tw->updateMask();
    01413         tw->update(); // Needed, when the mask doesn't change
    01414     }
    01415     else
    01416         delete tw;
    01417 }
    01418
    01419 const QWidget *QwtPicker::rubberBandWidget() const
    01420 {
    01421     return d_data->rubberBandWidget;
    01422 }
    01423
    01424 const QWidget *QwtPicker::trackerWidget() const
    01425 {
    01426     return d_data->trackerWidget;
    01427 }
    01428