# 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            parentWidget()->paintEngine()->type() != QPaintEngine::OpenGL )
    00135         {
    00136             /*
    00137               With Qt >= 4.3 drawing of the tracker can be implemented in an
    00138               easier way, using the textRect as mask.
    00139             */
    00140
    00141             d_hasTextMask = false;
    00142         }
    00143 #endif
    00144
    00145         if ( d_hasTextMask )
    00146         {
    00147             const QwtText label = d_picker->trackerText(
    00148                 d_picker->trackerPosition());
    00149             if ( label.testPaintAttribute(QwtText::PaintBackground)
    00150                 && label.backgroundBrush().style() != Qt::NoBrush )
    00151             {
    00152 #if QT_VERSION >= 0x040300
    00153                 if ( label.backgroundBrush().color().alpha() > 0 )
    00154 #endif
    00155                 // We don't need a text mask, when we have a background
    00156                 d_hasTextMask = false;
    00157             }
    00158         }
    00159
    00160         if ( d_hasTextMask )
    00161         {
    00162             QBitmap bm(width(), height());
    00163             bm.fill(Qt::color0);
    00164
    00165             QPainter painter(&bm);
    00166             painter.setFont(font());
    00167
    00168             QPen pen = d_picker->trackerPen();
    00169             pen.setColor(Qt::color1);
    00170             painter.setPen(pen);
    00171
    00172             d_picker->drawTracker(&painter);
    00173
    00174             mask = QRegion(bm);
    00175         }
    00176         else
    00177         {
    00178             mask = d_picker->trackerRect(font());
    00179         }
    00180     }
    00181
    00182 #if QT_VERSION < 0x040000
    00183     QWidget *w = parentWidget();
    00184     const bool doUpdate = w->isUpdatesEnabled();
    00185     const Qt::BackgroundMode bgMode = w->backgroundMode();
    00186     w->setUpdatesEnabled(false);
    00187     if ( bgMode != Qt::NoBackground )
    00188         w->setBackgroundMode(Qt::NoBackground);
    00189 #endif
    00190
    00191     setMask(mask);
    00192
    00193 #if QT_VERSION < 0x040000
    00194     if ( bgMode != Qt::NoBackground )
    00195         w->setBackgroundMode(bgMode);
    00196
    00197     w->setUpdatesEnabled(doUpdate);
    00198 #endif
    00199
    00200     setShown(!mask.isEmpty());
    00201 }
    00202
    00203 void QwtPicker::PickerWidget::paintEvent(QPaintEvent *e)
    00204 {
    00205     QPainter painter(this);
    00206     painter.setClipRegion(e->region());
    00207
    00208     if ( d_type == RubberBand )
    00209     {
    00210         painter.setPen(d_picker->rubberBandPen());
    00211         d_picker->drawRubberBand(&painter);
    00212     }
    00213
    00214     if ( d_type == Text )
    00215     {
    00216         /*
    00217            If we have a text mask we simply fill the region of
    00218            the mask. This gives better results for antialiased fonts.
    00219          */
    00220         bool doDrawTracker = !d_hasTextMask;
    00221 #if QT_VERSION < 0x040000
    00222         if ( !doDrawTracker && QPainter::redirect(this) )
    00223         {
    00224             // setMask + painter redirection doesn't work
    00225             doDrawTracker = true;
    00226         }
    00227 #endif
    00228         if ( doDrawTracker )
    00229         {
    00230             painter.setPen(d_picker->trackerPen());
    00231             d_picker->drawTracker(&painter);
    00232         }
    00233         else
    00234             painter.fillRect(e->rect(), QBrush(d_picker->trackerPen().color()));
    00235     }
    00236 }
    00237
    00247 QwtPicker::QwtPicker(QWidget *parent):
    00248     QObject(parent)
    00249 {
    00250     init(parent, NoSelection, NoRubberBand, AlwaysOff);
    00251 }
    00252
    00262 QwtPicker::QwtPicker(int selectionFlags, RubberBand rubberBand,
    00263         DisplayMode trackerMode, QWidget *parent):
    00264     QObject(parent)
    00265 {
    00266     init(parent, selectionFlags, rubberBand, trackerMode);
    00267 }
    00268
    00270 QwtPicker::~QwtPicker()
    00271 {
    00272     setMouseTracking(false);
    00273     delete d_data->stateMachine;
    00274     delete d_data->rubberBandWidget;
    00275     delete d_data->trackerWidget;
    00276     delete d_data;
    00277 }
    00278
    00280 void QwtPicker::init(QWidget *parent, int selectionFlags,
    00281     RubberBand rubberBand, DisplayMode trackerMode)
    00282 {
    00283     d_data = new PrivateData;
    00284
    00285     d_data->rubberBandWidget = NULL;
    00286     d_data->trackerWidget = NULL;
    00287
    00288     d_data->rubberBand = rubberBand;
    00289     d_data->enabled = false;
    00290     d_data->resizeMode = Stretch;
    00291     d_data->trackerMode = AlwaysOff;
    00292     d_data->isActive = false;
    00293     d_data->trackerPosition = QPoint(-1, -1);
    00294     d_data->mouseTracking = false;
    00295
    00296     d_data->stateMachine = NULL;
    00297     setSelectionFlags(selectionFlags);
    00298
    00299     if ( parent )
    00300     {
    00301 #if QT_VERSION >= 0x040000
    00302         if ( parent->focusPolicy() == Qt::NoFocus )
    00303             parent->setFocusPolicy(Qt::WheelFocus);
    00304 #else
    00305         if ( parent->focusPolicy() == QWidget::NoFocus )
    00306             parent->setFocusPolicy(QWidget::WheelFocus);
    00307 #endif
    00308
    00309         d_data->trackerFont = parent->font();
    00310         d_data->mouseTracking = parent->hasMouseTracking();
    00311         setEnabled(true);
    00312     }
    00313     setTrackerMode(trackerMode);
    00314 }
    00315
    00319 void QwtPicker::setStateMachine(QwtPickerMachine *stateMachine)
    00320 {
    00321     if ( d_data->stateMachine != stateMachine )
    00322     {
    00323         reset();
    00324
    00325         delete d_data->stateMachine;
    00326         d_data->stateMachine = stateMachine;
    00327
    00328         if ( d_data->stateMachine )
    00329             d_data->stateMachine->reset();
    00330     }
    00331 }
    00332
    00349 QwtPickerMachine *QwtPicker::stateMachine(int flags) const
    00350 {
    00351     if ( flags & PointSelection )
    00352     {
    00353         if ( flags & ClickSelection )
    00354             return new QwtPickerClickPointMachine;
    00355         else
    00356             return new QwtPickerDragPointMachine;
    00357     }
    00358     if ( flags & RectSelection )
    00359     {
    00360         if ( flags & ClickSelection )
    00361             return new QwtPickerClickRectMachine;
    00362         else
    00363             return new QwtPickerDragRectMachine;
    00364     }
    00365     if ( flags & PolygonSelection )
    00366     {
    00367         return new QwtPickerPolygonMachine();
    00368     }
    00369     return NULL;
    00370 }
    00371
    00373 QWidget *QwtPicker::parentWidget()
    00374 {
    00375     QObject *obj = parent();
    00376     if ( obj && obj->isWidgetType() )
    00377         return (QWidget *)obj;
    00378
    00379     return NULL;
    00380 }
    00381
    00383 const QWidget *QwtPicker::parentWidget() const
    00384 {
    00385     QObject *obj = parent();
    00386     if ( obj && obj->isWidgetType() )
    00387         return (QWidget *)obj;
    00388
    00389     return NULL;
    00390 }
    00391
    00401 void QwtPicker::setSelectionFlags(int flags)
    00402 {
    00403     d_data->selectionFlags = flags;
    00404     setStateMachine(stateMachine(flags));
    00405 }
    00406
    00412 int QwtPicker::selectionFlags() const
    00413 {
    00414     return d_data->selectionFlags;
    00415 }
    00416
    00425 void QwtPicker::setRubberBand(RubberBand rubberBand)
    00426 {
    00427     d_data->rubberBand = rubberBand;
    00428 }
    00429
    00434 QwtPicker::RubberBand QwtPicker::rubberBand() const
    00435 {
    00436     return d_data->rubberBand;
    00437 }
    00438
    00455 void QwtPicker::setTrackerMode(DisplayMode mode)
    00456 {
    00457     if ( d_data->trackerMode != mode )
    00458     {
    00459         d_data->trackerMode = mode;
    00460         setMouseTracking(d_data->trackerMode == AlwaysOn);
    00461     }
    00462 }
    00463
    00468 QwtPicker::DisplayMode QwtPicker::trackerMode() const
    00469 {
    00470     return d_data->trackerMode;
    00471 }
    00472
    00487 void QwtPicker::setResizeMode(ResizeMode mode)
    00488 {
    00489     d_data->resizeMode = mode;
    00490 }
    00491
    00497 QwtPicker::ResizeMode QwtPicker::resizeMode() const
    00498 {
    00499     return d_data->resizeMode;
    00500 }
    00501
    00511 void QwtPicker::setEnabled(bool enabled)
    00512 {
    00513     if ( d_data->enabled != enabled )
    00514     {
    00515         d_data->enabled = enabled;
    00516
    00517         QWidget *w = parentWidget();
    00518         if ( w )
    00519         {
    00520             if ( enabled )
    00521                 w->installEventFilter(this);
    00522             else
    00523                 w->removeEventFilter(this);
    00524         }
    00525
    00526         updateDisplay();
    00527     }
    00528 }
    00529
    00535 bool QwtPicker::isEnabled() const
    00536 {
    00537     return d_data->enabled;
    00538 }
    00539
    00546 void QwtPicker::setTrackerFont(const QFont &font)
    00547 {
    00548     if ( font != d_data->trackerFont )
    00549     {
    00550         d_data->trackerFont = font;
    00551         updateDisplay();
    00552     }
    00553 }
    00554
    00560 QFont QwtPicker::trackerFont() const
    00561 {
    00562     return d_data->trackerFont;
    00563 }
    00564
    00571 void QwtPicker::setTrackerPen(const QPen &pen)
    00572 {
    00573     if ( pen != d_data->trackerPen )
    00574     {
    00575         d_data->trackerPen = pen;
    00576         updateDisplay();
    00577     }
    00578 }
    00579
    00584 QPen QwtPicker::trackerPen() const
    00585 {
    00586     return d_data->trackerPen;
    00587 }
    00588
    00595 void QwtPicker::setRubberBandPen(const QPen &pen)
    00596 {
    00597     if ( pen != d_data->rubberBandPen )
    00598     {
    00599         d_data->rubberBandPen = pen;
    00600         updateDisplay();
    00601     }
    00602 }
    00603
    00608 QPen QwtPicker::rubberBandPen() const
    00609 {
    00610     return d_data->rubberBandPen;
    00611 }
    00612
    00626 QwtText QwtPicker::trackerText(const QPoint &pos) const
    00627 {
    00628     QString label;
    00629
    00630     switch(rubberBand())
    00631     {
    00632         case HLineRubberBand:
    00633             label.sprintf("%d", pos.y());
    00634             break;
    00635         case VLineRubberBand:
    00636             label.sprintf("%d", pos.x());
    00637             break;
    00638         default:
    00639             label.sprintf("%d, %d", pos.x(), pos.y());
    00640     }
    00641     return label;
    00642 }
    00643
    00652 void QwtPicker::drawRubberBand(QPainter *painter) const
    00653 {
    00654     if ( !isActive() || rubberBand() == NoRubberBand ||
    00655         rubberBandPen().style() == Qt::NoPen )
    00656     {
    00657         return;
    00658     }
    00659
    00660     const QRect &pRect = pickRect();
    00661     const QwtPolygon &pa = d_data->selection;
    00662
    00663     if ( selectionFlags() & PointSelection )
    00664     {
    00665         if ( pa.count() < 1 )
    00666             return;
    00667
    00668         const QPoint pos = pa[0];
    00669
    00670         switch(rubberBand())
    00671         {
    00672             case VLineRubberBand:
    00673                 QwtPainter::drawLine(painter, pos.x(),
    00674                     pRect.top(), pos.x(), pRect.bottom());
    00675                 break;
    00676
    00677             case HLineRubberBand:
    00678                 QwtPainter::drawLine(painter, pRect.left(),
    00679                     pos.y(), pRect.right(), pos.y());
    00680                 break;
    00681
    00682             case CrossRubberBand:
    00683                 QwtPainter::drawLine(painter, pos.x(),
    00684                     pRect.top(), pos.x(), pRect.bottom());
    00685                 QwtPainter::drawLine(painter, pRect.left(),
    00686                     pos.y(), pRect.right(), pos.y());
    00687                 break;
    00688             default:
    00689                 break;
    00690         }
    00691     }
    00692
    00693     else if ( selectionFlags() & RectSelection )
    00694     {
    00695         if ( pa.count() < 2 )
    00696             return;
    00697
    00698         QPoint p1 = pa[0];
    00699         QPoint p2 = pa[int(pa.count() - 1)];
    00700
    00701         if ( selectionFlags() & CenterToCorner )
    00702         {
    00703             p1.setX(p1.x() - (p2.x() - p1.x()));
    00704             p1.setY(p1.y() - (p2.y() - p1.y()));
    00705         }
    00706         else if ( selectionFlags() & CenterToRadius )
    00707         {
    00708             const int radius = qwtMax(qwtAbs(p2.x() - p1.x()),
    00709                 qwtAbs(p2.y() - p1.y()));
    00710             p2.setX(p1.x() + radius);
    00711             p2.setY(p1.y() + radius);
    00712             p1.setX(p1.x() - radius);
    00713             p1.setY(p1.y() - radius);
    00714         }
    00715
    00716 #if QT_VERSION < 0x040000
    00717         const QRect rect = QRect(p1, p2).normalize();
    00718 #else
    00719         const QRect rect = QRect(p1, p2).normalized();
    00720 #endif
    00721         switch(rubberBand())
    00722         {
    00723             case EllipseRubberBand:
    00724                 QwtPainter::drawEllipse(painter, rect);
    00725                 break;
    00726             case RectRubberBand:
    00727                 QwtPainter::drawRect(painter, rect);
    00728                 break;
    00729             default:
    00730                 break;
    00731         }
    00732     }
    00733     else if ( selectionFlags() & PolygonSelection )
    00734     {
    00735         if ( rubberBand() == PolygonRubberBand )
    00736             painter->drawPolyline(pa);
    00737     }
    00738 }
    00739
    00747 void QwtPicker::drawTracker(QPainter *painter) const
    00748 {
    00749     const QRect textRect = trackerRect(painter->font());
    00750     if ( !textRect.isEmpty() )
    00751     {
    00752         QwtText label = trackerText(d_data->trackerPosition);
    00753         if ( !label.isEmpty() )
    00754         {
    00755             painter->save();
    00756
    00757 #if defined(Q_WS_MAC)
    00758             // Antialiased fonts are broken on the Mac.
    00759 #if QT_VERSION >= 0x040000
    00760             painter->setRenderHint(QPainter::TextAntialiasing, false);
    00761 #else
    00762             QFont fnt = label.usedFont(painter->font());
    00763             fnt.setStyleStrategy(QFont::NoAntialias);
    00764             label.setFont(fnt);
    00765 #endif
    00766 #endif
    00767             label.draw(painter, textRect);
    00768
    00769             painter->restore();
    00770         }
    00771     }
    00772 }
    00773
    00774 QPoint QwtPicker::trackerPosition() const
    00775 {
    00776     return d_data->trackerPosition;
    00777 }
    00778
    00779 QRect QwtPicker::trackerRect(const QFont &font) const
    00780 {
    00781     if ( trackerMode() == AlwaysOff ||
    00782         (trackerMode() == ActiveOnly && !isActive() ) )
    00783     {
    00784         return QRect();
    00785     }
    00786
    00787     if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
    00788         return QRect();
    00789
    00790     QwtText text = trackerText(d_data->trackerPosition);
    00791     if ( text.isEmpty() )
    00792         return QRect();
    00793
    00794     QRect textRect(QPoint(0, 0), text.textSize(font));
    00795
    00796     const QPoint &pos = d_data->trackerPosition;
    00797
    00798     int alignment = 0;
    00799     if ( isActive() && d_data->selection.count() > 1
    00800         && rubberBand() != NoRubberBand )
    00801     {
    00802         const QPoint last =
    00803             d_data->selection[int(d_data->selection.count()) - 2];
    00804
    00805         alignment |= (pos.x() >= last.x()) ? Qt::AlignRight : Qt::AlignLeft;
    00806         alignment |= (pos.y() > last.y()) ? Qt::AlignBottom : Qt::AlignTop;
    00807     }
    00808     else
    00809         alignment = Qt::AlignTop | Qt::AlignRight;
    00810
    00811     const int margin = 5;
    00812
    00813     int x = pos.x();
    00814     if ( alignment & Qt::AlignLeft )
    00815         x -= textRect.width() + margin;
    00816     else if ( alignment & Qt::AlignRight )
    00817         x += margin;
    00818
    00819     int y = pos.y();
    00820     if ( alignment & Qt::AlignBottom )
    00821         y += margin;
    00822     else if ( alignment & Qt::AlignTop )
    00823         y -= textRect.height() + margin;
    00824
    00825     textRect.moveTopLeft(QPoint(x, y));
    00826
    00827     int right = qwtMin(textRect.right(), pickRect().right() - margin);
    00828     int bottom = qwtMin(textRect.bottom(), pickRect().bottom() - margin);
    00829     textRect.moveBottomRight(QPoint(right, bottom));
    00830
    00831     int left = qwtMax(textRect.left(), pickRect().left() + margin);
    00832     int top = qwtMax(textRect.top(), pickRect().top() + margin);
    00833     textRect.moveTopLeft(QPoint(left, top));
    00834
    00835     return textRect;
    00836 }
    00837
    00850 bool QwtPicker::eventFilter(QObject *o, QEvent *e)
    00851 {
    00852     if ( o && o == parentWidget() )
    00853     {
    00854         switch(e->type())
    00855         {
    00856             case QEvent::Resize:
    00857             {
    00858                 const QResizeEvent *re = (QResizeEvent *)e;
    00859                 if ( d_data->resizeMode == Stretch )
    00860                     stretchSelection(re->oldSize(), re->size());
    00861
    00862                 if ( d_data->rubberBandWidget )
    00863                     d_data->rubberBandWidget->resize(re->size());
    00864
    00865                 if ( d_data->trackerWidget )
    00866                     d_data->trackerWidget->resize(re->size());
    00867                 break;
    00868             }
    00869             case QEvent::Leave:
    00870                 widgetLeaveEvent(e);
    00871                 break;
    00872             case QEvent::MouseButtonPress:
    00873                 widgetMousePressEvent((QMouseEvent *)e);
    00874                 break;
    00875             case QEvent::MouseButtonRelease:
    00876                 widgetMouseReleaseEvent((QMouseEvent *)e);
    00877                 break;
    00878             case QEvent::MouseButtonDblClick:
    00879                 widgetMouseDoubleClickEvent((QMouseEvent *)e);
    00880                 break;
    00881             case QEvent::MouseMove:
    00882                 widgetMouseMoveEvent((QMouseEvent *)e);
    00883                 break;
    00884             case QEvent::KeyPress:
    00885                 widgetKeyPressEvent((QKeyEvent *)e);
    00886                 break;
    00887             case QEvent::KeyRelease:
    00888                 widgetKeyReleaseEvent((QKeyEvent *)e);
    00889                 break;
    00890             case QEvent::Wheel:
    00891                 widgetWheelEvent((QWheelEvent *)e);
    00892                 break;
    00893             default:
    00894                 break;
    00895         }
    00896     }
    00897     return false;
    00898 }
    00899
    00910 void QwtPicker::widgetMousePressEvent(QMouseEvent *e)
    00911 {
    00912     transition(e);
    00913 }
    00914
    00924 void QwtPicker::widgetMouseMoveEvent(QMouseEvent *e)
    00925 {
    00926     if ( pickRect().contains(e->pos()) )
    00927         d_data->trackerPosition = e->pos();
    00928     else
    00929         d_data->trackerPosition = QPoint(-1, -1);
    00930
    00931     if ( !isActive() )
    00932         updateDisplay();
    00933
    00934     transition(e);
    00935 }
    00936
    00944 void QwtPicker::widgetLeaveEvent(QEvent *)
    00945 {
    00946     d_data->trackerPosition = QPoint(-1, -1);
    00947     if ( !isActive() )
    00948         updateDisplay();
    00949 }
    00950
    00961 void QwtPicker::widgetMouseReleaseEvent(QMouseEvent *e)
    00962 {
    00963     transition(e);
    00964 }
    00965
    00975 void QwtPicker::widgetMouseDoubleClickEvent(QMouseEvent *me)
    00976 {
    00977     transition(me);
    00978 }
    00979
    00980
    00990 void QwtPicker::widgetWheelEvent(QWheelEvent *e)
    00991 {
    00992     if ( pickRect().contains(e->pos()) )
    00993         d_data->trackerPosition = e->pos();
    00994     else
    00995         d_data->trackerPosition = QPoint(-1, -1);
    00996
    00997     updateDisplay();
    00998
    00999     transition(e);
    01000 }
    01001
    01015 void QwtPicker::widgetKeyPressEvent(QKeyEvent *ke)
    01016 {
    01017     int dx = 0;
    01018     int dy = 0;
    01019
    01020     int offset = 1;
    01021     if ( ke->isAutoRepeat() )
    01022         offset = 5;
    01023
    01024     if ( keyMatch(KeyLeft, ke) )
    01025         dx = -offset;
    01026     else if ( keyMatch(KeyRight, ke) )
    01027         dx = offset;
    01028     else if ( keyMatch(KeyUp, ke) )
    01029         dy = -offset;
    01030     else if ( keyMatch(KeyDown, ke) )
    01031         dy = offset;
    01032     else if ( keyMatch(KeyAbort, ke) )
    01033     {
    01034         reset();
    01035     }
    01036     else
    01037         transition(ke);
    01038
    01039     if ( dx != 0 || dy != 0 )
    01040     {
    01041         const QRect rect = pickRect();
    01042         const QPoint pos = parentWidget()->mapFromGlobal(QCursor::pos());
    01043
    01044         int x = pos.x() + dx;
    01045         x = qwtMax(rect.left(), x);
    01046         x = qwtMin(rect.right(), x);
    01047
    01048         int y = pos.y() + dy;
    01049         y = qwtMax(rect.top(), y);
    01050         y = qwtMin(rect.bottom(), y);
    01051
    01052         QCursor::setPos(parentWidget()->mapToGlobal(QPoint(x, y)));
    01053     }
    01054 }
    01055
    01065 void QwtPicker::widgetKeyReleaseEvent(QKeyEvent *ke)
    01066 {
    01067     transition(ke);
    01068 }
    01069
    01077 void QwtPicker::transition(const QEvent *e)
    01078 {
    01079     if ( !d_data->stateMachine )
    01080         return;
    01081
    01082     QwtPickerMachine::CommandList commandList =
    01083         d_data->stateMachine->transition(*this, e);
    01084
    01085     QPoint pos;
    01086     switch(e->type())
    01087     {
    01088         case QEvent::MouseButtonDblClick:
    01089         case QEvent::MouseButtonPress:
    01090         case QEvent::MouseButtonRelease:
    01091         case QEvent::MouseMove:
    01092         {
    01093             const QMouseEvent *me = (QMouseEvent *)e;
    01094             pos = me->pos();
    01095             break;
    01096         }
    01097         default:
    01098             pos = parentWidget()->mapFromGlobal(QCursor::pos());
    01099     }
    01100
    01101     for ( uint i = 0; i < (uint)commandList.count(); i++ )
    01102     {
    01103         switch(commandList[i])
    01104         {
    01105             case QwtPickerMachine::Begin:
    01106             {
    01107                 begin();
    01108                 break;
    01109             }
    01110             case QwtPickerMachine::Append:
    01111             {
    01112                 append(pos);
    01113                 break;
    01114             }
    01115             case QwtPickerMachine::Move:
    01116             {
    01117                 move(pos);
    01118                 break;
    01119             }
    01120             case QwtPickerMachine::End:
    01121             {
    01122                 end();
    01123                 break;
    01124             }
    01125         }
    01126     }
    01127 }
    01128
    01134 void QwtPicker::begin()
    01135 {
    01136     if ( d_data->isActive )
    01137         return;
    01138
    01139     d_data->selection.resize(0);
    01140     d_data->isActive = true;
    01141
    01142     if ( trackerMode() != AlwaysOff )
    01143     {
    01144         if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 )
    01145         {
    01146             QWidget *w = parentWidget();
    01147             if ( w )
    01148                 d_data->trackerPosition = w->mapFromGlobal(QCursor::pos());
    01149         }
    01150     }
    01151
    01152     updateDisplay();
    01153     setMouseTracking(true);
    01154 }
    01155
    01166 bool QwtPicker::end(bool ok)
    01167 {
    01168     if ( d_data->isActive )
    01169     {
    01170         setMouseTracking(false);
    01171
    01172         d_data->isActive = false;
    01173
    01174         if ( trackerMode() == ActiveOnly )
    01175             d_data->trackerPosition = QPoint(-1, -1);
    01176
    01177         if ( ok )
    01178             ok = accept(d_data->selection);
    01179
    01180         if ( ok )
    01181             emit selected(d_data->selection);
    01182         else
    01183             d_data->selection.resize(0);
    01184
    01185         updateDisplay();
    01186     }
    01187     else
    01188         ok = false;
    01189
    01190     return ok;
    01191 }
    01192
    01196 void QwtPicker::reset()
    01197 {
    01198     if ( d_data->stateMachine )
    01199         d_data->stateMachine->reset();
    01200
    01201     if (isActive())
    01202         end(false);
    01203 }
    01204
    01213 void QwtPicker::append(const QPoint &pos)
    01214 {
    01215     if ( d_data->isActive )
    01216     {
    01217         const int idx = d_data->selection.count();
    01218         d_data->selection.resize(idx + 1);
    01219         d_data->selection[idx] = pos;
    01220
    01221         updateDisplay();
    01222
    01223         emit appended(pos);
    01224     }
    01225 }
    01226
    01235 void QwtPicker::move(const QPoint &pos)
    01236 {
    01237     if ( d_data->isActive )
    01238     {
    01239         const int idx = d_data->selection.count() - 1;
    01240         if ( idx >= 0 )
    01241         {
    01242             if ( d_data->selection[idx] != pos )
    01243             {
    01244                 d_data->selection[idx] = pos;
    01245
    01246                 updateDisplay();
    01247
    01248                 emit moved(pos);
    01249             }
    01250         }
    01251     }
    01252 }
    01253
    01254 bool QwtPicker::accept(QwtPolygon &) const
    01255 {
    01256     return true;
    01257 }
    01258
    01263 bool QwtPicker::isActive() const
    01264 {
    01265     return d_data->isActive;
    01266 }
    01267
    01269 const QwtPolygon &QwtPicker::selection() const
    01270 {
    01271     return d_data->selection;
    01272 }
    01273
    01283 void QwtPicker::stretchSelection(const QSize &oldSize, const QSize &newSize)
    01284 {
    01285     if ( oldSize.isEmpty() )
    01286     {
    01287         // avoid division by zero. But scaling for small sizes also
    01288         // doesn't make much sense, because of rounding losses. TODO ...
    01289         return;
    01290     }
    01291
    01292     const double xRatio =
    01293         double(newSize.width()) / double(oldSize.width());
    01294     const double yRatio =
    01295         double(newSize.height()) / double(oldSize.height());
    01296
    01297     for ( int i = 0; i < int(d_data->selection.count()); i++ )
    01298     {
    01299         QPoint &p = d_data->selection[i];
    01300         p.setX(qRound(p.x() * xRatio));
    01301         p.setY(qRound(p.y() * yRatio));
    01302
    01303         emit changed(d_data->selection);
    01304     }
    01305 }
    01306
    01320 void QwtPicker::setMouseTracking(bool enable)
    01321 {
    01322     QWidget *widget = parentWidget();
    01323     if ( !widget )
    01324         return;
    01325
    01326     if ( enable )
    01327     {
    01328         d_data->mouseTracking = widget->hasMouseTracking();
    01329         widget->setMouseTracking(true);
    01330     }
    01331     else
    01332     {
    01333         widget->setMouseTracking(d_data->mouseTracking);
    01334     }
    01335 }
    01336
    01342 QRect QwtPicker::pickRect() const
    01343 {
    01344     QRect rect;
    01345
    01346     const QWidget *widget = parentWidget();
    01347     if ( !widget )
    01348         return rect;
    01349
    01350     if ( widget->inherits("QFrame") )
    01351         rect = ((QFrame *)widget)->contentsRect();
    01352     else
    01353         rect = widget->rect();
    01354
    01355     return rect;
    01356 }
    01357
    01358 void QwtPicker::updateDisplay()
    01359 {
    01360     QWidget *w = parentWidget();
    01361
    01362     bool showRubberband = false;
    01363     bool showTracker = false;
    01364     if ( w && w->isVisible() && d_data->enabled )
    01365     {
    01366         if ( rubberBand() != NoRubberBand && isActive() &&
    01367             rubberBandPen().style() != Qt::NoPen )
    01368         {
    01369             showRubberband = true;
    01370         }
    01371
    01372         if ( trackerMode() == AlwaysOn ||
    01373             (trackerMode() == ActiveOnly && isActive() ) )
    01374         {
    01375             if ( trackerPen() != Qt::NoPen )
    01376                 showTracker = true;
    01377         }
    01378     }
    01379
    01380 #if QT_VERSION < 0x040000
    01381     QGuardedPtr<PickerWidget> &rw = d_data->rubberBandWidget;
    01382 #else
    01383     QPointer<PickerWidget> &rw = d_data->rubberBandWidget;
    01384 #endif
    01385     if ( showRubberband )
    01386     {
    01387         if ( rw.isNull() )
    01388         {
    01389             rw = new PickerWidget( this, w, PickerWidget::RubberBand);
    01390             rw->resize(w->size());
    01391         }
    01392         rw->updateMask();
    01393         rw->update(); // Needed, when the mask doesn't change
    01394     }
    01395     else
    01396         delete rw;
    01397
    01398 #if QT_VERSION < 0x040000
    01399     QGuardedPtr<PickerWidget> &tw = d_data->trackerWidget;
    01400 #else
    01401     QPointer<PickerWidget> &tw = d_data->trackerWidget;
    01402 #endif
    01403     if ( showTracker )
    01404     {
    01405         if ( tw.isNull() )
    01406         {
    01407             tw = new PickerWidget( this, w, PickerWidget::Text);
    01408             tw->resize(w->size());
    01409         }
    01410         tw->updateMask();
    01411         tw->update(); // Needed, when the mask doesn't change
    01412     }
    01413     else
    01414         delete tw;
    01415 }
    01416
    01417 const QWidget *QwtPicker::rubberBandWidget() const
    01418 {
    01419     return d_data->rubberBandWidget;
    01420 }
    01421
    01422 const QWidget *QwtPicker::trackerWidget() const
    01423 {
    01424     return d_data->trackerWidget;
    01425 }
    01426